xserver: Branch 'master' - 11 commits

Adam Jackson ajax at kemper.freedesktop.org
Wed Oct 5 17:54:05 UTC 2016


 configure.ac                  |    4 
 dix/inpututils.c              |   13 
 hw/xwayland/.gitignore        |    4 
 hw/xwayland/Makefile.am       |   28 +
 hw/xwayland/xwayland-cursor.c |    7 
 hw/xwayland/xwayland-input.c  |  725 +++++++++++++++++++++++++++++++++++++-----
 hw/xwayland/xwayland.c        |   89 +++++
 hw/xwayland/xwayland.h        |   43 ++
 include/input.h               |    5 
 9 files changed, 828 insertions(+), 90 deletions(-)

New commits:
commit a6e85e6330adcdcbcd939c0963daaecc96d41a2a
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:08 2016 +0800

    xwayland: Add pointer warp emulator
    
    Emulate pointer warps by locking the pointer and sending relative
    motion events instead of absolute. X will keep track of the "fake"
    pointer cursor position given the relative motion events, and the
    client warping the cursor will warp the faked cursor position.
    
    Various requirements need to be met for the pointer warp emulator to
    enable:
    
    The cursor must be invisible: since it would not be acceptable that a
    fake cursor position would be different from the visual representation
    of the cursor, emulation can only be done when there is no visual
    representation done by the Wayland compositor. Thus, for the emulator
    to enable, the cursor must be hidden, and would the cursor be displayed
    while the emulator is active, the emulator would be destroyed.
    
    The window that is warped within must be likely to have pointer focus.
    For example, warping outside of the window region will be ignored.
    
    The pointer warp emulator will disable itself once the fake cursor
    position leaves the window region, or the cursor is made visible.
    
    This makes various games depending on pointer warping (such as 3D
    first-person shooters and stategy games using click-to-drag-map like
    things) work.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index b2ae93f..0c1cd34 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -169,12 +169,19 @@ xwl_set_cursor(DeviceIntPtr device,
                ScreenPtr screen, CursorPtr cursor, int x, int y)
 {
     struct xwl_seat *xwl_seat;
+    Bool cursor_visibility_changed;
 
     xwl_seat = device->public.devicePrivate;
     if (xwl_seat == NULL)
         return;
 
+    cursor_visibility_changed = !!xwl_seat->x_cursor ^ !!cursor;
+
     xwl_seat->x_cursor = cursor;
+
+    if (cursor_visibility_changed)
+        xwl_seat_cursor_visibility_changed(xwl_seat);
+
     xwl_seat_set_cursor(xwl_seat);
 }
 
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 2f0aa4a..4d447a5 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -47,6 +47,21 @@ struct sync_pending {
 };
 
 static void
+xwl_pointer_warp_emulator_handle_motion(struct xwl_pointer_warp_emulator *warp_emulator,
+                                        double dx,
+                                        double dy,
+                                        double dx_unaccel,
+                                        double dy_unaccel);
+static void
+xwl_pointer_warp_emulator_maybe_lock(struct xwl_pointer_warp_emulator *warp_emulator,
+                                     struct xwl_window *xwl_window,
+                                     SpritePtr sprite,
+                                     int x, int y);
+
+static void
+xwl_seat_destroy_confined_pointer(struct xwl_seat *xwl_seat);
+
+static void
 xwl_pointer_control(DeviceIntPtr device, PtrCtrl *ctrl)
 {
     /* Nothing to do, dix handles all settings */
@@ -331,6 +346,12 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
         xwl_seat->cursor_frame_cb = NULL;
         xwl_seat_set_cursor(xwl_seat);
     }
+
+    if (xwl_seat->pointer_warp_emulator) {
+        xwl_pointer_warp_emulator_maybe_lock(xwl_seat->pointer_warp_emulator,
+                                             xwl_seat->focus_window,
+                                             NULL, 0, 0);
+    }
 }
 
 static void
@@ -351,8 +372,22 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
 {
     ValuatorMask mask;
 
-    if (xwl_seat->pending_pointer_event.has_absolute ||
+    if (xwl_seat->pointer_warp_emulator &&
         xwl_seat->pending_pointer_event.has_relative) {
+        double dx;
+        double dy;
+        double dx_unaccel;
+        double dy_unaccel;
+
+        dx = xwl_seat->pending_pointer_event.dx;
+        dy = xwl_seat->pending_pointer_event.dy;
+        dx_unaccel = xwl_seat->pending_pointer_event.dx_unaccel;
+        dy_unaccel = xwl_seat->pending_pointer_event.dy_unaccel;
+        xwl_pointer_warp_emulator_handle_motion(xwl_seat->pointer_warp_emulator,
+                                                dx, dy,
+                                                dx_unaccel, dy_unaccel);
+    } else if (xwl_seat->pending_pointer_event.has_absolute ||
+               xwl_seat->pending_pointer_event.has_relative) {
         int x;
         int y;
 
@@ -1271,6 +1306,236 @@ xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window)
     }
 }
 
