If there was an relative pointer motion within the same frame as an
absolute pointer motion, provide both the absolute coordinate and the
unaccelerated delta when setting the valuator mask.

If a frame contained only a relative motion, queue an absolute motion
with an unchanged position, but still pass the unaccelerated motion
event.

If the wl_seat advertised by the compositor is not new enough, assume
each relative and absolute pointer motion arrives within their own
separate frames.

Signed-off-by: Jonas Ådahl <jad...@gmail.com>
---
 hw/xwayland/xwayland-input.c | 90 ++++++++++++++++++++++++++++++++++++--------
 hw/xwayland/xwayland.h       |  7 ++++
 2 files changed, 82 insertions(+), 15 deletions(-)

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 19cfd93..e1d751c 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -336,30 +336,47 @@ pointer_handle_leave(void *data, struct wl_pointer 
*pointer,
 }
 
 static void
-dispatch_pointer_event(struct xwl_seat *xwl_seat)
+dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
 {
     ValuatorMask mask;
 
-    if (xwl_seat->pending_pointer_event.has_absolute) {
-        int sx;
-        int sy;
-        int dx;
-        int dy;
-
-        sx = wl_fixed_to_int(xwl_seat->pending_pointer_event.x);
-        sy = wl_fixed_to_int(xwl_seat->pending_pointer_event.y);
-        dx = xwl_seat->focus_window->window->drawable.x;
-        dy = xwl_seat->focus_window->window->drawable.y;
+    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_absolute) {
+            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;
+
+            x = dx + sx;
+            y = dy + sy;
+        } else {
+            miPointerGetPosition(xwl_seat->pointer, &x, &y);
+        }
 
         valuator_mask_zero(&mask);
-        valuator_mask_set(&mask, 0, dx + sx);
-        valuator_mask_set(&mask, 1, dy + sy);
+        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_set(&mask, 0, x);
+            valuator_mask_set(&mask, 1, y);
+        }
 
         QueuePointerEvents(xwl_seat->pointer, MotionNotify, 0,
                            POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
     }
 
     xwl_seat->pending_pointer_event.has_absolute = FALSE;
+    xwl_seat->pending_pointer_event.has_relative = FALSE;
 }
 
 static void
@@ -376,7 +393,7 @@ pointer_handle_motion(void *data, struct wl_pointer 
*pointer,
     xwl_seat->pending_pointer_event.y = sy_w;
 
     if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
-        dispatch_pointer_event(xwl_seat);
+        dispatch_pointer_motion_event(xwl_seat);
 }
 
 static void
@@ -441,7 +458,7 @@ pointer_handle_frame(void *data, struct wl_pointer 
*wl_pointer)
 {
     struct xwl_seat *xwl_seat = data;
 
-    dispatch_pointer_event(xwl_seat);
+    dispatch_pointer_motion_event(xwl_seat);
 }
 
 static void
@@ -474,6 +491,32 @@ static const struct wl_pointer_listener pointer_listener = 
{
 };
 
 static void
+relative_pointer_handle_relative_motion(void *data,
+                                        struct zwp_relative_pointer_v1 
*zwp_relative_pointer_v1,
+                                        uint32_t utime_hi,
+                                        uint32_t utime_lo,
+                                        wl_fixed_t dxf,
+                                        wl_fixed_t dyf,
+                                        wl_fixed_t dx_unaccelf,
+                                        wl_fixed_t dy_unaccelf)
+{
+    struct xwl_seat *xwl_seat = data;
+
+    xwl_seat->pending_pointer_event.has_relative = TRUE;
+    xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf);
+    xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf);
+    xwl_seat->pending_pointer_event.dx_unaccel = 
wl_fixed_to_double(dx_unaccelf);
+    xwl_seat->pending_pointer_event.dy_unaccel = 
wl_fixed_to_double(dy_unaccelf);
+
+    if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
+        dispatch_pointer_motion_event(xwl_seat);
+}
+
+static const struct zwp_relative_pointer_v1_listener relative_pointer_listener 
= {
+    relative_pointer_handle_relative_motion,
+};
+
+static void
 keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
                     uint32_t time, uint32_t key, uint32_t state)
 {
@@ -891,6 +934,18 @@ release_pointer(struct xwl_seat *xwl_seat)
 static void
 init_relative_pointer(struct xwl_seat *xwl_seat)
 {
+    struct zwp_relative_pointer_manager_v1 *relative_pointer_manager =
+        xwl_seat->xwl_screen->relative_pointer_manager;
+
+    if (relative_pointer_manager) {
+        xwl_seat->wp_relative_pointer =
+            zwp_relative_pointer_manager_v1_get_relative_pointer(
+                relative_pointer_manager, xwl_seat->wl_pointer);
+        zwp_relative_pointer_v1_add_listener(xwl_seat->wp_relative_pointer,
+                                             &relative_pointer_listener,
+                                             xwl_seat);
+    }
+
     if (xwl_seat->relative_pointer == NULL) {
         xwl_seat->relative_pointer =
             add_device(xwl_seat, "xwayland-relative-pointer",
@@ -903,6 +958,11 @@ init_relative_pointer(struct xwl_seat *xwl_seat)
 static void
 release_relative_pointer(struct xwl_seat *xwl_seat)
 {
+    if (xwl_seat->wp_relative_pointer) {
+        zwp_relative_pointer_v1_destroy(xwl_seat->wp_relative_pointer);
+        xwl_seat->wp_relative_pointer = NULL;
+    }
+
     if (xwl_seat->relative_pointer)
         DisableDevice(xwl_seat->relative_pointer, TRUE);
 }
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 1fbae15..24b3e91 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -125,6 +125,7 @@ struct xwl_seat {
     struct xwl_screen *xwl_screen;
     struct wl_seat *seat;
     struct wl_pointer *wl_pointer;
+    struct zwp_relative_pointer_v1 *wp_relative_pointer;
     struct wl_keyboard *wl_keyboard;
     struct wl_touch *wl_touch;
     struct wl_array keys;
@@ -150,6 +151,12 @@ struct xwl_seat {
         Bool has_absolute;
         wl_fixed_t x;
         wl_fixed_t y;
+
+        Bool has_relative;
+        double dx;
+        double dy;
+        double dx_unaccel;
+        double dy_unaccel;
     } pending_pointer_event;
 };
 
-- 
2.7.4

_______________________________________________
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