gtk/gdk/win32/gdkcursor-win32.c

269 lines
7.5 KiB
C
Raw Normal View History

1999-11-11 22:01:55 +00:00
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
1999-11-11 22:01:55 +00:00
* 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.
1999-11-11 22:01:55 +00:00
*
* You should have received a copy of the GNU Lesser General Public
1999-11-11 22:01:55 +00:00
* 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 "config.h"
#include "gdkwin32.h"
1999-11-11 22:01:55 +00:00
#include "gdkcursor.h"
Large changes to the Win32 backend, partially made necessary by the 2000-05-02 Tor Lillqvist <tml@iki.fi> Large changes to the Win32 backend, partially made necessary by the changes to the backend-independent internal structures. Attempts to implement similar backing store stuff as on X11. The current (CVS) version of the Win32 backend is *not* as stable as it was before the no-flicker branch was merged. A zipfile with that version is available from http://www.gimp.org/win32/. That should be use by "production" code until this CVS version is usable. (But note, the Win32 backend has never been claimed to be "production quality".) * README.win32: Add the above comment about versions. * gdk/gdkwindow.c: Don't use backing store for now on Win32. * gdk/gdk.def: Update. * gdk/gdkfont.h: Declare temporary Win32-only functions. Will presumably be replaced by some more better mechanism as 1.4 gets closer to release shape. * gdk/makefile.{cygwin,msc}: Update. * gdk/win32/*.c: Correct inclusions of the backend-specific and internal headers. Change code according to changes in these. Use gdk_drawable_*, not gdk_window_* where necessary. * gdk/win32/gdkdnd-win32.c: Use MISC selector for GDK_NOTE, not our old DND. * gdk/win32/gdkdrawable-win32.c (gdk_win32_draw_text): Don't try to interpret single characters as UTF-8. Thanks to Hans Breuer. Use correct function name in warning messages. * gdk/win32/gdkevents-win32.c: Use correct parameter lists for the GSourceFuncs gdk_event_prepare and gdk_event_check. (gdk_event_get_graphics_expose): Do implement, use PeekMessage. Thanks to Hans Breuer. (event_mask_string): Debugging function to print an GdkEventMask. (gdk_pointer_grab): Use it. * gdk/win32/gdkfont-win32.c: The Unicode subrange that the (old) book I used claimed was Hangul actually is CJK Unified Ideographs Extension A. Also, Hangul Syllables were missing. Improve logging. * gdk/win32/gdkgc-win32.c: Largish changes. * gdk/win32/gdkim-win32.c (gdk_set_locale): Use g_win32_getlocale() from GLib, and not setlocale() to get current locale name. * gdk/win32/gdkprivate-win32.h * gdk/win32/gdkwin32.h: Move stuff from gdkprivate-win32.h to gdkwin32.h, similarily as in the X11 backend. * gdk/win32/gdkwindow-win32.c (gdk_propagate_shapes): Bugfix, assignment was used instead of equals in if test. Thanks to Hans Breuer. * gdk/win32/makefile.{cygwin,msc} * gtk/makefile.{cygwin,msc}: Updates. Better kludge to get the path to the Win32 headers that works also with the mingw compiler. * gtk/gtkstyle.c: Include <string.h>.
2000-05-01 22:06:49 +00:00
#include "gdkinternals.h"
#include "gdkpixmap-win32.h"
Large changes to the Win32 backend, partially made necessary by the 2000-05-02 Tor Lillqvist <tml@iki.fi> Large changes to the Win32 backend, partially made necessary by the changes to the backend-independent internal structures. Attempts to implement similar backing store stuff as on X11. The current (CVS) version of the Win32 backend is *not* as stable as it was before the no-flicker branch was merged. A zipfile with that version is available from http://www.gimp.org/win32/. That should be use by "production" code until this CVS version is usable. (But note, the Win32 backend has never been claimed to be "production quality".) * README.win32: Add the above comment about versions. * gdk/gdkwindow.c: Don't use backing store for now on Win32. * gdk/gdk.def: Update. * gdk/gdkfont.h: Declare temporary Win32-only functions. Will presumably be replaced by some more better mechanism as 1.4 gets closer to release shape. * gdk/makefile.{cygwin,msc}: Update. * gdk/win32/*.c: Correct inclusions of the backend-specific and internal headers. Change code according to changes in these. Use gdk_drawable_*, not gdk_window_* where necessary. * gdk/win32/gdkdnd-win32.c: Use MISC selector for GDK_NOTE, not our old DND. * gdk/win32/gdkdrawable-win32.c (gdk_win32_draw_text): Don't try to interpret single characters as UTF-8. Thanks to Hans Breuer. Use correct function name in warning messages. * gdk/win32/gdkevents-win32.c: Use correct parameter lists for the GSourceFuncs gdk_event_prepare and gdk_event_check. (gdk_event_get_graphics_expose): Do implement, use PeekMessage. Thanks to Hans Breuer. (event_mask_string): Debugging function to print an GdkEventMask. (gdk_pointer_grab): Use it. * gdk/win32/gdkfont-win32.c: The Unicode subrange that the (old) book I used claimed was Hangul actually is CJK Unified Ideographs Extension A. Also, Hangul Syllables were missing. Improve logging. * gdk/win32/gdkgc-win32.c: Largish changes. * gdk/win32/gdkim-win32.c (gdk_set_locale): Use g_win32_getlocale() from GLib, and not setlocale() to get current locale name. * gdk/win32/gdkprivate-win32.h * gdk/win32/gdkwin32.h: Move stuff from gdkprivate-win32.h to gdkwin32.h, similarily as in the X11 backend. * gdk/win32/gdkwindow-win32.c (gdk_propagate_shapes): Bugfix, assignment was used instead of equals in if test. Thanks to Hans Breuer. * gdk/win32/makefile.{cygwin,msc} * gtk/makefile.{cygwin,msc}: Updates. Better kludge to get the path to the Win32 headers that works also with the mingw compiler. * gtk/gtkstyle.c: Include <string.h>.
2000-05-01 22:06:49 +00:00
#include "gdkprivate-win32.h"
1999-11-11 22:01:55 +00:00
#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 *ANDplane, *XORplane;
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);
ANDplane = g_malloc ((w/8) * h);
memset (ANDplane, 0xff, (w/8) * h);
XORplane = g_malloc ((w/8) * h);
memset (XORplane, 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 (ANDplane[pofs], bit);
if (data == 1)
SET_BIT (XORplane[pofs], bit);
}
}
}
#undef SET_BIT
#undef RESET_BIT
rv = CreateCursor (gdk_app_hmodule, cursors[i].hotx, cursors[i].hoty,
w, h, ANDplane, XORplane);
return rv;
}
1999-11-11 22:01:55 +00:00
GdkCursor*
gdk_cursor_new (GdkCursorType cursor_type)
{
GdkCursorPrivate *private;
GdkCursor *cursor;
HCURSOR hcursor;
1999-11-11 22:01:55 +00:00
hcursor = _gdk_win32_data_to_wcursor (cursor_type);
if (hcursor == NULL)
g_warning ("gdk_cursor_new: no cursor %d found", cursor_type);
1999-11-11 22:01:55 +00:00
else
GDK_NOTE (MISC, g_print ("gdk_cursor_new: %d: %#x\n",
cursor_type, (guint) hcursor));
1999-11-11 22:01:55 +00:00
private = g_new (GdkCursorPrivate, 1);
private->hcursor = hcursor;
1999-11-11 22:01:55 +00:00
cursor = (GdkCursor*) private;
cursor->type = cursor_type;
cursor->ref_count = 1;
1999-11-11 22:01:55 +00:00
return cursor;
}
static gboolean
color_is_white (GdkColor *color)
{
return (color->red == 0xFFFF
&& color->green == 0xFFFF
&& color->blue == 0xFFFF);
}
1999-11-11 22:01:55 +00:00
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;
1999-11-11 22:01:55 +00:00
GdkImage *source_image, *mask_image;
HCURSOR hcursor;
guchar *p, *q, *xor_mask, *and_mask;
1999-11-11 22:01:55 +00:00
gint width, height, cursor_width, cursor_height;
guchar residue;
gint ix, iy;
const gboolean bg_is_white = color_is_white (bg);
1999-11-11 22:01:55 +00:00
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);
1999-11-11 22:01:55 +00:00
source_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (source)->impl);
mask_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (mask)->impl);
1999-11-11 22:01:55 +00:00
g_return_val_if_fail (source_impl->width == mask_impl->width
&& source_impl->height == mask_impl->height,
1999-11-11 22:01:55 +00:00
NULL);
width = source_impl->width;
height = source_impl->height;
1999-11-11 22:01:55 +00:00
cursor_width = GetSystemMetrics (SM_CXCURSOR);
cursor_height = GetSystemMetrics (SM_CYCURSOR);
g_return_val_if_fail (width <= cursor_width && height <= cursor_height,
NULL);
1999-11-11 22:01:55 +00:00
residue = (1 << ((8-(width%8))%8)) - 1;
source_image = gdk_image_get (source, 0, 0, width, height);
mask_image = gdk_image_get (mask, 0, 0, width, height);
if (source_image->depth != 1 || mask_image->depth != 1)
{
gdk_image_unref (source_image);
gdk_image_unref (mask_image);
g_return_val_if_fail (source_image->depth == 1 && mask_image->depth == 1,
NULL);
1999-11-11 22:01:55 +00:00
}
/* 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.
1999-11-11 22:01:55 +00:00
*/
/* 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.
1999-11-11 22:01:55 +00:00
*/
for (iy = 0; iy < height; iy++)
{
p = (guchar *) source_image->mem + iy*source_image->bpl;
q = (guchar *) mask_image->mem + iy*mask_image->bpl;
for (ix = 0; ix < ((width-1)/8+1); ix++)
if (bg_is_white)
*p++ |= ~(*q++);
else
*p++ &= *q++;
1999-11-11 22:01:55 +00:00
}
/* XOR mask is initialized to zero */
xor_mask = g_malloc0 (cursor_width/8 * cursor_height);
1999-11-11 22:01:55 +00:00
for (iy = 0; iy < height; iy++)
{
p = (guchar *) source_image->mem + iy*source_image->bpl;
q = xor_mask + iy*cursor_width/8;
1999-11-11 22:01:55 +00:00
for (ix = 0; ix < ((width-1)/8+1); ix++)
if (bg_is_white)
*q++ = ~(*p++);
else
*q++ = *p++;
1999-11-11 22:01:55 +00:00
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);
1999-11-11 22:01:55 +00:00
for (iy = 0; iy < height; iy++)
{
p = (guchar *) mask_image->mem + iy*mask_image->bpl;
q = and_mask + iy*cursor_width/8;
1999-11-11 22:01:55 +00:00
for (ix = 0; ix < ((width-1)/8+1); ix++)
*q++ = ~(*p++);
1999-11-11 22:01:55 +00:00
q[-1] |= residue; /* Set left-over bits */
}
hcursor = CreateCursor (gdk_app_hmodule, x, y, cursor_width, cursor_height,
and_mask, xor_mask);
1999-11-11 22:01:55 +00:00
GDK_NOTE (MISC, g_print ("gdk_cursor_new_from_pixmap: "
"%#x (%dx%d) %#x (%dx%d) = %#x (%dx%d)\n",
(guint) GDK_PIXMAP_HBITMAP (source),
source_impl->width, source_impl->height,
(guint) GDK_PIXMAP_HBITMAP (mask),
mask_impl->width, mask_impl->height,
(guint) hcursor, cursor_width, cursor_height));
1999-11-11 22:01:55 +00:00
g_free (xor_mask);
g_free (and_mask);
1999-11-11 22:01:55 +00:00
gdk_image_unref (source_image);
gdk_image_unref (mask_image);
1999-11-11 22:01:55 +00:00
private = g_new (GdkCursorPrivate, 1);
private->hcursor = hcursor;
1999-11-11 22:01:55 +00:00
cursor = (GdkCursor*) private;
cursor->type = GDK_CURSOR_IS_PIXMAP;
cursor->ref_count = 1;
1999-11-11 22:01:55 +00:00
return cursor;
}
void
_gdk_cursor_destroy (GdkCursor *cursor)
1999-11-11 22:01:55 +00:00
{
GdkCursorPrivate *private;
g_return_if_fail (cursor != NULL);
private = (GdkCursorPrivate *) cursor;
GDK_NOTE (MISC, g_print ("_gdk_cursor_destroy: %#x\n",
(cursor->type == GDK_CURSOR_IS_PIXMAP) ? (guint) private->hcursor : 0));
1999-11-11 22:01:55 +00:00
if (!DestroyCursor (private->hcursor))
WIN32_API_FAILED ("DestroyCursor");
1999-11-11 22:01:55 +00:00
g_free (private);
}