From 4e9b9273f18f124e4ed323c272b62f2fbf67be9d Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Wed, 22 Dec 2021 08:31:14 +0200 Subject: [PATCH] apply labwc/labwc#85 to add support for pointer constraints --- cage.c | 8 +++++ meson.build | 1 + seat.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++-- seat.h | 11 ++++++ server.h | 6 ++++ 5 files changed, 121 insertions(+), 3 deletions(-) diff --git a/cage.c b/cage.c index 95f0cc7..272ae3d 100644 --- a/cage.c +++ b/cage.c @@ -36,6 +36,8 @@ #if CAGE_HAS_XWAYLAND #include #endif +#include +#include #include #include #include @@ -459,6 +461,12 @@ main(int argc, char *argv[]) goto end; } + server.relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server.wl_display); + server.constraints = wlr_pointer_constraints_v1_create(server.wl_display); + + server.new_constraint.notify = seat_create_constraint; + wl_signal_add(&server.constraints->events.new_constraint, &server.new_constraint); + #if CAGE_HAS_XWAYLAND xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { diff --git a/meson.build b/meson.build index 781d4de..e1bcaa3 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,7 @@ wayland_scanner_server = generator( server_protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], ] server_protos_headers = [] diff --git a/seat.c b/seat.c index f155506..72b1f1f 100644 --- a/seat.c +++ b/seat.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -252,7 +253,8 @@ handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *da bool handled = false; uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); - if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED && + !seat->current_constraint) { /* If Alt is held down and this button was pressed, we * attempt to process it as a compositor * keybinding. */ @@ -571,7 +573,18 @@ handle_cursor_motion_absolute(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(seat->cursor, event->device, event->x, event->y); + double lx, ly; + wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); + + double dx = lx - seat->cursor->x; + double dy = ly - seat->cursor->y; + + wlr_relative_pointer_manager_v1_send_relative_motion(seat->server->relative_pointer_manager, seat->seat, + (uint64_t) event->time_msec * 1000, dx, dy, dx, dy); + + if (!seat->current_constraint) { + wlr_cursor_move(seat->cursor, event->device, dx, dy); + } process_cursor_motion(seat, event->time_msec); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -580,9 +593,15 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion); + struct cg_server *server = seat->server; struct wlr_event_pointer_motion *event = data; - wlr_cursor_move(seat->cursor, event->device, event->delta_x, event->delta_y); + wlr_relative_pointer_manager_v1_send_relative_motion(server->relative_pointer_manager, seat->seat, + (uint64_t) event->time_msec * 1000, event->delta_x, + event->delta_y, event->unaccel_dx, event->unaccel_dy); + if (!seat->current_constraint) { + wlr_cursor_move(seat->cursor, event->device, event->delta_x, event->delta_y); + } process_cursor_motion(seat, event->time_msec); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -786,6 +805,8 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) wl_list_init(&seat->pointers); wl_list_init(&seat->touch); + wl_list_init(&seat->constraint_commit.link); + seat->new_input.notify = handle_new_input; wl_signal_add(&backend->events.new_input, &seat->new_input); @@ -867,5 +888,76 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) wlr_seat_keyboard_notify_enter(wlr_seat, view->wlr_surface, NULL, 0, NULL); } + struct wlr_pointer_constraint_v1 *constraint = + wlr_pointer_constraints_v1_constraint_for_surface(server->constraints, view->wlr_surface, wlr_seat); + seat_constrain_cursor(server, constraint); + process_cursor_motion(seat, -1); } + +static void +handle_constraint_commit(struct wl_listener *listener, void *data) +{ +} + +static void +destroy_constraint(struct wl_listener *listener, void *data) +{ + struct cg_constraint *constraint = wl_container_of(listener, constraint, destroy); + struct wlr_pointer_constraint_v1 *wlr_constraint = data; + struct cg_seat *seat = constraint->seat; + + wl_list_remove(&constraint->destroy.link); + if (seat->current_constraint == wlr_constraint) { + if (seat->constraint_commit.link.next != NULL) { + wl_list_remove(&seat->constraint_commit.link); + } + wl_list_init(&seat->constraint_commit.link); + seat->current_constraint = NULL; + } + + free(constraint); +} + +void +seat_create_constraint(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_constraint_v1 *wlr_constraint = data; + struct cg_server *server = wl_container_of(listener, server, new_constraint); + struct cg_view *view; + struct cg_constraint *constraint = calloc(1, sizeof(struct cg_constraint)); + + constraint->constraint = wlr_constraint; + constraint->seat = server->seat; + constraint->destroy.notify = destroy_constraint; + wl_signal_add(&wlr_constraint->events.destroy, &constraint->destroy); + + view = seat_get_focus(server->seat); + if (view->wlr_surface == wlr_constraint->surface) { + seat_constrain_cursor(server, wlr_constraint); + } +} + +void +seat_constrain_cursor(struct cg_server *server, struct wlr_pointer_constraint_v1 *constraint) +{ + struct cg_seat *seat = server->seat; + if (seat->current_constraint == constraint) { + return; + } + wl_list_remove(&seat->constraint_commit.link); + if (seat->current_constraint) { + wlr_pointer_constraint_v1_send_deactivated(seat->current_constraint); + } + + seat->current_constraint = constraint; + + if (constraint == NULL) { + wl_list_init(&seat->constraint_commit.link); + return; + } + + wlr_pointer_constraint_v1_send_activated(constraint); + seat->constraint_commit.notify = handle_constraint_commit; + wl_signal_add(&constraint->surface->events.commit, &seat->constraint_commit); +} diff --git a/seat.h b/seat.h index 5fb2db3..4cc755a 100644 --- a/seat.h +++ b/seat.h @@ -27,11 +27,13 @@ struct cg_seat { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; + struct wlr_pointer_constraint_v1 *current_constraint; struct wl_listener cursor_motion; struct wl_listener cursor_motion_absolute; struct wl_listener cursor_button; struct wl_listener cursor_axis; struct wl_listener cursor_frame; + struct wl_listener constraint_commit; int32_t touch_id; double touch_lx; @@ -85,9 +87,18 @@ struct cg_drag_icon { struct wl_listener destroy; }; +struct cg_constraint { + struct cg_seat *seat; + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; +}; + struct cg_seat *seat_create(struct cg_server *server, struct wlr_backend *backend); void seat_destroy(struct cg_seat *seat); struct cg_view *seat_get_focus(struct cg_seat *seat); void seat_set_focus(struct cg_seat *seat, struct cg_view *view); +void seat_create_constraint(struct wl_listener *listener, void *data); +void seat_constrain_cursor(struct cg_server *server, struct wlr_pointer_constraint_v1 *constraint); + #endif diff --git a/server.h b/server.h index bb7f3c1..d9d5dd6 100644 --- a/server.h +++ b/server.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #if CAGE_HAS_XWAYLAND #include @@ -42,6 +44,10 @@ struct cg_server { struct wl_list outputs; // cg_output::link struct wl_listener new_output; + struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; + struct wlr_pointer_constraints_v1 *constraints; + struct wl_listener new_constraint; + struct wl_listener xdg_toplevel_decoration; struct wl_listener new_xdg_shell_surface; #if CAGE_HAS_XWAYLAND