+
+ cursor = (GdkCursor*)(data);
+
+ if (!cursor)
+ return;
+
+ _gdk_x11_cursor_update_theme (cursor);
+}
+
+/**
+ * gdk_x11_display_set_cursor_theme:
+ * @display: (type GdkX11Display): a #GdkDisplay
+ * @theme: the name of the cursor theme to use, or %NULL to unset
+ * a previously set value
+ * @size: the cursor size to use, or 0 to keep the previous size
+ *
+ * Sets the cursor theme from which the images for cursor
+ * should be taken.
+ *
+ * If the windowing system supports it, existing cursors created
+ * with gdk_cursor_new(), gdk_cursor_new_for_display() and
+ * gdk_cursor_new_for_name() are updated to reflect the theme
+ * change. Custom cursors constructed with
+ * gdk_cursor_new_from_pixbuf() will have to be handled
+ * by the application (GTK+ applications can learn about
+ * cursor theme changes by listening for change notification
+ * for the corresponding #GtkSetting).
+ *
+ * Since: 2.8
+ */
+void
+gdk_x11_display_set_cursor_theme (GdkDisplay *display,
+ const gchar *theme,
+ const gint size)
+{
+ Display *xdisplay;
+ gchar *old_theme;
+ gint old_size;
+
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ old_theme = XcursorGetTheme (xdisplay);
+ old_size = XcursorGetDefaultSize (xdisplay);
+
+ if (old_size == size &&
+ (old_theme == theme ||
+ (old_theme && theme && strcmp (old_theme, theme) == 0)))
+ return;
+
+ theme_serial++;
+
+ XcursorSetTheme (xdisplay, theme);
+ if (size > 0)
+ XcursorSetDefaultSize (xdisplay, size);
+
+ g_slist_foreach (cursor_cache, update_cursor, NULL);
+}
+
+#else
+
+static GdkPixbuf*
+gdk_x11_cursor_get_image (GdkCursor *cursor)
+{
+ return NULL;
+}
+
+void
+gdk_x11_display_set_cursor_theme (GdkDisplay *display,
+ const gchar *theme,
+ const gint size)
+{
+ g_return_if_fail (GDK_IS_DISPLAY (display));
+}
+
+void
+_gdk_x11_cursor_update_theme (GdkCursor *cursor)
+{
+ g_return_if_fail (cursor != NULL);
+}
+
+#endif
+
+#ifdef HAVE_XCURSOR
+
+static XcursorImage*
+create_cursor_image (GdkPixbuf *pixbuf,
+ gint x,
+ gint y)
+{
+ guint width, height;
+ XcursorImage *xcimage;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ xcimage = XcursorImageCreate (width, height);
+
+ xcimage->xhot = x;
+ xcimage->yhot = y;
+
+ surface = cairo_image_surface_create_for_data ((guchar *) xcimage->pixels,
+ CAIRO_FORMAT_ARGB32,
+ width,
+ height,
+ width * 4);
+
+ cr = cairo_create (surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ cairo_surface_destroy (surface);
+
+ return xcimage;
+}
+
+GdkCursor *
+_gdk_x11_display_get_cursor_for_pixbuf (GdkDisplay *display,
+ GdkPixbuf *pixbuf,
+ gint x,
+ gint y)
+{
+ XcursorImage *xcimage;
+ Cursor xcursor;
+ GdkX11Cursor *private;
+ const char *option;
+ char *end;
+ gint64 value;
+
+ if (x == -1 && (option = gdk_pixbuf_get_option (pixbuf, "x_hot")))
+ {
+ errno = 0;
+ end = NULL;
+ value = g_ascii_strtoll (option, &end, 10);
+ if (errno == 0 &&
+ end != option &&
+ value >= 0 && value < G_MAXINT)
+ x = (gint) value;
+ }
+ if (y == -1 && (option = gdk_pixbuf_get_option (pixbuf, "y_hot")))
+ {
+ errno = 0;
+ end = NULL;
+ value = g_ascii_strtoll (option, &end, 10);
+ if (errno == 0 &&
+ end != option &&
+ value >= 0 && value < G_MAXINT)
+ y = (gint) value;
+ }
+
+ 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);
+
+ if (gdk_display_is_closed (display))
+ {
+ xcursor = None;
+ }
+ else
+ {
+ xcimage = create_cursor_image (pixbuf, x, y);
+ xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
+ XcursorImageDestroy (xcimage);
+ }
+
+ private = g_object_new (GDK_TYPE_X11_CURSOR,
+ "cursor-type", GDK_CURSOR_IS_PIXMAP,
+ "display", display,
+ NULL);
+ private->xcursor = xcursor;
+ private->name = NULL;
+ private->serial = theme_serial;
+
+ return GDK_CURSOR (private);
+}
+
+GdkCursor*
+_gdk_x11_display_get_cursor_for_name (GdkDisplay *display,
+ const gchar *name)
+{
+ Cursor xcursor;
+ Display *xdisplay;
+ GdkX11Cursor *private;
+
+ if (gdk_display_is_closed (display))
+ {
+ xcursor = None;
+ }
+ else
+ {
+ private = find_in_cache (display, GDK_CURSOR_IS_PIXMAP, name);
+
+ if (private)
+ {
+ /* Cache had it, add a ref for this user */
+ g_object_ref (private);
+
+ return (GdkCursor*) private;
+ }
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ xcursor = XcursorLibraryLoadCursor (xdisplay, name);
+ if (xcursor == None)
+ return NULL;
+ }
+
+ private = g_object_new (GDK_TYPE_X11_CURSOR,
+ "cursor-type", GDK_CURSOR_IS_PIXMAP,
+ "display", display,
+ NULL);
+ private->xcursor = xcursor;
+ private->name = g_strdup (name);
+ private->serial = theme_serial;
+
+ add_to_cache (private);
+
+ return GDK_CURSOR (private);
+}
+
+gboolean
+_gdk_x11_display_supports_cursor_alpha (GdkDisplay *display)
+{
+ return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
+}
+
+gboolean
+_gdk_x11_display_supports_cursor_color (GdkDisplay *display)
+{
+ return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
+}
+
+void
+_gdk_x11_display_get_default_cursor_size (GdkDisplay *display,
+ guint *width,
+ guint *height)
+{
+ *width = *height = XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
+}
+
+#else
+
+static GdkCursor*
+gdk_cursor_new_from_pixmap (GdkDisplay *display,
+ Pixmap source_pixmap,
+ Pixmap mask_pixmap,
+ const GdkRGBA *fg,
+ const GdkRGBA *bg,
+ gint x,
+ gint y)
+{
+ GdkX11Cursor *private;