diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index fcd94437c..79f871068 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -1,6 +1,7 @@ #ifndef _SWAY_INPUT_CURSOR_H #define _SWAY_INPUT_CURSOR_H #include +#include #include "sway/input/seat.h" struct sway_cursor { @@ -8,6 +9,9 @@ struct sway_cursor { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; + struct wlr_box *mapped_box; + bool locked; + struct wl_client *image_client; struct wl_listener motion; @@ -33,4 +37,15 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time); void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state); +void cursor_handle_constraint_inactive( + struct wl_listener *listener, + struct wlr_pointer_constraint_v1 *constraint); + +void cursor_handle_constraint_active( + struct wl_listener *listener, + struct wlr_pointer_constraint_v1_activation *activation); + +void cursor_handle_request_constraint(struct wl_listener *listener, + struct wlr_pointer_constraint_v1 *constraint); + #endif diff --git a/include/sway/server.h b/include/sway/server.h index 296fbf224..398ddb909 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include // TODO WLR: make Xwayland optional @@ -39,6 +40,11 @@ struct sway_server { struct wlr_wl_shell *wl_shell; struct wl_listener wl_shell_surface; + + struct wlr_pointer_constraints_v1 *pointer_constraints; + struct wl_listener constraint_active; + struct wl_listener constraint_inactive; + struct wl_listener request_constraint; }; struct sway_server server; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 648a74c44..5ebf72aa0 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -168,6 +168,8 @@ void view_close(struct sway_view *view); void view_damage(struct sway_view *view, bool whole); +void view_get_layout_box(struct sway_view *view, struct wlr_box *box); + void view_for_each_surface(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index a19f0752a..3299c8646 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -5,6 +5,7 @@ #include #endif #include +#include #include #include "list.h" #include "log.h" @@ -163,9 +164,11 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time) { static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, motion); struct wlr_event_pointer_motion *event = data; - wlr_cursor_move(cursor->cursor, event->device, - event->delta_x, event->delta_y); - cursor_send_pointer_motion(cursor, event->time_msec); + if (!cursor->locked) { + wlr_cursor_move(cursor->cursor, event->device, + event->delta_x, event->delta_y); + cursor_send_pointer_motion(cursor, event->time_msec); + } } static void handle_cursor_motion_absolute( @@ -173,8 +176,10 @@ static void handle_cursor_motion_absolute( struct sway_cursor *cursor = wl_container_of(listener, cursor, motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); - cursor_send_pointer_motion(cursor, event->time_msec); + if (!cursor->locked) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); + cursor_send_pointer_motion(cursor, event->time_msec); + } } void dispatch_cursor_button(struct sway_cursor *cursor, @@ -252,17 +257,19 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis); struct wlr_event_tablet_tool_axis *event = data; - if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && - (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - wlr_cursor_warp_absolute(cursor->cursor, event->device, - event->x, event->y); - cursor_send_pointer_motion(cursor, event->time_msec); - } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { - wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, -1); - cursor_send_pointer_motion(cursor, event->time_msec); - } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - wlr_cursor_warp_absolute(cursor->cursor, event->device, -1, event->y); - cursor_send_pointer_motion(cursor, event->time_msec); + if (!cursor->locked) { + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && + (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x, event->y); + cursor_send_pointer_motion(cursor, event->time_msec); + } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, -1); + cursor_send_pointer_motion(cursor, event->time_msec); + } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, -1, event->y); + cursor_send_pointer_motion(cursor, event->time_msec); + } } } @@ -322,6 +329,60 @@ static void handle_request_set_cursor(struct wl_listener *listener, cursor->image_client = focused_client; } +void cursor_handle_constraint_inactive( + struct wl_listener *listener, + struct wlr_pointer_constraint_v1 *constraint) { + struct sway_seat *seat = constraint->seat_client->seat->data; + struct sway_cursor *cursor = seat->cursor; + + if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) { + wlr_cursor_map_to_region(cursor->cursor, NULL); + free(cursor->mapped_box); + cursor->mapped_box = NULL; + } else { + struct sway_view *view = constraint->surface->data; + + seat->cursor->locked = false; + if (constraint->current.cursor_hint.valid) { + struct wlr_box view_box; + view_get_layout_box(view, &view_box); + wlr_cursor_warp(cursor->cursor, NULL, + view_box.x + constraint->current.cursor_hint.x, + view_box.y + constraint->current.cursor_hint.y); + } + } +} + +void cursor_handle_constraint_active( + struct wl_listener *listener, + struct wlr_pointer_constraint_v1_activation *activation) { + struct wlr_box *box = activation->box; + struct wlr_pointer_constraint_v1 *constraint = activation->pointer_constraint; + struct sway_seat* seat = constraint->seat_client->seat->data; + + if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) { + struct sway_view *view = constraint->surface->data; + if (!box) { + box = calloc(1, sizeof *box); + view_get_layout_box(view, box); + } else { + struct wlr_box view_box; + view_get_layout_box(view, &view_box); + box->x += view_box.x; + box->y += view_box.y; + } + seat->cursor->mapped_box = box; + wlr_cursor_map_to_region(seat->cursor->cursor, box); + } else { + seat->cursor->locked = true; + } +} + +void cursor_handle_request_constraint(struct wl_listener *listener, + struct wlr_pointer_constraint_v1 *constraint) { + wlr_pointer_constraint_v1_accept(constraint); +} + void sway_cursor_destroy(struct sway_cursor *cursor) { if (!cursor) { return; diff --git a/sway/input/seat.c b/sway/input/seat.c index 8bba7d8fc..46833ba25 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -227,6 +227,8 @@ struct sway_seat *seat_create(struct sway_input_manager *input, free(seat); return NULL; } + seat->wlr_seat->data = seat; + seat->wlr_seat->pointer_constraints = input->server->pointer_constraints; seat->cursor = sway_cursor_create(seat); if (!seat->cursor) { diff --git a/sway/server.c b/sway/server.c index 11cb95c08..7a87ca6a9 100644 --- a/sway/server.c +++ b/sway/server.c @@ -21,6 +21,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/input/cursor.h" #include "sway/input/input-manager.h" #include "sway/server.h" #include "sway/tree/layout.h" @@ -120,6 +121,17 @@ bool server_init(struct sway_server *server) { return false; } + server->pointer_constraints = wlr_pointer_constraints_v1_create(server->wl_display); + server->constraint_inactive.notify = (wl_notify_func_t)cursor_handle_constraint_inactive; + wl_signal_add(&server->pointer_constraints->events.constraint_inactive, + &server->constraint_inactive); + server->constraint_active.notify = (wl_notify_func_t)cursor_handle_constraint_active; + wl_signal_add(&server->pointer_constraints->events.constraint_active, + &server->constraint_active); + server->request_constraint.notify = (wl_notify_func_t)cursor_handle_request_constraint; + wl_signal_add(&server->pointer_constraints->events.request_constraint, + &server->request_constraint); + input_manager = input_manager_create(server); return true; } diff --git a/sway/tree/view.c b/sway/tree/view.c index b92c70996..5860f36e8 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -134,7 +134,7 @@ void view_damage(struct sway_view *view, bool whole) { } } -static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { +void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { struct sway_container *output = container_parent(view->swayc, C_OUTPUT); box->x = output->x + view->swayc->x; @@ -219,6 +219,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { struct sway_container *cont = container_view_create(focus, view); view->surface = wlr_surface; + wlr_surface->data = view; view->swayc = cont; view_init_subsurfaces(view, wlr_surface);