Commit 71fe4354 authored by Alexander Larsson's avatar Alexander Larsson

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.
parent 54f5e4af
......@@ -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);
......
......@@ -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
......@@ -388,8 +392,75 @@ 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);
}
......@@ -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);
......
......@@ -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
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
}
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment