xwayland: Use viewport scale for warping coordinates

When Xwayland is used rootful with hidpi, a viewport is in effect and a
scale applied.

This is however "transparent" to the Xserver which uses unscaled
coordinates, so to set the fake cursor position with a viewport and a
scale applied, we need to factor the scale to the coordinates before
passing the coordinate to the Wayland compositor through the method
zwp_locked_pointer_v1_set_cursor_position_hint().

Failing to do that will introduce a shift when warping the cursor
position.

v2: Use an xwl_window instead of an xwl_seat to improve readability
(Michel)

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1875
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 0e580872b0)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2151>
This commit is contained in:
Olivier Fourdan 2026-03-20 10:54:37 +01:00 committed by Marge Bot
parent 0473a59387
commit 53399164db

View file

@ -24,6 +24,7 @@
* SOFTWARE.
*/
#include <math.h>
#include <xwayland-config.h>
#include <linux/input.h>
@ -3293,26 +3294,30 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
{
struct zwp_locked_pointer_v1 *locked_pointer =
warp_emulator->locked_pointer;
struct xwl_window *focus_window;
WindowPtr window;
int sx, sy;
if (!warp_emulator->locked_pointer)
return;
if (!warp_emulator->xwl_seat->focus_window)
focus_window = warp_emulator->xwl_seat->focus_window;
if (!focus_window)
return;
window = warp_emulator->xwl_seat->focus_window->toplevel;
window = focus_window->toplevel;
if (x >= window->drawable.x ||
y >= window->drawable.y ||
x < (window->drawable.x + window->drawable.width) ||
y < (window->drawable.y + window->drawable.height)) {
sx = x - window->drawable.x;
sy = y - window->drawable.y;
sx = round((double) (x - window->drawable.x) /
focus_window->viewport_scale_x);
sy = round((double) (y - window->drawable.y) /
focus_window->viewport_scale_y);
zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer,
wl_fixed_from_int(sx),
wl_fixed_from_int(sy));
wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface);
wl_surface_commit(focus_window->surface);
}
}