summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Jacewicz <david.jacewicz27@protonmail.com>2022-06-17 15:13:13 -0400
committerOlivier Fourdan <ofourdan@redhat.com>2022-09-14 09:56:31 +0200
commit2db46363542bfd0f62f20f5a898fef07424ffccc (patch)
tree8c0eca28cd91d43dc659427dd73c8f4c39fdf5bf
parent9542cb1abd0fee0b33b3dfedfcc581ddc707c47b (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.c116
-rw-r--r--hw/xwayland/xwayland-input.h10
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;