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.
This commit is contained in:
Alexander Larsson 2013-08-06 16:21:05 +02:00
parent 54f5e4af53
commit 71fe43543c
8 changed files with 158 additions and 53 deletions

View File

@ -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);

View File

@ -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);
return GDK_CURSOR_GET_CLASS (cursor)->get_image (cursor);
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_surface (cursor,
x_hot, y_hot);
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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);
pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE,
8, image->width, image->height,
4 * image->width,
(GdkPixbufDestroyNotify)g_free, NULL);
memcpy (cairo_image_surface_get_data (surface),
image->pixels, 4 * image->width * image->height);
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);
cairo_surface_mark_dirty (surface);
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;
}