xwayland: Use relative values for raw events

Xwayland supports relative motion events from the Wayland compositor via
the relative-pointer protocol, and converts those to the absolute range
in device units for raw events.

Some X11 clients however wrongly assume relative values in the axis
values even for devices explicitly labeled as absolute. While this is a
bug in the client, such applications would work fine in plain Xorg but
not with Xwayland.

To avoid that issue, use the relative values for raw events without
conversion, so that such application continue to work in Xwayland.

Thanks Peter for figuring out the root cause.

v2: Don't duplicate relative and absolute events (Peter)
v3: Use POINTER_RAWONLY (Peter)

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
This commit is contained in:
Olivier Fourdan 2021-02-09 13:04:59 +01:00
parent ebdb2e2646
commit c5c5322ad6
1 changed files with 32 additions and 18 deletions

View File

@ -497,14 +497,33 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
dx_unaccel, dy_unaccel);
} else if (xwl_seat->pending_pointer_event.has_absolute ||
xwl_seat->pending_pointer_event.has_relative) {
int x;
int y;
if (xwl_seat->pending_pointer_event.has_relative) {
double dx, dx_unaccel;
double dy, dy_unaccel;
dx = xwl_seat->pending_pointer_event.dx;
dy = xwl_seat->pending_pointer_event.dy;
dx_unaccel = xwl_seat->pending_pointer_event.dx_unaccel;
dy_unaccel = xwl_seat->pending_pointer_event.dy_unaccel;
valuator_mask_zero(&mask);
valuator_mask_set_unaccelerated(&mask, 0, dx, dx_unaccel);
valuator_mask_set_unaccelerated(&mask, 1, dy, dy_unaccel);
QueuePointerEvents(xwl_seat->relative_pointer, MotionNotify, 0,
POINTER_RAWONLY, &mask);
}
if (xwl_seat->pending_pointer_event.has_absolute) {
ValuatorMask mask;
DeviceIntPtr device;
int flags;
int sx = wl_fixed_to_int(xwl_seat->pending_pointer_event.x);
int sy = wl_fixed_to_int(xwl_seat->pending_pointer_event.y);
int dx = xwl_seat->focus_window->window->drawable.x;
int dy = xwl_seat->focus_window->window->drawable.y;
int x;
int y;
if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) {
sx *= xwl_seat->focus_window->scale_x;
@ -513,26 +532,21 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
x = dx + sx;
y = dy + sy;
} else {
miPointerGetPosition(xwl_seat->pointer, &x, &y);
}
valuator_mask_zero(&mask);
if (xwl_seat->pending_pointer_event.has_relative) {
double dx_unaccel;
double dy_unaccel;
dx_unaccel = xwl_seat->pending_pointer_event.dx_unaccel;
dy_unaccel = xwl_seat->pending_pointer_event.dy_unaccel;
valuator_mask_set_absolute_unaccelerated(&mask, 0, x, dx_unaccel);
valuator_mask_set_absolute_unaccelerated(&mask, 1, y, dy_unaccel);
} else {
valuator_mask_zero(&mask);
valuator_mask_set(&mask, 0, x);
valuator_mask_set(&mask, 1, y);
}
QueuePointerEvents(xwl_seat->pointer, MotionNotify, 0,
POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
if (xwl_seat->pending_pointer_event.has_relative) {
flags = POINTER_ABSOLUTE | POINTER_SCREEN | POINTER_NORAW;
device = xwl_seat->relative_pointer;
} else {
flags = POINTER_ABSOLUTE | POINTER_SCREEN;
device = xwl_seat->pointer;
}
QueuePointerEvents(device, MotionNotify, 0, flags, &mask);
}
}
xwl_seat->pending_pointer_event.has_absolute = FALSE;