This prevents multiple scroll events happening for wayland compositors
which send axis values other than 10. For example, libinput will
typically return 15 for each scroll wheel step, and if a wayland
compositor sends those to xwayland without normalising them, 2 scroll
wheel steps will end up as 3 xorg scroll events. By listening for the
discrete_axis event, this will now correctly send only 2 xorg scroll
events.

The wayland protocol gurantees that there will always be an axis event
following an axis_discrete event. However, it does not gurantee that
other events (including other axis_discrete+axis pairs) will not happen
in between them. So we must keep a list of outstanding axis_discrete
events.

Signed-off-by: Scott Anderson <sc...@anderso.nz>
---
 hw/xwayland/xwayland-input.c | 41 +++++++++++++++++++++++++++++++++++-
 hw/xwayland/xwayland.h       |  1 +
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index a602f0887..6fd3c416b 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -37,6 +37,12 @@
 #include <misc.h>
 #include "tablet-unstable-v2-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;
@@ -565,6 +571,8 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
     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:
@@ -577,8 +585,22 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
         return;
     }
 
+    xorg_list_for_each_entry(iter, &xwl_seat->axis_discrete_pending, l) {
+        if (iter->axis == axis) {
+            pending = iter;
+            break;
+        }
+    }
+
     valuator_mask_zero(&mask);
-    valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / 
divisor);
+
+    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(xwl_seat->pointer, MotionNotify, 0, POINTER_RELATIVE, 
&mask);
 }
 
@@ -608,6 +630,16 @@ static void
 pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
                              uint32_t axis, int32_t discrete)
 {
+    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);
 }
 
 static const struct wl_pointer_listener pointer_listener = {
@@ -1337,6 +1369,7 @@ 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);
 }
 
@@ -1345,6 +1378,7 @@ 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) {
@@ -1357,6 +1391,11 @@ 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.h b/hw/xwayland/xwayland.h
index d70ad54bf..1a6e2f380 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -272,6 +272,7 @@ 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;
-- 
2.18.0

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to