+static void
+xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_emulator,
+                                       int x,
+                                       int y)
+{
+    struct zwp_locked_pointer_v1 *locked_pointer =
+        warp_emulator->locked_pointer;
+    WindowPtr window;
+    int sx, sy;
+
+    if (!warp_emulator->locked_pointer)
+        return;
+
+    if (!warp_emulator->xwl_seat->focus_window)
+        return;
+
+    window = warp_emulator->xwl_seat->focus_window->window;
+    if (x >= window->drawable.x ||
+        y >= window->drawable.y ||
+        x < (window->drawable.x + window->drawable.width) ||
+        y < (window->drawable.y + window->drawable.height)) {
+        sx = x - window->drawable.x;
+        sy = y - window->drawable.y;
+        zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer,
+                                                       wl_fixed_from_int(sx),
+                                                       wl_fixed_from_int(sy));
+        wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface);
+    }
+}
+
+static Bool
+xwl_pointer_warp_emulator_is_locked(struct xwl_pointer_warp_emulator *warp_emulator)
+{
+    if (warp_emulator->locked_pointer)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+static void
+xwl_pointer_warp_emulator_lock(struct xwl_pointer_warp_emulator *warp_emulator)
+{
+    struct xwl_seat *xwl_seat = warp_emulator->xwl_seat;
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
+    struct zwp_pointer_constraints_v1 *pointer_constraints =
+        xwl_screen->pointer_constraints;
+    struct xwl_window *lock_window = xwl_seat->focus_window;
+
+    warp_emulator->locked_window = lock_window;
+
+    warp_emulator->locked_pointer =
+        zwp_pointer_constraints_v1_lock_pointer(pointer_constraints,
+                                                lock_window->surface,
+                                                xwl_seat->wl_pointer,
+                                                NULL,
+                                                ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+}
+
+static void
+xwl_pointer_warp_emulator_maybe_lock(struct xwl_pointer_warp_emulator *warp_emulator,
+                                     struct xwl_window *xwl_window,
+                                     SpritePtr sprite,
+                                     int x, int y)
+{
+    struct xwl_seat *xwl_seat = warp_emulator->xwl_seat;
+    GrabPtr pointer_grab = xwl_seat->pointer->deviceGrab.grab;
+
+    if (warp_emulator->locked_pointer)
+        return;
+
+    /*
+     * If there is no grab, and the window doesn't have pointer focus, ignore
+     * the warp, as under Wayland it won't receive input anyway.
+     */
+    if (!pointer_grab && xwl_seat->focus_window != xwl_window)
+        return;
+
+    /*
+     * If there is a grab, but it's not an ownerEvents grab and the destination
+     * is not the pointer focus, ignore it, as events wouldn't be delivered
+     * there anyway.
+     */
+    if (pointer_grab &&
+        !pointer_grab->ownerEvents &&
+        XYToWindow(sprite, x, y) != xwl_seat->focus_window->window)
+        return;
+
+    xwl_pointer_warp_emulator_lock(warp_emulator);
+}
+
+static void
+xwl_pointer_warp_emulator_warp(struct xwl_pointer_warp_emulator *warp_emulator,
+                               struct xwl_window *xwl_window,
+                               SpritePtr sprite,
+                               int x, int y)
+{
+    xwl_pointer_warp_emulator_maybe_lock(warp_emulator,
+                                         xwl_window,
+                                         sprite,
+                                         x, y);
+    xwl_pointer_warp_emulator_set_fake_pos(warp_emulator, x, y);
+}
+
+static void
+xwl_pointer_warp_emulator_handle_motion(struct xwl_pointer_warp_emulator *warp_emulator,
+                                        double dx,
+                                        double dy,
+                                        double dx_unaccel,
+                                        double dy_unaccel)
+{
+    struct xwl_seat *xwl_seat = warp_emulator->xwl_seat;
+    ValuatorMask mask;
+    WindowPtr window;
+    int x, y;
+
+    valuator_mask_zero(&mask);
+    valuator_mask_set_unaccelerated(&mask, 0, dx, dx_unaccel);
+    valuator_mask_set_unaccelerated(&mask, 1, dy, dy_unaccel);
+
+    QueuePointerEvents(xwl_seat->relative_pointer, MotionNotify, 0,
+                       POINTER_RELATIVE, &mask);
+
+    window = xwl_seat->focus_window->window;
+    miPointerGetPosition(xwl_seat->pointer, &x, &y);
+
+    if (xwl_pointer_warp_emulator_is_locked(warp_emulator) &&
+        xwl_seat->cursor_confinement_window != warp_emulator->locked_window &&
+        (x < window->drawable.x ||
+         y < window->drawable.y ||
+         x >= (window->drawable.x + window->drawable.width) ||
+         y >= (window->drawable.y + window->drawable.height)))
+        xwl_seat_destroy_pointer_warp_emulator(xwl_seat);
+    else
+        xwl_pointer_warp_emulator_set_fake_pos(warp_emulator, x, y);
+}
+
+static struct xwl_pointer_warp_emulator *
+xwl_pointer_warp_emulator_create(struct xwl_seat *xwl_seat)
+{
+    struct xwl_pointer_warp_emulator *warp_emulator;
+
+    warp_emulator = calloc(sizeof *warp_emulator, 1);
+    if (!warp_emulator) {
+        ErrorF("%s: ENOMEM", __func__);
+        return NULL;
+    }
+
+    warp_emulator->xwl_seat = xwl_seat;
+
+    return warp_emulator;
+}
+
+static void
+xwl_pointer_warp_emulator_destroy(struct xwl_pointer_warp_emulator *warp_emulator)
+{
+    if (warp_emulator->locked_pointer)
+        zwp_locked_pointer_v1_destroy(warp_emulator->locked_pointer);
+    free(warp_emulator);
+}
+
+static void
+xwl_seat_create_pointer_warp_emulator(struct xwl_seat *xwl_seat)
+{
+    if (xwl_seat->confined_pointer)
+        xwl_seat_destroy_confined_pointer(xwl_seat);
+
+    xwl_seat->pointer_warp_emulator =
+        xwl_pointer_warp_emulator_create(xwl_seat);
+}
+
+static Bool
+xwl_seat_can_emulate_pointer_warp(struct xwl_seat *xwl_seat)
+{
+    struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
+
+    if (!xwl_screen->relative_pointer_manager)
+        return FALSE;
+
+    if (!xwl_screen->pointer_constraints)
+        return FALSE;
+
+    return TRUE;
+}
+
+void
+xwl_seat_emulate_pointer_warp(struct xwl_seat *xwl_seat,
+                              struct xwl_window *xwl_window,
+                              SpritePtr sprite,
+                              int x, int y)
+{
+    if (!xwl_seat_can_emulate_pointer_warp(xwl_seat))
+        return;
+
+    if (xwl_seat->x_cursor != NULL)
+        return;
+
+    if (!xwl_seat->pointer_warp_emulator)
+        xwl_seat_create_pointer_warp_emulator(xwl_seat);
+
+    if (!xwl_seat->pointer_warp_emulator)
+        return;
+
+    xwl_pointer_warp_emulator_warp(xwl_seat->pointer_warp_emulator,
+                                   xwl_window,
+                                   sprite,
+                                   x, y);
+}
+
+void
+xwl_seat_cursor_visibility_changed(struct xwl_seat *xwl_seat)
+{
+    if (xwl_seat->pointer_warp_emulator && xwl_seat->x_cursor != NULL)
+        xwl_seat_destroy_pointer_warp_emulator(xwl_seat);
+}
+
+void
+xwl_seat_destroy_pointer_warp_emulator(struct xwl_seat *xwl_seat)
+{
+    if (!xwl_seat->pointer_warp_emulator)
+        return;
+
+    xwl_pointer_warp_emulator_destroy(xwl_seat->pointer_warp_emulator);
+    xwl_seat->pointer_warp_emulator = NULL;
+
+    if (xwl_seat->cursor_confinement_window) {
+        xwl_seat_confine_pointer(xwl_seat,
+                                 xwl_seat->cursor_confinement_window);
+    }
+}
+
 void
 xwl_seat_confine_pointer(struct xwl_seat *xwl_seat,
                          struct xwl_window *xwl_window)
@@ -1281,13 +1546,17 @@ xwl_seat_confine_pointer(struct xwl_seat *xwl_seat,
     if (!pointer_constraints)
         return;
 
-    if (xwl_seat->cursor_confinement_window == xwl_window)
+    if (xwl_seat->cursor_confinement_window == xwl_window &&
+        xwl_seat->confined_pointer)
         return;
 
     xwl_seat_unconfine_pointer(xwl_seat);
 
     xwl_seat->cursor_confinement_window = xwl_window;
 
+    if (xwl_seat->pointer_warp_emulator)
+        return;
+
     xwl_seat->confined_pointer =
         zwp_pointer_constraints_v1_confine_pointer(pointer_constraints,
                                                    xwl_window->surface,
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 5d96fb2..c277870 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -165,6 +165,28 @@ xwl_screen_get_default_seat(struct xwl_screen *xwl_screen)
 }
 
 static void
+xwl_cursor_warped_to(DeviceIntPtr device,
+                     ScreenPtr screen,
+                     ClientPtr client,
+                     WindowPtr window,
+                     SpritePtr sprite,
+                     int x, int y)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_seat *xwl_seat = device->public.devicePrivate;
+    struct xwl_window *xwl_window;
+
+    if (!xwl_seat)
+        xwl_seat = xwl_screen_get_default_seat(xwl_screen);
+
+    xwl_window = xwl_window_from_window(window);
+    if (!xwl_window)
+        return;
+
+    xwl_seat_emulate_pointer_warp(xwl_seat, xwl_window, sprite, x, y);
+}
+
+static void
 xwl_cursor_confined_to(DeviceIntPtr device,
                        ScreenPtr screen,
                        WindowPtr window)
@@ -384,6 +406,10 @@ xwl_unrealize_window(WindowPtr window)
         if (xwl_seat->cursor_confinement_window &&
             xwl_seat->cursor_confinement_window->window == window)
             xwl_seat_unconfine_pointer(xwl_seat);
+        if (xwl_seat->pointer_warp_emulator &&
+            xwl_seat->pointer_warp_emulator->locked_window &&
+            xwl_seat->pointer_warp_emulator->locked_window->window == window)
+            xwl_seat_destroy_pointer_warp_emulator(xwl_seat);
         xwl_seat_clear_touch(xwl_seat, window);
     }
 
@@ -810,6 +836,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xwl_screen->CloseScreen = pScreen->CloseScreen;
     pScreen->CloseScreen = xwl_close_screen;
 
+    pScreen->CursorWarpedTo = xwl_cursor_warped_to;
     pScreen->CursorConfinedTo = xwl_cursor_confined_to;
 
     return ret;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index d32235b..5e5624b 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -120,6 +120,12 @@ struct xwl_touch {
     struct xorg_list link_touch;
 };
 
+struct xwl_pointer_warp_emulator {
+    struct xwl_seat *xwl_seat;
+    struct xwl_window *locked_window;
+    struct zwp_locked_pointer_v1 *locked_pointer;
+};
+
 struct xwl_seat {
     DeviceIntPtr pointer;
     DeviceIntPtr relative_pointer;
@@ -150,6 +156,8 @@ struct xwl_seat {
 
     struct xorg_list sync_pending;
 
+    struct xwl_pointer_warp_emulator *pointer_warp_emulator;
+
     struct xwl_window *cursor_confinement_window;
     struct zwp_confined_pointer_v1 *confined_pointer;
 
@@ -191,6 +199,15 @@ void xwl_seat_destroy(struct xwl_seat *xwl_seat);
 
 void xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window);
 
+void xwl_seat_emulate_pointer_warp(struct xwl_seat *xwl_seat,
+                                   struct xwl_window *xwl_window,
+                                   SpritePtr sprite,
+                                   int x, int y);
+
+void xwl_seat_destroy_pointer_warp_emulator(struct xwl_seat *xwl_seat);
+
+void xwl_seat_cursor_visibility_changed(struct xwl_seat *xwl_seat);
+
 void xwl_seat_confine_pointer(struct xwl_seat *xwl_seat,
                               struct xwl_window *xwl_window);
 void xwl_seat_unconfine_pointer(struct xwl_seat *xwl_seat);
commit 467ab142fff926e1475440dd5f649a49f45808fa
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:07 2016 +0800

    xwayland: Translate a pointer grab with confineTo to pointer confinement
    
    Translate grabbing a pointer device with confineTo set to a window into
    confining the Wayland pointer using the pointer constraints protocol.
    This makes clients that depend on the pointer not going outside of the
    window region, such as certain games and virtual machines viewers, to
    function more properly.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index ef3699d..2f0aa4a 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1272,6 +1272,47 @@ xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window)
 }
 
 void
