mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-29 15:01:23 +00:00
323bcc614d
2003-06-28 Tor Lillqvist <tml@iki.fi> Fix for #111028, thanks to J. Ali Harlow, who writes: I found that the GdkPixmap->GdkImage reference really isn't important. It's only really there to have somewhere convenient to store the location of the pixel data in the pixmap and as an easy way of accessing the dimensions of that data. I have therefore put together a fix which removes this reference entirely which seems to solve the problem. * gdk/win32/gdkpixmap-win32.h (struct _GdkPixmapImplWin32): Instead of a pointer to a GdkImage, keep a pointer to the pixels directly. * gdk/win32/gdkimage-win32.c (_gdk_win32_setup_pixmap_image): Remove. (_gdk_win32_new_image): New function, replacing the above. Creates a GdkImage without any associated GdkPixmap. (gdk_image_new_bitmap, _gdk_image_new_for_depth): Use it instead. * gdk/win32/gdkprivate-win32.h: Remove from here, too. * gdk/win32/gdkcursor-win32.c (gdk_cursor_new_from_pixmap) * gdk/win32/gdkdrawable-win32.c (blit_from_pixmap) * gdk/win32/gdkgc-win32.c (_gdk_win32_bitmap_to_hrgn) * gdk/win32/gdkmain-win32.c (_gdk_win32_drawable_description): * gdk/win32/gdkpixmap-win32.c (gdk_pixmap_impl_win32_finalize, gdk_pixmap_new, gdk_bitmap_create_from_data, gdk_pixmap_foreign_new) Corresponding changes.
320 lines
8.4 KiB
C
320 lines
8.4 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
* Copyright (C) 1998-2002 Tor Lillqvist
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "gdkdisplay.h"
|
|
#include "gdkcursor.h"
|
|
#include "gdkprivate-win32.h"
|
|
|
|
#include "xcursors.h"
|
|
|
|
static HCURSOR
|
|
_gdk_win32_data_to_wcursor (GdkCursorType cursor_type)
|
|
{
|
|
gint i, j, x, y, ofs;
|
|
HCURSOR rv = NULL;
|
|
gint w, h;
|
|
guchar *and_plane, *xor_plane;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (cursors); i++)
|
|
if (cursors[i].type == cursor_type)
|
|
break;
|
|
|
|
if (i >= G_N_ELEMENTS (cursors) || !cursors[i].name)
|
|
return NULL;
|
|
|
|
w = GetSystemMetrics (SM_CXCURSOR);
|
|
h = GetSystemMetrics (SM_CYCURSOR);
|
|
|
|
and_plane = g_malloc ((w/8) * h);
|
|
memset (and_plane, 0xff, (w/8) * h);
|
|
xor_plane = g_malloc ((w/8) * h);
|
|
memset (xor_plane, 0, (w/8) * h);
|
|
|
|
#define SET_BIT(v,b) (v |= (1 << b))
|
|
#define RESET_BIT(v,b) (v &= ~(1 << b))
|
|
|
|
for (j = 0, y = 0; y < cursors[i].height && y < h ; y++)
|
|
{
|
|
ofs = (y * w) / 8;
|
|
j = y * cursors[i].width;
|
|
|
|
for (x = 0; x < cursors[i].width && x < w ; x++, j++)
|
|
{
|
|
gint pofs = ofs + x / 8;
|
|
guchar data = (cursors[i].data[j/4] & (0xc0 >> (2 * (j%4)))) >> (2 * (3 - (j%4)));
|
|
gint bit = 7 - (j % cursors[i].width) % 8;
|
|
|
|
if (data)
|
|
{
|
|
RESET_BIT (and_plane[pofs], bit);
|
|
if (data == 1)
|
|
SET_BIT (xor_plane[pofs], bit);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef SET_BIT
|
|
#undef RESET_BIT
|
|
|
|
rv = CreateCursor (_gdk_app_hmodule, cursors[i].hotx, cursors[i].hoty,
|
|
w, h, and_plane, xor_plane);
|
|
if (rv == NULL)
|
|
WIN32_API_FAILED ("CreateCursor");
|
|
g_free (and_plane);
|
|
g_free (xor_plane);
|
|
|
|
return rv;
|
|
}
|
|
|
|
GdkCursor*
|
|
gdk_cursor_new_for_display (GdkDisplay *display,
|
|
GdkCursorType cursor_type)
|
|
{
|
|
GdkCursorPrivate *private;
|
|
GdkCursor *cursor;
|
|
HCURSOR hcursor;
|
|
|
|
g_return_val_if_fail (display == gdk_display_get_default (), NULL);
|
|
|
|
hcursor = _gdk_win32_data_to_wcursor (cursor_type);
|
|
|
|
if (hcursor == NULL)
|
|
g_warning ("gdk_cursor_new_for_display: no cursor %d found", cursor_type);
|
|
else
|
|
GDK_NOTE (MISC, g_print ("gdk_cursor_new_for_display: %d: %p\n",
|
|
cursor_type, hcursor));
|
|
|
|
private = g_new (GdkCursorPrivate, 1);
|
|
private->hcursor = hcursor;
|
|
cursor = (GdkCursor*) private;
|
|
cursor->type = cursor_type;
|
|
cursor->ref_count = 1;
|
|
|
|
return cursor;
|
|
}
|
|
|
|
static gboolean
|
|
color_is_white (GdkColor *color)
|
|
{
|
|
return (color->red == 0xFFFF
|
|
&& color->green == 0xFFFF
|
|
&& color->blue == 0xFFFF);
|
|
}
|
|
|
|
GdkCursor*
|
|
gdk_cursor_new_from_pixmap (GdkPixmap *source,
|
|
GdkPixmap *mask,
|
|
GdkColor *fg,
|
|
GdkColor *bg,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
GdkCursorPrivate *private;
|
|
GdkCursor *cursor;
|
|
GdkPixmapImplWin32 *source_impl, *mask_impl;
|
|
guchar *source_bits, *mask_bits;
|
|
gint source_bpl, mask_bpl;
|
|
HCURSOR hcursor;
|
|
guchar *p, *q, *xor_mask, *and_mask;
|
|
gint width, height, cursor_width, cursor_height;
|
|
guchar residue;
|
|
gint ix, iy;
|
|
const gboolean bg_is_white = color_is_white (bg);
|
|
|
|
g_return_val_if_fail (GDK_IS_PIXMAP (source), NULL);
|
|
g_return_val_if_fail (GDK_IS_PIXMAP (mask), NULL);
|
|
g_return_val_if_fail (fg != NULL, NULL);
|
|
g_return_val_if_fail (bg != NULL, NULL);
|
|
|
|
source_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (source)->impl);
|
|
mask_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (mask)->impl);
|
|
|
|
g_return_val_if_fail (source_impl->width == mask_impl->width
|
|
&& source_impl->height == mask_impl->height,
|
|
NULL);
|
|
width = source_impl->width;
|
|
height = source_impl->height;
|
|
cursor_width = GetSystemMetrics (SM_CXCURSOR);
|
|
cursor_height = GetSystemMetrics (SM_CYCURSOR);
|
|
|
|
g_return_val_if_fail (width <= cursor_width && height <= cursor_height,
|
|
NULL);
|
|
|
|
residue = (1 << ((8-(width%8))%8)) - 1;
|
|
|
|
source_bits = source_impl->bits;
|
|
mask_bits = mask_impl->bits;
|
|
|
|
g_return_val_if_fail (GDK_PIXMAP_OBJECT (source)->depth == 1
|
|
&& GDK_PIXMAP_OBJECT (mask)->depth == 1,
|
|
NULL);
|
|
|
|
source_bpl = ((width - 1)/32 + 1)*4;
|
|
mask_bpl = ((mask_impl->width - 1)/32 + 1)*4;
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
if (_gdk_debug_flags & GDK_DEBUG_CURSOR)
|
|
{
|
|
g_print ("gdk_cursor_new_from_pixmap: source=%p:\n",
|
|
source_impl->parent_instance.handle);
|
|
for (iy = 0; iy < height; iy++)
|
|
{
|
|
if (iy == 16)
|
|
break;
|
|
|
|
p = source_bits + iy*source_bpl;
|
|
for (ix = 0; ix < width; ix++)
|
|
{
|
|
if (ix == 79)
|
|
break;
|
|
g_print ("%c", ".X"[((*p)>>(7-(ix%8)))&1]);
|
|
if ((ix%8) == 7)
|
|
p++;
|
|
}
|
|
g_print ("\n");
|
|
}
|
|
g_print ("...mask=%p:\n", mask_impl->parent_instance.handle);
|
|
for (iy = 0; iy < height; iy++)
|
|
{
|
|
if (iy == 16)
|
|
break;
|
|
|
|
p = mask_bits + iy*source_bpl;
|
|
for (ix = 0; ix < width; ix++)
|
|
{
|
|
if (ix == 79)
|
|
break;
|
|
g_print ("%c", ".X"[((*p)>>(7-(ix%8)))&1]);
|
|
if ((ix%8) == 7)
|
|
p++;
|
|
}
|
|
g_print ("\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Such complex bit manipulation for this simple task, sigh.
|
|
* The X cursor and Windows cursor concepts are quite different.
|
|
* We assume here that we are always called with fg == black and
|
|
* bg == white, *or* the other way around. Random colours won't work.
|
|
* (Well, you will get a cursor, but not in those colours.)
|
|
*/
|
|
|
|
/* Note: The comments below refer to the case fg==black and
|
|
* bg==white, as that was what was implemented first. The fg==white
|
|
* (the "if (fg->pixel)" branches) case was added later.
|
|
*/
|
|
|
|
/* First set masked-out source bits, as all source bits matter on Windoze.
|
|
* As we invert them below, they will be clear in the final xor_mask.
|
|
*/
|
|
for (iy = 0; iy < height; iy++)
|
|
{
|
|
p = source_bits + iy*source_bpl;
|
|
q = mask_bits + iy*mask_bpl;
|
|
|
|
for (ix = 0; ix < ((width-1)/8+1); ix++)
|
|
if (bg_is_white)
|
|
*p++ |= ~(*q++);
|
|
else
|
|
*p++ &= *q++;
|
|
}
|
|
|
|
/* XOR mask is initialized to zero */
|
|
xor_mask = g_malloc0 (cursor_width/8 * cursor_height);
|
|
|
|
for (iy = 0; iy < height; iy++)
|
|
{
|
|
p = source_bits + iy*source_bpl;
|
|
q = xor_mask + iy*cursor_width/8;
|
|
|
|
for (ix = 0; ix < ((width-1)/8+1); ix++)
|
|
if (bg_is_white)
|
|
*q++ = ~(*p++);
|
|
else
|
|
*q++ = *p++;
|
|
|
|
q[-1] &= ~residue; /* Clear left-over bits */
|
|
}
|
|
|
|
/* AND mask is initialized to ones */
|
|
and_mask = g_malloc (cursor_width/8 * cursor_height);
|
|
memset (and_mask, 0xFF, cursor_width/8 * cursor_height);
|
|
|
|
for (iy = 0; iy < height; iy++)
|
|
{
|
|
p = mask_bits + iy*mask_bpl;
|
|
q = and_mask + iy*cursor_width/8;
|
|
|
|
for (ix = 0; ix < ((width-1)/8+1); ix++)
|
|
*q++ = ~(*p++);
|
|
|
|
q[-1] |= residue; /* Set left-over bits */
|
|
}
|
|
|
|
hcursor = CreateCursor (_gdk_app_hmodule, x, y, cursor_width, cursor_height,
|
|
and_mask, xor_mask);
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_cursor_new_from_pixmap: "
|
|
"%p (%dx%d) %p (%dx%d) = %p (%dx%d)\n",
|
|
GDK_PIXMAP_HBITMAP (source),
|
|
source_impl->width, source_impl->height,
|
|
GDK_PIXMAP_HBITMAP (mask),
|
|
mask_impl->width, mask_impl->height,
|
|
hcursor, cursor_width, cursor_height));
|
|
|
|
g_free (xor_mask);
|
|
g_free (and_mask);
|
|
|
|
private = g_new (GdkCursorPrivate, 1);
|
|
private->hcursor = hcursor;
|
|
cursor = (GdkCursor*) private;
|
|
cursor->type = GDK_CURSOR_IS_PIXMAP;
|
|
cursor->ref_count = 1;
|
|
|
|
return cursor;
|
|
}
|
|
|
|
void
|
|
_gdk_cursor_destroy (GdkCursor *cursor)
|
|
{
|
|
GdkCursorPrivate *private;
|
|
|
|
g_return_if_fail (cursor != NULL);
|
|
private = (GdkCursorPrivate *) cursor;
|
|
|
|
GDK_NOTE (MISC, g_print ("_gdk_cursor_destroy: %p\n",
|
|
(cursor->type == GDK_CURSOR_IS_PIXMAP) ? private->hcursor : 0));
|
|
|
|
if (GetCursor () == private->hcursor)
|
|
SetCursor (NULL);
|
|
|
|
if (!DestroyCursor (private->hcursor))
|
|
WIN32_API_FAILED ("DestroyCursor");
|
|
|
|
g_free (private);
|
|
}
|
|
|
|
GdkDisplay *
|
|
gdk_cursor_get_display (GdkCursor *cursor)
|
|
{
|
|
return gdk_display_get_default ();
|
|
}
|