mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-11-24 06:59:45 -05:00
Implement pointer-constraints protocol in wlroots and rootston
This commit is contained in:
parent
437f538772
commit
fa2e6e7d9d
23 changed files with 1134 additions and 20 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -303,15 +307,86 @@ 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);
|
||||
|
||||
double center_x = view->x + view->width / 2.;
|
||||
double center_y = view->y + view->height / 2.;
|
||||
|
||||
double lx1 = cursor->cursor->x;
|
||||
double ly1 = cursor->cursor->y;
|
||||
|
||||
double lx2 = lx1 + dx;
|
||||
double ly2 = ly1 + dy;
|
||||
|
||||
// Optimization for most common case.
|
||||
// This also makes sure that we don't encounter
|
||||
// precision bugs in the most common case.
|
||||
if (view->rotation == 0.0) {
|
||||
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;
|
||||
} else {
|
||||
assert(false);
|
||||
double c = cos(view->rotation);
|
||||
double s = sin(view->rotation);
|
||||
|
||||
double sx1 = c * (lx1 - center_x) - s * (ly1 - center_y) + view->width / 2.;
|
||||
double sy1 = s * (lx1 - center_x) + c * (ly1 - center_y) + view->height / 2.;
|
||||
|
||||
double sx2 = c * (lx2 - center_x) - s * (ly2 - center_y) + view->width / 2.;
|
||||
double sy2 = s * (lx2 - center_x) + c * (ly2 - center_y) + view->height / 2.;
|
||||
|
||||
double sx2_confined, sy2_confined;
|
||||
if (!wlr_region_confine(&cursor->confine, sx1, sy1, sx2, sy2, &sx2_confined, &sy2_confined)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid NaNs
|
||||
double fraction = (sx2 - sx1) > (sy2 - sy1) ?
|
||||
(sx2_confined - sx1) / (sx2 - sx1) :
|
||||
(sy2_confined - sy1) / (sy2 - sy1);
|
||||
|
||||
dx *= fraction;
|
||||
dy *= fraction;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
lx - view->x, ly - view->y, NULL)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_cursor_warp_closest(cursor->cursor, event->device, lx, ly);
|
||||
roots_cursor_update_position(cursor, event->time_msec);
|
||||
}
|
||||
|
||||
|
|
@ -405,18 +480,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,
|
||||
lx - view->x, 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,
|
||||
|
|
@ -446,3 +537,102 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
void roots_cursor_constrain(struct roots_cursor *cursor,
|
||||
struct wlr_pointer_constraint_v1 *constraint, double sx, double sy) {
|
||||
if (cursor->active_constraint != constraint) {
|
||||
wlr_log(WLR_DEBUG, "roots_cursor_constrain(%p, %p)", cursor, constraint);
|
||||
wlr_log(WLR_DEBUG, "cursor->active_constraint: %p", cursor->active_constraint);
|
||||
|
||||
if (cursor->active_constraint) {
|
||||
wlr_pointer_constraint_v1_send_deactivated(cursor->active_constraint);
|
||||
if (cursor->constraint_commit.link.next) {
|
||||
wl_list_remove(&cursor->constraint_commit.link);
|
||||
}
|
||||
}
|
||||
|
||||
cursor->active_constraint = constraint;
|
||||
|
||||
if (!constraint) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_pointer_constraint_v1_send_activated(constraint);
|
||||
wl_signal_add(&constraint->surface->events.commit,
|
||||
&cursor->constraint_commit);
|
||||
} else if (constraint == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pixman_region32_clear(&cursor->confine);
|
||||
|
||||
pixman_region32_t *region = &constraint->region;
|
||||
|
||||
if (!pixman_region32_contains_point(region, sx, 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.;
|
||||
|
||||
double lx, ly;
|
||||
if (view->rotation == 0.0) {
|
||||
lx = sx + view->x;
|
||||
ly = sy + view->y;
|
||||
} else {
|
||||
double c = cos(view->rotation);
|
||||
double s = sin(view->rotation);
|
||||
|
||||
double center_x = view->width / 2.;
|
||||
double center_y = view->height / 2.;
|
||||
|
||||
lx = c * (sx - center_x) - s * (sy - center_y) + center_x + view->x;
|
||||
ly = s * (sx - center_x) + c * (sy - center_y) + center_y + view->y;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,53 @@ static void input_inhibit_deactivate(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_constraint_create(
|
||||
struct wl_listener *listener,
|
||||
struct wlr_pointer_constraint_v1 *constraint) {
|
||||
struct roots_seat* seat = constraint->seat->data;
|
||||
|
||||
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 == constraint->surface) {
|
||||
assert(!seat->cursor->active_constraint);
|
||||
roots_cursor_constrain(seat->cursor, constraint, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_constraint_destroy(
|
||||
struct wl_listener *listener,
|
||||
struct wlr_pointer_constraint_v1 *constraint) {
|
||||
struct roots_seat* seat = constraint->seat->data;
|
||||
if (seat->cursor->active_constraint == constraint) {
|
||||
roots_cursor_constrain(seat->cursor, NULL, NAN, NAN);
|
||||
if (constraint->current.cursor_hint.valid && seat->cursor->pointer_view) {
|
||||
double sx = constraint->current.cursor_hint.x;
|
||||
double sy = constraint->current.cursor_hint.y;
|
||||
|
||||
struct roots_view *view = seat->cursor->pointer_view->view;
|
||||
|
||||
double lx, ly;
|
||||
if (view->rotation == 0.0) {
|
||||
lx = sx + view->x;
|
||||
ly = sy + view->y;
|
||||
} else {
|
||||
double c = cos(view->rotation);
|
||||
double s = sin(view->rotation);
|
||||
|
||||
double center_x = view->width / 2.;
|
||||
double center_y = view->height / 2.;
|
||||
|
||||
lx = c * (sx - center_x) - s * (sy - center_y) + center_x + view->x;
|
||||
ly = s * (sx - center_x) + c * (sy - center_y) + center_y + view->y;
|
||||
}
|
||||
|
||||
wlr_cursor_warp(seat->cursor->cursor, NULL, lx, ly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct roots_desktop *desktop_create(struct roots_server *server,
|
||||
struct roots_config *config) {
|
||||
wlr_log(WLR_DEBUG, "Initializing roots desktop");
|
||||
|
|
@ -906,6 +954,14 @@ 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->constraint_destroy.notify = (wl_notify_func_t)handle_constraint_destroy;
|
||||
wl_signal_add(&desktop->pointer_constraints->events.constraint_destroy,
|
||||
&desktop->constraint_destroy);
|
||||
desktop->constraint_create.notify = (wl_notify_func_t)handle_constraint_create;
|
||||
wl_signal_add(&desktop->pointer_constraints->events.constraint_create,
|
||||
&desktop->constraint_create);
|
||||
|
||||
return desktop;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -299,6 +299,22 @@ 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 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);
|
||||
}
|
||||
|
||||
static void seat_reset_device_mappings(struct roots_seat *seat,
|
||||
struct wlr_input_device *device) {
|
||||
struct wlr_cursor *cursor = seat->cursor->cursor;
|
||||
|
|
@ -434,6 +450,13 @@ 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);
|
||||
seat->cursor->constraint_commit.notify = handle_constraint_commit;
|
||||
}
|
||||
|
||||
static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener,
|
||||
|
|
@ -1188,7 +1211,9 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) {
|
|||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
roots_cursor_update_focus(seat->cursor);
|
||||
if (seat->cursor) {
|
||||
roots_cursor_update_focus(seat->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1224,7 +1249,10 @@ void roots_seat_set_focus_layer(struct roots_seat *seat,
|
|||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
roots_cursor_update_focus(seat->cursor);
|
||||
|
||||
if (seat->cursor) {
|
||||
roots_cursor_update_focus(seat->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
void roots_seat_set_exclusive_client(struct roots_seat *seat,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue