diff --git a/src/backend/wayland/wl_handlers.c b/src/backend/wayland/wl_handlers.c index a69254a..8420e34 100644 --- a/src/backend/wayland/wl_handlers.c +++ b/src/backend/wayland/wl_handlers.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -99,16 +100,54 @@ handle_pointer_axis(struct wl_listener *listener, void *data) * In headless mode the pointer is virtual so there is nothing physically * to lock, but activating keeps the client happy. */ +struct wl_constraint_ctx { + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; +}; + +static void +handle_pointer_constraint_destroy(struct wl_listener *listener, void *data) +{ + struct wl_constraint_ctx *ctx = + wl_container_of(listener, ctx, destroy); + struct wlr_pointer_constraint_v1 *constraint = ctx->constraint; + (void)data; + + if (constraint->current.cursor_hint.enabled && constraint->surface) { + /* Convert surface-local hint to global coordinates */ + double sx = constraint->current.cursor_hint.x; + double sy = constraint->current.cursor_hint.y; + int gx = 0, gy = 0; + /* Find the toplevel view owning this surface to get global pos */ + struct wl_toplevel_view *v; + wl_list_for_each(v, &wl_state.toplevel_list, link) { + if (v->xdg_surface && v->xdg_surface->surface == constraint->surface) { + gx = v->x; + gy = v->y; + break; + } + } + wl_pointer_warp_to(gx + (int)sx, gy + (int)sy); + } + + wl_list_remove(&ctx->destroy.link); + free(ctx); +} + void handle_new_pointer_constraint(struct wl_listener *listener, void *data) { (void)listener; struct wlr_pointer_constraint_v1 *constraint = data; - (void)constraint; - /* Activate immediately — in nested mode the real pointer is bounded - * by the host compositor's window anyway. */ + wlr_pointer_constraint_v1_send_activated(constraint); - wwarning("wl_backend: pointer constraint activated"); + + struct wl_constraint_ctx *ctx = calloc(1, sizeof(*ctx)); + if (ctx) { + ctx->constraint = constraint; + ctx->destroy.notify = handle_pointer_constraint_destroy; + wl_signal_add(&constraint->events.destroy, &ctx->destroy); + } } /*