diff options
author | David Jacewicz <david.jacewicz27@protonmail.com> | 2022-06-17 15:13:13 -0400 |
---|---|---|
committer | Olivier Fourdan <ofourdan@redhat.com> | 2022-09-14 09:56:31 +0200 |
commit | 2db46363542bfd0f62f20f5a898fef07424ffccc (patch) | |
tree | 8c0eca28cd91d43dc659427dd73c8f4c39fdf5bf | |
parent | 9542cb1abd0fee0b33b3dfedfcc581ddc707c47b (diff) |
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>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1367
(cherry picked from commit e37eeb7af2a84d32f0a74feb00613efda6bc966e)
(cherry picked from commit f0b2eeaf2fe406cc0b788bb3e4ff8c7a7653613d)
-rw-r--r-- | hw/xwayland/xwayland-input.c | 116 | ||||
-rw-r--r-- | hw/xwayland/xwayland-input.h | 10 |
2 files changed, 75 insertions, 51 deletions
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index eda69a193..a5bcc735d 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -50,12 +50,6 @@ #include "pointer-gestures-unstable-v1-client-protocol.h" #include "xwayland-keyboard-grab-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; @@ -611,6 +605,36 @@ dispatch_relative_motion(struct xwl_seat *xwl_seat) } 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) { Bool has_relative = xwl_seat->pending_pointer_event.has_relative; @@ -626,8 +650,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 @@ -684,42 +718,17 @@ 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; + xwl_seat->pending_pointer_event.has_vertical_scroll = TRUE; + xwl_seat->pending_pointer_event.scroll_dy = value; break; case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - index = 2; + xwl_seat->pending_pointer_event.has_horizontal_scroll = TRUE; + xwl_seat->pending_pointer_event.scroll_dx = value; break; - default: - return; - } - - 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 @@ -742,6 +751,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 @@ -750,14 +771,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 = { @@ -1718,7 +1741,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); } @@ -1727,7 +1749,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) { @@ -1740,11 +1761,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); diff --git a/hw/xwayland/xwayland-input.h b/hw/xwayland/xwayland-input.h index dbe215bdb..4fd175b13 100644 --- a/hw/xwayland/xwayland-input.h +++ b/hw/xwayland/xwayland-input.h @@ -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; |