diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index ef3699dbf..2f0aa4a26 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -1271,6 +1271,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[]) { diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index ab7069c53..5d96fb243 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 e95559ce9..d32235b2f 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,