From 40c345d6f3b5cfba19464e0b0e5732a194eaac3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 6 Mar 2020 11:50:38 +0100 Subject: [PATCH] cursor-sprite-xcursor: Emulate Wayland hotspot limitations For HiDPI pointer cursors backed by Wayland surfaces, the hotspot must be placed using integers on the logical pixel grid. In practice what this means is that if the client loads a cursor sprite with the buffer scale 2, and it's hotspot is not dividable by 2, it will be rounded down to an integer that can. E.g. a wl_surface with buffer scale 2 and a cursor image with hotspot coordinate (7, 7) will have the coordinate (3.5, 3.5) in surface coordinate space, and will in practice be rounded down to (3, 3) as the hotspot position in wl_pointer only takes integers. To not potentially shift by 1 pixel on HiDPI monitors when switching between wl_surface backend cursor sprites and built-in ones, make the built in one emulate the restrictions put up by the Wayland protocol. This also initializes the theme scale of the xcursor sprite instances to 1, as they may not have been set prior to being used, it'll only happen in response to "prepare-at" signals being emitted prior to rendering. Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/1092 https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1107 --- src/backends/meta-cursor-sprite-xcursor.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backends/meta-cursor-sprite-xcursor.c b/src/backends/meta-cursor-sprite-xcursor.c index 120ccb598..599d0e697 100644 --- a/src/backends/meta-cursor-sprite-xcursor.c +++ b/src/backends/meta-cursor-sprite-xcursor.c @@ -25,6 +25,7 @@ #include "clutter/clutter.h" #include "cogl/cogl.h" #include "meta/prefs.h" +#include "meta/util.h" struct _MetaCursorSpriteXcursor { @@ -124,6 +125,7 @@ load_from_current_xcursor_image (MetaCursorSpriteXcursor *sprite_xcursor) CoglContext *cogl_context; CoglTexture2D *texture; GError *error = NULL; + int hotspot_x, hotspot_y; g_assert (!meta_cursor_sprite_get_cogl_texture (sprite)); @@ -152,9 +154,21 @@ load_from_current_xcursor_image (MetaCursorSpriteXcursor *sprite_xcursor) g_error_free (error); } + if (meta_is_wayland_compositor ()) + { + hotspot_x = ((int) (xc_image->xhot / sprite_xcursor->theme_scale) * + sprite_xcursor->theme_scale); + hotspot_y = ((int) (xc_image->yhot / sprite_xcursor->theme_scale) * + sprite_xcursor->theme_scale); + } + else + { + hotspot_x = xc_image->xhot; + hotspot_y = xc_image->yhot; + } meta_cursor_sprite_set_texture (sprite, COGL_TEXTURE (texture), - xc_image->xhot, xc_image->yhot); + hotspot_x, hotspot_y); g_clear_pointer (&texture, cogl_object_unref); } @@ -272,6 +286,7 @@ meta_cursor_sprite_xcursor_finalize (GObject *object) static void meta_cursor_sprite_xcursor_init (MetaCursorSpriteXcursor *sprite_xcursor) { + sprite_xcursor->theme_scale = 1; sprite_xcursor->theme_dirty = TRUE; }