From: Benjamin Otte Date: Fri, 3 Nov 2017 21:41:31 +0000 (+0100) Subject: wayland: Redo cursor handling X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~23^2~899 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ec824b9e505a5964808ef648fb78a6c8dc0f54d6;p=gtk4.git wayland: Redo cursor handling This is in line with the X11 changes last patch. --- diff --git a/gdk/wayland/gdkcursor-wayland.c b/gdk/wayland/gdkcursor-wayland.c index 005175c87d..82f25e341a 100644 --- a/gdk/wayland/gdkcursor-wayland.c +++ b/gdk/wayland/gdkcursor-wayland.c @@ -36,49 +36,30 @@ #include -#define GDK_TYPE_WAYLAND_CURSOR (_gdk_wayland_cursor_get_type ()) -#define GDK_WAYLAND_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_CURSOR, GdkWaylandCursor)) -#define GDK_WAYLAND_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WAYLAND_CURSOR, GdkWaylandCursorClass)) -#define GDK_IS_WAYLAND_CURSOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_CURSOR)) -#define GDK_IS_WAYLAND_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WAYLAND_CURSOR)) -#define GDK_WAYLAND_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WAYLAND_CURSOR, GdkWaylandCursorClass)) - -typedef struct _GdkWaylandCursor GdkWaylandCursor; -typedef struct _GdkWaylandCursorClass GdkWaylandCursorClass; - -struct _GdkWaylandCursor -{ - GdkCursor cursor; - - struct - { - int width, height, scale; - cairo_surface_t *cairo_surface; - } surface; - - struct wl_cursor *wl_cursor; - int scale; -}; - -struct _GdkWaylandCursorClass +static void +gdk_wayland_cursor_remove_from_cache (gpointer data, GObject *cursor) { - GdkCursorClass cursor_class; -}; - -GType _gdk_wayland_cursor_get_type (void); + GdkWaylandDisplay *display = data; -G_DEFINE_TYPE (GdkWaylandCursor, _gdk_wayland_cursor, GDK_TYPE_CURSOR) + g_hash_table_remove (display->cursor_surface_cache, cursor); +} void _gdk_wayland_display_init_cursors (GdkWaylandDisplay *display) { - display->cursor_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + display->cursor_surface_cache = g_hash_table_new_full (gdk_cursor_hash, gdk_cursor_equal, NULL, (GDestroyNotify) cairo_surface_destroy); } void _gdk_wayland_display_finalize_cursors (GdkWaylandDisplay *display) { - g_hash_table_destroy (display->cursor_cache); + GHashTableIter iter; + gpointer cursor; + + g_hash_table_iter_init (&iter, display->cursor_surface_cache); + while (g_hash_table_iter_next (&iter, &cursor, NULL)) + g_object_weak_unref (G_OBJECT (cursor), gdk_wayland_cursor_remove_from_cache, display); + g_hash_table_destroy (display->cursor_surface_cache); } static const struct { @@ -136,22 +117,13 @@ name_fallback (const gchar *name) return NULL; } -static gboolean -_gdk_wayland_cursor_update (GdkWaylandDisplay *display_wayland, - GdkWaylandCursor *cursor) +static struct wl_cursor * +gdk_wayland_cursor_load_for_name (GdkWaylandDisplay *display_wayland, + struct wl_cursor_theme *theme, + const char *name) { struct wl_cursor *c; - struct wl_cursor_theme *theme; - const char *name; - name = gdk_cursor_get_name (GDK_CURSOR (cursor)); - - /* Do nothing if this is not a wl_cursor cursor. */ - if (name == NULL) - return FALSE; - - theme = _gdk_wayland_display_get_scaled_cursor_theme (display_wayland, - cursor->scale); c = wl_cursor_theme_get_cursor (theme, name); if (!c) { @@ -161,263 +133,201 @@ _gdk_wayland_cursor_update (GdkWaylandDisplay *display_wayland, if (fallback) { c = wl_cursor_theme_get_cursor (theme, fallback); - if (!c) - c = wl_cursor_theme_get_cursor (theme, "left_ptr"); } } - if (!c) - { - g_message ("Unable to load %s from the cursor theme", name); - return FALSE; - } - - cursor->wl_cursor = c; - - return TRUE; -} - -void -_gdk_wayland_display_update_cursors (GdkWaylandDisplay *display) -{ - GHashTableIter iter; - const char *name; - GdkWaylandCursor *cursor; - - g_hash_table_iter_init (&iter, display->cursor_cache); - - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &cursor)) - _gdk_wayland_cursor_update (display, cursor); + return c; } static void -gdk_wayland_cursor_finalize (GObject *object) +buffer_release_callback (void *_data, + struct wl_buffer *wl_buffer) { - GdkWaylandCursor *cursor = GDK_WAYLAND_CURSOR (object); - - if (cursor->surface.cairo_surface) - cairo_surface_destroy (cursor->surface.cairo_surface); + cairo_surface_t *cairo_surface = _data; - G_OBJECT_CLASS (_gdk_wayland_cursor_parent_class)->finalize (object); + cairo_surface_destroy (cairo_surface); } +static const struct wl_buffer_listener buffer_listener = { + buffer_release_callback +}; + struct wl_buffer * -_gdk_wayland_cursor_get_buffer (GdkCursor *cursor, - guint image_index, - int *hotspot_x, - int *hotspot_y, - int *w, - int *h, - int *scale) +_gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display, + GdkCursor *cursor, + guint desired_scale, + guint image_index, + int *hotspot_x, + int *hotspot_y, + int *width, + int *height, + int *scale) { - GdkWaylandCursor *wayland_cursor = GDK_WAYLAND_CURSOR (cursor); + desired_scale = MIN (desired_scale, GDK_WAYLAND_MAX_THEME_SCALE); - if (wayland_cursor->wl_cursor) + if (gdk_cursor_get_name (cursor)) { - struct wl_cursor_image *image; + struct wl_cursor *c; - if (image_index >= wayland_cursor->wl_cursor->image_count) + if (g_str_equal (gdk_cursor_get_name (cursor), "none")) { - g_warning (G_STRLOC " out of bounds cursor image [%d / %d]", - image_index, - wayland_cursor->wl_cursor->image_count - 1); - image_index = 0; + *hotspot_x = 0; + *hotspot_y = 0; + *width = 0; + *height = 0; + *scale = 1; + return NULL; } - image = wayland_cursor->wl_cursor->images[image_index]; - - *hotspot_x = image->hotspot_x / wayland_cursor->scale; - *hotspot_y = image->hotspot_y / wayland_cursor->scale; + c = gdk_wayland_cursor_load_for_name (display, + _gdk_wayland_display_get_scaled_cursor_theme (display, desired_scale), + gdk_cursor_get_name (cursor)); + if (c) + { + struct wl_cursor_image *image; - *w = image->width / wayland_cursor->scale; - *h = image->height / wayland_cursor->scale; - *scale = wayland_cursor->scale; + if (image_index >= c->image_count) + { + g_warning (G_STRLOC " out of bounds cursor image [%d / %d]", + image_index, + c->image_count - 1); + image_index = 0; + } - return wl_cursor_image_get_buffer (image); - } - else if (gdk_cursor_get_name (cursor) == NULL) /* From surface */ - { - *hotspot_x = - gdk_cursor_get_hotspot_x (cursor) / wayland_cursor->surface.scale; - *hotspot_y = - gdk_cursor_get_hotspot_y (cursor) / wayland_cursor->surface.scale; + image = c->images[image_index]; - *w = wayland_cursor->surface.width / wayland_cursor->surface.scale; - *h = wayland_cursor->surface.height / wayland_cursor->surface.scale; - *scale = wayland_cursor->surface.scale; + *hotspot_x = image->hotspot_x / desired_scale; + *hotspot_y = image->hotspot_y / desired_scale; - cairo_surface_reference (wayland_cursor->surface.cairo_surface); + *width = image->width / desired_scale; + *height = image->height / desired_scale; + *scale = desired_scale; - if (wayland_cursor->surface.cairo_surface) - return _gdk_wayland_shm_surface_get_wl_buffer (wayland_cursor->surface.cairo_surface); - } - - return NULL; -} - -guint -_gdk_wayland_cursor_get_next_image_index (GdkCursor *cursor, - guint current_image_index, - guint *next_image_delay) -{ - struct wl_cursor *wl_cursor = GDK_WAYLAND_CURSOR (cursor)->wl_cursor; - - if (wl_cursor && wl_cursor->image_count > 1) - { - if (current_image_index >= wl_cursor->image_count) - { - g_warning (G_STRLOC " out of bounds cursor image [%d / %d]", - current_image_index, wl_cursor->image_count - 1); - current_image_index = 0; + return wl_cursor_image_get_buffer (image); } - - /* Return the time to next image */ - if (next_image_delay) - *next_image_delay = wl_cursor->images[current_image_index]->delay; - - return (current_image_index + 1) % wl_cursor->image_count; } else - return current_image_index; -} - -void -_gdk_wayland_cursor_set_scale (GdkCursor *cursor, - guint scale) -{ - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_cursor_get_display (cursor)); - GdkWaylandCursor *wayland_cursor = GDK_WAYLAND_CURSOR (cursor); - - if (scale > GDK_WAYLAND_MAX_THEME_SCALE) { - g_warning (G_STRLOC ": cursor theme size %u too large", scale); - scale = GDK_WAYLAND_MAX_THEME_SCALE; - } + GdkTexture *texture = gdk_cursor_get_texture (cursor); + cairo_surface_t *surface; + struct wl_buffer *buffer; - if (wayland_cursor->scale == scale) - return; - - wayland_cursor->scale = scale; + surface = g_hash_table_lookup (display->cursor_surface_cache, cursor); + if (surface == NULL) + { + _gdk_wayland_display_create_shm_surface (display, + gdk_texture_get_width (texture), + gdk_texture_get_height (texture), + 1); + + gdk_texture_download (texture, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); + cairo_surface_mark_dirty (surface); + + g_object_weak_ref (G_OBJECT (cursor), gdk_wayland_cursor_remove_from_cache, display); + g_hash_table_insert (display->cursor_surface_cache, cursor, surface); + } - /* Blank cursor case */ - if (g_strcmp0 (gdk_cursor_get_name (cursor), "none") == 0) - return; + *hotspot_x = gdk_cursor_get_hotspot_x (cursor); + *hotspot_y = gdk_cursor_get_hotspot_y (cursor); + *width = gdk_texture_get_width (texture); + *height = gdk_texture_get_height (texture); + *scale = 1; - _gdk_wayland_cursor_update (display_wayland, wayland_cursor); -} + cairo_surface_reference (surface); + buffer = _gdk_wayland_shm_surface_get_wl_buffer (surface); + wl_buffer_add_listener (buffer, &buffer_listener, surface); -static void -_gdk_wayland_cursor_class_init (GdkWaylandCursorClass *wayland_cursor_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (wayland_cursor_class); + return buffer; + } - object_class->finalize = gdk_wayland_cursor_finalize; -} + if (gdk_cursor_get_fallback (cursor)) + return _gdk_wayland_cursor_get_buffer (display, + gdk_cursor_get_fallback (cursor), + desired_scale, + image_index, + hotspot_x, hotspot_y, + width, height, + scale); -static void -_gdk_wayland_cursor_init (GdkWaylandCursor *cursor) -{ + return NULL; } -GdkCursor * -_gdk_wayland_display_get_cursor_for_name_with_scale (GdkDisplay *display, - const gchar *name, - guint scale) +guint +_gdk_wayland_cursor_get_next_image_index (GdkWaylandDisplay *display, + GdkCursor *cursor, + guint scale, + guint current_image_index, + guint *next_image_delay) { - GdkWaylandCursor *private; - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display); - - g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); - - private = g_hash_table_lookup (display_wayland->cursor_cache, name); - if (private) - return GDK_CURSOR (g_object_ref (private)); - - private = g_object_new (GDK_TYPE_WAYLAND_CURSOR, - "display", display, - "name", name, - NULL); + struct wl_cursor *c; - /* Blank cursor case */ - if (g_str_equal (name, "none") || g_str_equal (name, "blank_cursor")) + if (!gdk_cursor_get_name (cursor) || + g_str_equal (gdk_cursor_get_name (cursor), "none")) { - private->scale = scale; - - return GDK_CURSOR (private); + *next_image_delay = 0; + return current_image_index; } - private->scale = scale; + c = gdk_wayland_cursor_load_for_name (display, + _gdk_wayland_display_get_scaled_cursor_theme (display, scale), + gdk_cursor_get_name (cursor)); - if (!_gdk_wayland_cursor_update (display_wayland, private)) + if (c) { - g_object_unref (private); - return NULL; + if (current_image_index >= c->image_count) + { + g_warning (G_STRLOC " out of bounds cursor image [%d / %d]", + current_image_index, c->image_count - 1); + current_image_index = 0; + } + + if (c->image_count == 1) + { + *next_image_delay = 0; + return current_image_index; + } + else + { + *next_image_delay = c->images[current_image_index]->delay; + return (current_image_index + 1) % c->image_count; + } } - /* Insert into cache. */ - g_hash_table_insert (display_wayland->cursor_cache, - (gpointer) gdk_cursor_get_name (GDK_CURSOR (private)), - g_object_ref (private)); - return GDK_CURSOR (private); + if (gdk_cursor_get_fallback (cursor)) + return _gdk_wayland_cursor_get_next_image_index (display, + gdk_cursor_get_fallback (cursor), + scale, + current_image_index, + next_image_delay); + + *next_image_delay = 0; + return current_image_index; } GdkCursor * _gdk_wayland_display_get_cursor_for_name (GdkDisplay *display, const gchar *name) { - return _gdk_wayland_display_get_cursor_for_name_with_scale (display, name, 1); + return g_object_new (GDK_TYPE_CURSOR, + "display", display, + "name", name, + NULL); } -static void -buffer_release_callback (void *_data, - struct wl_buffer *wl_buffer) -{ - cairo_surface_t *cairo_surface = _data; - - cairo_surface_destroy (cairo_surface); -} - -static const struct wl_buffer_listener buffer_listener = { - buffer_release_callback -}; - GdkCursor * _gdk_wayland_display_get_cursor_for_texture (GdkDisplay *display, GdkTexture *texture, int x, int y) { - GdkWaylandCursor *cursor; - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display); - struct wl_buffer *buffer; - - cursor = g_object_new (GDK_TYPE_WAYLAND_CURSOR, - "display", display_wayland, - "texture", texture, - "x", x, - "y", y, - NULL); - - cursor->surface.scale = 1; - cursor->surface.width = gdk_texture_get_width (texture); - cursor->surface.height = gdk_texture_get_height (texture); - - cursor->surface.cairo_surface = - _gdk_wayland_display_create_shm_surface (display_wayland, - cursor->surface.width, - cursor->surface.height, - cursor->surface.scale); - - buffer = _gdk_wayland_shm_surface_get_wl_buffer (cursor->surface.cairo_surface); - wl_buffer_add_listener (buffer, &buffer_listener, cursor->surface.cairo_surface); - - gdk_texture_download (texture, - cairo_image_surface_get_data (cursor->surface.cairo_surface), - cairo_image_surface_get_stride (cursor->surface.cairo_surface)); - cairo_surface_mark_dirty (cursor->surface.cairo_surface); - - return GDK_CURSOR (cursor); + return g_object_new (GDK_TYPE_CURSOR, + "display", display, + "texture", texture, + "x", x, + "y", y, + NULL); } void diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index c851823aa3..0fc6c58c66 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -407,7 +407,9 @@ gdk_wayland_device_update_window_cursor (GdkDevice *device) if (pointer->cursor) { - buffer = _gdk_wayland_cursor_get_buffer (pointer->cursor, + buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display), + pointer->cursor, + pointer->current_output_scale, pointer->cursor_image_index, &x, &y, &w, &h, &scale); } @@ -451,7 +453,9 @@ gdk_wayland_device_update_window_cursor (GdkDevice *device) } next_image_index = - _gdk_wayland_cursor_get_next_image_index (pointer->cursor, + _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display), + pointer->cursor, + pointer->current_output_scale, pointer->cursor_image_index, &next_image_delay); @@ -496,17 +500,6 @@ gdk_wayland_device_set_window_cursor (GdkDevice *device, if (seat->grab_cursor) cursor = seat->grab_cursor; - /* Setting the cursor to NULL means that we should use - * the default cursor - */ - if (!cursor) - { - guint scale = pointer->current_output_scale; - cursor = _gdk_wayland_display_get_cursor_for_name_with_scale (seat->display, "default", scale); - } - else - _gdk_wayland_cursor_set_scale (cursor, pointer->current_output_scale); - if (cursor == pointer->cursor) return; @@ -515,7 +508,10 @@ gdk_wayland_device_set_window_cursor (GdkDevice *device, if (pointer->cursor) g_object_unref (pointer->cursor); - pointer->cursor = g_object_ref (cursor); + if (cursor == NULL) + pointer->cursor = gdk_cursor_new_from_name (seat->display, "default"); + else + pointer->cursor = g_object_ref (cursor); gdk_wayland_device_update_window_cursor (device); } @@ -4523,9 +4519,6 @@ pointer_surface_update_scale (GdkDevice *device) pointer->current_output_scale = scale; - if (pointer->cursor) - _gdk_wayland_cursor_set_scale (pointer->cursor, scale); - gdk_wayland_device_update_window_cursor (device); } diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index 2d8a76319d..677f03e1e4 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -1107,8 +1107,6 @@ gdk_wayland_display_set_cursor_theme (GdkDisplay *display, g_free (display_wayland->cursor_theme_name); display_wayland->cursor_theme_name = g_strdup (name); display_wayland->cursor_theme_size = size; - - _gdk_wayland_display_update_cursors (display_wayland); } struct wl_cursor_theme * diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index a76a881e59..ed59818590 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -112,7 +112,7 @@ struct _GdkWaylandDisplay struct wl_cursor_theme *scaled_cursor_themes[GDK_WAYLAND_THEME_SCALES_COUNT]; gchar *cursor_theme_name; int cursor_theme_size; - GHashTable *cursor_cache; + GHashTable *cursor_surface_cache; GSource *event_source; diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index d319393559..af8bb2c07e 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -58,7 +58,6 @@ gboolean _gdk_wayland_keymap_key_is_modifier (GdkKeymap *keymap, void _gdk_wayland_display_init_cursors (GdkWaylandDisplay *display); void _gdk_wayland_display_finalize_cursors (GdkWaylandDisplay *display); -void _gdk_wayland_display_update_cursors (GdkWaylandDisplay *display); struct wl_cursor_theme * _gdk_wayland_display_get_scaled_cursor_theme (GdkWaylandDisplay *display_wayland, guint scale); @@ -84,19 +83,20 @@ gboolean _gdk_wayland_display_supports_cursor_color (GdkDisplay *display); void gdk_wayland_display_system_bell (GdkDisplay *display, GdkWindow *window); -struct wl_buffer *_gdk_wayland_cursor_get_buffer (GdkCursor *cursor, - guint image_index, - int *hotspot_x, - int *hotspot_y, - int *w, - int *h, - int *scale); -guint _gdk_wayland_cursor_get_next_image_index (GdkCursor *cursor, - guint current_image_index, - guint *next_image_delay); - -void _gdk_wayland_cursor_set_scale (GdkCursor *cursor, - guint scale); +struct wl_buffer *_gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display, + GdkCursor *cursor, + guint desired_scale, + guint image_index, + int *hotspot_x, + int *hotspot_y, + int *w, + int *h, + int *scale); +guint _gdk_wayland_cursor_get_next_image_index (GdkWaylandDisplay *display, + GdkCursor *cursor, + guint scale, + guint current_image_index, + guint *next_image_delay); void gdk_wayland_window_sync (GdkWindow *window); GdkDragProtocol _gdk_wayland_window_get_drag_protocol (GdkWindow *window,