diff --git a/Makefile b/Makefile index f0ff805..cc5e98c 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ -dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h pointer-constraints-unstable-v1-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -28,6 +28,9 @@ WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +pointer-constraints-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ wlr-layer-shell-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ diff --git a/dwl.c b/dwl.c index bbb27e4..8339e90 100644 --- a/dwl.c +++ b/dwl.c @@ -1,6 +1,7 @@ /* * See LICENSE file for copyright and license details. */ +#include #include #include #include @@ -35,8 +36,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -209,6 +212,13 @@ typedef struct { int x, y; } MonitorRule; +struct pointer_constraint { + struct wlr_pointer_constraint_v1 *constraint; + + struct wl_listener set_region; + struct wl_listener destroy; +}; + typedef struct { const char *id; const char *title; @@ -251,6 +261,7 @@ static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); +static void createpointerconstraint(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); @@ -260,12 +271,14 @@ static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionmgr(struct wl_listener *listener, void *data); +static void destroypointerconstraint(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); +static void handleconstraintcommit(struct wl_listener *listener, void *data); static void handlesig(int signo); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); @@ -377,6 +390,11 @@ static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; +struct wlr_pointer_constraints_v1 *pointer_constraints; +struct wlr_pointer_constraint_v1 *active_constraint; +static struct wl_listener constraint_commit; +struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; + #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data); @@ -930,6 +948,30 @@ createmon(struct wl_listener *listener, void *data) strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); } +void +createpointerconstraint(struct wl_listener *listener, void *data) +{ + if (focustop(selmon)) { + struct wlr_pointer_constraint_v1 *constraint = data; + struct pointer_constraint *pointer_constraint = calloc(1, sizeof(struct pointer_constraint)); + pointer_constraint->constraint = constraint; + + pointer_constraint->destroy.notify = destroypointerconstraint; + wl_signal_add(&constraint->events.destroy, &pointer_constraint->destroy); + + if (client_surface(focustop(selmon)) == constraint->surface) { + if (active_constraint == constraint) + return; + + active_constraint = constraint; + wlr_pointer_constraint_v1_send_activated(constraint); + + constraint_commit.notify = handleconstraintcommit; + wl_signal_add(&constraint->surface->events.commit, &constraint_commit); + } + } +} + void createnotify(struct wl_listener *listener, void *data) { @@ -1022,6 +1064,25 @@ createpointer(struct wlr_pointer *pointer) wlr_cursor_attach_input_device(cursor, &pointer->base); } +void +destroypointerconstraint(struct wl_listener *listener, void *data) +{ + struct wlr_pointer_constraint_v1 *constraint = data; + struct pointer_constraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy); + + wl_list_remove(&pointer_constraint->destroy.link); + + if (active_constraint == constraint) { + if (constraint_commit.link.next != NULL) { + wl_list_remove(&constraint_commit.link); + } + wl_list_init(&constraint_commit.link); + active_constraint = NULL; + } + + free(pointer_constraint); +} + void cursorframe(struct wl_listener *listener, void *data) { @@ -1295,6 +1356,12 @@ fullscreennotify(struct wl_listener *listener, void *data) setfullscreen(c, client_wants_fullscreen(c)); } +void +handleconstraintcommit(struct wl_listener *listener, void *data) +{ + assert(active_constraint->surface == data); +} + void handlesig(int signo) { @@ -1676,7 +1743,15 @@ 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->pointer->base, event->delta_x, event->delta_y); + wlr_relative_pointer_manager_v1_send_relative_motion( + relative_pointer_manager, + seat, (uint64_t)event->time_msec * 1000, + event->delta_x, event->delta_y, event->unaccel_dx, event->unaccel_dy); + + if (!active_constraint) { + wlr_cursor_move(cursor, &event->pointer->base, + event->delta_x, event->delta_y); + } motionnotify(event->time_msec); } @@ -2282,6 +2357,11 @@ setup(void) xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); + pointer_constraints = wlr_pointer_constraints_v1_create(dpy); + LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint); + + relative_pointer_manager = wlr_relative_pointer_manager_v1_create(dpy); + /* * Creates a cursor, which is a wlroots utility for tracking the cursor * image shown on screen.