[gtk+] gdk: Add gdk_cursor_get_surface()



commit 71fe43543c765f12b22e7c6508ed4d58ea5075a6
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Aug 6 16:21:05 2013 +0200

    gdk: Add gdk_cursor_get_surface()
    
    We want a surface so we can properly represent the scale factor for it.
    All backends are converted to use surfaces and we reimplement the
    backwards compat code in the generic code.

 gdk/broadway/gdkcursor-broadway.c |   12 ++++--
 gdk/gdkcursor.c                   |   73 ++++++++++++++++++++++++++++++++++++-
 gdk/gdkcursor.h                   |    4 ++
 gdk/gdkcursorprivate.h            |    4 ++-
 gdk/quartz/gdkcursor-quartz.c     |   12 ++++--
 gdk/wayland/gdkcursor-wayland.c   |    8 +++--
 gdk/win32/gdkcursor-win32.c       |   32 +++++++++++-----
 gdk/x11/gdkcursor-x11.c           |   66 ++++++++++++++++++---------------
 8 files changed, 158 insertions(+), 53 deletions(-)
---
diff --git a/gdk/broadway/gdkcursor-broadway.c b/gdk/broadway/gdkcursor-broadway.c
index 92acbda..72fc84e 100644
--- a/gdk/broadway/gdkcursor-broadway.c
+++ b/gdk/broadway/gdkcursor-broadway.c
@@ -51,7 +51,9 @@ struct _GdkBroadwayCursorClass
 
 G_DEFINE_TYPE (GdkBroadwayCursor, gdk_broadway_cursor, GDK_TYPE_CURSOR)
 
-static GdkPixbuf* gdk_broadway_cursor_get_image (GdkCursor *cursor);
+static cairo_surface_t * gdk_broadway_cursor_get_surface (GdkCursor *cursor,
+                                                         gdouble   *x_hot,
+                                                         gdouble   *y_hot);
 
 static void
 gdk_broadway_cursor_finalize (GObject *object)
@@ -67,7 +69,7 @@ gdk_broadway_cursor_class_init (GdkBroadwayCursorClass *xcursor_class)
 
   object_class->finalize = gdk_broadway_cursor_finalize;
 
-  cursor_class->get_image = gdk_broadway_cursor_get_image;
+  cursor_class->get_surface = gdk_broadway_cursor_get_surface;
 }
 
 static void
@@ -99,8 +101,10 @@ _gdk_broadway_display_get_cursor_for_type (GdkDisplay    *display,
   return GDK_CURSOR (private);
 }
 