+xwl_seat_confine_pointer(struct xwl_seat *xwl_seat,
+                         struct xwl_window *xwl_window)
+{
+    struct zwp_pointer_constraints_v1 *pointer_constraints =
+        xwl_seat->xwl_screen->pointer_constraints;
+
+    if (!pointer_constraints)
+        return;
+
+    if (xwl_seat->cursor_confinement_window == xwl_window)
+        return;
+
+    xwl_seat_unconfine_pointer(xwl_seat);
+
+    xwl_seat->cursor_confinement_window = xwl_window;
+
+    xwl_seat->confined_pointer =
+        zwp_pointer_constraints_v1_confine_pointer(pointer_constraints,
+                                                   xwl_window->surface,
+                                                   xwl_seat->wl_pointer,
+                                                   NULL,
+                                                   ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+}
+
+static void
+xwl_seat_destroy_confined_pointer(struct xwl_seat *xwl_seat)
+{
+    zwp_confined_pointer_v1_destroy(xwl_seat->confined_pointer);
+    xwl_seat->confined_pointer = NULL;
+}
+
+void
+xwl_seat_unconfine_pointer(struct xwl_seat *xwl_seat)
+{
+    xwl_seat->cursor_confinement_window = NULL;
+
+    if (xwl_seat->confined_pointer)
+        xwl_seat_destroy_confined_pointer(xwl_seat);
+}
+
+void
 InitInput(int argc, char *argv[])
 {
     ScreenPtr pScreen = screenInfo.screens[0];
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index ab7069c..5d96fb2 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -140,6 +140,54 @@ xwl_close_screen(ScreenPtr screen)
     return screen->CloseScreen(screen);
 }
 
+static struct xwl_window *
+xwl_window_from_window(WindowPtr window)
+{
+    struct xwl_window *xwl_window;
+
+    while (window) {
+        xwl_window = xwl_window_get(window);
+        if (xwl_window)
+            return xwl_window;
+
+        window = window->parent;
+    }
+
+    return NULL;
+}
+
+static struct xwl_seat *
+xwl_screen_get_default_seat(struct xwl_screen *xwl_screen)
+{
+    return container_of(xwl_screen->seat_list.prev,
+                        struct xwl_seat,
+                        link);
+}
+
+static void
+xwl_cursor_confined_to(DeviceIntPtr device,
+                       ScreenPtr screen,
+                       WindowPtr window)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_seat *xwl_seat = device->public.devicePrivate;
+    struct xwl_window *xwl_window;
+
+    if (!xwl_seat)
+        xwl_seat = xwl_screen_get_default_seat(xwl_screen);
+
+    if (window == screen->root) {
+        xwl_seat_unconfine_pointer(xwl_seat);
+        return;
+    }
+
+    xwl_window = xwl_window_from_window(window);
+    if (!xwl_window)
+        return;
+
+    xwl_seat_confine_pointer(xwl_seat, xwl_window);
+}
+
 static void
 damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
 {
@@ -333,6 +381,9 @@ xwl_unrealize_window(WindowPtr window)
             xwl_seat->focus_window = NULL;
         if (xwl_seat->last_xwindow == window)
             xwl_seat->last_xwindow = NullWindow;
+        if (xwl_seat->cursor_confinement_window &&
+            xwl_seat->cursor_confinement_window->window == window)
+            xwl_seat_unconfine_pointer(xwl_seat);
         xwl_seat_clear_touch(xwl_seat, window);
     }
 
