xwayland: Aggregate scroll axis events to fix kinetic scrolling
Pointer scroll events are collected in xwl_seat->pending_pointer_event as they are received in the pointer_handle_axis and pointer_handle_axis_discrete callbacks. They are dispatched together as a single event when pointer_handle_frame is called which "Indicates the end of a set of events that logically belong together" [1]. This patch also sends an event with dx=0, dy=0 when pointer_handle_axis_stop is called, which is what allows XWayland clients to recognise the end of a touchpad scroll. [1] https://wayland.app/protocols/wayland#wl_pointer:event:frame Signed-off-by: David Jacewicz <david.jacewicz27@protonmail.com> Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/926 Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
4cfdc5af31
commit
e37eeb7af2
|
@ -51,12 +51,6 @@
|
|||
#include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
|
||||
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
||||
|
||||
struct axis_discrete_pending {
|
||||
struct xorg_list l;
|
||||
uint32_t axis;
|
||||
int32_t discrete;
|
||||
};
|
||||
|
||||
struct sync_pending {
|
||||
struct xorg_list l;
|
||||
DeviceIntPtr pending_dev;
|
||||
|
@ -669,6 +663,36 @@ dispatch_relative_motion(struct xwl_seat *xwl_seat)
|
|||
POINTER_RAWONLY, &mask);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_scroll_motion(struct xwl_seat *xwl_seat)
|
||||
{
|
||||
ValuatorMask mask;
|
||||
const int divisor = 10;
|
||||
wl_fixed_t dy = xwl_seat->pending_pointer_event.scroll_dy;
|
||||
wl_fixed_t dx = xwl_seat->pending_pointer_event.scroll_dx;
|
||||
wl_fixed_t discrete_dy = xwl_seat->pending_pointer_event.scroll_discrete_dy;
|
||||
wl_fixed_t discrete_dx = xwl_seat->pending_pointer_event.scroll_discrete_dx;
|
||||
|
||||
valuator_mask_zero(&mask);
|
||||
if (xwl_seat->pending_pointer_event.has_vertical_scroll)
|
||||
valuator_mask_set_double(&mask,
|
||||
3,
|
||||
wl_fixed_to_double(dy) / divisor);
|
||||
else if (xwl_seat->pending_pointer_event.has_vertical_scroll_discrete)
|
||||
valuator_mask_set(&mask, 3, discrete_dy);
|
||||
|
||||
if (xwl_seat->pending_pointer_event.has_horizontal_scroll)
|
||||
valuator_mask_set_double(&mask,
|
||||
2,
|
||||
wl_fixed_to_double(dx) / divisor);
|
||||
else if (xwl_seat->pending_pointer_event.has_horizontal_scroll_discrete)
|
||||
valuator_mask_set(&mask, 2, discrete_dx);
|
||||
|
||||
QueuePointerEvents(get_pointer_device(xwl_seat),
|
||||
MotionNotify, 0, POINTER_RELATIVE, &mask);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
|
||||
{
|
||||
|
@ -685,8 +709,18 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
|
|||
dispatch_absolute_motion(xwl_seat);
|
||||
}
|
||||
|
||||
if (xwl_seat->pending_pointer_event.has_vertical_scroll ||
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll ||
|
||||
xwl_seat->pending_pointer_event.has_vertical_scroll_discrete ||
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll_discrete)
|
||||
dispatch_scroll_motion(xwl_seat);
|
||||
|
||||
xwl_seat->pending_pointer_event.has_absolute = FALSE;
|
||||
xwl_seat->pending_pointer_event.has_relative = FALSE;
|
||||
xwl_seat->pending_pointer_event.has_vertical_scroll = FALSE;
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll = FALSE;
|
||||
xwl_seat->pending_pointer_event.has_vertical_scroll_discrete = FALSE;
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll_discrete = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -743,42 +777,15 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
|
|||
uint32_t time, uint32_t axis, wl_fixed_t value)
|
||||
{
|
||||
struct xwl_seat *xwl_seat = data;
|
||||
int index;
|
||||
const int divisor = 10;
|
||||
ValuatorMask mask;
|
||||
struct axis_discrete_pending *pending = NULL;
|
||||
struct axis_discrete_pending *iter;
|
||||
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
index = 3;
|
||||
break;
|
||||
xwl_seat->pending_pointer_event.has_vertical_scroll = TRUE;
|
||||
xwl_seat->pending_pointer_event.scroll_dy = value;
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
index = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll = TRUE;
|
||||
xwl_seat->pending_pointer_event.scroll_dx = value;
|
||||
}
|
||||
|
||||
xorg_list_for_each_entry(iter, &xwl_seat->axis_discrete_pending, l) {
|
||||
if (iter->axis == axis) {
|
||||
pending = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
valuator_mask_zero(&mask);
|
||||
|
||||
if (pending) {
|
||||
valuator_mask_set(&mask, index, pending->discrete);
|
||||
xorg_list_del(&pending->l);
|
||||
free(pending);
|
||||
} else {
|
||||
valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor);
|
||||
}
|
||||
|
||||
QueuePointerEvents(get_pointer_device(xwl_seat),
|
||||
MotionNotify, 0, POINTER_RELATIVE, &mask);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -801,6 +808,18 @@ static void
|
|||
pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t time, uint32_t axis)
|
||||
{
|
||||
struct xwl_seat *xwl_seat = data;
|
||||
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
xwl_seat->pending_pointer_event.has_vertical_scroll = TRUE;
|
||||
xwl_seat->pending_pointer_event.scroll_dy = 0;
|
||||
break;
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll = TRUE;
|
||||
xwl_seat->pending_pointer_event.scroll_dx = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -809,14 +828,16 @@ pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
|||
{
|
||||
struct xwl_seat *xwl_seat = data;
|
||||
|
||||
struct axis_discrete_pending *pending = malloc(sizeof *pending);
|
||||
if (!pending)
|
||||
return;
|
||||
|
||||
pending->axis = axis;
|
||||
pending->discrete = discrete;
|
||||
|
||||
xorg_list_add(&pending->l, &xwl_seat->axis_discrete_pending);
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
xwl_seat->pending_pointer_event.has_vertical_scroll_discrete = TRUE;
|
||||
xwl_seat->pending_pointer_event.scroll_discrete_dy = discrete;
|
||||
break;
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
xwl_seat->pending_pointer_event.has_horizontal_scroll_discrete = TRUE;
|
||||
xwl_seat->pending_pointer_event.scroll_discrete_dx = discrete;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener pointer_listener = {
|
||||
|
@ -1832,7 +1853,6 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version
|
|||
wl_array_init(&xwl_seat->keys);
|
||||
|
||||
xorg_list_init(&xwl_seat->touches);
|
||||
xorg_list_init(&xwl_seat->axis_discrete_pending);
|
||||
xorg_list_init(&xwl_seat->sync_pending);
|
||||
}
|
||||
|
||||
|
@ -1841,7 +1861,6 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
|
|||
{
|
||||
struct xwl_touch *xwl_touch, *next_xwl_touch;
|
||||
struct sync_pending *p, *npd;
|
||||
struct axis_discrete_pending *ad, *ad_next;
|
||||
|
||||
xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch,
|
||||
&xwl_seat->touches, link_touch) {
|
||||
|
@ -1854,11 +1873,6 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
|
|||
free (p);
|
||||
}
|
||||
|
||||
xorg_list_for_each_entry_safe(ad, ad_next, &xwl_seat->axis_discrete_pending, l) {
|
||||
xorg_list_del(&ad->l);
|
||||
free(ad);
|
||||
}
|
||||
|
||||
release_tablet_manager_seat(xwl_seat);
|
||||
|
||||
release_grab(xwl_seat);
|
||||
|
|
|
@ -93,7 +93,6 @@ struct xwl_seat {
|
|||
char *keymap;
|
||||
struct wl_surface *keyboard_focus;
|
||||
|
||||
struct xorg_list axis_discrete_pending;
|
||||
struct xorg_list sync_pending;
|
||||
|
||||
struct xwl_pointer_warp_emulator *pointer_warp_emulator;
|
||||
|
@ -111,6 +110,15 @@ struct xwl_seat {
|
|||
double dy;
|
||||
double dx_unaccel;
|
||||
double dy_unaccel;
|
||||
|
||||
wl_fixed_t scroll_dy;
|
||||
wl_fixed_t scroll_dx;
|
||||
int32_t scroll_discrete_dy;
|
||||
int32_t scroll_discrete_dx;
|
||||
Bool has_vertical_scroll;
|
||||
Bool has_horizontal_scroll;
|
||||
Bool has_vertical_scroll_discrete;
|
||||
Bool has_horizontal_scroll_discrete;
|
||||
} pending_pointer_event;
|
||||
|
||||
struct xorg_list tablets;
|
||||
|
|
Loading…
Reference in New Issue