From 9071ce6c848ce214939fb84f85ae77de86de88d7 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 9 Apr 2021 12:37:49 -0500 Subject: [PATCH 001/329] nuke CSDs, hopefully for good! --- dwl.c | 45 ++++++--------------------------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/dwl.c b/dwl.c index 0deae84..d463985 100644 --- a/dwl.c +++ b/dwl.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -228,18 +229,15 @@ static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); -static void createxdeco(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); -static void destroyxdeco(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 void fullscreennotify(struct wl_listener *listener, void *data); static Client *focustop(Monitor *m); -static void getxdecomode(struct wl_listener *listener, void *data); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); @@ -312,7 +310,6 @@ static struct wl_list stack; /* stacking z-order */ static struct wl_list independents; static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; -static struct wlr_xdg_decoration_manager_v1 *xdeco_mgr; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; @@ -344,7 +341,6 @@ static struct wl_listener layout_change = {.notify = updatemons}; static struct wl_listener new_input = {.notify = inputdevice}; static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; static struct wl_listener new_output = {.notify = createmon}; -static struct wl_listener new_xdeco = {.notify = createxdeco}; static struct wl_listener new_xdg_surface = {.notify = createnotify}; static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; @@ -958,18 +954,6 @@ createpointer(struct wlr_input_device *device) wlr_cursor_attach_input_device(cursor, device); } -void -createxdeco(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - Decoration *d = wlr_deco->data = calloc(1, sizeof(*d)); - - LISTEN(&wlr_deco->events.request_mode, &d->request_mode, getxdecomode); - LISTEN(&wlr_deco->events.destroy, &d->destroy, destroyxdeco); - - getxdecomode(&d->request_mode, wlr_deco); -} - void cursorframe(struct wl_listener *listener, void *data) { @@ -1020,17 +1004,6 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } -void -destroyxdeco(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - Decoration *d = wlr_deco->data; - - wl_list_remove(&d->destroy.link); - wl_list_remove(&d->request_mode.link); - free(d); -} - void togglefullscreen(const Arg *arg) { @@ -1185,14 +1158,6 @@ focustop(Monitor *m) return NULL; } -void -getxdecomode(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - wlr_xdg_toplevel_decoration_v1_set_mode(wlr_deco, - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); -} - void incnmaster(const Arg *arg) { @@ -2051,9 +2016,11 @@ setup(void) xdg_shell = wlr_xdg_shell_create(dpy); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); - /* Use xdg_decoration protocol to negotiate server-side decorations */ - xdeco_mgr = wlr_xdg_decoration_manager_v1_create(dpy); - wl_signal_add(&xdeco_mgr->events.new_toplevel_decoration, &new_xdeco); + /* Use decoration protocols to negotiate server-side decorations */ + wlr_server_decoration_manager_set_default_mode( + wlr_server_decoration_manager_create(dpy), + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + wlr_xdg_decoration_manager_v1_create(dpy); /* * Creates a cursor, which is a wlroots utility for tracking the cursor From b372d4b55e256b96fe926c512499ed90c460d66f Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 14 Apr 2021 11:15:26 -0500 Subject: [PATCH 002/329] pipe status info into -s command Unlike with X window managers, the display socket in Wayland isn't set up prior to starting the compositor. Because of this, you can't pipe the compositor's output directly into a program which needs access to $WAYLAND_DISPLAY, which is a typical setup for this purpose. Existing scripts have been forced to create a pipe/FIFO or a temporary file as an intermediary. Instead, send the status info directly to stdin of the -s command, which *does* have access to $WAYLAND_DISPLAY. Fixes #103. --- dwl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index d463985..f4b9b3a 100644 --- a/dwl.c +++ b/dwl.c @@ -1805,15 +1805,22 @@ run(char *startup_cmd) setenv("WAYLAND_DISPLAY", socket, 1); if (startup_cmd) { + int piperw[2]; + pipe(piperw); startup_pid = fork(); if (startup_pid < 0) EBARF("startup: fork"); if (startup_pid == 0) { - dup2(STDERR_FILENO, STDOUT_FILENO); + dup2(piperw[0], STDIN_FILENO); + close(piperw[1]); execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); EBARF("startup: execl"); } + dup2(piperw[1], STDOUT_FILENO); + close(piperw[0]); } + /* If nobody is reading the status output, don't terminate */ + signal(SIGPIPE, SIG_IGN); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event From 6a0dec69ec47ed8143f13016e629e5502d6339a2 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Apr 2021 13:03:21 -0500 Subject: [PATCH 003/329] re-compile if config.mk changes --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a0d1cc3..1362db8 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ idle-protocol.o: idle-protocol.h config.h: | config.def.h cp config.def.h $@ -dwl.o: 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 dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o From 4170a90fbccb5823f536d7b77c2ba40e5358002b Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Apr 2021 13:04:31 -0500 Subject: [PATCH 004/329] group phony targets together in Makefile --- Makefile | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 1362db8..fe6ff04 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,14 @@ LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p))) all: dwl +clean: + rm -f dwl *.o *-protocol.h *-protocol.c + +install: dwl + install -D dwl $(PREFIX)/bin/dwl + +.PHONY: all clean install + # wayland-scanner is a tool which generates C headers and rigging for Wayland # protocols, which are specified in XML. wlroots requires you to rig these up # to your build system yourself and provide them in the include path. @@ -50,12 +58,3 @@ config.h: | 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: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o - -clean: - rm -f dwl *.o *-protocol.h *-protocol.c - -install: dwl - install -D dwl $(PREFIX)/bin/dwl - -.DEFAULT_GOAL=dwl -.PHONY: clean From 3727f4a7b3d230226f0082581444344d563e0f9c Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Apr 2021 13:05:05 -0500 Subject: [PATCH 005/329] update status info if focused client changes title Fixes #108. --- dwl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dwl.c b/dwl.c index d463985..c5308f5 100644 --- a/dwl.c +++ b/dwl.c @@ -96,6 +96,7 @@ typedef struct { struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; + struct wl_listener set_title; struct wl_listener fullscreen; struct wlr_box geom; /* layout-relative, includes border */ Monitor *mon; @@ -288,6 +289,7 @@ static void unmaplayersurface(LayerSurface *layersurface); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); static void updatemons(struct wl_listener *listener, void *data); +static void updatetitle(struct wl_listener *listener, void *data); static void view(const Arg *arg); static void virtualkeyboard(struct wl_listener *listener, void *data); static Client *xytoclient(double x, double y); @@ -891,6 +893,7 @@ createnotify(struct wl_listener *listener, void *data) LISTEN(&xdg_surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); c->isfullscreen = 0; @@ -994,6 +997,7 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); wl_list_remove(&c->destroy.link); + wl_list_remove(&c->set_title.link); wl_list_remove(&c->fullscreen.link); #ifdef XWAYLAND if (c->type == X11Managed) @@ -2291,6 +2295,14 @@ updatemons(struct wl_listener *listener, void *data) wlr_output_manager_v1_set_configuration(output_mgr, config); } +void +updatetitle(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_title); + if (c == focustop(c->mon)) + printstatus(); +} + void view(const Arg *arg) { @@ -2427,6 +2439,7 @@ createnotifyx11(struct wl_listener *listener, void *data) activatex11); LISTEN(&xwayland_surface->events.request_configure, &c->configure, configurex11); + LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify); LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen, fullscreennotify); From d57db4cac927126d1d006becf5f2ed743ac21474 Mon Sep 17 00:00:00 2001 From: Jason Goulet-Lipman Date: Mon, 19 Apr 2021 09:05:35 -0400 Subject: [PATCH 006/329] added uninstall target --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fe6ff04..5ff69e9 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,10 @@ clean: install: dwl install -D dwl $(PREFIX)/bin/dwl -.PHONY: all clean install +uninstall: + rm -f $(PREFIX)/bin/dwl + +.PHONY: all clean install uninstall # wayland-scanner is a tool which generates C headers and rigging for Wayland # protocols, which are specified in XML. wlroots requires you to rig these up From 1b139a860dacbca8c4b3f8d24930b3f829534206 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 18 May 2021 11:33:12 -0500 Subject: [PATCH 007/329] update README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 22dfa07..51aecf8 100644 --- a/README.md +++ b/README.md @@ -14,26 +14,27 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s - Any features provided by dwm/Xlib: simple window borders, tags, keybindings, client rules, mouse move/resize. Providing a built-in status bar is an exception to this goal, to avoid dependencies on font rendering and/or drawing libraries when an external bar could work well. - Configurable multi-monitor layout support, including position and rotation - Configurable HiDPI/multi-DPI support +- Provide information to external status bars via stdout/stdin - Various Wayland protocols -- XWayland support as provided by wlroots +- XWayland support as provided by wlroots (can be enabled in `config.mk`) - Zero flickering - Wayland users naturally expect that "every frame is perfect" Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Provide information to external status bars via stdout or another file descriptor +- Implement urgent/focus-request once the xdg-activation protocol [hits wlroots](https://github.com/swaywm/wlroots/pull/2718) - Implement the input-inhibitor protocol to support screen lockers - Implement the idle-inhibit protocol which lets applications such as mpv disable idle monitoring - Layer shell popups (used by Waybar) - Basic yes/no damage tracking to avoid needless redraws - More in-depth damage region tracking ([which may improve power usage](https://mozillagfx.wordpress.com/2019/10/22/dramatically-reduced-power-usage-in-firefox-70-on-macos-with-core-animation/)) - Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/12) -- Implement urgent/attention/focus-request once it's part of the xdg-shell protocol (https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/9) -Feature *non-goals* include: +Feature *non-goals* for the main codebase include: - Client-side decoration (any more than is necessary to tell the clients not to) - Client-initiated window management, such as move, resize, and close, which can be done through the compositor +- Animations and visual effects ## Building dwl From 93a58abf2955aa01b7c148b85490d443ab017fb7 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 22 May 2021 14:22:37 -0500 Subject: [PATCH 008/329] Wait until map to set window's tiled state Workaround for a bug in Chromium where it fails to attach a buffer to the surface. Fixes #119. --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index d7e798b..30a64f8 100644 --- a/dwl.c +++ b/dwl.c @@ -885,10 +885,6 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; - /* Tell the client not to try anything fancy */ - wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | - WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); @@ -1308,6 +1304,10 @@ mapnotify(struct wl_listener *listener, void *data) c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; + /* Tell the client not to try anything fancy */ + wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | + WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + /* Set initial monitor, tags, floating status, and focus */ applyrules(c); } From d8cf65c74f3b7132302027cfbf940de8548d7d17 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 22 May 2021 21:18:48 -0500 Subject: [PATCH 009/329] implement urgency hint --- README.md | 2 +- dwl.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 51aecf8..dc75cef 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s - Configurable multi-monitor layout support, including position and rotation - Configurable HiDPI/multi-DPI support - Provide information to external status bars via stdout/stdin +- Urgency hints via xdg-activate protocol - Various Wayland protocols - XWayland support as provided by wlroots (can be enabled in `config.mk`) - Zero flickering - Wayland users naturally expect that "every frame is perfect" @@ -22,7 +23,6 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Implement urgent/focus-request once the xdg-activation protocol [hits wlroots](https://github.com/swaywm/wlroots/pull/2718) - Implement the input-inhibitor protocol to support screen lockers - Implement the idle-inhibit protocol which lets applications such as mpv disable idle monitoring - Layer shell popups (used by Waybar) diff --git a/dwl.c b/dwl.c index d7e798b..4d0bc84 100644 --- a/dwl.c +++ b/dwl.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -107,7 +108,7 @@ typedef struct { #endif int bw; unsigned int tags; - int isfloating; + int isfloating, isurgent; uint32_t resize; /* configure serial of a pending resize */ int prevx; int prevy; @@ -290,6 +291,7 @@ static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); static void updatemons(struct wl_listener *listener, void *data); static void updatetitle(struct wl_listener *listener, void *data); +static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg); static void virtualkeyboard(struct wl_listener *listener, void *data); static Client *xytoclient(double x, double y); @@ -306,6 +308,7 @@ static struct wlr_renderer *drw; static struct wlr_compositor *compositor; static struct wlr_xdg_shell *xdg_shell; +static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wl_list stack; /* stacking z-order */ @@ -347,6 +350,7 @@ static struct wl_listener new_xdg_surface = {.notify = createnotify}; static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; +static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; @@ -1078,6 +1082,7 @@ focusclient(Client *c, int lift) wl_list_remove(&c->flink); wl_list_insert(&fstack, &c->flink); selmon = c->mon; + c->isurgent = 0; } printstatus(); @@ -1550,22 +1555,29 @@ void printstatus(void) { Monitor *m = NULL; - Client *c = NULL; - unsigned int activetags; + Client *c; + unsigned int occ, urg, sel; wl_list_for_each(m, &mons, link) { - activetags=0; + occ = urg = 0; wl_list_for_each(c, &clients, link) { - if (c->mon == m) - activetags |= c->tags; + if (c->mon != m) + continue; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; } - if (focustop(m)) + if ((c = focustop(m))) { printf("%s title %s\n", m->wlr_output->name, client_get_title(focustop(m))); - else + sel = c->tags; + } else { printf("%s title \n", m->wlr_output->name); + sel = 0; + } printf("%s selmon %u\n", m->wlr_output->name, m == selmon); - printf("%s tags %u %u\n", m->wlr_output->name, activetags, m->tagset[m->seltags]); + printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], + sel, urg); printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); } fflush(stdout); @@ -1825,6 +1837,7 @@ run(char *startup_cmd) } /* If nobody is reading the status output, don't terminate */ signal(SIGPIPE, SIG_IGN); + printstatus(); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event @@ -1997,6 +2010,10 @@ setup(void) wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); + /* Initializes the interface used to implement urgency hints */ + activation = wlr_xdg_activation_v1_create(dpy); + wl_signal_add(&activation->events.request_activate, &request_activate); + /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(); @@ -2310,6 +2327,21 @@ updatetitle(struct wl_listener *listener, void *data) printstatus(); } +void +urgent(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_activation_v1_request_activate_event *event = data; + Client *c; + + if (!wlr_surface_is_xdg_surface(event->surface)) + return; + c = wlr_xdg_surface_from_wlr_surface(event->surface)->data; + if (c != selclient()) { + c->isurgent = 1; + printstatus(); + } +} + void view(const Arg *arg) { From 9ab5e01d5b3864f151c222d001a8a2152f29b518 Mon Sep 17 00:00:00 2001 From: Sevz17 Date: Sun, 23 May 2021 11:24:32 -0500 Subject: [PATCH 010/329] before set tiled verify if client is xdg-shell, then set tile --- dwl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dwl.c b/dwl.c index 30a64f8..3a562b9 100644 --- a/dwl.c +++ b/dwl.c @@ -1304,9 +1304,17 @@ mapnotify(struct wl_listener *listener, void *data) c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; +#ifdef XWAYLAND + if (c->type == XDGShell) { + /* Tell the client not to try anything fancy */ + wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | + WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + } +#else /* Tell the client not to try anything fancy */ wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); +#endif /* Set initial monitor, tags, floating status, and focus */ applyrules(c); From 06ca86009296c1b8753cba259fd797703a281bbd Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 23 May 2021 18:28:13 -0500 Subject: [PATCH 011/329] factor xwayland hackiness out into client.h --- client.h | 11 +++++++++++ dwl.c | 11 +---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/client.h b/client.h index f4735c2..56e3089 100644 --- a/client.h +++ b/client.h @@ -141,6 +141,17 @@ client_set_size(Client *c, uint32_t width, uint32_t height) return wlr_xdg_toplevel_set_size(c->surface.xdg, width, height); } +static inline void +client_set_tiled(Client *c, uint32_t edges) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | + WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); +} + static inline struct wlr_surface * client_surface(Client *c) { diff --git a/dwl.c b/dwl.c index 3a562b9..9188f06 100644 --- a/dwl.c +++ b/dwl.c @@ -1304,17 +1304,8 @@ mapnotify(struct wl_listener *listener, void *data) c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; -#ifdef XWAYLAND - if (c->type == XDGShell) { - /* Tell the client not to try anything fancy */ - wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | - WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - } -#else /* Tell the client not to try anything fancy */ - wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | - WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); -#endif + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); /* Set initial monitor, tags, floating status, and focus */ applyrules(c); From 60c40c0989440fc54aa05b0e27cfbaad8c722fec Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 24 May 2021 22:03:39 -0500 Subject: [PATCH 012/329] print status on output create Along with starting the -s command earlier, this will allow the initial monitor setup to generate printstatus info. --- dwl.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dwl.c b/dwl.c index 9188f06..e0b404e 100644 --- a/dwl.c +++ b/dwl.c @@ -842,11 +842,13 @@ createmon(struct wl_listener *listener, void *data) LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); - wl_list_insert(&mons, &m->link); wlr_output_enable(wlr_output, 1); if (!wlr_output_commit(wlr_output)) return; + wl_list_insert(&mons, &m->link); + printstatus(); + /* Adds this to the output layout in the order it was configured in. * * The output layout utility automatically adds a wl_output global to the @@ -1786,27 +1788,9 @@ run(char *startup_cmd) const char *socket = wl_display_add_socket_auto(dpy); if (!socket) BARF("startup: display_add_socket_auto"); - - /* Start the backend. This will enumerate outputs and inputs, become the DRM - * master, etc */ - if (!wlr_backend_start(backend)) - BARF("startup: backend_start"); - - /* Now that outputs are initialized, choose initial selmon based on - * cursor position, and set default cursor image */ - selmon = xytomon(cursor->x, cursor->y); - - /* TODO hack to get cursor to display in its initial location (100, 100) - * instead of (0, 0) and then jumping. still may not be fully - * initialized, as the image/coordinates are not transformed for the - * monitor when displayed here */ - wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); - - /* Set the WAYLAND_DISPLAY environment variable to our socket and run the - * startup command if requested. */ setenv("WAYLAND_DISPLAY", socket, 1); + /* Now that the socket exists, run the startup command */ if (startup_cmd) { int piperw[2]; pipe(piperw); @@ -1825,6 +1809,22 @@ run(char *startup_cmd) /* If nobody is reading the status output, don't terminate */ signal(SIGPIPE, SIG_IGN); + /* Start the backend. This will enumerate outputs and inputs, become the DRM + * master, etc */ + if (!wlr_backend_start(backend)) + BARF("startup: backend_start"); + + /* Now that outputs are initialized, choose initial selmon based on + * cursor position, and set default cursor image */ + selmon = xytomon(cursor->x, cursor->y); + + /* TODO hack to get cursor to display in its initial location (100, 100) + * instead of (0, 0) and then jumping. still may not be fully + * initialized, as the image/coordinates are not transformed for the + * monitor when displayed here */ + wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event * loop configuration to listen to libinput events, DRM events, generate From 823cefd2920085a0f74899fb679020005a1b6e0b Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 25 May 2021 02:52:33 -0500 Subject: [PATCH 013/329] handle ephemeral pageflip failures If a transient failure occurs in wlr_output_commit, re-render until it doesn't happen. This could possibly be removed if we decide to implement damage tracking in the future. --- dwl.c | 54 +++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/dwl.c b/dwl.c index e0b404e..a38f452 100644 --- a/dwl.c +++ b/dwl.c @@ -1726,38 +1726,42 @@ rendermon(struct wl_listener *listener, void *data) } } - /* wlr_output_attach_render makes the OpenGL context current. */ - if (!wlr_output_attach_render(m->wlr_output, NULL)) - return; + /* HACK: This loop is the simplest way to handle ephemeral pageflip + * failures but probably not the best. Revisit if damage tracking is + * added. */ + do { + /* wlr_output_attach_render makes the OpenGL context current. */ + if (!wlr_output_attach_render(m->wlr_output, NULL)) + return; - if (render) { - /* Begin the renderer (calls glViewport and some other GL sanity checks) */ - wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); - wlr_renderer_clear(drw, rootcolor); + if (render) { + /* Begin the renderer (calls glViewport and some other GL sanity checks) */ + wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); + wlr_renderer_clear(drw, rootcolor); - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); - renderclients(m, &now); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); + renderclients(m, &now); #ifdef XWAYLAND - renderindependents(m->wlr_output, &now); + renderindependents(m->wlr_output, &now); #endif - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); - /* Hardware cursors are rendered by the GPU on a separate plane, and can be - * moved around without re-rendering what's beneath them - which is more - * efficient. However, not all hardware supports hardware cursors. For this - * reason, wlroots provides a software fallback, which we ask it to render - * here. wlr_cursor handles configuring hardware vs software cursors for you, - * and this function is a no-op when hardware cursors are in use. */ - wlr_output_render_software_cursors(m->wlr_output, NULL); + /* Hardware cursors are rendered by the GPU on a separate plane, and can be + * moved around without re-rendering what's beneath them - which is more + * efficient. However, not all hardware supports hardware cursors. For this + * reason, wlroots provides a software fallback, which we ask it to render + * here. wlr_cursor handles configuring hardware vs software cursors for you, + * and this function is a no-op when hardware cursors are in use. */ + wlr_output_render_software_cursors(m->wlr_output, NULL); - /* Conclude rendering and swap the buffers, showing the final frame - * on-screen. */ - wlr_renderer_end(drw); - } + /* Conclude rendering and swap the buffers, showing the final frame + * on-screen. */ + wlr_renderer_end(drw); + } - wlr_output_commit(m->wlr_output); + } while (!wlr_output_commit(m->wlr_output)); } void From bd2f7fbb4082d947ec2738cd31d403e9f0c10f50 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 26 May 2021 23:30:49 -0500 Subject: [PATCH 014/329] exit cleanly on INT/TERM --- dwl.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a38f452..a8e1dcd 100644 --- a/dwl.c +++ b/dwl.c @@ -259,6 +259,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void printstatus(void); static void quit(const Arg *arg); +static void quitsignal(int signo); static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now); @@ -1578,6 +1579,12 @@ quit(const Arg *arg) wl_display_terminate(dpy); } +void +quitsignal(int signo) +{ + quit(NULL); +} + void render(struct wlr_surface *surface, int sx, int sy, void *data) { @@ -1965,8 +1972,10 @@ setup(void) * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); - /* clean up child processes immediately */ + /* Set up signal handlers */ sigchld(0); + signal(SIGINT, quitsignal); + signal(SIGTERM, quitsignal); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable From c6f96d5391b43268f05787c4171ddc5ed4cbf0b8 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 3 Jun 2021 01:41:10 -0500 Subject: [PATCH 015/329] mention `-devel` packages It seems like there are people trying dwl who aren't as familiar with how their distros do development, so let's give them a pointer in the right direction. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51aecf8..5041c1b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Feature *non-goals* for the main codebase include: ## Building dwl -dwl has only two dependencies: wlroots 0.13 and wayland-protocols. Simply install these and run `make`. If you wish to build against a Git version of wlroots, check out the [wlroots-next branch](https://github.com/djpohly/dwl/tree/wlroots-next). +dwl has only two dependencies: wlroots and wayland-protocols. Simply install these (and their `-devel` versions if your distro has separate development packages) and run `make`. If you wish to build against a Git version of wlroots, check out the [wlroots-next branch](https://github.com/djpohly/dwl/tree/wlroots-next). To enable XWayland, you should also install xorg-xwayland and uncomment its flag in `config.mk`. From 3b05eadeaf5e2de4caf127cfa07642342cccddbc Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 30 Jun 2021 14:46:20 -0500 Subject: [PATCH 016/329] update notes about starting dwl Includes mention of video/input groups --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa9d1cc..5b3e4cb 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,19 @@ As in the dwm community, we encourage users to share patches they have created. ## Running dwl -dwl can be run as-is, with no arguments. In an existing Wayland or X11 session, this will open a window to act as a virtual display. When run from a TTY, the Wayland server will take over the entire virtual terminal. Clients started by dwl will have `WAYLAND_DISPLAY` set in their environment, and other clients can be started from outside the session by setting this variable accordingly. +dwl can be run on any of the backends supported by wlroots. This means you can run it as a separate window inside either an X11 or Wayland session, as well as directly from a VT console. Depending on your distro's setup, you may need to add your user to the `video` and `input` groups before you can run dwl on a VT. -You can also specify a startup program using the `-s` option. The argument to this option will be run at startup as a shell command (using `sh -c`) and can serve a similar function to `.xinitrc`: starting a service manager or other startup applications. Unlike `.xinitrc`, the display server will not shut down when this process terminates. Instead, as dwl is shutting down, it will send this process a SIGTERM and wait for it to terminate (if it hasn't already). This makes it ideal not only for initialization but also for execing into a user-level service manager like s6 or `systemd --user`. +When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the Wayland session. + +If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. The argument to this option will be parsed as a shell command (using `sh -c`) and can serve a similar function to `.xinitrc`. Unlike `.xinitrc`, the display server will not shut down when this process terminates. Instead, as dwl is shutting down, it will send this process a SIGTERM and wait for it to terminate (if it hasn't already). This makes it ideal for execing into a user service manager like [s6](https://skarnet.org/software/s6/), [anopa](https://jjacky.com/anopa/), [runit](http://smarden.org/runit/faq.html#userservices), or [`systemd --user`](https://wiki.archlinux.org/title/Systemd/User). + +Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes that it spawns. If you need to set environment variables that affect the entire dwl session (such as `XDG_RUNTIME_DIR` in the note below), these must be set prior to running dwl. Note: Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager such as `elogind` or `systemd-logind`. If your system doesn't do this automatically, you will need to configure it prior to launching `dwl`, e.g.: export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) mkdir -p $XDG_RUNTIME_DIR + dwl ## Replacements for X applications From 52e6bf47354b624e220cbff6df33d06ba1c3581e Mon Sep 17 00:00:00 2001 From: David Donahue Date: Thu, 1 Jul 2021 15:20:30 -0500 Subject: [PATCH 017/329] Moved printstatus() call in focusclient() to prevent printstatus being called on every frame when things like dmenu are up --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a2a0b69..9c31de2 100644 --- a/dwl.c +++ b/dwl.c @@ -1083,7 +1083,6 @@ focusclient(Client *c, int lift) selmon = c->mon; c->isurgent = 0; } - printstatus(); /* Deactivate old client if focus is changing */ if (old && (!c || client_surface(c) != old)) { @@ -1106,6 +1105,8 @@ focusclient(Client *c, int lift) } } + printstatus(); + if (!c) { /* With no client, all we have left is to clear focus */ wlr_seat_keyboard_notify_clear_focus(seat); From d175a58d733723fdeb307943b034fe7fda6086ed Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Mon, 2 Aug 2021 16:33:38 +0200 Subject: [PATCH 018/329] implement the presentation time protocol This lets applications, such as mpv with --video-sync=display-resample, know accurately when frames are displayed and ensure smooth video playback. --- dwl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dwl.c b/dwl.c index a2a0b69..20b01b0 100644 --- a/dwl.c +++ b/dwl.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -317,6 +318,7 @@ static struct wl_list independents; static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_presentation *presentation; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; @@ -1653,6 +1655,8 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) /* This lets the client know that we've displayed that frame and it can * prepare another one now if it likes. */ wlr_surface_send_frame_done(surface, rdata->when); + + wlr_presentation_surface_sampled_on_output(presentation, surface, output); } void @@ -2116,6 +2120,8 @@ setup(void) wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); + presentation = wlr_presentation_create(dpy, backend); + #ifdef XWAYLAND /* * Initialise the XWayland X server. From 8aa50dfdf1bd6daefe2a58f507a0d1353e47719f Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 3 Aug 2021 06:29:26 +0200 Subject: [PATCH 019/329] update IRC channel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b3e4cb..3b3a72f 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ You can find a [list of Wayland applications on the sway wiki](https://github.co ## IRC channel -dwl's IRC channel is #dwl on irc.freenode.net. +dwl's IRC channel is #dwl on irc.libera.chat. ## Acknowledgements From 3273f749ea86d3e7178955a0771d6783deae20e4 Mon Sep 17 00:00:00 2001 From: Palanix Date: Sat, 21 Aug 2021 01:53:38 +0200 Subject: [PATCH 020/329] wlr_layer_surface_v1_close has been replaced by wlr_layer_surface_v1_destroy --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a2a0b69..3b06948 100644 --- a/dwl.c +++ b/dwl.c @@ -553,7 +553,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int box.y -= state->margin.bottom; } if (box.width < 0 || box.height < 0) { - wlr_layer_surface_v1_close(wlr_layer_surface); + wlr_layer_surface_v1_destroy(wlr_layer_surface); continue; } layersurface->geo = box; From d4e08c07629b4534e45b292614899a6b9bb876bd Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 23 Aug 2021 18:59:31 -0500 Subject: [PATCH 021/329] update deprecated xkb function name --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index b898537..2c1634b 100644 --- a/dwl.c +++ b/dwl.c @@ -793,7 +793,7 @@ createkeyboard(struct wlr_input_device *device) /* Prepare an XKB keymap and assign it to the keyboard. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - keymap = xkb_map_new_from_names(context, &xkb_rules, + keymap = xkb_keymap_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); wlr_keyboard_set_keymap(device->keyboard, keymap); From 79dcc0d3271395fe1258d818718209254d846b1b Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Sat, 4 Sep 2021 13:46:58 +0200 Subject: [PATCH 022/329] reset cursor mode when grabc is unmapped --- dwl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwl.c b/dwl.c index 2c1634b..c798685 100644 --- a/dwl.c +++ b/dwl.c @@ -2292,6 +2292,10 @@ unmapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is unmapped, and should no longer be shown. */ Client *c = wl_container_of(listener, c, unmap); + if (c == grabc) { + cursor_mode = CurNormal; + grabc = NULL; + } wl_list_remove(&c->link); if (client_is_unmanaged(c)) return; From 2e9c4d8ea90e47667ef4fa417aa3e6f46034699e Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 5 Sep 2021 11:41:23 -0500 Subject: [PATCH 023/329] simplify client_for_each_surface All the XDG surface iterator does is iterate the main wlr_surface, then iterate the popups. If we inline that function, we can merge part of it with the X11 case. --- client.h | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/client.h b/client.h index 56e3089..4fd1863 100644 --- a/client.h +++ b/client.h @@ -5,7 +5,7 @@ * that they will simply compile out if the chosen #defines leave them unused. */ -/* Leave this function first; it's used in the others */ +/* Leave these functions first; they're used in the others */ static inline int client_is_x11(Client *c) { @@ -16,6 +16,16 @@ client_is_x11(Client *c) #endif } +static inline struct wlr_surface * +client_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->surface; +#endif + return c->surface.xdg->surface; +} + /* The others */ static inline void client_activate_surface(struct wlr_surface *s, int activated) @@ -35,14 +45,12 @@ client_activate_surface(struct wlr_surface *s, int activated) static inline void client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) { + wlr_surface_for_each_surface(client_surface(c), fn, data); #ifdef XWAYLAND - if (client_is_x11(c)) { - wlr_surface_for_each_surface(c->surface.xwayland->surface, - fn, data); + if (client_is_x11(c)) return; - } #endif - wlr_xdg_surface_for_each_surface(c->surface.xdg, fn, data); + wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data); } static inline const char * @@ -152,16 +160,6 @@ client_set_tiled(Client *c, uint32_t edges) WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); } -static inline struct wlr_surface * -client_surface(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->surface; -#endif - return c->surface.xdg->surface; -} - static inline struct wlr_surface * client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) { From 0c1e621b82fb55b5994ae5ab9956160a47dfec80 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 8 Sep 2021 23:16:56 -0500 Subject: [PATCH 024/329] simplify fullscreen expression --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 2c1634b..1951adb 100644 --- a/dwl.c +++ b/dwl.c @@ -1025,7 +1025,7 @@ void setfullscreen(Client *c, int fullscreen) { c->isfullscreen = fullscreen; - c->bw = (1 - fullscreen) * borderpx; + c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); if (fullscreen) { From 929d3d9569086963c7597dc1fcd38d59896278bc Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 5 Sep 2021 15:55:36 -0500 Subject: [PATCH 025/329] use type enum to distinguish Client from LayerSurface --- dwl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index c4ca60f..08f7e32 100644 --- a/dwl.c +++ b/dwl.c @@ -65,10 +65,10 @@ /* enums */ enum { CurNormal, CurMove, CurResize }; /* cursor */ +enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ -enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */ #endif typedef union { @@ -87,6 +87,8 @@ typedef struct { typedef struct Monitor Monitor; typedef struct { + /* Must be first */ + unsigned int type; /* XDGShell or X11* */ struct wl_list link; struct wl_list flink; struct wl_list slink; @@ -103,7 +105,6 @@ typedef struct { struct wlr_box geom; /* layout-relative, includes border */ Monitor *mon; #ifdef XWAYLAND - unsigned int type; struct wl_listener activate; struct wl_listener configure; #endif @@ -140,6 +141,8 @@ typedef struct { } Keyboard; typedef struct { + /* Must be first */ + unsigned int type; /* LayerShell */ struct wlr_layer_surface_v1 *layer_surface; struct wl_list link; @@ -917,6 +920,7 @@ createlayersurface(struct wl_listener *listener, void *data) } layersurface = calloc(1, sizeof(LayerSurface)); + layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, From 1b38801eef319a9f8b618bf29564104af6b0a39d Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 5 Sep 2021 16:07:28 -0500 Subject: [PATCH 026/329] use scene-graph API for Client/LayerSurface --- dwl.c | 422 ++++++++++++++++------------------------------------------ 1 file changed, 115 insertions(+), 307 deletions(-) diff --git a/dwl.c b/dwl.c index 08f7e32..2f4bb4c 100644 --- a/dwl.c +++ b/dwl.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -60,12 +61,12 @@ #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) -#define ROUND(X) ((int)((X)+0.5)) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) /* enums */ enum { CurNormal, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -89,9 +90,11 @@ typedef struct Monitor Monitor; typedef struct { /* Must be first */ unsigned int type; /* XDGShell or X11* */ + struct wlr_scene_node *scene; + struct wlr_scene_rect *border[4]; + struct wlr_scene_node *scene_surface; struct wl_list link; struct wl_list flink; - struct wl_list slink; union { struct wlr_xdg_surface *xdg; struct wlr_xwayland_surface *xwayland; @@ -143,8 +146,9 @@ typedef struct { typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ - struct wlr_layer_surface_v1 *layer_surface; + struct wlr_scene_node *scene; struct wl_list link; + struct wlr_layer_surface_v1 *layer_surface; struct wl_listener destroy; struct wl_listener map; @@ -203,14 +207,6 @@ typedef struct { int monitor; } Rule; -/* Used to move all of the data necessary to render a surface from the top-level - * frame handler to the per-surface render function. */ -struct render_data { - struct wlr_output *output; - struct timespec *when; - int x, y; /* layout-relative */ -}; - /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, @@ -265,13 +261,9 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, static void printstatus(void); static void quit(const Arg *arg); static void quitsignal(int signo); -static void render(struct wlr_surface *surface, int sx, int sy, void *data); -static void renderclients(Monitor *m, struct timespec *now); -static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now); static void rendermon(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); -static void scalebox(struct wlr_box *box, float scale); static Client *selclient(void); static void setcursor(struct wl_listener *listener, void *data); static void setpsel(struct wl_listener *listener, void *data); @@ -299,9 +291,8 @@ static void updatetitle(struct wl_listener *listener, void *data); static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg); static void virtualkeyboard(struct wl_listener *listener, void *data); -static Client *xytoclient(double x, double y); -static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, - double x, double y, double *sx, double *sy); +static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); static Monitor *xytomon(double x, double y); static void zoom(const Arg *arg); @@ -309,6 +300,8 @@ static void zoom(const Arg *arg); static const char broken[] = "broken"; static struct wl_display *dpy; static struct wlr_backend *backend; +static struct wlr_scene *scene; +static struct wlr_scene_node *layers[NUM_LAYERS]; static struct wlr_renderer *drw; static struct wlr_compositor *compositor; @@ -316,7 +309,6 @@ static struct wlr_xdg_shell *xdg_shell; static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ -static struct wl_list stack; /* stacking z-order */ static struct wl_list independents; static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; @@ -366,9 +358,7 @@ static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); -static void renderindependents(struct wlr_output *output, struct timespec *now); static void xwaylandready(struct wl_listener *listener, void *data); -static Client *xytoindependent(double x, double y); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; @@ -483,12 +473,17 @@ applyrules(Client *c) mon = m; } } + wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); setmon(c, mon, newtags); } void arrange(Monitor *m) { + Client *c; + wl_list_for_each(c, &clients, link) + wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, c->mon)); + if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); /* TODO recheck pointer focus here... or in resize()? */ @@ -567,6 +562,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int applyexclusive(usable_area, state->anchor, state->exclusive_zone, state->margin.top, state->margin.right, state->margin.bottom, state->margin.left); + wlr_scene_node_set_position(layersurface->scene, box.x, box.y); wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); } } @@ -650,7 +646,8 @@ buttonpress(struct wl_listener *listener, void *data) switch (event->state) { case WLR_BUTTON_PRESSED:; /* Change focus if the button was _pressed_ over a client */ - if ((c = xytoclient(cursor->x, cursor->y))) + xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); + if (c) focusclient(c, 1); keyboard = wlr_seat_get_keyboard(seat); @@ -762,6 +759,9 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = wlr_layer_surface->output; Monitor *m; + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); + if (!wlr_output) return; @@ -932,8 +932,13 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->layer_surface = wlr_layer_surface; wlr_layer_surface->data = layersurface; - m = wlr_layer_surface->output->data; + + layersurface->scene = wlr_scene_surface_tree_create( + layers[wlr_layer_surface->client_pending.layer], + wlr_layer_surface->surface); + layersurface->scene->data = layersurface; + wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer], &layersurface->link); @@ -1075,8 +1080,9 @@ focusclient(Client *c, int lift) /* Raise client in stacking order if requested */ if (c && lift) { - wl_list_remove(&c->slink); - wl_list_insert(&stack, &c->slink); + /* This isn't easy to do via the current API */ + wl_list_remove(&c->scene->state.link); + wl_list_insert(c->scene->parent->state.children.prev, &c->scene->state.link); } if (c && client_surface(c) == old) @@ -1303,27 +1309,40 @@ mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ Client *c = wl_container_of(listener, c, map); + int i; + + /* Create scene tree for this client and its border */ + c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; + c->scene_surface = wlr_scene_surface_tree_create(c->scene, client_surface(c)); + c->scene_surface->data = c; + for (i = 0; i < 4; i++) { + c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); + c->border[i]->node.data = c; + } if (client_is_unmanaged(c)) { + /* Floating, no border */ + wlr_scene_node_reparent(c->scene, layers[LyrFloat]); + c->bw = 0; + /* Insert this independent into independents lists. */ wl_list_insert(&independents, &c->link); return; } - /* Insert this client into client lists. */ - wl_list_insert(&clients, &c->link); - wl_list_insert(&fstack, &c->flink); - wl_list_insert(&stack, &c->slink); - + /* Initialize client geometry with room for border */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); client_get_geometry(c, &c->geom); c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; - /* Tell the client not to try anything fancy */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + /* Insert this client into client lists. */ + wl_list_insert(&clients, &c->link); + wl_list_insert(&fstack, &c->flink); /* Set initial monitor, tags, floating status, and focus */ applyrules(c); + resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0); } void @@ -1356,8 +1375,8 @@ void motionnotify(uint32_t time) { double sx = 0, sy = 0; - struct wlr_surface *surface = NULL; Client *c = NULL; + struct wlr_surface *surface = NULL; // time is 0 in internal calls meant to restore pointer focus. if (time) { @@ -1381,32 +1400,8 @@ motionnotify(uint32_t time) return; } - if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - cursor->x, cursor->y, &sx, &sy))) - ; - else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - cursor->x, cursor->y, &sx, &sy))) - ; -#ifdef XWAYLAND - /* Find an independent under the pointer and send the event along. */ - else if ((c = xytoindependent(cursor->x, cursor->y))) { - surface = wlr_surface_surface_at(c->surface.xwayland->surface, - cursor->x - c->surface.xwayland->x - c->bw, - cursor->y - c->surface.xwayland->y - c->bw, &sx, &sy); - - /* Otherwise, find the client under the pointer and send the event along. */ - } -#endif - else if ((c = xytoclient(cursor->x, cursor->y))) { - surface = client_surface_at(c, cursor->x - c->geom.x - c->bw, - cursor->y - c->geom.y - c->bw, &sx, &sy); - } - else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - cursor->x, cursor->y, &sx, &sy))) - ; - else - surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - cursor->x, cursor->y, &sx, &sy); + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it @@ -1437,7 +1432,10 @@ motionrelative(struct wl_listener *listener, void *data) void moveresize(const Arg *arg) { - if (cursor_mode != CurNormal || !(grabc = xytoclient(cursor->x, cursor->y))) + if (cursor_mode != CurNormal) + return; + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + if (!grabc) return; /* Float the window and tell motionnotify to grab it */ @@ -1604,140 +1602,11 @@ quitsignal(int signo) quit(NULL); } -void -render(struct wlr_surface *surface, int sx, int sy, void *data) -{ - /* This function is called for every surface that needs to be rendered. */ - struct render_data *rdata = data; - struct wlr_output *output = rdata->output; - double ox = 0, oy = 0; - struct wlr_box obox; - float matrix[9]; - enum wl_output_transform transform; - - /* We first obtain a wlr_texture, which is a GPU resource. wlroots - * automatically handles negotiating these with the client. The underlying - * resource could be an opaque handle passed from the client, or the client - * could have sent a pixel buffer which we copied to the GPU, or a few other - * means. You don't have to worry about this, wlroots takes care of it. */ - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) - return; - - /* The client has a position in layout coordinates. If you have two displays, - * one next to the other, both 1080p, a client on the rightmost display might - * have layout coordinates of 2000,100. We need to translate that to - * output-local coordinates, or (2000 - 1920). */ - wlr_output_layout_output_coords(output_layout, output, &ox, &oy); - - /* We also have to apply the scale factor for HiDPI outputs. This is only - * part of the puzzle, dwl does not fully support HiDPI. */ - obox.x = ox + rdata->x + sx; - obox.y = oy + rdata->y + sy; - obox.width = surface->current.width; - obox.height = surface->current.height; - scalebox(&obox, output->scale); - - /* - * Those familiar with OpenGL are also familiar with the role of matrices - * in graphics programming. We need to prepare a matrix to render the - * client with. wlr_matrix_project_box is a helper which takes a box with - * a desired x, y coordinates, width and height, and an output geometry, - * then prepares an orthographic projection and multiplies the necessary - * transforms to produce a model-view-projection matrix. - * - * Naturally you can do this any way you like, for example to make a 3D - * compositor. - */ - transform = wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &obox, transform, 0, - output->transform_matrix); - - /* This takes our matrix, the texture, and an alpha, and performs the actual - * rendering on the GPU. */ - wlr_render_texture_with_matrix(drw, texture, matrix, 1); - - /* This lets the client know that we've displayed that frame and it can - * prepare another one now if it likes. */ - wlr_surface_send_frame_done(surface, rdata->when); - - wlr_presentation_surface_sampled_on_output(presentation, surface, output); -} - -void -renderclients(Monitor *m, struct timespec *now) -{ - Client *c, *sel = selclient(); - const float *color; - double ox, oy; - int i, w, h; - struct render_data rdata; - struct wlr_box *borders; - struct wlr_surface *surface; - /* Each subsequent window we render is rendered on top of the last. Because - * our stacking list is ordered front-to-back, we iterate over it backwards. */ - wl_list_for_each_reverse(c, &stack, slink) { - /* Only render visible clients which show on this monitor */ - if (!VISIBLEON(c, c->mon) || !wlr_output_layout_intersects( - output_layout, m->wlr_output, &c->geom)) - continue; - - surface = client_surface(c); - ox = c->geom.x, oy = c->geom.y; - wlr_output_layout_output_coords(output_layout, m->wlr_output, - &ox, &oy); - - if (c->bw) { - w = surface->current.width; - h = surface->current.height; - borders = (struct wlr_box[4]) { - {ox, oy, w + 2 * c->bw, c->bw}, /* top */ - {ox, oy + c->bw, c->bw, h}, /* left */ - {ox + c->bw + w, oy + c->bw, c->bw, h}, /* right */ - {ox, oy + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */ - }; - - /* Draw window borders */ - color = (c == sel) ? focuscolor : bordercolor; - for (i = 0; i < 4; i++) { - scalebox(&borders[i], m->wlr_output->scale); - wlr_render_rect(drw, &borders[i], color, - m->wlr_output->transform_matrix); - } - } - - /* This calls our render function for each surface among the - * xdg_surface's toplevel and popups. */ - rdata.output = m->wlr_output; - rdata.when = now; - rdata.x = c->geom.x + c->bw; - rdata.y = c->geom.y + c->bw; - client_for_each_surface(c, render, &rdata); - } -} - -void -renderlayer(struct wl_list *layer_surfaces, struct timespec *now) -{ - LayerSurface *layersurface; - wl_list_for_each(layersurface, layer_surfaces, link) { - struct render_data rdata = { - .output = layersurface->layer_surface->output, - .when = now, - .x = layersurface->geo.x, - .y = layersurface->geo.y, - }; - - wlr_surface_for_each_surface(layersurface->layer_surface->surface, - render, &rdata); - } -} - void rendermon(struct wl_listener *listener, void *data) { Client *c; - int render = 1; + int skip = 0; /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ @@ -1746,13 +1615,9 @@ rendermon(struct wl_listener *listener, void *data) struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - /* Do not render if any XDG clients have an outstanding resize. */ - wl_list_for_each(c, &stack, slink) { - if (c->resize) { - wlr_surface_send_frame_done(client_surface(c), &now); - render = 0; - } - } + /* Skip rendering if any XDG clients have an outstanding resize. */ + wl_list_for_each(c, &clients, link) + skip = skip || c->resize; /* HACK: This loop is the simplest way to handle ephemeral pageflip * failures but probably not the best. Revisit if damage tracking is @@ -1762,50 +1627,46 @@ rendermon(struct wl_listener *listener, void *data) if (!wlr_output_attach_render(m->wlr_output, NULL)) return; - if (render) { + if (!skip) { /* Begin the renderer (calls glViewport and some other GL sanity checks) */ wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); wlr_renderer_clear(drw, rootcolor); - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); - renderclients(m, &now); -#ifdef XWAYLAND - renderindependents(m->wlr_output, &now); -#endif - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); - renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); - - /* Hardware cursors are rendered by the GPU on a separate plane, and can be - * moved around without re-rendering what's beneath them - which is more - * efficient. However, not all hardware supports hardware cursors. For this - * reason, wlroots provides a software fallback, which we ask it to render - * here. wlr_cursor handles configuring hardware vs software cursors for you, - * and this function is a no-op when hardware cursors are in use. */ - wlr_output_render_software_cursors(m->wlr_output, NULL); + /* Render the scene at (-mx, -my) to get this monitor's view. + * wlroots will not render windows falling outside the box. */ + wlr_scene_render_output(scene, m->wlr_output, -m->m.x, -m->m.y, NULL); /* Conclude rendering and swap the buffers, showing the final frame * on-screen. */ wlr_renderer_end(drw); } - } while (!wlr_output_commit(m->wlr_output)); + + /* Let clients know a frame has been rendered */ + wl_list_for_each(c, &clients, link) + wlr_surface_send_frame_done(client_surface(c), &now); } void resize(Client *c, int x, int y, int w, int h, int interact) { - /* - * Note that I took some shortcuts here. In a more fleshed-out - * compositor, you'd wait for the client to prepare a buffer at - * the new size, then commit any movement that was prepared. - */ struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; c->geom.x = x; c->geom.y = y; c->geom.width = w; c->geom.height = h; applybounds(c, bbox); + + /* Update scene-graph, including borders */ + wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y); + wlr_scene_node_set_position(c->scene_surface, c->bw, c->bw); + wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); + wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); + wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); + /* wlroots makes this a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); @@ -1870,15 +1731,6 @@ run(char *startup_cmd) } } -void -scalebox(struct wlr_box *box, float scale) -{ - box->width = ROUND((box->x + box->width) * scale) - ROUND(box->x * scale); - box->height = ROUND((box->y + box->height) * scale) - ROUND(box->y * scale); - box->x = ROUND(box->x * scale); - box->y = ROUND(box->y * scale); -} - Client * selclient(void) { @@ -1911,6 +1763,7 @@ void setfloating(Client *c, int floating) { c->isfloating = floating; + wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); } @@ -1957,7 +1810,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) } if (m) { /* Make sure window actually overlaps with the monitor */ - applybounds(c, &m->m); + resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0); wlr_surface_send_enter(client_surface(c), m->wlr_output); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ arrange(m); @@ -2010,6 +1863,15 @@ setup(void) if (!(backend = wlr_backend_autocreate(dpy))) BARF("couldn't create backend"); + /* Initialize the scene graph used to lay out windows */ + scene = wlr_scene_create(); + layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; + /* If we don't provide a renderer, autocreate makes a GLES2 renderer for us. * The renderer is responsible for defining the various pixel formats it * supports for shared memory, this configures that for clients. */ @@ -2054,7 +1916,6 @@ setup(void) */ wl_list_init(&clients); wl_list_init(&fstack); - wl_list_init(&stack); wl_list_init(&independents); idle = wlr_idle_create(dpy); @@ -2302,7 +2163,7 @@ unmapnotify(struct wl_listener *listener, void *data) setmon(c, NULL, 0); wl_list_remove(&c->flink); - wl_list_remove(&c->slink); + wlr_scene_node_destroy(c->scene); } void @@ -2386,37 +2247,31 @@ virtualkeyboard(struct wl_listener *listener, void *data) createkeyboard(device); } -Client * -xytoclient(double x, double y) +struct wlr_scene_node * +xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny) { - /* Find the topmost visible client (if any) at point (x, y), including - * borders. This relies on stack being ordered from top to bottom. */ - Client *c; - wl_list_for_each(c, &stack, slink) - if (VISIBLEON(c, c->mon) && wlr_box_contains_point(&c->geom, x, y)) - return c; - return NULL; -} - -struct wlr_surface * -xytolayersurface(struct wl_list *layer_surfaces, double x, double y, - double *sx, double *sy) -{ - LayerSurface *layersurface; - wl_list_for_each_reverse(layersurface, layer_surfaces, link) { - struct wlr_surface *sub; - if (!layersurface->layer_surface->mapped) - continue; - sub = wlr_layer_surface_v1_surface_at( - layersurface->layer_surface, - x - layersurface->geo.x, - y - layersurface->geo.y, - sx, sy); - if (sub) - return sub; + struct wlr_scene_node *node, *pnode; + struct wlr_surface *surface = NULL; + Client *c = NULL; + LayerSurface *l = NULL; + if ((node = wlr_scene_node_at(&scene->node, x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_SURFACE) + surface = wlr_scene_surface_from_node(node)->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = pnode->parent) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } } - return NULL; + + if (psurface) *psurface = surface; + if (pc) *pc = c; + if (pl) *pl = l; + return node; } Monitor * @@ -2520,31 +2375,6 @@ getatom(xcb_connection_t *xc, const char *name) return atom; } -void -renderindependents(struct wlr_output *output, struct timespec *now) -{ - Client *c; - struct render_data rdata; - struct wlr_box geom; - - wl_list_for_each_reverse(c, &independents, link) { - geom.x = c->surface.xwayland->x; - geom.y = c->surface.xwayland->y; - geom.width = c->surface.xwayland->width; - geom.height = c->surface.xwayland->height; - - /* Only render visible clients which show on this output */ - if (!wlr_output_layout_intersects(output_layout, output, &geom)) - continue; - - rdata.output = output; - rdata.when = now; - rdata.x = c->surface.xwayland->x; - rdata.y = c->surface.xwayland->y; - wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata); - } -} - void xwaylandready(struct wl_listener *listener, void *data) { @@ -2575,28 +2405,6 @@ xwaylandready(struct wl_listener *listener, void *data) xcb_disconnect(xc); } - -Client * -xytoindependent(double x, double y) -{ - /* Find the topmost visible independent at point (x, y). - * For independents, the most recently created can be used as the "top". - * We rely on the X11 convention of unmapping unmanaged when the "owning" - * client loses focus, which ensures that unmanaged are only visible on - * the current tag. */ - Client *c; - wl_list_for_each_reverse(c, &independents, link) { - struct wlr_box geom = { - .x = c->surface.xwayland->x, - .y = c->surface.xwayland->y, - .width = c->surface.xwayland->width, - .height = c->surface.xwayland->height, - }; - if (wlr_box_contains_point(&geom, x, y)) - return c; - } - return NULL; -} #endif int From be6f573b4ef723a3985489b0ac0eb035d7c34420 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 5 Sep 2021 16:09:26 -0500 Subject: [PATCH 027/329] use scene to keep track of LayerSurfaces' layers --- dwl.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 2f4bb4c..de4e573 100644 --- a/dwl.c +++ b/dwl.c @@ -156,7 +156,6 @@ typedef struct { struct wl_listener surface_commit; struct wlr_box geo; - enum zwlr_layer_shell_v1_layer layer; } LayerSurface; typedef struct { @@ -764,16 +763,14 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (!wlr_output) return; - m = wlr_output->data; - arrangelayers(m); - if (layersurface->layer != wlr_layer_surface->current.layer) { + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { wl_list_remove(&layersurface->link); wl_list_insert(&m->layers[wlr_layer_surface->current.layer], &layersurface->link); - layersurface->layer = wlr_layer_surface->current.layer; } + arrangelayers(m); } void From 0146a9954b2735a08b326abd69492ac3803ec709 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 5 Sep 2021 22:35:07 -0500 Subject: [PATCH 028/329] use scene_output for damage-tracked rendering --- dwl.c | 53 ++++++++++------------------------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/dwl.c b/dwl.c index de4e573..2b37533 100644 --- a/dwl.c +++ b/dwl.c @@ -174,6 +174,7 @@ typedef struct { struct Monitor { struct wl_list link; struct wlr_output *wlr_output; + struct wlr_scene_output *scene_output; struct wl_listener frame; struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ @@ -862,20 +863,8 @@ createmon(struct wl_listener *listener, void *data) * display, which Wayland clients can see to find out information about the * output (such as DPI, scale factor, manufacturer, etc). */ - wlr_output_layout_add(output_layout, wlr_output, r->x, r->y); - sgeom = *wlr_output_layout_get_box(output_layout, NULL); - - /* When adding monitors, the geometries of all monitors must be updated */ - wl_list_for_each(m, &mons, link) { - /* The first monitor in the list is the most recently added */ - Client *c; - wl_list_for_each(c, &clients, link) { - if (c->isfloating) - resize(c, c->geom.x + m->w.width, c->geom.y, - c->geom.width, c->geom.height, 0); - } - return; - } + m->scene_output = wlr_scene_output_create(scene, wlr_output); + wlr_output_layout_add_auto(output_layout, wlr_output); } void @@ -1602,44 +1591,21 @@ quitsignal(int signo) void rendermon(struct wl_listener *listener, void *data) { - Client *c; - int skip = 0; - /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); - + Client *c; + int skip = 0; struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - /* Skip rendering if any XDG clients have an outstanding resize. */ + /* Render if no XDG clients have an outstanding resize. */ wl_list_for_each(c, &clients, link) skip = skip || c->resize; - - /* HACK: This loop is the simplest way to handle ephemeral pageflip - * failures but probably not the best. Revisit if damage tracking is - * added. */ - do { - /* wlr_output_attach_render makes the OpenGL context current. */ - if (!wlr_output_attach_render(m->wlr_output, NULL)) - return; - - if (!skip) { - /* Begin the renderer (calls glViewport and some other GL sanity checks) */ - wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); - wlr_renderer_clear(drw, rootcolor); - - /* Render the scene at (-mx, -my) to get this monitor's view. - * wlroots will not render windows falling outside the box. */ - wlr_scene_render_output(scene, m->wlr_output, -m->m.x, -m->m.y, NULL); - - /* Conclude rendering and swap the buffers, showing the final frame - * on-screen. */ - wlr_renderer_end(drw); - } - } while (!wlr_output_commit(m->wlr_output)); + if (!skip && !wlr_scene_output_commit(m->scene_output)) + return; /* Let clients know a frame has been rendered */ + clock_gettime(CLOCK_MONOTONIC, &now); wl_list_for_each(c, &clients, link) wlr_surface_send_frame_done(client_surface(c), &now); } @@ -2186,6 +2152,7 @@ updatemons(struct wl_listener *listener, void *data) /* Get the effective monitor geometry to use for surfaces */ m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ From c8bf457c0f12955f89abf88e929a97d96d6f46de Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 21 Sep 2021 10:42:43 -0500 Subject: [PATCH 029/329] fixup: follow name change on surface_tree_create --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 2b37533..a15bbd8 100644 --- a/dwl.c +++ b/dwl.c @@ -920,7 +920,7 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->data = layersurface; m = wlr_layer_surface->output->data; - layersurface->scene = wlr_scene_surface_tree_create( + layersurface->scene = wlr_scene_subsurface_tree_create( layers[wlr_layer_surface->client_pending.layer], wlr_layer_surface->surface); layersurface->scene->data = layersurface; @@ -1299,7 +1299,7 @@ mapnotify(struct wl_listener *listener, void *data) /* Create scene tree for this client and its border */ c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; - c->scene_surface = wlr_scene_surface_tree_create(c->scene, client_surface(c)); + c->scene_surface = wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); c->scene_surface->data = c; for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); From 7de6920bd781d77b2d8d5abb847258c6153638c7 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 21 Sep 2021 14:42:36 -0500 Subject: [PATCH 030/329] send frame_done to all visible surfaces --- dwl.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a15bbd8..9e811ca 100644 --- a/dwl.c +++ b/dwl.c @@ -261,6 +261,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, static void printstatus(void); static void quit(const Arg *arg); static void quitsignal(int signo); +static void rendered(struct wlr_surface *surface, int sx, int sy, void *data); static void rendermon(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); @@ -1588,6 +1589,13 @@ quitsignal(int signo) quit(NULL); } +void +rendered(struct wlr_surface *surface, int sx, int sy, void *data) +{ + struct timespec *now = data; + wlr_surface_send_frame_done(surface, now); +} + void rendermon(struct wl_listener *listener, void *data) { @@ -1607,7 +1615,8 @@ rendermon(struct wl_listener *listener, void *data) /* Let clients know a frame has been rendered */ clock_gettime(CLOCK_MONOTONIC, &now); wl_list_for_each(c, &clients, link) - wlr_surface_send_frame_done(client_surface(c), &now); + if (VISIBLEON(c, c->mon)) + client_for_each_surface(c, rendered, &now); } void From 1e1482adcb3bad768c51b47db9bd86b9e54a9001 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Fri, 24 Sep 2021 16:12:12 -0500 Subject: [PATCH 031/329] client_pending has been renamed as pending in wlr_layer_surface_v1 as seen in swaywm/wlroots@59fa363 --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index a876e8c..4a58770 100644 --- a/dwl.c +++ b/dwl.c @@ -930,13 +930,13 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->data = layersurface; m = wlr_layer_surface->output->data; - wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer], + wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], &layersurface->link); - // Temporarily set the layer's current state to client_pending + // Temporarily set the layer's current state to pending // so that we can easily arrange it old_state = wlr_layer_surface->current; - wlr_layer_surface->current = wlr_layer_surface->client_pending; + wlr_layer_surface->current = wlr_layer_surface->pending; arrangelayers(m); wlr_layer_surface->current = old_state; } From 99fbebcae35aae1d9b673bddb6ebd6eb05feeecf Mon Sep 17 00:00:00 2001 From: ARDiDo <90479315+ARDiDo@users.noreply.github.com> Date: Sun, 26 Sep 2021 20:19:36 -0400 Subject: [PATCH 032/329] Remove redundant xcursor manager --- dwl.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/dwl.c b/dwl.c index 2c1634b..6303c25 100644 --- a/dwl.c +++ b/dwl.c @@ -323,10 +323,6 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; -#ifdef XWAYLAND -static struct wlr_xcursor *xcursor; -static struct wlr_xcursor_manager *xcursor_mgr; -#endif static struct wlr_seat *seat; static struct wl_list keyboards; @@ -2133,18 +2129,6 @@ setup(void) wl_signal_add(&xwayland->events.ready, &xwayland_ready); wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); - /* - * Create the XWayland cursor manager at scale 1, setting its default - * pointer to match the rest of dwl. - */ - xcursor_mgr = wlr_xcursor_manager_create(NULL, 24); - wlr_xcursor_manager_load(xcursor_mgr, 1); - if ((xcursor = wlr_xcursor_manager_get_xcursor(xcursor_mgr, "left_ptr", 1))) - wlr_xwayland_set_cursor(xwayland, - xcursor->images[0]->buffer, xcursor->images[0]->width * 4, - xcursor->images[0]->width, xcursor->images[0]->height, - xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); - setenv("DISPLAY", xwayland->display_name, 1); } else { fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); From df332de9d22f0680a362cd9408a96df58a1d04bc Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Fri, 24 Sep 2021 16:07:06 -0500 Subject: [PATCH 033/329] send frame_done also to all layer surfaces this fixes an issue when bemenu don't update his surface when typing --- dwl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 9e811ca..50ac1b1 100644 --- a/dwl.c +++ b/dwl.c @@ -1603,7 +1603,8 @@ rendermon(struct wl_listener *listener, void *data) * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); Client *c; - int skip = 0; + LayerSurface *layer; + int i, skip = 0; struct timespec now; /* Render if no XDG clients have an outstanding resize. */ @@ -1617,6 +1618,11 @@ rendermon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (VISIBLEON(c, c->mon)) client_for_each_surface(c, rendered, &now); + + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_for_each(layer, &m->layers[i], link) + wlr_layer_surface_v1_for_each_surface(layer->layer_surface, rendered, &now); + } void From 2c9423d1b7a387d63b07b96ecbda725f1e16002b Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Sun, 3 Oct 2021 22:08:00 -0500 Subject: [PATCH 034/329] `wlr_xdg_surface.configure_serial` has been moved into `wlr_xdg_surface_state` as seen in swaywm/wlroots@0e34208 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4a58770..868d57b 100644 --- a/dwl.c +++ b/dwl.c @@ -779,7 +779,7 @@ commitnotify(struct wl_listener *listener, void *data) Client *c = wl_container_of(listener, c, commit); /* mark a pending resize as completed */ - if (c->resize && c->resize <= c->surface.xdg->configure_serial) + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) c->resize = 0; } From 2d9740c2fc481d42eb0deace797553172cc234d9 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 6 Oct 2021 13:00:05 -0500 Subject: [PATCH 035/329] document status information and <&- in README As mentioned in #158. --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b3e4cb..79a7d8f 100644 --- a/README.md +++ b/README.md @@ -54,16 +54,24 @@ dwl can be run on any of the backends supported by wlroots. This means you can r When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the Wayland session. -If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. The argument to this option will be parsed as a shell command (using `sh -c`) and can serve a similar function to `.xinitrc`. Unlike `.xinitrc`, the display server will not shut down when this process terminates. Instead, as dwl is shutting down, it will send this process a SIGTERM and wait for it to terminate (if it hasn't already). This makes it ideal for execing into a user service manager like [s6](https://skarnet.org/software/s6/), [anopa](https://jjacky.com/anopa/), [runit](http://smarden.org/runit/faq.html#userservices), or [`systemd --user`](https://wiki.archlinux.org/title/Systemd/User). +If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. This command will be executed as a shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, but differs in that the display server will not shut down when this process terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait for it to terminate (if it hasn't already). This makes it ideal for execing into a user service manager like [s6](https://skarnet.org/software/s6/), [anopa](https://jjacky.com/anopa/), [runit](http://smarden.org/runit/faq.html#userservices), or [`systemd --user`](https://wiki.archlinux.org/title/Systemd/User). -Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes that it spawns. If you need to set environment variables that affect the entire dwl session (such as `XDG_RUNTIME_DIR` in the note below), these must be set prior to running dwl. - -Note: Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager such as `elogind` or `systemd-logind`. If your system doesn't do this automatically, you will need to configure it prior to launching `dwl`, e.g.: +Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes that it spawns. If you need to set environment variables that affect the entire dwl session, these must be set prior to running dwl. For example, Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager such as `elogind` or `systemd-logind`. If your system doesn't do this automatically, you will need to configure it prior to launching `dwl`, e.g.: export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) mkdir -p $XDG_RUNTIME_DIR dwl +### Status information + +Information about selected layouts, current window title, and selected/occupied/urgent tags is written to the stdin of the `-s` command (see the `printstatus()` function for details). This information can be used to populate an external status bar with a script that parses the information. Failing to read this information will cause dwl to block, so if you do want to run a startup command that does not consume the status information, you can close standard input with the `<&-` shell redirection, for example: + + dwl -s 'foot --server <&-' + +If your startup command is a shell script, you can achieve the same inside the script with the line + + exec <&- + ## Replacements for X applications You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). From ebfefa84bad5a930df4df85b150c27f1d4fe6de6 Mon Sep 17 00:00:00 2001 From: Humm Date: Wed, 13 Oct 2021 23:11:40 +0200 Subject: [PATCH 036/329] -s: close unused fds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dup2 doesn’t close fds, it only duplicates them. The old ones weren’t closed, causing problems (like dwl blocking due to the child process never reading from the reading end, even if stdin has been closed). --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 6303c25..f84460f 100644 --- a/dwl.c +++ b/dwl.c @@ -1823,11 +1823,13 @@ run(char *startup_cmd) EBARF("startup: fork"); if (startup_pid == 0) { dup2(piperw[0], STDIN_FILENO); + close(piperw[0]); close(piperw[1]); execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); EBARF("startup: execl"); } dup2(piperw[1], STDOUT_FILENO); + close(piperw[1]); close(piperw[0]); } /* If nobody is reading the status output, don't terminate */ From 894f2a3152481f7c53baad14dabc1511b70c7bd7 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Sun, 31 Oct 2021 15:32:49 -0600 Subject: [PATCH 037/329] change border color according to focus state --- dwl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dwl.c b/dwl.c index 58a1bd9..a2054b5 100644 --- a/dwl.c +++ b/dwl.c @@ -1064,6 +1064,8 @@ focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; struct wlr_keyboard *kb; + Client *w; + int i; /* Raise client in stacking order if requested */ if (c && lift) { @@ -1081,6 +1083,9 @@ focusclient(Client *c, int lift) wl_list_insert(&fstack, &c->flink); selmon = c->mon; c->isurgent = 0; + + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], focuscolor); } /* Deactivate old client if focus is changing */ @@ -1100,6 +1105,16 @@ focusclient(Client *c, int lift) )) return; } else { +#ifdef XWAYLAND + if (wlr_surface_is_xwayland_surface(old)) + w = wlr_xwayland_surface_from_wlr_surface(old)->data; + else +#endif + w = wlr_xdg_surface_from_wlr_surface(old)->data; + + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(w->border[i], bordercolor); + client_activate_surface(old, 0); } } @@ -1305,6 +1320,7 @@ mapnotify(struct wl_listener *listener, void *data) for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); c->border[i]->node.data = c; + wlr_scene_rect_set_color(c->border[i], bordercolor); } if (client_is_unmanaged(c)) { From 03e167dbb70fbc967e310f95200bcd63f43cac72 Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Sat, 13 Nov 2021 17:22:52 +0100 Subject: [PATCH 038/329] fullscreennotify: don't crash if called before map SDL2 calls xdg_toplevel.unset_fullscreen() before the surface is mapped. This causes a segfault in dwl because setfullscreen() expects the surface to be mapped already. Therefore, delay the setfullscreen call until the surface is mapped. --- dwl.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6303c25..f99fc9a 100644 --- a/dwl.c +++ b/dwl.c @@ -1042,7 +1042,13 @@ void fullscreennotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - setfullscreen(c, !c->isfullscreen); + struct wlr_xdg_toplevel_set_fullscreen_event *event = data; + if (!c->mon) { + /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ + c->isfullscreen = event->fullscreen; + return; + } + setfullscreen(c, event->fullscreen); } Monitor * @@ -1316,6 +1322,9 @@ mapnotify(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus */ applyrules(c); + + if (c->isfullscreen) + setfullscreen(c, 1); } void From 52dbc97ed69f368e63fae57b028072f01d07ee7d Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Sun, 3 Oct 2021 22:08:00 -0500 Subject: [PATCH 039/329] `wlr_xdg_surface.configure_serial` has been moved into `wlr_xdg_surface_state` as seen in swaywm/wlroots@0e34208 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5a525d5..f563fd3 100644 --- a/dwl.c +++ b/dwl.c @@ -779,7 +779,7 @@ commitnotify(struct wl_listener *listener, void *data) Client *c = wl_container_of(listener, c, commit); /* mark a pending resize as completed */ - if (c->resize && c->resize <= c->surface.xdg->configure_serial) + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) c->resize = 0; } From 27f66c87152765942324f85be6b83d0028de295e Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 16 Dec 2021 11:50:11 -0600 Subject: [PATCH 040/329] explicitly create renderer and allocator autocreate was removed --- dwl.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index f563fd3..4353cfd 100644 --- a/dwl.c +++ b/dwl.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -307,6 +308,7 @@ static const char broken[] = "broken"; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_renderer *drw; +static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; static struct wlr_xdg_shell *xdg_shell; @@ -822,6 +824,8 @@ createmon(struct wl_listener *listener, void *data) Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); m->wlr_output = wlr_output; + wlr_output_init_render(wlr_output, alloc, drw); + /* Initialize monitor state using configured rules */ for (size_t i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); @@ -2006,12 +2010,15 @@ setup(void) if (!(backend = wlr_backend_autocreate(dpy))) BARF("couldn't create backend"); - /* If we don't provide a renderer, autocreate makes a GLES2 renderer for us. - * The renderer is responsible for defining the various pixel formats it - * supports for shared memory, this configures that for clients. */ - drw = wlr_backend_get_renderer(backend); + /* Create a renderer with the default implementation */ + if (!(drw = wlr_renderer_autocreate(backend))) + BARF("couldn't create renderer"); wlr_renderer_init_wl_display(drw, dpy); + /* Create a default allocator */ + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + BARF("couldn't create allocator"); + /* This creates some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces and the data device manager * handles the clipboard. Each of these wlroots interfaces has room for you From 317175da08aedf80f0bfaf71849feea531872a88 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Fri, 31 Dec 2021 14:51:50 -0600 Subject: [PATCH 041/329] Newly launched or closed clients ALWAYS generate status update Prior to this change, if a client whose tag(s) are not currently selected is launched or killed, no update to status was printed and status bars being fed by printstatus() did not update newly active or newly inactive (but unselected) tags. --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 8683462..fcd7700 100644 --- a/dwl.c +++ b/dwl.c @@ -1320,6 +1320,7 @@ mapnotify(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus */ applyrules(c); + printstatus(); } void @@ -2290,6 +2291,7 @@ unmapnotify(struct wl_listener *listener, void *data) setmon(c, NULL, 0); wl_list_remove(&c->flink); wl_list_remove(&c->slink); + printstatus(); } void From f587b2fd2c9f5967b9e8ca99fe70fbc80fb6c220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C3=ABl=20Gu=C3=A9neau?= Date: Sat, 8 Jan 2022 17:41:45 +0100 Subject: [PATCH 042/329] fix client_set_tiled, which was ignoring its "edges" argument --- client.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client.h b/client.h index 4fd1863..a6b3723 100644 --- a/client.h +++ b/client.h @@ -156,8 +156,7 @@ client_set_tiled(Client *c, uint32_t edges) if (client_is_x11(c)) return; #endif - wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | - WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + wlr_xdg_toplevel_set_tiled(c->surface.xdg, edges); } static inline struct wlr_surface * From 3300f6c9114885160706e1599801b5000de1dd31 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 18 Jan 2022 11:33:56 -0600 Subject: [PATCH 043/329] Upgrade for wlroots surface refactoring See [1] for details. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3412 --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 8683462..5020a78 100644 --- a/dwl.c +++ b/dwl.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -2029,6 +2030,7 @@ setup(void) wlr_gamma_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); + wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); From ac896a7df4bac35d43579b450f1e4eeabe7a9d44 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 1 Feb 2022 18:58:32 -0600 Subject: [PATCH 044/329] Shift+6 generates XKB_KEY_asciicircum --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 089aa37..738a3ca 100644 --- a/config.def.h +++ b/config.def.h @@ -96,7 +96,7 @@ static const Key keys[] = { TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3), TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4), - TAGKEYS( XKB_KEY_6, XKB_KEY_caret, 5), + TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5), TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6), TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), From ed44bc0c9069e0b55a4765bca10a5ad87732f019 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Wed, 2 Feb 2022 23:18:58 -0600 Subject: [PATCH 045/329] update wlr-output-layout-get-box --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 8683462..ab34d56 100644 --- a/dwl.c +++ b/dwl.c @@ -863,7 +863,7 @@ createmon(struct wl_listener *listener, void *data) * output (such as DPI, scale factor, manufacturer, etc). */ wlr_output_layout_add(output_layout, wlr_output, r->x, r->y); - sgeom = *wlr_output_layout_get_box(output_layout, NULL); + wlr_output_layout_get_box(output_layout, NULL, &sgeom); /* When adding monitors, the geometries of all monitors must be updated */ wl_list_for_each(m, &mons, link) { @@ -2305,7 +2305,7 @@ updatemons(struct wl_listener *listener, void *data) struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); Monitor *m; - sgeom = *wlr_output_layout_get_box(output_layout, NULL); + wlr_output_layout_get_box(output_layout, NULL, &sgeom); wl_list_for_each(m, &mons, link) { struct wlr_output_configuration_head_v1 *config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); @@ -2314,7 +2314,8 @@ updatemons(struct wl_listener *listener, void *data) /* TODO: move focus if selmon is disabled */ /* Get the effective monitor geometry to use for surfaces */ - m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); + wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ From b8ce8d0fbb7cd1ad09ea15ded4a19dc1346e9bcd Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Thu, 3 Feb 2022 21:54:44 -0600 Subject: [PATCH 046/329] Account for changes expecting wlr_xdg_toplevel rather than wlr_xdg_surface --- client.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client.h b/client.h index 4fd1863..ce41c1c 100644 --- a/client.h +++ b/client.h @@ -39,7 +39,7 @@ client_activate_surface(struct wlr_surface *s, int activated) #endif if (wlr_surface_is_xdg_surface(s)) wlr_xdg_toplevel_set_activated( - wlr_xdg_surface_from_wlr_surface(s), activated); + wlr_xdg_surface_from_wlr_surface(s)->toplevel, activated); } static inline void @@ -121,7 +121,7 @@ client_send_close(Client *c) return; } #endif - wlr_xdg_toplevel_send_close(c->surface.xdg); + wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); } static inline void @@ -133,7 +133,7 @@ client_set_fullscreen(Client *c, int fullscreen) return; } #endif - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen); + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); } static inline uint32_t @@ -146,7 +146,7 @@ client_set_size(Client *c, uint32_t width, uint32_t height) return 0; } #endif - return wlr_xdg_toplevel_set_size(c->surface.xdg, width, height); + return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height); } static inline void @@ -156,7 +156,7 @@ client_set_tiled(Client *c, uint32_t edges) if (client_is_x11(c)) return; #endif - wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | + wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); } From b0098d9d095509e4999965d261fe4282040a187a Mon Sep 17 00:00:00 2001 From: Nihal Jere Date: Tue, 22 Feb 2022 23:03:26 -0600 Subject: [PATCH 047/329] die on allocation failure --- dwl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dwl.c b/dwl.c index 36a3871..1b9260b 100644 --- a/dwl.c +++ b/dwl.c @@ -787,6 +787,8 @@ createkeyboard(struct wlr_input_device *device) struct xkb_context *context; struct xkb_keymap *keymap; Keyboard *kb = device->data = calloc(1, sizeof(*kb)); + if (!kb) + EBARF("createkeyboard: calloc"); kb->device = device; /* Prepare an XKB keymap and assign it to the keyboard. */ @@ -818,6 +820,8 @@ createmon(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = data; const MonitorRule *r; Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); + if (!m) + EBARF("createmon: calloc"); m->wlr_output = wlr_output; wlr_output_init_render(wlr_output, alloc, drw); @@ -891,6 +895,8 @@ createnotify(struct wl_listener *listener, void *data) /* Allocate a Client for this surface */ c = xdg_surface->data = calloc(1, sizeof(*c)); + if (!c) + EBARF("createnotify: calloc"); c->surface.xdg = xdg_surface; c->bw = borderpx; @@ -917,6 +923,8 @@ createlayersurface(struct wl_listener *listener, void *data) } layersurface = calloc(1, sizeof(LayerSurface)); + if (!layersurface) + EBARF("layersurface: calloc"); LISTEN(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, @@ -2478,6 +2486,8 @@ createnotifyx11(struct wl_listener *listener, void *data) /* Allocate a Client for this surface */ c = xwayland_surface->data = calloc(1, sizeof(*c)); + if (!c) + EBARF("createnotifyx11: calloc"); c->surface.xwayland = xwayland_surface; c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; From d1ff1e6f75d9c53c953957b5c0a64e0bcb40008b Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Tue, 28 Sep 2021 18:08:52 -0500 Subject: [PATCH 048/329] remove typedef `Decoration` --- dwl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dwl.c b/dwl.c index 36a3871..9f6a2e7 100644 --- a/dwl.c +++ b/dwl.c @@ -119,11 +119,6 @@ typedef struct { int isfullscreen; } Client; -typedef struct { - struct wl_listener request_mode; - struct wl_listener destroy; -} Decoration; - typedef struct { uint32_t mod; xkb_keysym_t keysym; From 3e6d584de107a3d555d652b55bf5227d03f2f957 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Tue, 2 Nov 2021 17:09:54 -0600 Subject: [PATCH 049/329] update URL to wlroots project (GitHub->GitLab) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79a7d8f..1389803 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Join us on our [Discord server](https://discord.gg/jJxZnrGPWN)! -dwl is a compact, hackable compositor for Wayland based on [wlroots](https://github.com/swaywm/wlroots). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is: +dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is: - Easy to understand, hack on, and extend with patches - One C source file (or a very small number) configurable via `config.h` From 230d3432e9633da09a31ed933d8bcaff491db807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 5 Mar 2022 21:07:25 -0600 Subject: [PATCH 050/329] wlr_virtual_keyboard_v1 now has its own wlr_keyboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit which has its own wlr_input_device Signed-off-by: Leonardo Hernández Hernández --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ec4beb2..fcb00da 100644 --- a/dwl.c +++ b/dwl.c @@ -2375,7 +2375,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->input_device; + struct wlr_input_device *device = &keyboard->keyboard.base; createkeyboard(device); } From 8cace1921823e250041f7d85d939960f33824451 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Thu, 4 Nov 2021 08:19:13 -0600 Subject: [PATCH 051/329] fix crash when the last monitor is disconnected --- dwl.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 0619ff1..67a3cd5 100644 --- a/dwl.c +++ b/dwl.c @@ -57,7 +57,7 @@ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) -#define VISIBLEON(C, M) ((C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) +#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) @@ -720,10 +720,11 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->link); wlr_output_layout_remove(output_layout, m->wlr_output); - nmons = wl_list_length(&mons); - do // don't switch to disabled mons - selmon = wl_container_of(mons.prev, selmon, link); - while (!selmon->wlr_output->enabled && i++ < nmons); + if ((nmons = wl_list_length(&mons))) + do // don't switch to disabled mons + selmon = wl_container_of(mons.prev, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + focusclient(focustop(selmon), 1); closemon(m); free(m); @@ -860,6 +861,16 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add(output_layout, wlr_output, r->x, r->y); sgeom = *wlr_output_layout_get_box(output_layout, NULL); + /* If length == 1 we need update selmon. + * Maybe it will change in run(). */ + if (wl_list_length(&mons) == 1) { + Client *c; + selmon = m; + /* If there is any client, set c->mon to this monitor */ + wl_list_for_each(c, &clients, link) + setmon(c, m, c->tags); + } + /* When adding monitors, the geometries of all monitors must be updated */ wl_list_for_each(m, &mons, link) { /* The first monitor in the list is the most recently added */ From f673305e86bea5804fa8c68ffa43f120e7d9f9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 10 Mar 2022 11:37:11 -0600 Subject: [PATCH 052/329] replace tabs by spaces in alignment --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 738a3ca..8408659 100644 --- a/config.def.h +++ b/config.def.h @@ -84,7 +84,7 @@ static const Key keys[] = { { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, { MODKEY, XKB_KEY_space, setlayout, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, - { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, From 5d9c9a9a685bb026b35032ab8cbc0575785a74ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 10 Mar 2022 14:34:36 -0600 Subject: [PATCH 053/329] don't warn about unused result Closes: #186 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index cd4e821..d1b161e 100644 --- a/config.mk +++ b/config.mk @@ -2,7 +2,7 @@ PREFIX = /usr/local # Default compile flags (overridable by environment) -CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wdeclaration-after-statement +CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement # Uncomment to build XWayland support #CFLAGS += -DXWAYLAND From 05a473335ea4c69569d9ad34298b4f42a555e6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 10 Mar 2022 14:48:14 -0600 Subject: [PATCH 054/329] use wlr_box for previous geom --- dwl.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index 67a3cd5..ba150fa 100644 --- a/dwl.c +++ b/dwl.c @@ -101,7 +101,7 @@ typedef struct { struct wl_listener destroy; struct wl_listener set_title; struct wl_listener fullscreen; - struct wlr_box geom; /* layout-relative, includes border */ + struct wlr_box geom, prev; /* layout-relative, includes border */ Monitor *mon; #ifdef XWAYLAND unsigned int type; @@ -112,10 +112,6 @@ typedef struct { unsigned int tags; int isfloating, isurgent; uint32_t resize; /* configure serial of a pending resize */ - int prevx; - int prevy; - int prevwidth; - int prevheight; int isfullscreen; } Client; @@ -1035,15 +1031,12 @@ setfullscreen(Client *c, int fullscreen) client_set_fullscreen(c, fullscreen); if (fullscreen) { - c->prevx = c->geom.x; - c->prevy = c->geom.y; - c->prevheight = c->geom.height; - c->prevwidth = c->geom.width; + c->prev = c->geom; resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ - resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0); + resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0); arrange(c->mon); } } From 2b2f72d7c287fe3255dfa8f7db13f81c6a534a57 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Fri, 24 Sep 2021 16:07:06 -0500 Subject: [PATCH 055/329] use wlr_scene_output_send_frame_done() --- dwl.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/dwl.c b/dwl.c index 301256b..5dd566a 100644 --- a/dwl.c +++ b/dwl.c @@ -262,7 +262,6 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, static void printstatus(void); static void quit(const Arg *arg); static void quitsignal(int signo); -static void rendered(struct wlr_surface *surface, int sx, int sy, void *data); static void rendermon(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); @@ -1605,13 +1604,6 @@ quitsignal(int signo) quit(NULL); } -void -rendered(struct wlr_surface *surface, int sx, int sy, void *data) -{ - struct timespec *now = data; - wlr_surface_send_frame_done(surface, now); -} - void rendermon(struct wl_listener *listener, void *data) { @@ -1631,14 +1623,7 @@ rendermon(struct wl_listener *listener, void *data) /* Let clients know a frame has been rendered */ clock_gettime(CLOCK_MONOTONIC, &now); - wl_list_for_each(c, &clients, link) - if (VISIBLEON(c, c->mon)) - client_for_each_surface(c, rendered, &now); - - for (i = 0; i < LENGTH(m->layers); i++) - wl_list_for_each(layer, &m->layers[i], link) - wlr_layer_surface_v1_for_each_surface(layer->layer_surface, rendered, &now); - + wlr_scene_output_send_frame_done(m->scene_output, &now); } void From b97d9e1ce102fe0aa2331b480827b523164c7d42 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Sun, 31 Oct 2021 17:05:40 -0600 Subject: [PATCH 056/329] use wlr_scene_node_raise_to_top() --- dwl.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 5dd566a..4e90d17 100644 --- a/dwl.c +++ b/dwl.c @@ -1067,11 +1067,8 @@ focusclient(Client *c, int lift) int i; /* Raise client in stacking order if requested */ - if (c && lift) { - /* This isn't easy to do via the current API */ - wl_list_remove(&c->scene->state.link); - wl_list_insert(c->scene->parent->state.children.prev, &c->scene->state.link); - } + if (c && lift) + wlr_scene_node_raise_to_top(c->scene); if (c && client_surface(c) == old) return; From 4465dcb6da1fb91177fc26b4513d14c48eb56d5e Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Tue, 15 Feb 2022 17:38:56 -0600 Subject: [PATCH 057/329] fix left border 'y' position also add comment about border ordering --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4e90d17..d2f910c 100644 --- a/dwl.c +++ b/dwl.c @@ -92,7 +92,7 @@ typedef struct { /* Must be first */ unsigned int type; /* XDGShell or X11* */ struct wlr_scene_node *scene; - struct wlr_scene_rect *border[4]; + struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ struct wlr_scene_node *scene_surface; struct wl_list link; struct wl_list flink; @@ -1641,6 +1641,7 @@ resize(Client *c, int x, int y, int w, int h, int interact) wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); + wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); /* wlroots makes this a no-op if size hasn't changed */ From a7c4f6100a81c68aad6faf9061332f1fbacddd98 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Sun, 13 Feb 2022 14:32:47 -0600 Subject: [PATCH 058/329] use scene layer shell helper --- dwl.c | 138 +++------------------------------------------------------- 1 file changed, 5 insertions(+), 133 deletions(-) diff --git a/dwl.c b/dwl.c index 657bf8d..4a46542 100644 --- a/dwl.c +++ b/dwl.c @@ -144,6 +144,7 @@ typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ struct wlr_scene_node *scene; + struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wlr_layer_surface_v1 *layer_surface; @@ -151,18 +152,8 @@ typedef struct { struct wl_listener map; struct wl_listener unmap; struct wl_listener surface_commit; - - struct wlr_box geo; } LayerSurface; -typedef struct { - uint32_t singular_anchor; - uint32_t anchor_triplet; - int *positive_axis; - int *negative_axis; - int margin; -} Edge; - typedef struct { const char *symbol; void (*arrange)(Monitor *); @@ -206,9 +197,6 @@ typedef struct { /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); -static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, - int32_t exclusive, int32_t margin_top, int32_t margin_right, - int32_t margin_bottom, int32_t margin_left); static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, @@ -386,61 +374,6 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.y = bbox->y; } -void -applyexclusive(struct wlr_box *usable_area, - uint32_t anchor, int32_t exclusive, - int32_t margin_top, int32_t margin_right, - int32_t margin_bottom, int32_t margin_left) { - Edge edges[] = { - { // Top - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .positive_axis = &usable_area->y, - .negative_axis = &usable_area->height, - .margin = margin_top, - }, - { // Bottom - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->height, - .margin = margin_bottom, - }, - { // Left - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = &usable_area->x, - .negative_axis = &usable_area->width, - .margin = margin_left, - }, - { // Right - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->width, - .margin = margin_right, - } - }; - for (size_t i = 0; i < LENGTH(edges); i++) { - if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) - && exclusive + edges[i].margin > 0) { - if (edges[i].positive_axis) - *edges[i].positive_axis += exclusive + edges[i].margin; - if (edges[i].negative_axis) - *edges[i].negative_axis -= exclusive + edges[i].margin; - break; - } - } -} - void applyrules(Client *c) { @@ -492,72 +425,11 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wl_list_for_each(layersurface, list, link) { struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; - struct wlr_box bounds; - struct wlr_box box = { - .width = state->desired_width, - .height = state->desired_height - }; - const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; if (exclusive != (state->exclusive_zone > 0)) continue; - bounds = state->exclusive_zone == -1 ? full_area : *usable_area; - - // Horizontal axis - if ((state->anchor & both_horiz) && box.width == 0) { - box.x = bounds.x; - box.width = bounds.width; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x = bounds.x; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x = bounds.x + (bounds.width - box.width); - } else { - box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } - // Vertical axis - if ((state->anchor & both_vert) && box.height == 0) { - box.y = bounds.y; - box.height = bounds.height; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y = bounds.y; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y = bounds.y + (bounds.height - box.height); - } else { - box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } - // Margin - if ((state->anchor & both_horiz) == both_horiz) { - box.x += state->margin.left; - box.width -= state->margin.left + state->margin.right; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x += state->margin.left; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x -= state->margin.right; - } - if ((state->anchor & both_vert) == both_vert) { - box.y += state->margin.top; - box.height -= state->margin.top + state->margin.bottom; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y += state->margin.top; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y -= state->margin.bottom; - } - if (box.width < 0 || box.height < 0) { - wlr_layer_surface_v1_destroy(wlr_layer_surface); - continue; - } - layersurface->geo = box; - - if (state->exclusive_zone > 0) - applyexclusive(usable_area, state->anchor, state->exclusive_zone, - state->margin.top, state->margin.right, - state->margin.bottom, state->margin.left); - wlr_scene_node_set_position(layersurface->scene, box.x, box.y); - wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); + wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); } } @@ -916,9 +788,9 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->data = layersurface; m = wlr_layer_surface->output->data; - layersurface->scene = wlr_scene_subsurface_tree_create( - layers[wlr_layer_surface->pending.layer], - wlr_layer_surface->surface); + layersurface->scene_layer = wlr_scene_layer_surface_v1_create( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface); + layersurface->scene = layersurface->scene_layer->node; layersurface->scene->data = layersurface; wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], From 0e5d7124de4e7ba0baa080547fcfee41b1d5174d Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Wed, 26 Jan 2022 00:54:00 -0600 Subject: [PATCH 059/329] use loop to call arrangelayer zwlr_layer_shell_v1_layer are ordered by bottom-most first so we can just use a loop from 3 to 0 --- dwl.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/dwl.c b/dwl.c index 9991c95..cd9e74d 100644 --- a/dwl.c +++ b/dwl.c @@ -560,6 +560,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int void arrangelayers(Monitor *m) { + int i; struct wlr_box usable_area = m->m; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, @@ -568,30 +569,18 @@ arrangelayers(Monitor *m) LayerSurface *layersurface; struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); - // Arrange exclusive surfaces from top->bottom - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, 1); - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, 1); - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, 1); - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, 1); + /* Arrange exclusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 1); if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { m->w = usable_area; arrange(m); } - // Arrange non-exlusive surfaces from top->bottom - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, 0); - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, 0); - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, 0); - arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, 0); + /* Arrange non-exlusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 0); // Find topmost keyboard interactive layer, if such a layer exists for (size_t i = 0; i < LENGTH(layers_above_shell); i++) { From 4d26d302200f20294b97d01e49a9a4a7f0b189d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 11 Mar 2022 18:52:22 -0600 Subject: [PATCH 060/329] suckless style: don't use '//' for comments --- dwl.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dwl.c b/dwl.c index cd9e74d..47b5187 100644 --- a/dwl.c +++ b/dwl.c @@ -164,7 +164,7 @@ struct Monitor { struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ - struct wl_list layers[4]; // LayerSurface::link + struct wl_list layers[4]; /* LayerSurface::link */ const Layout *lt[2]; unsigned int seltags; unsigned int sellt; @@ -394,7 +394,7 @@ applyexclusive(struct wlr_box *usable_area, int32_t margin_top, int32_t margin_right, int32_t margin_bottom, int32_t margin_left) { Edge edges[] = { - { // Top + { /* Top */ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | @@ -403,7 +403,7 @@ applyexclusive(struct wlr_box *usable_area, .negative_axis = &usable_area->height, .margin = margin_top, }, - { // Bottom + { /* Bottom */ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | @@ -412,7 +412,7 @@ applyexclusive(struct wlr_box *usable_area, .negative_axis = &usable_area->height, .margin = margin_bottom, }, - { // Left + { /* Left */ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | @@ -421,7 +421,7 @@ applyexclusive(struct wlr_box *usable_area, .negative_axis = &usable_area->width, .margin = margin_left, }, - { // Right + { /* Right */ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | @@ -504,7 +504,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int bounds = state->exclusive_zone == -1 ? full_area : *usable_area; - // Horizontal axis + /* Horizontal axis */ if ((state->anchor & both_horiz) && box.width == 0) { box.x = bounds.x; box.width = bounds.width; @@ -515,7 +515,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int } else { box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); } - // Vertical axis + /* Vertical axis */ if ((state->anchor & both_vert) && box.height == 0) { box.y = bounds.y; box.height = bounds.height; @@ -526,7 +526,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int } else { box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); } - // Margin + /* Margin */ if ((state->anchor & both_horiz) == both_horiz) { box.x += state->margin.left; box.width -= state->margin.left + state->margin.right; @@ -582,13 +582,13 @@ arrangelayers(Monitor *m) for (i = 3; i >= 0; i--) arrangelayer(m, &m->layers[i], &usable_area, 0); - // Find topmost keyboard interactive layer, if such a layer exists + /* Find topmost keyboard interactive layer, if such a layer exists */ for (size_t i = 0; i < LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && layersurface->layer_surface->mapped) { - // Deactivate the focused client. + /* Deactivate the focused client. */ focusclient(NULL, 0); wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); @@ -706,7 +706,7 @@ cleanupmon(struct wl_listener *listener, void *data) wlr_output_layout_remove(output_layout, m->wlr_output); if ((nmons = wl_list_length(&mons))) - do // don't switch to disabled mons + do /* don't switch to disabled mons */ selmon = wl_container_of(mons.prev, selmon, link); while (!selmon->wlr_output->enabled && i++ < nmons); @@ -718,7 +718,7 @@ cleanupmon(struct wl_listener *listener, void *data) void closemon(Monitor *m) { - // move closed monitor's clients to the focused one + /* move closed monitor's clients to the focused one */ Client *c; wl_list_for_each(c, &clients, link) { @@ -932,8 +932,9 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], &layersurface->link); - // Temporarily set the layer's current state to pending - // so that we can easily arrange it + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it + */ old_state = wlr_layer_surface->current; wlr_layer_surface->current = wlr_layer_surface->pending; arrangelayers(m); @@ -1352,7 +1353,7 @@ motionnotify(uint32_t time) struct wlr_surface *surface = NULL; Client *c = NULL; - // time is 0 in internal calls meant to restore pointer focus. + /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { wlr_idle_notify_activity(idle, seat); @@ -2607,8 +2608,7 @@ main(int argc, char *argv[]) if (optind < argc) goto usage; - // Wayland requires XDG_RUNTIME_DIR for creating its communications - // socket + /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ if (!getenv("XDG_RUNTIME_DIR")) BARF("XDG_RUNTIME_DIR must be set"); setup(); From 08020d61b7ed2c13a544c7c3f051754088475a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 11 Mar 2022 23:02:37 -0600 Subject: [PATCH 061/329] more style fixes --- dwl.c | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/dwl.c b/dwl.c index 47b5187..65244e7 100644 --- a/dwl.c +++ b/dwl.c @@ -623,7 +623,7 @@ buttonpress(struct wl_listener *listener, void *data) wlr_idle_notify_activity(idle, seat); switch (event->state) { - case WLR_BUTTON_PRESSED:; + case WLR_BUTTON_PRESSED: /* Change focus if the button was _pressed_ over a client */ if ((c = xytoclient(cursor->x, cursor->y))) focusclient(c, 1); @@ -642,8 +642,7 @@ buttonpress(struct wl_listener *listener, void *data) /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ if (cursor_mode != CurNormal) { - wlr_xcursor_manager_set_cursor_image(cursor_mgr, - "left_ptr", cursor); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); cursor_mode = CurNormal; /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); @@ -1278,16 +1277,16 @@ void killclient(const Arg *arg) { Client *sel = selclient(); - if (!sel) - return; - client_send_close(sel); + if (sel) + client_send_close(sel); } void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, map); - wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); + wlr_surface_send_enter(layersurface->layer_surface->surface, + layersurface->layer_surface->output); motionnotify(0); } @@ -1406,8 +1405,7 @@ motionnotify(uint32_t time) * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ if (!surface && time) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, - "left_ptr", cursor); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); pointerfocus(c, surface, sx, sy, time); } @@ -1423,8 +1421,7 @@ 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_cursor_move(cursor, event->device, event->delta_x, event->delta_y); motionnotify(event->time_msec); } @@ -1644,8 +1641,7 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) * compositor. */ transform = wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &obox, transform, 0, - output->transform_matrix); + wlr_matrix_project_box(matrix, &obox, transform, 0, output->transform_matrix); /* This takes our matrix, the texture, and an alpha, and performs the actual * rendering on the GPU. */ @@ -1678,8 +1674,7 @@ renderclients(Monitor *m, struct timespec *now) surface = client_surface(c); ox = c->geom.x, oy = c->geom.y; - wlr_output_layout_output_coords(output_layout, m->wlr_output, - &ox, &oy); + wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy); if (c->bw) { w = surface->current.width; @@ -1695,8 +1690,7 @@ renderclients(Monitor *m, struct timespec *now) color = (c == sel) ? focuscolor : bordercolor; for (i = 0; i < 4; i++) { scalebox(&borders[i], m->wlr_output->scale); - wlr_render_rect(drw, &borders[i], color, - m->wlr_output->transform_matrix); + wlr_render_rect(drw, &borders[i], color, m->wlr_output->transform_matrix); } } @@ -2113,12 +2107,9 @@ setup(void) wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, &new_virtual_keyboard); seat = wlr_seat_create(dpy, "seat0"); - wl_signal_add(&seat->events.request_set_cursor, - &request_cursor); - wl_signal_add(&seat->events.request_set_selection, - &request_set_sel); - wl_signal_add(&seat->events.request_set_primary_selection, - &request_set_psel); + wl_signal_add(&seat->events.request_set_cursor, &request_cursor); + wl_signal_add(&seat->events.request_set_selection, &request_set_sel); + wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); @@ -2226,10 +2217,9 @@ void togglefloating(const Arg *arg) { Client *sel = selclient(); - if (!sel) - return; /* return if fullscreen */ - setfloating(sel, !sel->isfloating /* || sel->isfixed */); + if (sel && !sel->isfullscreen) + setfloating(sel, !sel->isfloating); } void @@ -2491,8 +2481,7 @@ createnotifyx11(struct wl_listener *listener, void *data) /* Listen to the various events it can emit */ LISTEN(&xwayland_surface->events.map, &c->map, mapnotify); LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xwayland_surface->events.request_activate, &c->activate, - activatex11); + LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11); LISTEN(&xwayland_surface->events.request_configure, &c->configure, configurex11); LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); From 0c4740b27735199f2c194b47c85ab321250631b4 Mon Sep 17 00:00:00 2001 From: Humm Date: Wed, 5 Jan 2022 01:54:02 +0100 Subject: [PATCH 062/329] add dwl(1) Documentation is good. Man pages are documentation. A program without a man page is worthless. --- Makefile | 5 +- config.mk | 1 + dwl.1 | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 dwl.1 diff --git a/Makefile b/Makefile index 5ff69e9..536454f 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,11 @@ clean: rm -f dwl *.o *-protocol.h *-protocol.c install: dwl - install -D dwl $(PREFIX)/bin/dwl + install -Dm755 dwl $(PREFIX)/bin/dwl + install -Dm644 dwl.1 $(MANDIR)/man1/dwl.1 uninstall: - rm -f $(PREFIX)/bin/dwl + rm -f $(PREFIX)/bin/dwl $(MANDIR)/man1/dwl.1 .PHONY: all clean install uninstall diff --git a/config.mk b/config.mk index cd4e821..e38a8e5 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,6 @@ # paths PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man # Default compile flags (overridable by environment) CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wdeclaration-after-statement diff --git a/dwl.1 b/dwl.1 new file mode 100644 index 0000000..eea0f70 --- /dev/null +++ b/dwl.1 @@ -0,0 +1,144 @@ +.Dd January 8, 2021 +.Dt DWL 1 +.Os +.Sh NAME +.Nm dwl +.Nd dwm for Wayland +.Sh SYNOPSIS +.Nm +.Op Fl s Ar command +.Sh DESCRIPTION +.Nm +is a Wayland compositor based on wlroots. +It is intended to fill the same space in the Wayland world that +.Nm dwm +does for X11. +.Pp +When given the +.Fl s +option, +.Nm +starts a shell process running +.Ar command +when starting. +When stopping, it sends +.Dv SIGTERM +to the child process and waits for it to exit. +.Pp +Users are encouraged to customize +.Nm +by editing the sources, in particular +.Pa config.h . +The default key bindings are as follows: +.Bl -tag -width 20n -offset indent -compact +.It Mod-[1-9] +Show only all windows with a tag. +.It Mod-Ctrl-[1-9] +Show all windows with a tag. +.It Mod-Shift-[1-9] +Move window to a single tag. +.It Mod-Ctrl-Shift-[1-9] +Toggle tag for window. +.It Mod-p +Spawn +.Nm bemenu-run . +.It Mod-Shift-Return +Spawn +.Nm alacritty . +.It Mod-[jk] +Move focus down/up the stack. +.It Mod-[id] +Increase/decrease number of windows in master area. +.It Mod-[hl] +Decrease/increase master area. +.It Mod-Return +Move window on top of stack or switch top of stack with second window. +.It Mod-Tab +Show only all windows with previous tag. +.It Mod-Shift-c +Close window. +.It Mod-t +Switch to tabbed layout. +.It Mod-f +Switch to floating layout. +.It Mod-m +Switch to monocle layout. +.It Mod-Space +Switch to previous layout. +.It Mod-Shift-Space +Toggle floating state of window. +.It Mod-e +Toggle fullscreen state of window. +.It Mod-0 +Show all windows. +.It Mod-Shift-0 +Set all tags for window. +.It Mod-, +Move focus to previous monitor. +.It Mod-. +Move focus to next monitor. +.It Mod-Shift-, +Move window to previous monitor. +.It Mod-Shift-. +Move window to next monitor. +.It Mod-Shift-q +Quit +.Nm . +.El +These might differ depending on your keyboard layout. +.Sh ENVIRONMENT +These environment variables are used by +.Nm : +.Bl -tag -width XDG_RUNTIME_DIR +.It Ev XDG_RUNTIME_DIR +A directory where temporary user files, such as the Wayland socket, +are stored. +.It Ev XDG_CONFIG_DIR +A directory containung configuration of various programs and +libraries, including libxkbcommon. +.It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET +Tell how to connect to an underlying X11 or Wayland server. +.It Ev WLR_* +Various variables specific to wlroots. +.It Ev XKB_* , XLOCALEDIR , XCOMPOSEFILE +Various variables specific to libxkbcommon. +.It Ev XCURSOR_PATH +List of directories to search for XCursor themes in. +.It Ev HOME +A directory where there are always dear files there for you. +Waiting for you to clean them up. +.El +.Pp +These are set by +.Nm : +.Bl -tag -width WAYLAND_DISPLAY +.It Ev WAYLAND_DISPLAY +Tell how to connect to +.Nm . +.It Ev DISPLAY +If using +.Nm Xwayland , +tell how to connect to the +.Nm Xwayland +server. +.El +.Sh EXAMPLES +Start +.Nm +with s6 in the background: +.Dl dwl -s 's6-svscan <&-' +.Sh SEE ALSO +.Xr alacritty 1 , +.Xr bemenu 1 , +.Xr dwm 1 , +.Xr xkeyboard-config 7 +.Sh CAVEATS +The child process's standard input is connected with a pipe to +.Nm . +If the child process neither reads from the pipe nor closes its +standard input, +.Nm +will freeze after a while due to it blocking when writing to the full +pipe buffer. +.Sh BUGS +All of them. From 2cd0b3173d2ba7078347a8172b497d12fa592549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Mar 2022 15:16:06 -0600 Subject: [PATCH 063/329] print status about floating and fullscreen --- dwl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 65244e7..1388acb 100644 --- a/dwl.c +++ b/dwl.c @@ -1036,6 +1036,7 @@ setfullscreen(Client *c, int fullscreen) resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0); arrange(c->mon); } + printstatus(); } void @@ -1568,10 +1569,14 @@ printstatus(void) urg |= c->tags; } if ((c = focustop(m))) { - printf("%s title %s\n", m->wlr_output->name, client_get_title(focustop(m))); + printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); + printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen); + printf("%s floating %u\n", m->wlr_output->name, c->isfloating); sel = c->tags; } else { printf("%s title \n", m->wlr_output->name); + printf("%s fullscreen \n", m->wlr_output->name); + printf("%s floating \n", m->wlr_output->name); sel = 0; } @@ -1902,6 +1907,7 @@ setfloating(Client *c, int floating) { c->isfloating = floating; arrange(c->mon); + printstatus(); } void From ebff6e38a02086bd6078a444641a83cb226f9995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Mar 2022 17:11:52 -0600 Subject: [PATCH 064/329] always call arrange() on setfullscreen() also don't count full screen clients on tile() --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 1388acb..20e7c5c 100644 --- a/dwl.c +++ b/dwl.c @@ -1034,8 +1034,8 @@ setfullscreen(Client *c, int fullscreen) /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0); - arrange(c->mon); } + arrange(c->mon); printstatus(); } @@ -2193,7 +2193,7 @@ tile(Monitor *m) Client *c; wl_list_for_each(c, &clients, link) - if (VISIBLEON(c, m) && !c->isfloating) + if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) n++; if (n == 0) return; From 43228bd493f53f996a645156f0505b63e79a4f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Mar 2022 20:54:44 -0600 Subject: [PATCH 065/329] don't use fullscreen event in fullscreennotify() --- client.h | 10 ++++++++++ dwl.c | 7 ++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/client.h b/client.h index 56e3089..f955688 100644 --- a/client.h +++ b/client.h @@ -95,6 +95,16 @@ client_is_float_type(Client *c) return 0; } +static inline int +client_wants_fullscreen(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->fullscreen; +#endif + return c->surface.xdg->toplevel->requested.fullscreen; +} + static inline int client_is_unmanaged(Client *c) { diff --git a/dwl.c b/dwl.c index f99fc9a..612f3d7 100644 --- a/dwl.c +++ b/dwl.c @@ -1042,13 +1042,14 @@ void fullscreennotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - struct wlr_xdg_toplevel_set_fullscreen_event *event = data; + int fullscreen = client_wants_fullscreen(c); + if (!c->mon) { /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ - c->isfullscreen = event->fullscreen; + c->isfullscreen = fullscreen; return; } - setfullscreen(c, event->fullscreen); + setfullscreen(c, fullscreen); } Monitor * From 1087bc5db98faf12e02e57433ed52cbc9845e98b Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Fri, 29 Oct 2021 18:38:24 -0500 Subject: [PATCH 066/329] use wlr_scene_xdg_surface_create() for xdg_popups --- dwl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index d2f910c..8deee97 100644 --- a/dwl.c +++ b/dwl.c @@ -875,7 +875,11 @@ createnotify(struct wl_listener *listener, void *data) struct wlr_xdg_surface *xdg_surface = data; Client *c; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + xdg_surface->surface->data = wlr_scene_xdg_surface_create( + xdg_surface->popup->parent->data, xdg_surface); + return; + } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) return; /* Allocate a Client for this surface */ @@ -1311,7 +1315,8 @@ mapnotify(struct wl_listener *listener, void *data) /* Create scene tree for this client and its border */ c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; - c->scene_surface = wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); + c->scene_surface = client_surface(c)->data = + wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); c->scene_surface->data = c; for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); From b92c0ff57fbf9cc9ffb2a33e689acc08b8745f1d Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Tue, 1 Feb 2022 01:16:56 -0600 Subject: [PATCH 067/329] add support for layer_shell popups --- dwl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 8deee97..0d8a1b1 100644 --- a/dwl.c +++ b/dwl.c @@ -871,7 +871,10 @@ void createnotify(struct wl_listener *listener, void *data) { /* This event is raised when wlr_xdg_shell receives a new xdg surface from a - * client, either a toplevel (application window) or popup. */ + * client, either a toplevel (application window) or popup, + * or when wlr_layer_shell receives a new popup from a layer. + * If you want to do something tricky with popups you should check if + * its parent is wlr_xdg_shell or wlr_layer_shell */ struct wlr_xdg_surface *xdg_surface = data; Client *c; @@ -924,8 +927,8 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->data = layersurface; m = wlr_layer_surface->output->data; - layersurface->scene = wlr_scene_subsurface_tree_create( - layers[wlr_layer_surface->pending.layer], + layersurface->scene = wlr_layer_surface->surface->data = + wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], wlr_layer_surface->surface); layersurface->scene->data = layersurface; From 863eedd05e8d292ccef2530d9b4b8b5475b8cbef Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Mon, 31 Jan 2022 14:02:59 -0600 Subject: [PATCH 068/329] set correct position for unmanaged clients - don't allow to move/resize with them - don't focus unmanaged clients on buttonpress() --- dwl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 0d8a1b1..7f8d3f4 100644 --- a/dwl.c +++ b/dwl.c @@ -645,7 +645,8 @@ buttonpress(struct wl_listener *listener, void *data) case WLR_BUTTON_PRESSED:; /* Change focus if the button was _pressed_ over a client */ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); - if (c) + /* Don't focus unmanaged clients */ + if (c && !client_is_unmanaged(c)) focusclient(c, 1); keyboard = wlr_seat_get_keyboard(seat); @@ -1328,9 +1329,12 @@ mapnotify(struct wl_listener *listener, void *data) } if (client_is_unmanaged(c)) { + client_get_geometry(c, &c->geom); /* Floating, no border */ wlr_scene_node_reparent(c->scene, layers[LyrFloat]); c->bw = 0; + wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, + c->geom.y + borderpx); /* Insert this independent into independents lists. */ wl_list_insert(&independents, &c->link); @@ -1442,7 +1446,7 @@ moveresize(const Arg *arg) if (cursor_mode != CurNormal) return; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); - if (!grabc) + if (!grabc || client_is_unmanaged(grabc)) return; /* Float the window and tell motionnotify to grab it */ From 2768af5a9bfd7cb5f874a8d61f4bc9a1188b82fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 16 Mar 2022 21:42:45 -0600 Subject: [PATCH 069/329] make sure configure and activate listeners are removed from list --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3c57c23..09ddc9a 100644 --- a/dwl.c +++ b/dwl.c @@ -1004,9 +1004,10 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->set_title.link); wl_list_remove(&c->fullscreen.link); #ifdef XWAYLAND - if (c->type == X11Managed) + if (c->type != XDGShell) { + wl_list_remove(&c->configure.link); wl_list_remove(&c->activate.link); - else if (c->type == XDGShell) + } else #endif wl_list_remove(&c->commit.link); free(c); From 294fb324d8f67c33552b15d3f1f79fe524d5f8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 16 Mar 2022 23:08:17 -0600 Subject: [PATCH 070/329] constraint popups to its parent client Closes: #146 Closes: #155 --- client.h | 21 +++++++++++++++++++++ dwl.c | 9 ++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 191dcc5..22454a5 100644 --- a/client.h +++ b/client.h @@ -179,3 +179,24 @@ client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) #endif return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); } + +static inline Client * +client_from_popup(struct wlr_xdg_popup *popup) +{ + struct wlr_xdg_surface *surface = popup->base; + + while (1) { + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!wlr_surface_is_xdg_surface(surface->popup->parent)) + return NULL; + + surface = wlr_xdg_surface_from_wlr_surface(surface->popup->parent); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + return surface->data; + case WLR_XDG_SURFACE_ROLE_NONE: + return NULL; + } + } +} diff --git a/dwl.c b/dwl.c index 09ddc9a..58f1b36 100644 --- a/dwl.c +++ b/dwl.c @@ -880,7 +880,14 @@ createnotify(struct wl_listener *listener, void *data) struct wlr_xdg_surface *xdg_surface = data; Client *c; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_box box; + if (!(c = client_from_popup(xdg_surface->popup))) + return; + client_get_geometry(c, &box); + wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); + return; + } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) return; /* Allocate a Client for this surface */ From 1dfd867d9caa61d9f3fabf695a72b2fea35b6193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 17 Mar 2022 17:02:03 -0600 Subject: [PATCH 071/329] fix crash of Firefox when opening a popup larger than its size --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 58f1b36..8e0a399 100644 --- a/dwl.c +++ b/dwl.c @@ -882,9 +882,11 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; - if (!(c = client_from_popup(xdg_surface->popup))) + if (!(c = client_from_popup(xdg_surface->popup)) || !c->mon) return; - client_get_geometry(c, &box); + box = c->mon->m; + box.x -= c->geom.x; + box.y -= c->geom.y; wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); return; } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) From f1c92b05fb124d6865d4dfb0c121b3dbf7fd5407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 00:49:47 -0600 Subject: [PATCH 072/329] get old client by surface's node --- dwl.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index 347178b..4df0e95 100644 --- a/dwl.c +++ b/dwl.c @@ -1076,7 +1076,6 @@ focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; struct wlr_keyboard *kb; - Client *w; int i; /* Raise client in stacking order if requested */ @@ -1114,15 +1113,11 @@ focusclient(Client *c, int lift) )) return; } else { -#ifdef XWAYLAND - if (wlr_surface_is_xwayland_surface(old)) - w = wlr_xwayland_surface_from_wlr_surface(old)->data; - else -#endif - w = wlr_xdg_surface_from_wlr_surface(old)->data; - - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(w->border[i], bordercolor); + Client *w; + struct wlr_scene_node *node = old->data; + if ((w = node->data)) + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(w->border[i], bordercolor); client_activate_surface(old, 0); } From 1b22ef16161fe832e14aa29678e09eb7df56e395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 00:52:21 -0600 Subject: [PATCH 073/329] use xdg_shell helper for xwayland continue using wlr_scene_subsurface_create() --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 4df0e95..464554c 100644 --- a/dwl.c +++ b/dwl.c @@ -1319,8 +1319,9 @@ mapnotify(struct wl_listener *listener, void *data) /* Create scene tree for this client and its border */ c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; - c->scene_surface = client_surface(c)->data = - wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); + c->scene_surface = client_surface(c)->data = c->type == XDGShell + ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) + : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); c->scene_surface->data = c; for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); From 0815626d4c4db3aa05ed256975476d6a31be2125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 00:59:52 -0600 Subject: [PATCH 074/329] pointerfocus: only use provided surface if a client is given focus it --- dwl.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/dwl.c b/dwl.c index 464554c..392cec1 100644 --- a/dwl.c +++ b/dwl.c @@ -1540,9 +1540,8 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, struct timespec now; int internal_call = !time; - /* Use top level surface if nothing more specific given */ - if (c && !surface) - surface = client_surface(c); + if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) + focusclient(c, 0); /* If surface is NULL, clear pointer focus */ if (!surface) { @@ -1555,21 +1554,12 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, time = now.tv_sec * 1000 + now.tv_nsec / 1000000; } - /* If surface is already focused, only notify of motion */ - if (surface == seat->pointer_state.focused_surface) { - wlr_seat_pointer_notify_motion(seat, time, sx, sy); - return; - } - - /* Otherwise, let the client know that the mouse cursor has entered one - * of its surfaces, and make keyboard focus follow if desired. */ + /* Let the client know that the mouse cursor has entered one + * of its surfaces, and make keyboard focus follow if desired. + * wlroots makes this a no-op if surface is already focused */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); - if (!c || client_is_unmanaged(c)) - return; - - if (sloppyfocus && !internal_call) - focusclient(c, 0); } void From 254f799fde51faf71ce3ec5e7af75826f4263d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 01:02:50 -0600 Subject: [PATCH 075/329] do not create borders for unmanaged clients --- dwl.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index 392cec1..8f6e816 100644 --- a/dwl.c +++ b/dwl.c @@ -1323,17 +1323,11 @@ mapnotify(struct wl_listener *listener, void *data) ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); c->scene_surface->data = c; - for (i = 0; i < 4; i++) { - c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); - c->border[i]->node.data = c; - wlr_scene_rect_set_color(c->border[i], bordercolor); - } if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); - /* Floating, no border */ + /* Floating */ wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - c->bw = 0; wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, c->geom.y + borderpx); @@ -1342,6 +1336,13 @@ mapnotify(struct wl_listener *listener, void *data) return; } + for (i = 0; i < 4; i++) { + c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); + c->border[i]->node.data = c; + wlr_scene_rect_set_color(c->border[i], bordercolor); + wlr_scene_node_lower_to_bottom(&c->border[i]->node); + } + /* Initialize client geometry with room for border */ client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); client_get_geometry(c, &c->geom); From 467123dc99db4a537f1043e081cc4a6db136417b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 01:03:33 -0600 Subject: [PATCH 076/329] make sure to destroy wlr_scene_node of unmanaged clients --- dwl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8f6e816..c63dbe4 100644 --- a/dwl.c +++ b/dwl.c @@ -2139,8 +2139,10 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } wl_list_remove(&c->link); - if (client_is_unmanaged(c)) + if (client_is_unmanaged(c)) { + wlr_scene_node_destroy(c->scene); return; + } setmon(c, NULL, 0); wl_list_remove(&c->flink); From 475c13414479d1013c83309fcc4bb8a8707aa721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 01:25:53 -0600 Subject: [PATCH 077/329] do not allow set client size less than its min size --- client.h | 20 ++++++++++++++++++++ dwl.c | 6 ++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/client.h b/client.h index 191dcc5..c59b7a9 100644 --- a/client.h +++ b/client.h @@ -179,3 +179,23 @@ client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) #endif return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); } + +static inline void +client_min_size(Client *c, int *width, int *height) +{ + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state *state; +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface_size_hints *size_hints; + size_hints = c->surface.xwayland->size_hints; + *width = size_hints->min_width; + *height = size_hints->min_height; + return; + } +#endif + toplevel = c->surface.xdg->toplevel; + state = &toplevel->current; + *width = state->min_width; + *height = state->min_height; +} diff --git a/dwl.c b/dwl.c index c63dbe4..d2f0718 100644 --- a/dwl.c +++ b/dwl.c @@ -1636,11 +1636,13 @@ rendermon(struct wl_listener *listener, void *data) void resize(Client *c, int x, int y, int w, int h, int interact) { + int min_width = 0, min_height = 0; struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + client_min_size(c, &min_width, &min_height); c->geom.x = x; c->geom.y = y; - c->geom.width = w; - c->geom.height = h; + c->geom.width = MAX(min_width + 2 * c->bw, w); + c->geom.height = MAX(min_height + 2 * c->bw, h); applybounds(c, bbox); /* Update scene-graph, including borders */ From e4bf83e26d4eccfcab3d54c6ebdbcc53a90346cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 01:43:30 -0600 Subject: [PATCH 078/329] update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1389803..d094599 100644 --- a/README.md +++ b/README.md @@ -19,15 +19,14 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s - Various Wayland protocols - XWayland support as provided by wlroots (can be enabled in `config.mk`) - Zero flickering - Wayland users naturally expect that "every frame is perfect" +- Layer shell popups (used by Waybar) +- Damage tracking provided by scenegraph API Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Implement the input-inhibitor protocol to support screen lockers -- Implement the idle-inhibit protocol which lets applications such as mpv disable idle monitoring -- Layer shell popups (used by Waybar) -- Basic yes/no damage tracking to avoid needless redraws -- More in-depth damage region tracking ([which may improve power usage](https://mozillagfx.wordpress.com/2019/10/22/dramatically-reduced-power-usage-in-firefox-70-on-macos-with-core-animation/)) +- Implement the input-inhibitor protocol to support screen lockers (see https://github.com/djpohly/dwl/pull/132) +- Implement the idle-inhibit protocol which lets applications such as mpv disable idle monitoring (see https://github.com/djpohly/dwl/pull/133) - Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/12) Feature *non-goals* for the main codebase include: From e645ea8301f3d6edf14cfb36c4d663bf721d3200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 10:40:40 -0600 Subject: [PATCH 079/329] attach presentation to scene --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index bb3ff9a..7f4da78 100644 --- a/dwl.c +++ b/dwl.c @@ -1986,6 +1986,7 @@ setup(void) wl_signal_add(&output_mgr->events.test, &output_mgr_test); presentation = wlr_presentation_create(dpy, backend); + wlr_scene_set_presentation(scene, presentation); #ifdef XWAYLAND /* From 19c14b058c9188b7010ffd62bcb1276417e9ed67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 11:04:34 -0600 Subject: [PATCH 080/329] remove unneeded variables --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 7f4da78..2d95286 100644 --- a/dwl.c +++ b/dwl.c @@ -1625,8 +1625,7 @@ rendermon(struct wl_listener *listener, void *data) * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); Client *c; - LayerSurface *layer; - int i, skip = 0; + int skip = 0; struct timespec now; /* Render if no XDG clients have an outstanding resize. */ From 98f33cd01dc452df411c07eab3b107f0172081f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 17:20:31 -0600 Subject: [PATCH 081/329] follow up wlroots input device events renaming --- dwl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index fcb00da..8a1e3ea 100644 --- a/dwl.c +++ b/dwl.c @@ -619,7 +619,7 @@ axisnotify(struct wl_listener *listener, void *data) { /* This event is forwarded by the cursor when a pointer emits an axis event, * for example when you move the scroll wheel. */ - struct wlr_event_pointer_axis *event = data; + struct wlr_pointer_axis_event *event = data; wlr_idle_notify_activity(idle, seat); /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, @@ -630,7 +630,7 @@ axisnotify(struct wl_listener *listener, void *data) void buttonpress(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_button *event = data; + struct wlr_pointer_button_event *event = data; struct wlr_keyboard *keyboard; uint32_t mods; Client *c; @@ -1228,7 +1228,7 @@ keypress(struct wl_listener *listener, void *data) int i; /* This event is raised when a key is pressed or released. */ Keyboard *kb = wl_container_of(listener, kb, key); - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; /* Translate libinput keycode -> xkbcommon */ uint32_t keycode = event->keycode + 8; @@ -1340,8 +1340,8 @@ motionabsolute(struct wl_listener *listener, void *data) * move the mouse over the window. You could enter the window from any edge, * 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); + struct wlr_pointer_motion_absolute_event *event = data; + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); motionnotify(event->time_msec); } @@ -1416,14 +1416,13 @@ motionrelative(struct wl_listener *listener, void *data) { /* This event is forwarded by the cursor when a pointer emits a _relative_ * pointer motion event (i.e. a delta) */ - struct wlr_event_pointer_motion *event = data; + struct wlr_pointer_motion_event *event = data; /* The cursor doesn't move unless we tell it to. The cursor automatically * handles constraining the motion to the output layout, as well as any * 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_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y); motionnotify(event->time_msec); } From dd463b25c7de4ea802038997a93ea749297b8c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 20 Mar 2022 12:32:44 -0600 Subject: [PATCH 082/329] remove independents list --- dwl.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 2d95286..01f51ad 100644 --- a/dwl.c +++ b/dwl.c @@ -302,7 +302,6 @@ static struct wlr_xdg_shell *xdg_shell; static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ -static struct wl_list independents; static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; @@ -1337,9 +1336,6 @@ mapnotify(struct wl_listener *listener, void *data) wlr_scene_node_reparent(c->scene, layers[LyrFloat]); wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, c->geom.y + borderpx); - - /* Insert this independent into independents lists. */ - wl_list_insert(&independents, &c->link); return; } @@ -1917,7 +1913,6 @@ setup(void) */ wl_list_init(&clients); wl_list_init(&fstack); - wl_list_init(&independents); idle = wlr_idle_create(dpy); @@ -2147,12 +2142,13 @@ unmapnotify(struct wl_listener *listener, void *data) cursor_mode = CurNormal; grabc = NULL; } - wl_list_remove(&c->link); + if (client_is_unmanaged(c)) { wlr_scene_node_destroy(c->scene); return; } + wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); wlr_scene_node_destroy(c->scene); From 0dea553428c8c534ea8bbb914b1ec775cf36e4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 20 Mar 2022 19:09:28 -0600 Subject: [PATCH 083/329] destroy scene_output in cleanupmon() --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 01f51ad..74f8549 100644 --- a/dwl.c +++ b/dwl.c @@ -703,6 +703,7 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->frame.link); wl_list_remove(&m->link); wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); if ((nmons = wl_list_length(&mons))) do /* don't switch to disabled mons */ From c50f187c1f784c010b1261848fade72b9401b28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 13:52:33 -0600 Subject: [PATCH 084/329] improve floating detection mostly copied from sway --- client.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/client.h b/client.h index a5fc0d2..41c9b9a 100644 --- a/client.h +++ b/client.h @@ -91,16 +91,37 @@ client_get_title(Client *c) static inline int client_is_float_type(Client *c) { + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; + #ifdef XWAYLAND - if (client_is_x11(c)) - for (size_t i = 0; i < c->surface.xwayland->window_type_len; i++) - if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility]) + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + struct wlr_xwayland_surface_size_hints *size_hints; + if (surface->modal) + return 1; + + for (size_t i = 0; i < surface->window_type_len; i++) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] || + surface->window_type[i] == netatom[NetWMWindowTypeSplash] || + surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || + surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; + + size_hints = surface->size_hints; + if (size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 + && (size_hints->max_width == size_hints->min_width || + size_hints->max_height == size_hints->min_height)) + return 1; + } #endif - return 0; + + toplevel = c->surface.xdg->toplevel; + state = toplevel->current; + return (state.min_width != 0 && state.min_height != 0 + && (state.min_width == state.max_width + || state.min_height == state.max_height)) + || toplevel->parent; } static inline int From 2bc01debdcf2c6cf13583c6a67f8a6a824446408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 13:28:44 -0600 Subject: [PATCH 085/329] remove a useless resize in mapnotify() applyrules() calls setmon() which calls resize() --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 74f8549..0b82e42 100644 --- a/dwl.c +++ b/dwl.c @@ -1359,7 +1359,6 @@ mapnotify(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus */ applyrules(c); - resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0); printstatus(); if (c->isfullscreen) From ee1a72211d066de3766980d0452945df0a50334c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 21:17:58 -0600 Subject: [PATCH 086/329] only skip frames if there are visible clients that have a resize --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 0b82e42..cd9e8d5 100644 --- a/dwl.c +++ b/dwl.c @@ -1624,9 +1624,11 @@ rendermon(struct wl_listener *listener, void *data) int skip = 0; struct timespec now; - /* Render if no XDG clients have an outstanding resize. */ + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. + */ wl_list_for_each(c, &clients, link) - skip = skip || c->resize; + skip = skip || (c->resize && VISIBLEON(c, m)); if (!skip && !wlr_scene_output_commit(m->scene_output)) return; From 86fe15f76c752cb848da580af8f7d897f932cae6 Mon Sep 17 00:00:00 2001 From: Sevz Date: Mon, 21 Mar 2022 22:34:30 -0600 Subject: [PATCH 087/329] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 9b9eef4..64e2054 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,4 +7,16 @@ assignees: '' --- +## Info +dwl's commit: +wlroots version: +## Description + From 330792b1fc37db86743d7c186577776e05295e00 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Mon, 21 Mar 2022 23:03:52 +0100 Subject: [PATCH 088/329] implement drag and drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For brevity, only a single drag icon at a time is supported. Co-authored-by: Leonardo Hernández Hernández --- dwl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dwl.c b/dwl.c index cd9e8d5..22287fb 100644 --- a/dwl.c +++ b/dwl.c @@ -227,6 +227,7 @@ static void cursorframe(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); +static void dragicondestroy(struct wl_listener *listener, void *data); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -254,6 +255,7 @@ static void printstatus(void); static void quit(const Arg *arg); static void quitsignal(int signo); static void rendermon(struct wl_listener *listener, void *data); +static void requeststartdrag(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); static Client *selclient(void); @@ -268,6 +270,7 @@ static void setmon(Client *c, Monitor *m, unsigned int newtags); static void setup(void); static void sigchld(int unused); static void spawn(const Arg *arg); +static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); @@ -340,6 +343,9 @@ static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; 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}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -1023,6 +1029,16 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } +void +dragicondestroy(struct wl_listener *listener, void *data) +{ + struct wlr_drag_icon *icon = data; + wlr_scene_node_destroy(icon->data); + // Focus enter isn't sent during drag, so refocus the focused node. + focusclient(selclient(), 1); + motionnotify(0); +} + void togglefullscreen(const Arg *arg) { @@ -1400,11 +1416,16 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); + + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1665,6 +1686,18 @@ resize(Client *c, int x, int y, int w, int h, int interact) c->geom.height - 2 * c->bw); } +void +requeststartdrag(struct wl_listener *listener, void *data) +{ + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, + event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); +} + void run(char *startup_cmd) { @@ -1976,6 +2009,8 @@ setup(void) wl_signal_add(&seat->events.request_set_cursor, &request_cursor); wl_signal_add(&seat->events.request_set_selection, &request_set_sel); wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); + wl_signal_add(&seat->events.request_start_drag, &request_start_drag); + wl_signal_add(&seat->events.start_drag, &start_drag); output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); @@ -2026,6 +2061,19 @@ spawn(const Arg *arg) } } +void +startdrag(struct wl_listener *listener, void *data) +{ + struct wlr_drag *drag = data; + + if (!drag->icon) + return; + + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); + wlr_scene_node_raise_to_top(drag->icon->data); + wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); +} + void tag(const Arg *arg) { From 9aec6049ecbefe3618f34002d2239cc9462c07e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Mar 2022 15:02:02 -0600 Subject: [PATCH 089/329] clients now works as expected in drag motion --- dwl.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 22287fb..f8d01f2 100644 --- a/dwl.c +++ b/dwl.c @@ -1416,16 +1416,11 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1564,6 +1559,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; int internal_call = !time; + struct wlr_drag_icon *icon; if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -1585,6 +1581,13 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); + /* If there are is a drag icon, update its position */ + /* For anyone who wants to change this function: for some reason + * (maybe a wlroots bug?, or is it intended?) if we change the node position + * before telling the seat for a motion, the clients don't recognize the drag */ + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } void From d8f430accfb66c2575de608bb1b4c71815e4379a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Mar 2022 23:29:01 -0600 Subject: [PATCH 090/329] add sway LICENSE file part of the code in dwl is taken from sway, so credit it. dwm and sway are both licensed under the MIT license --- LICENSE | 2 +- LICENSE.sway | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 LICENSE.sway diff --git a/LICENSE b/LICENSE index e4bb015..658085a 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ dwl - dwm for Wayland Copyright © 2020 dwl team -See also the files LICENSE.tinywl and LICENSE.dwm. +See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/LICENSE.sway b/LICENSE.sway new file mode 100644 index 0000000..3e0cacc --- /dev/null +++ b/LICENSE.sway @@ -0,0 +1,19 @@ +Copyright (c) 2016-2017 Drew DeVault + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 326eee14445f8a2c08e80c30778445630c75d3bb Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Mon, 12 Jul 2021 23:44:16 +0200 Subject: [PATCH 091/329] Add a configuration option for fullscreen locking Some people are annoyed to have this new behaviour forced for some application which use fake fullscreen. --- config.def.h | 1 + dwl.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 8408659..539dba6 100644 --- a/config.def.h +++ b/config.def.h @@ -1,6 +1,7 @@ /* appearance */ static const int sloppyfocus = 1; /* focus follows mouse */ static const unsigned int borderpx = 1; /* border pixel of windows */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; diff --git a/dwl.c b/dwl.c index f8d01f2..9ea44e2 100644 --- a/dwl.c +++ b/dwl.c @@ -1177,7 +1177,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = selclient(); - if (!sel) + if (!sel || (sel->isfullscreen && lockfullscreen)) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { From 0662bc5a69cac39b92644c60534b5490d139e2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 09:01:01 -0600 Subject: [PATCH 092/329] wlr_seat_set_keyboard() now takes wlr_keyboard as parameter --- dwl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index d9f2ae1..bac2e8c 100644 --- a/dwl.c +++ b/dwl.c @@ -129,7 +129,7 @@ typedef struct { typedef struct { struct wl_list link; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener modifiers; struct wl_listener key; @@ -643,7 +643,7 @@ createkeyboard(struct wlr_input_device *device) Keyboard *kb = device->data = calloc(1, sizeof(*kb)); if (!kb) EBARF("createkeyboard: calloc"); - kb->device = device; + kb->wlr_keyboard = device->keyboard; /* Prepare an XKB keymap and assign it to the keyboard. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -660,7 +660,7 @@ createkeyboard(struct wlr_input_device *device) LISTEN(&device->keyboard->events.key, &kb->key, keypress); LISTEN(&device->events.destroy, &kb->destroy, cleanupkeyboard); - wlr_seat_set_keyboard(seat, device); + wlr_seat_set_keyboard(seat, device->keyboard); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -1135,10 +1135,10 @@ keypress(struct wl_listener *listener, void *data) /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms( - kb->device->keyboard->xkb_state, keycode, &syms); + kb->wlr_keyboard->xkb_state, keycode, &syms); int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); + uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); wlr_idle_notify_activity(idle, seat); @@ -1149,7 +1149,7 @@ keypress(struct wl_listener *listener, void *data) if (!handled) { /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); } @@ -1167,10 +1167,10 @@ keypressmod(struct wl_listener *listener, void *data) * same seat. You can swap out the underlying wlr_keyboard like this and * wlr_seat handles this transparently. */ - wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, - &kb->device->keyboard->modifiers); + &kb->wlr_keyboard->modifiers); } void From 7d724dc7f34561e7a6d4ab97ff24b07805593f63 Mon Sep 17 00:00:00 2001 From: Palanix Date: Mon, 28 Feb 2022 23:46:24 +0100 Subject: [PATCH 093/329] Fix dwl freezing when resizing --- dwl.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 9ea44e2..3185062 100644 --- a/dwl.c +++ b/dwl.c @@ -178,6 +178,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + int un_map; /* If a map/unmap happened on this monitor, then this should be true */ }; typedef struct { @@ -1379,6 +1380,8 @@ mapnotify(struct wl_listener *listener, void *data) if (c->isfullscreen) setfullscreen(c, 1); + + c->mon->un_map = 1; } void @@ -1648,17 +1651,27 @@ rendermon(struct wl_listener *listener, void *data) int skip = 0; struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + /* Render if no XDG clients have an outstanding resize and are visible on - * this monitor. - */ - wl_list_for_each(c, &clients, link) - skip = skip || (c->resize && VISIBLEON(c, m)); + * this monitor. */ + /* Checking m->un_map for every client is not optimal but works */ + wl_list_for_each(c, &clients, link) { + if ((c->resize && m->un_map) || (c->type == XDGShell + && (c->surface.xdg->pending.geometry.width != + c->surface.xdg->current.geometry.width + || c->surface.xdg->pending.geometry.height != + c->surface.xdg->current.geometry.height))) { + /* Lie */ + wlr_surface_send_frame_done(client_surface(c), &now); + skip = 1; + } + } if (!skip && !wlr_scene_output_commit(m->scene_output)) return; - /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(m->scene_output, &now); + m->un_map = 0; } void @@ -2196,6 +2209,9 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } + if (c->mon) + c->mon->un_map = 1; + if (client_is_unmanaged(c)) { wlr_scene_node_destroy(c->scene); return; From 4ef89996242c3b31a9957666f9f5b8cf7ef5cce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 14:03:07 -0600 Subject: [PATCH 094/329] add note about how to change MODKEY for windows key --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index 539dba6..9bdf8b5 100644 --- a/config.def.h +++ b/config.def.h @@ -52,6 +52,7 @@ static const int repeat_delay = 600; static const int tap_to_click = 1; static const int natural_scrolling = 0; +/* If you want to use the windows key change this to WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT #define TAGKEYS(KEY,SKEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ From 3bace9ce6b9d5fa7c8871a414ed97976e44ecb9c Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 23 Mar 2022 22:01:04 +0100 Subject: [PATCH 095/329] inline the presentation variable This variable can be removed since with scene-graph wlr_presentation_surface_sampled_on_output no longer needs to be called. --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 3185062..65d1381 100644 --- a/dwl.c +++ b/dwl.c @@ -309,7 +309,6 @@ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; -static struct wlr_presentation *presentation; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; @@ -2032,8 +2031,7 @@ setup(void) wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); - presentation = wlr_presentation_create(dpy, backend); - wlr_scene_set_presentation(scene, presentation); + wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); #ifdef XWAYLAND /* From 7a2e0eef746950f6ac0863dcbb5c957836a6d8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 12:13:49 -0600 Subject: [PATCH 096/329] Revert "clients now works as expected in drag motion" This reverts commit 9aec6049ecbefe3618f34002d2239cc9462c07e9. this problem is caused because xytonode() returns the surface of the drag icon --- dwl.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 65d1381..ce53dfa 100644 --- a/dwl.c +++ b/dwl.c @@ -1418,11 +1418,16 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); + + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1561,7 +1566,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; int internal_call = !time; - struct wlr_drag_icon *icon; if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -1583,13 +1587,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); - /* If there are is a drag icon, update its position */ - /* For anyone who wants to change this function: for some reason - * (maybe a wlroots bug?, or is it intended?) if we change the node position - * before telling the seat for a motion, the clients don't recognize the drag */ - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } void From bf8cc526deab39e269da219667ae24b6f8adecc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 14:18:38 -0600 Subject: [PATCH 097/329] set position of the drag icon in startdrag() --- dwl.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index ce53dfa..536b4d6 100644 --- a/dwl.c +++ b/dwl.c @@ -1415,21 +1415,20 @@ motionnotify(uint32_t time) double sx = 0, sy = 0; Client *c = NULL; struct wlr_surface *surface = NULL; + struct wlr_drag_icon *icon; /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ @@ -2081,7 +2080,7 @@ startdrag(struct wl_listener *listener, void *data) return; drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); - wlr_scene_node_raise_to_top(drag->icon->data); + motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From feb972acd0ea130bc3af0f0f7072a70fa3c786bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 13:50:08 -0600 Subject: [PATCH 098/329] fix drag icon's surface returned by xytonode --- dwl.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index 536b4d6..f8c2264 100644 --- a/dwl.c +++ b/dwl.c @@ -67,7 +67,7 @@ /* enums */ enum { CurNormal, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -1911,6 +1911,7 @@ setup(void) layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrNoFocus] = &wlr_scene_tree_create(&scene->node)->node; /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2079,7 +2080,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrNoFocus], drag->icon->surface); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } @@ -2308,17 +2309,23 @@ xytonode(double x, double y, struct wlr_surface **psurface, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; + int i; + int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; - if ((node = wlr_scene_node_at(&scene->node, x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_SURFACE) - surface = wlr_scene_surface_from_node(node)->surface; - /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = pnode->parent) - c = pnode->data; - if (c && c->type == LayerShell) { - c = NULL; - l = pnode->data; + for (i = 0; i < LENGTH(focus_order); i++) { + if ((node = wlr_scene_node_at(layers[focus_order[i]], x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_SURFACE) + surface = wlr_scene_surface_from_node(node)->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = pnode->parent) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } } + if (surface) + break; } if (psurface) *psurface = surface; From 4276410a3d575aad3f90ff81406382824389db28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 13:52:33 -0600 Subject: [PATCH 099/329] improve floating detection mostly copied from sway --- client.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/client.h b/client.h index e4a87e1..db043d2 100644 --- a/client.h +++ b/client.h @@ -91,16 +91,37 @@ client_get_title(Client *c) static inline int client_is_float_type(Client *c) { + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; + #ifdef XWAYLAND - if (client_is_x11(c)) - for (size_t i = 0; i < c->surface.xwayland->window_type_len; i++) - if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility]) + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + struct wlr_xwayland_surface_size_hints *size_hints; + if (surface->modal) + return 1; + + for (size_t i = 0; i < surface->window_type_len; i++) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] || + surface->window_type[i] == netatom[NetWMWindowTypeSplash] || + surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || + surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; + + size_hints = surface->size_hints; + if (size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 + && (size_hints->max_width == size_hints->min_width || + size_hints->max_height == size_hints->min_height)) + return 1; + } #endif - return 0; + + toplevel = c->surface.xdg->toplevel; + state = toplevel->current; + return (state.min_width != 0 && state.min_height != 0 + && (state.min_width == state.max_width + || state.min_height == state.max_height)) + || toplevel->parent; } static inline int From 40db9c88eaa4c32832c0bf7f7da56b8b73598519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 13:28:44 -0600 Subject: [PATCH 100/329] remove a useless resize in mapnotify() applyrules() calls setmon() which calls resize() --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index bac2e8c..c6b8ab9 100644 --- a/dwl.c +++ b/dwl.c @@ -1232,7 +1232,6 @@ mapnotify(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus */ applyrules(c); - resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0); printstatus(); if (c->isfullscreen) From a7f77779078328e40eff41d3ee8102ebc6d41af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 21:17:58 -0600 Subject: [PATCH 101/329] only skip frames if there are visible clients that have a resize --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index c6b8ab9..222cb62 100644 --- a/dwl.c +++ b/dwl.c @@ -1497,9 +1497,11 @@ rendermon(struct wl_listener *listener, void *data) int skip = 0; struct timespec now; - /* Render if no XDG clients have an outstanding resize. */ + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. + */ wl_list_for_each(c, &clients, link) - skip = skip || c->resize; + skip = skip || (c->resize && VISIBLEON(c, m)); if (!skip && !wlr_scene_output_commit(m->scene_output)) return; From 23af627d80d3bf42ae5d0731a79b4634ace86f9f Mon Sep 17 00:00:00 2001 From: Sevz Date: Mon, 21 Mar 2022 22:34:30 -0600 Subject: [PATCH 102/329] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 9b9eef4..64e2054 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,4 +7,16 @@ assignees: '' --- +## Info +dwl's commit: +wlroots version: +## Description + From f2be10fd43a38e0a727f679aae26737470a15a77 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Mon, 21 Mar 2022 23:03:52 +0100 Subject: [PATCH 103/329] implement drag and drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For brevity, only a single drag icon at a time is supported. Co-authored-by: Leonardo Hernández Hernández --- dwl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dwl.c b/dwl.c index 222cb62..18c2d60 100644 --- a/dwl.c +++ b/dwl.c @@ -216,6 +216,7 @@ static void cursorframe(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); +static void dragicondestroy(struct wl_listener *listener, void *data); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -243,6 +244,7 @@ static void printstatus(void); static void quit(const Arg *arg); static void quitsignal(int signo); static void rendermon(struct wl_listener *listener, void *data); +static void requeststartdrag(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); static Client *selclient(void); @@ -257,6 +259,7 @@ static void setmon(Client *c, Monitor *m, unsigned int newtags); static void setup(void); static void sigchld(int unused); static void spawn(const Arg *arg); +static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); @@ -329,6 +332,9 @@ static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; 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}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -896,6 +902,16 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } +void +dragicondestroy(struct wl_listener *listener, void *data) +{ + struct wlr_drag_icon *icon = data; + wlr_scene_node_destroy(icon->data); + // Focus enter isn't sent during drag, so refocus the focused node. + focusclient(selclient(), 1); + motionnotify(0); +} + void togglefullscreen(const Arg *arg) { @@ -1273,11 +1289,16 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); + + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1538,6 +1559,18 @@ resize(Client *c, int x, int y, int w, int h, int interact) c->geom.height - 2 * c->bw); } +void +requeststartdrag(struct wl_listener *listener, void *data) +{ + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, + event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); +} + void run(char *startup_cmd) { @@ -1850,6 +1883,8 @@ setup(void) wl_signal_add(&seat->events.request_set_cursor, &request_cursor); wl_signal_add(&seat->events.request_set_selection, &request_set_sel); wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); + wl_signal_add(&seat->events.request_start_drag, &request_start_drag); + wl_signal_add(&seat->events.start_drag, &start_drag); output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); @@ -1900,6 +1935,19 @@ spawn(const Arg *arg) } } +void +startdrag(struct wl_listener *listener, void *data) +{ + struct wlr_drag *drag = data; + + if (!drag->icon) + return; + + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); + wlr_scene_node_raise_to_top(drag->icon->data); + wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); +} + void tag(const Arg *arg) { From d8ab893dab76c5f2921c30bde04fa141fb788b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Mar 2022 15:02:02 -0600 Subject: [PATCH 104/329] clients now works as expected in drag motion --- dwl.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 18c2d60..0f742e4 100644 --- a/dwl.c +++ b/dwl.c @@ -1289,16 +1289,11 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1437,6 +1432,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; int internal_call = !time; + struct wlr_drag_icon *icon; if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -1458,6 +1454,13 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); + /* If there are is a drag icon, update its position */ + /* For anyone who wants to change this function: for some reason + * (maybe a wlroots bug?, or is it intended?) if we change the node position + * before telling the seat for a motion, the clients don't recognize the drag */ + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } void From 0db6f3c5b5f971bebfbbf8ec9bf94134f5506600 Mon Sep 17 00:00:00 2001 From: Humm Date: Wed, 5 Jan 2022 01:54:02 +0100 Subject: [PATCH 105/329] add dwl(1) Documentation is good. Man pages are documentation. A program without a man page is worthless. --- Makefile | 5 +- config.mk | 1 + dwl.1 | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 dwl.1 diff --git a/Makefile b/Makefile index 5ff69e9..536454f 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,11 @@ clean: rm -f dwl *.o *-protocol.h *-protocol.c install: dwl - install -D dwl $(PREFIX)/bin/dwl + install -Dm755 dwl $(PREFIX)/bin/dwl + install -Dm644 dwl.1 $(MANDIR)/man1/dwl.1 uninstall: - rm -f $(PREFIX)/bin/dwl + rm -f $(PREFIX)/bin/dwl $(MANDIR)/man1/dwl.1 .PHONY: all clean install uninstall diff --git a/config.mk b/config.mk index d1b161e..960fc8a 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,6 @@ # paths PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man # Default compile flags (overridable by environment) CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement diff --git a/dwl.1 b/dwl.1 new file mode 100644 index 0000000..eea0f70 --- /dev/null +++ b/dwl.1 @@ -0,0 +1,144 @@ +.Dd January 8, 2021 +.Dt DWL 1 +.Os +.Sh NAME +.Nm dwl +.Nd dwm for Wayland +.Sh SYNOPSIS +.Nm +.Op Fl s Ar command +.Sh DESCRIPTION +.Nm +is a Wayland compositor based on wlroots. +It is intended to fill the same space in the Wayland world that +.Nm dwm +does for X11. +.Pp +When given the +.Fl s +option, +.Nm +starts a shell process running +.Ar command +when starting. +When stopping, it sends +.Dv SIGTERM +to the child process and waits for it to exit. +.Pp +Users are encouraged to customize +.Nm +by editing the sources, in particular +.Pa config.h . +The default key bindings are as follows: +.Bl -tag -width 20n -offset indent -compact +.It Mod-[1-9] +Show only all windows with a tag. +.It Mod-Ctrl-[1-9] +Show all windows with a tag. +.It Mod-Shift-[1-9] +Move window to a single tag. +.It Mod-Ctrl-Shift-[1-9] +Toggle tag for window. +.It Mod-p +Spawn +.Nm bemenu-run . +.It Mod-Shift-Return +Spawn +.Nm alacritty . +.It Mod-[jk] +Move focus down/up the stack. +.It Mod-[id] +Increase/decrease number of windows in master area. +.It Mod-[hl] +Decrease/increase master area. +.It Mod-Return +Move window on top of stack or switch top of stack with second window. +.It Mod-Tab +Show only all windows with previous tag. +.It Mod-Shift-c +Close window. +.It Mod-t +Switch to tabbed layout. +.It Mod-f +Switch to floating layout. +.It Mod-m +Switch to monocle layout. +.It Mod-Space +Switch to previous layout. +.It Mod-Shift-Space +Toggle floating state of window. +.It Mod-e +Toggle fullscreen state of window. +.It Mod-0 +Show all windows. +.It Mod-Shift-0 +Set all tags for window. +.It Mod-, +Move focus to previous monitor. +.It Mod-. +Move focus to next monitor. +.It Mod-Shift-, +Move window to previous monitor. +.It Mod-Shift-. +Move window to next monitor. +.It Mod-Shift-q +Quit +.Nm . +.El +These might differ depending on your keyboard layout. +.Sh ENVIRONMENT +These environment variables are used by +.Nm : +.Bl -tag -width XDG_RUNTIME_DIR +.It Ev XDG_RUNTIME_DIR +A directory where temporary user files, such as the Wayland socket, +are stored. +.It Ev XDG_CONFIG_DIR +A directory containung configuration of various programs and +libraries, including libxkbcommon. +.It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET +Tell how to connect to an underlying X11 or Wayland server. +.It Ev WLR_* +Various variables specific to wlroots. +.It Ev XKB_* , XLOCALEDIR , XCOMPOSEFILE +Various variables specific to libxkbcommon. +.It Ev XCURSOR_PATH +List of directories to search for XCursor themes in. +.It Ev HOME +A directory where there are always dear files there for you. +Waiting for you to clean them up. +.El +.Pp +These are set by +.Nm : +.Bl -tag -width WAYLAND_DISPLAY +.It Ev WAYLAND_DISPLAY +Tell how to connect to +.Nm . +.It Ev DISPLAY +If using +.Nm Xwayland , +tell how to connect to the +.Nm Xwayland +server. +.El +.Sh EXAMPLES +Start +.Nm +with s6 in the background: +.Dl dwl -s 's6-svscan <&-' +.Sh SEE ALSO +.Xr alacritty 1 , +.Xr bemenu 1 , +.Xr dwm 1 , +.Xr xkeyboard-config 7 +.Sh CAVEATS +The child process's standard input is connected with a pipe to +.Nm . +If the child process neither reads from the pipe nor closes its +standard input, +.Nm +will freeze after a while due to it blocking when writing to the full +pipe buffer. +.Sh BUGS +All of them. From 1a5b7e068b1bf0c02be2ae8b13aa1c85972226ab Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 3 Aug 2021 06:29:26 +0200 Subject: [PATCH 106/329] update IRC channel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d094599..13a0000 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ You can find a [list of Wayland applications on the sway wiki](https://github.co ## IRC channel -dwl's IRC channel is #dwl on irc.freenode.net. +dwl's IRC channel is #dwl on irc.libera.chat. ## Acknowledgements From 5a1debb5f0fec4f149f8a4490828116e3b1f3b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Mar 2022 23:29:01 -0600 Subject: [PATCH 107/329] add sway LICENSE file part of the code in dwl is taken from sway, so credit it. dwm and sway are both licensed under the MIT license --- LICENSE | 2 +- LICENSE.sway | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 LICENSE.sway diff --git a/LICENSE b/LICENSE index e4bb015..658085a 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ dwl - dwm for Wayland Copyright © 2020 dwl team -See also the files LICENSE.tinywl and LICENSE.dwm. +See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/LICENSE.sway b/LICENSE.sway new file mode 100644 index 0000000..3e0cacc --- /dev/null +++ b/LICENSE.sway @@ -0,0 +1,19 @@ +Copyright (c) 2016-2017 Drew DeVault + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From b42abeac69b08558c06611a725a997f4ad0affd8 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Mon, 12 Jul 2021 23:44:16 +0200 Subject: [PATCH 108/329] Add a configuration option for fullscreen locking Some people are annoyed to have this new behaviour forced for some application which use fake fullscreen. --- config.def.h | 1 + dwl.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 8408659..539dba6 100644 --- a/config.def.h +++ b/config.def.h @@ -1,6 +1,7 @@ /* appearance */ static const int sloppyfocus = 1; /* focus follows mouse */ static const unsigned int borderpx = 1; /* border pixel of windows */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; diff --git a/dwl.c b/dwl.c index 0f742e4..cf6889e 100644 --- a/dwl.c +++ b/dwl.c @@ -1050,7 +1050,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = selclient(); - if (!sel) + if (!sel || (sel->isfullscreen && lockfullscreen)) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { From a41d6cb00fb4729b690ffd962cc814f42fe3f28f Mon Sep 17 00:00:00 2001 From: Palanix Date: Mon, 28 Feb 2022 23:46:24 +0100 Subject: [PATCH 109/329] Fix dwl freezing when resizing --- dwl.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index cf6889e..a198177 100644 --- a/dwl.c +++ b/dwl.c @@ -170,6 +170,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + int un_map; /* If a map/unmap happened on this monitor, then this should be true */ }; typedef struct { @@ -1252,6 +1253,8 @@ mapnotify(struct wl_listener *listener, void *data) if (c->isfullscreen) setfullscreen(c, 1); + + c->mon->un_map = 1; } void @@ -1521,17 +1524,27 @@ rendermon(struct wl_listener *listener, void *data) int skip = 0; struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + /* Render if no XDG clients have an outstanding resize and are visible on - * this monitor. - */ - wl_list_for_each(c, &clients, link) - skip = skip || (c->resize && VISIBLEON(c, m)); + * this monitor. */ + /* Checking m->un_map for every client is not optimal but works */ + wl_list_for_each(c, &clients, link) { + if ((c->resize && m->un_map) || (c->type == XDGShell + && (c->surface.xdg->pending.geometry.width != + c->surface.xdg->current.geometry.width + || c->surface.xdg->pending.geometry.height != + c->surface.xdg->current.geometry.height))) { + /* Lie */ + wlr_surface_send_frame_done(client_surface(c), &now); + skip = 1; + } + } if (!skip && !wlr_scene_output_commit(m->scene_output)) return; - /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(m->scene_output, &now); + m->un_map = 0; } void @@ -2070,6 +2083,9 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } + if (c->mon) + c->mon->un_map = 1; + if (client_is_unmanaged(c)) { wlr_scene_node_destroy(c->scene); return; From 855e6c189806b195e7f2f851c37dd4a21d3e5366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 14:03:07 -0600 Subject: [PATCH 110/329] add note about how to change MODKEY for windows key --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index 539dba6..9bdf8b5 100644 --- a/config.def.h +++ b/config.def.h @@ -52,6 +52,7 @@ static const int repeat_delay = 600; static const int tap_to_click = 1; static const int natural_scrolling = 0; +/* If you want to use the windows key change this to WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT #define TAGKEYS(KEY,SKEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ From 281c947e5f19b5c304baa51de9d90e69c80a5a9a Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 23 Mar 2022 22:01:04 +0100 Subject: [PATCH 111/329] inline the presentation variable This variable can be removed since with scene-graph wlr_presentation_surface_sampled_on_output no longer needs to be called. --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index a198177..2d58079 100644 --- a/dwl.c +++ b/dwl.c @@ -298,7 +298,6 @@ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; -static struct wlr_presentation *presentation; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; @@ -1906,8 +1905,7 @@ setup(void) wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); - presentation = wlr_presentation_create(dpy, backend); - wlr_scene_set_presentation(scene, presentation); + wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); #ifdef XWAYLAND /* From f353a0e759037e13419ddab6747afd6b6c736cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 12:13:49 -0600 Subject: [PATCH 112/329] Revert "clients now works as expected in drag motion" This reverts commit 9aec6049ecbefe3618f34002d2239cc9462c07e9. this problem is caused because xytonode() returns the surface of the drag icon --- dwl.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 2d58079..71996e7 100644 --- a/dwl.c +++ b/dwl.c @@ -1291,11 +1291,16 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); + + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1434,7 +1439,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; int internal_call = !time; - struct wlr_drag_icon *icon; if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -1456,13 +1460,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); - /* If there are is a drag icon, update its position */ - /* For anyone who wants to change this function: for some reason - * (maybe a wlroots bug?, or is it intended?) if we change the node position - * before telling the seat for a motion, the clients don't recognize the drag */ - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } void From c2899bc00b03c8a4a6d11c2b9a00a4114949f427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 14:18:38 -0600 Subject: [PATCH 113/329] set position of the drag icon in startdrag() --- dwl.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 71996e7..9f72768 100644 --- a/dwl.c +++ b/dwl.c @@ -1288,21 +1288,20 @@ motionnotify(uint32_t time) double sx = 0, sy = 0; Client *c = NULL; struct wlr_surface *surface = NULL; + struct wlr_drag_icon *icon; /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ @@ -1955,7 +1954,7 @@ startdrag(struct wl_listener *listener, void *data) return; drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); - wlr_scene_node_raise_to_top(drag->icon->data); + motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From 3e79a9a5d7a7d66effaca573798f4c5b77e99773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 13:50:08 -0600 Subject: [PATCH 114/329] fix drag icon's surface returned by xytonode --- dwl.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index 9f72768..3f3f447 100644 --- a/dwl.c +++ b/dwl.c @@ -68,7 +68,7 @@ /* enums */ enum { CurNormal, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -1784,6 +1784,7 @@ setup(void) layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrNoFocus] = &wlr_scene_tree_create(&scene->node)->node; /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -1953,7 +1954,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrNoFocus], drag->icon->surface); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } @@ -2183,17 +2184,23 @@ xytonode(double x, double y, struct wlr_surface **psurface, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; + int i; + int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; - if ((node = wlr_scene_node_at(&scene->node, x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_SURFACE) - surface = wlr_scene_surface_from_node(node)->surface; - /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = pnode->parent) - c = pnode->data; - if (c && c->type == LayerShell) { - c = NULL; - l = pnode->data; + for (i = 0; i < LENGTH(focus_order); i++) { + if ((node = wlr_scene_node_at(layers[focus_order[i]], x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_SURFACE) + surface = wlr_scene_surface_from_node(node)->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = pnode->parent) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } } + if (surface) + break; } if (psurface) *psurface = surface; From faaee90cbd42d991f6e96e516035df2a1bab8361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 20 Mar 2022 19:09:28 -0600 Subject: [PATCH 115/329] destroy scene_output in cleanupmon() --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 3f3f447..86f8c34 100644 --- a/dwl.c +++ b/dwl.c @@ -582,6 +582,7 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->frame.link); wl_list_remove(&m->link); wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); if ((nmons = wl_list_length(&mons))) do /* don't switch to disabled mons */ From ae614ee5125891a4d75fac97c754207f97834a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 12 Jul 2021 19:58:55 -0500 Subject: [PATCH 116/329] implement idle-inhibitor protocol This allows clients to disable idle monitoring --- README.md | 2 +- dwl.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 13a0000..22172d5 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s - Any features provided by dwm/Xlib: simple window borders, tags, keybindings, client rules, mouse move/resize. Providing a built-in status bar is an exception to this goal, to avoid dependencies on font rendering and/or drawing libraries when an external bar could work well. - Configurable multi-monitor layout support, including position and rotation - Configurable HiDPI/multi-DPI support +- Idle-inhibit protocol which lets applications such as mpv disable idle monitoring - Provide information to external status bars via stdout/stdin - Urgency hints via xdg-activate protocol - Various Wayland protocols @@ -26,7 +27,6 @@ Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots - Implement the input-inhibitor protocol to support screen lockers (see https://github.com/djpohly/dwl/pull/132) -- Implement the idle-inhibit protocol which lets applications such as mpv disable idle monitoring (see https://github.com/djpohly/dwl/pull/133) - Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/12) Feature *non-goals* for the main codebase include: diff --git a/dwl.c b/dwl.c index f8c2264..01d165b 100644 --- a/dwl.c +++ b/dwl.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -219,12 +220,14 @@ static void cleanupmon(struct wl_listener *listener, void *data); static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); +static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_input_device *device); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); static void cursorframe(struct wl_listener *listener, void *data); +static void destroyidleinhibitor(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); @@ -307,6 +310,7 @@ static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; +static struct wlr_idle_inhibit_manager_v1 *idle_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; @@ -331,6 +335,8 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_frame = {.notify = cursorframe}; static struct wl_listener cursor_motion = {.notify = motionrelative}; static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; +static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; +static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor}; static struct wl_listener layout_change = {.notify = updatemons}; static struct wl_listener new_input = {.notify = inputdevice}; static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; @@ -769,6 +775,15 @@ commitnotify(struct wl_listener *listener, void *data) c->resize = 0; } +void +createidleinhibitor(struct wl_listener *listener, void *data) +{ + struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; + wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); + + wlr_idle_set_enabled(idle, seat, 0); +} + void createkeyboard(struct wlr_input_device *device) { @@ -988,6 +1003,14 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +destroyidleinhibitor(struct wl_listener *listener, void *data) +{ + /* I've been testing and at this point the inhibitor has not yet been + * removed from the list, checking if it has at least one item. */ + wlr_idle_set_enabled(idle, seat, wl_list_length(&idle_inhibit_mgr->inhibitors) <= 1); +} + void destroylayersurfacenotify(struct wl_listener *listener, void *data) { @@ -1147,6 +1170,7 @@ focusclient(Client *c, int lift) } printstatus(); + wlr_idle_set_enabled(idle, seat, wl_list_empty(&idle_inhibit_mgr->inhibitors)); if (!c) { /* With no client, all we have left is to clear focus */ @@ -1963,6 +1987,9 @@ setup(void) idle = wlr_idle_create(dpy); + idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); + wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); + layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); From a95338ca43c7b979ef81fb9d6b0c561beda93be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 3 Jul 2021 15:48:40 -0500 Subject: [PATCH 117/329] implement input-inhibitor protocol --- README.md | 2 +- dwl.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 22172d5..72488e3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s - Idle-inhibit protocol which lets applications such as mpv disable idle monitoring - Provide information to external status bars via stdout/stdin - Urgency hints via xdg-activate protocol +- Support screen lockers via input-inhibitor protocol - Various Wayland protocols - XWayland support as provided by wlroots (can be enabled in `config.mk`) - Zero flickering - Wayland users naturally expect that "every frame is perfect" @@ -26,7 +27,6 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Implement the input-inhibitor protocol to support screen lockers (see https://github.com/djpohly/dwl/pull/132) - Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/12) Feature *non-goals* for the main codebase include: diff --git a/dwl.c b/dwl.c index 01d165b..1bee09c 100644 --- a/dwl.c +++ b/dwl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -311,6 +312,7 @@ static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; +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; @@ -1309,8 +1311,10 @@ keypress(struct wl_listener *listener, void *data) wlr_idle_notify_activity(idle, seat); - /* On _press_, attempt to process a compositor keybinding. */ - if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + /* 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) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; @@ -1996,6 +2000,8 @@ setup(void) xdg_shell = wlr_xdg_shell_create(dpy); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); + /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(dpy), From cb4265ac8c48faeac385b038b59ac53a736d142d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 24 Mar 2022 14:19:08 -0600 Subject: [PATCH 118/329] check `m` in commitlayersurfacenotify() --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 1bee09c..529dbf8 100644 --- a/dwl.c +++ b/dwl.c @@ -755,9 +755,8 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) wlr_scene_node_reparent(layersurface->scene, layers[wlr_layer_surface->current.layer]); - if (!wlr_output) + if (!wlr_output || !(m = wlr_output->data)) return; - m = wlr_output->data; if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { wl_list_remove(&layersurface->link); From f75e4262229e26ea159742b96f6b63aef472ed8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 17:05:21 -0600 Subject: [PATCH 119/329] createkeyboard now takes wlr_keyboard --- dwl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dwl.c b/dwl.c index 86f8c34..99205c1 100644 --- a/dwl.c +++ b/dwl.c @@ -208,7 +208,7 @@ static void cleanupmon(struct wl_listener *listener, void *data); static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); -static void createkeyboard(struct wlr_input_device *device); +static void createkeyboard(struct wlr_keyboard *keyboard); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data); @@ -562,7 +562,7 @@ void cleanupkeyboard(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; - Keyboard *kb = device->data; + Keyboard *kb = device->keyboard->data; wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); @@ -643,31 +643,31 @@ commitnotify(struct wl_listener *listener, void *data) } void -createkeyboard(struct wlr_input_device *device) +createkeyboard(struct wlr_keyboard *keyboard) { struct xkb_context *context; struct xkb_keymap *keymap; - Keyboard *kb = device->data = calloc(1, sizeof(*kb)); + Keyboard *kb = keyboard->data = calloc(1, sizeof(*kb)); if (!kb) EBARF("createkeyboard: calloc"); - kb->wlr_keyboard = device->keyboard; + kb->wlr_keyboard = keyboard; /* Prepare an XKB keymap and assign it to the keyboard. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); keymap = xkb_keymap_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); /* Here we set up listeners for keyboard events. */ - LISTEN(&device->keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&device->keyboard->events.key, &kb->key, keypress); - LISTEN(&device->events.destroy, &kb->destroy, cleanupkeyboard); + LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); + LISTEN(&keyboard->events.key, &kb->key, keypress); + LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); - wlr_seat_set_keyboard(seat, device->keyboard); + wlr_seat_set_keyboard(seat, keyboard); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -1099,7 +1099,7 @@ inputdevice(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(device); + createkeyboard(device->keyboard); break; case WLR_INPUT_DEVICE_POINTER: createpointer(device); @@ -2174,7 +2174,7 @@ virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; struct wlr_input_device *device = &keyboard->keyboard.base; - createkeyboard(device); + createkeyboard(device->keyboard); } struct wlr_scene_node * From 7018ed9218b05e15d191adcae04167f9d6fc8bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 17:08:44 -0600 Subject: [PATCH 120/329] createpointer now takes wlr_pointer --- dwl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 99205c1..3f66be4 100644 --- a/dwl.c +++ b/dwl.c @@ -212,7 +212,7 @@ static void createkeyboard(struct wlr_keyboard *keyboard); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data); -static void createpointer(struct wlr_input_device *device); +static void createpointer(struct wlr_pointer *pointer); static void cursorframe(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); @@ -831,11 +831,11 @@ createlayersurface(struct wl_listener *listener, void *data) } void -createpointer(struct wlr_input_device *device) +createpointer(struct wlr_pointer *pointer) { - if (wlr_input_device_is_libinput(device)) { + if (wlr_input_device_is_libinput(&pointer->base)) { struct libinput_device *libinput_device = (struct libinput_device*) - wlr_libinput_get_device_handle(device); + wlr_libinput_get_device_handle(&pointer->base); if (tap_to_click && libinput_device_config_tap_get_finger_count(libinput_device)) libinput_device_config_tap_set_enabled(libinput_device, LIBINPUT_CONFIG_TAP_ENABLED); @@ -848,7 +848,7 @@ createpointer(struct wlr_input_device *device) * is proxied through wlr_cursor. On another compositor, you might take this * opportunity to do libinput configuration on the device to set * acceleration, etc. */ - wlr_cursor_attach_input_device(cursor, device); + wlr_cursor_attach_input_device(cursor, &pointer->base); } void @@ -1102,7 +1102,7 @@ inputdevice(struct wl_listener *listener, void *data) createkeyboard(device->keyboard); break; case WLR_INPUT_DEVICE_POINTER: - createpointer(device); + createpointer(device->pointer); break; default: /* TODO handle other input device types */ From aab397c30b9b9e4223a4f408431eb3aa5521cb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Mar 2022 15:52:26 -0600 Subject: [PATCH 121/329] new functions ecalloc() and die() die() replaces EBARF and BARF and allow us to add `-pedantic` to CFLAGS --- Makefile | 4 ++-- config.mk | 2 +- dwl.c | 46 ++++++++++++++++++---------------------------- util.c | 35 +++++++++++++++++++++++++++++++++++ util.h | 4 ++++ 5 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile index 536454f..bba8c9f 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,6 @@ idle-protocol.o: idle-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 util.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 util.o diff --git a/config.mk b/config.mk index 960fc8a..ab61185 100644 --- a/config.mk +++ b/config.mk @@ -3,7 +3,7 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man # Default compile flags (overridable by environment) -CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement +CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement -pedantic # Uncomment to build XWayland support #CFLAGS += -DXWAYLAND diff --git a/dwl.c b/dwl.c index 529dbf8..a3b33aa 100644 --- a/dwl.c +++ b/dwl.c @@ -54,9 +54,9 @@ #include #endif +#include "util.h" + /* macros */ -#define BARF(fmt, ...) do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } while (0) -#define EBARF(fmt, ...) BARF(fmt ": %s", ##__VA_ARGS__, strerror(errno)) #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) @@ -790,9 +790,7 @@ createkeyboard(struct wlr_input_device *device) { struct xkb_context *context; struct xkb_keymap *keymap; - Keyboard *kb = device->data = calloc(1, sizeof(*kb)); - if (!kb) - EBARF("createkeyboard: calloc"); + Keyboard *kb = device->data = ecalloc(1, sizeof(*kb)); kb->device = device; /* Prepare an XKB keymap and assign it to the keyboard. */ @@ -823,9 +821,7 @@ createmon(struct wl_listener *listener, void *data) * monitor) becomes available. */ struct wlr_output *wlr_output = data; const MonitorRule *r; - Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); - if (!m) - EBARF("createmon: calloc"); + Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; wlr_output_init_render(wlr_output, alloc, drw); @@ -910,9 +906,7 @@ createnotify(struct wl_listener *listener, void *data) return; /* Allocate a Client for this surface */ - c = xdg_surface->data = calloc(1, sizeof(*c)); - if (!c) - EBARF("createnotify: calloc"); + c = xdg_surface->data = ecalloc(1, sizeof(*c)); c->surface.xdg = xdg_surface; c->bw = borderpx; @@ -938,9 +932,7 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->output = selmon->wlr_output; } - layersurface = calloc(1, sizeof(LayerSurface)); - if (!layersurface) - EBARF("layersurface: calloc"); + layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, commitlayersurfacenotify); @@ -1744,7 +1736,7 @@ run(char *startup_cmd) /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); if (!socket) - BARF("startup: display_add_socket_auto"); + die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); /* Now that the socket exists, run the startup command */ @@ -1753,13 +1745,13 @@ run(char *startup_cmd) pipe(piperw); startup_pid = fork(); if (startup_pid < 0) - EBARF("startup: fork"); + die("startup: fork:"); if (startup_pid == 0) { dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); - EBARF("startup: execl"); + die("startup: execl:"); } dup2(piperw[1], STDOUT_FILENO); close(piperw[1]); @@ -1772,7 +1764,7 @@ run(char *startup_cmd) /* Start the backend. This will enumerate outputs and inputs, become the DRM * master, etc */ if (!wlr_backend_start(backend)) - BARF("startup: backend_start"); + die("startup: backend_start"); /* Now that outputs are initialized, choose initial selmon based on * cursor position, and set default cursor image */ @@ -1928,7 +1920,7 @@ setup(void) * if the backend does not support hardware cursors (some older GPUs * don't). */ if (!(backend = wlr_backend_autocreate(dpy))) - BARF("couldn't create backend"); + die("couldn't create backend"); /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); @@ -1942,12 +1934,12 @@ setup(void) /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) - BARF("couldn't create renderer"); + die("couldn't create renderer"); wlr_renderer_init_wl_display(drw, dpy); /* Create a default allocator */ if (!(alloc = wlr_allocator_autocreate(backend, drw))) - BARF("couldn't create allocator"); + die("couldn't create allocator"); /* This creates some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces and the data device manager @@ -2088,7 +2080,7 @@ sigchld(int unused) * setting our own disposition for SIGCHLD. */ if (signal(SIGCHLD, sigchld) == SIG_ERR) - EBARF("can't install SIGCHLD handler"); + die("can't install SIGCHLD handler:"); while (0 < waitpid(-1, NULL, WNOHANG)) ; } @@ -2100,7 +2092,7 @@ spawn(const Arg *arg) dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); - EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]); + die("dwl: execvp %s failed:", ((char **)arg->v)[0]); } } @@ -2435,9 +2427,7 @@ createnotifyx11(struct wl_listener *listener, void *data) setfullscreen(c, 0); /* Allocate a Client for this surface */ - c = xwayland_surface->data = calloc(1, sizeof(*c)); - if (!c) - EBARF("createnotifyx11: calloc"); + c = xwayland_surface->data = ecalloc(1, sizeof(*c)); c->surface.xwayland = xwayland_surface; c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; @@ -2517,12 +2507,12 @@ main(int argc, char *argv[]) /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ if (!getenv("XDG_RUNTIME_DIR")) - BARF("XDG_RUNTIME_DIR must be set"); + die("XDG_RUNTIME_DIR must be set"); setup(); run(startup_cmd); cleanup(); return EXIT_SUCCESS; usage: - BARF("Usage: %s [-s startup command]", argv[0]); + die("Usage: %s [-s startup command]", argv[0]); } diff --git a/util.c b/util.c new file mode 100644 index 0000000..932f89b --- /dev/null +++ b/util.c @@ -0,0 +1,35 @@ +/* See LICENSE.dwm file for copyright and license details. */ +#include +#include +#include +#include + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..4c94117 --- /dev/null +++ b/util.h @@ -0,0 +1,4 @@ +/* See LICENSE.dwm file for copyright and license details. */ + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); From e08bd1292288f662eb265461a8c1a9d7501b0445 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 29 Mar 2022 15:55:06 -0500 Subject: [PATCH 122/329] make sure to leave XWayland process waitable On SIGCHLD, check to make sure the terminated process is not the XWayland process before reaping it, allowing wlroots to waitpid() for it successfully. Fixes #177. --- dwl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3f66be4..a14dc5c 100644 --- a/dwl.c +++ b/dwl.c @@ -1925,6 +1925,7 @@ setup(void) void sigchld(int unused) { + siginfo_t in; /* We should be able to remove this function in favor of a simple * signal(SIGCHLD, SIG_IGN); * but the Xwayland implementation in wlroots currently prevents us from @@ -1932,8 +1933,12 @@ sigchld(int unused) */ if (signal(SIGCHLD, sigchld) == SIG_ERR) EBARF("can't install SIGCHLD handler"); - while (0 < waitpid(-1, NULL, WNOHANG)) - ; + /* WNOWAIT leaves the child in a waitable state, in case this is the + * XWayland process + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && in.si_pid != xwayland->server->pid) + waitpid(in.si_pid, NULL, 0); } void From 0ddde0c85a46370759e85f3437e3475b569d5c41 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 29 Mar 2022 16:09:29 -0500 Subject: [PATCH 123/329] move sigchld() into XWayland section --- dwl.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/dwl.c b/dwl.c index a14dc5c..ae5ed93 100644 --- a/dwl.c +++ b/dwl.c @@ -258,7 +258,6 @@ static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, unsigned int newtags); static void setup(void); -static void sigchld(int unused); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); @@ -341,6 +340,7 @@ static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); +static void sigchld(int unused); static void xwaylandready(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; @@ -1762,7 +1762,11 @@ setup(void) dpy = wl_display_create(); /* Set up signal handlers */ +#ifdef XWAYLAND sigchld(0); +#else + signal(SIGCHLD, SIG_IGN); +#endif signal(SIGINT, quitsignal); signal(SIGTERM, quitsignal); @@ -1922,25 +1926,6 @@ setup(void) #endif } -void -sigchld(int unused) -{ - siginfo_t in; - /* We should be able to remove this function in favor of a simple - * signal(SIGCHLD, SIG_IGN); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - if (signal(SIGCHLD, sigchld) == SIG_ERR) - EBARF("can't install SIGCHLD handler"); - /* WNOWAIT leaves the child in a waitable state, in case this is the - * XWayland process - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && in.si_pid != xwayland->server->pid) - waitpid(in.si_pid, NULL, 0); -} - void spawn(const Arg *arg) { @@ -2317,6 +2302,25 @@ getatom(xcb_connection_t *xc, const char *name) return atom; } +void +sigchld(int unused) +{ + siginfo_t in; + /* We should be able to remove this function in favor of a simple + * signal(SIGCHLD, SIG_IGN); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + EBARF("can't install SIGCHLD handler"); + /* WNOWAIT leaves the child in a waitable state, in case this is the + * XWayland process + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && in.si_pid != xwayland->server->pid) + waitpid(in.si_pid, NULL, 0); +} + void xwaylandready(struct wl_listener *listener, void *data) { From 2d6f932ecfc9580721cfa6a2f8dfa22d2af540c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 31 Mar 2022 09:21:27 -0600 Subject: [PATCH 124/329] don't let -pedantic be overridable by environment --- Makefile | 2 +- config.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bba8c9f..70c31d3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ include config.mk -CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 +CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -pedantic WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols) WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner) diff --git a/config.mk b/config.mk index ab61185..960fc8a 100644 --- a/config.mk +++ b/config.mk @@ -3,7 +3,7 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man # Default compile flags (overridable by environment) -CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement -pedantic +CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement # Uncomment to build XWayland support #CFLAGS += -DXWAYLAND From ae313911153b9c9ca8bef8ded97b95c0c2f49624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 31 Mar 2022 09:31:01 -0600 Subject: [PATCH 125/329] initialize rules and xkb_rules to fix compile errors with `-pedantic` --- config.def.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 9bdf8b5..00f6a85 100644 --- a/config.def.h +++ b/config.def.h @@ -13,8 +13,8 @@ static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ /* examples: { "Gimp", NULL, 0, 1, -1 }, - { "firefox", NULL, 1 << 8, 0, -1 }, */ + { "firefox", NULL, 1 << 8, 0, -1 }, }; /* layout(s) */ @@ -43,6 +43,7 @@ static const struct xkb_rule_names xkb_rules = { /* example: .options = "ctrl:nocaps", */ + .options = "", }; static const int repeat_rate = 25; From b424602ebc2dc26a3c974ee2a87ab745821491b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 31 Mar 2022 09:39:34 -0600 Subject: [PATCH 126/329] add DESTDIR --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 70c31d3..48a0aa7 100644 --- a/Makefile +++ b/Makefile @@ -15,11 +15,11 @@ clean: rm -f dwl *.o *-protocol.h *-protocol.c install: dwl - install -Dm755 dwl $(PREFIX)/bin/dwl - install -Dm644 dwl.1 $(MANDIR)/man1/dwl.1 + install -Dm755 dwl $(DESTDIR)$(PREFIX)/bin/dwl + install -Dm644 dwl.1 $(DESTDIR)$(MANDIR)/man1/dwl.1 uninstall: - rm -f $(PREFIX)/bin/dwl $(MANDIR)/man1/dwl.1 + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 .PHONY: all clean install uninstall From 79b7e755b010fc1486a89a46251a404cb97a341a Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Sat, 6 Nov 2021 19:51:17 +0100 Subject: [PATCH 127/329] Layer shell: Prevent infinte configure/commit loop Check the wlr_layer_surface_v1_state.committed bitmask to see if we need to rearrange. This is also what sway does. Without this check, every commit request (even if only the attached buffer changed) will lead to another configure event, which will lead to another commit, etc. This loop results in swaybg consuming 100% CPU. Co-authored-by: Owen Rafferty --- dwl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dwl.c b/dwl.c index a3b33aa..bc74c96 100644 --- a/dwl.c +++ b/dwl.c @@ -140,6 +140,7 @@ typedef struct { typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ + int mapped; struct wlr_scene_node *scene; struct wl_list link; struct wlr_layer_surface_v1 *layer_surface; @@ -758,6 +759,12 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (!wlr_output || !(m = wlr_output->data)) return; + if (wlr_layer_surface->current.committed == 0 + && layersurface->mapped == wlr_layer_surface->mapped) + return; + + layersurface->mapped = wlr_layer_surface->mapped; + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { wl_list_remove(&layersurface->link); wl_list_insert(&m->layers[wlr_layer_surface->current.layer], From 4d3adea68325b70eafbd56a31023f96b92532b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 31 Mar 2022 12:24:09 -0600 Subject: [PATCH 128/329] die on pipe failure --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index bc74c96..ac62120 100644 --- a/dwl.c +++ b/dwl.c @@ -1749,9 +1749,9 @@ run(char *startup_cmd) /* Now that the socket exists, run the startup command */ if (startup_cmd) { int piperw[2]; - pipe(piperw); - startup_pid = fork(); - if (startup_pid < 0) + if (pipe(piperw) < 0) + die("startup: pipe:"); + if ((startup_pid = fork()) < 0) die("startup: fork:"); if (startup_pid == 0) { dup2(piperw[0], STDIN_FILENO); From 720f56161e5401afc1526d1ebfb977b191ca10f5 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 3 Apr 2022 00:01:52 -0500 Subject: [PATCH 129/329] Remove vestigial monitor configuration info The x/y fields in monitor rules are unused and were meant to be deleted. Also removes the outdated comment in config.h. --- config.def.h | 4 +--- dwl.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/config.def.h b/config.def.h index 00f6a85..7e61695 100644 --- a/config.def.h +++ b/config.def.h @@ -25,9 +25,7 @@ static const Layout layouts[] = { { "[M]", monocle }, }; -/* monitors - * The order in which monitors are defined determines their position. - * Non-configured monitors are always added to the left. */ +/* monitors */ static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: diff --git a/dwl.c b/dwl.c index ac62120..24d015f 100644 --- a/dwl.c +++ b/dwl.c @@ -191,8 +191,6 @@ typedef struct { float scale; const Layout *lt; enum wl_output_transform rr; - int x; - int y; } MonitorRule; typedef struct { From 6901743b0c334079ddc185af4f6844c336631d84 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 3 Apr 2022 00:13:11 -0500 Subject: [PATCH 130/329] Remove removed fields from struct instances --- config.def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index 7e61695..7eb80b5 100644 --- a/config.def.h +++ b/config.def.h @@ -29,10 +29,10 @@ static const Layout layouts[] = { static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, 0, 0 }, + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, */ /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, 0, 0 }, + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, }; /* keyboard */ From 437aea866268779e9599c584d5c5ab25ae682840 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 3 Apr 2022 00:14:08 -0500 Subject: [PATCH 131/329] It's past my bedtime. --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 7eb80b5..190b0da 100644 --- a/config.def.h +++ b/config.def.h @@ -27,7 +27,7 @@ static const Layout layouts[] = { /* monitors */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect x y */ + /* name mfact nmaster scale layout rotate/reflect */ /* example of a HiDPI laptop monitor: { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, */ From 02ac9378c4fb40969db6e897605016bbaf422961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 5 Apr 2022 22:07:20 -0500 Subject: [PATCH 132/329] includes: abc --- dwl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 24d015f..816eaa5 100644 --- a/dwl.c +++ b/dwl.c @@ -3,6 +3,7 @@ */ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -10,9 +11,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -21,13 +22,12 @@ #include #include #include -#include -#include #include #include -#include +#include +#include #include -#include +#include #include #include #include @@ -35,10 +35,10 @@ #include #include #include -#include #include -#include +#include #include +#include #include #include #include @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #ifdef XWAYLAND From af741e586b80440b59b61e8fdc22c69fb7e8a457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 5 Apr 2022 22:15:46 -0500 Subject: [PATCH 133/329] typedefs: abc --- dwl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 816eaa5..424485f 100644 --- a/dwl.c +++ b/dwl.c @@ -120,6 +120,14 @@ typedef struct { int isfullscreen; } Client; +typedef struct { + uint32_t singular_anchor; + uint32_t anchor_triplet; + int *positive_axis; + int *negative_axis; + int margin; +} Edge; + typedef struct { uint32_t mod; xkb_keysym_t keysym; @@ -152,14 +160,6 @@ typedef struct { struct wlr_box geo; } LayerSurface; -typedef struct { - uint32_t singular_anchor; - uint32_t anchor_triplet; - int *positive_axis; - int *negative_axis; - int margin; -} Edge; - typedef struct { const char *symbol; void (*arrange)(Monitor *); From c00697e6438164e08baacc309b3dcdb727053aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 5 Apr 2022 23:04:04 -0500 Subject: [PATCH 134/329] abc --- dwl.c | 238 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/dwl.c b/dwl.c index 424485f..b09fc6f 100644 --- a/dwl.c +++ b/dwl.c @@ -221,9 +221,9 @@ static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_input_device *device); +static void createlayersurface(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 createlayersurface(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); static void cursorframe(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); @@ -234,8 +234,8 @@ static void dragicondestroy(struct wl_listener *listener, void *data); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); -static void fullscreennotify(struct wl_listener *listener, void *data); static Client *focustop(Monitor *m); +static void fullscreennotify(struct wl_listener *listener, void *data); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); @@ -263,13 +263,13 @@ static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); static Client *selclient(void); static void setcursor(struct wl_listener *listener, void *data); -static void setpsel(struct wl_listener *listener, void *data); -static void setsel(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, unsigned int newtags); +static void setpsel(struct wl_listener *listener, void *data); +static void setsel(struct wl_listener *listener, void *data); static void setup(void); static void sigchld(int unused); static void spawn(const Arg *arg); @@ -289,9 +289,9 @@ static void updatetitle(struct wl_listener *listener, void *data); static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg); static void virtualkeyboard(struct wl_listener *listener, void *data); +static Monitor *xytomon(double x, double y); static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); -static Monitor *xytomon(double x, double y); static void zoom(const Arg *arg); /* variables */ @@ -818,6 +818,50 @@ createkeyboard(struct wlr_input_device *device) wl_list_insert(&keyboards, &kb->link); } +void +createlayersurface(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *wlr_layer_surface = data; + LayerSurface *layersurface; + Monitor *m; + struct wlr_layer_surface_v1_state old_state; + + if (!wlr_layer_surface->output) { + wlr_layer_surface->output = selmon->wlr_output; + } + + layersurface = ecalloc(1, sizeof(LayerSurface)); + layersurface->type = LayerShell; + LISTEN(&wlr_layer_surface->surface->events.commit, + &layersurface->surface_commit, commitlayersurfacenotify); + LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, + destroylayersurfacenotify); + LISTEN(&wlr_layer_surface->events.map, &layersurface->map, + maplayersurfacenotify); + LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap, + unmaplayersurfacenotify); + + layersurface->layer_surface = wlr_layer_surface; + wlr_layer_surface->data = layersurface; + m = wlr_layer_surface->output->data; + + layersurface->scene = wlr_layer_surface->surface->data = + wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], + wlr_layer_surface->surface); + layersurface->scene->data = layersurface; + + wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], + &layersurface->link); + + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it + */ + old_state = wlr_layer_surface->current; + wlr_layer_surface->current = wlr_layer_surface->pending; + arrangelayers(m); + wlr_layer_surface->current = old_state; +} + void createmon(struct wl_listener *listener, void *data) { @@ -924,50 +968,6 @@ createnotify(struct wl_listener *listener, void *data) c->isfullscreen = 0; } -void -createlayersurface(struct wl_listener *listener, void *data) -{ - struct wlr_layer_surface_v1 *wlr_layer_surface = data; - LayerSurface *layersurface; - Monitor *m; - struct wlr_layer_surface_v1_state old_state; - - if (!wlr_layer_surface->output) { - wlr_layer_surface->output = selmon->wlr_output; - } - - layersurface = ecalloc(1, sizeof(LayerSurface)); - layersurface->type = LayerShell; - LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); - LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, - destroylayersurfacenotify); - LISTEN(&wlr_layer_surface->events.map, &layersurface->map, - maplayersurfacenotify); - LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap, - unmaplayersurfacenotify); - - layersurface->layer_surface = wlr_layer_surface; - wlr_layer_surface->data = layersurface; - m = wlr_layer_surface->output->data; - - layersurface->scene = wlr_layer_surface->surface->data = - wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], - wlr_layer_surface->surface); - layersurface->scene->data = layersurface; - - wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], - &layersurface->link); - - /* Temporarily set the layer's current state to pending - * so that we can easily arrange it - */ - old_state = wlr_layer_surface->current; - wlr_layer_surface->current = wlr_layer_surface->pending; - arrangelayers(m); - wlr_layer_surface->current = old_state; -} - void createpointer(struct wlr_input_device *device) { @@ -1049,57 +1049,6 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } -void -dragicondestroy(struct wl_listener *listener, void *data) -{ - struct wlr_drag_icon *icon = data; - wlr_scene_node_destroy(icon->data); - // Focus enter isn't sent during drag, so refocus the focused node. - focusclient(selclient(), 1); - motionnotify(0); -} - -void -togglefullscreen(const Arg *arg) -{ - Client *sel = selclient(); - if (sel) - setfullscreen(sel, !sel->isfullscreen); -} - -void -setfullscreen(Client *c, int fullscreen) -{ - c->isfullscreen = fullscreen; - c->bw = fullscreen ? 0 : borderpx; - client_set_fullscreen(c, fullscreen); - - if (fullscreen) { - c->prev = c->geom; - resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); - } else { - /* restore previous size instead of arrange for floating windows since - * client positions are set by the user and cannot be recalculated */ - resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0); - } - arrange(c->mon); - printstatus(); -} - -void -fullscreennotify(struct wl_listener *listener, void *data) -{ - Client *c = wl_container_of(listener, c, fullscreen); - int fullscreen = client_wants_fullscreen(c); - - if (!c->mon) { - /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ - c->isfullscreen = fullscreen; - return; - } - setfullscreen(c, fullscreen); -} - Monitor * dirtomon(enum wlr_direction dir) { @@ -1114,6 +1063,16 @@ dirtomon(enum wlr_direction dir) return selmon; } +void +dragicondestroy(struct wl_listener *listener, void *data) +{ + struct wlr_drag_icon *icon = data; + wlr_scene_node_destroy(icon->data); + // Focus enter isn't sent during drag, so refocus the focused node. + focusclient(selclient(), 1); + motionnotify(0); +} + void focusclient(Client *c, int lift) { @@ -1229,6 +1188,20 @@ focustop(Monitor *m) return NULL; } +void +fullscreennotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, fullscreen); + int fullscreen = client_wants_fullscreen(c); + + if (!c->mon) { + /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ + c->isfullscreen = fullscreen; + return; + } + setfullscreen(c, fullscreen); +} + void incnmaster(const Arg *arg) { @@ -1692,6 +1665,18 @@ rendermon(struct wl_listener *listener, void *data) m->un_map = 0; } +void +requeststartdrag(struct wl_listener *listener, void *data) +{ + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, + event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); +} + void resize(Client *c, int x, int y, int w, int h, int interact) { @@ -1720,18 +1705,6 @@ resize(Client *c, int x, int y, int w, int h, int interact) c->geom.height - 2 * c->bw); } -void -requeststartdrag(struct wl_listener *listener, void *data) -{ - struct wlr_seat_request_start_drag_event *event = data; - - if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, - event->serial)) - wlr_seat_start_pointer_drag(seat, event->drag, event->serial); - else - wlr_data_source_destroy(event->drag->source); -} - void run(char *startup_cmd) { @@ -1830,6 +1803,25 @@ setfloating(Client *c, int floating) printstatus(); } +void +setfullscreen(Client *c, int fullscreen) +{ + c->isfullscreen = fullscreen; + c->bw = fullscreen ? 0 : borderpx; + client_set_fullscreen(c, fullscreen); + + if (fullscreen) { + c->prev = c->geom; + resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); + } else { + /* restore previous size instead of arrange for floating windows since + * client positions are set by the user and cannot be recalculated */ + resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0); + } + arrange(c->mon); + printstatus(); +} + void setlayout(const Arg *arg) { @@ -2176,6 +2168,14 @@ togglefloating(const Arg *arg) setfloating(sel, !sel->isfloating); } +void +togglefullscreen(const Arg *arg) +{ + Client *sel = selclient(); + if (sel) + setfullscreen(sel, !sel->isfullscreen); +} + void toggletag(const Arg *arg) { @@ -2329,6 +2329,13 @@ virtualkeyboard(struct wl_listener *listener, void *data) createkeyboard(device); } +Monitor * +xytomon(double x, double y) +{ + struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); + return o ? o->data : NULL; +} + struct wlr_scene_node * xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny) @@ -2362,13 +2369,6 @@ xytonode(double x, double y, struct wlr_surface **psurface, return node; } -Monitor * -xytomon(double x, double y) -{ - struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); - return o ? o->data : NULL; -} - void zoom(const Arg *arg) { From b86fcf6504e7b6aafcace2e099d2de822c25fbf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 10 Apr 2022 21:38:48 -0500 Subject: [PATCH 135/329] add missing return in client_is_floating_type() This causes all Xwayland clients to be treated as floating --- client.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client.h b/client.h index 41c9b9a..2ea0d22 100644 --- a/client.h +++ b/client.h @@ -113,6 +113,8 @@ client_is_float_type(Client *c) && (size_hints->max_width == size_hints->min_width || size_hints->max_height == size_hints->min_height)) return 1; + + return 0; } #endif From 4a2e761914f88d4d284ec74b147104f53c394523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 12 Apr 2022 23:52:05 -0500 Subject: [PATCH 136/329] replace deleted EBARF() with die() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index dd62956..06402c0 100644 --- a/dwl.c +++ b/dwl.c @@ -2339,7 +2339,7 @@ sigchld(int unused) * setting our own disposition for SIGCHLD. */ if (signal(SIGCHLD, sigchld) == SIG_ERR) - EBARF("can't install SIGCHLD handler"); + die("can't install SIGCHLD handler:"); /* WNOWAIT leaves the child in a waitable state, in case this is the * XWayland process */ From a48ce99e6a3c0dda331781942995a85ba8e438a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 15 Apr 2022 17:40:02 -0500 Subject: [PATCH 137/329] use pointer math in xytonode() --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index b09fc6f..88043d8 100644 --- a/dwl.c +++ b/dwl.c @@ -2344,11 +2344,11 @@ xytonode(double x, double y, struct wlr_surface **psurface, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; - int i; + const int *layer; int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; - for (i = 0; i < LENGTH(focus_order); i++) { - if ((node = wlr_scene_node_at(layers[focus_order[i]], x, y, nx, ny))) { + for (layer = focus_order; layer < END(focus_order); layer++) { + if ((node = wlr_scene_node_at(layers[*layer], x, y, nx, ny))) { if (node->type == WLR_SCENE_NODE_SURFACE) surface = wlr_scene_surface_from_node(node)->surface; /* Walk the tree to find a node that knows the client */ From dc7709a00edebe323d8e192ff48f14f72f1e2142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 16 Apr 2022 15:51:13 -0500 Subject: [PATCH 138/329] schedule a configure on maximize request see maximizenotify() for more info --- dwl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dwl.c b/dwl.c index 06402c0..f4ce462 100644 --- a/dwl.c +++ b/dwl.c @@ -104,6 +104,7 @@ typedef struct { } surface; struct wl_listener commit; struct wl_listener map; + struct wl_listener maximize; struct wl_listener unmap; struct wl_listener destroy; struct wl_listener set_title; @@ -233,6 +234,7 @@ static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data); +static void maximizenotify(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); static void motionnotify(uint32_t time); @@ -840,6 +842,8 @@ createnotify(struct wl_listener *listener, void *data) LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, + maximizenotify); c->isfullscreen = 0; } @@ -1254,6 +1258,18 @@ mapnotify(struct wl_listener *listener, void *data) c->mon->un_map = 1; } +void +maximizenotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client would like to maximize itself, + * typically because the user clicked on the maximize button on + * client-side decorations. dwl doesn't support maximization, but + * to conform to xdg-shell protocol we still must send a configure. + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + Client *c = wl_container_of(listener, c, maximize); + wlr_xdg_surface_schedule_configure(c->surface.xdg); +} + void monocle(Monitor *m) { From d071a899f3b302f3fbaa85c378d0854b7fa39e8e Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Mon, 25 Apr 2022 13:48:41 -0700 Subject: [PATCH 139/329] Run printstatus() when a monitor is removed --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 88043d8..0628bfb 100644 --- a/dwl.c +++ b/dwl.c @@ -740,6 +740,7 @@ closemon(Monitor *m) if (c->mon == m) setmon(c, selmon, c->tags); } + printstatus(); } void From 3a4b7d104ff8bfc14862b7e41bcacb35677306a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 3 Apr 2022 17:18:05 -0500 Subject: [PATCH 140/329] restack xwayland surface on focusclient() --- dwl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dwl.c b/dwl.c index 0628bfb..b675b67 100644 --- a/dwl.c +++ b/dwl.c @@ -1135,6 +1135,15 @@ focusclient(Client *c, int lift) return; } +#ifdef XWAYLAND + /* This resolves an issue where the last spawned xwayland client + * receives all pointer activity. + */ + if (c->type == X11Managed) + wlr_xwayland_surface_restack(c->surface.xwayland, NULL, + XCB_STACK_MODE_ABOVE); +#endif + /* Have a client, so focus its top-level wlr_surface */ kb = wlr_seat_get_keyboard(seat); wlr_seat_keyboard_notify_enter(seat, client_surface(c), From 31fa6600a174d44be69d66c16dfefd80583409a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 8 May 2022 17:51:42 -0500 Subject: [PATCH 141/329] replace wlr_xwayland_surface_size_hints with xcb_size_hints_t --- client.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client.h b/client.h index db043d2..1796ef0 100644 --- a/client.h +++ b/client.h @@ -97,7 +97,7 @@ client_is_float_type(Client *c) #ifdef XWAYLAND if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; - struct wlr_xwayland_surface_size_hints *size_hints; + xcb_size_hints_t *size_hints; if (surface->modal) return 1; @@ -208,8 +208,7 @@ client_min_size(Client *c, int *width, int *height) struct wlr_xdg_toplevel_state *state; #ifdef XWAYLAND if (client_is_x11(c)) { - struct wlr_xwayland_surface_size_hints *size_hints; - size_hints = c->surface.xwayland->size_hints; + xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints; *width = size_hints->min_width; *height = size_hints->min_height; return; From e0d310fd84eb4fa34527f6695c998ce9f5eb56d6 Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Tue, 5 Apr 2022 23:22:15 -0700 Subject: [PATCH 142/329] Handle 'wlr_seat_get_keyboard' possibly returning null. --- dwl.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index b675b67..74b11a8 100644 --- a/dwl.c +++ b/dwl.c @@ -600,8 +600,11 @@ arrangelayers(Monitor *m) layersurface->layer_surface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); - wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, - kb->keycodes, kb->num_keycodes, &kb->modifiers); + if (kb) + wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, + kb->keycodes, kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, NULL, 0, NULL); return; } } @@ -641,7 +644,7 @@ buttonpress(struct wl_listener *listener, void *data) focusclient(c, 1); keyboard = wlr_seat_get_keyboard(seat); - mods = wlr_keyboard_get_modifiers(keyboard); + mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (b = buttons; b < END(buttons); b++) { if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && b->func) { @@ -1146,8 +1149,11 @@ focusclient(Client *c, int lift) /* Have a client, so focus its top-level wlr_surface */ kb = wlr_seat_get_keyboard(seat); - wlr_seat_keyboard_notify_enter(seat, client_surface(c), - kb->keycodes, kb->num_keycodes, &kb->modifiers); + if (kb) + wlr_seat_keyboard_notify_enter(seat, client_surface(c), + kb->keycodes, kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, client_surface(c), NULL, 0, NULL); /* Activate the new client */ client_activate_surface(client_surface(c), 1); From 5d8084daa7812931b53d65312b2cebf9a8453e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 9 May 2022 14:52:03 -0500 Subject: [PATCH 143/329] add flag to print version and exit --- Makefile | 2 +- config.mk | 3 +++ dwl.c | 4 +++- generate-version.sh | 13 +++++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100755 generate-version.sh diff --git a/Makefile b/Makefile index 48a0aa7..c235633 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ include config.mk -CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -pedantic +CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -pedantic -DVERSION=\"$(VERSION)\" WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols) WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner) diff --git a/config.mk b/config.mk index 960fc8a..37b4114 100644 --- a/config.mk +++ b/config.mk @@ -1,3 +1,6 @@ +_VERSION = 0.3.1 +VERSION = $(shell ./generate-version.sh $(_VERSION)) + # paths PREFIX = /usr/local MANDIR = $(PREFIX)/share/man diff --git a/dwl.c b/dwl.c index 74b11a8..48eb1a3 100644 --- a/dwl.c +++ b/dwl.c @@ -2516,9 +2516,11 @@ main(int argc, char *argv[]) char *startup_cmd = NULL; int c; - while ((c = getopt(argc, argv, "s:h")) != -1) { + while ((c = getopt(argc, argv, "s:hv")) != -1) { if (c == 's') startup_cmd = optarg; + else if (c == 'v') + die("dwl " VERSION); else goto usage; } diff --git a/generate-version.sh b/generate-version.sh new file mode 100755 index 0000000..cf408e1 --- /dev/null +++ b/generate-version.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +if git tag --contains HEAD | grep -q $1; then + echo $1 +else + branch="$(git rev-parse --abbrev-ref HEAD)" + commit="$(git rev-parse --short HEAD)" + if [ "${branch}" != "main" ]; then + echo $1-$branch-$commit + else + echo $1-$commit + fi +fi From d5a741c9b47f744428e75a76b9f5f6410acfbcf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 9 May 2022 15:20:37 -0500 Subject: [PATCH 144/329] add dist target --- Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c235633..0c2b78d 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,15 @@ all: dwl clean: rm -f dwl *.o *-protocol.h *-protocol.c +dist: clean + mkdir -p dwl-$(VERSION) + cp -R LICENSE* Makefile README.md generate-version.sh client.h\ + config.def.h config.mk protocols dwl.1 dwl.c util.c util.h\ + dwl-$(VERSION) + echo "echo $(VERSION)" > dwl-$(VERSION)/generate-version.sh + tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) + rm -rf dwl-$(VERSION) + install: dwl install -Dm755 dwl $(DESTDIR)$(PREFIX)/bin/dwl install -Dm644 dwl.1 $(DESTDIR)$(MANDIR)/man1/dwl.1 @@ -21,7 +30,7 @@ install: dwl uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 -.PHONY: all clean install uninstall +.PHONY: all clean dist install uninstall # wayland-scanner is a tool which generates C headers and rigging for Wayland # protocols, which are specified in XML. wlroots requires you to rig these up From 063736f8981c5f71b816f4e8ab2ab54618c3ee8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 10 May 2022 11:39:33 -0500 Subject: [PATCH 145/329] add `-v` flag to the manpage Thanks @Humm42 --- dwl.1 | 7 +++++++ dwl.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dwl.1 b/dwl.1 index eea0f70..f50602c 100644 --- a/dwl.1 +++ b/dwl.1 @@ -6,6 +6,7 @@ .Nd dwm for Wayland .Sh SYNOPSIS .Nm +.Op Fl v .Op Fl s Ar command .Sh DESCRIPTION .Nm @@ -15,6 +16,12 @@ It is intended to fill the same space in the Wayland world that does for X11. .Pp When given the +.Fl v +option, +.Nm +writes its name and version to standard error and exits unsuccessfully. +.Pp +When given the .Fl s option, .Nm diff --git a/dwl.c b/dwl.c index 48eb1a3..3ebe37a 100644 --- a/dwl.c +++ b/dwl.c @@ -2536,5 +2536,5 @@ main(int argc, char *argv[]) return EXIT_SUCCESS; usage: - die("Usage: %s [-s startup command]", argv[0]); + die("Usage: %s [-v] [-s startup command]", argv[0]); } From 22bd75226bc897a3b2ad90f36883ff489d435eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 10 May 2022 11:42:40 -0500 Subject: [PATCH 146/329] remove trailing whitespaces --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 3ebe37a..8088d9f 100644 --- a/dwl.c +++ b/dwl.c @@ -600,10 +600,10 @@ arrangelayers(Monitor *m) layersurface->layer_surface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); - if (kb) + if (kb) wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); - else + else wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, NULL, 0, NULL); return; } @@ -1149,10 +1149,10 @@ focusclient(Client *c, int lift) /* Have a client, so focus its top-level wlr_surface */ kb = wlr_seat_get_keyboard(seat); - if (kb) + if (kb) wlr_seat_keyboard_notify_enter(seat, client_surface(c), kb->keycodes, kb->num_keycodes, &kb->modifiers); - else + else wlr_seat_keyboard_notify_enter(seat, client_surface(c), NULL, 0, NULL); /* Activate the new client */ From 06d9230a9611ab70041c7dbb1bf3d9e9ea497271 Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Wed, 11 May 2022 14:30:10 +0200 Subject: [PATCH 147/329] Run focusclient when switching to monocle layout --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 8088d9f..55e9f35 100644 --- a/dwl.c +++ b/dwl.c @@ -1405,6 +1405,7 @@ monocle(Monitor *m) continue; resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0); } + focusclient(focustop(m), 1); } void From 3c11ad9aa6d3d8d69c926d5c767aedfdf1cd03b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 14 May 2022 00:24:06 -0500 Subject: [PATCH 148/329] fix segfault when dragging chromium tabs --- client.h | 15 +++++++++------ dwl.c | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/client.h b/client.h index 2ea0d22..a7b546a 100644 --- a/client.h +++ b/client.h @@ -30,16 +30,19 @@ client_surface(Client *c) static inline void client_activate_surface(struct wlr_surface *s, int activated) { + struct wlr_xdg_surface *surface; #ifdef XWAYLAND - if (wlr_surface_is_xwayland_surface(s)) { - wlr_xwayland_surface_activate( - wlr_xwayland_surface_from_wlr_surface(s), activated); + struct wlr_xwayland_surface *xsurface; + if (wlr_surface_is_xwayland_surface(s) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) { + wlr_xwayland_surface_activate(xsurface, activated); return; } #endif - if (wlr_surface_is_xdg_surface(s)) - wlr_xdg_toplevel_set_activated( - wlr_xdg_surface_from_wlr_surface(s), activated); + if (wlr_surface_is_xdg_surface(s) + && (surface = wlr_xdg_surface_from_wlr_surface(s)) + && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) + wlr_xdg_toplevel_set_activated(surface, activated); } static inline void diff --git a/dwl.c b/dwl.c index 55e9f35..abff38a 100644 --- a/dwl.c +++ b/dwl.c @@ -1121,7 +1121,7 @@ focusclient(Client *c, int lift) } else { Client *w; struct wlr_scene_node *node = old->data; - if ((w = node->data)) + if (old->role_data && (w = node->data)) for (i = 0; i < 4; i++) wlr_scene_rect_set_color(w->border[i], bordercolor); From 2f8736b986786f526efbd2bb6863ed39bba4d3e0 Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Sun, 15 May 2022 13:18:40 +0200 Subject: [PATCH 149/329] Check if XWayland client size_hints are NULL --- client.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client.h b/client.h index a7b546a..e0964da 100644 --- a/client.h +++ b/client.h @@ -215,8 +215,13 @@ client_min_size(Client *c, int *width, int *height) if (client_is_x11(c)) { struct wlr_xwayland_surface_size_hints *size_hints; size_hints = c->surface.xwayland->size_hints; - *width = size_hints->min_width; - *height = size_hints->min_height; + if (size_hints) { + *width = size_hints->min_width; + *height = size_hints->min_height; + } else { + *width = 0; + *height = 0; + } return; } #endif From 79a148224ffb5a55510de691f95eda2d32c6d2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 15 May 2022 17:17:58 -0500 Subject: [PATCH 150/329] specify version in wlr_xdg_shell_create() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 40ace0c..0acb22e 100644 --- a/dwl.c +++ b/dwl.c @@ -1896,7 +1896,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy); + xdg_shell = wlr_xdg_shell_create(dpy, 2); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); From 5de68ba71362553e31a36f6a5a594e0ee830e611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 17 May 2022 13:23:29 -0500 Subject: [PATCH 151/329] sync manpage and help info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Leonardo Hernández Hernández --- dwl.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.1 b/dwl.1 index f50602c..d958210 100644 --- a/dwl.1 +++ b/dwl.1 @@ -7,7 +7,7 @@ .Sh SYNOPSIS .Nm .Op Fl v -.Op Fl s Ar command +.Op Fl s Ar startup command .Sh DESCRIPTION .Nm is a Wayland compositor based on wlroots. From 8870ba0bb8106a4a367bd8dee78178891b8c19db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 17 May 2022 14:38:18 -0500 Subject: [PATCH 152/329] implement urgency hints for xwayland clients --- dwl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dwl.c b/dwl.c index abff38a..90a2789 100644 --- a/dwl.c +++ b/dwl.c @@ -112,6 +112,7 @@ typedef struct { #ifdef XWAYLAND struct wl_listener activate; struct wl_listener configure; + struct wl_listener set_hints; #endif int bw; unsigned int tags; @@ -358,6 +359,7 @@ static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); +static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; @@ -1046,6 +1048,7 @@ destroynotify(struct wl_listener *listener, void *data) #ifdef XWAYLAND if (c->type != XDGShell) { wl_list_remove(&c->configure.link); + wl_list_remove(&c->set_hints.link); wl_list_remove(&c->activate.link); } else #endif @@ -2460,6 +2463,7 @@ createnotifyx11(struct wl_listener *listener, void *data) LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11); LISTEN(&xwayland_surface->events.request_configure, &c->configure, configurex11); + LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints); LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify); LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen, @@ -2479,6 +2483,16 @@ getatom(xcb_connection_t *xc, const char *name) return atom; } +void +sethints(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_hints); + if (c != selclient()) { + c->isurgent = c->surface.xwayland->hints_urgency; + printstatus(); + } +} + void xwaylandready(struct wl_listener *listener, void *data) { From 283c043b5c8cc6f2d5b8a5e72e1a5924b2c1532e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 21 May 2022 20:44:08 -0500 Subject: [PATCH 153/329] chase wlroots scene-surface refactor --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 84e5f2e..65cb97a 100644 --- a/dwl.c +++ b/dwl.c @@ -2253,8 +2253,9 @@ xytonode(double x, double y, struct wlr_surface **psurface, for (layer = focus_order; layer < END(focus_order); layer++) { if ((node = wlr_scene_node_at(layers[*layer], x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_SURFACE) - surface = wlr_scene_surface_from_node(node)->surface; + if (node->type == WLR_SCENE_NODE_BUFFER) + surface = wlr_scene_surface_from_buffer( + wlr_scene_buffer_from_node(node))->surface; /* Walk the tree to find a node that knows the client */ for (pnode = node; pnode && !c; pnode = pnode->parent) c = pnode->data; From ecbc2c61db180dc8ab1053b7cdc1e4817be33d36 Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Sun, 27 Mar 2022 17:04:41 -0700 Subject: [PATCH 154/329] Add configuration options for touchpads --- config.def.h | 24 ++++++++++++++++++++++++ dwl.c | 31 +++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/config.def.h b/config.def.h index 190b0da..4f131dd 100644 --- a/config.def.h +++ b/config.def.h @@ -49,7 +49,31 @@ static const int repeat_delay = 600; /* Trackpad */ static const int tap_to_click = 1; +static const int tap_and_drag = 1; +static const int drag_lock = 1; static const int natural_scrolling = 0; +static const int disable_while_typing = 1; +static const int left_handed = 0; +static const int middle_button_emulation = 0; +/* You can choose between: +LIBINPUT_CONFIG_SCROLL_NO_SCROLL +LIBINPUT_CONFIG_SCROLL_2FG +LIBINPUT_CONFIG_SCROLL_EDGE +LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN +*/ +static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; +/* You can choose between: +LIBINPUT_CONFIG_SEND_EVENTS_ENABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED +LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE +*/ +static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; +/* You can choose between: +LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT +LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE +*/ +static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; +static const double accel_speed = 0.0; /* If you want to use the windows key change this to WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT diff --git a/dwl.c b/dwl.c index 90a2789..b4b4b0d 100644 --- a/dwl.c +++ b/dwl.c @@ -981,17 +981,36 @@ createpointer(struct wlr_input_device *device) struct libinput_device *libinput_device = (struct libinput_device*) wlr_libinput_get_device_handle(device); - if (tap_to_click && libinput_device_config_tap_get_finger_count(libinput_device)) - libinput_device_config_tap_set_enabled(libinput_device, LIBINPUT_CONFIG_TAP_ENABLED); + if (libinput_device_config_tap_get_finger_count(libinput_device)) { + libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); + libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag); + libinput_device_config_tap_set_enabled(libinput_device, drag_lock); + } if (libinput_device_config_scroll_has_natural_scroll(libinput_device)) libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling); + + if (libinput_device_config_dwt_is_available(libinput_device)) + libinput_device_config_dwt_set_enabled(libinput_device, disable_while_typing); + + if (libinput_device_config_left_handed_is_available(libinput_device)) + libinput_device_config_left_handed_set(libinput_device, left_handed); + + if (libinput_device_config_middle_emulation_is_available(libinput_device)) + libinput_device_config_middle_emulation_set_enabled(libinput_device, middle_button_emulation); + + if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method (libinput_device, scroll_method); + + if (libinput_device_config_send_events_get_modes(libinput_device)) + libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); + + if (libinput_device_config_accel_is_available(libinput_device)) { + libinput_device_config_accel_set_profile(libinput_device, accel_profile); + libinput_device_config_accel_set_speed(libinput_device, accel_speed); + } } - /* We don't do anything special with pointers. All of our pointer handling - * is proxied through wlr_cursor. On another compositor, you might take this - * opportunity to do libinput configuration on the device to set - * acceleration, etc. */ wlr_cursor_attach_input_device(cursor, device); } From 40449fa64fcacb98372e576cc21e192ab783162f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 23 May 2022 09:14:21 -0500 Subject: [PATCH 155/329] add a new function to get a client from a wlr_surface --- client.h | 7 +++++++ dwl.c | 9 ++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client.h b/client.h index e0964da..ec760ec 100644 --- a/client.h +++ b/client.h @@ -231,6 +231,13 @@ client_min_size(Client *c, int *width, int *height) *height = state->min_height; } +static inline Client * +client_from_wlr_surface(struct wlr_surface *surface) +{ + struct wlr_scene_node *n = surface->data; + return n ? n->data : NULL; +} + static inline Client * client_from_popup(struct wlr_xdg_popup *popup) { diff --git a/dwl.c b/dwl.c index b4b4b0d..81ad91e 100644 --- a/dwl.c +++ b/dwl.c @@ -1142,8 +1142,7 @@ focusclient(Client *c, int lift) return; } else { Client *w; - struct wlr_scene_node *node = old->data; - if (old->role_data && (w = node->data)) + if (old->role_data && (w = client_from_wlr_surface(old))) for (i = 0; i < 4; i++) wlr_scene_rect_set_color(w->border[i], bordercolor); @@ -2336,11 +2335,7 @@ void urgent(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; - Client *c; - - if (!wlr_surface_is_xdg_surface(event->surface)) - return; - c = wlr_xdg_surface_from_wlr_surface(event->surface)->data; + Client *c = client_from_wlr_surface(event->surface); if (c != selclient()) { c->isurgent = 1; printstatus(); From 48ec914f439c962ac14f75bfcb0c40282c6a0de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 25 May 2022 14:49:32 -0500 Subject: [PATCH 156/329] destroy layersurface's scene node in destroylayersurfacenotify() --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 81ad91e..a317ee9 100644 --- a/dwl.c +++ b/dwl.c @@ -1045,6 +1045,7 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->map.link); wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); + wlr_scene_node_destroy(layersurface->scene); if (layersurface->layer_surface->output) { Monitor *m = layersurface->layer_surface->output->data; if (m) From 7018b9b65c35ece131823069d887c0a6386c8e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 25 May 2022 15:01:38 -0500 Subject: [PATCH 157/329] correct libinput function name for drag_lock --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a317ee9..7de82f9 100644 --- a/dwl.c +++ b/dwl.c @@ -984,7 +984,7 @@ createpointer(struct wlr_input_device *device) if (libinput_device_config_tap_get_finger_count(libinput_device)) { libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag); - libinput_device_config_tap_set_enabled(libinput_device, drag_lock); + libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock); } if (libinput_device_config_scroll_has_natural_scroll(libinput_device)) From 52e0d00942584b4a8a9ca1f59ffdea26277604ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 24 May 2022 14:37:55 -0500 Subject: [PATCH 158/329] check client_surface() returning NULL now client_surface()->data is a pointer to the wlr_scene_tree of clients which allows us to not call wlr_scene_node_lower_to_bottom() for every clients --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 7de82f9..d0f5afc 100644 --- a/dwl.c +++ b/dwl.c @@ -1376,10 +1376,12 @@ mapnotify(struct wl_listener *listener, void *data) /* Create scene tree for this client and its border */ c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; - c->scene_surface = client_surface(c)->data = c->type == XDGShell + c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - c->scene_surface->data = c; + if (client_surface(c)) + client_surface(c)->data = c->scene; + c->scene->data = c->scene_surface->data = c; if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); @@ -1394,7 +1396,6 @@ mapnotify(struct wl_listener *listener, void *data) c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); c->border[i]->node.data = c; wlr_scene_rect_set_color(c->border[i], bordercolor); - wlr_scene_node_lower_to_bottom(&c->border[i]->node); } /* Initialize client geometry with room for border */ From 2623a96ebf4c0b43e65d3ff3d7c1b0e56634acf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 24 May 2022 14:46:03 -0500 Subject: [PATCH 159/329] call client_set-size() if client has a resize --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index d0f5afc..f061ebe 100644 --- a/dwl.c +++ b/dwl.c @@ -784,6 +784,8 @@ commitnotify(struct wl_listener *listener, void *data) /* mark a pending resize as completed */ if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) c->resize = 0; + else if (c->resize) + c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); } void From 70da04a714914990556b8f123895301a57ee6d3f Mon Sep 17 00:00:00 2001 From: Lennart Jablonka Date: Fri, 3 Jun 2022 01:15:06 +0200 Subject: [PATCH 160/329] initialize xkb_rules.options to a null pointer Initializing it to an empty string had broken configuring xkbcommon through the environment (XKB_DEFAULT_OPTIONS). Fixes: ae313911153b ("initialize rules and xkb_rules") --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 4f131dd..8c27380 100644 --- a/config.def.h +++ b/config.def.h @@ -41,7 +41,7 @@ static const struct xkb_rule_names xkb_rules = { /* example: .options = "ctrl:nocaps", */ - .options = "", + .options = NULL, }; static const int repeat_rate = 25; From b91017e713d4e6719d19368b883e54af4731f0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 5 Jun 2022 15:27:40 -0500 Subject: [PATCH 161/329] disable scene node at unmaplayersurface() --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index f061ebe..ca0368a 100644 --- a/dwl.c +++ b/dwl.c @@ -2250,7 +2250,8 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { - layersurface->layer_surface->mapped = 0; + layersurface->layer_surface->mapped = layersurface->mapped = 0; + wlr_scene_node_set_enabled(layersurface->scene, 0); if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(selclient(), 1); From 4dfa45659a6084cd3c800235040d83822f421afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 5 Jun 2022 16:55:57 -0500 Subject: [PATCH 162/329] fix compiler error with gcc complaining about parentheses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dwl.c: In function ‘unmaplayersurface’: dwl.c:2253:9: error: suggest parentheses around assignment used as truth value [-Werror=parentheses] 2253 | layersurface->layer_surface->mapped = layersurface->mapped = 0; | ^~~~~~~~~~~~ cc1: all warnings being treated as errors make: *** [: dwl.o] Error 1 clang not affected --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ca0368a..e4bed14 100644 --- a/dwl.c +++ b/dwl.c @@ -2250,7 +2250,7 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { - layersurface->layer_surface->mapped = layersurface->mapped = 0; + layersurface->layer_surface->mapped = (layersurface->mapped = 0); wlr_scene_node_set_enabled(layersurface->scene, 0); if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) From a5a0674f6a92bc47eed51fa5e08279d9d6b1b369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 6 Jun 2022 22:50:50 -0500 Subject: [PATCH 163/329] improve client_from_wlr_surface() --- client.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/client.h b/client.h index ec760ec..6791a4d 100644 --- a/client.h +++ b/client.h @@ -232,10 +232,22 @@ client_min_size(Client *c, int *width, int *height) } static inline Client * -client_from_wlr_surface(struct wlr_surface *surface) +client_from_wlr_surface(struct wlr_surface *s) { - struct wlr_scene_node *n = surface->data; - return n ? n->data : NULL; + struct wlr_xdg_surface *surface; + +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; + if (s->role_data && wlr_surface_is_xwayland_surface(s) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) + return xsurface->data; +#endif + if (s->role_data && wlr_surface_is_xdg_surface(s) + && (surface = wlr_xdg_surface_from_wlr_surface(s)) + && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) + return surface->data; + + return NULL; } static inline Client * From 7b42232ad10bdb5585a5df9222dd9c15a1a63f80 Mon Sep 17 00:00:00 2001 From: KawaiiAmber Date: Wed, 25 May 2022 16:04:19 -0600 Subject: [PATCH 164/329] convert makefile to be more portable --- Makefile | 108 +++++++++++++++++++++++++++++------------------------- config.mk | 9 +++-- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 0c2b78d..cab513c 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,60 @@ +.POSIX: +.SUFFIXES: + include config.mk -CFLAGS += -I. -DWLR_USE_UNSTABLE -std=c99 -pedantic -DVERSION=\"$(VERSION)\" +# flags for compiling +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -DVERSION=\"$(VERSION)\" -WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols) -WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner) +# Wayland utils +WAYLAND_PROTOCOLS = `pkg-config --variable=pkgdatadir wayland-protocols` +WAYLAND_SCANNER = `pkg-config --variable=wayland_scanner wayland-scanner` -PKGS = wlroots wayland-server xcb xkbcommon libinput -CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p))) -LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p))) +# CFLAGS / LDFLAGS +PKGS = wlroots wayland-server xcb xkbcommon libinput +DWLCFLAGS = `pkg-config --cflags $(PKGS)` $(DWLCPPFLAGS) $(CFLAGS) $(XWAYLAND) +LDLIBS = `pkg-config --libs $(PKGS)` +# build rules + +# wayland-scanner is a tool which generates C headers and rigging for Wayland +# protocols, which are specified in XML. wlroots requires you to rig these up +# to your build system yourself and provide them in the include path. all: dwl +dwl: dwl.o xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o util.o + $(CC) $(LDLIBS) -o $@ dwl.o xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o util.o +dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h +xdg-shell-protocol.o: xdg-shell-protocol.h xdg-shell-protocol.c +wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.c +idle-protocol.o: idle-protocol.h idle-protocol.c +util.o: util.c util.h +# wayland scanner rules to generate .h / .c files +xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +xdg-shell-protocol.c: + $(WAYLAND_SCANNER) private-code \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +wlr-layer-shell-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-layer-shell-unstable-v1.xml $@ +wlr-layer-shell-unstable-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + protocols/wlr-layer-shell-unstable-v1.xml $@ +idle-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/idle.xml $@ +idle-protocol.c: + $(WAYLAND_SCANNER) private-code \ + protocols/idle.xml $@ + +config.h: + cp config.def.h $@ clean: rm -f dwl *.o *-protocol.h *-protocol.c +# distribution archive dist: clean mkdir -p dwl-$(VERSION) cp -R LICENSE* Makefile README.md generate-version.sh client.h\ @@ -23,51 +64,18 @@ dist: clean tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) rm -rf dwl-$(VERSION) -install: dwl - install -Dm755 dwl $(DESTDIR)$(PREFIX)/bin/dwl - install -Dm644 dwl.1 $(DESTDIR)$(MANDIR)/man1/dwl.1 +# install rules +install: dwl + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp dwl $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl + mkdir -p $(DESTDIR)$(MANDIR)/man1 + cp dwl.1 $(DESTDIR)$(MANDIR)/man1 + chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 -.PHONY: all clean dist install uninstall - -# wayland-scanner is a tool which generates C headers and rigging for Wayland -# protocols, which are specified in XML. wlroots requires you to rig these up -# to your build system yourself and provide them in the include path. -xdg-shell-protocol.h: - $(WAYLAND_SCANNER) server-header \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ - -xdg-shell-protocol.c: - $(WAYLAND_SCANNER) private-code \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ - -xdg-shell-protocol.o: xdg-shell-protocol.h - -wlr-layer-shell-unstable-v1-protocol.h: - $(WAYLAND_SCANNER) server-header \ - protocols/wlr-layer-shell-unstable-v1.xml $@ - -wlr-layer-shell-unstable-v1-protocol.c: - $(WAYLAND_SCANNER) private-code \ - protocols/wlr-layer-shell-unstable-v1.xml $@ - -wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h - -idle-protocol.h: - $(WAYLAND_SCANNER) server-header \ - protocols/idle.xml $@ - -idle-protocol.c: - $(WAYLAND_SCANNER) private-code \ - protocols/idle.xml $@ - -idle-protocol.o: idle-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 util.h - -dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o util.o +.SUFFIXES: .c .o +.c.o: + $(CC) $(CPPFLAGS) $(DWLCFLAGS) -c $< diff --git a/config.mk b/config.mk index 37b4114..3a5e37f 100644 --- a/config.mk +++ b/config.mk @@ -1,12 +1,13 @@ _VERSION = 0.3.1 -VERSION = $(shell ./generate-version.sh $(_VERSION)) +VERSION = `./generate-version.sh $(_VERSION)` # paths PREFIX = /usr/local MANDIR = $(PREFIX)/share/man -# Default compile flags (overridable by environment) -CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement +# Compile flags that can be used +#CFLAGS = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement +XWAYLAND = # Uncomment to build XWayland support -#CFLAGS += -DXWAYLAND +#XWAYLAND = -DXWAYLAND From 14641560b0035402e699b0df0bea75f183ceb057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 30 May 2022 16:18:31 -0500 Subject: [PATCH 165/329] include xcb only when building with xwayland support --- Makefile | 2 +- config.mk | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cab513c..3371144 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ WAYLAND_PROTOCOLS = `pkg-config --variable=pkgdatadir wayland-protocols` WAYLAND_SCANNER = `pkg-config --variable=wayland_scanner wayland-scanner` # CFLAGS / LDFLAGS -PKGS = wlroots wayland-server xcb xkbcommon libinput +PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) DWLCFLAGS = `pkg-config --cflags $(PKGS)` $(DWLCPPFLAGS) $(CFLAGS) $(XWAYLAND) LDLIBS = `pkg-config --libs $(PKGS)` diff --git a/config.mk b/config.mk index 3a5e37f..ba24bb8 100644 --- a/config.mk +++ b/config.mk @@ -9,5 +9,7 @@ MANDIR = $(PREFIX)/share/man #CFLAGS = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement XWAYLAND = +XLIBS = # Uncomment to build XWayland support #XWAYLAND = -DXWAYLAND +#XLIBS = xcb From 50b6630f3d53b6635ce83565ccc4b900fdc15956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 30 May 2022 16:23:14 -0500 Subject: [PATCH 166/329] do not generate *-protocol.{c,o} according with https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/62fbf3f4ba1b2993e29dfb46f077e5806f7aac1c they are unused and wlroots-based compositors don't need to do this --- Makefile | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 3371144..a8c1c0f 100644 --- a/Makefile +++ b/Makefile @@ -21,38 +21,26 @@ LDLIBS = `pkg-config --libs $(PKGS)` # protocols, which are specified in XML. wlroots requires you to rig these up # to your build system yourself and provide them in the include path. all: dwl -dwl: dwl.o xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o util.o - $(CC) $(LDLIBS) -o $@ dwl.o xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o util.o +dwl: dwl.o util.o + $(CC) $(LDLIBS) -o $@ dwl.o util.o dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h -xdg-shell-protocol.o: xdg-shell-protocol.h xdg-shell-protocol.c -wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.c -idle-protocol.o: idle-protocol.h idle-protocol.c util.o: util.c util.h # wayland scanner rules to generate .h / .c files xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ -xdg-shell-protocol.c: - $(WAYLAND_SCANNER) private-code \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ wlr-layer-shell-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ -wlr-layer-shell-unstable-v1-protocol.c: - $(WAYLAND_SCANNER) private-code \ - protocols/wlr-layer-shell-unstable-v1.xml $@ idle-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/idle.xml $@ -idle-protocol.c: - $(WAYLAND_SCANNER) private-code \ - protocols/idle.xml $@ config.h: cp config.def.h $@ clean: - rm -f dwl *.o *-protocol.h *-protocol.c + rm -f dwl *.o *-protocol.h # distribution archive dist: clean From d969289bafbbd5f035f8f483746ae824415bd1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 6 Jun 2022 23:31:35 -0500 Subject: [PATCH 167/329] use LDFLAGS to build dwl target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a8c1c0f..59b2519 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ LDLIBS = `pkg-config --libs $(PKGS)` # to your build system yourself and provide them in the include path. all: dwl dwl: dwl.o util.o - $(CC) $(LDLIBS) -o $@ dwl.o util.o + $(CC) $(LDLIBS) $(LDFLAGS) -o $@ dwl.o util.o dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h util.o: util.c util.h From c7007b48115ac4913fad7e887c402f1c643f51bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 7 Jun 2022 00:31:58 -0500 Subject: [PATCH 168/329] chase wlroots scene-tree changes --- dwl.c | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/dwl.c b/dwl.c index 65cb97a..8d08810 100644 --- a/dwl.c +++ b/dwl.c @@ -94,9 +94,9 @@ typedef struct Monitor Monitor; typedef struct { /* Must be first */ unsigned int type; /* XDGShell or X11* */ - struct wlr_scene_node *scene; + struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ - struct wlr_scene_node *scene_surface; + struct wlr_scene_tree *scene_surface; struct wl_list link; struct wl_list flink; union { @@ -144,7 +144,7 @@ typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ int mapped; - struct wlr_scene_node *scene; + struct wlr_scene_tree *scene; struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wlr_layer_surface_v1 *layer_surface; @@ -291,7 +291,7 @@ static const char broken[] = "broken"; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; -static struct wlr_scene_node *layers[NUM_LAYERS]; +static struct wlr_scene_tree *layers[NUM_LAYERS]; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; @@ -412,7 +412,7 @@ applyrules(Client *c) mon = m; } } - wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); setmon(c, mon, newtags); } @@ -421,7 +421,7 @@ arrange(Monitor *m) { Client *c; wl_list_for_each(c, &clients, link) - wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, c->mon)); + wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, c->mon)); if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); @@ -632,7 +632,7 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = wlr_layer_surface->output; Monitor *m; - wlr_scene_node_reparent(layersurface->scene, + wlr_scene_node_reparent(&layersurface->scene->node, layers[wlr_layer_surface->current.layer]); if (!wlr_output || !(m = wlr_output->data)) @@ -730,9 +730,9 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->scene_layer = wlr_scene_layer_surface_v1_create( layers[wlr_layer_surface->pending.layer], wlr_layer_surface); layersurface->scene = wlr_layer_surface->surface->data = - layersurface->scene_layer->node; + &layersurface->scene_layer->tree->node; - layersurface->scene->data = layersurface; + layersurface->scene->node.data = layersurface; wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], &layersurface->link); @@ -969,7 +969,7 @@ focusclient(Client *c, int lift) /* Raise client in stacking order if requested */ if (c && lift) - wlr_scene_node_raise_to_top(c->scene); + wlr_scene_node_raise_to_top(&c->scene->node); if (c && client_surface(c) == old) return; @@ -1236,17 +1236,17 @@ mapnotify(struct wl_listener *listener, void *data) int i; /* Create scene tree for this client and its border */ - c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; + c->scene = wlr_scene_tree_create(layers[LyrTile]); c->scene_surface = client_surface(c)->data = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - c->scene_surface->data = c; + c->scene_surface->node.data = c; if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); /* Floating */ - wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, + wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); + wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx, c->geom.y + borderpx); return; } @@ -1590,8 +1590,8 @@ resize(Client *c, int x, int y, int w, int h, int interact) applybounds(c, bbox); /* Update scene-graph, including borders */ - wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y); - wlr_scene_node_set_position(c->scene_surface, c->bw, c->bw); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); @@ -1710,7 +1710,7 @@ void setfloating(Client *c, int floating) { c->isfloating = floating; - wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } @@ -1836,13 +1836,13 @@ setup(void) /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); - layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrNoFocus] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrBg] = wlr_scene_tree_create(&scene->tree); + layers[LyrBottom] = wlr_scene_tree_create(&scene->tree); + layers[LyrTile] = wlr_scene_tree_create(&scene->tree); + layers[LyrFloat] = wlr_scene_tree_create(&scene->tree); + layers[LyrTop] = wlr_scene_tree_create(&scene->tree); + layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); + layers[LyrNoFocus] = wlr_scene_tree_create(&scene->tree); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2139,14 +2139,14 @@ unmapnotify(struct wl_listener *listener, void *data) c->mon->un_map = 1; if (client_is_unmanaged(c)) { - wlr_scene_node_destroy(c->scene); + wlr_scene_node_destroy(&c->scene->node); return; } wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); - wlr_scene_node_destroy(c->scene); + wlr_scene_node_destroy(&c->scene->node); printstatus(); } @@ -2252,12 +2252,12 @@ xytonode(double x, double y, struct wlr_surface **psurface, int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; for (layer = focus_order; layer < END(focus_order); layer++) { - if ((node = wlr_scene_node_at(layers[*layer], x, y, nx, ny))) { + if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { if (node->type == WLR_SCENE_NODE_BUFFER) surface = wlr_scene_surface_from_buffer( wlr_scene_buffer_from_node(node))->surface; /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = pnode->parent) + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) c = pnode->data; if (c && c->type == LayerShell) { c = NULL; From 4b890336e21edc6a69bd3463b22a4c1318a669e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 7 Jun 2022 00:55:41 -0500 Subject: [PATCH 169/329] use xdg-shell v3 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8d08810..a71f294 100644 --- a/dwl.c +++ b/dwl.c @@ -1901,7 +1901,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy, 2); + xdg_shell = wlr_xdg_shell_create(dpy, 3); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); From 948fdcf709e86f380eef26ee529683d2c396e58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 9 Jun 2022 12:45:02 -0500 Subject: [PATCH 170/329] use xdg-shell v4 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a71f294..852eecf 100644 --- a/dwl.c +++ b/dwl.c @@ -1901,7 +1901,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy, 3); + xdg_shell = wlr_xdg_shell_create(dpy, 4); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); From a32db11f16fae3f57af3795d2463996b95e7ba1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 9 Jun 2022 12:45:42 -0500 Subject: [PATCH 171/329] set client bounds at resize --- client.h | 10 ++++++++++ dwl.c | 1 + 2 files changed, 11 insertions(+) diff --git a/client.h b/client.h index 6648c59..9431d11 100644 --- a/client.h +++ b/client.h @@ -45,6 +45,16 @@ client_activate_surface(struct wlr_surface *s, int activated) wlr_xdg_toplevel_set_activated(surface->toplevel, activated); } +static inline uint32_t +client_set_bounds(Client *c, int32_t width, int32_t height) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); +} + static inline void client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) { diff --git a/dwl.c b/dwl.c index 852eecf..b56abd7 100644 --- a/dwl.c +++ b/dwl.c @@ -1582,6 +1582,7 @@ resize(Client *c, int x, int y, int w, int h, int interact) { int min_width = 0, min_height = 0; struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + client_set_bounds(c, w, h); client_min_size(c, &min_width, &min_height); c->geom.x = x; c->geom.y = y; From c990dbd441684a9744cb744792488c34af20e9c7 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Fri, 10 Jun 2022 19:26:45 +0300 Subject: [PATCH 172/329] fix link failure with --as-needed --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59b2519..36a0f2f 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ LDLIBS = `pkg-config --libs $(PKGS)` # to your build system yourself and provide them in the include path. all: dwl dwl: dwl.o util.o - $(CC) $(LDLIBS) $(LDFLAGS) -o $@ dwl.o util.o + $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) -o $@ dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h util.o: util.c util.h From c008bf2a7d76fd4b91267be6a67bd090b839c3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 10 Jun 2022 12:08:36 -0500 Subject: [PATCH 173/329] add $(LIBS) to $(LDLIBS) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 36a0f2f..ac24ae7 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ WAYLAND_SCANNER = `pkg-config --variable=wayland_scanner wayland-scanner` # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) DWLCFLAGS = `pkg-config --cflags $(PKGS)` $(DWLCPPFLAGS) $(CFLAGS) $(XWAYLAND) -LDLIBS = `pkg-config --libs $(PKGS)` +LDLIBS = `pkg-config --libs $(PKGS)` $(LIBS) # build rules From 8bce3b1583977dee0c8a1815c558cae3b9346f67 Mon Sep 17 00:00:00 2001 From: Marco Siedentopf Date: Fri, 10 Jun 2022 01:30:22 +0000 Subject: [PATCH 174/329] add click method configuration option Add the libinput configuration option to choose between Software Button Areas and Clickfinger --- config.def.h | 7 +++++++ dwl.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/config.def.h b/config.def.h index 4f131dd..fabadb3 100644 --- a/config.def.h +++ b/config.def.h @@ -63,10 +63,17 @@ LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN */ static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; /* You can choose between: +LIBINPUT_CONFIG_CLICK_METHOD_NONE +LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS +LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER +*/ +static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; +/* You can choose between: LIBINPUT_CONFIG_SEND_EVENTS_ENABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE */ + static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; /* You can choose between: LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT diff --git a/dwl.c b/dwl.c index e4bed14..e0f7e99 100644 --- a/dwl.c +++ b/dwl.c @@ -1003,6 +1003,9 @@ createpointer(struct wlr_input_device *device) if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) libinput_device_config_scroll_set_method (libinput_device, scroll_method); + + if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (libinput_device, click_method); if (libinput_device_config_send_events_get_modes(libinput_device)) libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); From 583f471cfe61f9f92d238ad2d2d9a9db29e40aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 10 Jun 2022 12:32:22 -0500 Subject: [PATCH 175/329] add some blank lines --- config.def.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index fabadb3..a98ec36 100644 --- a/config.def.h +++ b/config.def.h @@ -62,19 +62,21 @@ LIBINPUT_CONFIG_SCROLL_EDGE LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN */ static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; + /* You can choose between: LIBINPUT_CONFIG_CLICK_METHOD_NONE LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER */ static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + /* You can choose between: LIBINPUT_CONFIG_SEND_EVENTS_ENABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE */ - static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + /* You can choose between: LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE From 671a9b450b636f5a2ebfefe159fea44e3b615fad Mon Sep 17 00:00:00 2001 From: Grant Nichol Date: Sun, 12 Jun 2022 15:41:43 -0500 Subject: [PATCH 176/329] Fix make install while files are in use When the dwl executable is in use, cp fails without the -f flag. POSIX defines this flag with: > If a file descriptor for a destination file cannot be obtained, > as described in step 3.a.ii., attempt to unlink the destination > file and proceed. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ac24ae7..2c1782b 100644 --- a/Makefile +++ b/Makefile @@ -56,10 +56,10 @@ dist: clean install: dwl mkdir -p $(DESTDIR)$(PREFIX)/bin - cp dwl $(DESTDIR)$(PREFIX)/bin + cp -f dwl $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl mkdir -p $(DESTDIR)$(MANDIR)/man1 - cp dwl.1 $(DESTDIR)$(MANDIR)/man1 + cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1 chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 From d26ddfc7fd36d420990eee94d3c4badb90217bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 13 Jun 2022 12:01:18 -0500 Subject: [PATCH 177/329] kill child process in cleanup() --- dwl.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dwl.c b/dwl.c index e0f7e99..8a85c79 100644 --- a/dwl.c +++ b/dwl.c @@ -297,6 +297,7 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; +static pid_t child_pid = -1; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; @@ -687,7 +688,10 @@ cleanup(void) wlr_xwayland_destroy(xwayland); #endif wl_display_destroy_clients(dpy); - + if (child_pid > 0) { + kill(child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); + } wlr_backend_destroy(backend); wlr_xcursor_manager_destroy(cursor_mgr); wlr_cursor_destroy(cursor); @@ -1753,8 +1757,6 @@ resize(Client *c, int x, int y, int w, int h, int interact) void run(char *startup_cmd) { - pid_t startup_pid = -1; - /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); if (!socket) @@ -1766,9 +1768,9 @@ run(char *startup_cmd) int piperw[2]; if (pipe(piperw) < 0) die("startup: pipe:"); - if ((startup_pid = fork()) < 0) + if ((child_pid = fork()) < 0) die("startup: fork:"); - if (startup_pid == 0) { + if (child_pid == 0) { dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); @@ -1804,11 +1806,6 @@ run(char *startup_cmd) * loop configuration to listen to libinput events, DRM events, generate * frame events at the refresh rate, and so on. */ wl_display_run(dpy); - - if (startup_cmd) { - kill(startup_pid, SIGTERM); - waitpid(startup_pid, NULL, 0); - } } Client * @@ -2120,10 +2117,12 @@ sigchld(int unused) * but the Xwayland implementation in wlroots currently prevents us from * setting our own disposition for SIGCHLD. */ + pid_t pid; if (signal(SIGCHLD, sigchld) == SIG_ERR) die("can't install SIGCHLD handler:"); - while (0 < waitpid(-1, NULL, WNOHANG)) - ; + while (0 < (pid = waitpid(-1, NULL, WNOHANG))) + if (pid == child_pid) + child_pid = -1; } void From 2ef5abfb728bbf157641becfe0db4d6e3d57bca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Jun 2022 15:36:27 -0500 Subject: [PATCH 178/329] remove unneeded check in focusclient() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8a85c79..d5bd989 100644 --- a/dwl.c +++ b/dwl.c @@ -1152,7 +1152,7 @@ focusclient(Client *c, int lift) return; } else { Client *w; - if (old->role_data && (w = client_from_wlr_surface(old))) + if ((w = client_from_wlr_surface(old))) for (i = 0; i < 4; i++) wlr_scene_rect_set_color(w->border[i], bordercolor); From 4ae6d0f3873451306e1ef04d88e0fab4e2b04548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Jun 2022 15:54:13 -0500 Subject: [PATCH 179/329] move ugglyness to client.h --- client.h | 11 +++++++++++ dwl.c | 10 +--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/client.h b/client.h index 6791a4d..d9bb7f3 100644 --- a/client.h +++ b/client.h @@ -231,6 +231,17 @@ client_min_size(Client *c, int *width, int *height) *height = state->min_height; } +static inline void +client_restack_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + wlr_xwayland_surface_restack(c->surface.xwayland, NULL, + XCB_STACK_MODE_ABOVE); +#endif + return; +} + static inline Client * client_from_wlr_surface(struct wlr_surface *s) { diff --git a/dwl.c b/dwl.c index d5bd989..04ba50f 100644 --- a/dwl.c +++ b/dwl.c @@ -1129,6 +1129,7 @@ focusclient(Client *c, int lift) wl_list_insert(&fstack, &c->flink); selmon = c->mon; c->isurgent = 0; + client_restack_surface(c); for (i = 0; i < 4; i++) wlr_scene_rect_set_color(c->border[i], focuscolor); @@ -1169,15 +1170,6 @@ focusclient(Client *c, int lift) return; } -#ifdef XWAYLAND - /* This resolves an issue where the last spawned xwayland client - * receives all pointer activity. - */ - if (c->type == X11Managed) - wlr_xwayland_surface_restack(c->surface.xwayland, NULL, - XCB_STACK_MODE_ABOVE); -#endif - /* Have a client, so focus its top-level wlr_surface */ kb = wlr_seat_get_keyboard(seat); if (kb) From 553ba5b7c8e6a6b119ca1c3f9839177c28a32d3d Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Thu, 16 Jun 2022 14:03:35 -0500 Subject: [PATCH 180/329] Add known dwl tag status bar options to README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 72488e3..55e977b 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,14 @@ If your startup command is a shell script, you can achieve the same inside the s exec <&- +Existing dwl-specific status bars and dwl-specific scripts for other status bars include: +- [somebar](https://sr.ht/~raphi/somebar/) status bar designed for dwl +- [dtaobarv2.sh](https://cdn.discordapp.com/attachments/792078050024095745/862428883423723560/dtaobarv2.sh) for use with [dtao](https://github.com/djpohly/dtao) (See "Pinned Messages" on the "customizations" channel of the [dwl Discord server](https://discord.gg/jJxZnrGPWN) for details.) +- [dwlbar.sh](https://cdn.discordapp.com/attachments/792078050024095745/810926218529472592/dwlbar.sh) for use with [waybar](https://github.com/Alexays/Waybar) (See "Pinned Messages" on the "customizations" channel of the [dwl Discord server](https://discord.gg/jJxZnrGPWN) for details.) +- [waybar-dwl](https://codeberg.org/fauxmight/waybar-dwl.git) for use with [waybar](https://github.com/Alexays/Waybar) +- [dwl-tags.sh](https://codeberg.org/novakane/yambar/src/branch/master/examples/scripts/dwl-tags.sh) for use with [yambar](https://codeberg.org/dnkl/yambar) +- [waybar-dwl.sh](https://gitee.com/guyuming76/personal/tree/dwl/gentoo/waybar-dwl) for use with [waybar](https://github.com/Alexays/Waybar) (ACCESS TO THIS SCRIPT REQUIRES gitee.com LOGIN!) + ## Replacements for X applications You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). From 79ad72413d8df7e184ff8f458d53a1f53a2cb878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 20 Jun 2022 18:05:16 -0500 Subject: [PATCH 181/329] don't set `c->isfullscreen` to zero calloc initializes all fields to zero --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index 04ba50f..8a9f97d 100644 --- a/dwl.c +++ b/dwl.c @@ -977,7 +977,6 @@ createnotify(struct wl_listener *listener, void *data) LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); - c->isfullscreen = 0; } void @@ -2468,7 +2467,6 @@ createnotifyx11(struct wl_listener *listener, void *data) c->surface.xwayland = xwayland_surface; c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; - c->isfullscreen = 0; /* Listen to the various events it can emit */ LISTEN(&xwayland_surface->events.map, &c->map, mapnotify); From 9b84940e37ec84933d1247bbf3eb76d9efe7c589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 20 Jun 2022 23:46:11 -0500 Subject: [PATCH 182/329] unconstrain layer shell popups also unconstrain popups from monitor's usable area --- client.h | 8 +++++--- dwl.c | 33 ++++++++++++++++----------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/client.h b/client.h index d9bb7f3..4112fd6 100644 --- a/client.h +++ b/client.h @@ -261,15 +261,17 @@ client_from_wlr_surface(struct wlr_surface *s) return NULL; } -static inline Client * -client_from_popup(struct wlr_xdg_popup *popup) +static inline void * +toplevel_from_popup(struct wlr_xdg_popup *popup) { struct wlr_xdg_surface *surface = popup->base; while (1) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_POPUP: - if (!wlr_surface_is_xdg_surface(surface->popup->parent)) + if (wlr_surface_is_layer_surface(surface->popup->parent)) + return wlr_layer_surface_v1_from_wlr_surface(surface->popup->parent)->data; + else if (!wlr_surface_is_xdg_surface(surface->popup->parent)) return NULL; surface = wlr_xdg_surface_from_wlr_surface(surface->popup->parent); diff --git a/dwl.c b/dwl.c index 8a9f97d..0eb8fdb 100644 --- a/dwl.c +++ b/dwl.c @@ -90,8 +90,10 @@ typedef struct { typedef struct Monitor Monitor; typedef struct { - /* Must be first */ + /* Must keep these three elements in this order */ unsigned int type; /* XDGShell or X11* */ + struct wlr_box geom; /* layout-relative, includes border */ + Monitor *mon; struct wlr_scene_node *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ struct wlr_scene_node *scene_surface; @@ -107,8 +109,7 @@ typedef struct { struct wl_listener destroy; struct wl_listener set_title; struct wl_listener fullscreen; - struct wlr_box geom, prev; /* layout-relative, includes border */ - Monitor *mon; + struct wlr_box prev; /* layout-relative, includes border */ #ifdef XWAYLAND struct wl_listener activate; struct wl_listener configure; @@ -146,19 +147,19 @@ typedef struct { } Keyboard; typedef struct { - /* Must be first */ + /* Must keep these three elements in this order */ unsigned int type; /* LayerShell */ - int mapped; + struct wlr_box geom; + Monitor *mon; struct wlr_scene_node *scene; struct wl_list link; + int mapped; struct wlr_layer_surface_v1 *layer_surface; struct wl_listener destroy; struct wl_listener map; struct wl_listener unmap; struct wl_listener surface_commit; - - struct wlr_box geo; } LayerSurface; typedef struct { @@ -559,7 +560,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wlr_layer_surface_v1_destroy(wlr_layer_surface); continue; } - layersurface->geo = box; + layersurface->geom = box; if (state->exclusive_zone > 0) applyexclusive(usable_area, state->anchor, state->exclusive_zone, @@ -835,7 +836,6 @@ createlayersurface(struct wl_listener *listener, void *data) { struct wlr_layer_surface_v1 *wlr_layer_surface = data; LayerSurface *layersurface; - Monitor *m; struct wlr_layer_surface_v1_state old_state; if (!wlr_layer_surface->output) { @@ -855,14 +855,14 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->layer_surface = wlr_layer_surface; wlr_layer_surface->data = layersurface; - m = wlr_layer_surface->output->data; + layersurface->mon = wlr_layer_surface->output->data; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], wlr_layer_surface->surface); layersurface->scene->data = layersurface; - wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], &layersurface->link); /* Temporarily set the layer's current state to pending @@ -870,7 +870,7 @@ createlayersurface(struct wl_listener *listener, void *data) */ old_state = wlr_layer_surface->current; wlr_layer_surface->current = wlr_layer_surface->pending; - arrangelayers(m); + arrangelayers(layersurface->mon); wlr_layer_surface->current = old_state; } @@ -955,9 +955,9 @@ createnotify(struct wl_listener *listener, void *data) struct wlr_box box; xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); - if (!(c = client_from_popup(xdg_surface->popup)) || !c->mon) + if (!(c = toplevel_from_popup(xdg_surface->popup)) || !c->mon) return; - box = c->mon->m; + box = c->mon->w; box.x -= c->geom.x; box.y -= c->geom.y; wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); @@ -1055,9 +1055,8 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(layersurface->scene); if (layersurface->layer_surface->output) { - Monitor *m = layersurface->layer_surface->output->data; - if (m) - arrangelayers(m); + if (layersurface->mon) + arrangelayers(layersurface->mon); layersurface->layer_surface->output = NULL; } free(layersurface); From c1578bc14db7822743ffdbde93b2c22b1a0b5f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Jun 2022 16:03:20 -0500 Subject: [PATCH 183/329] use LayerSurface.mon when possible --- dwl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 0eb8fdb..3ccf9bc 100644 --- a/dwl.c +++ b/dwl.c @@ -759,14 +759,13 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_output *wlr_output = wlr_layer_surface->output; - Monitor *m; + + if (!wlr_output || !(layersurface->mon = wlr_output->data)) + return; wlr_scene_node_reparent(layersurface->scene, layers[wlr_layer_surface->current.layer]); - if (!wlr_output || !(m = wlr_output->data)) - return; - if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; @@ -775,10 +774,10 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { wl_list_remove(&layersurface->link); - wl_list_insert(&m->layers[wlr_layer_surface->current.layer], + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], &layersurface->link); } - arrangelayers(m); + arrangelayers(layersurface->mon); } void @@ -1055,7 +1054,7 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(layersurface->scene); if (layersurface->layer_surface->output) { - if (layersurface->mon) + if ((layersurface->mon = layersurface->layer_surface->output->data)) arrangelayers(layersurface->mon); layersurface->layer_surface->output = NULL; } @@ -1361,8 +1360,9 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, map); + layersurface->mon = layersurface->layer_surface->output->data; wlr_surface_send_enter(layersurface->layer_surface->surface, - layersurface->layer_surface->output); + layersurface->mon->wlr_output); motionnotify(0); } From 461d02d3e03a5f0dc42fbb71dd8ab728b9c7e424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Jun 2022 16:25:18 -0500 Subject: [PATCH 184/329] chase wlroots input_device changes --- dwl.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index b56abd7..beab572 100644 --- a/dwl.c +++ b/dwl.c @@ -575,8 +575,7 @@ cleanup(void) void cleanupkeyboard(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - Keyboard *kb = device->keyboard->data; + Keyboard *kb = wlr_keyboard_from_input_device(data)->data; wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); @@ -1118,10 +1117,10 @@ inputdevice(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(device->keyboard); + createkeyboard(wlr_keyboard_from_input_device(device)); break; case WLR_INPUT_DEVICE_POINTER: - createpointer(device->pointer); + createpointer(wlr_pointer_from_input_device(device)); break; default: /* TODO handle other input device types */ @@ -2230,8 +2229,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->keyboard.base; - createkeyboard(device->keyboard); + createkeyboard(&keyboard->keyboard); } Monitor * From 097b4a30f5906fb45ce805115dd9dde48aefe60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 24 Jun 2022 14:30:52 -0500 Subject: [PATCH 185/329] unconstrain layer shell popups from monitor size unconstrain other popups from monitor usable area --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 3ccf9bc..5f4d5fd 100644 --- a/dwl.c +++ b/dwl.c @@ -956,7 +956,7 @@ createnotify(struct wl_listener *listener, void *data) xdg_surface->popup->parent->data, xdg_surface); if (!(c = toplevel_from_popup(xdg_surface->popup)) || !c->mon) return; - box = c->mon->w; + box = c->type == LayerShell ? c->mon->m : c->mon->w; box.x -= c->geom.x; box.y -= c->geom.y; wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); From 549335ae5458834f91a59ee14f385d17b2d4f888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 24 Jun 2022 14:46:08 -0500 Subject: [PATCH 186/329] avoid layer surface popups appearing below x{dg,wayland} clients --- dwl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5f4d5fd..0d4163e 100644 --- a/dwl.c +++ b/dwl.c @@ -952,9 +952,14 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; + LayerSurface *l; + void *toplevel = toplevel_from_popup(xdg_surface->popup); xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); - if (!(c = toplevel_from_popup(xdg_surface->popup)) || !c->mon) + if (wlr_surface_is_layer_surface(xdg_surface->popup->parent) && (l = toplevel) + && l->layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + wlr_scene_node_reparent(xdg_surface->surface->data, layers[LyrTop]); + if (!(c = toplevel) || !c->mon) return; box = c->type == LayerShell ? c->mon->m : c->mon->w; box.x -= c->geom.x; From 2aa391361c877f3319050e57c828e065a61d9d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 24 Jun 2022 15:36:13 -0500 Subject: [PATCH 187/329] inline unmaplayersurface() into unmaplayersurfacenotify() unmap signal is guaranted to be emitted before destroy signal so is useless checking if it is mapped at destroy --- dwl.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index 0d4163e..e349d8b 100644 --- a/dwl.c +++ b/dwl.c @@ -283,7 +283,6 @@ static void togglefloating(const Arg *arg); static void togglefullscreen(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); -static void unmaplayersurface(LayerSurface *layersurface); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); static void updatemons(struct wl_listener *listener, void *data); @@ -1050,8 +1049,6 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); - if (layersurface->layer_surface->mapped) - unmaplayersurface(layersurface); wl_list_remove(&layersurface->link); wl_list_remove(&layersurface->destroy.link); wl_list_remove(&layersurface->map.link); @@ -2245,8 +2242,10 @@ toggleview(const Arg *arg) } void -unmaplayersurface(LayerSurface *layersurface) +unmaplayersurfacenotify(struct wl_listener *listener, void *data) { + LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); + layersurface->layer_surface->mapped = (layersurface->mapped = 0); wlr_scene_node_set_enabled(layersurface->scene, 0); if (layersurface->layer_surface->surface == @@ -2255,13 +2254,6 @@ unmaplayersurface(LayerSurface *layersurface) motionnotify(0); } -void -unmaplayersurfacenotify(struct wl_listener *listener, void *data) -{ - LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); - unmaplayersurface(layersurface); -} - void unmapnotify(struct wl_listener *listener, void *data) { From 72e0a560d9836c5e8658003f548203bcd722e565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 24 Jun 2022 19:15:24 -0500 Subject: [PATCH 188/329] respect size hints --- client.h | 83 ++++++++++++++++++++++++++------------------------------ dwl.c | 18 +++++++----- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/client.h b/client.h index 4112fd6..7301d25 100644 --- a/client.h +++ b/client.h @@ -81,6 +81,32 @@ client_get_geometry(Client *c, struct wlr_box *geom) wlr_xdg_surface_get_geometry(c->surface.xdg, geom); } +static inline void +client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) +{ + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state *state; +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface_size_hints *size_hints; + size_hints = c->surface.xwayland->size_hints; + if (size_hints) { + max->width = size_hints->max_width; + max->height = size_hints->max_height; + min->width = size_hints->min_width; + min->height = size_hints->min_height; + } + return; + } +#endif + toplevel = c->surface.xdg->toplevel; + state = &toplevel->current; + max->width = state->max_width; + max->height = state->max_height; + min->width = state->min_width; + min->height = state->min_height; +} + static inline const char * client_get_title(Client *c) { @@ -94,39 +120,31 @@ client_get_title(Client *c) static inline int client_is_float_type(Client *c) { - struct wlr_xdg_toplevel *toplevel; - struct wlr_xdg_toplevel_state state; + struct wlr_box min = {0}, max = {0}; + client_get_size_hints(c, &max, &min); #ifdef XWAYLAND if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; - struct wlr_xwayland_surface_size_hints *size_hints; if (surface->modal) return 1; for (size_t i = 0; i < surface->window_type_len; i++) - if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] || - surface->window_type[i] == netatom[NetWMWindowTypeSplash] || - surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || - surface->window_type[i] == netatom[NetWMWindowTypeUtility]) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] + || surface->window_type[i] == netatom[NetWMWindowTypeSplash] + || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] + || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; - size_hints = surface->size_hints; - if (size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 - && (size_hints->max_width == size_hints->min_width || - size_hints->max_height == size_hints->min_height)) - return 1; - - return 0; + return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) + && (min.width == max.width || min.height == max.height)) + || c->surface.xwayland->parent; } #endif - toplevel = c->surface.xdg->toplevel; - state = toplevel->current; - return (state.min_width != 0 && state.min_height != 0 - && (state.min_width == state.max_width - || state.min_height == state.max_height)) - || toplevel->parent; + return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) + && (min.width == max.width || min.height == max.height)) + || c->surface.xdg->toplevel->parent; } static inline int @@ -206,31 +224,6 @@ client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); } -static inline void -client_min_size(Client *c, int *width, int *height) -{ - struct wlr_xdg_toplevel *toplevel; - struct wlr_xdg_toplevel_state *state; -#ifdef XWAYLAND - if (client_is_x11(c)) { - struct wlr_xwayland_surface_size_hints *size_hints; - size_hints = c->surface.xwayland->size_hints; - if (size_hints) { - *width = size_hints->min_width; - *height = size_hints->min_height; - } else { - *width = 0; - *height = 0; - } - return; - } -#endif - toplevel = c->surface.xdg->toplevel; - state = &toplevel->current; - *width = state->min_width; - *height = state->min_height; -} - static inline void client_restack_surface(Client *c) { diff --git a/dwl.c b/dwl.c index e349d8b..36a7543 100644 --- a/dwl.c +++ b/dwl.c @@ -381,9 +381,15 @@ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; void applybounds(Client *c, struct wlr_box *bbox) { - /* set minimum possible */ - c->geom.width = MAX(1, c->geom.width); - c->geom.height = MAX(1, c->geom.height); + struct wlr_box min = {0}, max = {0}; + client_get_size_hints(c, &max, &min); + /* try to set size hints */ + c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); + c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); + if (max.width > 0) + c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); + if (max.height > 0) + c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; @@ -1721,13 +1727,11 @@ requeststartdrag(struct wl_listener *listener, void *data) void resize(Client *c, int x, int y, int w, int h, int interact) { - int min_width = 0, min_height = 0; struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; - client_min_size(c, &min_width, &min_height); c->geom.x = x; c->geom.y = y; - c->geom.width = MAX(min_width + 2 * c->bw, w); - c->geom.height = MAX(min_height + 2 * c->bw, h); + c->geom.width = w; + c->geom.height = h; applybounds(c, bbox); /* Update scene-graph, including borders */ From 7cc6c640e2412935bf195ec55dafeb5852c71dd1 Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Tue, 28 Jun 2022 20:14:23 +0200 Subject: [PATCH 189/329] Checks for overflows for client max width and height --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 36a7543..393e80f 100644 --- a/dwl.c +++ b/dwl.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -386,9 +387,9 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); - if (max.width > 0) + if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) // Checks for overflow c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); - if (max.height > 0) + if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) // Checks for overflow c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); if (c->geom.x >= bbox->x + bbox->width) From ff70337c163dfadea2c997a9b030e978fb463c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 6 Jul 2022 19:14:12 -0500 Subject: [PATCH 190/329] check current and pending geometry to set c->resize to zero Fixes #260 --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 393e80f..675f4fc 100644 --- a/dwl.c +++ b/dwl.c @@ -792,10 +792,10 @@ commitnotify(struct wl_listener *listener, void *data) Client *c = wl_container_of(listener, c, commit); /* mark a pending resize as completed */ - if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) + if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial + || (c->surface.xdg->current.geometry.width == c->surface.xdg->pending.geometry.width + && c->surface.xdg->current.geometry.height == c->surface.xdg->pending.geometry.height))) c->resize = 0; - else if (c->resize) - c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); } void From 829dec659875d19db08bb4e4334cecb087895fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 24 Jun 2022 19:41:26 -0500 Subject: [PATCH 191/329] resize now takes `struct wlr_box` as parameter --- dwl.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/dwl.c b/dwl.c index 675f4fc..cb71aae 100644 --- a/dwl.c +++ b/dwl.c @@ -262,7 +262,7 @@ static void quit(const Arg *arg); static void quitsignal(int signo); static void rendermon(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); -static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resize(Client *c, struct wlr_box geo, int interact); static void run(char *startup_cmd); static Client *selclient(void); static void setcursor(struct wl_listener *listener, void *data); @@ -751,8 +751,8 @@ closemon(Monitor *m) wl_list_for_each(c, &clients, link) { if (c->isfloating && c->geom.x > m->m.width) - resize(c, c->geom.x - m->w.width, c->geom.y, - c->geom.width, c->geom.height, 0); + resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y, + .width = c->geom.width, .height = c->geom.height}, 0); if (c->mon == m) setmon(c, selmon, c->tags); } @@ -1434,7 +1434,7 @@ monocle(Monitor *m) wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) continue; - resize(c, m->w.x, m->w.y, m->w.width, m->w.height, 0); + resize(c, m->w, 0); } focusclient(focustop(m), 1); } @@ -1476,13 +1476,12 @@ motionnotify(uint32_t time) /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ - resize(grabc, cursor->x - grabcx, cursor->y - grabcy, - grabc->geom.width, grabc->geom.height, 1); + resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy, + .width = grabc->geom.width, .height = grabc->geom.height}, 1); return; } else if (cursor_mode == CurResize) { - resize(grabc, grabc->geom.x, grabc->geom.y, - cursor->x - grabc->geom.x, - cursor->y - grabc->geom.y, 1); + resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, + .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1); return; } @@ -1726,13 +1725,10 @@ requeststartdrag(struct wl_listener *listener, void *data) } void -resize(Client *c, int x, int y, int w, int h, int interact) +resize(Client *c, struct wlr_box geo, int interact) { struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; - c->geom.x = x; - c->geom.y = y; - c->geom.width = w; - c->geom.height = h; + c->geom = geo; applybounds(c, bbox); /* Update scene-graph, including borders */ @@ -1851,11 +1847,11 @@ setfullscreen(Client *c, int fullscreen) if (fullscreen) { c->prev = c->geom; - resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0); + resize(c, c->mon->m, 0); } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ - resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0); + resize(c, c->prev, 0); } arrange(c->mon); printstatus(); @@ -1904,7 +1900,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) } if (m) { /* Make sure window actually overlaps with the monitor */ - resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0); + resize(c, c->geom, 0); wlr_surface_send_enter(client_surface(c), m->wlr_output); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ arrange(m); @@ -2170,7 +2166,7 @@ tagmon(const Arg *arg) void tile(Monitor *m) { - unsigned int i, n = 0, h, mw, my, ty; + unsigned int i, n = 0, mw, my, ty; Client *c; wl_list_for_each(c, &clients, link) @@ -2188,12 +2184,12 @@ tile(Monitor *m) if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) continue; if (i < m->nmaster) { - h = (m->w.height - my) / (MIN(n, m->nmaster) - i); - resize(c, m->w.x, m->w.y + my, mw, h, 0); + resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw, + .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0); my += c->geom.height; } else { - h = (m->w.height - ty) / (n - i); - resize(c, m->w.x + mw, m->w.y + ty, m->w.width - mw, h, 0); + resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty, + .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0); ty += c->geom.height; } i++; From c6d97f1db741185841c20f3c1771e359acc9b66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 1 Apr 2022 14:03:52 -0600 Subject: [PATCH 192/329] arrange client's monitor if size has change since last commit --- dwl.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index cb71aae..c66d3d9 100644 --- a/dwl.c +++ b/dwl.c @@ -790,6 +790,12 @@ void commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); + struct wlr_box box; + client_get_geometry(c, &box); + + if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw + || box.height != c->geom.height - 2 * c->bw)) + arrange(c->mon); /* mark a pending resize as completed */ if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial @@ -980,7 +986,6 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; - LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); @@ -1085,9 +1090,8 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->configure.link); wl_list_remove(&c->set_hints.link); wl_list_remove(&c->activate.link); - } else + } #endif - wl_list_remove(&c->commit.link); free(c); } @@ -1387,8 +1391,14 @@ mapnotify(struct wl_listener *listener, void *data) c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - if (client_surface(c)) + if (client_surface(c)) { client_surface(c)->data = c->scene; + /* Ideally we should do this in createnotify{,x11} but at that moment + * wlr_xwayland_surface doesn't have wlr_surface yet + */ + LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); + + } c->scene->data = c->scene_surface->data = c; if (client_is_unmanaged(c)) { @@ -2276,6 +2286,7 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); + wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); } From 0eff78d6c268f7dc1a16861f051d9cd2108161a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 6 Jul 2022 23:28:49 -0500 Subject: [PATCH 193/329] include DWLCFLAGS into linking step --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2c1782b..6a8323b 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ LDLIBS = `pkg-config --libs $(PKGS)` $(LIBS) # to your build system yourself and provide them in the include path. all: dwl dwl: dwl.o util.o - $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) -o $@ + $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h util.o: util.c util.h From 87fc3a58ab72ff6ff6eb6e1156ff208fcb9e3739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 6 Jul 2022 23:48:53 -0500 Subject: [PATCH 194/329] check pointer focus in arrange() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index c66d3d9..7a585d5 100644 --- a/dwl.c +++ b/dwl.c @@ -496,7 +496,7 @@ arrange(Monitor *m) if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); - /* TODO recheck pointer focus here... or in resize()? */ + motionnotify(0); } void From 8e03bce6217117f0687cd727ae2c47bdd3c0fe5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Jul 2022 00:21:51 -0500 Subject: [PATCH 195/329] only call wlr_seat_keyboard_notify_enter() if a keyboard is found --- dwl.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dwl.c b/dwl.c index 7a585d5..0c80691 100644 --- a/dwl.c +++ b/dwl.c @@ -613,8 +613,6 @@ arrangelayers(Monitor *m) if (kb) wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); - else - wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, NULL, 0, NULL); return; } } @@ -1185,8 +1183,6 @@ focusclient(Client *c, int lift) if (kb) wlr_seat_keyboard_notify_enter(seat, client_surface(c), kb->keycodes, kb->num_keycodes, &kb->modifiers); - else - wlr_seat_keyboard_notify_enter(seat, client_surface(c), NULL, 0, NULL); /* Activate the new client */ client_activate_surface(client_surface(c), 1); From af12e777f2eaf3237e4e95945646ef676d466e6e Mon Sep 17 00:00:00 2001 From: David-Valters <46930139+David-Valters@users.noreply.github.com> Date: Wed, 13 Jul 2022 14:40:49 +0300 Subject: [PATCH 196/329] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 55e977b..dd986b7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,9 @@ Feature *non-goals* for the main codebase include: ## Building dwl -dwl has only two dependencies: wlroots and wayland-protocols. Simply install these (and their `-devel` versions if your distro has separate development packages) and run `make`. If you wish to build against a Git version of wlroots, check out the [wlroots-next branch](https://github.com/djpohly/dwl/tree/wlroots-next). +dwl has only two dependencies: `wlroots` and `wayland-protocols`. + +Simply install these (and their `-devel` versions if your distro has separate development packages) and run `make`. If you wish to build against a Git version of wlroots, check out the [wlroots-next branch](https://github.com/djpohly/dwl/tree/wlroots-next). To enable XWayland, you should also install xorg-xwayland and uncomment its flag in `config.mk`. From 058c699ac2552db13ea8bbef64182c59cceaf55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 15 Jul 2022 00:27:31 -0500 Subject: [PATCH 197/329] only set bounds for clients that support it --- client.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 9431d11..978c8e1 100644 --- a/client.h +++ b/client.h @@ -52,7 +52,10 @@ client_set_bounds(Client *c, int32_t width, int32_t height) if (client_is_x11(c)) return 0; #endif - return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + if (c->surface.xdg->client->shell->version >= + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) + return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + return 0; } static inline void From e98719f5523597d02e82632a4af2676a1299497e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 15 Jul 2022 00:48:28 -0500 Subject: [PATCH 198/329] remove a useless check if `s->role_data == NULL`, wlr_*_surface_from_wlr_surface() will return NULL and we are checking it --- client.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.h b/client.h index 7301d25..681f842 100644 --- a/client.h +++ b/client.h @@ -242,11 +242,11 @@ client_from_wlr_surface(struct wlr_surface *s) #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; - if (s->role_data && wlr_surface_is_xwayland_surface(s) + if (wlr_surface_is_xwayland_surface(s) && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) return xsurface->data; #endif - if (s->role_data && wlr_surface_is_xdg_surface(s) + if (wlr_surface_is_xdg_surface(s) && (surface = wlr_xdg_surface_from_wlr_surface(s)) && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) return surface->data; From c70db2d06a7c868ba2d36de0984f5b39afd1a1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 19 Jul 2022 11:52:15 -0500 Subject: [PATCH 199/329] Revert "only call wlr_seat_keyboard_notify_enter() if a keyboard is found" This reverts commit 8e03bce6217117f0687cd727ae2c47bdd3c0fe5a. fixes #270 --- dwl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwl.c b/dwl.c index 0c80691..7a585d5 100644 --- a/dwl.c +++ b/dwl.c @@ -613,6 +613,8 @@ arrangelayers(Monitor *m) if (kb) wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, NULL, 0, NULL); return; } } @@ -1183,6 +1185,8 @@ focusclient(Client *c, int lift) if (kb) wlr_seat_keyboard_notify_enter(seat, client_surface(c), kb->keycodes, kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, client_surface(c), NULL, 0, NULL); /* Activate the new client */ client_activate_surface(client_surface(c), 1); From deb48ff48b186ff77a7e9d3b3ab724ff4c3c340f Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Tue, 19 Jul 2022 20:12:03 +0300 Subject: [PATCH 200/329] force line-buffered stdout if stdout is not a tty --- dwl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 7a585d5..6464289 100644 --- a/dwl.c +++ b/dwl.c @@ -1674,7 +1674,6 @@ printstatus(void) sel, urg); printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); } - fflush(stdout); } void @@ -1943,6 +1942,9 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { + /* Force line-buffered stdout */ + setvbuf(stdout, NULL, _IOLBF, 0); + /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); From e0822926068e84b0fc391e0306f66ea0ec16cf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 20 Jun 2022 18:33:14 -0500 Subject: [PATCH 201/329] do not focus clients if a layer surface is focused --- dwl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 6464289..65d7e24 100644 --- a/dwl.c +++ b/dwl.c @@ -299,6 +299,7 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; static pid_t child_pid = -1; +static struct wlr_surface *exclusive_focus; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; @@ -610,11 +611,12 @@ arrangelayers(Monitor *m) layersurface->layer_surface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); + exclusive_focus = layersurface->layer_surface->surface; if (kb) - wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, + wlr_seat_keyboard_notify_enter(seat, exclusive_focus, kb->keycodes, kb->num_keycodes, &kb->modifiers); else - wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, NULL, 0, NULL); + wlr_seat_keyboard_notify_enter(seat, exclusive_focus, NULL, 0, NULL); return; } } @@ -1125,6 +1127,9 @@ focusclient(Client *c, int lift) struct wlr_surface *old = seat->keyboard_state.focused_surface; struct wlr_keyboard *kb; int i; + /* Do not focus clients if a layer surface is focused */ + if (exclusive_focus) + return; /* Raise client in stacking order if requested */ if (c && lift) @@ -2261,6 +2266,8 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) layersurface->layer_surface->mapped = (layersurface->mapped = 0); wlr_scene_node_set_enabled(layersurface->scene, 0); + if (layersurface->layer_surface->surface == exclusive_focus) + exclusive_focus = NULL; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(selclient(), 1); From 90a12c90a0aa0ac16327b0816de4d9dff69b357e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 19 Jul 2022 20:13:56 -0500 Subject: [PATCH 202/329] always set the same monitor and tags for child clients of a client fixes #272 --- client.h | 52 +++++++++++++++++++++++++++++++++------------------- dwl.c | 11 +++++++++-- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/client.h b/client.h index 681f842..dc4a6c4 100644 --- a/client.h +++ b/client.h @@ -26,6 +26,25 @@ client_surface(Client *c) return c->surface.xdg->surface; } +static inline Client * +client_from_wlr_surface(struct wlr_surface *s) +{ + struct wlr_xdg_surface *surface; + +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; + if (s && wlr_surface_is_xwayland_surface(s) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) + return xsurface->data; +#endif + if (s && wlr_surface_is_xdg_surface(s) + && (surface = wlr_xdg_surface_from_wlr_surface(s)) + && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) + return surface->data; + + return NULL; +} + /* The others */ static inline void client_activate_surface(struct wlr_surface *s, int activated) @@ -117,6 +136,20 @@ client_get_title(Client *c) return c->surface.xdg->toplevel->title; } +static inline Client * +client_get_parent(Client *c) +{ + Client *p; +#ifdef XWAYLAND + if (client_is_x11(c) && c->surface.xwayland->parent) + return client_from_wlr_surface(c->surface.xwayland->parent->surface); +#endif + if (c->surface.xdg->toplevel->parent) + return client_from_wlr_surface(c->surface.xdg->toplevel->parent->surface); + + return NULL; +} + static inline int client_is_float_type(Client *c) { @@ -235,25 +268,6 @@ client_restack_surface(Client *c) return; } -static inline Client * -client_from_wlr_surface(struct wlr_surface *s) -{ - struct wlr_xdg_surface *surface; - -#ifdef XWAYLAND - struct wlr_xwayland_surface *xsurface; - if (wlr_surface_is_xwayland_surface(s) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) - return xsurface->data; -#endif - if (wlr_surface_is_xdg_surface(s) - && (surface = wlr_xdg_surface_from_wlr_surface(s)) - && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) - return surface->data; - - return NULL; -} - static inline void * toplevel_from_popup(struct wlr_xdg_popup *popup) { diff --git a/dwl.c b/dwl.c index 65d7e24..727e6e1 100644 --- a/dwl.c +++ b/dwl.c @@ -1388,7 +1388,7 @@ void mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ - Client *c = wl_container_of(listener, c, map); + Client *p, *c = wl_container_of(listener, c, map); int i; /* Create scene tree for this client and its border */ @@ -1432,7 +1432,14 @@ mapnotify(struct wl_listener *listener, void *data) wl_list_insert(&fstack, &c->flink); /* Set initial monitor, tags, floating status, and focus */ - applyrules(c); + if ((p = client_get_parent(c))) { + /* Set the same monitor and tags than its parent */ + c->isfloating = 1; + wlr_scene_node_reparent(c->scene, layers[LyrFloat]); + setmon(c, p->mon, p->tags); + } else { + applyrules(c); + } printstatus(); if (c->isfullscreen) From 8cdb9971264adfdc35777b5a9935c2e4c47eea9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 23 Jul 2022 02:08:10 -0500 Subject: [PATCH 203/329] conform the xdg-protocol with fullscreen translucent clients see `setfullscreen()` for more info --- config.def.h | 2 ++ dwl.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/config.def.h b/config.def.h index 43f35cd..29c6dbf 100644 --- a/config.def.h +++ b/config.def.h @@ -5,6 +5,8 @@ static const int lockfullscreen = 1; /* 1 will force focus on the fullscree static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ +static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; diff --git a/dwl.c b/dwl.c index 727e6e1..35c72f0 100644 --- a/dwl.c +++ b/dwl.c @@ -98,6 +98,7 @@ typedef struct { struct wlr_scene_node *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ struct wlr_scene_node *scene_surface; + struct wlr_scene_rect *fullscreen_bg; /* See setfullscreen() for info */ struct wl_list link; struct wl_list flink; union { @@ -1869,10 +1870,23 @@ setfullscreen(Client *c, int fullscreen) if (fullscreen) { c->prev = c->geom; resize(c, c->mon->m, 0); + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + * For brevity we set a black background for all clients + */ + c->fullscreen_bg = wlr_scene_rect_create(c->scene, + c->geom.width, c->geom.height, fullscreen_bg); + wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ resize(c, c->prev, 0); + wlr_scene_node_destroy(&c->fullscreen_bg->node); } arrange(c->mon); printstatus(); From b04c73be3de62d2739b5bb85e40f0c9af1122903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 23 Jul 2022 13:25:47 -0500 Subject: [PATCH 204/329] make sure we do not create a double fullscreen_bg and also make sure we do not destroy it if it does not exist Fixes: #274 --- dwl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 35c72f0..7886b64 100644 --- a/dwl.c +++ b/dwl.c @@ -1879,14 +1879,19 @@ setfullscreen(Client *c, int fullscreen) * * For brevity we set a black background for all clients */ - c->fullscreen_bg = wlr_scene_rect_create(c->scene, - c->geom.width, c->geom.height, fullscreen_bg); - wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); + if (!c->fullscreen_bg) { + c->fullscreen_bg = wlr_scene_rect_create(c->scene, + c->geom.width, c->geom.height, fullscreen_bg); + wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); + } } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ resize(c, c->prev, 0); - wlr_scene_node_destroy(&c->fullscreen_bg->node); + if (c->fullscreen_bg) { + wlr_scene_node_destroy(&c->fullscreen_bg->node); + c->fullscreen_bg = NULL; + } } arrange(c->mon); printstatus(); From 7eee0a8229f2debed4ca552d0de5d7fe8a5721a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 24 Jul 2022 16:43:13 -0500 Subject: [PATCH 205/329] use the layer surface to create popups --- dwl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index 7886b64..42cd806 100644 --- a/dwl.c +++ b/dwl.c @@ -967,18 +967,17 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; - LayerSurface *l; - void *toplevel = toplevel_from_popup(xdg_surface->popup); + LayerSurface *l = toplevel_from_popup(xdg_surface->popup); xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); - if (wlr_surface_is_layer_surface(xdg_surface->popup->parent) && (l = toplevel) + if (wlr_surface_is_layer_surface(xdg_surface->popup->parent) && l && l->layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) wlr_scene_node_reparent(xdg_surface->surface->data, layers[LyrTop]); - if (!(c = toplevel) || !c->mon) + if (!l || !l->mon) return; - box = c->type == LayerShell ? c->mon->m : c->mon->w; - box.x -= c->geom.x; - box.y -= c->geom.y; + box = l->type == LayerShell ? l->mon->m : l->mon->w; + box.x -= l->geom.x; + box.y -= l->geom.y; wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); return; } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) From 9d2eb8483b52a7a4858454d557196d83e1a24011 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Mon, 25 Jul 2022 08:14:33 +0300 Subject: [PATCH 206/329] fix segfault if parent->mon is unset --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 42cd806..d580b2d 100644 --- a/dwl.c +++ b/dwl.c @@ -1436,7 +1436,8 @@ mapnotify(struct wl_listener *listener, void *data) /* Set the same monitor and tags than its parent */ c->isfloating = 1; wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - setmon(c, p->mon, p->tags); + /* TODO recheck if !p->mon is possible with wlroots 0.16.0 */ + setmon(c, p->mon ? p->mon : selmon, p->tags); } else { applyrules(c); } From 662e06e68e9bc2c41c3cb90d36c4d9998ff1f958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 30 Jul 2022 14:44:17 -0500 Subject: [PATCH 207/329] check client_from_wlr_surface() returning NULL in urgent() fix #281 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index d580b2d..039b8ff 100644 --- a/dwl.c +++ b/dwl.c @@ -2377,7 +2377,7 @@ urgent(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *c = client_from_wlr_surface(event->surface); - if (c != selclient()) { + if (c && c != selclient()) { c->isurgent = 1; printstatus(); } From 620fd9dc5666f11b322a7088a220f408636a77e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 8 Aug 2022 21:19:16 -0500 Subject: [PATCH 208/329] use `git describe` to generate version --- config.mk | 2 +- generate-version.sh | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100755 generate-version.sh diff --git a/config.mk b/config.mk index ba24bb8..4638d5f 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ _VERSION = 0.3.1 -VERSION = `./generate-version.sh $(_VERSION)` +VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` # paths PREFIX = /usr/local diff --git a/generate-version.sh b/generate-version.sh deleted file mode 100755 index cf408e1..0000000 --- a/generate-version.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -if git tag --contains HEAD | grep -q $1; then - echo $1 -else - branch="$(git rev-parse --abbrev-ref HEAD)" - commit="$(git rev-parse --short HEAD)" - if [ "${branch}" != "main" ]; then - echo $1-$branch-$commit - else - echo $1-$commit - fi -fi From 6ce035303e686d976b98fa887231c0a23690aefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 8 Aug 2022 21:30:37 -0500 Subject: [PATCH 209/329] fix dist target --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6a8323b..1bdc7d6 100644 --- a/Makefile +++ b/Makefile @@ -45,10 +45,9 @@ clean: # distribution archive dist: clean mkdir -p dwl-$(VERSION) - cp -R LICENSE* Makefile README.md generate-version.sh client.h\ - config.def.h config.mk protocols dwl.1 dwl.c util.c util.h\ + cp -R LICENSE* Makefile README.md client.h config.def.h\ + config.mk protocols dwl.1 dwl.c util.c util.h\ dwl-$(VERSION) - echo "echo $(VERSION)" > dwl-$(VERSION)/generate-version.sh tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) rm -rf dwl-$(VERSION) From 3431ac165dfa46fbee1e2857ffe9dd19c86c4050 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 5 Aug 2022 13:00:59 -0500 Subject: [PATCH 210/329] 2200: let's use this wisely Looks like [suckless-dev] was right about one thing. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd986b7..887bf29 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ dwl is a compact, hackable compositor for Wayland based on [wlroots](https://git - Easy to understand, hack on, and extend with patches - One C source file (or a very small number) configurable via `config.h` -- Limited to 2000 SLOC to promote hackability +- Limited to 2200 SLOC to promote hackability - Tied to as few external dependencies as possible dwl is not meant to provide every feature under the sun. Instead, like dwm, it sticks to features which are necessary, simple, and straightforward to implement given the base on which it is built. Implemented default features are: From b6e3fc1645c5ac53277ab0dc20d7c266e1581b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 10 Aug 2022 23:57:03 -0500 Subject: [PATCH 211/329] rework outputmgrapplyortest() first disable requested monitors, then enable and/or change mode, x and y, etc. This is mostly what sway does --- dwl.c | 56 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/dwl.c b/dwl.c index 039b8ff..7d53ab9 100644 --- a/dwl.c +++ b/dwl.c @@ -1583,34 +1583,48 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) struct wlr_output_configuration_head_v1 *config_head; int ok = 1; + /* First disable outputs we need to disable */ wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; - - wlr_output_enable(wlr_output, config_head->state.enabled); - if (config_head->state.enabled) { - if (config_head->state.mode) - wlr_output_set_mode(wlr_output, config_head->state.mode); - else - wlr_output_set_custom_mode(wlr_output, - config_head->state.custom_mode.width, - config_head->state.custom_mode.height, - config_head->state.custom_mode.refresh); - - wlr_output_layout_move(output_layout, wlr_output, - config_head->state.x, config_head->state.y); - wlr_output_set_transform(wlr_output, config_head->state.transform); - wlr_output_set_scale(wlr_output, config_head->state.scale); + if (!wlr_output->enabled || config_head->state.enabled) + continue; + wlr_output_enable(wlr_output, 0); + if (test) { + ok &= wlr_output_test(wlr_output); + wlr_output_rollback(wlr_output); + } else { + ok &= wlr_output_commit(wlr_output); } + } - if (!(ok = wlr_output_test(wlr_output))) - break; - } + /* Then enable outputs that need to */ wl_list_for_each(config_head, &config->heads, link) { - if (ok && !test) - wlr_output_commit(config_head->state.output); + struct wlr_output *wlr_output = config_head->state.output; + if (!config_head->state.enabled) + continue; + + wlr_output_enable(wlr_output, 1); + if (config_head->state.mode) + wlr_output_set_mode(wlr_output, config_head->state.mode); else - wlr_output_rollback(config_head->state.output); + wlr_output_set_custom_mode(wlr_output, + config_head->state.custom_mode.width, + config_head->state.custom_mode.height, + config_head->state.custom_mode.refresh); + + wlr_output_layout_move(output_layout, wlr_output, + config_head->state.x, config_head->state.y); + wlr_output_set_transform(wlr_output, config_head->state.transform); + wlr_output_set_scale(wlr_output, config_head->state.scale); + + if (test) { + ok &= wlr_output_test(wlr_output); + wlr_output_rollback(wlr_output); + } else { + ok &= wlr_output_commit(wlr_output); + } } + if (ok) wlr_output_configuration_v1_send_succeeded(config); else From 48396a1bf8ce4282c4fc76d853195e1026caf7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 11 Aug 2022 15:25:13 -0500 Subject: [PATCH 212/329] fix crash when setting a custom mode --- dwl.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 7d53ab9..5031e0a 100644 --- a/dwl.c +++ b/dwl.c @@ -1621,7 +1621,23 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) ok &= wlr_output_test(wlr_output); wlr_output_rollback(wlr_output); } else { - ok &= wlr_output_commit(wlr_output); + int output_ok = 1; + /* If it's a custom mode to avoid an assertion failed in wlr_output_commit() + * we test if that mode does not fail rather than just call wlr_output_commit(). + * We do not test normal modes because (at least in my hardware (@sevz17)) + * wlr_output_test() fails even if that mode can actually be set */ + if (!config_head->state.mode) + ok &= (output_ok = wlr_output_test(wlr_output) + && wlr_output_commit(wlr_output)); + else + ok &= wlr_output_commit(wlr_output); + + /* In custom modes we call wlr_output_test(), it it fails + * we need to rollback, and normal modes seems to does not cause + * assertions failed in wlr_output_commit() which rollback + * the output on failure */ + if (!output_ok) + wlr_output_rollback(wlr_output); } } From 28af37cd1f6dce140df8e99659d0af07dc1d9985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 12 Aug 2022 23:58:11 -0500 Subject: [PATCH 213/329] handle client_from_wlr_surface() receiving a subsurface --- client.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client.h b/client.h index dc4a6c4..c091b81 100644 --- a/client.h +++ b/client.h @@ -30,6 +30,7 @@ static inline Client * client_from_wlr_surface(struct wlr_surface *s) { struct wlr_xdg_surface *surface; + struct wlr_surface *parent; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; @@ -42,6 +43,8 @@ client_from_wlr_surface(struct wlr_surface *s) && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) return surface->data; + if (s && wlr_surface_is_subsurface(s)) + return client_from_wlr_surface(wlr_surface_get_root_surface(s)); return NULL; } From f173c56c320a57e76a6bee578c3b9365f3a83950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Aug 2022 00:07:11 -0500 Subject: [PATCH 214/329] initialize to zero the box used in commitnotify() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5031e0a..0431119 100644 --- a/dwl.c +++ b/dwl.c @@ -793,7 +793,7 @@ void commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); - struct wlr_box box; + struct wlr_box box = {0}; client_get_geometry(c, &box); if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw From 8d2516e83cb1e1d1cfc4fe31e69ed87d71405592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Aug 2022 00:38:08 -0500 Subject: [PATCH 215/329] reorder isfullscreen in Client definition --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 0431119..227f345 100644 --- a/dwl.c +++ b/dwl.c @@ -119,9 +119,8 @@ typedef struct { #endif int bw; unsigned int tags; - int isfloating, isurgent; + int isfloating, isurgent, isfullscreen; uint32_t resize; /* configure serial of a pending resize */ - int isfullscreen; } Client; typedef struct { From 7a343b98cf37fb293313dada734c0d433b27fba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Aug 2022 00:41:08 -0500 Subject: [PATCH 216/329] change type of c->bw: int -> unsigned int --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 227f345..40ea05a 100644 --- a/dwl.c +++ b/dwl.c @@ -117,7 +117,7 @@ typedef struct { struct wl_listener configure; struct wl_listener set_hints; #endif - int bw; + unsigned int bw; unsigned int tags; int isfloating, isurgent, isfullscreen; uint32_t resize; /* configure serial of a pending resize */ From a7f77160d1b36029b496384087c0d71d27d73079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 16 Aug 2022 20:57:09 -0500 Subject: [PATCH 217/329] don't respect size hints for fullscreen clients Fixes: #292 --- dwl.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index 40ea05a..212afd1 100644 --- a/dwl.c +++ b/dwl.c @@ -383,15 +383,17 @@ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; void applybounds(Client *c, struct wlr_box *bbox) { - struct wlr_box min = {0}, max = {0}; - client_get_size_hints(c, &max, &min); - /* try to set size hints */ - c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); - c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); - if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) // Checks for overflow - c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); - if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) // Checks for overflow - c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); + if (!c->isfullscreen) { + struct wlr_box min = {0}, max = {0}; + client_get_size_hints(c, &max, &min); + /* try to set size hints */ + c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); + c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); + if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) // Checks for overflow + c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); + if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) // Checks for overflow + c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); + } if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; From 174919ec5342af19504661b30359068af5fcf1c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 18 Aug 2022 16:51:15 -0500 Subject: [PATCH 218/329] set monitor for clients that don't have one on monitor creation --- dwl.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 212afd1..cf7d307 100644 --- a/dwl.c +++ b/dwl.c @@ -896,6 +896,7 @@ createmon(struct wl_listener *listener, void *data) * monitor) becomes available. */ struct wlr_output *wlr_output = data; const MonitorRule *r; + Client *c; Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; @@ -944,15 +945,10 @@ createmon(struct wl_listener *listener, void *data) m->scene_output = wlr_scene_output_create(scene, wlr_output); wlr_output_layout_add_auto(output_layout, wlr_output); - /* If length == 1 we need update selmon. - * Maybe it will change in run(). */ - if (wl_list_length(&mons) == 1) { - Client *c; - selmon = m; - /* If there is any client, set c->mon to this monitor */ - wl_list_for_each(c, &clients, link) + /* If there are clients without monitor set this as their monitor */ + wl_list_for_each(c, &clients, link) + if (!c->mon) setmon(c, m, c->tags); - } } void From 07bf1832bf2c435107f4664c82efc756f3fdd784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 18 Aug 2022 16:59:38 -0500 Subject: [PATCH 219/329] set monitor for clients that don't have one in updatemons() only if selmon is enabled and the clients are mapped --- client.h | 10 ++++++++++ dwl.c | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/client.h b/client.h index c091b81..c54a2f3 100644 --- a/client.h +++ b/client.h @@ -183,6 +183,16 @@ client_is_float_type(Client *c) || c->surface.xdg->toplevel->parent; } +static inline int +client_is_mapped(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->mapped; +#endif + return c->surface.xdg->mapped; +} + static inline int client_wants_fullscreen(Client *c) { diff --git a/dwl.c b/dwl.c index cf7d307..3a044d3 100644 --- a/dwl.c +++ b/dwl.c @@ -2365,6 +2365,7 @@ updatemons(struct wl_listener *listener, void *data) */ struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); + Client *c; Monitor *m; sgeom = *wlr_output_layout_get_box(output_layout, NULL); wl_list_for_each(m, &mons, link) { @@ -2388,6 +2389,11 @@ updatemons(struct wl_listener *listener, void *data) config_head->state.y = m->m.y; } + if (selmon && selmon->wlr_output->enabled) + wl_list_for_each(c, &clients, link) + if (!c->mon && client_is_mapped(c)) + setmon(c, selmon, c->tags); + wlr_output_manager_v1_set_configuration(output_mgr, config); } From dfcd142ce4079d36f5a0a73f9104ba87c365ef12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 18 Aug 2022 17:24:11 -0500 Subject: [PATCH 220/329] don't try to set monitor for clients in createmon() this is done in updatemons() --- dwl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dwl.c b/dwl.c index 3a044d3..ebb74b8 100644 --- a/dwl.c +++ b/dwl.c @@ -944,11 +944,6 @@ createmon(struct wl_listener *listener, void *data) */ m->scene_output = wlr_scene_output_create(scene, wlr_output); wlr_output_layout_add_auto(output_layout, wlr_output); - - /* If there are clients without monitor set this as their monitor */ - wl_list_for_each(c, &clients, link) - if (!c->mon) - setmon(c, m, c->tags); } void From 406aebcbd2d9526834ad4131ac8b454a9f27c0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Aug 2022 19:57:20 -0500 Subject: [PATCH 221/329] prevent an infinite loop if try to use focusmon() with all monitors disabled --- dwl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index ebb74b8..f76e30f 100644 --- a/dwl.c +++ b/dwl.c @@ -1192,9 +1192,11 @@ focusclient(Client *c, int lift) void focusmon(const Arg *arg) { - do - selmon = dirtomon(arg->i); - while (!selmon->wlr_output->enabled); + int i = 0, nmons = wl_list_length(&mons); + if (nmons) + do /* don't switch to disabled mons */ + selmon = dirtomon(arg->i); + while (!selmon->wlr_output->enabled && i++ < nmons); focusclient(focustop(selmon), 1); } From b9295e8cee8d3e057f92a9fea1523c379c298f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 27 Aug 2022 16:29:23 -0500 Subject: [PATCH 222/329] sort client.h functions --- client.h | 136 +++++++++++++++++++++++++++---------------------------- 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/client.h b/client.h index c54a2f3..5988db3 100644 --- a/client.h +++ b/client.h @@ -16,16 +16,6 @@ client_is_x11(Client *c) #endif } -static inline struct wlr_surface * -client_surface(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->surface; -#endif - return c->surface.xdg->surface; -} - static inline Client * client_from_wlr_surface(struct wlr_surface *s) { @@ -48,6 +38,56 @@ client_from_wlr_surface(struct wlr_surface *s) return NULL; } +static inline Client * +client_get_parent(Client *c) +{ + Client *p; +#ifdef XWAYLAND + if (client_is_x11(c) && c->surface.xwayland->parent) + return client_from_wlr_surface(c->surface.xwayland->parent->surface); +#endif + if (c->surface.xdg->toplevel->parent) + return client_from_wlr_surface(c->surface.xdg->toplevel->parent->surface); + + return NULL; +} + +static inline void +client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) +{ + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state *state; +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface_size_hints *size_hints; + size_hints = c->surface.xwayland->size_hints; + if (size_hints) { + max->width = size_hints->max_width; + max->height = size_hints->max_height; + min->width = size_hints->min_width; + min->height = size_hints->min_height; + } + return; + } +#endif + toplevel = c->surface.xdg->toplevel; + state = &toplevel->current; + max->width = state->max_width; + max->height = state->max_height; + min->width = state->min_width; + min->height = state->min_height; +} + +static inline struct wlr_surface * +client_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->surface; +#endif + return c->surface.xdg->surface; +} + /* The others */ static inline void client_activate_surface(struct wlr_surface *s, int activated) @@ -103,32 +143,6 @@ client_get_geometry(Client *c, struct wlr_box *geom) wlr_xdg_surface_get_geometry(c->surface.xdg, geom); } -static inline void -client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) -{ - struct wlr_xdg_toplevel *toplevel; - struct wlr_xdg_toplevel_state *state; -#ifdef XWAYLAND - if (client_is_x11(c)) { - struct wlr_xwayland_surface_size_hints *size_hints; - size_hints = c->surface.xwayland->size_hints; - if (size_hints) { - max->width = size_hints->max_width; - max->height = size_hints->max_height; - min->width = size_hints->min_width; - min->height = size_hints->min_height; - } - return; - } -#endif - toplevel = c->surface.xdg->toplevel; - state = &toplevel->current; - max->width = state->max_width; - max->height = state->max_height; - min->width = state->min_width; - min->height = state->min_height; -} - static inline const char * client_get_title(Client *c) { @@ -139,19 +153,6 @@ client_get_title(Client *c) return c->surface.xdg->toplevel->title; } -static inline Client * -client_get_parent(Client *c) -{ - Client *p; -#ifdef XWAYLAND - if (client_is_x11(c) && c->surface.xwayland->parent) - return client_from_wlr_surface(c->surface.xwayland->parent->surface); -#endif - if (c->surface.xdg->toplevel->parent) - return client_from_wlr_surface(c->surface.xdg->toplevel->parent->surface); - - return NULL; -} static inline int client_is_float_type(Client *c) @@ -171,16 +172,11 @@ client_is_float_type(Client *c) || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; - - return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) - && (min.width == max.width || min.height == max.height)) - || c->surface.xwayland->parent; } #endif - return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) && (min.width == max.width || min.height == max.height)) - || c->surface.xdg->toplevel->parent; + || client_get_parent(c); } static inline int @@ -193,16 +189,6 @@ client_is_mapped(Client *c) return c->surface.xdg->mapped; } -static inline int -client_wants_fullscreen(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->fullscreen; -#endif - return c->surface.xdg->toplevel->requested.fullscreen; -} - static inline int client_is_unmanaged(Client *c) { @@ -212,6 +198,17 @@ client_is_unmanaged(Client *c) return 0; } +static inline void +client_restack_surface(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + wlr_xwayland_surface_restack(c->surface.xwayland, NULL, + XCB_STACK_MODE_ABOVE); +#endif + return; +} + static inline void client_send_close(Client *c) { @@ -270,15 +267,14 @@ client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); } -static inline void -client_restack_surface(Client *c) +static inline int +client_wants_fullscreen(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) - wlr_xwayland_surface_restack(c->surface.xwayland, NULL, - XCB_STACK_MODE_ABOVE); + return c->surface.xwayland->fullscreen; #endif - return; + return c->surface.xdg->toplevel->requested.fullscreen; } static inline void * From d738573e22649dfb01f70eca00cef221839c9efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 27 Aug 2022 16:05:12 -0500 Subject: [PATCH 223/329] new function to notify keyboard enter --- client.h | 10 ++++++++++ dwl.c | 15 ++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/client.h b/client.h index 5988db3..a881131 100644 --- a/client.h +++ b/client.h @@ -198,6 +198,16 @@ client_is_unmanaged(Client *c) return 0; } +static inline void +client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) +{ + if (kb) + wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, + kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); +} + static inline void client_restack_surface(Client *c) { diff --git a/dwl.c b/dwl.c index f76e30f..66aea65 100644 --- a/dwl.c +++ b/dwl.c @@ -590,7 +590,6 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; - struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) @@ -614,11 +613,7 @@ arrangelayers(Monitor *m) /* Deactivate the focused client. */ focusclient(NULL, 0); exclusive_focus = layersurface->layer_surface->surface; - if (kb) - wlr_seat_keyboard_notify_enter(seat, exclusive_focus, - kb->keycodes, kb->num_keycodes, &kb->modifiers); - else - wlr_seat_keyboard_notify_enter(seat, exclusive_focus, NULL, 0, NULL); + client_notify_enter(exclusive_focus, wlr_seat_get_keyboard(seat)); return; } } @@ -1117,7 +1112,6 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - struct wlr_keyboard *kb; int i; /* Do not focus clients if a layer surface is focused */ if (exclusive_focus) @@ -1178,12 +1172,7 @@ focusclient(Client *c, int lift) } /* Have a client, so focus its top-level wlr_surface */ - kb = wlr_seat_get_keyboard(seat); - if (kb) - wlr_seat_keyboard_notify_enter(seat, client_surface(c), - kb->keycodes, kb->num_keycodes, &kb->modifiers); - else - wlr_seat_keyboard_notify_enter(seat, client_surface(c), NULL, 0, NULL); + client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); /* Activate the new client */ client_activate_surface(client_surface(c), 1); From 83e37820d778f935af0123d3b4bc0512265fbfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 28 Aug 2022 21:40:03 -0500 Subject: [PATCH 224/329] add support for the single pixel buffer protocol --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index f900f88..52109ee 100644 --- a/dwl.c +++ b/dwl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1949,6 +1950,7 @@ setup(void) wlr_gamma_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); + wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ From 0e993b5fb1820189b78bed9fc2eb642230b47a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 12 Aug 2022 23:47:34 -0500 Subject: [PATCH 225/329] conform the idle inhibitor protocol previously we disable idle tracking simply due to the fact that it exist --- dwl.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 66aea65..a3b13b6 100644 --- a/dwl.c +++ b/dwl.c @@ -216,6 +216,7 @@ static void arrangelayers(Monitor *m); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); +static void checkidleinhibitor(struct wlr_surface *exclude); static void cleanup(void); static void cleanupkeyboard(struct wl_listener *listener, void *data); static void cleanupmon(struct wl_listener *listener, void *data); @@ -687,6 +688,25 @@ chvt(const Arg *arg) wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); } +void +checkidleinhibitor(struct wlr_surface *exclude) +{ + Client *c, *w; + int inhibited = 0; + struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + c = client_from_wlr_surface(inhibitor->surface); + if (exclude && (!(w = client_from_wlr_surface(exclude)) || w == c)) + continue; + if (!c || VISIBLEON(c, c->mon)) { + inhibited = 1; + break; + } + } + + wlr_idle_set_enabled(idle, NULL, !inhibited); +} + void cleanup(void) { @@ -809,7 +829,7 @@ createidleinhibitor(struct wl_listener *listener, void *data) struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); - wlr_idle_set_enabled(idle, seat, 0); + checkidleinhibitor(NULL); } void @@ -1040,9 +1060,9 @@ cursorframe(struct wl_listener *listener, void *data) void destroyidleinhibitor(struct wl_listener *listener, void *data) { - /* I've been testing and at this point the inhibitor has not yet been - * removed from the list, checking if it has at least one item. */ - wlr_idle_set_enabled(idle, seat, wl_list_length(&idle_inhibit_mgr->inhibitors) <= 1); + /* `data` is the wlr_surface of the idle inhibitor being destroyed, + * at this point the idle inhibitor is still in the list of the manager */ + checkidleinhibitor(data); } void @@ -1163,7 +1183,7 @@ focusclient(Client *c, int lift) } printstatus(); - wlr_idle_set_enabled(idle, seat, wl_list_empty(&idle_inhibit_mgr->inhibitors)); + checkidleinhibitor(NULL); if (!c) { /* With no client, all we have left is to clear focus */ From 226051974060746d02d787ac1ef70b6267ee51b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 24 Jul 2022 17:18:44 -0500 Subject: [PATCH 226/329] various improvements to layer surface - remove various useless assignments of layersurface->mon - styles changes - do not set wlr_layer_surface->output to NULL at destroy --- dwl.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/dwl.c b/dwl.c index a3b13b6..8556cba 100644 --- a/dwl.c +++ b/dwl.c @@ -783,25 +783,23 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_output *wlr_output = wlr_layer_surface->output; - if (!wlr_output || !(layersurface->mon = wlr_output->data)) + if (!layersurface->mon) return; - wlr_scene_node_reparent(layersurface->scene, - layers[wlr_layer_surface->current.layer]); + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; - layersurface->mapped = wlr_layer_surface->mapped; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } arrangelayers(layersurface->mon); } @@ -868,14 +866,13 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; - if (!wlr_layer_surface->output) { + if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon->wlr_output; - } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); + &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); LISTEN(&wlr_layer_surface->events.map, &layersurface->map, @@ -884,8 +881,8 @@ createlayersurface(struct wl_listener *listener, void *data) unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; - wlr_layer_surface->data = layersurface; layersurface->mon = wlr_layer_surface->output->data; + wlr_layer_surface->data = layersurface; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], @@ -1076,11 +1073,8 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(layersurface->scene); - if (layersurface->layer_surface->output) { - if ((layersurface->mon = layersurface->layer_surface->output->data)) - arrangelayers(layersurface->mon); - layersurface->layer_surface->output = NULL; - } + if (layersurface->mon) + arrangelayers(layersurface->mon); free(layersurface); } @@ -1380,10 +1374,8 @@ killclient(const Arg *arg) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, map); - layersurface->mon = layersurface->layer_surface->output->data; - wlr_surface_send_enter(layersurface->layer_surface->surface, - layersurface->mon->wlr_output); + LayerSurface *l = wl_container_of(listener, l, map); + wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); motionnotify(0); } From c017916d35795cf85e5181907f5e97a1d702612a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 31 Aug 2022 16:05:19 -0500 Subject: [PATCH 227/329] Revert "various improvements to layer surface" see https://github.com/djpohly/dwl/issues/289#issuecomment-1231287114 This reverts commit 226051974060746d02d787ac1ef70b6267ee51b4. --- dwl.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/dwl.c b/dwl.c index 8556cba..a3b13b6 100644 --- a/dwl.c +++ b/dwl.c @@ -783,23 +783,25 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_output *wlr_output = wlr_layer_surface->output; - if (!layersurface->mon) + if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { - wlr_scene_node_reparent(layersurface->scene, - layers[wlr_layer_surface->current.layer]); - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; + layersurface->mapped = wlr_layer_surface->mapped; + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } arrangelayers(layersurface->mon); } @@ -866,13 +868,14 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; - if (!wlr_layer_surface->output) + if (!wlr_layer_surface->output) { wlr_layer_surface->output = selmon->wlr_output; + } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); + &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); LISTEN(&wlr_layer_surface->events.map, &layersurface->map, @@ -881,8 +884,8 @@ createlayersurface(struct wl_listener *listener, void *data) unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; - layersurface->mon = wlr_layer_surface->output->data; wlr_layer_surface->data = layersurface; + layersurface->mon = wlr_layer_surface->output->data; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], @@ -1073,8 +1076,11 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(layersurface->scene); - if (layersurface->mon) - arrangelayers(layersurface->mon); + if (layersurface->layer_surface->output) { + if ((layersurface->mon = layersurface->layer_surface->output->data)) + arrangelayers(layersurface->mon); + layersurface->layer_surface->output = NULL; + } free(layersurface); } @@ -1374,8 +1380,10 @@ killclient(const Arg *arg) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, map); - wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); + LayerSurface *layersurface = wl_container_of(listener, layersurface, map); + layersurface->mon = layersurface->layer_surface->output->data; + wlr_surface_send_enter(layersurface->layer_surface->surface, + layersurface->mon->wlr_output); motionnotify(0); } From 40b1c0b849ee48c428f7f901afcdc67d20f3cf7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 16:54:53 -0500 Subject: [PATCH 228/329] Revert "Revert "various improvements to layer surface"" This reverts commit c017916d35795cf85e5181907f5e97a1d702612a. --- dwl.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/dwl.c b/dwl.c index a3b13b6..8556cba 100644 --- a/dwl.c +++ b/dwl.c @@ -783,25 +783,23 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_output *wlr_output = wlr_layer_surface->output; - if (!wlr_output || !(layersurface->mon = wlr_output->data)) + if (!layersurface->mon) return; - wlr_scene_node_reparent(layersurface->scene, - layers[wlr_layer_surface->current.layer]); + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; - layersurface->mapped = wlr_layer_surface->mapped; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } arrangelayers(layersurface->mon); } @@ -868,14 +866,13 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; - if (!wlr_layer_surface->output) { + if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon->wlr_output; - } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); + &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); LISTEN(&wlr_layer_surface->events.map, &layersurface->map, @@ -884,8 +881,8 @@ createlayersurface(struct wl_listener *listener, void *data) unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; - wlr_layer_surface->data = layersurface; layersurface->mon = wlr_layer_surface->output->data; + wlr_layer_surface->data = layersurface; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], @@ -1076,11 +1073,8 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(layersurface->scene); - if (layersurface->layer_surface->output) { - if ((layersurface->mon = layersurface->layer_surface->output->data)) - arrangelayers(layersurface->mon); - layersurface->layer_surface->output = NULL; - } + if (layersurface->mon) + arrangelayers(layersurface->mon); free(layersurface); } @@ -1380,10 +1374,8 @@ killclient(const Arg *arg) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, map); - layersurface->mon = layersurface->layer_surface->output->data; - wlr_surface_send_enter(layersurface->layer_surface->surface, - layersurface->mon->wlr_output); + LayerSurface *l = wl_container_of(listener, l, map); + wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); motionnotify(0); } From 1f59b76d7726c83e8131609d806d5c78abb89356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 17:29:41 -0500 Subject: [PATCH 229/329] prevent segfault when destroying monitors also don't count unmapped surfaces for exclusive zone and exclusive_focus is now of type `void *` --- dwl.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 8556cba..85db889 100644 --- a/dwl.c +++ b/dwl.c @@ -300,7 +300,7 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; static pid_t child_pid = -1; -static struct wlr_surface *exclusive_focus; +static void *exclusive_focus; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; @@ -522,7 +522,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (exclusive != (state->exclusive_zone > 0)) + if (wlr_layer_surface->mapped && exclusive != (state->exclusive_zone > 0)) continue; bounds = state->exclusive_zone == -1 ? full_area : *usable_area; @@ -613,8 +613,8 @@ arrangelayers(Monitor *m) layersurface->layer_surface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); - exclusive_focus = layersurface->layer_surface->surface; - client_notify_enter(exclusive_focus, wlr_seat_get_keyboard(seat)); + exclusive_focus = layersurface; + client_notify_enter(layersurface->layer_surface->surface, wlr_seat_get_keyboard(seat)); return; } } @@ -749,6 +749,7 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); wl_list_remove(&m->link); + wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); @@ -783,8 +784,9 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_output *wlr_output = wlr_layer_surface->output; - if (!layersurface->mon) + if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { @@ -1073,8 +1075,6 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(layersurface->scene); - if (layersurface->mon) - arrangelayers(layersurface->mon); free(layersurface); } @@ -2317,7 +2317,10 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) layersurface->layer_surface->mapped = (layersurface->mapped = 0); wlr_scene_node_set_enabled(layersurface->scene, 0); - if (layersurface->layer_surface->surface == exclusive_focus) + if (layersurface->layer_surface->output + && (layersurface->mon = layersurface->layer_surface->output->data)) + arrangelayers(layersurface->mon); + if (layersurface == exclusive_focus) exclusive_focus = NULL; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) From 19a8a095ebe782065903b9a03670560371302206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 18:22:15 -0500 Subject: [PATCH 230/329] call setfullscreen() in setmon() this will help when sending to another monitor a fullscreen client and also will prevent a crash when a client request fullscreen when it has no monitor --- dwl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 85db889..f6db3c1 100644 --- a/dwl.c +++ b/dwl.c @@ -1438,9 +1438,6 @@ mapnotify(struct wl_listener *listener, void *data) } printstatus(); - if (c->isfullscreen) - setfullscreen(c, 1); - c->mon->un_map = 1; } @@ -1889,6 +1886,8 @@ void setfullscreen(Client *c, int fullscreen) { c->isfullscreen = fullscreen; + if (!c->mon) + return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); @@ -1968,7 +1967,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) resize(c, c->geom, 0); wlr_surface_send_enter(client_surface(c), m->wlr_output); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ - arrange(m); + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } focusclient(focustop(selmon), 1); } From 68576799b96950dd36ed7c71ba0c4b1607a13cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 18:49:20 -0500 Subject: [PATCH 231/329] don't arrange layers on disabled monitors --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index f6db3c1..669580a 100644 --- a/dwl.c +++ b/dwl.c @@ -591,6 +591,8 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; + if (!m || !m->wlr_output->enabled) + return; /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) From e91f71e8d6b6b29da69ec0cd8ad8f7dec2878df3 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharchenko Date: Fri, 2 Sep 2022 19:57:35 +0300 Subject: [PATCH 232/329] Add direct irc link Also, move IRC section to the top so that it's more accessible. --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 887bf29..6b12ab0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dwl - dwm for Wayland -Join us on our [Discord server](https://discord.gg/jJxZnrGPWN)! +Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) and at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is: @@ -85,10 +85,6 @@ Existing dwl-specific status bars and dwl-specific scripts for other status bars You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). -## IRC channel - -dwl's IRC channel is #dwl on irc.libera.chat. - ## Acknowledgements dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots developers. This was made possible in many cases by looking at how sway accomplished something, then trying to do the same in as suckless a way as possible. From a94d089c405c677ed4ae7e7c340bf52b49126d9c Mon Sep 17 00:00:00 2001 From: Dmitry Zakharchenko Date: Sun, 4 Sep 2022 12:00:00 +0300 Subject: [PATCH 233/329] Minor changes to README --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6b12ab0..f68290c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dwl - dwm for Wayland -Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) and at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. +Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) or at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is: @@ -73,17 +73,11 @@ If your startup command is a shell script, you can achieve the same inside the s exec <&- -Existing dwl-specific status bars and dwl-specific scripts for other status bars include: -- [somebar](https://sr.ht/~raphi/somebar/) status bar designed for dwl -- [dtaobarv2.sh](https://cdn.discordapp.com/attachments/792078050024095745/862428883423723560/dtaobarv2.sh) for use with [dtao](https://github.com/djpohly/dtao) (See "Pinned Messages" on the "customizations" channel of the [dwl Discord server](https://discord.gg/jJxZnrGPWN) for details.) -- [dwlbar.sh](https://cdn.discordapp.com/attachments/792078050024095745/810926218529472592/dwlbar.sh) for use with [waybar](https://github.com/Alexays/Waybar) (See "Pinned Messages" on the "customizations" channel of the [dwl Discord server](https://discord.gg/jJxZnrGPWN) for details.) -- [waybar-dwl](https://codeberg.org/fauxmight/waybar-dwl.git) for use with [waybar](https://github.com/Alexays/Waybar) -- [dwl-tags.sh](https://codeberg.org/novakane/yambar/src/branch/master/examples/scripts/dwl-tags.sh) for use with [yambar](https://codeberg.org/dnkl/yambar) -- [waybar-dwl.sh](https://gitee.com/guyuming76/personal/tree/dwl/gentoo/waybar-dwl) for use with [waybar](https://github.com/Alexays/Waybar) (ACCESS TO THIS SCRIPT REQUIRES gitee.com LOGIN!) +To get a list of status bars that work with dwl consult our [wiki](https://github.com/djpohly/dwl/wiki#compatible-status-bars). ## Replacements for X applications -You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). +You can find a [list of useful resources on our wiki](https://github.com/djpohly/dwl/wiki#migrating-from-x). ## Acknowledgements From 14a1e3e2a2ced87d4f373c93c7caae48ccb02f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Sep 2022 16:30:23 -0500 Subject: [PATCH 234/329] set c->prev in mapnotify() Closes: #300 --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 669580a..9a7b42e 100644 --- a/dwl.c +++ b/dwl.c @@ -1423,6 +1423,7 @@ mapnotify(struct wl_listener *listener, void *data) client_get_geometry(c, &c->geom); c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; + c->prev = c->geom; /* Insert this client into client lists. */ wl_list_insert(&clients, &c->link); From 14c010a0d69eb8a528d63a311a94134a52cab8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Sep 2022 00:10:00 -0500 Subject: [PATCH 235/329] only enable/disable clients from the specified monitor in arrange() also fix a crash when m is null, this can only happen when selmon is NULL --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 9a7b42e..5ed534e 100644 --- a/dwl.c +++ b/dwl.c @@ -496,9 +496,10 @@ arrange(Monitor *m) { Client *c; wl_list_for_each(c, &clients, link) - wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, c->mon)); + if (c->mon == m) + wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, m)); - if (m->lt[m->sellt]->arrange) + if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); } From dc59f7733d0315b3240b46321f3b5ae2ecc16b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Sep 2022 00:29:44 -0500 Subject: [PATCH 236/329] enable adaptive sync if supported but don't cause monitors to be ignored if it fails --- dwl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 52109ee..b80f3aa 100644 --- a/dwl.c +++ b/dwl.c @@ -803,7 +803,6 @@ createmon(struct wl_listener *listener, void *data) * monitor's preferred mode; a more sophisticated compositor would let * the user configure it. */ wlr_output_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output)); - wlr_output_enable_adaptive_sync(wlr_output, 1); /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); @@ -813,6 +812,11 @@ createmon(struct wl_listener *listener, void *data) if (!wlr_output_commit(wlr_output)) return; + /* Try to enable adaptive sync, note that not all monitors support it. + * wlr_output_commit() will deactivate it in case it cannot be enabled */ + wlr_output_enable_adaptive_sync(wlr_output, 1); + wlr_output_commit(wlr_output); + wl_list_insert(&mons, &m->link); printstatus(); From 1aacfada29657ec1104f856687400e65927e54b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Sep 2022 22:48:16 -0500 Subject: [PATCH 237/329] set `c->prev` in setmon() and not in mapnotify() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5ed534e..41ce69f 100644 --- a/dwl.c +++ b/dwl.c @@ -1424,7 +1424,6 @@ mapnotify(struct wl_listener *listener, void *data) client_get_geometry(c, &c->geom); c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; - c->prev = c->geom; /* Insert this client into client lists. */ wl_list_insert(&clients, &c->link); @@ -1960,6 +1959,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) if (oldmon == m) return; c->mon = m; + c->prev = c->geom; /* TODO leave/enter is not optimal but works */ if (oldmon) { From 80084839a9d9a3aaed323a267bbd2f061f37c8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Sep 2022 23:24:50 -0500 Subject: [PATCH 238/329] remove obsolete check of c->mon in fullscreennotify() since 19a8a095ebe782065903b9a03670560371302206 it's checked in setfullscreen() --- dwl.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 41ce69f..753ee40 100644 --- a/dwl.c +++ b/dwl.c @@ -1246,14 +1246,7 @@ void fullscreennotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - int fullscreen = client_wants_fullscreen(c); - - if (!c->mon) { - /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ - c->isfullscreen = fullscreen; - return; - } - setfullscreen(c, fullscreen); + setfullscreen(c, client_wants_fullscreen(c)); } void From d1496a2a9b4a336ea08f0ed3eae7fa3f155989b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Sep 2022 23:54:57 -0500 Subject: [PATCH 239/329] fix condition that always evaluate to false in commitlayersurfacenotify() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 753ee40..58dc4db 100644 --- a/dwl.c +++ b/dwl.c @@ -792,7 +792,7 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + if (layers[wlr_layer_surface->current.layer] != layersurface->scene->parent) { wlr_scene_node_reparent(layersurface->scene, layers[wlr_layer_surface->current.layer]); wl_list_remove(&layersurface->link); From 871463c32740d601241123770a65fea0d737fb54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 00:10:53 -0500 Subject: [PATCH 240/329] define _POSIX_C_SOURCE through CPPFLAGS like dwm --- Makefile | 2 +- dwl.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1bdc7d6..4afd717 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ include config.mk # flags for compiling -DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -DVERSION=\"$(VERSION)\" +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" # Wayland utils WAYLAND_PROTOCOLS = `pkg-config --variable=pkgdatadir wayland-protocols` diff --git a/dwl.c b/dwl.c index 58dc4db..530ee4e 100644 --- a/dwl.c +++ b/dwl.c @@ -1,7 +1,6 @@ /* * See LICENSE file for copyright and license details. */ -#define _POSIX_C_SOURCE 200809L #include #include #include From 303fc72b124721ef86d1340367a2d3474716c367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 00:13:03 -0500 Subject: [PATCH 241/329] append `-dev` to $(_VERSION) (should have added it a long time ago) --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 4638d5f..55c7262 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.3.1 +_VERSION = 0.3.1-dev VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` # paths From ae42e4390b4606527b9f98148f53ae3638d1bcea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 00:25:26 -0500 Subject: [PATCH 242/329] update link to input-protocols --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f68290c..132fb32 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/12) +- Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/235) Feature *non-goals* for the main codebase include: From 9bcef3d040790b5f3064e33e149891120055a377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 16:35:55 -0500 Subject: [PATCH 243/329] resize the fullscreen background when resize the client --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 530ee4e..912a877 100644 --- a/dwl.c +++ b/dwl.c @@ -1780,6 +1780,8 @@ resize(Client *c, struct wlr_box geo, int interact) wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); + if (c->fullscreen_bg) + wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height); /* wlroots makes this a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, From 1bb9c4583a4e5b0975ed9b57e994f1d958f04c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 18:41:39 -0500 Subject: [PATCH 244/329] fix exclusive zone of unmapped layer surfaces Fixes: https://github.com/djpohly/dwl/issues/302 --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 912a877..7c3855d 100644 --- a/dwl.c +++ b/dwl.c @@ -522,7 +522,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (wlr_layer_surface->mapped && exclusive != (state->exclusive_zone > 0)) + if (!((LayerSurface *)wlr_layer_surface->data)->mapped + || exclusive != (state->exclusive_zone > 0)) continue; bounds = state->exclusive_zone == -1 ? full_area : *usable_area; @@ -901,6 +902,7 @@ createlayersurface(struct wl_listener *listener, void *data) */ old_state = wlr_layer_surface->current; wlr_layer_surface->current = wlr_layer_surface->pending; + layersurface->mapped = 1; arrangelayers(layersurface->mon); wlr_layer_surface->current = old_state; } @@ -2312,7 +2314,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); - layersurface->layer_surface->mapped = (layersurface->mapped = 0); + layersurface->mapped = 0; wlr_scene_node_set_enabled(layersurface->scene, 0); if (layersurface->layer_surface->output && (layersurface->mon = layersurface->layer_surface->output->data)) From f8f94c97f5d324c8876e88d0d82fd518eca25b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 22:11:06 -0500 Subject: [PATCH 245/329] fix idle inhibitor check previously we tried to get a client from the surface and then compare it with the excluded surface, if we cannot get a client from the surface (e.g: a layer surface) it just ignored all the next idle inhibitors no matter what What I have should done is just checking if the excluded surface is equal to the current idle inhibitor's surface and continue in case it is. --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 7c3855d..9420ae5 100644 --- a/dwl.c +++ b/dwl.c @@ -694,14 +694,14 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { - Client *c, *w; int inhibited = 0; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - c = client_from_wlr_surface(inhibitor->surface); - if (exclude && (!(w = client_from_wlr_surface(exclude)) || w == c)) + Client *c; + if (exclude == inhibitor->surface) continue; - if (!c || VISIBLEON(c, c->mon)) { + if (!(c = client_from_wlr_surface(inhibitor->surface)) + || VISIBLEON(c, c->mon)) { inhibited = 1; break; } From 93de6e82a296aaf8aa15733e485fdd4ef34595d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 22:25:46 -0500 Subject: [PATCH 246/329] inline input_device in virtualkeyboard() --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 9420ae5..27d5fae 100644 --- a/dwl.c +++ b/dwl.c @@ -2433,8 +2433,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->input_device; - createkeyboard(device); + createkeyboard(&keyboard->input_device); } Monitor * From c50904666334375f50e69e3c030d6a7a67bf8c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:42:58 -0500 Subject: [PATCH 247/329] add some comments --- dwl.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 27d5fae..24902bf 100644 --- a/dwl.c +++ b/dwl.c @@ -389,6 +389,8 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); + /* Some clients set them max size to INT_MAX, which does not violates + * the protocol but its innecesary, they can set them max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) // Checks for overflow c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) // Checks for overflow @@ -522,6 +524,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + /* Unmapped surfaces shouldn't have exclusive zone */ if (!((LayerSurface *)wlr_layer_surface->data)->mapped || exclusive != (state->exclusive_zone > 0)) continue; @@ -631,6 +634,8 @@ axisnotify(struct wl_listener *listener, void *data) * for example when you move the scroll wheel. */ struct wlr_event_pointer_axis *event = data; wlr_idle_notify_activity(idle, seat); + /* TODO: allow usage of scroll whell for mousebindings, it can be implemented + * checking the event's orientation and the delta of the event */ /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, event->delta, @@ -700,6 +705,8 @@ checkidleinhibitor(struct wlr_surface *exclude) Client *c; if (exclude == inhibitor->surface) continue; + /* In case we can't get a client from the surface assume that it is + * visible, for example a layer surface */ if (!(c = client_from_wlr_surface(inhibitor->surface)) || VISIBLEON(c, c->mon)) { inhibited = 1; @@ -789,6 +796,8 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_output *wlr_output = wlr_layer_surface->output; + /* For some reason this layersurface have no monitor, this can be because + * its monitor has just been destroyed */ if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; @@ -980,9 +989,14 @@ createnotify(struct wl_listener *listener, void *data) LayerSurface *l = toplevel_from_popup(xdg_surface->popup); xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); + /* Raise to top layer if the inmediate parent of the popup is on + * bottom/background layer, which will cause popups appear below the + * x{dg,wayland} clients */ if (wlr_surface_is_layer_surface(xdg_surface->popup->parent) && l && l->layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) wlr_scene_node_reparent(xdg_surface->surface->data, layers[LyrTop]); + /* Probably the check of `l` is useless, the only thing that can be NULL + * is its monitor */ if (!l || !l->mon) return; box = l->type == LayerShell ? l->mon->m : l->mon->w; @@ -1158,9 +1172,7 @@ focusclient(Client *c, int lift) if (old && (!c || client_surface(c) != old)) { /* If an overlay is focused, don't focus or activate the client, * but only update its position in fstack to render its border with focuscolor - * and focus it after the overlay is closed. - * It's probably pointless to check if old is a layer surface - * since it can't be anything else at this point. */ + * and focus it after the overlay is closed. */ if (wlr_surface_is_layer_surface(old)) { struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); @@ -1233,6 +1245,9 @@ focusstack(const Arg *arg) focusclient(c, 1); } +/* We probably should change the name of this, it sounds like + * will focus the topmost client of this mon, when actually will + * only return that client */ Client * focustop(Monitor *m) { @@ -1398,14 +1413,17 @@ mapnotify(struct wl_listener *listener, void *data) } c->scene->data = c->scene_surface->data = c; +#ifdef XWAYLAND + /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); - /* Floating */ + /* Unmanaged clients always are floating */ wlr_scene_node_reparent(c->scene, layers[LyrFloat]); wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, c->geom.y + borderpx); return; } +#endif for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); @@ -1482,6 +1500,7 @@ motionnotify(uint32_t time) selmon = xytomon(cursor->x, cursor->y); } + /* Update drag icon's position if any */ if (seat->drag && (icon = seat->drag->icon)) wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, cursor->y + icon->surface->sy); @@ -2533,6 +2552,7 @@ createnotifyx11(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xwayland_surface = data; Client *c; + /* TODO: why we unset fullscreen when a xwayland client is created? */ wl_list_for_each(c, &clients, link) if (c->isfullscreen && VISIBLEON(c, c->mon)) setfullscreen(c, 0); From 77ba8e51276ce94515913091d669db21e856e8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:44:19 -0500 Subject: [PATCH 248/329] use wl_container_of() instead of data in some functions --- dwl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 24902bf..bcc0804 100644 --- a/dwl.c +++ b/dwl.c @@ -739,8 +739,7 @@ cleanup(void) void cleanupkeyboard(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - Keyboard *kb = device->data; + Keyboard *kb = wl_container_of(listener, kb, destroy); wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); @@ -752,14 +751,13 @@ cleanupkeyboard(struct wl_listener *listener, void *data) void cleanupmon(struct wl_listener *listener, void *data) { - struct wlr_output *wlr_output = data; - Monitor *m = wlr_output->data; + Monitor *m = wl_container_of(listener, m, destroy); int nmons, i = 0; wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); wl_list_remove(&m->link); - wlr_output->data = NULL; + m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); From fd67087a82d52f79cb3f02f9048ee4dd603fd8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:45:14 -0500 Subject: [PATCH 249/329] make sure the parent is mapped prior set monitor and tags --- dwl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index bcc0804..be94832 100644 --- a/dwl.c +++ b/dwl.c @@ -1439,13 +1439,14 @@ mapnotify(struct wl_listener *listener, void *data) wl_list_insert(&clients, &c->link); wl_list_insert(&fstack, &c->flink); - /* Set initial monitor, tags, floating status, and focus */ - if ((p = client_get_parent(c))) { - /* Set the same monitor and tags than its parent */ + /* Set initial monitor, tags, floating status, and focus: + * we always consider floating, clients that have parent and thus + * we set the same tags and monitor than its parent, if not + * try to apply rules for them */ + if ((p = client_get_parent(c)) && client_is_mapped(p)) { c->isfloating = 1; wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - /* TODO recheck if !p->mon is possible with wlroots 0.16.0 */ - setmon(c, p->mon ? p->mon : selmon, p->tags); + setmon(c, p->mon, p->tags); } else { applyrules(c); } From c8a9f634515cbf5a943a982bb4b603682c0eca22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:48:38 -0500 Subject: [PATCH 250/329] prior run the startup command start the backend this allow use clients like wlr-randr in the startup command --- dwl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index be94832..09e60ec 100644 --- a/dwl.c +++ b/dwl.c @@ -1817,7 +1817,12 @@ run(char *startup_cmd) die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); - /* Now that the socket exists, run the startup command */ + /* Start the backend. This will enumerate outputs and inputs, become the DRM + * master, etc */ + if (!wlr_backend_start(backend)) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup command */ if (startup_cmd) { int piperw[2]; if (pipe(piperw) < 0) @@ -1839,12 +1844,7 @@ run(char *startup_cmd) signal(SIGPIPE, SIG_IGN); printstatus(); - /* Start the backend. This will enumerate outputs and inputs, become the DRM - * master, etc */ - if (!wlr_backend_start(backend)) - die("startup: backend_start"); - - /* Now that outputs are initialized, choose initial selmon based on + /* At this point the outputs are initialized, choose initial selmon based on * cursor position, and set default cursor image */ selmon = xytomon(cursor->x, cursor->y); From ba7dcb2dea2d5dc46b73b6b9194daab94a325a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:45:57 -0500 Subject: [PATCH 251/329] don't try to move outputs when its x,y hasn't change when using wlr_output_layout_move() wlroots internally change the state of the output to manually configured and when updating the layout these outputs aren't ignored by wlroots, leaving us at our own --- dwl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 09e60ec..8557540 100644 --- a/dwl.c +++ b/dwl.c @@ -1607,6 +1607,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) /* Then enable outputs that need to */ wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; + Monitor *m = wlr_output->data; if (!config_head->state.enabled) continue; @@ -1619,8 +1620,11 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) config_head->state.custom_mode.height, config_head->state.custom_mode.refresh); - wlr_output_layout_move(output_layout, wlr_output, - config_head->state.x, config_head->state.y); + /* Don't move monitors if position wouldn't change, this to avoid + * wlroots marking the output as manually configured */ + if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) + wlr_output_layout_move(output_layout, wlr_output, + config_head->state.x, config_head->state.y); wlr_output_set_transform(wlr_output, config_head->state.transform); wlr_output_set_scale(wlr_output, config_head->state.scale); From bcc8ce7a40d30023eb97934419c2102c91846563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:16:10 -0500 Subject: [PATCH 252/329] fix segfault when unlocking swaylock on two monitor setup wlr_*_surface_from_wlr_surface() can return NULL if the surface is being destroyed Fixes: https://github.com/djpohly/dwl/issues/305 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8557540..4d8100d 100644 --- a/dwl.c +++ b/dwl.c @@ -1175,7 +1175,7 @@ focusclient(Client *c, int lift) struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); - if (wlr_layer_surface->mapped && ( + if (wlr_layer_surface && wlr_layer_surface->mapped && ( wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY )) From bc72af6e2430cfb8db2f5fa1b9800c86f445b6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:20:00 -0500 Subject: [PATCH 253/329] fix unmanaged clients not being unlinked from the commit listener --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 4d8100d..8ed6ae3 100644 --- a/dwl.c +++ b/dwl.c @@ -2362,14 +2362,14 @@ unmapnotify(struct wl_listener *listener, void *data) if (c->mon) c->mon->un_map = 1; - if (client_is_unmanaged(c)) { - wlr_scene_node_destroy(c->scene); - return; - } + if (client_is_unmanaged(c)) + goto end; wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); + +end: wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); From cd96f889b8a254d4005d1f0cff71f8031d00ecd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:21:19 -0500 Subject: [PATCH 254/329] fix use of loop initial declaration forbidden by the suckless style --- dwl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 8ed6ae3..30bafa9 100644 --- a/dwl.c +++ b/dwl.c @@ -412,6 +412,7 @@ applyexclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, int32_t margin_bottom, int32_t margin_left) { + size_t i; Edge edges[] = { { /* Top */ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, @@ -450,7 +451,7 @@ applyexclusive(struct wlr_box *usable_area, .margin = margin_right, } }; - for (size_t i = 0; i < LENGTH(edges); i++) { + for (i = 0; i < LENGTH(edges); i++) { if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) && exclusive + edges[i].margin > 0) { if (edges[i].positive_axis) @@ -612,7 +613,7 @@ arrangelayers(Monitor *m) arrangelayer(m, &m->layers[i], &usable_area, 0); /* Find topmost keyboard interactive layer, if such a layer exists */ - for (size_t i = 0; i < LENGTH(layers_above_shell); i++) { + for (i = 0; i < LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && @@ -922,13 +923,14 @@ createmon(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = data; const MonitorRule *r; Client *c; + size_t i; Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; wlr_output_init_render(wlr_output, alloc, drw); /* Initialize monitor state using configured rules */ - for (size_t i = 0; i < LENGTH(m->layers); i++) + for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); m->tagset[0] = m->tagset[1] = 1; for (r = monrules; r < END(monrules); r++) { From d14ee99661e420c8e3d8fcc6791429a0e08bd915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:33:58 -0500 Subject: [PATCH 255/329] remove useless check of `m` in arrangelayers() it is supossed to avoid a crash when we pass m=NULL as argument however it would crash anyway and also because we should not pass m=NULL --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index 30bafa9..798ba80 100644 --- a/dwl.c +++ b/dwl.c @@ -596,8 +596,6 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; - if (!m || !m->wlr_output->enabled) - return; /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) From 7710cf050d1a66f35fc590e0000bb300a707a5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:04:46 -0500 Subject: [PATCH 256/329] change the default term to `foot` it is closer to the suckless philosophy (foot implements things that the suckless guys would say that should be done by tmux or something else, but I have no desire to create a new terminal emulator, and the best fit is foot) also alacritty uses +100Mb of memory, more that dwl itself (~90Mb) and foot only ~20Mb --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 29c6dbf..ec1f052 100644 --- a/config.def.h +++ b/config.def.h @@ -98,7 +98,7 @@ static const double accel_speed = 0.0; #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } /* commands */ -static const char *termcmd[] = { "alacritty", NULL }; +static const char *termcmd[] = { "foot", NULL }; static const char *menucmd[] = { "bemenu-run", NULL }; static const Key keys[] = { From d11358762d3693e8e268ecf01861f522a0dc96f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:49:30 -0500 Subject: [PATCH 257/329] add missing library (xcb-icccm) this library is also used by wlroots, so nothing new --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 4638d5f..c7b5d16 100644 --- a/config.mk +++ b/config.mk @@ -12,4 +12,4 @@ XWAYLAND = XLIBS = # Uncomment to build XWayland support #XWAYLAND = -DXWAYLAND -#XLIBS = xcb +#XLIBS = xcb xcb-icccm From a1b33826cfeb9a6764428c44cfba7d26089b40be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 16:36:18 -0500 Subject: [PATCH 258/329] Revert "remove useless check of `m` in arrangelayers()" This partially reverts commit d14ee99661e420c8e3d8fcc6791429a0e08bd915. Checking if the output is enabled is necessary to avoid a segfault later --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 798ba80..36d3327 100644 --- a/dwl.c +++ b/dwl.c @@ -596,6 +596,8 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; + if (!m->wlr_output->enabled) + return; /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) From 570e6e2c2763bc3a7bd270a9571cfedeb1083fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 16:50:29 -0500 Subject: [PATCH 259/329] fix clients not being focused after destroy a layer surface --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 36d3327..a64f4e7 100644 --- a/dwl.c +++ b/dwl.c @@ -2340,11 +2340,11 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) layersurface->mapped = 0; wlr_scene_node_set_enabled(layersurface->scene, 0); + if (layersurface == exclusive_focus) + exclusive_focus = NULL; if (layersurface->layer_surface->output && (layersurface->mon = layersurface->layer_surface->output->data)) arrangelayers(layersurface->mon); - if (layersurface == exclusive_focus) - exclusive_focus = NULL; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(selclient(), 1); From fbaeb853638a984c69045923eb662d783035762c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 17:23:07 -0500 Subject: [PATCH 260/329] now really fix clients not being focused after unmapping a layer surface --- dwl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index a64f4e7..c1fb9c1 100644 --- a/dwl.c +++ b/dwl.c @@ -617,7 +617,7 @@ arrangelayers(Monitor *m) wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && - layersurface->layer_surface->mapped) { + layersurface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); exclusive_focus = layersurface; @@ -1177,10 +1177,9 @@ focusclient(Client *c, int lift) struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); - if (wlr_layer_surface && wlr_layer_surface->mapped && ( - wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || - wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY - )) + if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped + && (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP + || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)) return; } else { Client *w; From 1fdc65ff930a326c92b58129970026daec400862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 17:25:12 -0500 Subject: [PATCH 261/329] make more permissive exclusive focus now you can call focusstack() while a layer surface is focused and when it gets unmapped the newly focused clients will be actually focused --- dwl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index c1fb9c1..270f8f0 100644 --- a/dwl.c +++ b/dwl.c @@ -1145,9 +1145,6 @@ focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; int i; - /* Do not focus clients if a layer surface is focused */ - if (exclusive_focus) - return; /* Raise client in stacking order if requested */ if (c && lift) @@ -1164,8 +1161,11 @@ focusclient(Client *c, int lift) c->isurgent = 0; client_restack_surface(c); - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], focuscolor); + /* Don't change border color if there is a exclusive focus + * (at this moment it means that a layer surface is focused) */ + if (!exclusive_focus) + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], focuscolor); } /* Deactivate old client if focus is changing */ From 31106eff64406a004beb18c265a8b6fa0ae4f7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 20 Sep 2022 23:34:48 -0500 Subject: [PATCH 262/329] rework Makefile - allow user to use a different pkg-config binary - restore almost all (and add other ones) warning flags (-Werror is not set) - $(XWAYLAND) is added to our CPPFLAGS - remove useless comments - don't generate idle-protocol.h (not used) --- Makefile | 31 +++++++++++-------------------- config.mk | 5 ++--- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 4afd717..6605796 100644 --- a/Makefile +++ b/Makefile @@ -4,45 +4,38 @@ include config.mk # flags for compiling -DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" - -# Wayland utils -WAYLAND_PROTOCOLS = `pkg-config --variable=pkgdatadir wayland-protocols` -WAYLAND_SCANNER = `pkg-config --variable=wayland_scanner wayland-scanner` +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) +DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) -DWLCFLAGS = `pkg-config --cflags $(PKGS)` $(DWLCPPFLAGS) $(CFLAGS) $(XWAYLAND) -LDLIBS = `pkg-config --libs $(PKGS)` $(LIBS) +DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) +LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) -# build rules +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 xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland # protocols, which are specified in XML. wlroots requires you to rig these up # to your build system yourself and provide them in the include path. -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 xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h -util.o: util.c util.h +WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner` +WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` -# wayland scanner rules to generate .h / .c files xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ wlr-layer-shell-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ -idle-protocol.h: - $(WAYLAND_SCANNER) server-header \ - protocols/idle.xml $@ config.h: cp config.def.h $@ clean: rm -f dwl *.o *-protocol.h -# distribution archive dist: clean mkdir -p dwl-$(VERSION) cp -R LICENSE* Makefile README.md client.h config.def.h\ @@ -51,8 +44,6 @@ dist: clean tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) rm -rf dwl-$(VERSION) -# install rules - install: dwl mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f dwl $(DESTDIR)$(PREFIX)/bin diff --git a/config.mk b/config.mk index 55c7262..091c03a 100644 --- a/config.mk +++ b/config.mk @@ -1,13 +1,12 @@ _VERSION = 0.3.1-dev VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` +PKG_CONFIG = pkg-config + # paths PREFIX = /usr/local MANDIR = $(PREFIX)/share/man -# Compile flags that can be used -#CFLAGS = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement - XWAYLAND = XLIBS = # Uncomment to build XWayland support From 2385d826122d24b72cab2ce531ad538d87407622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 20 Sep 2022 23:40:35 -0500 Subject: [PATCH 263/329] remove unused variables --- client.h | 2 -- dwl.c | 1 - 2 files changed, 3 deletions(-) diff --git a/client.h b/client.h index a881131..4ecdd47 100644 --- a/client.h +++ b/client.h @@ -20,7 +20,6 @@ static inline Client * client_from_wlr_surface(struct wlr_surface *s) { struct wlr_xdg_surface *surface; - struct wlr_surface *parent; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; @@ -41,7 +40,6 @@ client_from_wlr_surface(struct wlr_surface *s) static inline Client * client_get_parent(Client *c) { - Client *p; #ifdef XWAYLAND if (client_is_x11(c) && c->surface.xwayland->parent) return client_from_wlr_surface(c->surface.xwayland->parent->surface); diff --git a/dwl.c b/dwl.c index 270f8f0..6fbc771 100644 --- a/dwl.c +++ b/dwl.c @@ -922,7 +922,6 @@ createmon(struct wl_listener *listener, void *data) * monitor) becomes available. */ struct wlr_output *wlr_output = data; const MonitorRule *r; - Client *c; size_t i; Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; From e46238b95ee3e74ee7a54e592276e8b1be2f0ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 22 Sep 2022 14:36:53 -0500 Subject: [PATCH 264/329] change cursor surface in internal calls of motionnotify() and call motionnotify() after unmapping a client and when focusing a client Fixes: https://github.com/djpohly/dwl/issues/308 --- dwl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6fbc771..3538cf3 100644 --- a/dwl.c +++ b/dwl.c @@ -1199,6 +1199,9 @@ focusclient(Client *c, int lift) return; } + /* Change cursor surface */ + motionnotify(0); + /* Have a client, so focus its top-level wlr_surface */ client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); @@ -1521,7 +1524,7 @@ motionnotify(uint32_t time) /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ - if (!surface && time) + if (!surface) wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); pointerfocus(c, surface, sx, sy, time); @@ -2373,6 +2376,7 @@ end: wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); + motionnotify(0); } void From c00faae26370682c307cfb107b12123d10d49053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Sep 2022 23:04:18 -0500 Subject: [PATCH 265/329] fix various segfaults when selmon is NULL --- dwl.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 3538cf3..0bb551e 100644 --- a/dwl.c +++ b/dwl.c @@ -880,7 +880,10 @@ createlayersurface(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1_state old_state; if (!wlr_layer_surface->output) - wlr_layer_surface->output = selmon->wlr_output; + wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; + + if (!wlr_layer_surface->output) + wlr_layer_surface_v1_destroy(wlr_layer_surface); layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; @@ -1269,6 +1272,8 @@ fullscreennotify(struct wl_listener *listener, void *data) void incnmaster(const Arg *arg) { + if (!arg || !selmon) + return; selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1948,6 +1953,8 @@ setfullscreen(Client *c, int fullscreen) void setlayout(const Arg *arg) { + if (!selmon) + return; if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) selmon->sellt ^= 1; if (arg && arg->v) @@ -1963,7 +1970,7 @@ setmfact(const Arg *arg) { float f; - if (!arg || !selmon->lt[selmon->sellt]->arrange) + if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) return; f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.1 || f > 0.9) @@ -2250,9 +2257,8 @@ void tagmon(const Arg *arg) { Client *sel = selclient(); - if (!sel) - return; - setmon(sel, dirtomon(arg->i), 0); + if (sel) + setmon(sel, dirtomon(arg->i), 0); } void @@ -2324,7 +2330,7 @@ toggletag(const Arg *arg) void toggleview(const Arg *arg) { - unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; @@ -2445,7 +2451,7 @@ urgent(struct wl_listener *listener, void *data) void view(const Arg *arg) { - if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + if (selmon && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) @@ -2507,7 +2513,7 @@ zoom(const Arg *arg) { Client *c, *sel = selclient(); - if (!sel || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) + if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) return; /* Search for the first tiled window that is not sel, marking sel as From fc8b2a8335365dbf3966f0a9bb783a4cb33fdcbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 26 Sep 2022 20:31:36 -0500 Subject: [PATCH 266/329] fix bad condition --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 0bb551e..cc08787 100644 --- a/dwl.c +++ b/dwl.c @@ -2451,7 +2451,7 @@ urgent(struct wl_listener *listener, void *data) void view(const Arg *arg) { - if (selmon && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) From c13d948ea90fa55fb5b3180f2aa0ee4114ef6df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 14:15:25 -0500 Subject: [PATCH 267/329] destroy renderer and allocator in cleanup() --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index cc08787..e7571fe 100644 --- a/dwl.c +++ b/dwl.c @@ -730,6 +730,8 @@ cleanup(void) waitpid(child_pid, NULL, 0); } wlr_backend_destroy(backend); + wlr_renderer_destroy(drw); + wlr_allocator_destroy(alloc); wlr_xcursor_manager_destroy(cursor_mgr); wlr_cursor_destroy(cursor); wlr_output_layout_destroy(output_layout); From b5776e5180010ead5232efb36b2490f4fc9e1366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 16:20:31 -0500 Subject: [PATCH 268/329] avoid setting duplicate cursor image Reference: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3436 Based on: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3595 --- dwl.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index e7571fe..339ebe5 100644 --- a/dwl.c +++ b/dwl.c @@ -298,6 +298,7 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; +static const char *cursor_image = "left_ptr"; static pid_t child_pid = -1; static void *exclusive_focus; static struct wl_display *dpy; @@ -674,10 +675,13 @@ buttonpress(struct wl_listener *listener, void *data) break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ - /* TODO should reset to the pointer focus's current setcursor */ if (cursor_mode != CurNormal) { - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); cursor_mode = CurNormal; + /* Clear the pointer focus, this way if the cursor is over a surface + * we will send an enter event after which the client will provide us + * a cursor surface */ + wlr_seat_pointer_clear_focus(seat); + motionnotify(0); /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); setmon(grabc, selmon, 0); @@ -1531,8 +1535,8 @@ motionnotify(uint32_t time) /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ - if (!surface) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + if (!surface && (!cursor_image || strcmp(cursor_image, "left_ptr"))) + wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); pointerfocus(c, surface, sx, sy, time); } @@ -1567,7 +1571,7 @@ moveresize(const Arg *arg) case CurMove: grabcx = cursor->x - grabc->geom.x; grabcy = cursor->y - grabc->geom.y; - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "fleur", cursor); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor); break; case CurResize: /* Doesn't work for X11 output - the next absolute motion event @@ -1576,7 +1580,7 @@ moveresize(const Arg *arg) grabc->geom.x + grabc->geom.width, grabc->geom.y + grabc->geom.height); wlr_xcursor_manager_set_cursor_image(cursor_mgr, - "bottom_right_corner", cursor); + (cursor_image = "bottom_right_corner"), cursor); break; } } @@ -1702,7 +1706,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, * wlroots makes this a no-op if surface is already focused */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); - } void @@ -1867,7 +1870,7 @@ run(char *startup_cmd) * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event @@ -1890,10 +1893,12 @@ setcursor(struct wl_listener *listener, void *data) { /* This event is raised by the seat when a client provides a cursor image */ struct wlr_seat_pointer_request_set_cursor_event *event = data; - /* If we're "grabbing" the cursor, don't use the client's image */ - /* TODO still need to save the provided surface to restore later */ + /* If we're "grabbing" the cursor, don't use the client's image, we will + * restore it after "grabbing" sending a leave event, followed by a enter + * event, which will result in the client requesting set the cursor surface */ if (cursor_mode != CurNormal) return; + cursor_image = NULL; /* This can be sent by any client, so we check to make sure this one is * actually has pointer focus first. If so, we can tell the cursor to * use the provided surface as the cursor image. It will set the From b8bc54b65d7dfaf1c7aa92de32f8ca37d8e011f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 18:29:59 -0500 Subject: [PATCH 269/329] properly handle cursor motion when button is held Based on: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3653 --- dwl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 339ebe5..b4fa1ef 100644 --- a/dwl.c +++ b/dwl.c @@ -66,7 +66,7 @@ #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) /* enums */ -enum { CurNormal, CurMove, CurResize }; /* cursor */ +enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND @@ -672,10 +672,11 @@ buttonpress(struct wl_listener *listener, void *data) return; } } + cursor_mode = CurPressed; break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ - if (cursor_mode != CurNormal) { + if (cursor_mode != CurNormal && cursor_mode != CurPressed) { cursor_mode = CurNormal; /* Clear the pointer focus, this way if the cursor is over a surface * we will send an enter event after which the client will provide us @@ -686,6 +687,8 @@ buttonpress(struct wl_listener *listener, void *data) selmon = xytomon(cursor->x, cursor->y); setmon(grabc, selmon, 0); return; + } else { + cursor_mode = CurNormal; } break; } @@ -1532,6 +1535,13 @@ motionnotify(uint32_t time) /* Find the client under the pointer and send the event along. */ xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + if (cursor_mode == CurPressed) { + surface = seat->pointer_state.focused_surface; + c = client_from_wlr_surface(surface); + sx = c ? cursor->x - c->geom.x : 0; + sy = c ? cursor->y - c->geom.y : 0; + } + /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ From 434ed119f3427c1539aff95c57977c35921afb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 1 Oct 2022 23:33:17 -0500 Subject: [PATCH 270/329] wlroots check map state of layersurfaces this for us --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index eb072bb..32a1650 100644 --- a/dwl.c +++ b/dwl.c @@ -456,9 +456,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; - /* Unmapped surfaces shouldn't have exclusive zone */ - if (!((LayerSurface *)wlr_layer_surface->data)->mapped - || exclusive != (state->exclusive_zone > 0)) + if (exclusive != (state->exclusive_zone > 0)) continue; wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); From 8559141b30bfa9acdad4c2385b712b5ee51e1794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 3 Oct 2022 23:28:58 -0500 Subject: [PATCH 271/329] avoid usage of goto Based on this suggestion: https://github.com/guyuming76/dwl/commit/bc72af6e2430cfb8db2f5fa1b9800c86f445b6d6#commitcomment-85592855 --- dwl.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index b4fa1ef..5f9cbcd 100644 --- a/dwl.c +++ b/dwl.c @@ -2388,14 +2388,12 @@ unmapnotify(struct wl_listener *listener, void *data) if (c->mon) c->mon->un_map = 1; - if (client_is_unmanaged(c)) - goto end; + if (!client_is_unmanaged(c)) { + wl_list_remove(&c->link); + setmon(c, NULL, 0); + wl_list_remove(&c->flink); + } - wl_list_remove(&c->link); - setmon(c, NULL, 0); - wl_list_remove(&c->flink); - -end: wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); From 87c4c1f62947d927084e3b2cca224dba72e9f0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 5 Oct 2022 21:28:14 -0500 Subject: [PATCH 272/329] convert some warnings to errors --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6605796..ccca079 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ include config.mk # flags for compiling DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) -DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros +DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\ + -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) From f6820a6c29b6bcb9a14166793d7f1fba2f98444e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 7 Oct 2022 00:02:29 -0500 Subject: [PATCH 273/329] fix drag and drop not working this fixes another issue where the cursor doesn't change when selecting text but there is still an issue about not changing border color of clients during dnd operations Bug: https://github.com/djpohly/dwl/issues/318 --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 5f9cbcd..fc8f7b2 100644 --- a/dwl.c +++ b/dwl.c @@ -1535,7 +1535,7 @@ motionnotify(uint32_t time) /* Find the client under the pointer and send the event along. */ xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); - if (cursor_mode == CurPressed) { + if (cursor_mode == CurPressed && !seat->drag) { surface = seat->pointer_state.focused_surface; c = client_from_wlr_surface(surface); sx = c ? cursor->x - c->geom.x : 0; @@ -1545,7 +1545,7 @@ motionnotify(uint32_t time) /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ - if (!surface && (!cursor_image || strcmp(cursor_image, "left_ptr"))) + if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr"))) wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); pointerfocus(c, surface, sx, sy, time); @@ -1906,7 +1906,7 @@ setcursor(struct wl_listener *listener, void *data) /* If we're "grabbing" the cursor, don't use the client's image, we will * restore it after "grabbing" sending a leave event, followed by a enter * event, which will result in the client requesting set the cursor surface */ - if (cursor_mode != CurNormal) + if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; cursor_image = NULL; /* This can be sent by any client, so we check to make sure this one is From 0d1ca4663ca62329e1e171053ceb35bbc71ec30a Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Sat, 8 Oct 2022 13:20:34 +0000 Subject: [PATCH 274/329] allow moveresize() while the left mouse button is pressed Fixes: https://github.com/djpohly/dwl/issues/319 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index fc8f7b2..3fdef90 100644 --- a/dwl.c +++ b/dwl.c @@ -1569,7 +1569,7 @@ motionrelative(struct wl_listener *listener, void *data) void moveresize(const Arg *arg) { - if (cursor_mode != CurNormal) + if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); if (!grabc || client_is_unmanaged(grabc)) From 952fde68a3cb1871f39c464d56f999d5a966e7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Oct 2022 13:00:03 -0500 Subject: [PATCH 275/329] correctly handle cursor motion when button is held (for layer surfaces) --- client.h | 15 +++++++++++++++ dwl.c | 11 +++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/client.h b/client.h index 4ecdd47..09e7609 100644 --- a/client.h +++ b/client.h @@ -307,3 +307,18 @@ toplevel_from_popup(struct wlr_xdg_popup *popup) } } } + +static inline void * +toplevel_from_wlr_layer_surface(struct wlr_surface *s) +{ + Client *c; + struct wlr_layer_surface_v1 *wlr_layer_surface; + + if ((c = client_from_wlr_surface(s))) + return c; + else if (s && wlr_surface_is_layer_surface(s) + && (wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(s))) + return wlr_layer_surface->data; + + return NULL; +} diff --git a/dwl.c b/dwl.c index 3fdef90..76430aa 100644 --- a/dwl.c +++ b/dwl.c @@ -1504,6 +1504,7 @@ motionnotify(uint32_t time) { double sx = 0, sy = 0; Client *c = NULL; + LayerSurface *l; struct wlr_surface *surface = NULL; struct wlr_drag_icon *icon; @@ -1536,10 +1537,12 @@ motionnotify(uint32_t time) xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag) { - surface = seat->pointer_state.focused_surface; - c = client_from_wlr_surface(surface); - sx = c ? cursor->x - c->geom.x : 0; - sy = c ? cursor->y - c->geom.y : 0; + if ((l = toplevel_from_wlr_layer_surface( + seat->pointer_state.focused_surface))) { + surface = seat->pointer_state.focused_surface; + sx = cursor->x - l->geom.x; + sy = cursor->y - l->geom.y; + } } /* If there's no client surface under the cursor, set the cursor image to a From 7f3c9fa0ae83c9113b10b0e1b92ae2bc53836c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Oct 2022 20:48:48 -0500 Subject: [PATCH 276/329] rename LyrNoFocus -> LyrDragIcon --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 76430aa..8c02b40 100644 --- a/dwl.c +++ b/dwl.c @@ -68,7 +68,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrDragIcon, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -2080,7 +2080,7 @@ setup(void) layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrNoFocus] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrDragIcon] = &wlr_scene_tree_create(&scene->node)->node; /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2256,7 +2256,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrNoFocus], drag->icon->surface); + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From 3902fba76961beff924e900e3de3f952d7f98bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Oct 2022 20:50:17 -0500 Subject: [PATCH 277/329] rename dragicondestroy() -> destroydragicon() to match the rest of the code --- dwl.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dwl.c b/dwl.c index 8c02b40..78e8d54 100644 --- a/dwl.c +++ b/dwl.c @@ -229,11 +229,11 @@ static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); 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); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); -static void dragicondestroy(struct wl_listener *listener, void *data); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -340,6 +340,7 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_frame = {.notify = cursorframe}; static struct wl_listener cursor_motion = {.notify = motionrelative}; static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; +static struct wl_listener drag_icon_destroy = {.notify = destroydragicon}; static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor}; static struct wl_listener layout_change = {.notify = updatemons}; @@ -356,7 +357,6 @@ static struct wl_listener request_set_psel = {.notify = setpsel}; 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}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -1085,6 +1085,16 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +destroydragicon(struct wl_listener *listener, void *data) +{ + struct wlr_drag_icon *icon = data; + wlr_scene_node_destroy(icon->data); + /* Focus enter isn't sent during drag, so refocus the focused node. */ + focusclient(selclient(), 1); + motionnotify(0); +} + void destroyidleinhibitor(struct wl_listener *listener, void *data) { @@ -1141,16 +1151,6 @@ dirtomon(enum wlr_direction dir) return selmon; } -void -dragicondestroy(struct wl_listener *listener, void *data) -{ - struct wlr_drag_icon *icon = data; - wlr_scene_node_destroy(icon->data); - // Focus enter isn't sent during drag, so refocus the focused node. - focusclient(selclient(), 1); - motionnotify(0); -} - void focusclient(Client *c, int lift) { From 1438dfc1509b22612166407c565f65f635d3ab97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Oct 2022 20:51:05 -0500 Subject: [PATCH 278/329] fix bad indentation in createpointer() --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 78e8d54..c77464f 100644 --- a/dwl.c +++ b/dwl.c @@ -1059,8 +1059,8 @@ createpointer(struct wlr_input_device *device) if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) libinput_device_config_scroll_set_method (libinput_device, scroll_method); - if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) - libinput_device_config_click_set_method (libinput_device, click_method); + if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (libinput_device, click_method); if (libinput_device_config_send_events_get_modes(libinput_device)) libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); From 765656902fdaaf8c4320d4a16ea8cba4294656a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Oct 2022 20:51:40 -0500 Subject: [PATCH 279/329] use `/* */` for comments in applybounds() --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index c77464f..29c9eea 100644 --- a/dwl.c +++ b/dwl.c @@ -392,9 +392,9 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); /* Some clients set them max size to INT_MAX, which does not violates * the protocol but its innecesary, they can set them max size to zero. */ - if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) // Checks for overflow + if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); - if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) // Checks for overflow + if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); } From 4eabf6f7eb4ec596e41db4ced0c5ac7149e0eaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 11 Oct 2022 13:11:14 -0500 Subject: [PATCH 280/329] disable and destroy monitor's layer surfaces when it's being destroyed Fixes: https://github.com/djpohly/dwl/issues/314 --- dwl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 29c9eea..64bf2e2 100644 --- a/dwl.c +++ b/dwl.c @@ -762,7 +762,15 @@ void cleanupmon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, destroy); - int nmons, i = 0; + LayerSurface *l, *tmp; + int nmons, i; + + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { + wl_list_for_each_safe(l, tmp, &m->layers[i], link) { + wlr_scene_node_set_enabled(l->scene, 0); + wlr_layer_surface_v1_destroy(l->layer_surface); + } + } wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); @@ -771,7 +779,7 @@ cleanupmon(struct wl_listener *listener, void *data) wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); - if ((nmons = wl_list_length(&mons))) + if (!(i = 0) && (nmons = wl_list_length(&mons))) do /* don't switch to disabled mons */ selmon = wl_container_of(mons.prev, selmon, link); while (!selmon->wlr_output->enabled && i++ < nmons); From 9e912cf790b6f4120dd4baaee1aad924f279581b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 13 Oct 2022 22:05:09 -0500 Subject: [PATCH 281/329] delete the idle protocol xml file --- protocols/idle.xml | 49 ---------------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 protocols/idle.xml diff --git a/protocols/idle.xml b/protocols/idle.xml deleted file mode 100644 index 92d9989..0000000 --- a/protocols/idle.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - . - ]]> - - - This interface allows to monitor user idle time on a given seat. The interface - allows to register timers which trigger after no user activity was registered - on the seat for a given interval. It notifies when user activity resumes. - - This is useful for applications wanting to perform actions when the user is not - interacting with the system, e.g. chat applications setting the user as away, power - management features to dim screen, etc.. - - - - - - - - - - - - - - - - - - - - - - From 332ceb7136da268ff3e62f32d40bc8969f0aca37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Jun 2022 16:05:07 -0500 Subject: [PATCH 282/329] allow unmanaged clients (like dzen or dmenu) to have keyboard focus --- client.h | 11 +++++++++++ dwl.c | 29 ++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/client.h b/client.h index 09e7609..49982e0 100644 --- a/client.h +++ b/client.h @@ -275,6 +275,17 @@ client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); } +static inline int +client_wants_focus(Client *c) +{ +#ifdef XWAYLAND + return client_is_unmanaged(c) + && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland) + && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; +#endif + return 0; +} + static inline int client_wants_fullscreen(Client *c) { diff --git a/dwl.c b/dwl.c index 64bf2e2..2f0d9a6 100644 --- a/dwl.c +++ b/dwl.c @@ -659,8 +659,7 @@ buttonpress(struct wl_listener *listener, void *data) case WLR_BUTTON_PRESSED: /* Change focus if the button was _pressed_ over a client */ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); - /* Don't focus unmanaged clients */ - if (c && !client_is_unmanaged(c)) + if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) focusclient(c, 1); keyboard = wlr_seat_get_keyboard(seat); @@ -1173,7 +1172,7 @@ focusclient(Client *c, int lift) return; /* Put the new client atop the focus stack and select its monitor */ - if (c) { + if (c && !client_is_unmanaged(c)) { wl_list_remove(&c->flink); wl_list_insert(&fstack, &c->flink); selmon = c->mon; @@ -1192,6 +1191,7 @@ focusclient(Client *c, int lift) /* If an overlay is focused, don't focus or activate the client, * but only update its position in fstack to render its border with focuscolor * and focus it after the overlay is closed. */ + Client *w = client_from_wlr_surface(old); if (wlr_surface_is_layer_surface(old)) { struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); @@ -1200,11 +1200,13 @@ focusclient(Client *c, int lift) && (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)) return; - } else { - Client *w; - if ((w = client_from_wlr_surface(old))) - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(w->border[i], bordercolor); + } else if (w && w == exclusive_focus && client_wants_focus(w)) { + return; + /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg + * and probably other clients */ + } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(w->border[i], bordercolor); client_activate_surface(old, 0); } @@ -1444,6 +1446,10 @@ mapnotify(struct wl_listener *listener, void *data) wlr_scene_node_reparent(c->scene, layers[LyrFloat]); wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, c->geom.y + borderpx); + if (client_wants_focus(c)) { + focusclient(c, 1); + exclusive_focus = c; + } return; } #endif @@ -2399,7 +2405,12 @@ unmapnotify(struct wl_listener *listener, void *data) if (c->mon) c->mon->un_map = 1; - if (!client_is_unmanaged(c)) { + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) + exclusive_focus = NULL; + if (client_surface(c) == seat->keyboard_state.focused_surface) + focusclient(selclient(), 1); + } else { wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); From 2d9d758c8dec083178ff78b154da784b97260bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 15 Oct 2022 15:12:37 -0500 Subject: [PATCH 283/329] stop trying resize clients during commitnotify() instead resize them in configurex11() --- dwl.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/dwl.c b/dwl.c index 2f0d9a6..c7fe999 100644 --- a/dwl.c +++ b/dwl.c @@ -836,12 +836,6 @@ void commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); - struct wlr_box box = {0}; - client_get_geometry(c, &box); - - if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw - || box.height != c->geom.height - 2 * c->bw)) - arrange(c->mon); /* mark a pending resize as completed */ if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial @@ -1033,6 +1027,7 @@ createnotify(struct wl_listener *listener, void *data) LISTEN(&xdg_surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); @@ -1139,8 +1134,9 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->configure.link); wl_list_remove(&c->set_hints.link); wl_list_remove(&c->activate.link); - } + } else #endif + { wl_list_remove(&c->commit.link); } free(c); } @@ -1428,14 +1424,8 @@ mapnotify(struct wl_listener *listener, void *data) c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - if (client_surface(c)) { + if (client_surface(c)) client_surface(c)->data = c->scene; - /* Ideally we should do this in createnotify{,x11} but at that moment - * wlr_xwayland_surface doesn't have wlr_surface yet - */ - LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); - - } c->scene->data = c->scene_surface->data = c; #ifdef XWAYLAND @@ -2416,7 +2406,6 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->flink); } - wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); motionnotify(0); @@ -2592,9 +2581,12 @@ void configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); - struct wlr_xwayland_surface_configure_event *event = data; - wlr_xwayland_surface_configure(c->surface.xwayland, - event->x, event->y, event->width, event->height); + struct wlr_xwayland_surface_configure_event *e = data; + if (c->isfloating) + resize(c, (struct wlr_box){.x = e->x, .y = e->y, + .width = e->width, .height = e->height}, 0); + else + arrange(c->mon); } void From 110cde8f67e24d9d1d2483e19f7740612163ebb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 15 Oct 2022 18:09:42 -0500 Subject: [PATCH 284/329] update comment about exclusive focus in focusclient() --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index c7fe999..1a52255 100644 --- a/dwl.c +++ b/dwl.c @@ -1175,8 +1175,7 @@ focusclient(Client *c, int lift) c->isurgent = 0; client_restack_surface(c); - /* Don't change border color if there is a exclusive focus - * (at this moment it means that a layer surface is focused) */ + /* Don't change border color if there is an exclusive focus */ if (!exclusive_focus) for (i = 0; i < 4; i++) wlr_scene_rect_set_color(c->border[i], focuscolor); From e9826de2959609f597bc80137183828562315c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 15 Oct 2022 18:19:43 -0500 Subject: [PATCH 285/329] Revert "stop trying resize clients during commitnotify()" This reverts commit 2d9d758c8dec083178ff78b154da784b97260bd1. wasn't meant to be pushed to main --- dwl.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index 1a52255..a80de05 100644 --- a/dwl.c +++ b/dwl.c @@ -836,6 +836,12 @@ void commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); + struct wlr_box box = {0}; + client_get_geometry(c, &box); + + if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw + || box.height != c->geom.height - 2 * c->bw)) + arrange(c->mon); /* mark a pending resize as completed */ if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial @@ -1027,7 +1033,6 @@ createnotify(struct wl_listener *listener, void *data) LISTEN(&xdg_surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); @@ -1134,9 +1139,8 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->configure.link); wl_list_remove(&c->set_hints.link); wl_list_remove(&c->activate.link); - } else + } #endif - { wl_list_remove(&c->commit.link); } free(c); } @@ -1423,8 +1427,14 @@ mapnotify(struct wl_listener *listener, void *data) c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - if (client_surface(c)) + if (client_surface(c)) { client_surface(c)->data = c->scene; + /* Ideally we should do this in createnotify{,x11} but at that moment + * wlr_xwayland_surface doesn't have wlr_surface yet + */ + LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); + + } c->scene->data = c->scene_surface->data = c; #ifdef XWAYLAND @@ -2405,6 +2415,7 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->flink); } + wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); motionnotify(0); @@ -2580,12 +2591,9 @@ void configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); - struct wlr_xwayland_surface_configure_event *e = data; - if (c->isfloating) - resize(c, (struct wlr_box){.x = e->x, .y = e->y, - .width = e->width, .height = e->height}, 0); - else - arrange(c->mon); + struct wlr_xwayland_surface_configure_event *event = data; + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); } void From 1eeb3689d3ec5b917b5ccf730a6497e4b9fcd0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 23 Oct 2022 12:32:57 -0500 Subject: [PATCH 286/329] add support for the ext-idle-notify-v1 protocol for now we use macros to support both KDE idle and ext-idle, wlroots will likely drop support for KDE idle in 0.17 --- dwl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 32a1650..c29d554 100644 --- a/dwl.c +++ b/dwl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) +#define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -308,6 +310,7 @@ static struct wlr_xdg_activation_v1 *activation; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; +static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; @@ -511,7 +514,7 @@ axisnotify(struct wl_listener *listener, void *data) /* This event is forwarded by the cursor when a pointer emits an axis event, * for example when you move the scroll wheel. */ struct wlr_pointer_axis_event *event = data; - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* TODO: allow usage of scroll whell for mousebindings, it can be implemented * checking the event's orientation and the delta of the event */ /* Notify the client with pointer focus of the axis event. */ @@ -529,7 +532,7 @@ buttonpress(struct wl_listener *listener, void *data) Client *c; const Button *b; - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; switch (event->state) { case WLR_BUTTON_PRESSED: @@ -599,6 +602,7 @@ checkidleinhibitor(struct wlr_surface *exclude) } wlr_idle_set_enabled(idle, NULL, !inhibited); + wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } void @@ -1239,7 +1243,7 @@ keypress(struct wl_listener *listener, void *data) int handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ @@ -1403,7 +1407,7 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -2029,6 +2033,7 @@ setup(void) wl_list_init(&fstack); idle = wlr_idle_create(dpy); + idle_notifier = wlr_idle_notifier_v1_create(dpy); idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); From fd2c47cb7012bfcc5a49bed01d785abb49c67acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 14:02:25 -0500 Subject: [PATCH 287/329] mention the polkit dependency when using elogind or systemd-logind Bug: https://github.com/djpohly/dwl/issues/138 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 132fb32..579f417 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ As in the dwm community, we encourage users to share patches they have created. ## Running dwl -dwl can be run on any of the backends supported by wlroots. This means you can run it as a separate window inside either an X11 or Wayland session, as well as directly from a VT console. Depending on your distro's setup, you may need to add your user to the `video` and `input` groups before you can run dwl on a VT. +dwl can be run on any of the backends supported by wlroots. This means you can run it as a separate window inside either an X11 or Wayland session, as well as directly from a VT console. Depending on your distro's setup, you may need to add your user to the `video` and `input` groups before you can run dwl on a VT. If you are using `elogind` or `systemd-logind` you need to install polkit; otherwise you need to add yourself in the `seat` group and enable/start the seatd daemon. When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the Wayland session. From f494891a9aaf1f20e9900223ce2a068b6d237c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 14:22:11 -0500 Subject: [PATCH 288/329] limit the line length to 79 in the readme --- README.md | 111 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 579f417..05f149c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,29 @@ # dwl - dwm for Wayland -Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) or at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. +Join us on our [Discord server] or at [#dwl] on irc.libera.chat. -dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is: +dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is +intended to fill the same space in the Wayland world that dwm does in X11, +primarily in terms of philosophy, and secondarily in terms of functionality. +Like dwm, dwl is: - Easy to understand, hack on, and extend with patches - One C source file (or a very small number) configurable via `config.h` - Limited to 2200 SLOC to promote hackability - Tied to as few external dependencies as possible -dwl is not meant to provide every feature under the sun. Instead, like dwm, it sticks to features which are necessary, simple, and straightforward to implement given the base on which it is built. Implemented default features are: +dwl is not meant to provide every feature under the sun. Instead, like dwm, it +sticks to features which are necessary, simple, and straightforward to implement +given the base on which it is built. Implemented default features are: -- Any features provided by dwm/Xlib: simple window borders, tags, keybindings, client rules, mouse move/resize. Providing a built-in status bar is an exception to this goal, to avoid dependencies on font rendering and/or drawing libraries when an external bar could work well. +- Any features provided by dwm/Xlib: simple window borders, tags, keybindings, + client rules, mouse move/resize. Providing a built-in status bar is an + exception to this goal, to avoid dependencies on font rendering and/or + drawing libraries when an external bar could work well. - Configurable multi-monitor layout support, including position and rotation - Configurable HiDPI/multi-DPI support -- Idle-inhibit protocol which lets applications such as mpv disable idle monitoring +- Idle-inhibit protocol which lets applications such as mpv disable idle + monitoring - Provide information to external status bars via stdout/stdin - Urgency hints via xdg-activate protocol - Support screen lockers via input-inhibitor protocol @@ -27,37 +36,68 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots -- Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and https://github.com/djpohly/dwl/pull/235) +- Implement the text-input and input-method protocols to support IME once ibus + implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and + https://github.com/djpohly/dwl/pull/235) Feature *non-goals* for the main codebase include: - Client-side decoration (any more than is necessary to tell the clients not to) -- Client-initiated window management, such as move, resize, and close, which can be done through the compositor +- Client-initiated window management, such as move, resize, and close, which can + be done through the compositor - Animations and visual effects ## Building dwl dwl has only two dependencies: `wlroots` and `wayland-protocols`. -Simply install these (and their `-devel` versions if your distro has separate development packages) and run `make`. If you wish to build against a Git version of wlroots, check out the [wlroots-next branch](https://github.com/djpohly/dwl/tree/wlroots-next). +Simply install these (and their `-devel` versions if your distro has separate +development packages) and run `make`. If you wish to build against a Git +version of wlroots, check out the [wlroots-next branch]. -To enable XWayland, you should also install xorg-xwayland and uncomment its flag in `config.mk`. +To enable XWayland, you should also install xorg-xwayland and uncomment its flag +in `config.mk`. ## Configuration -All configuration is done by editing `config.h` and recompiling, in the same manner as dwm. There is no way to separately restart the window manager in Wayland without restarting the entire display server, so any changes will take effect the next time dwl is executed. +All configuration is done by editing `config.h` and recompiling, in the same +manner as dwm. There is no way to separately restart the window manager in +Wayland without restarting the entire display server, so any changes will take +effect the next time dwl is executed. -As in the dwm community, we encourage users to share patches they have created. Check out the [patches page on our wiki](https://github.com/djpohly/dwl/wiki/Patches)! +As in the dwm community, we encourage users to share patches they have created. +Check out the [patches page on our wiki]! ## Running dwl -dwl can be run on any of the backends supported by wlroots. This means you can run it as a separate window inside either an X11 or Wayland session, as well as directly from a VT console. Depending on your distro's setup, you may need to add your user to the `video` and `input` groups before you can run dwl on a VT. If you are using `elogind` or `systemd-logind` you need to install polkit; otherwise you need to add yourself in the `seat` group and enable/start the seatd daemon. +dwl can be run on any of the backends supported by wlroots. This means you can +run it as a separate window inside either an X11 or Wayland session, as well +as directly from a VT console. Depending on your distro's setup, you may need +to add your user to the `video` and `input` groups before you can run dwl on +a VT. If you are using `elogind` or `systemd-logind` you need to install +polkit; otherwise you need to add yourself in the `seat` group and +enable/start the seatd daemon. -When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the Wayland session. +When dwl is run with no arguments, it will launch the server and begin handling +any shortcuts configured in `config.h`. There is no status bar or other +decoration initially; these are instead clients that can be run within +the Wayland session. -If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. This command will be executed as a shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, but differs in that the display server will not shut down when this process terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait for it to terminate (if it hasn't already). This makes it ideal for execing into a user service manager like [s6](https://skarnet.org/software/s6/), [anopa](https://jjacky.com/anopa/), [runit](http://smarden.org/runit/faq.html#userservices), or [`systemd --user`](https://wiki.archlinux.org/title/Systemd/User). +If you would like to run a script or command automatically at startup, you can +specify the command using the `-s` option. This command will be executed as a +shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, +but differs in that the display server will not shut down when this process +terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait +for it to terminate (if it hasn't already). This makes it ideal for execing into +a user service manager like [s6], [anopa], [runit], or [`systemd --user`]. -Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes that it spawns. If you need to set environment variables that affect the entire dwl session, these must be set prior to running dwl. For example, Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager such as `elogind` or `systemd-logind`. If your system doesn't do this automatically, you will need to configure it prior to launching `dwl`, e.g.: +Note: The `-s` command is run as a *child process* of dwl, which means that it +does not have the ability to affect the environment of dwl or of any processes +that it spawns. If you need to set environment variables that affect the entire +dwl session, these must be set prior to running dwl. For example, Wayland +requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager +such as `elogind` or `systemd-logind`. If your system doesn't do this +automatically, you will need to configure it prior to launching `dwl`, e.g.: export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) mkdir -p $XDG_RUNTIME_DIR @@ -65,26 +105,53 @@ Note: The `-s` command is run as a *child process* of dwl, which means that it d ### Status information -Information about selected layouts, current window title, and selected/occupied/urgent tags is written to the stdin of the `-s` command (see the `printstatus()` function for details). This information can be used to populate an external status bar with a script that parses the information. Failing to read this information will cause dwl to block, so if you do want to run a startup command that does not consume the status information, you can close standard input with the `<&-` shell redirection, for example: +Information about selected layouts, current window title, and +selected/occupied/urgent tags is written to the stdin of the `-s` command (see +the `printstatus()` function for details). This information can be used to +populate an external status bar with a script that parses the information. +Failing to read this information will cause dwl to block, so if you do want to +run a startup command that does not consume the status information, you can +close standard input with the `<&-` shell redirection, for example: dwl -s 'foot --server <&-' -If your startup command is a shell script, you can achieve the same inside the script with the line +If your startup command is a shell script, you can achieve the same inside the +script with the line exec <&- -To get a list of status bars that work with dwl consult our [wiki](https://github.com/djpohly/dwl/wiki#compatible-status-bars). +To get a list of status bars that work with dwl consult our [wiki]. ## Replacements for X applications -You can find a [list of useful resources on our wiki](https://github.com/djpohly/dwl/wiki#migrating-from-x). +You can find a [list of useful resources on our wiki]. ## Acknowledgements -dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots developers. This was made possible in many cases by looking at how sway accomplished something, then trying to do the same in as suckless a way as possible. +dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots +developers. This was made possible in many cases by looking at how sway +accomplished something, then trying to do the same in as suckless a way as +possible. -Many thanks to suckless.org and the dwm developers and community for the inspiration, and to the various contributors to the project, including: +Many thanks to suckless.org and the dwm developers and community for the +inspiration, and to the various contributors to the project, including: - Alexander Courtis for the XWayland implementation -- Guido Cella for the layer-shell protocol implementation, patch maintenance, and for helping to keep the project running +- Guido Cella for the layer-shell protocol implementation, patch maintenance, + and for helping to keep the project running - Stivvo for output management and fullscreen support, and patch maintenance + + +[Discord server]: https://discord.gg/jJxZnrGPWN +[#dwl]: https://web.libera.chat/?channels=#dwl +[Wayland]: https://wayland.freedesktop.org/ +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ +[wlroots-next branch]: https://github.com/djpohly/dwl/tree/wlroots-next +[patches page on our wiki]: https://github.com/djpohly/dwl/wiki/Patches +[s6]: https://skarnet.org/software/s6/ +[anopa]: https://jjacky.com/anopa/ +[runit]: http://smarden.org/runit/faq.html#userservices +[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User +[wiki]: https://github.com/djpohly/dwl/wiki#compatible-status-bars +[list of useful resources on our wiki]: + https://github.com/djpohly/dwl/wiki#migrating-from-x From 2f7834b130dbd930b06ae4d8ef802bd115b011d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 14:55:03 -0500 Subject: [PATCH 289/329] sort util.c functions --- util.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/util.c b/util.c index 932f89b..cca7c19 100644 --- a/util.c +++ b/util.c @@ -6,16 +6,6 @@ #include "util.h" -void * -ecalloc(size_t nmemb, size_t size) -{ - void *p; - - if (!(p = calloc(nmemb, size))) - die("calloc:"); - return p; -} - void die(const char *fmt, ...) { va_list ap; @@ -33,3 +23,13 @@ die(const char *fmt, ...) { exit(1); } + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} From 9588b46b5c47a9b4990340ba54a3b4dc075ba55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 15:25:13 -0500 Subject: [PATCH 290/329] only raise the client's node in monocle() Fixes: https://github.com/djpohly/dwl/issues/326 --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a80de05..8c7644e 100644 --- a/dwl.c +++ b/dwl.c @@ -1495,7 +1495,8 @@ monocle(Monitor *m) continue; resize(c, m->w, 0); } - focusclient(focustop(m), 1); + if ((c = focustop(m))) + wlr_scene_node_raise_to_top(c->scene); } void From cb01ce9bcfd1f968fd2537643d2c61137b76e829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Aug 2022 19:54:01 -0500 Subject: [PATCH 291/329] move focus and clients off disabled monitors --- dwl.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 8c7644e..0c2328b 100644 --- a/dwl.c +++ b/dwl.c @@ -1698,6 +1698,9 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) else wlr_output_configuration_v1_send_failed(config); wlr_output_configuration_v1_destroy(config); + + /* TODO: use a wrapper function? */ + updatemons(NULL, NULL); } void @@ -2435,14 +2438,38 @@ updatemons(struct wl_listener *listener, void *data) struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); Client *c; + struct wlr_output_configuration_head_v1 *config_head; Monitor *m; + + /* First remove from the layout the disabled monitors */ + wl_list_for_each(m, &mons, link) { + int nmons, i = 0; + if (m->wlr_output->enabled) + continue; + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); + config_head->state.enabled = 0; + if (m == selmon && (nmons = wl_list_length(&mons))) + do /* don't switch to disabled mons */ + selmon = wl_container_of(mons.next, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + /* Remove this output from the layout to avoid cursor enter inside it */ + wlr_output_layout_remove(output_layout, m->wlr_output); + focusclient(focustop(selmon), 1); + closemon(m); + memset(&m->m, 0, sizeof(m->m)); + memset(&m->w, 0, sizeof(m->w)); + } + /* Insert outputs that need to */ + wl_list_for_each(m, &mons, link) + if (m->wlr_output->enabled + && !wlr_output_layout_get(output_layout, m->wlr_output)) + wlr_output_layout_add_auto(output_layout, m->wlr_output); + /* Now that we update the output layout we can get its box */ sgeom = *wlr_output_layout_get_box(output_layout, NULL); wl_list_for_each(m, &mons, link) { - struct wlr_output_configuration_head_v1 *config_head = - wlr_output_configuration_head_v1_create(config, m->wlr_output); - - /* TODO: move clients off disabled monitors */ - /* TODO: move focus if selmon is disabled */ + if (!m->wlr_output->enabled) + continue; + config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); /* Get the effective monitor geometry to use for surfaces */ m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); @@ -2452,7 +2479,7 @@ updatemons(struct wl_listener *listener, void *data) /* Don't move clients to the left output when plugging monitors */ arrange(m); - config_head->state.enabled = m->wlr_output->enabled; + config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; config_head->state.y = m->m.y; From 9b5f0f0fc5d668538e190f525f01c5a150a5570a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 19 Aug 2022 10:05:51 -0500 Subject: [PATCH 292/329] use just one loop in outputmgrapplyortest() we do the magic in updatemons() --- dwl.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/dwl.c b/dwl.c index 0c2328b..50a8416 100644 --- a/dwl.c +++ b/dwl.c @@ -1631,28 +1631,13 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) struct wlr_output_configuration_head_v1 *config_head; int ok = 1; - /* First disable outputs we need to disable */ - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - if (!wlr_output->enabled || config_head->state.enabled) - continue; - wlr_output_enable(wlr_output, 0); - if (test) { - ok &= wlr_output_test(wlr_output); - wlr_output_rollback(wlr_output); - } else { - ok &= wlr_output_commit(wlr_output); - } - } - - /* Then enable outputs that need to */ wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; Monitor *m = wlr_output->data; - if (!config_head->state.enabled) - continue; - wlr_output_enable(wlr_output, 1); + wlr_output_enable(wlr_output, config_head->state.enabled); + if (!config_head->state.enabled) + goto apply_or_test; if (config_head->state.mode) wlr_output_set_mode(wlr_output, config_head->state.mode); else @@ -1669,6 +1654,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) wlr_output_set_transform(wlr_output, config_head->state.transform); wlr_output_set_scale(wlr_output, config_head->state.scale); +apply_or_test: if (test) { ok &= wlr_output_test(wlr_output); wlr_output_rollback(wlr_output); @@ -1678,7 +1664,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) * we test if that mode does not fail rather than just call wlr_output_commit(). * We do not test normal modes because (at least in my hardware (@sevz17)) * wlr_output_test() fails even if that mode can actually be set */ - if (!config_head->state.mode) + if (!config_head->state.mode && config_head->state.enabled) ok &= (output_ok = wlr_output_test(wlr_output) && wlr_output_commit(wlr_output)); else From a9e2ebaf4163278086d2cc290f164028dec0839b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 1 Sep 2022 19:25:27 -0500 Subject: [PATCH 293/329] closemon() now updates selmon if needed --- dwl.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dwl.c b/dwl.c index 50a8416..85edb9d 100644 --- a/dwl.c +++ b/dwl.c @@ -762,7 +762,7 @@ cleanupmon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, destroy); LayerSurface *l, *tmp; - int nmons, i; + int i; for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { wl_list_for_each_safe(l, tmp, &m->layers[i], link) { @@ -778,12 +778,6 @@ cleanupmon(struct wl_listener *listener, void *data) wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); - if (!(i = 0) && (nmons = wl_list_length(&mons))) - do /* don't switch to disabled mons */ - selmon = wl_container_of(mons.prev, selmon, link); - while (!selmon->wlr_output->enabled && i++ < nmons); - - focusclient(focustop(selmon), 1); closemon(m); free(m); } @@ -791,8 +785,17 @@ cleanupmon(struct wl_listener *listener, void *data) void closemon(Monitor *m) { - /* move closed monitor's clients to the focused one */ + /* update selmon if needed and + * move closed monitor's clients to the focused one */ Client *c; + if (wl_list_empty(&mons)) { + selmon = NULL; + } else if (m == selmon) { + int nmons = wl_list_length(&mons), i = 0; + do /* don't switch to disabled mons */ + selmon = wl_container_of(mons.next, selmon, link); + while (!selmon->wlr_output->enabled && i++ < nmons); + } wl_list_for_each(c, &clients, link) { if (c->isfloating && c->geom.x > m->m.width) @@ -801,6 +804,7 @@ closemon(Monitor *m) if (c->mon == m) setmon(c, selmon, c->tags); } + focusclient(focustop(selmon), 1); printstatus(); } @@ -2429,18 +2433,12 @@ updatemons(struct wl_listener *listener, void *data) /* First remove from the layout the disabled monitors */ wl_list_for_each(m, &mons, link) { - int nmons, i = 0; if (m->wlr_output->enabled) continue; config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); config_head->state.enabled = 0; - if (m == selmon && (nmons = wl_list_length(&mons))) - do /* don't switch to disabled mons */ - selmon = wl_container_of(mons.next, selmon, link); - while (!selmon->wlr_output->enabled && i++ < nmons); /* Remove this output from the layout to avoid cursor enter inside it */ wlr_output_layout_remove(output_layout, m->wlr_output); - focusclient(focustop(selmon), 1); closemon(m); memset(&m->m, 0, sizeof(m->m)); memset(&m->w, 0, sizeof(m->w)); From 846ce52b926797dc51f9fcdc2d121ee63fb68580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 15:43:20 -0500 Subject: [PATCH 294/329] fix crash in dirtomon() when selmon is disabled --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 85edb9d..2baa659 100644 --- a/dwl.c +++ b/dwl.c @@ -1152,10 +1152,12 @@ Monitor * dirtomon(enum wlr_direction dir) { struct wlr_output *next; - if ((next = wlr_output_layout_adjacent_output(output_layout, + if (wlr_output_layout_get(output_layout, selmon->wlr_output) + && (next = wlr_output_layout_adjacent_output(output_layout, dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) return next->data; - if ((next = wlr_output_layout_farthest_output(output_layout, + if (wlr_output_layout_get(output_layout, selmon->wlr_output) + && (next = wlr_output_layout_farthest_output(output_layout, dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), selmon->wlr_output, selmon->m.x, selmon->m.y))) return next->data; From 8298f20a7174eb9c70b375b92810ab3320fedf97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 18:30:09 -0500 Subject: [PATCH 295/329] allow change adaptive sync in outputmgrapplyortest() --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 3ba4eaf..7d41883 100644 --- a/dwl.c +++ b/dwl.c @@ -1557,6 +1557,8 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) config_head->state.x, config_head->state.y); wlr_output_set_transform(wlr_output, config_head->state.transform); wlr_output_set_scale(wlr_output, config_head->state.scale); + wlr_output_enable_adaptive_sync(wlr_output, + config_head->state.adaptive_sync_enabled); apply_or_test: if (test) { From 99f062273e6a04abe4258c23284087698a8ecad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 19:02:44 -0500 Subject: [PATCH 296/329] only destroy monitor's layer surfaces at destroy --- dwl.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 7d41883..8b019da 100644 --- a/dwl.c +++ b/dwl.c @@ -644,12 +644,9 @@ cleanupmon(struct wl_listener *listener, void *data) LayerSurface *l, *tmp; int i; - for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { - wl_list_for_each_safe(l, tmp, &m->layers[i], link) { - wlr_scene_node_set_enabled(&l->scene->node, 0); + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) + wl_list_for_each_safe(l, tmp, &m->layers[i], link) wlr_layer_surface_v1_destroy(l->layer_surface); - } - } wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); From 448a96de13042c76634c2a898c370889b33693d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 30 Oct 2022 01:03:44 -0500 Subject: [PATCH 297/329] remove now unneeded workaround in outputmgrapplyortest() --- dwl.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/dwl.c b/dwl.c index 8b019da..fa59386 100644 --- a/dwl.c +++ b/dwl.c @@ -1562,23 +1562,7 @@ apply_or_test: ok &= wlr_output_test(wlr_output); wlr_output_rollback(wlr_output); } else { - int output_ok = 1; - /* If it's a custom mode to avoid an assertion failed in wlr_output_commit() - * we test if that mode does not fail rather than just call wlr_output_commit(). - * We do not test normal modes because (at least in my hardware (@sevz17)) - * wlr_output_test() fails even if that mode can actually be set */ - if (!config_head->state.mode && config_head->state.enabled) - ok &= (output_ok = wlr_output_test(wlr_output) - && wlr_output_commit(wlr_output)); - else - ok &= wlr_output_commit(wlr_output); - - /* In custom modes we call wlr_output_test(), it it fails - * we need to rollback, and normal modes seems to does not cause - * assertions failed in wlr_output_commit() which rollback - * the output on failure */ - if (!output_ok) - wlr_output_rollback(wlr_output); + ok &= wlr_output_commit(wlr_output); } } From 3cc22de712415342e4865eef099fcfde49bcf734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 31 Oct 2022 23:33:23 -0600 Subject: [PATCH 298/329] client: don't change border color during drags Fixes: https://github.com/djpohly/dwl/issues/318 --- dwl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 2baa659..9080115 100644 --- a/dwl.c +++ b/dwl.c @@ -1185,8 +1185,9 @@ focusclient(Client *c, int lift) c->isurgent = 0; client_restack_surface(c); - /* Don't change border color if there is an exclusive focus */ - if (!exclusive_focus) + /* Don't change border color if there is an exclusive focus or we are + * handling a drag operation */ + if (!exclusive_focus && !seat->drag) for (i = 0; i < 4; i++) wlr_scene_rect_set_color(c->border[i], focuscolor); } @@ -2261,6 +2262,9 @@ void startdrag(struct wl_listener *listener, void *data) { struct wlr_drag *drag = data; + /* During drag the focus isn't sent to clients, this causes that + * we don't update border color acording the pointer coordinates */ + focusclient(NULL, 0); if (!drag->icon) return; From 8bd344257501b9293126348bf956beb8c9ddcfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 31 Oct 2022 20:42:17 -0600 Subject: [PATCH 299/329] layersurface: create a dedicated scene tree for popups this tree should be always above the top layer Fixes: https://github.com/djpohly/dwl/issues/328 --- dwl.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index 9080115..52bfa58 100644 --- a/dwl.c +++ b/dwl.c @@ -152,6 +152,7 @@ typedef struct { struct wlr_box geom; Monitor *mon; struct wlr_scene_node *scene; + struct wlr_scene_node *popups; struct wl_list link; int mapped; struct wlr_layer_surface_v1 *layer_surface; @@ -583,6 +584,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int state->margin.top, state->margin.right, state->margin.bottom, state->margin.left); wlr_scene_node_set_position(layersurface->scene, box.x, box.y); + wlr_scene_node_set_position(layersurface->popups, box.x, box.y); wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); } } @@ -823,10 +825,14 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (layers[wlr_layer_surface->current.layer] != layersurface->scene->parent) { wlr_scene_node_reparent(layersurface->scene, layers[wlr_layer_surface->current.layer]); + wlr_scene_node_reparent(layersurface->popups, + layers[wlr_layer_surface->current.layer]); wl_list_remove(&layersurface->link); wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], &layersurface->link); } + if (wlr_layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + wlr_scene_node_reparent(layersurface->popups, layers[LyrTop]); if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) @@ -920,10 +926,11 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->mon = wlr_layer_surface->output->data; wlr_layer_surface->data = layersurface; - layersurface->scene = wlr_layer_surface->surface->data = - wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], - wlr_layer_surface->surface); + layersurface->scene = wlr_scene_subsurface_tree_create( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface->surface); layersurface->scene->data = layersurface; + layersurface->popups = wlr_layer_surface->surface->data = + &wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer])->node; wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], &layersurface->link); @@ -1011,12 +1018,6 @@ createnotify(struct wl_listener *listener, void *data) LayerSurface *l = toplevel_from_popup(xdg_surface->popup); xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); - /* Raise to top layer if the inmediate parent of the popup is on - * bottom/background layer, which will cause popups appear below the - * x{dg,wayland} clients */ - if (wlr_surface_is_layer_surface(xdg_surface->popup->parent) && l - && l->layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - wlr_scene_node_reparent(xdg_surface->surface->data, layers[LyrTop]); /* Probably the check of `l` is useless, the only thing that can be NULL * is its monitor */ if (!l || !l->mon) From f1639ba9d5c807792fe5d0628caa1faf3316ca44 Mon Sep 17 00:00:00 2001 From: shua Date: Wed, 9 Nov 2022 01:01:50 -0500 Subject: [PATCH 300/329] check null in toplevel_from_popup managed to SEGFAULT the server by trying to create a popup without setting a parent first. Not sure if this is dwl or wlroots issue, so also opened a ticket upstream: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3811 --- client.h | 4 +++- dwl.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 49982e0..38330d5 100644 --- a/client.h +++ b/client.h @@ -304,7 +304,9 @@ toplevel_from_popup(struct wlr_xdg_popup *popup) while (1) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_POPUP: - if (wlr_surface_is_layer_surface(surface->popup->parent)) + if (!surface->popup->parent) + return NULL; + else if (wlr_surface_is_layer_surface(surface->popup->parent)) return wlr_layer_surface_v1_from_wlr_surface(surface->popup->parent)->data; else if (!wlr_surface_is_xdg_surface(surface->popup->parent)) return NULL; diff --git a/dwl.c b/dwl.c index 52bfa58..5ee3c92 100644 --- a/dwl.c +++ b/dwl.c @@ -1016,6 +1016,8 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; LayerSurface *l = toplevel_from_popup(xdg_surface->popup); + if (!xdg_surface->popup->parent) + return; xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); /* Probably the check of `l` is useless, the only thing that can be NULL From b59c7f6a2e263a67983bed69cd733fe2e5ab0ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 10 Nov 2022 23:12:52 -0600 Subject: [PATCH 301/329] config.def.h: fix comment Fixes: https://github.com/djpohly/dwl/issues/333 --- config.def.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index ec1f052..b3caab3 100644 --- a/config.def.h +++ b/config.def.h @@ -86,8 +86,9 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; static const double accel_speed = 0.0; -/* If you want to use the windows key change this to WLR_MODIFIER_LOGO */ +/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT + #define TAGKEYS(KEY,SKEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ From 569f55401693c9d2850f056f20ca2bd5bd5977fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 19 Nov 2022 01:34:15 -0600 Subject: [PATCH 302/329] don't unfocus focused client when starting a drag this fix chromium keyboard focus loss after a drag Fix: 3cc22de712415342e4865eef099fcfde49bcf734 --- dwl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dwl.c b/dwl.c index 5ee3c92..b884d06 100644 --- a/dwl.c +++ b/dwl.c @@ -2265,9 +2265,6 @@ void startdrag(struct wl_listener *listener, void *data) { struct wlr_drag *drag = data; - /* During drag the focus isn't sent to clients, this causes that - * we don't update border color acording the pointer coordinates */ - focusclient(NULL, 0); if (!drag->icon) return; From 88d386bfdcedb8b46d7c4c7a3ebac2476cfcf46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 12 Nov 2022 20:05:56 -0600 Subject: [PATCH 303/329] configurex11: resize floating clients and arrange tiled clients' monitor --- dwl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3bf5cdc..2903d9d 100644 --- a/dwl.c +++ b/dwl.c @@ -2486,8 +2486,13 @@ configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); struct wlr_xwayland_surface_configure_event *event = data; - wlr_xwayland_surface_configure(c->surface.xwayland, - event->x, event->y, event->width, event->height); + if (!c->mon) + return; + if (c->isfloating || c->type == X11Unmanaged) + resize(c, (struct wlr_box){.x = event->x, .y = event->y, + .width = event->width, .height = event->height}, 0); + else + arrange(c->mon); } void From 93a911d6e93f760a5139bfe0d1c1eb90886c414f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Nov 2022 16:39:17 -0600 Subject: [PATCH 304/329] simplify `if` expression in checkidleinhibitor() --- dwl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 2903d9d..8599764 100644 --- a/dwl.c +++ b/dwl.c @@ -588,16 +588,15 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { + Client *c; int inhibited = 0; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - Client *c; - if (exclude == inhibitor->surface) - continue; /* In case we can't get a client from the surface assume that it is * visible, for example a layer surface */ - if (!(c = client_from_wlr_surface(inhibitor->surface)) - || VISIBLEON(c, c->mon)) { + if (exclude != inhibitor->surface + && (!(c = client_from_wlr_surface(inhibitor->surface)) + || VISIBLEON(c, c->mon))) { inhibited = 1; break; } From 60a98b87f395618be8d35c1100e019588e255d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Nov 2022 16:46:43 -0600 Subject: [PATCH 305/329] inhibit idle if surface's node is enabled --- dwl.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 8599764..949f7b3 100644 --- a/dwl.c +++ b/dwl.c @@ -588,15 +588,12 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { - Client *c; int inhibited = 0; + struct wlr_scene_tree *tree; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - /* In case we can't get a client from the surface assume that it is - * visible, for example a layer surface */ - if (exclude != inhibitor->surface - && (!(c = client_from_wlr_surface(inhibitor->surface)) - || VISIBLEON(c, c->mon))) { + if (exclude != inhibitor->surface && (tree = inhibitor->surface->data) + && tree->node.enabled) { inhibited = 1; break; } From 63d6de58669ea4ee6876e7e624fa3c3bd9e83a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Nov 2022 16:57:41 -0600 Subject: [PATCH 306/329] fix set of layersurface->popups and surface->data --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 949f7b3..3f2b261 100644 --- a/dwl.c +++ b/dwl.c @@ -804,7 +804,7 @@ createlayersurface(struct wl_listener *listener, void *data) layers[wlr_layer_surface->pending.layer], wlr_layer_surface); layersurface->scene = layersurface->scene_layer->tree; layersurface->popups = wlr_layer_surface->surface->data = - &wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer])->node; + wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer]); layersurface->scene->node.data = layersurface; From 7eebe677879373672774c06c81c0e3eda22d03ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 22:29:26 -0600 Subject: [PATCH 307/329] set x and y of the layersurface's geometry box --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 3f2b261..579dad1 100644 --- a/dwl.c +++ b/dwl.c @@ -466,6 +466,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); wlr_scene_node_set_position(&layersurface->popups->node, layersurface->scene->node.x, layersurface->scene->node.y); + layersurface->geom.x = layersurface->scene->node.x; + layersurface->geom.y = layersurface->scene->node.y; } } From 05eca0e2d95a44a2d33959b8362a21a0f974e17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 22:32:20 -0600 Subject: [PATCH 308/329] rename xwayland_surface to xsurface this save us 2 lines --- dwl.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dwl.c b/dwl.c index 579dad1..88c398f 100644 --- a/dwl.c +++ b/dwl.c @@ -2496,7 +2496,7 @@ configurex11(struct wl_listener *listener, void *data) void createnotifyx11(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xwayland_surface = data; + struct wlr_xwayland_surface *xsurface = data; Client *c; /* TODO: why we unset fullscreen when a xwayland client is created? */ wl_list_for_each(c, &clients, link) @@ -2504,22 +2504,20 @@ createnotifyx11(struct wl_listener *listener, void *data) setfullscreen(c, 0); /* Allocate a Client for this surface */ - c = xwayland_surface->data = ecalloc(1, sizeof(*c)); - c->surface.xwayland = xwayland_surface; - c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; + c = xsurface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xsurface; + c->type = xsurface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; /* Listen to the various events it can emit */ - LISTEN(&xwayland_surface->events.map, &c->map, mapnotify); - LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11); - LISTEN(&xwayland_surface->events.request_configure, &c->configure, - configurex11); - LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints); - LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); - LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen, - fullscreennotify); + LISTEN(&xsurface->events.map, &c->map, mapnotify); + LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); + LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); + LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } Atom From caec566286b1bbef1758bcf0599677650017c5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 11 Nov 2022 00:22:36 -0600 Subject: [PATCH 309/329] create a dedicated layer for fullscreen clients Bug: https://github.com/djpohly/dwl/issues/327 --- dwl.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/dwl.c b/dwl.c index 88c398f..aacc345 100644 --- a/dwl.c +++ b/dwl.c @@ -73,7 +73,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrDragIcon, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -102,7 +102,6 @@ typedef struct { struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ struct wlr_scene_tree *scene_surface; - struct wlr_scene_rect *fullscreen_bg; /* See setfullscreen() for info */ struct wl_list link; struct wl_list flink; union { @@ -171,6 +170,7 @@ struct Monitor { struct wl_list link; struct wlr_output *wlr_output; struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ struct wl_listener frame; struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ @@ -445,6 +445,9 @@ arrange(Monitor *m) if (c->mon == m) wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, + (c = focustop(m)) && c->isfullscreen); + if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); @@ -655,6 +658,7 @@ cleanupmon(struct wl_listener *listener, void *data) m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); + wlr_scene_node_destroy(&m->fullscreen_bg->node); closemon(m); free(m); @@ -874,6 +878,18 @@ createmon(struct wl_listener *listener, void *data) wl_list_insert(&mons, &m->link); printstatus(); + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + */ + /* updatemons() will resize and set correct position */ + m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); + /* Adds this to the output layout in the order it was configured in. * * The output layout utility automatically adds a wl_output global to the @@ -1724,8 +1740,6 @@ resize(Client *c, struct wlr_box geo, int interact) wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); - if (c->fullscreen_bg) - wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height); /* wlroots makes this a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, @@ -1833,32 +1847,16 @@ setfullscreen(Client *c, int fullscreen) return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[fullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); if (fullscreen) { c->prev = c->geom; resize(c, c->mon->m, 0); - /* The xdg-protocol specifies: - * - * If the fullscreened surface is not opaque, the compositor must make - * sure that other screen content not part of the same surface tree (made - * up of subsurfaces, popups or similarly coupled surfaces) are not - * visible below the fullscreened surface. - * - * For brevity we set a black background for all clients - */ - if (!c->fullscreen_bg) { - c->fullscreen_bg = wlr_scene_rect_create(c->scene, - c->geom.width, c->geom.height, fullscreen_bg); - wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); - } } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ resize(c, c->prev, 0); - if (c->fullscreen_bg) { - wlr_scene_node_destroy(&c->fullscreen_bg->node); - c->fullscreen_bg = NULL; - } } arrange(c->mon); printstatus(); @@ -1976,6 +1974,7 @@ setup(void) layers[LyrBottom] = wlr_scene_tree_create(&scene->tree); layers[LyrTile] = wlr_scene_tree_create(&scene->tree); layers[LyrFloat] = wlr_scene_tree_create(&scene->tree); + layers[LyrFS] = wlr_scene_tree_create(&scene->tree); layers[LyrTop] = wlr_scene_tree_create(&scene->tree); layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree); @@ -2342,6 +2341,9 @@ updatemons(struct wl_listener *listener, void *data) /* Don't move clients to the left output when plugging monitors */ arrange(m); + wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); + wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; @@ -2411,7 +2413,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, Client *c = NULL; LayerSurface *l = NULL; const int *layer; - int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; + int focus_order[] = { LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; for (layer = focus_order; layer < END(focus_order); layer++) { if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { From 087373698afeab0af9257358955f1c3c772d24e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Nov 2022 14:44:24 -0600 Subject: [PATCH 310/329] Revert "Add a configuration option for fullscreen locking" now all fullcreen clients are rendered above tiled and floating clients This partially reverts commit 326eee14445f8a2c08e80c30778445630c75d3bb. --- config.def.h | 1 - dwl.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index b3caab3..0473b40 100644 --- a/config.def.h +++ b/config.def.h @@ -1,7 +1,6 @@ /* appearance */ static const int sloppyfocus = 1; /* focus follows mouse */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; diff --git a/dwl.c b/dwl.c index aacc345..c1ff934 100644 --- a/dwl.c +++ b/dwl.c @@ -1156,7 +1156,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = selclient(); - if (!sel || (sel->isfullscreen && lockfullscreen)) + if (!sel || sel->isfullscreen) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { From 87d87cc4041a997d00ebf234ca5118b9248a3b95 Mon Sep 17 00:00:00 2001 From: krypek <115574014+krypciak@users.noreply.github.com> Date: Wed, 23 Nov 2022 22:56:52 +0100 Subject: [PATCH 311/329] Fix comparison between signed and unsigned int When c->bw is 0, the right side of the MAX functions gets turned into an unsigned integer and that results in -1 being the outcome. This causes big issues in xwayland clients. --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index b884d06..fc6c4da 100644 --- a/dwl.c +++ b/dwl.c @@ -389,8 +389,8 @@ applybounds(Client *c, struct wlr_box *bbox) struct wlr_box min = {0}, max = {0}; client_get_size_hints(c, &max, &min); /* try to set size hints */ - c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); - c->geom.height = MAX(min.height + (2 * c->bw), c->geom.height); + c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); + c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); /* Some clients set them max size to INT_MAX, which does not violates * the protocol but its innecesary, they can set them max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ From 3213088aa23e1f6cad1a5ba506dfb7318e1011c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 30 Nov 2022 17:42:58 -0600 Subject: [PATCH 312/329] do not try to set the parent's same tags and monitor for xwayland clients References: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index c1ff934..fd22c8f 100644 --- a/dwl.c +++ b/dwl.c @@ -1381,7 +1381,8 @@ mapnotify(struct wl_listener *listener, void *data) * we always consider floating, clients that have parent and thus * we set the same tags and monitor than its parent, if not * try to apply rules for them */ - if ((p = client_get_parent(c))) { + /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ + if (c->type == XDGShell && (p = client_get_parent(c))) { c->isfloating = 1; wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); setmon(c, p->mon, p->tags); From c91d21b68f436bc61dfce8b3f47beb5855bdd1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 25 Nov 2022 12:15:55 -0600 Subject: [PATCH 313/329] do not move/resize if grabbed client is fullscreen --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index fd22c8f..4648890 100644 --- a/dwl.c +++ b/dwl.c @@ -1510,7 +1510,7 @@ moveresize(const Arg *arg) if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); - if (!grabc || client_is_unmanaged(grabc)) + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) return; /* Float the window and tell motionnotify to grab it */ From 10c56d63489506ee852f3ec18f078e60ba1885f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 30 Nov 2022 18:51:35 -0600 Subject: [PATCH 314/329] add option to allow invisible surfaces to disable idle tracking --- config.def.h | 13 +++++++------ dwl.c | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/config.def.h b/config.def.h index 0473b40..8f01192 100644 --- a/config.def.h +++ b/config.def.h @@ -1,11 +1,12 @@ /* appearance */ -static const int sloppyfocus = 1; /* focus follows mouse */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; -static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; -static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +static const int sloppyfocus = 1; /* focus follows mouse */ +static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; +static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; +static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ -static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; +static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; diff --git a/dwl.c b/dwl.c index 4648890..f07a867 100644 --- a/dwl.c +++ b/dwl.c @@ -597,8 +597,9 @@ checkidleinhibitor(struct wlr_surface *exclude) struct wlr_scene_tree *tree; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - if (exclude != inhibitor->surface && (tree = inhibitor->surface->data) - && tree->node.enabled) { + if (bypass_surface_visibility || (exclude != inhibitor->surface + && (tree = inhibitor->surface->data) + && tree->node.enabled)) { inhibited = 1; break; } From 6df6781b437937e835d8caca14024829747bd2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 30 Nov 2022 18:54:54 -0600 Subject: [PATCH 315/329] simplify check for surface's node state all `struct wlr_surface` should have a `wlr_scene_tree *` as data --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index f07a867..3f6db50 100644 --- a/dwl.c +++ b/dwl.c @@ -594,11 +594,10 @@ void checkidleinhibitor(struct wlr_surface *exclude) { int inhibited = 0; - struct wlr_scene_tree *tree; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + struct wlr_scene_tree *tree = inhibitor->surface->data; if (bypass_surface_visibility || (exclude != inhibitor->surface - && (tree = inhibitor->surface->data) && tree->node.enabled)) { inhibited = 1; break; From b4fb1f77c768fb7bd568d3cc67c59dcfdb7cae28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 1 Dec 2022 20:49:49 -0600 Subject: [PATCH 316/329] fix xwayland clients being floating by default Fix 3213088aa23e1f6cad1a5ba506dfb7318e1011c9 References: https://github.com/djpohly/dwl/pull/334#issuecomment-1333147730 --- client.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client.h b/client.h index 3c81135..c18d01a 100644 --- a/client.h +++ b/client.h @@ -184,8 +184,7 @@ client_is_float_type(Client *c) } #endif return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) - && (min.width == max.width || min.height == max.height)) - || client_get_parent(c); + && (min.width == max.width || min.height == max.height)); } static inline int From f929eaef1e15c2624de20cdcb0e348e6cab21152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Dec 2022 10:07:24 -0600 Subject: [PATCH 317/329] ask for version instead of commit in bug reports --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 64e2054..6b60803 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- ## Info -dwl's commit: +dwl version: wlroots version: ## Description