diff options
author | Benjamin Otte <otte@redhat.com> | 2017-11-03 06:01:56 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2017-11-04 00:07:13 +0100 |
commit | e294f7155583469ad25f2da0a3ffa1ca4ab099df (patch) | |
tree | 3f7f8d799334536046cf66bea01c9491e754129c | |
parent | d30d55be9eae94868af249e84976743a3e2e4614 (diff) | |
download | gtk+-e294f7155583469ad25f2da0a3ffa1ca4ab099df.tar.gz |
x11: Redo cursor handling completely
Instead of creating a GdkX11Cursor, create GdkCursors. Cache the XCursor
in a hash table instead.
Also, make use of the new fallback mechanism for fallback code: Make
sure to provide cursors for the names that are guaranteed to exist, but
do not do bad attempts at displaying texture surfaces.
Black/White/transparent is not a replacement for those.
-rw-r--r-- | docs/reference/gdk/gdk4-sections.txt | 12 | ||||
-rw-r--r-- | gdk/x11/gdkcursor-x11.c | 753 | ||||
-rw-r--r-- | gdk/x11/gdkdevice-core-x11.c | 8 | ||||
-rw-r--r-- | gdk/x11/gdkdevice-xi2.c | 5 | ||||
-rw-r--r-- | gdk/x11/gdkdisplay-x11.h | 3 | ||||
-rw-r--r-- | gdk/x11/gdkprivate-x11.h | 1 | ||||
-rw-r--r-- | gdk/x11/gdkx-autocleanups.h | 1 | ||||
-rw-r--r-- | gdk/x11/gdkx.h | 1 | ||||
-rw-r--r-- | gdk/x11/gdkx11cursor.h | 83 | ||||
-rw-r--r-- | gdk/x11/gdkx11display.h | 3 | ||||
-rw-r--r-- | gdk/x11/meson.build | 1 | ||||
-rw-r--r-- | testsuite/gtk/objects-finalize.c | 1 |
12 files changed, 249 insertions, 623 deletions
diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index 97bae3d45c..ebd74cdcef 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -835,7 +835,6 @@ gdk_cursor_get_hotspot_y gdk_cursor_get_texture <SUBSECTION Standard> -GDK_TYPE_CURSOR_TYPE GDK_TYPE_CURSOR <SUBSECTION Private> @@ -899,8 +898,6 @@ gdk_drag_context_get_type <FILE>x_interaction</FILE> GDK_WINDOW_XID GDK_DISPLAY_XDISPLAY -GDK_CURSOR_XCURSOR -GDK_CURSOR_XDISPLAY GDK_POINTER_TO_XID GDK_XID_TO_POINTER gdk_x11_lookup_xdisplay @@ -915,6 +912,7 @@ gdk_x11_display_set_startup_notification_id gdk_x11_display_get_xdisplay gdk_x11_display_get_xscreen gdk_x11_display_get_xrootwindow +gdk_x11_display_get_xcursor gdk_x11_display_grab gdk_x11_display_ungrab gdk_x11_display_error_trap_push @@ -944,8 +942,6 @@ gdk_x11_window_get_desktop gdk_x11_window_set_utf8_property gdk_x11_window_set_frame_extents gdk_x11_window_set_frame_sync_enabled -gdk_x11_cursor_get_xcursor -gdk_x11_cursor_get_xdisplay gdk_x11_keymap_get_group_for_state gdk_x11_keymap_key_is_modifier gdk_x11_visual_get_xvisual @@ -971,12 +967,6 @@ GDK_X11_APP_LAUNCH_CONTEXT_CLASS GDK_IS_X11_APP_LAUNCH_CONTEXT GDK_IS_X11_APP_LAUNCH_CONTEXT_CLASS GDK_X11_APP_LAUNCH_CONTEXT_GET_CLASS -GDK_TYPE_X11_CURSOR -GDK_X11_CURSOR -GDK_X11_CURSOR_CLASS -GDK_IS_X11_CURSOR -GDK_IS_X11_CURSOR_CLASS -GDK_X11_CURSOR_GET_CLASS GDK_TYPE_X11_DEVICE_CORE GDK_X11_DEVICE_CORE GDK_X11_DEVICE_CORE_CLASS diff --git a/gdk/x11/gdkcursor-x11.c b/gdk/x11/gdkcursor-x11.c index ff0ebba337..a8dae1c391 100644 --- a/gdk/x11/gdkcursor-x11.c +++ b/gdk/x11/gdkcursor-x11.c @@ -42,150 +42,32 @@ #include <X11/extensions/Xfixes.h> #endif #include <string.h> -#include <errno.h> -#include <math.h> -struct _GdkX11Cursor -{ - GdkCursor cursor; - - Cursor xcursor; - guint serial; -}; - -struct _GdkX11CursorClass -{ - GdkCursorClass cursor_class; -}; - -static guint theme_serial = 0; - -/* cursor_cache holds a cache of non-pixmap cursors to avoid expensive - * libXcursor searches, cursors are added to it but only removed when - * their display is closed. We make the assumption that since there are - * a small number of display’s and a small number of cursor’s that this - * list will stay small enough not to be a problem. - */ -static GSList* cursor_cache = NULL; - -struct cursor_cache_key -{ - GdkDisplay* display; - const char* name; -}; - -/* Caller should check if there is already a match first. - * Cursor MUST be either a typed cursor or a pixmap with - * a non-NULL name. - */ static void -add_to_cache (GdkX11Cursor* cursor) -{ - cursor_cache = g_slist_prepend (cursor_cache, cursor); - - /* Take a ref so that if the caller frees it we still have it */ - g_object_ref (cursor); -} - -/* Returns 0 on a match - */ -static gint -cache_compare_func (gconstpointer listelem, - gconstpointer target) -{ - GdkX11Cursor* cursor = (GdkX11Cursor*)listelem; - struct cursor_cache_key* key = (struct cursor_cache_key*)target; - - if (gdk_cursor_get_display (GDK_CURSOR (cursor)) != key->display) - return 1; /* No match */ - - /* Elements marked as pixmap must be named cursors - * (since we don't store normal pixmap cursors - */ - return strcmp (key->name, gdk_cursor_get_name (GDK_CURSOR (cursor))); -} - -/* Returns the cursor if there is a match, NULL if not - */ -static GdkX11Cursor* -find_in_cache (GdkDisplay *display, - const char *name) +gdk_x11_cursor_remove_from_cache (gpointer data, GObject *cursor) { - GSList* res; - struct cursor_cache_key key; - - key.display = display; - key.name = name; - - res = g_slist_find_custom (cursor_cache, &key, cache_compare_func); - - if (res) - return (GdkX11Cursor *) res->data; + GdkDisplay *display = data; + Cursor xcursor; - return NULL; + xcursor = GDK_POINTER_TO_XID (g_hash_table_steal (GDK_X11_DISPLAY (display)->cursors, cursor)); + XFreeCursor (GDK_DISPLAY_XDISPLAY (display), xcursor); } -/* Called by gdk_x11_display_finalize to flush any cached cursors - * for a dead display. - */ void _gdk_x11_cursor_display_finalize (GdkDisplay *display) { - GSList* item; - GSList** itemp; /* Pointer to the thing to fix when we delete an item */ - item = cursor_cache; - itemp = &cursor_cache; - while (item) + GHashTableIter iter; + gpointer cursor; + + if (GDK_X11_DISPLAY (display)->cursors) { - GdkX11Cursor* cursor = (GdkX11Cursor*)(item->data); - if (gdk_cursor_get_display (GDK_CURSOR (cursor)) == display) - { - GSList* olditem; - g_object_unref ((GdkCursor*) cursor); - /* Remove this item from the list */ - *(itemp) = item->next; - olditem = item; - item = item->next; - g_slist_free_1 (olditem); - } - else - { - itemp = &(item->next); - item = item->next; - } + g_hash_table_iter_init (&iter, GDK_X11_DISPLAY (display)->cursors); + while (g_hash_table_iter_next (&iter, &cursor, NULL)) + g_object_weak_unref (G_OBJECT (cursor), gdk_x11_cursor_remove_from_cache, display); + g_hash_table_unref (GDK_X11_DISPLAY (display)->cursors); } } -/*** GdkX11Cursor ***/ - -G_DEFINE_TYPE (GdkX11Cursor, gdk_x11_cursor, GDK_TYPE_CURSOR) - -static void -gdk_x11_cursor_finalize (GObject *object) -{ - GdkX11Cursor *private = GDK_X11_CURSOR (object); - GdkDisplay *display; - - display = gdk_cursor_get_display (GDK_CURSOR (object)); - if (private->xcursor && !gdk_display_is_closed (display)) - XFreeCursor (GDK_DISPLAY_XDISPLAY (display), private->xcursor); - - G_OBJECT_CLASS (gdk_x11_cursor_parent_class)->finalize (object); -} - -static void -gdk_x11_cursor_class_init (GdkX11CursorClass *xcursor_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (xcursor_class); - - object_class->finalize = gdk_x11_cursor_finalize; -} - -static void -gdk_x11_cursor_init (GdkX11Cursor *cursor) -{ -} - static Cursor get_blank_cursor (GdkDisplay *display) { @@ -218,159 +100,73 @@ get_blank_cursor (GdkDisplay *display) return cursor; } -/** - * gdk_x11_cursor_get_xdisplay: - * @cursor: (type GdkX11Cursor): a #GdkCursor. - * - * Returns the display of a #GdkCursor. - * - * Returns: (transfer none): an Xlib Display*. - **/ -Display * -gdk_x11_cursor_get_xdisplay (GdkCursor *cursor) -{ - g_return_val_if_fail (cursor != NULL, NULL); - - return GDK_DISPLAY_XDISPLAY (gdk_cursor_get_display (cursor)); -} - -/** - * gdk_x11_cursor_get_xcursor: - * @cursor: (type GdkX11Cursor): a #GdkCursor. - * - * Returns the X cursor belonging to a #GdkCursor. - * - * Returns: an Xlib Cursor. - **/ -Cursor -gdk_x11_cursor_get_xcursor (GdkCursor *cursor) -{ - g_return_val_if_fail (cursor != NULL, None); - - return ((GdkX11Cursor *)cursor)->xcursor; -} - -#if defined(HAVE_XCURSOR) && defined(HAVE_XFIXES) && XFIXES_MAJOR >= 2 - -void -_gdk_x11_cursor_update_theme (GdkCursor *cursor) -{ - Display *xdisplay; - GdkX11Cursor *private; - Cursor new_cursor = None; - GdkX11Display *display_x11; - - private = (GdkX11Cursor *) cursor; - display_x11 = GDK_X11_DISPLAY (gdk_cursor_get_display (cursor)); - xdisplay = GDK_DISPLAY_XDISPLAY (display_x11); - - if (!display_x11->have_xfixes) - return; - - if (private->serial == theme_serial) - return; - - private->serial = theme_serial; - - if (private->xcursor != None) - { - const char *name; - - name = gdk_cursor_get_name (cursor); - if (name) - new_cursor = XcursorLibraryLoadCursor (xdisplay, name); - - if (new_cursor != None) - { - XFixesChangeCursor (xdisplay, new_cursor, private->xcursor); - private->xcursor = new_cursor; - } - } -} - -static void -update_cursor (gpointer data, - gpointer user_data) -{ - GdkCursor *cursor; - - 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_from_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 const struct { + const char *css_name; + const char *traditional_name; + int cursor_glyph; +} name_map[] = { + { "default", "left_ptr", XC_left_ptr, }, + { "help", "left_ptr", XC_question_arrow }, + { "context-menu", "left_ptr", XC_left_ptr }, + { "pointer", "hand", XC_hand1 }, + { "progress", "left_ptr_watch", XC_watch }, + { "wait", "watch", XC_watch }, + { "cell", "crosshair", XC_plus }, + { "crosshair", "cross", XC_crosshair }, + { "text", "xterm", XC_xterm }, + { "vertical-text","xterm", XC_xterm }, + { "alias", "dnd-link", XC_target }, + { "copy", "dnd-copy", XC_target }, + { "move", "dnd-move", XC_target }, + { "no-drop", "dnd-none", XC_pirate }, + { "dnd-ask", "dnd-copy", XC_target }, /* not CSS, but we want to guarantee it anyway */ + { "not-allowed", "crossed_circle", XC_pirate }, + { "grab", "hand2", XC_hand2 }, + { "grabbing", "hand2", XC_hand2 }, + { "all-scroll", "left_ptr", XC_left_ptr }, + { "col-resize", "h_double_arrow", XC_sb_h_double_arrow }, + { "row-resize", "v_double_arrow", XC_sb_v_double_arrow }, + { "n-resize", "top_side", XC_top_side }, + { "e-resize", "right_side", XC_right_side }, + { "s-resize", "bottom_side", XC_bottom_side }, + { "w-resize", "left_side", XC_left_side }, + { "ne-resize", "top_right_corner", XC_top_right_corner }, + { "nw-resize", "top_left_corner", XC_top_left_corner }, + { "se-resize", "bottom_right_corner", XC_bottom_right_corner }, + { "sw-resize", "bottom_left_corner", XC_bottom_left_corner }, + { "ew-resize", "h_double_arrow", XC_sb_h_double_arrow }, + { "ns-resize", "v_double_arrow", XC_sb_v_double_arrow }, + { "nesw-resize", "fd_double_arrow", XC_X_cursor }, + { "nwse-resize", "bd_double_arrow", XC_X_cursor }, + { "zoom-in", "left_ptr", XC_draped_box }, + { "zoom-out", "left_ptr", XC_draped_box }, + { NULL, NULL, XC_X_cursor } +}; -void -gdk_x11_display_set_cursor_theme (GdkDisplay *display, - const gchar *theme, - const gint size) +GdkCursor* +_gdk_x11_display_get_cursor_for_name (GdkDisplay *display, + const gchar *name) { - g_return_if_fail (GDK_IS_DISPLAY (display)); + return g_object_new (GDK_TYPE_CURSOR, + "display", display, + "name", name, + NULL); } -void -_gdk_x11_cursor_update_theme (GdkCursor *cursor) +GdkCursor * +_gdk_x11_display_get_cursor_for_texture (GdkDisplay *display, + GdkTexture *texture, + int x, + int y) { - g_return_if_fail (cursor != NULL); + return g_object_new (GDK_TYPE_CURSOR, + "display", display, + "texture", texture, + "x", x, + "y", y, + NULL); } -#endif - #ifdef HAVE_XCURSOR static XcursorImage* @@ -393,89 +189,31 @@ create_cursor_image (GdkTexture *texture, return xcimage; } -GdkCursor * -_gdk_x11_display_get_cursor_for_texture (GdkDisplay *display, - GdkTexture *texture, - int x, - int y) +static Cursor +gdk_x11_cursor_create_for_texture (GdkDisplay *display, + GdkTexture *texture, + int x, + int y) { XcursorImage *xcimage; Cursor xcursor; - GdkX11Cursor *private; int target_scale; - if (gdk_display_is_closed (display)) - { - xcursor = None; - } - else - { - target_scale = - gdk_monitor_get_scale_factor (gdk_display_get_primary_monitor (display)); - xcimage = create_cursor_image (texture, x, y, target_scale); - xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage); - XcursorImageDestroy (xcimage); - } + target_scale = + gdk_monitor_get_scale_factor (gdk_display_get_primary_monitor (display)); + xcimage = create_cursor_image (texture, x, y, target_scale); + xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage); + XcursorImageDestroy (xcimage); - private = g_object_new (GDK_TYPE_X11_CURSOR, - "display", display, - "texture", texture, - "x", x, - "y", y, - NULL); - private->xcursor = xcursor; - private->serial = theme_serial; - - return GDK_CURSOR (private); + return xcursor; } -static const struct { - const gchar *css_name, *traditional_name; -} name_map[] = { - { "default", "left_ptr" }, - { "help", "left_ptr" }, - { "context-menu", "left_ptr" }, - { "pointer", "hand" }, - { "progress", "left_ptr_watch" }, - { "wait", "watch" }, - { "cell", "crosshair" }, - { "crosshair", "cross" }, - { "text", "xterm" }, - { "vertical-text","xterm" }, - { "alias", "dnd-link" }, - { "copy", "dnd-copy" }, - { "move", "dnd-move" }, - { "no-drop", "dnd-none" }, - { "dnd-ask", "dnd-copy" }, /* not CSS, but we want to guarantee it anyway */ - { "not-allowed", "crossed_circle" }, - { "grab", "hand2" }, - { "grabbing", "hand2" }, - { "all-scroll", "left_ptr" }, - { "col-resize", "h_double_arrow" }, - { "row-resize", "v_double_arrow" }, - { "n-resize", "top_side" }, - { "e-resize", "right_side" }, - { "s-resize", "bottom_side" }, - { "w-resize", "left_side" }, - { "ne-resize", "top_right_corner" }, - { "nw-resize", "top_left_corner" }, - { "se-resize", "bottom_right_corner" }, - { "sw-resize", "bottom_left_corner" }, - { "ew-resize", "h_double_arrow" }, - { "ns-resize", "v_double_arrow" }, - { "nesw-resize", "fd_double_arrow" }, - { "nwse-resize", "bd_double_arrow" }, - { "zoom-in", "left_ptr" }, - { "zoom-out", "left_ptr" }, - { NULL, NULL } -}; - static const gchar * name_fallback (const gchar *name) { gint i; - for (i = 0; name_map[i].css_name; i++) + for (i = 0; i < G_N_ELEMENTS (name_map); i++) { if (g_str_equal (name_map[i].css_name, name)) return name_map[i].traditional_name; @@ -484,34 +222,19 @@ name_fallback (const gchar *name) return NULL; } -GdkCursor* -_gdk_x11_display_get_cursor_for_name (GdkDisplay *display, - const gchar *name) +static Cursor +gdk_x11_cursor_create_for_name (GdkDisplay *display, + const char *name) { Cursor xcursor; Display *xdisplay; - GdkX11Cursor *private; - if (gdk_display_is_closed (display)) - { - xcursor = None; - } - else if (strcmp (name, "none") == 0) + if (strcmp (name, "none") == 0) { xcursor = get_blank_cursor (display); } else { - private = find_in_cache (display, 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) @@ -520,29 +243,11 @@ _gdk_x11_display_get_cursor_for_name (GdkDisplay *display, fallback = name_fallback (name); if (fallback) - { - xcursor = XcursorLibraryLoadCursor (xdisplay, fallback); - if (xcursor == None) - xcursor = XcursorLibraryLoadCursor (xdisplay, "left_ptr"); - } - } - if (xcursor == None) - { - g_message ("Unable to load %s from the cursor theme", name); - return NULL; + xcursor = XcursorLibraryLoadCursor (xdisplay, fallback); } } - private = g_object_new (GDK_TYPE_X11_CURSOR, - "display", display, - "name", name, - NULL); - private->xcursor = xcursor; - private->serial = theme_serial; - - add_to_cache (private); - - return GDK_CURSOR (private); + return xcursor; } gboolean @@ -567,146 +272,32 @@ _gdk_x11_display_get_default_cursor_size (GdkDisplay *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) +static Cursor +gdk_x11_cursor_create_for_texture (GdkDisplay *display, + GdkTexture *texture, + int x, + int y) { - GdkX11Cursor *private; - Cursor xcursor; - XColor xfg, xbg; - - g_return_val_if_fail (fg != NULL, NULL); - g_return_val_if_fail (bg != NULL, NULL); - - xfg.red = fg->red * 65535; - xfg.blue = fg->blue * 65535; - xfg.green = fg->green * 65535; - - xbg.red = bg->red * 65535; - xbg.blue = bg->blue * 65535; - xbg.green = bg->green * 65535; - - if (gdk_display_is_closed (display)) - xcursor = None; - else - xcursor = XCreatePixmapCursor (GDK_DISPLAY_XDISPLAY (display), - source_pixmap, mask_pixmap, &xfg, &xbg, x, y); - private = g_object_new (GDK_TYPE_X11_CURSOR, - "display", display, - NULL); - private->xcursor = xcursor; - private->serial = theme_serial; - - return GDK_CURSOR (private); + return None; } -GdkCursor * -_gdk_x11_display_get_cursor_for_surface (GdkDisplay *display, - cairo_surface_t *surface, - gdouble x, - gdouble y) +static Cursor +gdk_x11_cursor_create_for_name (GdkDisplay *display, + const gchar *name) { - GdkCursor *cursor; - cairo_surface_t *pixmap, *mask; - guint width, height, n_channels, rowstride, data_stride, i, j; - guint8 *data, *mask_data, *pixels; - GdkRGBA fg = { 0, 0, 0, 1 }; - GdkRGBA bg = { 1, 1, 1, 1 }; - GdkScreen *screen; - cairo_surface_t *image; - cairo_t *cr; - GdkPixbuf *pixbuf; - - width = cairo_image_surface_get_width (surface); - height = cairo_image_surface_get_height (surface); - - g_return_val_if_fail (0 <= x && x < width, NULL); - g_return_val_if_fail (0 <= y && y < height, NULL); - - /* Note: This does not support scaled surfaced, if you need that you - want XCursor anyway */ - pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height); - - n_channels = gdk_pixbuf_get_n_channels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - pixels = gdk_pixbuf_get_pixels (pixbuf); + gint i; - data_stride = 4 * ((width + 31) / 32); - data = g_new0 (guint8, data_stride * height); - mask_data = g_new0 (guint8, data_stride * height); + if (g_str_equal (name, "none")) + return get_blank_cursor (display); - for (j = 0; j < height; j++) + for (i = 0; i < G_N_ELEMENTS (name_map); i++) { - guint8 *src = pixels + j * rowstride; - guint8 *d = data + data_stride * j; - guint8 *md = mask_data + data_stride * j; - - for (i = 0; i < width; i++) - { - if (src[1] < 0x80) - *d |= 1 << (i % 8); - - if (n_channels == 3 || src[3] >= 0x80) - *md |= 1 << (i % 8); - - src += n_channels; - if (i % 8 == 7) - { - d++; - md++; - } - } + if (g_str_equal (name_map[i].css_name, name) || + g_str_equal (name_map[i].traditional_name, name)) + return XCreateFontCursor (GDK_DISPLAY_XDISPLAY (display), name_map[i].cursor_glyph); } - g_object_unref (pixbuf); - - pixmap = _gdk_x11_window_create_bitmap_surface (gdk_display_get_root_window (display), - width, height); - cr = cairo_create (pixmap); - image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A1, - width, height, data_stride); - cairo_set_source_surface (cr, image, 0, 0); - cairo_surface_destroy (image); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - cairo_destroy (cr); - - mask = _gdk_x11_window_create_bitmap_surface (gdk_display_get_root_window (display), - width, height); - cr = cairo_create (mask); - image = cairo_image_surface_create_for_data (mask_data, CAIRO_FORMAT_A1, - width, height, data_stride); - cairo_set_source_surface (cr, image, 0, 0); - cairo_surface_destroy (image); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - cairo_destroy (cr); - - cursor = gdk_cursor_new_from_pixmap (display, - cairo_xlib_surface_get_drawable (pixmap), - cairo_xlib_surface_get_drawable (mask), - &fg, &bg, - x, y); - - cairo_surface_destroy (pixmap); - cairo_surface_destroy (mask); - - g_free (data); - g_free (mask_data); - - return cursor; -} - -GdkCursor* -_gdk_x11_display_get_cursor_for_name (GdkDisplay *display, - const gchar *name) -{ - return NULL; + return None; } gboolean @@ -747,3 +338,131 @@ _gdk_x11_display_get_maximal_cursor_size (GdkDisplay *display, GDK_WINDOW_XID (window), 128, 128, width, height); } + +/** + * 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_from_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) +{ +#if defined(HAVE_XCURSOR) && defined(HAVE_XFIXES) && XFIXES_MAJOR >= 2 + Display *xdisplay; + gchar *old_theme; + gint old_size; + gpointer cursor, xcursor; + GHashTableIter iter; + + 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; + + XcursorSetTheme (xdisplay, theme); + if (size > 0) + XcursorSetDefaultSize (xdisplay, size); + + g_hash_table_iter_init (&iter, GDK_X11_DISPLAY (display)->cursors); + while (g_hash_table_iter_next (&iter, &cursor, &xcursor)) + { + const char *name = gdk_cursor_get_name (cursor); + + if (name) + { + Cursor new_cursor = gdk_x11_cursor_create_for_name (display, name); + + if (new_cursor != None) + { + XFixesChangeCursor (xdisplay, new_cursor, GDK_POINTER_TO_XID (xcursor)); + g_hash_table_iter_replace (&iter, GDK_XID_TO_POINTER (new_cursor)); + } + else + { + g_hash_table_iter_remove (&iter); + } + } + } +#endif +} + +/** + * gdk_x11_display_get_xcursor: + * @display: a #GdkDisplay + * @cursor: a #GdkCursor. + * + * Returns the X cursor 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. On old + * X servers that don't support the XCursor extension, all cursors + * may even fall back to a few default cursors. + * + * Returns: an Xlib Cursor. + **/ +Cursor +gdk_x11_display_get_xcursor (GdkDisplay *display, + GdkCursor *cursor) +{ + GdkX11Display *x11_display = GDK_X11_DISPLAY (display); + Cursor xcursor; + + g_return_val_if_fail (cursor != NULL, None); + + if (gdk_display_is_closed (display)) + return None; + + if (x11_display->cursors == NULL) + x11_display->cursors = g_hash_table_new (gdk_cursor_hash, gdk_cursor_equal); + + xcursor = GDK_POINTER_TO_XID (g_hash_table_lookup (x11_display->cursors, cursor)); + if (xcursor) + return xcursor; + + if (gdk_cursor_get_name (cursor)) + xcursor = gdk_x11_cursor_create_for_name (display, gdk_cursor_get_name (cursor)); + else + xcursor = gdk_x11_cursor_create_for_texture (display, + gdk_cursor_get_texture (cursor), + gdk_cursor_get_hotspot_x (cursor), + gdk_cursor_get_hotspot_y (cursor)); + + if (xcursor != None) + { + g_object_weak_ref (G_OBJECT (cursor), gdk_x11_cursor_remove_from_cache, display); + g_hash_table_insert (x11_display->cursors, cursor, GDK_XID_TO_POINTER (xcursor)); + return xcursor; + } + + if (gdk_cursor_get_fallback (cursor)) + return gdk_x11_display_get_xcursor (display, gdk_cursor_get_fallback (cursor)); + + return None; +} + diff --git a/gdk/x11/gdkdevice-core-x11.c b/gdk/x11/gdkdevice-core-x11.c index 5737bf60aa..ef2aad5757 100644 --- a/gdk/x11/gdkdevice-core-x11.c +++ b/gdk/x11/gdkdevice-core-x11.c @@ -216,14 +216,15 @@ gdk_x11_device_core_set_window_cursor (GdkDevice *device, GdkWindow *window, GdkCursor *cursor) { + GdkDisplay *display = gdk_device_get_display (device); Cursor xcursor; if (!cursor) xcursor = None; else - xcursor = gdk_x11_cursor_get_xcursor (cursor); + xcursor = gdk_x11_display_get_xcursor (display, cursor); - XDefineCursor (GDK_WINDOW_XDISPLAY (window), + XDefineCursor (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), xcursor); } @@ -369,8 +370,7 @@ gdk_x11_device_core_grab (GdkDevice *device, xcursor = None; else { - _gdk_x11_cursor_update_theme (cursor); - xcursor = gdk_x11_cursor_get_xcursor (cursor); + xcursor = gdk_x11_display_get_xcursor (display, cursor); } xevent_mask = 0; diff --git a/gdk/x11/gdkdevice-xi2.c b/gdk/x11/gdkdevice-xi2.c index 8af7f34313..b94ae39eec 100644 --- a/gdk/x11/gdkdevice-xi2.c +++ b/gdk/x11/gdkdevice-xi2.c @@ -290,7 +290,7 @@ gdk_x11_device_xi2_set_window_cursor (GdkDevice *device, XIDefineCursor (GDK_WINDOW_XDISPLAY (window), device_xi2->device_id, GDK_WINDOW_XID (window), - gdk_x11_cursor_get_xcursor (cursor)); + gdk_x11_display_get_xcursor (GDK_WINDOW_DISPLAY (window), cursor)); else XIUndefineCursor (GDK_WINDOW_XDISPLAY (window), device_xi2->device_id, @@ -439,8 +439,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device, xcursor = None; else { - _gdk_x11_cursor_update_theme (cursor); - xcursor = gdk_x11_cursor_get_xcursor (cursor); + xcursor = gdk_x11_display_get_xcursor (display, cursor); } mask.deviceid = device_xi2->device_id; diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 9f7491f36f..536cd68501 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -105,6 +105,9 @@ struct _GdkX11Display /* input GdkWindow list */ GList *input_windows; + /* GdkCursor => XCursor */ + GHashTable *cursors; + GPtrArray *monitors; int primary_monitor; diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h index 7a84fce648..bffa8308d9 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -267,7 +267,6 @@ void _gdk_x11_screen_init_root_window (GdkScreen *screen); void _gdk_x11_screen_init_visuals (GdkScreen *screen, gboolean setup_display); -void _gdk_x11_cursor_update_theme (GdkCursor *cursor); void _gdk_x11_cursor_display_finalize (GdkDisplay *display); void _gdk_x11_window_register_dnd (GdkWindow *window); diff --git a/gdk/x11/gdkx-autocleanups.h b/gdk/x11/gdkx-autocleanups.h index fcc27df08b..90b47dcff8 100644 --- a/gdk/x11/gdkx-autocleanups.h +++ b/gdk/x11/gdkx-autocleanups.h @@ -22,7 +22,6 @@ #ifndef __GI_SCANNER__ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkX11AppLaunchContext, g_object_unref) -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkX11Cursor, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkX11DeviceCore, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkX11DeviceManagerCore, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkX11DeviceManagerXI2, g_object_unref) diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h index c6f5ec8075..87960fdfc8 100644 --- a/gdk/x11/gdkx.h +++ b/gdk/x11/gdkx.h @@ -33,7 +33,6 @@ #define __GDKX_H_INSIDE__ #include <gdk/x11/gdkx11applaunchcontext.h> -#include <gdk/x11/gdkx11cursor.h> #include <gdk/x11/gdkx11device.h> #include <gdk/x11/gdkx11device-core.h> #include <gdk/x11/gdkx11device-xi2.h> diff --git a/gdk/x11/gdkx11cursor.h b/gdk/x11/gdkx11cursor.h deleted file mode 100644 index 046cf706e7..0000000000 --- a/gdk/x11/gdkx11cursor.h +++ /dev/null @@ -1,83 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - */ - -/* - * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS - * file for a list of people on the GTK+ Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. - */ - -#ifndef __GDK_X11_CURSOR_H__ -#define __GDK_X11_CURSOR_H__ - -#if !defined (__GDKX_H_INSIDE__) && !defined (GDK_COMPILATION) -#error "Only <gdk/gdkx.h> can be included directly." -#endif - -#include <gdk/gdk.h> - -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -G_BEGIN_DECLS - -#define GDK_TYPE_X11_CURSOR (gdk_x11_cursor_get_type ()) -#define GDK_X11_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_X11_CURSOR, GdkX11Cursor)) -#define GDK_X11_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_X11_CURSOR, GdkX11CursorClass)) -#define GDK_IS_X11_CURSOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_X11_CURSOR)) -#define GDK_IS_X11_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_X11_CURSOR)) -#define GDK_X11_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_X11_CURSOR, GdkX11CursorClass)) - -#ifdef GDK_COMPILATION -typedef struct _GdkX11Cursor GdkX11Cursor; -#else -typedef GdkCursor GdkX11Cursor; -#endif -typedef struct _GdkX11CursorClass GdkX11CursorClass; - -GDK_AVAILABLE_IN_ALL -GType gdk_x11_cursor_get_type (void); - -GDK_AVAILABLE_IN_ALL -Display *gdk_x11_cursor_get_xdisplay (GdkCursor *cursor); -GDK_AVAILABLE_IN_ALL -Cursor gdk_x11_cursor_get_xcursor (GdkCursor *cursor); - -/** - * GDK_CURSOR_XDISPLAY: - * @cursor: a #GdkCursor. - * - * Returns the display of a #GdkCursor. - * - * Returns: an Xlib Display*. - */ -#define GDK_CURSOR_XDISPLAY(cursor) (gdk_x11_cursor_get_xdisplay (cursor)) - -/** - * GDK_CURSOR_XCURSOR: - * @cursor: a #GdkCursor. - * - * Returns the X cursor belonging to a #GdkCursor. - * - * Returns: an Xlib Cursor. - */ -#define GDK_CURSOR_XCURSOR(cursor) (gdk_x11_cursor_get_xcursor (cursor)) - -G_END_DECLS - -#endif /* __GDK_X11_CURSOR_H__ */ diff --git a/gdk/x11/gdkx11display.h b/gdk/x11/gdkx11display.h index a72b9db47b..22035567a2 100644 --- a/gdk/x11/gdkx11display.h +++ b/gdk/x11/gdkx11display.h @@ -62,6 +62,9 @@ GDK_AVAILABLE_IN_3_94 Screen * gdk_x11_display_get_xscreen (GdkDisplay *display); GDK_AVAILABLE_IN_3_94 Window gdk_x11_display_get_xrootwindow (GdkDisplay *display); +GDK_AVAILABLE_IN_3_94 +Cursor gdk_x11_display_get_xcursor (GdkDisplay *display, + GdkCursor *cursor); #define GDK_DISPLAY_XDISPLAY(display) (gdk_x11_display_get_xdisplay (display)) diff --git a/gdk/x11/meson.build b/gdk/x11/meson.build index 28f0428528..4afc1cb386 100644 --- a/gdk/x11/meson.build +++ b/gdk/x11/meson.build @@ -31,7 +31,6 @@ gdk_x11_sources = files([ gdk_x11_public_headers = files([ 'gdkx-autocleanups.h', 'gdkx11applaunchcontext.h', - 'gdkx11cursor.h', 'gdkx11device-core.h', 'gdkx11device-xi2.h', 'gdkx11device.h', diff --git a/testsuite/gtk/objects-finalize.c b/testsuite/gtk/objects-finalize.c index 4b8a33dc82..26b0362885 100644 --- a/testsuite/gtk/objects-finalize.c +++ b/testsuite/gtk/objects-finalize.c @@ -109,7 +109,6 @@ main (int argc, char **argv) !G_TYPE_IS_ABSTRACT (all_types[i]) && #ifdef GDK_WINDOWING_X11 all_types[i] != GDK_TYPE_X11_WINDOW && - all_types[i] != GDK_TYPE_X11_CURSOR && all_types[i] != GDK_TYPE_X11_SCREEN && all_types[i] != GDK_TYPE_X11_DISPLAY && all_types[i] != GDK_TYPE_X11_DEVICE_MANAGER_CORE && |