From ecbc2c61db180dc8ab1053b7cdc1e4817be33d36 Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Sun, 27 Mar 2022 17:04:41 -0700 Subject: [PATCH 01/62] 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 02/62] 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 03/62] 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 04/62] 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 05/62] 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 06/62] 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 07/62] 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 08/62] 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 09/62] 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 10/62] 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 11/62] 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 12/62] 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 13/62] 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 14/62] 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 c990dbd441684a9744cb744792488c34af20e9c7 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Fri, 10 Jun 2022 19:26:45 +0300 Subject: [PATCH 15/62] 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 16/62] 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 17/62] 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 18/62] 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 19/62] 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 20/62] 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 21/62] 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 22/62] 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 23/62] 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 24/62] 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 25/62] 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 26/62] 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 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 27/62] 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 28/62] 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 29/62] 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 30/62] 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 31/62] 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 32/62] 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 33/62] 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 34/62] 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 35/62] 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 36/62] 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 37/62] 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 38/62] 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 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 39/62] 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 40/62] 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 41/62] 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 42/62] 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 43/62] 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 44/62] 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 45/62] 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 46/62] 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 47/62] 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 48/62] 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 49/62] 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 50/62] 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 51/62] 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 52/62] 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 53/62] 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 54/62] 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 55/62] 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 56/62] 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 57/62] 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 58/62] 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 59/62] 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 60/62] 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 61/62] 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 62/62] 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); }