@@ -759,6 +810,8 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xwl_screen->CloseScreen = pScreen->CloseScreen;
     pScreen->CloseScreen = xwl_close_screen;
 
+    pScreen->CursorConfinedTo = xwl_cursor_confined_to;
+
     return ret;
 }
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index e95559c..d32235b 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -150,6 +150,9 @@ struct xwl_seat {
 
     struct xorg_list sync_pending;
 
+    struct xwl_window *cursor_confinement_window;
+    struct zwp_confined_pointer_v1 *confined_pointer;
+
     struct {
         Bool has_absolute;
         wl_fixed_t x;
@@ -188,6 +191,10 @@ void xwl_seat_destroy(struct xwl_seat *xwl_seat);
 
 void xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window);
 
+void xwl_seat_confine_pointer(struct xwl_seat *xwl_seat,
+                              struct xwl_window *xwl_window);
+void xwl_seat_unconfine_pointer(struct xwl_seat *xwl_seat);
+
 Bool xwl_screen_init_output(struct xwl_screen *xwl_screen);
 
 struct xwl_output *xwl_output_create(struct xwl_screen *xwl_screen,
commit ca7b593fbe54bc9a0b44037e62e4b4401cbd375e
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Thu Sep 29 10:42:13 2016 +0800

    xwayland: Bind pointer constraints global
    
    Will be used by the pointer warp emulator.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore
index 6e4e54d..38ada56 100644
--- a/hw/xwayland/.gitignore
+++ b/hw/xwayland/.gitignore
@@ -1,5 +1,7 @@
 Xwayland
 drm-client-protocol.h
 drm-protocol.c
+pointer-constraints-unstable-v1-client-protocol.h
+pointer-constraints-unstable-v1-protocol.c
 relative-pointer-unstable-v1-client-protocol.h
 relative-pointer-unstable-v1-protocol.c
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 75b8ead..a3c9fce 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -54,7 +54,9 @@ endif
 
 Xwayland_built_sources +=					\
 	relative-pointer-unstable-v1-client-protocol.h		\
-	relative-pointer-unstable-v1-protocol.c
+	relative-pointer-unstable-v1-protocol.c			\
+	pointer-constraints-unstable-v1-client-protocol.h	\
+	pointer-constraints-unstable-v1-protocol.c
 
 nodist_Xwayland_SOURCES = $(Xwayland_built_sources)
 CLEANFILES = $(Xwayland_built_sources)
@@ -72,6 +74,11 @@ relative-pointer-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/
 relative-pointer-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 
+pointer-constraints-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+pointer-constraints-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
 %-protocol.c : %.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 48f1294..ef3699d 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1143,6 +1143,16 @@ init_relative_pointer_manager(struct xwl_screen *xwl_screen,
 }
 
 static void
+init_pointer_constraints(struct xwl_screen *xwl_screen,
+                         uint32_t id, uint32_t version)
+{
+    xwl_screen->pointer_constraints =
+        wl_registry_bind(xwl_screen->registry, id,
+                         &zwp_pointer_constraints_v1_interface,
+                         1);
+}
+
+static void
 input_handler(void *data, struct wl_registry *registry, uint32_t id,
               const char *interface, uint32_t version)
 {
@@ -1153,6 +1163,8 @@ input_handler(void *data, struct wl_registry *registry, uint32_t id,
         xwl_screen->expecting_event++;
     } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
         init_relative_pointer_manager(xwl_screen, id, version);
+    } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
+        init_pointer_constraints(xwl_screen, id, version);
     }
 }
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index e07b850..e95559c 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -43,6 +43,7 @@
 #include <exevents.h>
 
 #include "relative-pointer-unstable-v1-client-protocol.h"