-static GdkPixbuf*
-gdk_broadway_cursor_get_image (GdkCursor *cursor)
+static cairo_surface_t *
+gdk_broadway_cursor_get_surface (GdkCursor *cursor,
+                                gdouble *x_hot,
+                                gdouble *y_hot)
 {
   g_return_val_if_fail (cursor != NULL, NULL);
 
diff --git a/gdk/gdkcursor.c b/gdk/gdkcursor.c
index 0b2b80d..d182591 100644
--- a/gdk/gdkcursor.c
+++ b/gdk/gdkcursor.c
@@ -24,12 +24,16 @@
 
 #include "config.h"
 
+#define GDK_PIXBUF_ENABLE_BACKEND
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
 #include "gdkcursor.h"
 #include "gdkcursorprivate.h"
 #include "gdkdisplayprivate.h"
 #include "gdkintl.h"
 #include "gdkinternals.h"
 
+#include <math.h>
 
 /**
  * SECTION:cursors
@@ -389,7 +393,74 @@ gdk_cursor_get_display (GdkCursor *cursor)
 GdkPixbuf*  
 gdk_cursor_get_image (GdkCursor *cursor)
 {
+  int w, h;
+  cairo_surface_t *surface;
+  GdkPixbuf *pixbuf;
+  gchar buf[32];
+  double x_hot, y_hot;
+  double x_scale, y_scale;
+
+  g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL);
+
+  surface = gdk_cursor_get_surface (cursor, &x_hot, &y_hot);
+  if (surface == NULL)
+    return NULL;
+ 
+  w = cairo_image_surface_get_width (surface);
+  h = cairo_image_surface_get_height (surface);
+
+  x_scale = y_scale = 1;
+#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
+  cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
+#endif
+
+  pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, w, h);
+  cairo_surface_destroy (surface);
+
+  if (x_scale != 1)
+    {
+      GdkPixbuf *old;
+
+      old = pixbuf;
+      pixbuf = gdk_pixbuf_scale_simple (old,
+                                       w / x_scale, h / y_scale,
+                                       GDK_INTERP_HYPER);
+      g_object_unref (old);
+    }
+
+  
+  g_snprintf (buf, 32, "%d", (int)x_hot);
+  gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
+
+  g_snprintf (buf, 32, "%d", (int)y_hot);
+  gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
+
+  return pixbuf;
+}
+
+/**
+ * gdk_cursor_get_surface:
+ * @cursor: a #GdkCursor
+ * @x_hot: Location to store the hotspot x position, or %NULL
+ * @y_hot: Location to store the hotspot y position, or %NULL
+ *
+ * Returns a #cairo_surface_t (image surface) with the image used to display the cursor.
+ *
+ * Note that depending on the capabilities of the windowing system and
+ * on the cursor, GDK may not be able to obtain the image data. In this
+ * case, %NULL is returned.
+ *
+ * Returns: (transfer full): a #cairo_surface_t representing @cursor, or %NULL
+ *
+ * Since: 3.10
+ */
+cairo_surface_t *
+gdk_cursor_get_surface (GdkCursor *cursor,
+                       gdouble *x_hot,
+                       gdouble *y_hot)
+{
   g_return_val_if_fail (GDK_IS_CURSOR (cursor), NULL);
 
-  return GDK_CURSOR_GET_CLASS (cursor)->get_image (cursor);
+  return GDK_CURSOR_GET_CLASS (cursor)->get_surface (cursor,
+                                                    x_hot, y_hot);
 }
diff --git a/gdk/gdkcursor.h b/gdk/gdkcursor.h
index c526101..50880b3 100644
--- a/gdk/gdkcursor.h
+++ b/gdk/gdkcursor.h
@@ -239,6 +239,10 @@ GDK_DEPRECATED_IN_3_0_FOR(g_object_unref)
 void        gdk_cursor_unref             (GdkCursor       *cursor);
 GDK_AVAILABLE_IN_ALL
 GdkPixbuf*  gdk_cursor_get_image         (GdkCursor       *cursor);
+GDK_AVAILABLE_IN_3_10
+cairo_surface_t *gdk_cursor_get_surface  (GdkCursor       *cursor,
+                                         gdouble         *x_hot,
+                                         gdouble         *y_hot);
 GDK_AVAILABLE_IN_ALL
 GdkCursorType gdk_cursor_get_cursor_type (GdkCursor       *cursor);
 
diff --git a/gdk/gdkcursorprivate.h b/gdk/gdkcursorprivate.h
index e637d3d..15dbe03 100644
--- a/gdk/gdkcursorprivate.h
+++ b/gdk/gdkcursorprivate.h
@@ -47,7 +47,9 @@ struct _GdkCursorClass
 {
   GObjectClass parent_class;
 
-  GdkPixbuf *   (* get_image)   (GdkCursor *    cursor);
+  cairo_surface_t * (* get_surface) (GdkCursor *cursor,
+                                    gdouble   *x_hot,
+                                    gdouble   *y_hot);
 };
 
 G_END_DECLS
diff --git a/gdk/quartz/gdkcursor-quartz.c b/gdk/quartz/gdkcursor-quartz.c
index 7e5adc5..1b1ed3e 100644
--- a/gdk/quartz/gdkcursor-quartz.c
+++ b/gdk/quartz/gdkcursor-quartz.c
@@ -284,7 +284,9 @@ _gdk_quartz_display_get_cursor_for_name (GdkDisplay  *display,
 
 G_DEFINE_TYPE (GdkQuartzCursor, gdk_quartz_cursor, GDK_TYPE_CURSOR)
 
-static GdkPixbuf *gdk_quartz_cursor_get_image (GdkCursor *cursor);
+static cairo_surface_t *gdk_quartz_cursor_get_surface (GdkCursor *cursor,
+                                                      gdouble *x_hot,
+                                                      gdouble *y_hot);
 
 static void
 gdk_quartz_cursor_finalize (GObject *object)
@@ -304,7 +306,7 @@ gdk_quartz_cursor_class_init (GdkQuartzCursorClass *quartz_cursor_class)
 
   object_class->finalize = gdk_quartz_cursor_finalize;
 
-  cursor_class->get_image = gdk_quartz_cursor_get_image;
+  cursor_class->get_surface = gdk_quartz_cursor_get_surface;
 }
 
 static void
@@ -360,8 +362,10 @@ _gdk_quartz_cursor_get_ns_cursor (GdkCursor *cursor)
   return cursor_private->nscursor;
 }
 
