From e42014573a89be8b24f911f504780719f65c45ab Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 27 Sep 2024 22:06:17 -0400 Subject: [PATCH 1/2] wayland: Bring back the pointer viewporter This was a thinko in 403da9a2d5355c199682b. We have the cursor image in device pixels, but we still need to apply the viewporter to inform the compositor about the desired pointer size in application pixels. --- gdk/wayland/gdkcursor-wayland.c | 20 ++++++++++++++------ gdk/wayland/gdkdevice-wayland-private.h | 1 + gdk/wayland/gdkdevice-wayland.c | 13 ++++++++++++- gdk/wayland/gdkprivate-wayland.h | 3 ++- gdk/wayland/gdkseat-wayland.c | 3 +++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/gdk/wayland/gdkcursor-wayland.c b/gdk/wayland/gdkcursor-wayland.c index 68c24de4892..577379f5ec0 100644 --- a/gdk/wayland/gdkcursor-wayland.c +++ b/gdk/wayland/gdkcursor-wayland.c @@ -160,7 +160,8 @@ _gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display, int *hotspot_x, int *hotspot_y, int *width, - int *height) + int *height, + double *scale) { GdkTexture *texture; @@ -172,6 +173,7 @@ _gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display, { *hotspot_x = *hotspot_y = 0; *width = *height = 0; + *scale = 1; return NULL; } @@ -194,10 +196,12 @@ _gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display, image = c->images[image_index]; - *width = image->width; - *height = image->height; - *hotspot_x = image->hotspot_x; - *hotspot_y = image->hotspot_y; + *scale = c->size / (double) display->cursor_theme_size; + + *width = image->width / *scale; + *height = image->height / *scale; + *hotspot_x = image->hotspot_x / *scale; + *hotspot_y = image->hotspot_y / *scale; return wl_cursor_image_get_buffer (image); } @@ -231,6 +235,7 @@ from_texture: *hotspot_y = gdk_cursor_get_hotspot_y (cursor); *width = gdk_texture_get_width (texture); *height = gdk_texture_get_height (texture); + *scale = 1; cairo_surface_reference (surface); buffer = _gdk_wayland_shm_surface_get_wl_buffer (surface); @@ -242,6 +247,8 @@ from_texture: } else { + *scale = desired_scale; + texture = gdk_cursor_get_texture_for_size (cursor, display->cursor_theme_size, desired_scale, @@ -281,7 +288,8 @@ from_texture: desired_scale, image_index, hotspot_x, hotspot_y, - width, height); + width, height, + scale); } else { diff --git a/gdk/wayland/gdkdevice-wayland-private.h b/gdk/wayland/gdkdevice-wayland-private.h index 01ed67dfa8a..9b0c4e429c8 100644 --- a/gdk/wayland/gdkdevice-wayland-private.h +++ b/gdk/wayland/gdkdevice-wayland-private.h @@ -62,6 +62,7 @@ struct _GdkWaylandPointerData { uint32_t grab_time; struct wl_surface *pointer_surface; + struct wp_viewport *pointer_surface_viewport; guint cursor_is_default: 1; GdkCursor *cursor; guint cursor_timeout_id; diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 771be3cdfd5..5c41e99fd8b 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -261,6 +261,7 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device) gdk_wayland_device_get_pointer (wayland_device); struct wl_buffer *buffer; int x, y, w, h; + double scale; guint next_image_index, next_image_delay; gboolean retval = G_SOURCE_REMOVE; GdkWaylandTabletData *tablet; @@ -273,7 +274,8 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device) pointer->cursor, pointer->current_output_scale, pointer->cursor_image_index, - &x, &y, &w, &h); + &x, &y, &w, &h, + &scale); } else { @@ -310,6 +312,15 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device) if (buffer) { wl_surface_attach (pointer->pointer_surface, buffer, 0, 0); + if (pointer->pointer_surface_viewport) + { + wp_viewport_set_source (pointer->pointer_surface_viewport, + wl_fixed_from_int (0), + wl_fixed_from_int (0), + wl_fixed_from_double (w * scale), + wl_fixed_from_double (h * scale)); + wp_viewport_set_destination (pointer->pointer_surface_viewport, w, h); + } wl_surface_damage (pointer->pointer_surface, 0, 0, w, h); wl_surface_commit (pointer->pointer_surface); } diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index d2a87240b0f..b2549c67a99 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -121,7 +121,8 @@ struct wl_buffer *_gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display, int *hotspot_x, int *hotspot_y, int *w, - int *h); + int *h, + double *scale); guint _gdk_wayland_cursor_get_next_image_index (GdkWaylandDisplay *display, GdkCursor *cursor, guint scale, diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c index 823cfe93ac5..007c973810d 100644 --- a/gdk/wayland/gdkseat-wayland.c +++ b/gdk/wayland/gdkseat-wayland.c @@ -3894,6 +3894,7 @@ gdk_wayland_pointer_data_finalize (GdkWaylandPointerData *pointer) g_clear_object (&pointer->cursor); wl_surface_destroy (pointer->pointer_surface); g_slist_free (pointer->pointer_surface_outputs); + g_clear_pointer (&pointer->pointer_surface_viewport, wp_viewport_destroy); } static void @@ -4260,6 +4261,8 @@ init_pointer_data (GdkWaylandPointerData *pointer_data, wl_surface_add_listener (pointer_data->pointer_surface, &pointer_surface_listener, logical_device); + if (display_wayland->viewporter) + pointer_data->pointer_surface_viewport = wp_viewporter_get_viewport (display_wayland->viewporter, pointer_data->pointer_surface); } void -- GitLab From 3768c751c5799a03459a7969fbb88d1046fe1c95 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 28 Sep 2024 10:26:42 -0400 Subject: [PATCH 2/2] wayland: Improve our cursor size selection When picking a cursor image size for a given size, look for sizes that do better when scaled by the viewporter: - exact size - twice the size - closest larger size - closest size --- gdk/wayland/cursor/xcursor.c | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/gdk/wayland/cursor/xcursor.c b/gdk/wayland/cursor/xcursor.c index 8ee675b3757..7570b067cc2 100644 --- a/gdk/wayland/cursor/xcursor.c +++ b/gdk/wayland/cursor/xcursor.c @@ -402,6 +402,38 @@ _XcursorFindBestSize (XcursorFileHeader *fileHeader, if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) continue; thisSize = fileHeader->tocs[n].subtype; + if (thisSize == size) + { + bestSize = size; + nsizes++; + } + } + + if (bestSize) + goto done; + + for (n = 0; n < fileHeader->ntoc; n++) + { + if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) + continue; + thisSize = fileHeader->tocs[n].subtype; + if (thisSize == 2 * size) + { + bestSize = 2 * size; + nsizes++; + } + } + + if (bestSize) + goto done; + + for (n = 0; n < fileHeader->ntoc; n++) + { + if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) + continue; + thisSize = fileHeader->tocs[n].subtype; + if (thisSize < size) + continue; if (!bestSize || dist (thisSize, size) < dist (bestSize, size)) { bestSize = thisSize; @@ -410,6 +442,25 @@ _XcursorFindBestSize (XcursorFileHeader *fileHeader, else if (thisSize == bestSize) nsizes++; } + + if (bestSize) + goto done; + + for (n = 0; n < fileHeader->ntoc; n++) + { + if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) + continue; + thisSize = fileHeader->tocs[n].subtype; + if (!bestSize || dist (thisSize, size) < dist (bestSize, size)) + { + bestSize = thisSize; + nsizes = 1; + } + else if (thisSize == bestSize) + nsizes++; + } + +done: *nsizesp = nsizes; return bestSize; } -- GitLab