+#include "pointer-constraints-unstable-v1-client-protocol.h"
 
 struct xwl_screen {
     int width;
@@ -78,6 +79,7 @@ struct xwl_screen {
     struct wl_shm *shm;
     struct wl_shell *shell;
     struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
+    struct zwp_pointer_constraints_v1 *pointer_constraints;
 
     uint32_t serial;
 
commit c14a8c6cc0fcd56c380d1220c2a8f04b74edee93
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:05 2016 +0800

    xwayland: Put getting a xwl_window from a Window in a helper
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 46a2dfc..ab7069c 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -103,6 +103,12 @@ static DevPrivateKeyRec xwl_window_private_key;
 static DevPrivateKeyRec xwl_screen_private_key;
 static DevPrivateKeyRec xwl_pixmap_private_key;
 
+static struct xwl_window *
+xwl_window_get(WindowPtr window)
+{
+    return dixLookupPrivate(&window->devPrivates, &xwl_window_private_key);
+}
+
 struct xwl_screen *
 xwl_screen_get(ScreenPtr screen)
 {
@@ -335,8 +341,7 @@ xwl_unrealize_window(WindowPtr window)
     xwl_screen->UnrealizeWindow = screen->UnrealizeWindow;
     screen->UnrealizeWindow = xwl_unrealize_window;
 
-    xwl_window =
-        dixLookupPrivate(&window->devPrivates, &xwl_window_private_key);
+    xwl_window = xwl_window_get(window);
     if (!xwl_window)
         return ret;
 
commit b4644ce8d3420447a8e5a2339238968da0a59de7
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:04 2016 +0800

    xwayland: Set unaccelerated pointer motion delta if available
    
    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 <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 355e69a..48f1294 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -347,30 +347,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
@@ -387,7 +404,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
@@ -452,7 +469,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
@@ -485,6 +502,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)
 {
@@ -905,6 +948,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",
@@ -917,6 +972,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 4d5de76..e07b850 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -126,6 +126,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;
@@ -151,6 +152,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;
 };
 
commit aa9634d03bc2434dfd25476529eccb14e46fcfdc
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:03 2016 +0800

    xwayland: Dispatch pointer motion events on wl_pointer.frame if possible
    
    Wait until wl_pointer.frame with dispatching the pointer motion event,
    if wl_pointer.frame is supported by the compositor. This will later be
    used to combine unaccelerated motion deltas with the absolute motion
    delta.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 2782225..355e69a 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -347,27 +347,47 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer,
 }
 
 static void
+dispatch_pointer_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;
+
+        valuator_mask_zero(&mask);
+        valuator_mask_set(&mask, 0, dx + sx);
+        valuator_mask_set(&mask, 1, dy + sy);
+
+        QueuePointerEvents(xwl_seat->pointer, MotionNotify, 0,
+                           POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
+    }
+
+    xwl_seat->pending_pointer_event.has_absolute = FALSE;
+}
+
+static void
 pointer_handle_motion(void *data, struct wl_pointer *pointer,
                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
 {
     struct xwl_seat *xwl_seat = data;
-    int32_t dx, dy;
-    int sx = wl_fixed_to_int(sx_w);
-    int sy = wl_fixed_to_int(sy_w);
-    ValuatorMask mask;
 
     if (!xwl_seat->focus_window)
         return;
 
-    dx = xwl_seat->focus_window->window->drawable.x;
-    dy = xwl_seat->focus_window->window->drawable.y;
-
-    valuator_mask_zero(&mask);
-    valuator_mask_set(&mask, 0, dx + sx);
-    valuator_mask_set(&mask, 1, dy + sy);
+    xwl_seat->pending_pointer_event.has_absolute = TRUE;
+    xwl_seat->pending_pointer_event.x = sx_w;
+    xwl_seat->pending_pointer_event.y = sy_w;
 
-    QueuePointerEvents(xwl_seat->pointer, MotionNotify, 0,
-                       POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
+    if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
+        dispatch_pointer_event(xwl_seat);
 }
 
 static void
@@ -427,12 +447,41 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
     QueuePointerEvents(xwl_seat->pointer, MotionNotify, 0, POINTER_RELATIVE, &mask);
 }
 
+static void
+pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
+{
+    struct xwl_seat *xwl_seat = data;
+
+    dispatch_pointer_event(xwl_seat);
+}
+
+static void
+pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source)
+{
+}
+
+static void
+pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
+                         uint32_t time, uint32_t axis)
+{
+}
+
+static void
+pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
+                             uint32_t axis, int32_t discrete)
+{
+}
+
 static const struct wl_pointer_listener pointer_listener = {
     pointer_handle_enter,
     pointer_handle_leave,
     pointer_handle_motion,
     pointer_handle_button,
     pointer_handle_axis,
+    pointer_handle_frame,
+    pointer_handle_axis_source,
+    pointer_handle_axis_stop,
+    pointer_handle_axis_discrete,
 };
 
 static void
@@ -987,7 +1036,7 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version
 
     xwl_seat->seat =
         wl_registry_bind(xwl_screen->registry, id,
-                         &wl_seat_interface, min(version, 4));
+                         &wl_seat_interface, min(version, 5));
     xwl_seat->id = id;
 
     xwl_seat->cursor = wl_compositor_create_surface(xwl_screen->compositor);
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 9f8d984..4d5de76 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -146,6 +146,12 @@ struct xwl_seat {
     struct wl_surface *keyboard_focus;
 
     struct xorg_list sync_pending;
+
+    struct {
+        Bool has_absolute;
+        wl_fixed_t x;
+        wl_fixed_t y;
+    } pending_pointer_event;
 };
 
 struct xwl_output {
commit 42e8902395cb27af5c28306abd577a92c467a62d
Author: Krzysztof Sobiecki <sobkas at gmail.com>
Date:   Tue Sep 13 22:23:49 2016 +0800

    xwayland: Add a new input device used for pointer warping/locking
    
    Generating relative and absolute movement events from the same input
    device is problematic, because an absolute pointer device doesn't
    expect to see any relative motion events. To be able to generate
    relative pointer motion events including unaccelerated deltas, create a
    secondary pointer device 'xwayland-relative-pointer', and use that for
    emitting relative motion events.
    
    Signed-off-by: Krzysztof Sobiecki <sobkas at gmail.com>
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 5251429..2782225 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -134,6 +134,56 @@ xwl_pointer_proc(DeviceIntPtr device, int what)
 #undef NAXES
 }
 
+static int
+xwl_pointer_proc_relative(DeviceIntPtr device, int what)
+{
+#define NAXES 2
+    Atom axes_labels[NAXES] = { 0 };
+
+    switch (what) {
+    case DEVICE_INIT:
+        device->public.on = FALSE;
+
+        axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+        axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+
+        /*
+         * We'll never send buttons, but XGetPointerMapping might in certain
+         * situations make the client think we have no buttons.
+         */
+        if (!init_pointer_buttons(device))
+            return BadValue;
+
+        if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels,
+                                           GetMotionHistorySize(), Relative))
+            return BadValue;
+
+        /* Valuators */
+        InitValuatorAxisStruct(device, 0, axes_labels[0],
+                               NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
+        InitValuatorAxisStruct(device, 1, axes_labels[1],
+                               NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative);
+
+        if (!InitPtrFeedbackClassDeviceStruct(device, xwl_pointer_control))
+            return BadValue;
+
+        return Success;
+
+    case DEVICE_ON:
+        device->public.on = TRUE;
+        return Success;
+
+    case DEVICE_OFF:
+    case DEVICE_CLOSE:
+        device->public.on = FALSE;
+        return Success;
+    }
+
+    return BadMatch;
+
+#undef NAXES
+}
+
 static void
 xwl_keyboard_control(DeviceIntPtr device, KeybdCtrl *ctrl)
 {
@@ -804,6 +854,25 @@ release_pointer(struct xwl_seat *xwl_seat)
 }
 
 static void