-static GdkPixbuf *
-gdk_quartz_cursor_get_image (GdkCursor *cursor)
+static cairo_surface_t *
+gdk_quartz_cursor_get_surface (GdkCursor *cursor,
+                              gdouble *x_hot,
+                              gdouble *y_hot)
 {
   /* FIXME: Implement */
   return NULL;
diff --git a/gdk/wayland/gdkcursor-wayland.c b/gdk/wayland/gdkcursor-wayland.c
index 25a86de..035106f 100644
--- a/gdk/wayland/gdkcursor-wayland.c
+++ b/gdk/wayland/gdkcursor-wayland.c
@@ -174,8 +174,10 @@ gdk_wayland_cursor_finalize (GObject *object)
   G_OBJECT_CLASS (_gdk_wayland_cursor_parent_class)->finalize (object);
 }
 
-static GdkPixbuf*
-gdk_wayland_cursor_get_image (GdkCursor *cursor)
+static cairo_surface_t *
+gdk_wayland_cursor_get_surface (GdkCursor *cursor,
+                               gdouble *x_hot,
+                               gdouble *y_hot)
 {
   return NULL;
 }
@@ -258,7 +260,7 @@ _gdk_wayland_cursor_class_init (GdkWaylandCursorClass *wayland_cursor_class)
 
   object_class->finalize = gdk_wayland_cursor_finalize;
 
-  cursor_class->get_image = gdk_wayland_cursor_get_image;
+  cursor_class->get_surface = gdk_wayland_cursor_get_surface;
 }
 
 static void
diff --git a/gdk/win32/gdkcursor-win32.c b/gdk/win32/gdkcursor-win32.c
index 86e7d7b..1ce7cb1 100644
--- a/gdk/win32/gdkcursor-win32.c
+++ b/gdk/win32/gdkcursor-win32.c
@@ -250,7 +250,7 @@ _gdk_win32_display_get_cursor_for_name (GdkDisplay  *display,
 }
 
 GdkPixbuf *
-gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon)
+gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon, gint *x_hot, gint *y_hot)
 {
   GdkPixbuf *pixbuf = NULL;
   ICONINFO ii;
@@ -407,11 +407,10 @@ gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon)
        }
     }
 
-  g_snprintf (buf, sizeof (buf), "%ld", ii.xHotspot);
-  gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
-
-  g_snprintf (buf, sizeof (buf), "%ld", ii.yHotspot);
-  gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
+  if (x_hot)
+    *x_hot = ii.xHotspot;
+  if (y_hot)
+    *y_hot = ii.yHotspot;
 
   /* release temporary resources */
  out2:
@@ -425,12 +424,25 @@ gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon)
   return pixbuf;
 }
 
-static GdkPixbuf *
-_gdk_win32_cursor_get_image (GdkCursor *cursor)
+static cairo_surface_t *
+_gdk_win32_cursor_get_surface (GdkCursor *cursor,
+                              gdouble *x_hot,
+                              gdouble *y_hot)
 {
+  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface
+
   g_return_val_if_fail (cursor != NULL, NULL);
 
-  return gdk_win32_icon_to_pixbuf_libgtk_only (((GdkWin32Cursor *) cursor)->hcursor);
+  pixbuf = gdk_win32_icon_to_pixbuf_libgtk_only (((GdkWin32Cursor *) cursor)->hcursor, x_hot, y_hot);
+
+  if (pixbuf == NULL)
+    return NULL;
+
+  surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
+  g_object_unref (pixbuf);
+
+  return surface;
 }
 
 GdkCursor *
@@ -830,5 +842,5 @@ gdk_win32_cursor_class_init(GdkWin32CursorClass *klass)
 
   object_class->finalize = _gdk_win32_cursor_finalize;
   
-  cursor_class->get_image = _gdk_win32_cursor_get_image;
+  cursor_class->get_surface = _gdk_win32_cursor_get_surface;
 }
