[PATCH xserver 13/14 v2] xwayland: Translate a pointer grab with confineTo to pointer confinement

Jonas Ådahl jadahl at gmail.com
Tue Sep 13 07:17:07 UTC 2016


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>
---

No changes since v1.

 hw/xwayland/xwayland-input.c | 41 ++++++++++++++++++++++++++++++++++
 hw/xwayland/xwayland.c       | 53 ++++++++++++++++++++++++++++++++++++++++++++
 hw/xwayland/xwayland.h       |  7 ++++++
 3 files changed, 101 insertions(+)

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index a6c816f..48aadc7 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -1254,6 +1254,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 5ceab0f..d22aba3 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -139,6 +139,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)
 {
@@ -332,6 +380,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);
     }
 
@@ -731,6 +782,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 a5d5d91..d62f49a 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -149,6 +149,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;
@@ -187,6 +190,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,
-- 
2.7.4



More information about the xorg-devel mailing list