From f5072151a9a6748571ffcc8766e148fd73a9d814 Mon Sep 17 00:00:00 2001 From: ARDiDo <90479315+ARDiDo@users.noreply.github.com> Date: Sun, 17 Oct 2021 16:54:35 -0400 Subject: [PATCH] add pointer constraints --- include/labwc.h | 18 ++++++++ protocols/meson.build | 1 + src/cursor.c | 101 ++++++++++++++++++++++++++++++++++++++---- src/seat.c | 7 +++ src/server.c | 9 ++++ 5 files changed, 127 insertions(+), 9 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 68c54692..eb00fd02 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -72,6 +74,7 @@ struct seat { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; struct wlr_drag_icon *drag_icon; + struct wlr_pointer_constraint_v1 *current_constraint; /* if set, views cannot receive focus */ struct wlr_layer_surface_v1 *focused_layer; @@ -96,6 +99,7 @@ struct seat { struct wl_listener request_start_drag; struct wl_listener start_drag; struct wl_listener destroy_drag; + struct wl_listener constraint_commit; }; struct server { @@ -143,6 +147,10 @@ struct server { struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; + struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; + struct wlr_pointer_constraints_v1 *constraints; + struct wl_listener new_constraint; + /* Set when in cycle (alt-tab) mode */ struct view *cycle_view; @@ -312,6 +320,12 @@ struct xdg_popup { struct wl_listener new_popup; }; +struct constraint { + struct seat *seat; + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; +}; + void xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup); void xdg_toplevel_decoration(struct wl_listener *listener, void *data); @@ -435,4 +449,8 @@ void osd_update(struct server *server); bool input_inhibit_blocks_surface(struct seat *seat, struct wl_resource *resource); +void create_constraint(struct wl_listener *listener, void *data); +void constrain_cursor(struct server *server, struct wlr_pointer_constraint_v1 + *constraint); + #endif /* __LABWC_H */ diff --git a/protocols/meson.build b/protocols/meson.build index 6541a5fb..c342e0f1 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -15,6 +15,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'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-input-inhibitor-unstable-v1.xml'], ] diff --git a/src/cursor.c b/src/cursor.c index 774e044b..5fc711d8 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -236,6 +236,81 @@ start_drag(struct wl_listener *listener, void *data) wl_signal_add(&seat->drag_icon->events.destroy, &seat->destroy_drag); } +void +handle_constraint_commit(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, constraint_commit); + struct wlr_pointer_constraint_v1 *constraint = seat->current_constraint; + assert(constraint->surface = data); +} + +void +destroy_constraint(struct wl_listener *listener, void *data) +{ + struct constraint *constraint = wl_container_of(listener, constraint, + destroy); + struct wlr_pointer_constraint_v1 *wlr_constraint = data; + struct 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 +create_constraint(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_constraint_v1 *wlr_constraint = data; + struct server *server = wl_container_of(listener, server, + new_constraint); + struct view *view; + struct constraint *constraint = calloc(1, sizeof(struct constraint)); + + constraint->constraint = wlr_constraint; + constraint->seat = &server->seat; + constraint->destroy.notify = destroy_constraint; + wl_signal_add(&wlr_constraint->events.destroy, &constraint->destroy); + + view = desktop_focused_view(server); + if (view->surface == wlr_constraint->surface) { + constrain_cursor(server, wlr_constraint); + } +} + +void +constrain_cursor(struct server *server, struct wlr_pointer_constraint_v1 + *constraint) +{ + struct 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); +} + static void cursor_motion(struct wl_listener *listener, void *data) { @@ -244,17 +319,25 @@ cursor_motion(struct wl_listener *listener, void *data) * _relative_ pointer motion event (i.e. a delta) */ struct seat *seat = wl_container_of(listener, seat, cursor_motion); + struct server *server = seat->server; struct wlr_event_pointer_motion *event = data; - /* - * The cursor doesn't move unless we tell it to. The cursor - * automatically handles constraining the motion to the output layout, - * as well as any special configuration applied for the specific input - * device which generated the event. You can pass NULL for the device - * if you want to move the cursor around without any input. - */ - 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) { + /* + * The cursor doesn't move unless we tell it to. The cursor + * automatically handles constraining the motion to the output layout, + * as well as any special configuration applied for the specific input + * device which generated the event. You can pass NULL for the device + * if you want to move the cursor around without any input. + */ + wlr_cursor_move(seat->cursor, event->device, event->delta_x, + event->delta_y); + } process_cursor_motion(seat->server, event->time_msec); } diff --git a/src/seat.c b/src/seat.c index a9189789..f912762b 100644 --- a/src/seat.c +++ b/src/seat.c @@ -181,6 +181,7 @@ seat_init(struct server *server) exit(EXIT_FAILURE); } + wl_list_init(&seat->constraint_commit.link); wl_list_init(&seat->inputs); seat->new_input.notify = new_input_notify; wl_signal_add(&server->backend->events.new_input, &seat->new_input); @@ -242,6 +243,12 @@ seat_focus_surface(struct seat *seat, struct wlr_surface *surface) struct wlr_keyboard *kb = &seat->keyboard_group->keyboard; wlr_seat_keyboard_notify_enter(seat->seat, surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); + + struct server *server = seat->server; + struct wlr_pointer_constraint_v1 *constraint = + wlr_pointer_constraints_v1_constraint_for_surface(server->constraints, + surface, seat->seat); + constrain_cursor(server, constraint); } void diff --git a/src/server.c b/src/server.c index 0b944bfe..4cbfac8f 100644 --- a/src/server.c +++ b/src/server.c @@ -269,6 +269,15 @@ server_init(struct server *server) wlr_data_control_manager_v1_create(server->wl_display); wlr_gamma_control_manager_v1_create(server->wl_display); + 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 = create_constraint; + wl_signal_add(&server->constraints->events.new_constraint, + &server->new_constraint); + server->input_inhibit = wlr_input_inhibit_manager_create(server->wl_display); if (!server->input_inhibit) {