diff --git a/gdk/x11/gdkcursor-x11.c b/gdk/x11/gdkcursor-x11.c
index 8d4da14..507ec42 100644
--- a/gdk/x11/gdkcursor-x11.c
+++ b/gdk/x11/gdkcursor-x11.c
@@ -169,7 +169,9 @@ _gdk_x11_cursor_display_finalize (GdkDisplay *display)
 
 G_DEFINE_TYPE (GdkX11Cursor, gdk_x11_cursor, GDK_TYPE_CURSOR)
 
-static GdkPixbuf* gdk_x11_cursor_get_image (GdkCursor *cursor);
+static cairo_surface_t *gdk_x11_cursor_get_surface (GdkCursor *cursor,
+                                                   gdouble   *x_hot,
+                                                   gdouble   *y_hot);
 
 static void
 gdk_x11_cursor_finalize (GObject *object)
@@ -194,7 +196,7 @@ gdk_x11_cursor_class_init (GdkX11CursorClass *xcursor_class)
 
   object_class->finalize = gdk_x11_cursor_finalize;
 
-  cursor_class->get_image = gdk_x11_cursor_get_image;
+  cursor_class->get_surface = gdk_x11_cursor_get_surface;
 }
 
 static void
@@ -316,22 +318,25 @@ gdk_x11_cursor_get_xcursor (GdkCursor *cursor)
 
 #if defined(HAVE_XCURSOR) && defined(HAVE_XFIXES) && XFIXES_MAJOR >= 2
 
-static GdkPixbuf*  
-gdk_x11_cursor_get_image (GdkCursor *cursor)
+static cairo_surface_t *  
+gdk_x11_cursor_get_surface (GdkCursor *cursor,
+                           gdouble   *x_hot,
+                           gdouble   *y_hot)
 {
+  GdkDisplay *display;
   Display *xdisplay;
   GdkX11Cursor *private;
   XcursorImages *images = NULL;
   XcursorImage *image;
   gint size;
-  gchar buf[32];
-  guchar *data, *p, tmp;
-  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
+  gint scale;
   gchar *theme;
   
   private = GDK_X11_CURSOR (cursor);
-    
-  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_cursor_get_display (cursor));
+
+  display = gdk_cursor_get_display (cursor);
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
 
   size = XcursorGetDefaultSize (xdisplay);
   theme = XcursorGetTheme (xdisplay);
@@ -349,31 +354,30 @@ gdk_x11_cursor_get_image (GdkCursor *cursor)
 
   image = images->images[0];
 
-  data = g_malloc (4 * image->width * image->height);
-  memcpy (data, image->pixels, 4 * image->width * image->height);
+  /* Assume the currently set cursor was defined for the screen
+     scale */
+  scale =
+    gdk_screen_get_monitor_scale_factor (gdk_display_get_default_screen (display), 0);
 
-  for (p = data; p < data + (4 * image->width * image->height); p += 4)
-    {
-      tmp = p[0];
-      p[0] = p[2];
-      p[2] = tmp;
-    }
+  surface = gdk_window_create_similar_image_surface (NULL,
+                                                    CAIRO_FORMAT_ARGB32,
+                                                    image->width,
+                                                    image->height,
+                                                    scale);
+
+  memcpy (cairo_image_surface_get_data (surface),
+         image->pixels, 4 * image->width * image->height);
 
-  pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE,
-                                     8, image->width, image->height,
-                                     4 * image->width,
-                                     (GdkPixbufDestroyNotify)g_free, NULL);
+  cairo_surface_mark_dirty (surface);
 
-  if (private->name)
-    gdk_pixbuf_set_option (pixbuf, "name", private->name);
-  g_snprintf (buf, 32, "%d", image->xhot);
-  gdk_pixbuf_set_option (pixbuf, "x_hot", buf);
-  g_snprintf (buf, 32, "%d", image->yhot);
-  gdk_pixbuf_set_option (pixbuf, "y_hot", buf);
+  if (x_hot)
+    *x_hot = (double)image->xhot / scale;
+  if (y_hot)
+    *y_hot = (double)image->yhot / scale;
 
   XcursorImagesDestroy (images);
 
-  return pixbuf;
+  return surface;
 }
 
 void
@@ -484,8 +488,10 @@ gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
 
 #else
 
-static GdkPixbuf*
-gdk_x11_cursor_get_image (GdkCursor *cursor)
+static cairo_surface_t *
+gdk_x11_cursor_get_surface (GdkCursor *cursor,
+                           gdouble *x_hot,
+                           gdouble *y_hot)
 {
   return NULL;
 }


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