+init_relative_pointer(struct xwl_seat *xwl_seat)
+{
+    if (xwl_seat->relative_pointer == NULL) {
+        xwl_seat->relative_pointer =
+            add_device(xwl_seat, "xwayland-relative-pointer",
+                       xwl_pointer_proc_relative);
+        ActivateDevice(xwl_seat->relative_pointer, TRUE);
+    }
+    EnableDevice(xwl_seat->relative_pointer, TRUE);
+}
+
+static void
+release_relative_pointer(struct xwl_seat *xwl_seat)
+{
+    if (xwl_seat->relative_pointer)
+        DisableDevice(xwl_seat->relative_pointer, TRUE);
+}
+
+static void
 init_keyboard(struct xwl_seat *xwl_seat)
 {
     DeviceIntPtr master;
@@ -869,8 +938,10 @@ seat_handle_capabilities(void *data, struct wl_seat *seat,
 
     if (caps & WL_SEAT_CAPABILITY_POINTER && xwl_seat->wl_pointer == NULL) {
         init_pointer(xwl_seat);
+        init_relative_pointer(xwl_seat);
     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && xwl_seat->wl_pointer) {
         release_pointer(xwl_seat);
+        release_relative_pointer(xwl_seat);
     }
 
     if (caps & WL_SEAT_CAPABILITY_KEYBOARD && xwl_seat->wl_keyboard == NULL) {
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 4928435..9f8d984 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -120,6 +120,7 @@ struct xwl_touch {
 
 struct xwl_seat {
     DeviceIntPtr pointer;
+    DeviceIntPtr relative_pointer;
     DeviceIntPtr keyboard;
     DeviceIntPtr touch;
     struct xwl_screen *xwl_screen;
commit 011ada724afdba8955f1d4844b306e61390eead8
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:01 2016 +0800

    xwayland: Move pointer button initialization into helper
    
    We'll later use this for initializing buttons for the relative pointer
    since they need to be the same.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index b8acc87..5251429 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -52,31 +52,44 @@ xwl_pointer_control(DeviceIntPtr device, PtrCtrl *ctrl)
     /* Nothing to do, dix handles all settings */
 }
 
-static int
-xwl_pointer_proc(DeviceIntPtr device, int what)
+static Bool
+init_pointer_buttons(DeviceIntPtr device)
 {
 #define NBUTTONS 10
-#define NAXES 4
     BYTE map[NBUTTONS + 1];
     int i = 0;
     Atom btn_labels[NBUTTONS] = { 0 };
+
+    for (i = 1; i <= NBUTTONS; i++)
+        map[i] = i;
+
+    btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+    btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+    btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+    btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+    btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+    btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+    btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+    /* don't know about the rest */
+
+    if (!InitButtonClassDeviceStruct(device, NBUTTONS, btn_labels, map))
+        return FALSE;
+
+    return TRUE;
+}
+
+static int
+xwl_pointer_proc(DeviceIntPtr device, int what)
+{
+#define NAXES 4
     Atom axes_labels[NAXES] = { 0 };
 
     switch (what) {
     case DEVICE_INIT:
         device->public.on = FALSE;
 
-        for (i = 1; i <= NBUTTONS; i++)
-            map[i] = i;
-
-        btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
-        btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
-        btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
-        btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
-        btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
-        btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
-        btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
-        /* don't know about the rest */
+        if (!init_pointer_buttons(device))
+            return BadValue;
 
         axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
         axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
@@ -103,9 +116,6 @@ xwl_pointer_proc(DeviceIntPtr device, int what)
         if (!InitPtrFeedbackClassDeviceStruct(device, xwl_pointer_control))
             return BadValue;
 
-        if (!InitButtonClassDeviceStruct(device, NBUTTONS, btn_labels, map))
-            return BadValue;
-
         return Success;
 
     case DEVICE_ON:
commit a77d0715c6272cc1778a54dccd8cb68dc28cd761
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:17:00 2016 +0800

    xwayland: Split up device class init/release into functions
    
    Put device class initialization in init_[device_class](xwl_seat) and
    releasing in release_[device class](xwl_seat). The purpose is to make
    it easier to add more type of initialization here later, without making
    the function too large.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 177cf44..b8acc87 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -768,74 +768,111 @@ add_device(struct xwl_seat *xwl_seat,
 }
 
 static void
+init_pointer(struct xwl_seat *xwl_seat)
+{
+    xwl_seat->wl_pointer = wl_seat_get_pointer(xwl_seat->seat);
+    wl_pointer_add_listener(xwl_seat->wl_pointer,
+                            &pointer_listener, xwl_seat);
+
+    if (xwl_seat->pointer == NULL) {
+        xwl_seat_set_cursor(xwl_seat);
+        xwl_seat->pointer =
+            add_device(xwl_seat, "xwayland-pointer", xwl_pointer_proc);
+        ActivateDevice(xwl_seat->pointer, TRUE);
+    }
+    EnableDevice(xwl_seat->pointer, TRUE);
+}
+
+static void
+release_pointer(struct xwl_seat *xwl_seat)
+{
+    wl_pointer_release(xwl_seat->wl_pointer);
+    xwl_seat->wl_pointer = NULL;
+
+    if (xwl_seat->pointer)
+        DisableDevice(xwl_seat->pointer, TRUE);
+}
+
+static void
+init_keyboard(struct xwl_seat *xwl_seat)
+{
+    DeviceIntPtr master;
+
+    xwl_seat->wl_keyboard = wl_seat_get_keyboard(xwl_seat->seat);
+    wl_keyboard_add_listener(xwl_seat->wl_keyboard,
+                             &keyboard_listener, xwl_seat);
+
+    if (xwl_seat->keyboard == NULL) {
+        xwl_seat->keyboard =
+            add_device(xwl_seat, "xwayland-keyboard", xwl_keyboard_proc);
+        ActivateDevice(xwl_seat->keyboard, TRUE);
+    }
+    EnableDevice(xwl_seat->keyboard, TRUE);
+    xwl_seat->keyboard->key->xkbInfo->checkRepeat = keyboard_check_repeat;
+    master = GetMaster(xwl_seat->keyboard, MASTER_KEYBOARD);
+    if (master)
+        master->key->xkbInfo->checkRepeat = keyboard_check_repeat;
+}
+
+static void
+release_keyboard(struct xwl_seat *xwl_seat)
+{
+    wl_keyboard_release(xwl_seat->wl_keyboard);
+    xwl_seat->wl_keyboard = NULL;
+
+    if (xwl_seat->keyboard) {
+        remove_sync_pending(xwl_seat->keyboard);
+        DisableDevice(xwl_seat->keyboard, TRUE);
+    }
+}
+
+static void
+init_touch(struct xwl_seat *xwl_seat)
+{
+    xwl_seat->wl_touch = wl_seat_get_touch(xwl_seat->seat);
+    wl_touch_add_listener(xwl_seat->wl_touch,
+                          &touch_listener, xwl_seat);
+
+    if (xwl_seat->touch)
+        EnableDevice(xwl_seat->touch, TRUE);
+    else {
+        xwl_seat->touch =
+            add_device(xwl_seat, "xwayland-touch", xwl_touch_proc);
+    }
+}
+
+static void
+release_touch(struct xwl_seat *xwl_seat)
+{
+    wl_touch_release(xwl_seat->wl_touch);
+    xwl_seat->wl_touch = NULL;
+
+    if (xwl_seat->touch)
+        DisableDevice(xwl_seat->touch, TRUE);
+}
+
+static void
 seat_handle_capabilities(void *data, struct wl_seat *seat,
                          enum wl_seat_capability caps)
 {
     struct xwl_seat *xwl_seat = data;
-    DeviceIntPtr master;
 
     if (caps & WL_SEAT_CAPABILITY_POINTER && xwl_seat->wl_pointer == NULL) {
-        xwl_seat->wl_pointer = wl_seat_get_pointer(seat);
-        wl_pointer_add_listener(xwl_seat->wl_pointer,
-                                &pointer_listener, xwl_seat);
-
-        if (xwl_seat->pointer == NULL) {
-            xwl_seat_set_cursor(xwl_seat);
-            xwl_seat->pointer =
-                add_device(xwl_seat, "xwayland-pointer", xwl_pointer_proc);
-            ActivateDevice(xwl_seat->pointer, TRUE);
-        }
-        EnableDevice(xwl_seat->pointer, TRUE);
+        init_pointer(xwl_seat);
     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && xwl_seat->wl_pointer) {
-        wl_pointer_release(xwl_seat->wl_pointer);
-        xwl_seat->wl_pointer = NULL;
-
-        if (xwl_seat->pointer)
-            DisableDevice(xwl_seat->pointer, TRUE);
+        release_pointer(xwl_seat);
     }
 
     if (caps & WL_SEAT_CAPABILITY_KEYBOARD && xwl_seat->wl_keyboard == NULL) {
-        xwl_seat->wl_keyboard = wl_seat_get_keyboard(seat);
-        wl_keyboard_add_listener(xwl_seat->wl_keyboard,
-                                 &keyboard_listener, xwl_seat);
-
-        if (xwl_seat->keyboard == NULL) {
-            xwl_seat->keyboard =
-                add_device(xwl_seat, "xwayland-keyboard", xwl_keyboard_proc);
-            ActivateDevice(xwl_seat->keyboard, TRUE);
-        }
-        EnableDevice(xwl_seat->keyboard, TRUE);
-        xwl_seat->keyboard->key->xkbInfo->checkRepeat = keyboard_check_repeat;
-        master = GetMaster(xwl_seat->keyboard, MASTER_KEYBOARD);
-        if (master)
-            master->key->xkbInfo->checkRepeat = keyboard_check_repeat;
+        init_keyboard(xwl_seat);
     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && xwl_seat->wl_keyboard) {
-        wl_keyboard_release(xwl_seat->wl_keyboard);
-        xwl_seat->wl_keyboard = NULL;
-
-        if (xwl_seat->keyboard) {
-            remove_sync_pending(xwl_seat->keyboard);
-            DisableDevice(xwl_seat->keyboard, TRUE);
-        }
+        release_keyboard(xwl_seat);
     }
 
     if (caps & WL_SEAT_CAPABILITY_TOUCH && xwl_seat->wl_touch == NULL) {
-        xwl_seat->wl_touch = wl_seat_get_touch(seat);
-        wl_touch_add_listener(xwl_seat->wl_touch,
-                              &touch_listener, xwl_seat);
-
-        if (xwl_seat->touch)
-            EnableDevice(xwl_seat->touch, TRUE);
-        else {
-            xwl_seat->touch =
-                add_device(xwl_seat, "xwayland-touch", xwl_touch_proc);
-        }
+        init_touch(xwl_seat);
     } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && xwl_seat->wl_touch) {
-        wl_touch_release(xwl_seat->wl_touch);
-        xwl_seat->wl_touch = NULL;
-
-        if (xwl_seat->touch)
-            DisableDevice(xwl_seat->touch, TRUE);
+        release_touch(xwl_seat);
     }
 
     xwl_seat->xwl_screen->expecting_event--;
commit 9037ba736a0424feee2fb6ac20cf7687613dc452
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Thu Sep 29 10:40:01 2016 +0800

    xwayland: Bind the relative pointer manager
    
    Will be used for getting unaccelerated motion events and later for
    relative motions used by a pointer warp emulator.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/configure.ac b/configure.ac
index 4fff769..329dc5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2533,7 +2533,7 @@ AM_CONDITIONAL(XFAKESERVER, [test "x$KDRIVE" = xyes && test "x$XFAKE" = xyes])
 
 dnl Xwayland DDX
 
-XWAYLANDMODULES="wayland-client >= 1.3.0 libdrm epoxy"
+XWAYLANDMODULES="wayland-client >= 1.3.0 wayland-protocols >= 1.1 libdrm epoxy"
 if test "x$XF86VIDMODE" = xyes; then
 	XWAYLANDMODULES="$XWAYLANDMODULES $VIDMODEPROTO"
 fi
@@ -2562,6 +2562,8 @@ if test "x$XWAYLAND" = xyes; then
 	WAYLAND_PREFIX=`$PKG_CONFIG --variable=prefix wayland-client`
 	AC_PATH_PROG([WAYLAND_SCANNER], [wayland-scanner],,
 		     [${WAYLAND_PREFIX}/bin$PATH_SEPARATOR$PATH])
+
+	AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, `$PKG_CONFIG --variable=pkgdatadir wayland-protocols`)
 fi
 
 
diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore
index c54ba2d..6e4e54d 100644
--- a/hw/xwayland/.gitignore
+++ b/hw/xwayland/.gitignore
@@ -1,3 +1,5 @@
 Xwayland
 drm-client-protocol.h
 drm-protocol.c
+relative-pointer-unstable-v1-client-protocol.h
+relative-pointer-unstable-v1-protocol.c
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 34fd633..75b8ead 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -30,6 +30,7 @@ Xwayland_LDADD =				\
 	$(XSERVER_SYS_LIBS)
 Xwayland_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
 
+Xwayland_built_sources =
 
 if GLAMOR_EGL
 Xwayland_SOURCES += 				\
@@ -39,13 +40,11 @@ Xwayland_SOURCES += 				\
 	xwayland-glamor-xv.c
 endif
 
-nodist_Xwayland_SOURCES =			\
+glamor_built_sources =				\
 	drm-client-protocol.h			\
 	drm-protocol.c
 
-CLEANFILES = $(nodist_Xwayland_SOURCES)
-
-xwayland-glamor.c : $(nodist_Xwayland_SOURCES)
+Xwayland_built_sources += $(glamor_built_sources)
 
 glamor_lib = $(top_builddir)/glamor/libglamor.la
 
@@ -53,12 +52,26 @@ Xwayland_LDADD += $(GLAMOR_LIBS) $(GBM_LIBS) -lEGL -lGL
 Xwayland_DEPENDENCIES = $(glamor_lib) $(XWAYLAND_LIBS)
 endif
 
+Xwayland_built_sources +=					\
+	relative-pointer-unstable-v1-client-protocol.h		\
+	relative-pointer-unstable-v1-protocol.c
+
+nodist_Xwayland_SOURCES = $(Xwayland_built_sources)
+CLEANFILES = $(Xwayland_built_sources)
+
 EXTRA_DIST = drm.xml
 
 
+$(Xwayland_SOURCES): $(Xwayland_built_sources)
+
 relink:
 	$(AM_V_at)rm -f Xwayland$(EXEEXT) && $(MAKE) Xwayland$(EXEEXT)
 
+relative-pointer-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+relative-pointer-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
 %-protocol.c : %.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index d3a8e50..177cf44 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -906,6 +906,16 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat)
 }
 
 static void
+init_relative_pointer_manager(struct xwl_screen *xwl_screen,
+                              uint32_t id, uint32_t version)
+{
+    xwl_screen->relative_pointer_manager =
+        wl_registry_bind(xwl_screen->registry, id,
+                         &zwp_relative_pointer_manager_v1_interface,
+                         1);
+}
+
+static void
 input_handler(void *data, struct wl_registry *registry, uint32_t id,
               const char *interface, uint32_t version)
 {
@@ -914,6 +924,8 @@ input_handler(void *data, struct wl_registry *registry, uint32_t id,
     if (strcmp(interface, "wl_seat") == 0 && version >= 3) {
         create_input_device(xwl_screen, id, version);
         xwl_screen->expecting_event++;
+    } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
+        init_relative_pointer_manager(xwl_screen, id, version);
     }
 }
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 3ce7a63..4928435 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -42,6 +42,8 @@
 #include <randrstr.h>
 #include <exevents.h>
 
+#include "relative-pointer-unstable-v1-client-protocol.h"
+
 struct xwl_screen {
     int width;
     int height;
@@ -75,6 +77,7 @@ struct xwl_screen {
     struct wl_compositor *compositor;
     struct wl_shm *shm;
     struct wl_shell *shell;
+    struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
 
     uint32_t serial;
 
commit 0fae3be0686cae746e03d6e4592f97278cc2275d
Author: Jonas Ådahl <jadahl at gmail.com>
Date:   Tue Sep 13 15:16:57 2016 +0800

    dix: Add valuator_mask_set_absolute_unaccelerated
    
    Add a valuator mask setter for setting absolute coordinate combined
    with unaccelerated motion deltas. This will later be used by Xwayland
    to combine a wl_pointer.motion() event with the unaccelerated delta of
    a wp_relative_pointer.relative_motion() event.
    
    Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/inpututils.c b/dix/inpututils.c
index 5b7da3a..6bff9ef 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -636,6 +636,19 @@ valuator_mask_drop_unaccelerated(ValuatorMask *mask)
     mask->has_unaccelerated = FALSE;
 }
 
+void
+valuator_mask_set_absolute_unaccelerated(ValuatorMask *mask,
+                                         int valuator,
+                                         int absolute,
+                                         double unaccel)
+{
+    BUG_WARN_MSG(mask->last_bit != -1 && !mask->has_unaccelerated,
+                 "Do not mix valuator types, zero mask first\n");
+    _valuator_mask_set_double(mask, valuator, absolute);
+    mask->has_unaccelerated = TRUE;
+    mask->unaccelerated[valuator] = unaccel;
+}
+
 /**
  * Set both accelerated and unaccelerated value for this mask.
  */
diff --git a/include/input.h b/include/input.h
index e0f6b9b..c7b1e91 100644
--- a/include/input.h
+++ b/include/input.h
@@ -675,12 +675,15 @@ extern _X_EXPORT Bool valuator_mask_fetch(const ValuatorMask *mask,
                                           int valnum, int *val);
 extern _X_EXPORT Bool valuator_mask_fetch_double(const ValuatorMask *mask,
                                                  int valnum, double *val);
-
 extern _X_EXPORT Bool valuator_mask_has_unaccelerated(const ValuatorMask *mask);
 extern _X_EXPORT void valuator_mask_set_unaccelerated(ValuatorMask *mask,
                                                       int valuator,
                                                       double accel,
                                                       double unaccel);
+extern _X_EXPORT void valuator_mask_set_absolute_unaccelerated(ValuatorMask *mask,
+                                                               int valuator,
+                                                               int absolute,
+                                                               double unaccel);
 extern _X_EXPORT double valuator_mask_get_accelerated(const ValuatorMask *mask,
                                                       int valuator);
 extern _X_EXPORT double valuator_mask_get_unaccelerated(const ValuatorMask *mask,


More information about the xorg-commit mailing list