diff options
Diffstat (limited to 'rootston')
-rw-r--r-- | rootston/config.c | 1 | ||||
-rw-r--r-- | rootston/cursor.c | 219 | ||||
-rw-r--r-- | rootston/desktop.c | 67 | ||||
-rw-r--r-- | rootston/keyboard.c | 8 | ||||
-rw-r--r-- | rootston/output.c | 2 | ||||
-rw-r--r-- | rootston/rootston.ini.example | 2 | ||||
-rw-r--r-- | rootston/seat.c | 24 |
7 files changed, 300 insertions, 23 deletions
diff --git a/rootston/config.c b/rootston/config.c index 92d90de1..5c168679 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -506,6 +506,7 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) { add_binding_config(&config->bindings, "Logo+Shift+E", "exit"); add_binding_config(&config->bindings, "Ctrl+q", "close"); add_binding_config(&config->bindings, "Alt+Tab", "next_window"); + add_binding_config(&config->bindings, "Logo+Escape", "break_pointer_constraint"); struct roots_keyboard_config *kc = calloc(1, sizeof(struct roots_keyboard_config)); kc->meta_key = WLR_MODIFIER_LOGO; diff --git a/rootston/cursor.c b/rootston/cursor.c index 2b8d9a3e..9a163c63 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -1,9 +1,12 @@ #define _XOPEN_SOURCE 700 +#include <assert.h> #include <math.h> #include <stdlib.h> +#include <wlr/types/wlr_region.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/util/edges.h> #include <wlr/util/log.h> +#include <wlr/util/region.h> #ifdef __linux__ #include <linux/input-event-codes.h> #elif __FreeBSD__ @@ -11,6 +14,7 @@ #endif #include "rootston/cursor.h" #include "rootston/desktop.h" +#include "rootston/view.h" #include "rootston/xcursor.h" struct roots_cursor *roots_cursor_create(struct roots_seat *seat) { @@ -100,7 +104,7 @@ static void seat_view_deco_button(struct roots_seat_view *view, double sx, } static void roots_passthrough_cursor(struct roots_cursor *cursor, - uint32_t time) { + int64_t time) { bool focus_changed; double sx, sy; struct roots_view *view = NULL; @@ -108,11 +112,13 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, struct roots_desktop *desktop = seat->input->server->desktop; struct wlr_surface *surface = desktop_surface_at(desktop, cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); + struct wl_client *client = NULL; if (surface) { client = wl_resource_get_client(surface->resource); } - if (surface && !roots_seat_allow_input(cursor->seat, surface->resource)) { + + if (surface && !roots_seat_allow_input(seat, surface->resource)) { return; } @@ -125,21 +131,27 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, if (view) { struct roots_seat_view *seat_view = roots_seat_view_from_view(seat, view); - if (cursor->pointer_view && (surface || - seat_view != cursor->pointer_view)) { + + if (cursor->pointer_view && + !cursor->wlr_surface && (surface || seat_view != cursor->pointer_view)) { seat_view_deco_leave(cursor->pointer_view); - cursor->pointer_view = NULL; } + + cursor->pointer_view = seat_view; + if (!surface) { - cursor->pointer_view = seat_view; seat_view_deco_motion(seat_view, sx, sy); } + } else { + cursor->pointer_view = NULL; } + cursor->wlr_surface = surface; + if (surface) { focus_changed = (seat->seat->pointer_state.focused_surface != surface); wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); - if (!focus_changed) { + if (!focus_changed && time > 0) { wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); } } else { @@ -152,6 +164,10 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, } } +void roots_cursor_update_focus(struct roots_cursor *cursor) { + roots_passthrough_cursor(cursor, -1); +} + void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t time) { struct roots_seat *seat = cursor->seat; @@ -262,7 +278,7 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, } else { if (view && !surface && cursor->pointer_view) { seat_view_deco_button(cursor->pointer_view, - sx, sy, button, state); + sx, sy, button, state); } if (state == WLR_BUTTON_RELEASED && @@ -291,15 +307,59 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, void roots_cursor_handle_motion(struct roots_cursor *cursor, struct wlr_event_pointer_motion *event) { - wlr_cursor_move(cursor->cursor, event->device, - event->delta_x, event->delta_y); + double dx = event->delta_x; + double dy = event->delta_y; + + if (cursor->active_constraint) { + struct roots_view *view = cursor->pointer_view->view; + assert(view); + + // TODO: handle rotated views + if (view->rotation == 0.0) { + double lx1 = cursor->cursor->x; + double ly1 = cursor->cursor->y; + + double lx2 = lx1 + dx; + double ly2 = ly1 + dy; + + double sx1 = lx1 - view->x; + double sy1 = ly1 - view->y; + + double sx2 = lx2 - view->x; + double sy2 = ly2 - view->y; + + double sx2_confined, sy2_confined; + if (!wlr_region_confine(&cursor->confine, sx1, sy1, sx2, sy2, + &sx2_confined, &sy2_confined)) { + return; + } + + dx = sx2_confined - sx1; + dy = sy2_confined - sy1; + } + } + + wlr_cursor_move(cursor->cursor, event->device, dx, dy); roots_cursor_update_position(cursor, event->time_msec); } void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, struct wlr_event_pointer_motion_absolute *event) { - wlr_cursor_warp_absolute(cursor->cursor, - event->device, event->x, event->y); + double lx, ly; + wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, event->x, + event->y, &lx, &ly); + + if (cursor->pointer_view) { + struct roots_view *view = cursor->pointer_view->view; + + if (cursor->active_constraint && + !pixman_region32_contains_point(&cursor->confine, + floor(lx - view->x), floor(ly - view->y), NULL)) { + return; + } + } + + wlr_cursor_warp_closest(cursor->cursor, event->device, lx, ly); roots_cursor_update_position(cursor, event->time_msec); } @@ -324,7 +384,7 @@ void roots_cursor_handle_touch_down(struct roots_cursor *cursor, double sx, sy; struct wlr_surface *surface = desktop_surface_at( - desktop, lx, ly, &sx, &sy, NULL); + desktop, lx, ly, &sx, &sy, NULL); uint32_t serial = 0; if (surface && roots_seat_allow_input(cursor->seat, surface->resource)) { @@ -393,18 +453,34 @@ void roots_cursor_handle_touch_motion(struct roots_cursor *cursor, void roots_cursor_handle_tool_axis(struct roots_cursor *cursor, struct wlr_event_tablet_tool_axis *event) { + double x = NAN, y = NAN; 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); - roots_cursor_update_position(cursor, event->time_msec); + x = event->x; + y = event->y; } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { - wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, -1); - roots_cursor_update_position(cursor, event->time_msec); + x = event->x; } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - wlr_cursor_warp_absolute(cursor->cursor, event->device, -1, event->y); - roots_cursor_update_position(cursor, event->time_msec); + y = event->y; + } + + double lx, ly; + wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, + x, y, &lx, &ly); + + + if (cursor->pointer_view) { + struct roots_view *view = cursor->pointer_view->view; + + if (cursor->active_constraint && + !pixman_region32_contains_point(&cursor->confine, + floor(lx - view->x), floor(ly - view->y), NULL)) { + return; + } } + + wlr_cursor_warp_closest(cursor->cursor, event->device, lx, ly); + roots_cursor_update_position(cursor, event->time_msec); } void roots_cursor_handle_tool_tip(struct roots_cursor *cursor, @@ -434,3 +510,106 @@ void roots_cursor_handle_request_set_cursor(struct roots_cursor *cursor, event->hotspot_y); cursor->cursor_client = event->seat_client->client; } + +void roots_cursor_handle_focus_change(struct roots_cursor *cursor, + struct wlr_seat_pointer_focus_change_event *event) { + double sx = event->sx; + double sy = event->sy; + + double lx = cursor->cursor->x; + double ly = cursor->cursor->y; + + wlr_log(WLR_DEBUG, "entered surface %p, lx: %f, ly: %f, sx: %f, sy: %f", + event->new_surface, lx, ly, sx, sy); + + roots_cursor_constrain(cursor, + wlr_pointer_constraints_v1_constraint_for_surface( + cursor->seat->input->server->desktop->pointer_constraints, + event->new_surface, cursor->seat->seat), + sx, sy); +} + +void roots_cursor_handle_constraint_commit(struct roots_cursor *cursor) { + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + + struct roots_view *view; + double sx, sy; + struct wlr_surface *surface = desktop_surface_at(desktop, + cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); + // This should never happen but views move around right when they're + // created from (0, 0) to their actual coordinates. + if (surface != cursor->active_constraint->surface) { + roots_cursor_update_focus(cursor); + } else { + roots_cursor_constrain(cursor, cursor->active_constraint, sx, sy); + } +} + +static void handle_constraint_commit(struct wl_listener *listener, + void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, constraint_commit); + assert(cursor->active_constraint->surface == data); + roots_cursor_handle_constraint_commit(cursor); +} + +void roots_cursor_constrain(struct roots_cursor *cursor, + struct wlr_pointer_constraint_v1 *constraint, double sx, double sy) { + if (cursor->active_constraint == constraint) { + return; + } + + wlr_log(WLR_DEBUG, "roots_cursor_constrain(%p, %p)", + cursor, constraint); + wlr_log(WLR_DEBUG, "cursor->active_constraint: %p", + cursor->active_constraint); + + wl_list_remove(&cursor->constraint_commit.link); + wl_list_init(&cursor->constraint_commit.link); + if (cursor->active_constraint) { + wlr_pointer_constraint_v1_send_deactivated( + cursor->active_constraint); + } + + cursor->active_constraint = constraint; + + if (constraint == NULL) { + return; + } + + wlr_pointer_constraint_v1_send_activated(constraint); + + wl_list_remove(&cursor->constraint_commit.link); + wl_signal_add(&constraint->surface->events.commit, + &cursor->constraint_commit); + cursor->constraint_commit.notify = handle_constraint_commit; + + pixman_region32_clear(&cursor->confine); + + pixman_region32_t *region = &constraint->region; + + if (!pixman_region32_contains_point(region, floor(sx), floor(sy), NULL)) { + // Warp into region if possible + int nboxes; + pixman_box32_t *boxes = pixman_region32_rectangles(region, &nboxes); + if (nboxes > 0) { + struct roots_view *view = cursor->pointer_view->view; + + double sx = (boxes[0].x1 + boxes[0].x2) / 2.; + double sy = (boxes[0].y1 + boxes[0].y2) / 2.; + + rotate_child_position(&sx, &sy, 0, 0, view->width, view->height, + view->rotation); + + double lx = view->x + sx; + double ly = view->y + sy; + + wlr_cursor_warp_closest(cursor->cursor, NULL, lx, ly); + } + } + + // A locked pointer will result in an empty region, thus disallowing all movement + if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) { + pixman_region32_copy(&cursor->confine, region); + } +} diff --git a/rootston/desktop.c b/rootston/desktop.c index 3f6d977e..c180c839 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -15,6 +15,7 @@ #include <wlr/types/wlr_input_inhibitor.h> #include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_output_layout.h> +#include <wlr/types/wlr_pointer_constraints_v1.h> #include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_server_decoration.h> #include <wlr/types/wlr_wl_shell.h> @@ -776,6 +777,62 @@ static void input_inhibit_deactivate(struct wl_listener *listener, void *data) { } } +static void handle_constraint_destroy(struct wl_listener *listener, + void *data) { + struct roots_pointer_constraint *constraint = + wl_container_of(listener, constraint, destroy); + struct wlr_pointer_constraint_v1 *wlr_constraint = data; + struct roots_seat *seat = wlr_constraint->seat->data; + + wl_list_remove(&constraint->destroy.link); + + if (seat->cursor->active_constraint == wlr_constraint) { + wl_list_remove(&seat->cursor->constraint_commit.link); + wl_list_init(&seat->cursor->constraint_commit.link); + seat->cursor->active_constraint = NULL; + + if (wlr_constraint->current.committed & + WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && + seat->cursor->pointer_view) { + double sx = wlr_constraint->current.cursor_hint.x; + double sy = wlr_constraint->current.cursor_hint.y; + + struct roots_view *view = seat->cursor->pointer_view->view; + rotate_child_position(&sx, &sy, 0, 0, view->width, view->height, + view->rotation); + double lx = view->x + sx; + double ly = view->y + sy; + + wlr_cursor_warp(seat->cursor->cursor, NULL, lx, ly); + } + } + + free(constraint); +} + +static void handle_pointer_constraint(struct wl_listener *listener, + void *data) { + struct wlr_pointer_constraint_v1 *wlr_constraint = data; + struct roots_seat *seat = wlr_constraint->seat->data; + + struct roots_pointer_constraint *constraint = + calloc(1, sizeof(struct roots_pointer_constraint)); + constraint->constraint = wlr_constraint; + + constraint->destroy.notify = handle_constraint_destroy; + wl_signal_add(&wlr_constraint->events.destroy, &constraint->destroy); + + double sx, sy; + struct wlr_surface *surface = desktop_surface_at( + seat->input->server->desktop, + seat->cursor->cursor->x, seat->cursor->cursor->y, &sx, &sy, NULL); + + if (surface == wlr_constraint->surface) { + assert(!seat->cursor->active_constraint); + roots_cursor_constrain(seat->cursor, wlr_constraint, sx, sy); + } +} + struct roots_desktop *desktop_create(struct roots_server *server, struct roots_config *config) { wlr_log(WLR_DEBUG, "Initializing roots desktop"); @@ -887,10 +944,10 @@ struct roots_desktop *desktop_create(struct roots_server *server, wlr_input_inhibit_manager_create(server->wl_display); desktop->input_inhibit_activate.notify = input_inhibit_activate; wl_signal_add(&desktop->input_inhibit->events.activate, - &desktop->input_inhibit_activate); + &desktop->input_inhibit_activate); desktop->input_inhibit_deactivate.notify = input_inhibit_deactivate; wl_signal_add(&desktop->input_inhibit->events.deactivate, - &desktop->input_inhibit_deactivate); + &desktop->input_inhibit_deactivate); desktop->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create( server->wl_display); @@ -906,6 +963,12 @@ struct roots_desktop *desktop_create(struct roots_server *server, &desktop->xdg_toplevel_decoration); desktop->xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; + desktop->pointer_constraints = + wlr_pointer_constraints_v1_create(server->wl_display); + desktop->pointer_constraint.notify = handle_pointer_constraint; + wl_signal_add(&desktop->pointer_constraints->events.new_constraint, + &desktop->pointer_constraint); + return desktop; } diff --git a/rootston/keyboard.c b/rootston/keyboard.c index b5a8093b..6ba0bd6d 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -8,6 +8,7 @@ #include <wlr/backend/multi.h> #include <wlr/backend/session.h> #include <wlr/types/wlr_input_device.h> +#include <wlr/types/wlr_pointer_constraints_v1.h> #include <wlr/types/wlr_pointer.h> #include <wlr/util/log.h> #include <xkbcommon/xkbcommon.h> @@ -176,6 +177,13 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, decoration->wlr_decoration, mode); } } + } else if (strcmp(command, "break_pointer_constraint") == 0) { + struct wl_list *list = + &keyboard->input->seats; + struct roots_seat *seat; + wl_list_for_each(seat, list, link) { + roots_cursor_constrain(seat->cursor, NULL, NAN, NAN); + } } else { wlr_log(WLR_ERROR, "unknown binding command: %s", command); } diff --git a/rootston/output.c b/rootston/output.c index 4207f0d0..e85612fa 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -22,7 +22,7 @@ * Rotate a child's position relative to a parent. The parent size is (pw, ph), * the child position is (*sx, *sy) and its size is (sw, sh). */ -static void rotate_child_position(double *sx, double *sy, double sw, double sh, +void rotate_child_position(double *sx, double *sy, double sw, double sh, double pw, double ph, float rotation) { if (rotation != 0.0) { // Coordinates relative to the center of the subsurface diff --git a/rootston/rootston.ini.example b/rootston/rootston.ini.example index bb0efa44..4b75e9c6 100644 --- a/rootston/rootston.ini.example +++ b/rootston/rootston.ini.example @@ -53,9 +53,11 @@ meta-key = Logo # - "close" to close the current view # - "next_window" to cycle through windows # - "alpha" to cycle a window's alpha channel +# - "break_pointer_constraint" to decline and deactivate all pointer constraints [bindings] Logo+Shift+e = exit Logo+q = close Logo+m = maximize +Logo+Escape = break_pointer_constraint Alt+Tab = next_window Ctrl+Shift+a = alpha diff --git a/rootston/seat.c b/rootston/seat.c index 507254d4..e3336fde 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -299,6 +299,14 @@ static void handle_request_set_cursor(struct wl_listener *listener, roots_cursor_handle_request_set_cursor(cursor, event); } +static void handle_pointer_focus_change(struct wl_listener *listener, + void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, focus_change); + struct wlr_seat_pointer_focus_change_event *event = data; + roots_cursor_handle_focus_change(cursor, event); +} + static void seat_reset_device_mappings(struct roots_seat *seat, struct wlr_input_device *device) { struct wlr_cursor *cursor = seat->cursor->cursor; @@ -434,6 +442,12 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { wl_signal_add(&seat->seat->events.request_set_cursor, &seat->cursor->request_set_cursor); seat->cursor->request_set_cursor.notify = handle_request_set_cursor; + + wl_signal_add(&seat->seat->pointer_state.events.focus_change, + &seat->cursor->focus_change); + seat->cursor->focus_change.notify = handle_pointer_focus_change; + + wl_list_init(&seat->cursor->constraint_commit.link); } static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, @@ -567,6 +581,7 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { free(seat); return NULL; } + seat->seat->data = seat; roots_seat_init_cursor(seat); if (!seat->cursor) { @@ -1186,6 +1201,10 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface, NULL, 0, NULL); } + + if (seat->cursor) { + roots_cursor_update_focus(seat->cursor); + } } /** @@ -1220,6 +1239,11 @@ void roots_seat_set_focus_layer(struct roots_seat *seat, wlr_seat_keyboard_notify_enter(seat->seat, layer->surface, NULL, 0, NULL); } + + + if (seat->cursor) { + roots_cursor_update_focus(seat->cursor); + } } void roots_seat_set_exclusive_client(struct roots_seat *seat, |