[gtk+] Win32: Re-work cursor handling



commit c06b1cc103b8e7da906db25988f5c94d6d64ad1f
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Tue Nov 7 15:39:48 2017 +0800

    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 9e0b9fe..e6eb29f 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,
   /* <prefix>/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 57ee4b5..fb52a68 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 9d7a18d..ea3e2df 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 7945ed4..9e21c68 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 47e5759..cb74e66 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 df2d985..5ef92dc 100644
--- a/gdk/win32/gdkwin32display.h
+++ b/gdk/win32/gdkwin32display.h
@@ -31,6 +31,8 @@
 
 #include <gdk/gdk.h>
 
+#include <windows.h>
+
 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 11ccec0..bef238c 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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]