From c06b1cc103b8e7da906db25988f5c94d6d64ad1f Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Tue, 7 Nov 2017 15:39:48 +0800 Subject: [PATCH] Win32: Re-work cursor handling Like the X11 and Wayland backends, re-work how the cursors are being handled. So, we use a hash table to cache up the HCURSORS that we create along the way. We still need to cache up the icon/cursor themes since this is something that is not part of Windows but was added on to support icon/cursor themes such as Adwaita on Windows, but should be in-line with what is going on in GdkCursor. Also, remove the _gdk_grab_cursor global variable in gdkprivate-win32.h, and replace it with another variable in the GdkWin32Display structure, to make things cleaner in the process. https://bugzilla.gnome.org/show_bug.cgi?id=773299 --- gdk/win32/gdkcursor-win32.c | 495 +++++++++++++++++----------------- gdk/win32/gdkdevice-virtual.c | 54 ++-- gdk/win32/gdkdisplay-win32.h | 5 +- gdk/win32/gdkevents-win32.c | 18 +- gdk/win32/gdkprivate-win32.h | 8 +- gdk/win32/gdkwin32display.h | 6 + gdk/win32/gdkwindow-win32.c | 24 +- 7 files changed, 323 insertions(+), 287 deletions(-) diff --git a/gdk/win32/gdkcursor-win32.c b/gdk/win32/gdkcursor-win32.c index 9e0b9fe474..e6eb29fe9a 100644 --- a/gdk/win32/gdkcursor-win32.c +++ b/gdk/win32/gdkcursor-win32.c @@ -22,6 +22,7 @@ #include "gdkscreen.h" #include "gdkcursor.h" #include "gdkwin32.h" +#include "gdktextureprivate.h" #include "gdkdisplay-win32.h" @@ -77,8 +78,8 @@ static DefaultCursor default_cursors[] = { }; static HCURSOR -hcursor_from_x_cursor (gint i, - GdkCursorType cursor_type) +hcursor_from_x_cursor (gint i, + const gchar *name) { gint j, x, y, ofs; HCURSOR rv; @@ -93,7 +94,7 @@ hcursor_from_x_cursor (gint i, xor_plane = g_malloc ((w/8) * h); memset (xor_plane, 0, (w/8) * h); - if (cursor_type != GDK_BLANK_CURSOR) + if (strcmp (name, "none") != 0) { #define SET_BIT(v,b) (v |= (1 << b)) @@ -142,7 +143,8 @@ hcursor_from_x_cursor (gint i, } static HCURSOR -win32_cursor_create_hcursor (Win32Cursor *cursor) +win32_cursor_create_hcursor (Win32Cursor *cursor, + const gchar *name) { HCURSOR result; @@ -174,7 +176,7 @@ win32_cursor_create_hcursor (Win32Cursor *cursor) break; case GDK_WIN32_CURSOR_CREATE: result = hcursor_from_x_cursor (cursor->xcursor_number, - cursor->cursor_type); + name); break; default: result = NULL; @@ -189,8 +191,7 @@ win32_cursor_new (GdkWin32CursorLoadType load_type, gint width, gint height, guint load_flags, - gint xcursor_number, - GdkCursorType cursor_type) + gint xcursor_number) { Win32Cursor *result; @@ -201,7 +202,6 @@ win32_cursor_new (GdkWin32CursorLoadType load_type, result->height = height; result->load_flags = load_flags; result->xcursor_number = xcursor_number; - result->cursor_type = cursor_type; return result; } @@ -243,7 +243,7 @@ win32_cursor_theme_load_from (Win32CursorTheme *theme, gchar *dot; Win32Cursor *cursor; - fullname = g_strconcat (dir, "/", filename, NULL); + fullname = g_build_filename (dir, filename, NULL); filenamew = g_utf8_to_utf16 (fullname, -1, NULL, NULL, NULL); g_free (fullname); @@ -269,8 +269,8 @@ win32_cursor_theme_load_from (Win32CursorTheme *theme, size, size, LR_LOADFROMFILE | (size == 0 ? LR_DEFAULTSIZE : 0), - 0, 0); + g_hash_table_insert (theme->named_cursors, cursor_name, cursor); } } @@ -289,13 +289,13 @@ win32_cursor_theme_load_from_dirs (Win32CursorTheme *theme, /* /share/icons */ for (i = 0; dirs[i]; i++) { - theme_dir = g_strconcat (dirs[i], "/icons/", name, "/cursors", NULL); + theme_dir = g_build_filename (dirs[i], "icons", name, "cursors", NULL); win32_cursor_theme_load_from (theme, size, theme_dir); g_free (theme_dir); } /* ~/.icons */ - theme_dir = g_strconcat (g_get_home_dir (), "/icons/", name, "/cursors", NULL); + theme_dir = g_build_filename (g_get_home_dir (), "icons", name, "cursors", NULL); win32_cursor_theme_load_from (theme, size, theme_dir); g_free (theme_dir); } @@ -324,7 +324,7 @@ win32_cursor_theme_load_system (Win32CursorTheme *theme, /* Fall back to X cursors, but only if we've got no theme cursor */ if (hcursor == NULL && g_hash_table_lookup (theme->named_cursors, cursors[i].name) == NULL) - hcursor = hcursor_from_x_cursor (i, cursors[i].type); + hcursor = hcursor_from_x_cursor (i, cursors[i].name); if (hcursor == NULL) continue; @@ -335,7 +335,6 @@ win32_cursor_theme_load_system (Win32CursorTheme *theme, size, size, LR_SHARED | (size == 0 ? LR_DEFAULTSIZE : 0), - 0, 0); g_hash_table_insert (theme->named_cursors, g_strdup (cursors[i].name), @@ -359,7 +358,6 @@ win32_cursor_theme_load_system (Win32CursorTheme *theme, size, size, LR_SHARED | (size == 0 ? LR_DEFAULTSIZE : 0), - 0, 0); g_hash_table_insert (theme->named_cursors, g_strdup (default_cursors[i].name), @@ -369,7 +367,7 @@ win32_cursor_theme_load_system (Win32CursorTheme *theme, Win32CursorTheme * win32_cursor_theme_load (const gchar *name, - gint size) + gint size) { Win32CursorTheme *result = g_new0 (Win32CursorTheme, 1); @@ -409,52 +407,52 @@ win32_cursor_theme_get_cursor (Win32CursorTheme *theme, return g_hash_table_lookup (theme->named_cursors, name); } -static HCURSOR -hcursor_from_type (GdkCursorType cursor_type) +static void +gdk_win32_cursor_remove_from_cache (gpointer data, GObject *cursor) { - gint i = 0; - - if (cursor_type != GDK_BLANK_CURSOR) - { - for (i = 0; i < G_N_ELEMENTS (cursors); i++) - if (cursors[i].type == cursor_type) - break; + GdkDisplay *display = data; + HCURSOR hcursor; - if (i >= G_N_ELEMENTS (cursors) || !cursors[i].name) - return NULL; + hcursor = g_hash_table_lookup (GDK_WIN32_DISPLAY (display)->cursors, cursor); - /* Use real Win32 cursor if possible */ - if (cursors[i].builtin) - return LoadImageA (NULL, cursors[i].builtin, IMAGE_CURSOR, 0, 0, - LR_SHARED | LR_DEFAULTSIZE); - } + if (GetCursor () == hcursor) + SetCursor (NULL); - return hcursor_from_x_cursor (i, cursor_type); + if (!DestroyCursor (hcursor)) + g_warning (G_STRLOC ": DestroyCursor (%p) failed: %lu", hcursor, GetLastError ()); } -struct _GdkWin32CursorClass -{ - GdkCursorClass cursor_class; -}; - -G_DEFINE_TYPE (GdkWin32Cursor, gdk_win32_cursor, GDK_TYPE_CURSOR) - -static void -_gdk_win32_cursor_finalize (GObject *object) +void +_gdk_win32_display_finalize_cursors (GdkWin32Display *display) { - GdkWin32Cursor *private = GDK_WIN32_CURSOR (object); + GHashTableIter iter; + gpointer cursor; - if (GetCursor () == private->hcursor) - SetCursor (NULL); + if (display->cursors) + { + g_hash_table_iter_init (&iter, display->cursors); + while (g_hash_table_iter_next (&iter, &cursor, NULL)) + g_object_weak_unref (G_OBJECT (cursor), + gdk_win32_cursor_remove_from_cache, + GDK_DISPLAY (display)); + g_hash_table_unref (display->cursors); + } - if (!DestroyCursor (private->hcursor)) - g_warning (G_STRLOC ": DestroyCursor (%p) failed: %lu", private->hcursor, GetLastError ()); + g_free (display->cursor_theme_name); - g_free (private->name); + if (display->cursor_theme) + win32_cursor_theme_destroy (display->cursor_theme); +} - G_OBJECT_CLASS (gdk_win32_cursor_parent_class)->finalize (object); +void +_gdk_win32_display_init_cursors (GdkWin32Display *display) +{ + display->cursors = g_hash_table_new (gdk_cursor_hash, + gdk_cursor_equal); + display->cursor_theme_name = g_strdup ("system"); } +/* This is where we use the names mapped to the equivilants that Windows define by default */ static HCURSOR hcursor_idc_from_name (const gchar *name) { @@ -479,7 +477,7 @@ hcursor_x_from_name (const gchar *name) for (i = 0; i < G_N_ELEMENTS (cursors); i++) if (cursors[i].name == NULL || strcmp (cursors[i].name, name) == 0) - return hcursor_from_x_cursor (i, cursors[i].type); + return hcursor_from_x_cursor (i, name); return NULL; } @@ -501,7 +499,7 @@ hcursor_from_theme (GdkDisplay *display, if (theme_cursor == NULL) return NULL; - return win32_cursor_create_hcursor (theme_cursor); + return win32_cursor_create_hcursor (theme_cursor, name); } static HCURSOR @@ -510,9 +508,6 @@ hcursor_from_name (GdkDisplay *display, { HCURSOR hcursor; - if (strcmp (name, "none") == 0) - return hcursor_from_type (GDK_BLANK_CURSOR); - /* Try current theme first */ hcursor = hcursor_from_theme (display, name); @@ -529,195 +524,196 @@ hcursor_from_name (GdkDisplay *display, return hcursor; } -static GdkCursor* -cursor_new_from_hcursor (GdkDisplay *display, - HCURSOR hcursor, - const gchar *name, - GdkCursorType cursor_type) +/* Create a blank cursor */ +static HCURSOR +create_blank_cursor (void) { - GdkWin32Cursor *private; - GdkCursor *cursor; + gint w, h; + guchar *and_plane, *xor_plane; + HCURSOR rv; - private = g_object_new (GDK_TYPE_WIN32_CURSOR, - "display", display, - NULL); + w = GetSystemMetrics (SM_CXCURSOR); + h = GetSystemMetrics (SM_CYCURSOR); - private->name = g_strdup (name); + 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); - private->hcursor = hcursor; - cursor = (GdkCursor*) private; + rv = CreateCursor (_gdk_app_hmodule, 0, 0, + w, h, and_plane, xor_plane); - return cursor; + if (rv == NULL) + WIN32_API_FAILED ("CreateCursor"); + + return rv; } -static gboolean -_gdk_win32_cursor_update (GdkWin32Display *win32_display, - GdkWin32Cursor *cursor) +static HCURSOR +gdk_win32_cursor_create_for_name (GdkDisplay *display, + const gchar *name) { HCURSOR hcursor = NULL; - Win32CursorTheme *theme; - Win32Cursor *theme_cursor; + GdkCursor *result; + GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - /* Do nothing if this is not a named cursor. */ - if (cursor->name == NULL) - return FALSE; + /* Blank cursor case */ + if (strcmp (name, "none") == 0) + return create_blank_cursor (); - theme = _gdk_win32_display_get_cursor_theme (win32_display); - theme_cursor = win32_cursor_theme_get_cursor (theme, cursor->name); + hcursor = hcursor_from_name (display, name); - if (theme_cursor != NULL) - hcursor = win32_cursor_create_hcursor (theme_cursor); + /* allow to load named cursor resources linked into the executable */ + if (!hcursor) + hcursor = LoadCursor (_gdk_app_hmodule, name); if (hcursor == NULL) - { - g_warning (G_STRLOC ": Unable to load %s from the cursor theme", cursor->name); - - hcursor = hcursor_idc_from_name (cursor->name); - - if (hcursor == NULL) - hcursor = hcursor_x_from_name (cursor->name); - - if (hcursor == NULL) - return FALSE; - } + return NULL; - if (GetCursor () == cursor->hcursor) - SetCursor (hcursor); + return hcursor; +} - if (!DestroyCursor (cursor->hcursor)) - g_warning (G_STRLOC ": DestroyCursor (%p) failed: %lu", cursor->hcursor, GetLastError ()); +static HICON +pixbuf_to_hicon (GdkPixbuf *pixbuf, + gboolean is_icon, + gint x, + gint y); - cursor->hcursor = hcursor; +static HCURSOR +gdk_win32_cursor_create_for_texture (GdkDisplay *display, + GdkTexture *texture, + int x, + int y) +{ + cairo_surface_t *surface; + GdkPixbuf *pixbuf; + gint width, height; + HICON icon; - return TRUE; + surface = gdk_texture_download_surface (texture); + width = cairo_image_surface_get_width (surface); + height = cairo_image_surface_get_height (surface); + + pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height); + + icon = pixbuf_to_hicon (pixbuf, TRUE, 0, 0); + + g_object_unref (pixbuf); + + return (HCURSOR)icon; } -void -_gdk_win32_display_update_cursors (GdkWin32Display *display) +GdkCursor * +gdk_win32_display_cursor_from_hcursor (GdkDisplay *display, + HCURSOR hcursor) { GHashTableIter iter; - const char *name; - GdkWin32Cursor *cursor; - - g_hash_table_iter_init (&iter, display->cursor_cache); + gpointer cursor_current, hcursor_current; + + GdkCursor *cursor = NULL; + GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &cursor)) - _gdk_win32_cursor_update (display, cursor); -} + if (win32_display->cursors) + { + g_hash_table_iter_init (&iter, win32_display->cursors); + while (g_hash_table_iter_next (&iter, &cursor_current, &hcursor_current)) + if ((HCURSOR)hcursor_current == hcursor) + { + cursor = (GdkCursor*) cursor_current; + break; + } + } -void -_gdk_win32_display_init_cursors (GdkWin32Display *display) -{ - display->cursor_cache = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - g_object_unref); - display->cursor_theme_name = g_strdup ("system"); + return cursor; } -void -_gdk_win32_display_finalize_cursors (GdkWin32Display *display) +HCURSOR +_gdk_win32_display_get_cursor_for_surface (GdkDisplay *display, + cairo_surface_t *surface, + gdouble x, + gdouble y) { - g_free (display->cursor_theme_name); - - if (display->cursor_theme) - win32_cursor_theme_destroy (display->cursor_theme); + HCURSOR hcursor; + GdkPixbuf *pixbuf; + gint width, height; - g_hash_table_destroy (display->cursor_cache); -} + g_return_val_if_fail (surface != NULL, NULL); + width = cairo_image_surface_get_width (surface); + height = cairo_image_surface_get_height (surface); + pixbuf = gdk_pixbuf_get_from_surface (surface, + 0, + 0, + width, + height); -GdkCursor* -_gdk_win32_display_get_cursor_for_type (GdkDisplay *display, - GdkCursorType cursor_type) -{ - GEnumClass *enum_class; - GEnumValue *enum_value; - gchar *cursor_name; - HCURSOR hcursor; - GdkCursor *result; - GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); + g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL); + g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL); - enum_class = g_type_class_ref (GDK_TYPE_CURSOR_TYPE); - enum_value = g_enum_get_value (enum_class, cursor_type); - cursor_name = g_strdup (enum_value->value_nick); - g_strdelimit (cursor_name, "-", '_'); - g_type_class_unref (enum_class); + hcursor = _gdk_win32_pixbuf_to_hcursor (pixbuf, x, y); - result = g_hash_table_lookup (win32_display->cursor_cache, cursor_name); - if (result) - { - g_free (cursor_name); - return g_object_ref (result); - } + g_object_unref (pixbuf); + + return hcursor; +} - hcursor = hcursor_from_name (display, cursor_name); +static gboolean +_gdk_win32_cursor_update (GdkWin32Display *win32_display, + GdkCursor *cursor, + HCURSOR hcursor) +{ + HCURSOR hcursor_new = NULL; + Win32CursorTheme *theme; + Win32Cursor *theme_cursor; - if (hcursor == NULL) - hcursor = hcursor_from_type (cursor_type); + const gchar *name = gdk_cursor_get_name (cursor); - if (hcursor == NULL) - g_warning ("gdk_cursor_new_for_display: no cursor %d found", cursor_type); - else - GDK_NOTE (CURSOR, g_print ("gdk_cursor_new_for_display: %d: %p\n", - cursor_type, hcursor)); + /* Do nothing if this is not a named cursor. */ + if (name == NULL) + return FALSE; - result = cursor_new_from_hcursor (display, hcursor, cursor_name, cursor_type); + theme = _gdk_win32_display_get_cursor_theme (win32_display); + theme_cursor = win32_cursor_theme_get_cursor (theme, name); - if (result == NULL) - return result; + if (theme_cursor != NULL) + hcursor_new = win32_cursor_create_hcursor (theme_cursor, name); - /* Blank cursor case */ - if (cursor_type == GDK_BLANK_CURSOR || - !cursor_name || - g_str_equal (cursor_name, "none") || - g_str_equal (cursor_name, "blank_cursor")) + if (hcursor_new == NULL) { - g_free (cursor_name); - return result; - } + g_warning (G_STRLOC ": Unable to load %s from the cursor theme", name); - g_hash_table_insert (win32_display->cursor_cache, - cursor_name, - g_object_ref (result)); + hcursor_new = hcursor_idc_from_name (name); - return result; -} + if (hcursor_new == NULL) + hcursor_new = hcursor_x_from_name (name); -GdkCursor* -_gdk_win32_display_get_cursor_for_name (GdkDisplay *display, - const gchar *name) -{ - HCURSOR hcursor = NULL; - GdkCursor *result; - GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); + if (hcursor_new == NULL) + return FALSE; + } - result = g_hash_table_lookup (win32_display->cursor_cache, name); - if (result) - return g_object_ref (result); + if (GetCursor () == hcursor) + SetCursor (hcursor_new); - hcursor = hcursor_from_name (display, name); + if (!DestroyCursor (hcursor)) + g_warning (G_STRLOC ": DestroyCursor (%p) failed: %lu", hcursor, GetLastError ()); - /* allow to load named cursor resources linked into the executable */ - if (!hcursor) - hcursor = LoadCursor (_gdk_app_hmodule, name); + g_hash_table_replace (win32_display->cursors, cursor, hcursor_new); - if (hcursor == NULL) - return NULL; - - result = cursor_new_from_hcursor (display, hcursor, name, GDK_X_CURSOR); + return TRUE; +} - /* Blank cursor case */ - if (!name || - g_str_equal (name, "none") || - g_str_equal (name, "blank_cursor")) - return result; +void +_gdk_win32_display_update_cursors (GdkWin32Display *display) +{ + GHashTableIter iter; + GdkCursor *cursor; + HCURSOR hcursor; - g_hash_table_insert (win32_display->cursor_cache, - g_strdup (name), - g_object_ref (result)); + g_hash_table_iter_init (&iter, display->cursors); - return result; + while (g_hash_table_iter_next (&iter, (gpointer *) &cursor, &hcursor)) + _gdk_win32_cursor_update (display, cursor, hcursor); } GdkPixbuf * @@ -896,38 +892,6 @@ gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon, return pixbuf; } -GdkCursor * -_gdk_win32_display_get_cursor_for_surface (GdkDisplay *display, - cairo_surface_t *surface, - gdouble x, - gdouble y) -{ - HCURSOR hcursor; - GdkPixbuf *pixbuf; - gint width, height; - - g_return_val_if_fail (surface != NULL, NULL); - - width = cairo_image_surface_get_width (surface); - height = cairo_image_surface_get_height (surface); - pixbuf = gdk_pixbuf_get_from_surface (surface, - 0, - 0, - width, - height); - - g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); - g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL); - g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL); - - hcursor = _gdk_win32_pixbuf_to_hcursor (pixbuf, x, y); - - g_object_unref (pixbuf); - if (!hcursor) - return NULL; - return cursor_new_from_hcursor (display, hcursor, NULL, GDK_CURSOR_IS_PIXMAP); -} - gboolean _gdk_win32_display_supports_cursor_alpha (GdkDisplay *display) { @@ -1252,9 +1216,24 @@ pixbuf_to_hicon (GdkPixbuf *pixbuf, } HICON -_gdk_win32_pixbuf_to_hicon (GdkPixbuf *pixbuf) +_gdk_win32_texture_to_hicon (GdkTexture *texture) { - return pixbuf_to_hicon (pixbuf, TRUE, 0, 0); + cairo_surface_t *surface; + GdkPixbuf *pixbuf; + gint width, height; + HICON icon; + + surface = gdk_texture_download_surface (texture); + width = cairo_image_surface_get_width (surface); + height = cairo_image_surface_get_height (surface); + + pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height); + + icon = pixbuf_to_hicon (pixbuf, TRUE, 0, 0); + + g_object_unref (pixbuf); + + return icon; } HICON @@ -1265,20 +1244,54 @@ _gdk_win32_pixbuf_to_hcursor (GdkPixbuf *pixbuf, return pixbuf_to_hicon (pixbuf, FALSE, x_hotspot, y_hotspot); } -HICON -gdk_win32_pixbuf_to_hicon_libgtk_only (GdkPixbuf *pixbuf) -{ - return _gdk_win32_pixbuf_to_hicon (pixbuf); -} -static void -gdk_win32_cursor_init (GdkWin32Cursor *cursor) -{ -} -static void -gdk_win32_cursor_class_init(GdkWin32CursorClass *klass) + +/** + * gdk_win32_display_get_hcursor: + * @display: (type GdkWin32Display): a #GdkDisplay + * @cursor: a #GdkCursor. + * + * Returns the Win32 HCURSOR belonging to a #GdkCursor, potentially + * creating the cursor. + * + * Be aware that the returned cursor may not be unique to @cursor. + * It may for example be shared with its fallback cursor. + * + * Returns: a Win32 HCURSOR. + **/ +HCURSOR +gdk_win32_display_get_hcursor (GdkDisplay *display, + GdkCursor *cursor) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); + HCURSOR hcursor; + + g_return_val_if_fail (cursor != NULL, NULL); + + if (gdk_display_is_closed (display)) + return NULL; + + hcursor = g_hash_table_lookup (win32_display->cursors, cursor); + if (hcursor != NULL) + return hcursor; - object_class->finalize = _gdk_win32_cursor_finalize; + if (gdk_cursor_get_name (cursor)) + hcursor = gdk_win32_cursor_create_for_name (display, gdk_cursor_get_name (cursor)); + else + hcursor = gdk_win32_cursor_create_for_texture (display, + gdk_cursor_get_texture (cursor), + gdk_cursor_get_hotspot_x (cursor), + gdk_cursor_get_hotspot_y (cursor)); + + if (hcursor != NULL) + { + g_object_weak_ref (G_OBJECT (cursor), gdk_win32_cursor_remove_from_cache, display); + g_hash_table_insert (win32_display->cursors, cursor, hcursor); + return hcursor; + } + + if (gdk_cursor_get_fallback (cursor)) + return gdk_win32_display_get_hcursor (display, gdk_cursor_get_fallback (cursor)); + + return NULL; } diff --git a/gdk/win32/gdkdevice-virtual.c b/gdk/win32/gdkdevice-virtual.c index 57ee4b59af..fb52a68446 100644 --- a/gdk/win32/gdkdevice-virtual.c +++ b/gdk/win32/gdkdevice-virtual.c @@ -26,6 +26,7 @@ #include "gdkdevice-virtual.h" #include "gdkdevice-win32.h" #include "gdkwin32.h" +#include "gdkdisplay-win32.h" G_DEFINE_TYPE (GdkDeviceVirtual, gdk_device_virtual, GDK_TYPE_DEVICE) @@ -89,11 +90,20 @@ gdk_device_virtual_get_state (GdkDevice *device, static void gdk_device_virtual_set_window_cursor (GdkDevice *device, - GdkWindow *window, - GdkCursor *cursor) + GdkWindow *window, + GdkCursor *cursor) { - if (cursor != NULL && GDK_WIN32_CURSOR (cursor)->hcursor != NULL) - SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor); + if (cursor != NULL) + { + GdkDisplay *display = gdk_window_get_display (window); + HCURSOR hcursor = NULL; + + if (display != NULL) + hcursor = gdk_win32_display_get_hcursor (display, cursor); + + if (hcursor != NULL) + SetCursor (hcursor); + } } static void @@ -136,18 +146,19 @@ gdk_device_virtual_grab (GdkDevice *device, if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD) { - if (_gdk_win32_grab_cursor != NULL) - { - if (GetCursor () == GDK_WIN32_CURSOR (_gdk_win32_grab_cursor)->hcursor) - SetCursor (NULL); - } + GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_device_get_display (device)); + if (display->grab_cursor != NULL) + { + if (GetCursor () == g_hash_table_lookup (display->cursors, display->grab_cursor)) + SetCursor (NULL); + } - g_set_object (&_gdk_win32_grab_cursor, cursor); + g_set_object (&display->grab_cursor, cursor); - if (_gdk_win32_grab_cursor != NULL) - SetCursor (GDK_WIN32_CURSOR (_gdk_win32_grab_cursor)->hcursor); + if (display->grab_cursor != NULL) + SetCursor (g_hash_table_lookup (display->cursors, display->grab_cursor)); else - SetCursor (LoadCursor (NULL, IDC_ARROW)); + SetCursor (LoadCursor (NULL, IDC_ARROW)); SetCapture (GDK_WINDOW_HWND (window)); } @@ -157,12 +168,14 @@ gdk_device_virtual_grab (GdkDevice *device, static void gdk_device_virtual_ungrab (GdkDevice *device, - guint32 time_) + guint32 time_) { GdkDeviceGrabInfo *info; GdkDisplay *display; + GdkWin32Display *win32_display; display = gdk_device_get_display (device); + win32_display = GDK_WIN32_DISPLAY (display); info = _gdk_display_get_last_device_grab (display, device); if (info) @@ -170,12 +183,13 @@ gdk_device_virtual_ungrab (GdkDevice *device, if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD) { - if (_gdk_win32_grab_cursor != NULL) - { - if (GetCursor () == GDK_WIN32_CURSOR (_gdk_win32_grab_cursor)->hcursor) - SetCursor (NULL); - } - g_clear_object (&_gdk_win32_grab_cursor); + if (win32_display->grab_cursor != NULL) + { + if (GetCursor () == g_hash_table_lookup (win32_display->cursors, win32_display->grab_cursor)) + SetCursor (NULL); + } + + g_clear_object (&win32_display->grab_cursor); ReleaseCapture (); } diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h index 9d7a18dd52..ea3e2dff57 100644 --- a/gdk/win32/gdkdisplay-win32.h +++ b/gdk/win32/gdkdisplay-win32.h @@ -64,7 +64,6 @@ struct _GdkWin32Display Win32CursorTheme *cursor_theme; gchar *cursor_theme_name; int cursor_theme_size; - GHashTable *cursor_cache; HWND hwnd; HWND clipboard_hwnd; @@ -90,6 +89,10 @@ struct _GdkWin32Display GdkWin32ShcoreFuncs shcore_funcs; GdkWin32User32DPIFuncs user32_dpi_funcs; + + /* Cursor Items (GdkCursor->HCURSOR) */ + GHashTable *cursors; + GdkCursor *grab_cursor; }; struct _GdkWin32DisplayClass diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 7945ed42a6..9e21c68746 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -108,8 +108,6 @@ static gboolean gdk_event_dispatch (GSource *source, extern gint _gdk_input_ignore_core; -GdkCursor *_gdk_win32_grab_cursor; - typedef struct { GSource source; @@ -2136,6 +2134,7 @@ gdk_event_translate (MSG *msg, GdkDisplay *display; GdkWindow *window = NULL; GdkWindowImplWin32 *impl; + GdkWin32Display *win32_display; GdkWindow *new_window; @@ -3063,15 +3062,20 @@ gdk_event_translate (MSG *msg, if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT) break; - if (grab_window != NULL && _gdk_win32_grab_cursor != NULL) - cursor = _gdk_win32_grab_cursor; + if (grab_window != NULL) + { + win32_display = GDK_WIN32_DISPLAY (gdk_window_get_display (grab_window)); + + if (win32_display->grab_cursor != NULL) + cursor = win32_display->grab_cursor; + } else - cursor = NULL; + cursor = NULL; if (cursor != NULL) { - GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", cursor)); - SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor); + GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", cursor)); + SetCursor (g_hash_table_lookup (win32_display->cursors, cursor)); return_val = TRUE; *ret_valp = TRUE; } diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 47e5759c93..cb74e6679b 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -132,7 +132,6 @@ struct _GdkWin32Cursor { GdkCursor cursor; - gchar *name; HCURSOR hcursor; }; @@ -354,15 +353,13 @@ extern GHashTable *_format_atom_table; /* Hold the result of a delayed rendering */ extern HGLOBAL _delayed_rendering_data; -extern GdkCursor *_gdk_win32_grab_cursor; - HGLOBAL _gdk_win32_selection_convert_to_dib (HGLOBAL hdata, GdkAtom target); /* Convert a pixbuf to an HICON (or HCURSOR). Supports alpha under * Windows XP, thresholds alpha otherwise. */ -HICON _gdk_win32_pixbuf_to_hicon (GdkPixbuf *pixbuf); +HICON _gdk_win32_texture_to_hicon (GdkTexture *texture); HICON _gdk_win32_pixbuf_to_hcursor (GdkPixbuf *pixbuf, gint x_hotspot, gint y_hotspot); @@ -370,6 +367,8 @@ HICON _gdk_win32_pixbuf_to_hcursor (GdkPixbuf *pixbuf, void _gdk_win32_display_init_cursors (GdkWin32Display *display); void _gdk_win32_display_finalize_cursors (GdkWin32Display *display); void _gdk_win32_display_update_cursors (GdkWin32Display *display); +GdkCursor *_gdk_win32_display_get_cursor_for_name (GdkDisplay *display, const gchar* cursor_name); +GdkCursor *gdk_win32_display_cursor_from_hcursor (GdkDisplay *display, HCURSOR hcursor); typedef struct _Win32CursorTheme Win32CursorTheme; @@ -393,7 +392,6 @@ struct _Win32Cursor { gint height; guint load_flags; gint xcursor_number; - GdkCursorType cursor_type; }; Win32CursorTheme *win32_cursor_theme_load (const gchar *name, diff --git a/gdk/win32/gdkwin32display.h b/gdk/win32/gdkwin32display.h index df2d98537c..5ef92dc6a9 100644 --- a/gdk/win32/gdkwin32display.h +++ b/gdk/win32/gdkwin32display.h @@ -31,6 +31,8 @@ #include +#include + G_BEGIN_DECLS #ifdef GDK_COMPILATION @@ -55,6 +57,10 @@ void gdk_win32_display_set_cursor_theme (GdkDisplay *display, const gchar *name, gint size); +GDK_AVAILABLE_IN_3_94 +HCURSOR gdk_win32_display_get_hcursor (GdkDisplay *display, + GdkCursor *cursor); + G_END_DECLS #endif /* __GDK_WIN32_DISPLAY_H__ */ diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 11ccec0ded..bef238cf20 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -688,7 +688,7 @@ _gdk_win32_display_create_window_impl (GdkDisplay *display, (window->window_type == GDK_WINDOW_TEMP ? "TEMP" : "???")), (attributes->wclass == GDK_INPUT_OUTPUT ? "" : "input-only"))); - hparent = GDK_WINDOW_HWND (real_parent); + hparent = (real_parent != NULL) ? GDK_WINDOW_HWND (real_parent) : NULL; impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL); impl->wrapper = GDK_WINDOW (window); @@ -725,7 +725,7 @@ _gdk_win32_display_create_window_impl (GdkDisplay *display, hparent = GetDesktopWindow (); } /* Children of foreign windows aren't toplevel windows */ - if (GDK_WINDOW_TYPE (real_parent) == GDK_WINDOW_FOREIGN) + if (real_parent != NULL && GDK_WINDOW_TYPE (real_parent) == GDK_WINDOW_FOREIGN) { dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN; } @@ -744,7 +744,9 @@ _gdk_win32_display_create_window_impl (GdkDisplay *display, case GDK_WINDOW_TEMP: /* A temp window is not necessarily a top level window */ - dwStyle = (real_parent == NULL || gdk_win32_display_get_root_window (display) == real_parent) ? WS_POPUP : WS_CHILDWINDOW); + dwStyle = (real_parent == NULL || + gdk_win32_display_get_root_window (display) == real_parent) ? + WS_POPUP : WS_CHILDWINDOW; dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS; dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; offset_x = _gdk_offset_x; @@ -2005,8 +2007,6 @@ gdk_win32_window_get_geometry (GdkWindow *window, API_CALL (GetClientRect, (GDK_WINDOW_HWND (window), &rect)); - if (!window_is_root) - { POINT pt; GdkWindow *parent = gdk_window_get_parent (window); @@ -2033,7 +2033,6 @@ gdk_win32_window_get_geometry (GdkWindow *window, rect.right += _gdk_offset_x * impl->window_scale; rect.bottom += _gdk_offset_y * impl->window_scale; } - } if (x) *x = rect.left / impl->window_scale; @@ -2246,7 +2245,6 @@ gdk_win32_window_set_icon_list (GdkWindow *window, GList *textures) { GdkTexture *big_texture, *small_texture; - GdkPixbuf *big_pixbuf, *small_pixbuf; gint big_diff, small_diff; gint big_w, big_h, small_w, small_h; gint w, h; @@ -2273,9 +2271,9 @@ gdk_win32_window_set_icon_list (GdkWindow *window, big_diff = 0; small_diff = 0; - for (l = textures; l; l = l->next) + for (GList *l = textures; l; l = l->next) { - texture = l->data; + GdkTexture *texture = l->data; w = gdk_texture_get_width (texture); h = gdk_texture_get_height (texture); @@ -2301,10 +2299,10 @@ gdk_win32_window_set_icon_list (GdkWindow *window, } /* Create the icons */ - big_hicon = gdk_win32_texture_to_hicon (big_texture); - g_object_unref (big_pixbuf); + big_hicon = _gdk_win32_texture_to_hicon (big_texture); + g_object_unref (big_texture); small_hicon = _gdk_win32_texture_to_hicon (small_texture); - g_object_unref (small_pixbuf); + g_object_unref (small_texture); /* Set the icons */ SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, @@ -4399,7 +4397,7 @@ setup_drag_move_resize_context (GdkWindow *window, cursor_name = get_cursor_name_from_op (op, edge); - context->cursor = _gdk_win32_display_get_cursor_for_name (display, cursor_name); + context->cursor = gdk_cursor_new_from_name (cursor_name, NULL); pointer_window = child_window_at_coordinates (window, root_x, root_y); -- 2.30.2