From 95ab5c656f73ad4b079cfea886e0ea462113013b Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Thu, 31 Mar 2022 15:49:01 +0800 Subject: [PATCH] add basic support for pointer constraints A simplified version of johanmalm/labwc#85. --- Makefile | 14 ++++++++++-- dwl.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 536454f..3ebbcf0 100644 --- a/Makefile +++ b/Makefile @@ -56,9 +56,19 @@ idle-protocol.c: idle-protocol.o: idle-protocol.h +pointer-constraints-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ + +pointer-constraints-unstable-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ + +pointer-constraints-unstable-v1-protocol.o: pointer-constraints-unstable-v1-protocol.h + config.h: | config.def.h cp config.def.h $@ -dwl.o: config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h +dwl.o: config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h pointer-constraints-unstable-v1-protocol.h -dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o +dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o pointer-constraints-unstable-v1-protocol.o diff --git a/dwl.c b/dwl.c index 529dbf8..53e5779 100644 --- a/dwl.c +++ b/dwl.c @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include #include @@ -295,6 +297,9 @@ static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface ** Client **pc, LayerSurface **pl, double *nx, double *ny); static Monitor *xytomon(double x, double y); static void zoom(const Arg *arg); +static void constraincursor(struct wlr_pointer_constraint_v1 *con); +static void newconstraint(struct wl_listener *listener, void *data); +static void destroyconstraint(struct wl_listener *listener, void *data); /* variables */ static const char broken[] = "broken"; @@ -316,6 +321,8 @@ static struct wlr_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; +struct wlr_pointer_constraints_v1 *constraints; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -331,6 +338,8 @@ static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; +struct wlr_pointer_constraint_v1 *constraint = NULL; + /* global event handlers */ static struct wl_listener cursor_axis = {.notify = axisnotify}; static struct wl_listener cursor_button = {.notify = buttonpress}; @@ -354,6 +363,8 @@ static struct wl_listener request_set_sel = {.notify = setsel}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; static struct wl_listener drag_icon_destroy = {.notify = dragicondestroy}; +static struct wl_listener new_constraint = {.notify = newconstraint}; +static struct wl_listener destroy_constraint = {.notify = destroyconstraint}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -1313,7 +1324,7 @@ keypress(struct wl_listener *listener, void *data) /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ if (!input_inhibit_mgr->active_inhibitor - && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + && event->state == WL_KEYBOARD_KEY_STATE_PRESSED && !constraint) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; @@ -1425,6 +1436,7 @@ monocle(Monitor *m) void motionabsolute(struct wl_listener *listener, void *data) { + double lx, ly, dx, dy; /* This event is forwarded by the cursor when a pointer emits an _absolute_ * motion event, from 0..1 on each axis. This happens, for example, when * wlroots is running under a Wayland window rather than KMS+DRM, and you @@ -1432,7 +1444,11 @@ motionabsolute(struct wl_listener *listener, void *data) * so we have to warp the mouse there. There is also some hardware which * emits these events. */ struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(cursor, event->device, event->x, event->y); + wlr_cursor_absolute_to_layout_coords(cursor, event->device, event->x, event->y, &lx, &ly); + dx = lx - cursor->x; + dy = ly - cursor->y; + wlr_relative_pointer_manager_v1_send_relative_motion(relative_pointer_mgr, seat, + (uint64_t)event->time_msec * 1000, dx, dy, dx, dy); motionnotify(event->time_msec); } @@ -1492,7 +1508,11 @@ motionrelative(struct wl_listener *listener, void *data) * 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(cursor, event->device, event->delta_x, event->delta_y); + wlr_relative_pointer_manager_v1_send_relative_motion(relative_pointer_mgr, seat, + (uint64_t)event->time_msec * 1000, event->delta_x, + event->delta_y, event->unaccel_dx, event->unaccel_dy); + if (!constraint) + wlr_cursor_move(cursor, event->device, event->delta_x, event->delta_y); motionnotify(event->time_msec); } @@ -1586,12 +1606,49 @@ outputmgrtest(struct wl_listener *listener, void *data) outputmgrapplyortest(config, 1); } +static void +destroyconstraint(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_constraint_v1 *con = data; + + wl_list_remove(&destroy_constraint.link); + if (constraint == con) + constraint = NULL; +} + +void +constraincursor(struct wlr_pointer_constraint_v1 *con) +{ + if (constraint == con) + return; + + if (constraint) + wlr_pointer_constraint_v1_send_deactivated(constraint); + + constraint = con; + wlr_pointer_constraint_v1_send_activated(constraint); +} + +void +newconstraint(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_constraint_v1 *con = data; + + wl_signal_add(&con->events.destroy, &destroy_constraint); + + constraincursor(con); +} + void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; int internal_call = !time; + struct wlr_pointer_constraint_v1 *con; + + con = wlr_pointer_constraints_v1_constraint_for_surface(constraints, surface, seat); + constraincursor(con); if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -2001,6 +2058,10 @@ setup(void) input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); + relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); + constraints = wlr_pointer_constraints_v1_create(dpy); + wl_signal_add(&constraints->events.new_constraint, &new_constraint); + /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(dpy),