From 13b929d7d79a7142901d0e7035806ee7f3b7af9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Dec 2022 23:06:53 -0600 Subject: [PATCH 01/62] remove unneeded call to wlr_scene_rect_set_color() wlr_scene_rect_create() requires a color as parameter --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 2a8162c..c304256 100644 --- a/dwl.c +++ b/dwl.c @@ -1361,7 +1361,6 @@ mapnotify(struct wl_listener *listener, void *data) for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); c->border[i]->node.data = c; - wlr_scene_rect_set_color(c->border[i], bordercolor); } /* Initialize client geometry with room for border */ From c56bc42eb5480783f3bc97f769bac3d9eebcb373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 3 Dec 2022 14:30:38 -0600 Subject: [PATCH 02/62] sort client_get_parent() --- client.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/client.h b/client.h index 4dc9e1a..b443a8d 100644 --- a/client.h +++ b/client.h @@ -37,19 +37,6 @@ client_from_wlr_surface(struct wlr_surface *s) return NULL; } -static inline Client * -client_get_parent(Client *c) -{ -#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->base->surface); - - return NULL; -} - static inline void client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) { @@ -153,6 +140,19 @@ client_get_geometry(Client *c, struct wlr_box *geom) wlr_xdg_surface_get_geometry(c->surface.xdg, geom); } +static inline Client * +client_get_parent(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c) && c->surface.xwayland->parent) + return toplevel_from_wlr_surface(c->surface.xwayland->parent->surface); +#endif + if (c->surface.xdg->toplevel->parent) + return toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface); + + return NULL; +} + static inline const char * client_get_title(Client *c) { From 38bd00351a444d37184716d6124bb47817758bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 3 Dec 2022 14:31:18 -0600 Subject: [PATCH 03/62] merge toplevel_from_{wlr_layer_surface,popup} into client_from_wlr_surface now it is a big function called toplevel_from_wlr_surface --- client.h | 108 ++++++++++++++++++++++++------------------------------- dwl.c | 10 +++--- 2 files changed, 52 insertions(+), 66 deletions(-) diff --git a/client.h b/client.h index b443a8d..c12a107 100644 --- a/client.h +++ b/client.h @@ -16,27 +16,6 @@ client_is_x11(Client *c) #endif } -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; - - if (s && wlr_surface_is_subsurface(s)) - return client_from_wlr_surface(wlr_surface_get_root_surface(s)); - return NULL; -} - static inline void client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) { @@ -72,6 +51,53 @@ client_surface(Client *c) return c->surface.xdg->surface; } +static inline void * +toplevel_from_wlr_surface(struct wlr_surface *s) +{ + struct wlr_xdg_surface *xdg_surface; + struct wlr_surface *root_surface; + struct wlr_layer_surface_v1 *layer_surface; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; +#endif + + if (!s) + return NULL; + root_surface = wlr_surface_get_root_surface(s); + +#ifdef XWAYLAND + if (wlr_surface_is_xwayland_surface(root_surface) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) + return xsurface->data; +#endif + + if (wlr_surface_is_layer_surface(root_surface) + && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) + return layer_surface->data; + + if (wlr_surface_is_xdg_surface(root_surface) + && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) { + while (1) { + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!xdg_surface->popup->parent) + return NULL; + else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) + return toplevel_from_wlr_surface(xdg_surface->popup->parent); + + xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + return xdg_surface->data; + case WLR_XDG_SURFACE_ROLE_NONE: + return NULL; + } + } + } + + return NULL; +} + /* The others */ static inline void client_activate_surface(struct wlr_surface *s, int activated) @@ -320,43 +346,3 @@ client_wants_fullscreen(Client *c) #endif return c->surface.xdg->toplevel->requested.fullscreen; } - -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 (!surface->popup->parent) - return NULL; - else if (wlr_surface_is_layer_surface(surface->popup->parent)) - return wlr_layer_surface_v1_from_wlr_surface(surface->popup->parent)->data; - else if (!wlr_surface_is_xdg_surface(surface->popup->parent)) - return NULL; - - surface = wlr_xdg_surface_from_wlr_surface(surface->popup->parent); - break; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - return surface->data; - case WLR_XDG_SURFACE_ROLE_NONE: - return NULL; - } - } -} - -static inline void * -toplevel_from_wlr_layer_surface(struct wlr_surface *s) -{ - Client *c; - struct wlr_layer_surface_v1 *wlr_layer_surface; - - if ((c = client_from_wlr_surface(s))) - return c; - else if (s && wlr_surface_is_layer_surface(s) - && (wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(s))) - return wlr_layer_surface->data; - - return NULL; -} diff --git a/dwl.c b/dwl.c index c304256..9c2fc3d 100644 --- a/dwl.c +++ b/dwl.c @@ -908,7 +908,7 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; - LayerSurface *l = toplevel_from_popup(xdg_surface->popup); + LayerSurface *l = toplevel_from_wlr_surface(xdg_surface->surface); if (!xdg_surface->popup->parent) return; xdg_surface->surface->data = wlr_scene_xdg_surface_create( @@ -1096,7 +1096,7 @@ focusclient(Client *c, int lift) /* If an overlay is focused, don't focus or activate the client, * but only update its position in fstack to render its border with focuscolor * and focus it after the overlay is closed. */ - Client *w = client_from_wlr_surface(old); + Client *w = toplevel_from_wlr_surface(old); if (wlr_surface_is_layer_surface(old)) { struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); @@ -1472,7 +1472,7 @@ motionnotify(uint32_t time) xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag) { - if ((l = toplevel_from_wlr_layer_surface( + if ((l = toplevel_from_wlr_surface( seat->pointer_state.focused_surface))) { surface = seat->pointer_state.focused_surface; sx = cursor->x - l->geom.x; @@ -2357,8 +2357,8 @@ void 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 && c != selclient()) { + Client *c = toplevel_from_wlr_surface(event->surface); + if (c && c->type != LayerShell && c != selclient()) { c->isurgent = 1; printstatus(); } From 22336612ae75954c68a7d4cd3f30fbebf94f441f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 3 Dec 2022 15:17:43 -0600 Subject: [PATCH 04/62] improve type safety of toplevel_from_wlr_surface() --- client.h | 47 ++++++++++++++++++++++++++++++++--------------- dwl.c | 49 ++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/client.h b/client.h index c12a107..77cde58 100644 --- a/client.h +++ b/client.h @@ -51,29 +51,38 @@ client_surface(Client *c) return c->surface.xdg->surface; } -static inline void * -toplevel_from_wlr_surface(struct wlr_surface *s) +static inline int +toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) { struct wlr_xdg_surface *xdg_surface; struct wlr_surface *root_surface; struct wlr_layer_surface_v1 *layer_surface; + Client *c = NULL; + LayerSurface *l = NULL; + int type = -1; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; #endif if (!s) - return NULL; + return type; root_surface = wlr_surface_get_root_surface(s); #ifdef XWAYLAND if (wlr_surface_is_xwayland_surface(root_surface) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) - return xsurface->data; + && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) { + c = xsurface->data; + type = c->type; + goto end; + } #endif if (wlr_surface_is_layer_surface(root_surface) - && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) - return layer_surface->data; + && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) { + l = layer_surface->data; + type = LayerShell; + goto end; + } if (wlr_surface_is_xdg_surface(root_surface) && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) { @@ -81,21 +90,28 @@ toplevel_from_wlr_surface(struct wlr_surface *s) switch (xdg_surface->role) { case WLR_XDG_SURFACE_ROLE_POPUP: if (!xdg_surface->popup->parent) - return NULL; + return -1; else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) - return toplevel_from_wlr_surface(xdg_surface->popup->parent); + return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - return xdg_surface->data; + c = xdg_surface->data; + type = c->type; + goto end; case WLR_XDG_SURFACE_ROLE_NONE: - return NULL; + return -1; } } } - return NULL; +end: + if (pl) + *pl = l; + if (pc) + *pc = c; + return type; } /* The others */ @@ -169,14 +185,15 @@ client_get_geometry(Client *c, struct wlr_box *geom) static inline Client * client_get_parent(Client *c) { + Client *p = NULL; #ifdef XWAYLAND if (client_is_x11(c) && c->surface.xwayland->parent) - return toplevel_from_wlr_surface(c->surface.xwayland->parent->surface); + toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); #endif if (c->surface.xdg->toplevel->parent) - return toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface); + toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); - return NULL; + return p; } static inline const char * diff --git a/dwl.c b/dwl.c index 9c2fc3d..3d71d19 100644 --- a/dwl.c +++ b/dwl.c @@ -904,22 +904,21 @@ createnotify(struct wl_listener *listener, void *data) * If you want to do something tricky with popups you should check if * its parent is wlr_xdg_shell or wlr_layer_shell */ struct wlr_xdg_surface *xdg_surface = data; - Client *c; + Client *c = NULL; + LayerSurface *l = NULL; if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; - LayerSurface *l = toplevel_from_wlr_surface(xdg_surface->surface); + int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l); if (!xdg_surface->popup->parent) return; xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); - /* Probably the check of `l` is useless, the only thing that can be NULL - * is its monitor */ - if (!l || !l->mon) + if ((!l || !l->mon) || (!c || !c->mon)) return; - box = l->type == LayerShell ? l->mon->m : l->mon->w; - box.x -= l->geom.x; - box.y -= l->geom.y; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); return; } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) @@ -1096,15 +1095,12 @@ focusclient(Client *c, int lift) /* If an overlay is focused, don't focus or activate the client, * but only update its position in fstack to render its border with focuscolor * and focus it after the overlay is closed. */ - Client *w = toplevel_from_wlr_surface(old); - if (wlr_surface_is_layer_surface(old)) { - struct wlr_layer_surface_v1 *wlr_layer_surface = - wlr_layer_surface_v1_from_wlr_surface(old); - - if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped - && (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP - || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)) - return; + Client *w = NULL; + LayerSurface *l = NULL; + int type = toplevel_from_wlr_surface(old, &w, &l); + if (type == LayerShell && l->scene->node.enabled + && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + return; } else if (w && w == exclusive_focus && client_wants_focus(w)) { return; /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg @@ -1438,8 +1434,9 @@ void motionnotify(uint32_t time) { double sx = 0, sy = 0; - Client *c = NULL; - LayerSurface *l; + Client *c = NULL, *w = NULL; + LayerSurface *l = NULL; + int type; struct wlr_surface *surface = NULL; struct wlr_drag_icon *icon; @@ -1472,11 +1469,12 @@ motionnotify(uint32_t time) xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag) { - if ((l = toplevel_from_wlr_surface( - seat->pointer_state.focused_surface))) { + if ((type = toplevel_from_wlr_surface( + seat->pointer_state.focused_surface, &w, &l)) >= 0) { + c = w; surface = seat->pointer_state.focused_surface; - sx = cursor->x - l->geom.x; - sy = cursor->y - l->geom.y; + sx = cursor->x - (type == LayerShell ? l->geom.x : w->geom.x); + sy = cursor->y - (type == LayerShell ? l->geom.y : w->geom.y); } } @@ -2357,8 +2355,9 @@ void urgent(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; - Client *c = toplevel_from_wlr_surface(event->surface); - if (c && c->type != LayerShell && c != selclient()) { + Client *c = NULL; + int type = toplevel_from_wlr_surface(event->surface, &c, NULL); + if (type >= 0 && type != LayerShell && c != selclient()) { c->isurgent = 1; printstatus(); } From c9a0a8bf6de9130655342e362a5a9f09c6a7fd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Dec 2022 23:21:21 -0600 Subject: [PATCH 05/62] bump version to 0.4-rc2 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index c2dd026..86b90ab 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.4-rc1 +_VERSION = 0.4-rc2 VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From 19b5d47a9e712b980749b7b9e1c562701d5afafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Dec 2022 13:31:48 -0600 Subject: [PATCH 06/62] fix popups appearing outside the monitor and a potentially crash --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 3d71d19..1dae796 100644 --- a/dwl.c +++ b/dwl.c @@ -914,7 +914,7 @@ createnotify(struct wl_listener *listener, void *data) return; xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); - if ((!l || !l->mon) || (!c || !c->mon)) + if ((l && !l->mon) || (c && !c->mon)) return; box = type == LayerShell ? l->mon->m : c->mon->w; box.x -= (type == LayerShell ? l->geom.x : c->geom.x); From 9136b6247d186790926bdee32d0a17d668ff8924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Dec 2022 13:34:35 -0600 Subject: [PATCH 07/62] return early if couldn't find the popup's parent --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 1dae796..b26743c 100644 --- a/dwl.c +++ b/dwl.c @@ -910,7 +910,7 @@ createnotify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_box box; int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l); - if (!xdg_surface->popup->parent) + if (!xdg_surface->popup->parent || type < 0) return; xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); From 4a32293548667e68cd9a103e22368b8db1754deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Dec 2022 13:56:28 -0600 Subject: [PATCH 08/62] Revert "fix flickering when resizing/spawning windows" This reverts commit 017bb7d7521f68d37bfe656c10f45edbcc92dd61. Bug: https://github.com/djpohly/dwl/issues/349 --- client.h | 15 --------------- dwl.c | 29 +++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/client.h b/client.h index 77cde58..dbf018f 100644 --- a/client.h +++ b/client.h @@ -240,21 +240,6 @@ client_is_mapped(Client *c) return c->surface.xdg->mapped; } -static inline int -client_is_rendered_on_mon(Client *c, Monitor *m) -{ - /* This is needed for when you don't want to check formal assignment, - * but rather actual displaying of the pixels. - * Usually VISIBLEON suffices and is also faster. */ - struct wlr_surface_output *s; - if (!c->scene->node.enabled) - return 0; - wl_list_for_each(s, &client_surface(c)->current_outputs, link) - if (s->output == m->wlr_output) - return 1; - return 0; -} - static inline int client_is_unmanaged(Client *c) { diff --git a/dwl.c b/dwl.c index b26743c..a1f579a 100644 --- a/dwl.c +++ b/dwl.c @@ -182,6 +182,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + int un_map; /* If a map/unmap happened on this monitor, then this should be true */ }; typedef struct { @@ -1383,6 +1384,8 @@ mapnotify(struct wl_listener *listener, void *data) } printstatus(); + c->mon->un_map = 1; + unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) @@ -1683,19 +1686,30 @@ rendermon(struct wl_listener *listener, void *data) * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); Client *c; + int skip = 0; struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + /* Render if no XDG clients have an outstanding resize and are visible on * this monitor. */ - wl_list_for_each(c, &clients, link) - if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize)) - goto skip; - if (!wlr_scene_output_commit(m->scene_output)) + /* Checking m->un_map for every client is not optimal but works */ + wl_list_for_each(c, &clients, link) { + if ((c->resize && m->un_map) || (c->type == XDGShell + && (c->surface.xdg->pending.geometry.width != + c->surface.xdg->current.geometry.width + || c->surface.xdg->pending.geometry.height != + c->surface.xdg->current.geometry.height))) { + /* Lie */ + wlr_surface_send_frame_done(client_surface(c), &now); + skip = 1; + } + } + if (!skip && !wlr_scene_output_commit(m->scene_output)) return; -skip: /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(m->scene_output, &now); + m->un_map = 0; } void @@ -2260,6 +2274,9 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } + if (c->mon) + c->mon->un_map = 1; + if (client_is_unmanaged(c)) { if (c == exclusive_focus) exclusive_focus = NULL; From d42a977b5ba8ae09753c7f6fcf4e2044bac7d92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Dec 2022 13:56:46 -0600 Subject: [PATCH 09/62] Revert "remove unneeded changes in commitnotify()" This reverts commit 30c24a53ad2aaa842bc3b028ba0b98e3362dad7c. Bug: https://github.com/djpohly/dwl/issues/349 --- dwl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a1f579a..d1f39d5 100644 --- a/dwl.c +++ b/dwl.c @@ -730,9 +730,14 @@ commitnotify(struct wl_listener *listener, void *data) struct wlr_box box = {0}; client_get_geometry(c, &box); + if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw + || box.height != c->geom.height - 2 * c->bw)) + arrange(c->mon); /* mark a pending resize as completed */ - if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial)) + 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; } From 79b051f2425af8a1e91a61fba145beb00f522973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Feb 2022 11:56:57 -0600 Subject: [PATCH 10/62] implement ext-session-lock-v1 --- dwl.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 167 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index d1f39d5..9ee3c76 100644 --- a/dwl.c +++ b/dwl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, LyrBlock, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -173,6 +174,8 @@ struct Monitor { struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ struct wl_listener frame; struct wl_listener destroy; + struct wl_listener destroy_lock_surface; + struct wlr_session_lock_surface_v1 *lock_surface; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ @@ -202,6 +205,15 @@ typedef struct { int monitor; } Rule; +typedef struct { + struct wlr_scene_tree *scene; + + struct wlr_session_lock_v1 *lock; + struct wl_listener new_surface; + struct wl_listener unlock; + struct wl_listener destroy; +} SessionLock; + /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); static void applyrules(Client *c); @@ -222,6 +234,7 @@ static void commitnotify(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); static void createlayersurface(struct wl_listener *listener, void *data); +static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); @@ -229,7 +242,11 @@ static void cursorframe(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); +static void destroylock(SessionLock *lock, int unlocked); +static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); +static void destroysessionlock(struct wl_listener *listener, void *data); +static void destroysessionmgr(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); @@ -242,6 +259,7 @@ static int keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); +static void locksession(struct wl_listener *listener, void *data); static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data); static void maximizenotify(struct wl_listener *listener, void *data); @@ -281,6 +299,7 @@ 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 unlocksession(struct wl_listener *listener, void *data); 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); @@ -297,6 +316,7 @@ static void zoom(const Arg *arg); static const char broken[] = "broken"; static const char *cursor_image = "left_ptr"; static pid_t child_pid = -1; +static int locked; static void *exclusive_focus; static struct wl_display *dpy; static struct wlr_backend *backend; @@ -321,6 +341,10 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; +static struct wlr_session_lock_manager_v1 *session_lock_mgr; +static struct wlr_scene_rect *locked_bg; +static struct wlr_session_lock_v1 *cur_lock; + static struct wlr_seat *seat; static struct wl_list keyboards; static unsigned int cursor_mode; @@ -355,6 +379,8 @@ static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; +static struct wl_listener session_lock_create_lock = {.notify = locksession}; +static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -504,8 +530,8 @@ arrangelayers(Monitor *m) for (i = 0; i < LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { - if (layersurface->layer_surface->current.keyboard_interactive && - layersurface->mapped) { + if (!locked && layersurface->layer_surface->current.keyboard_interactive + && layersurface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); exclusive_focus = layersurface; @@ -544,6 +570,10 @@ buttonpress(struct wl_listener *listener, void *data) switch (event->state) { case WLR_BUTTON_PRESSED: + cursor_mode = CurPressed; + if (locked) + break; + /* Change focus if the button was _pressed_ over a client */ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) @@ -558,11 +588,10 @@ buttonpress(struct wl_listener *listener, void *data) return; } } - cursor_mode = CurPressed; break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ - if (cursor_mode != CurNormal && cursor_mode != CurPressed) { + if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { cursor_mode = CurNormal; /* Clear the pointer focus, this way if the cursor is over a surface * we will send an enter event after which the client will provide us @@ -828,6 +857,25 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->current = old_state; } +void +createlocksurface(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, new_surface); + struct wlr_session_lock_surface_v1 *lock_surface = data; + Monitor *m = lock_surface->output->data; + struct wlr_scene_tree *scene_tree = lock_surface->surface->data = + wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); + m->lock_surface = lock_surface; + + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); + + LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface); + + if (m == selmon) + client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); +} + void createmon(struct wl_listener *listener, void *data) { @@ -1032,6 +1080,49 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) free(layersurface); } +void +destroylock(SessionLock *lock, int unlock) +{ + wlr_seat_keyboard_notify_clear_focus(seat); + if ((locked = !unlock)) + goto destroy; + + wlr_scene_node_set_enabled(&locked_bg->node, 0); + + focusclient(focustop(selmon), 0); + motionnotify(0); + +destroy: + wl_list_remove(&lock->new_surface.link); + wl_list_remove(&lock->unlock.link); + wl_list_remove(&lock->destroy.link); + + wlr_scene_node_destroy(&lock->scene->node); + cur_lock = NULL; + free(lock); +} + +void +destroylocksurface(struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of(listener, m, destroy_lock_surface); + struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; + + m->lock_surface = NULL; + wl_list_remove(&m->destroy_lock_surface.link); + + if (lock_surface->surface == seat->keyboard_state.focused_surface) { + if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { + surface = wl_container_of(cur_lock->surfaces.next, surface, link); + client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); + } else if (!locked) { + focusclient(focustop(selmon), 1); + } else { + wlr_seat_keyboard_clear_focus(seat); + } + } +} + void destroynotify(struct wl_listener *listener, void *data) { @@ -1052,6 +1143,20 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } +void +destroysessionlock(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, destroy); + destroylock(lock, 0); +} + +void +destroysessionmgr(struct wl_listener *listener, void *data) +{ + wl_list_remove(&session_lock_create_lock.link); + wl_list_remove(&session_lock_mgr_destroy.link); +} + Monitor * dirtomon(enum wlr_direction dir) { @@ -1074,6 +1179,9 @@ focusclient(Client *c, int lift) struct wlr_surface *old = seat->keyboard_state.focused_surface; int i; + if (locked) + return; + /* Raise client in stacking order if requested */ if (c && lift) wlr_scene_node_raise_to_top(&c->scene->node); @@ -1276,7 +1384,7 @@ keypress(struct wl_listener *listener, void *data) /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ - if (!input_inhibit_mgr->active_inhibitor + if (!locked && !input_inhibit_mgr->active_inhibitor && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; @@ -1315,6 +1423,31 @@ killclient(const Arg *arg) client_send_close(sel); } +void +locksession(struct wl_listener *listener, void *data) +{ + struct wlr_session_lock_v1 *session_lock = data; + SessionLock *lock; + wlr_scene_node_set_enabled(&locked_bg->node, 1); + if (cur_lock) { + wlr_session_lock_v1_destroy(session_lock); + return; + } + lock = ecalloc(1, sizeof(*lock)); + focusclient(NULL, 0); + + lock->scene = wlr_scene_tree_create(layers[LyrBlock]); + cur_lock = lock->lock = session_lock; + locked = 1; + session_lock->data = lock; + + LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); + LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); + LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); + + wlr_session_lock_v1_send_locked(session_lock); +} + void maplayersurfacenotify(struct wl_listener *listener, void *data) { @@ -1985,6 +2118,7 @@ setup(void) layers[LyrTop] = wlr_scene_tree_create(&scene->tree); layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree); + layers[LyrBlock] = wlr_scene_tree_create(&scene->tree); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2049,6 +2183,12 @@ setup(void) wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); + session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); + wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); + wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); + locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, + (float [4]){0.1, 0.1, 0.1, 1.0}); + wlr_scene_node_set_enabled(&locked_bg->node, 0); /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( @@ -2251,6 +2391,13 @@ toggleview(const Arg *arg) printstatus(); } +void +unlocksession(struct wl_listener *listener, void *data) +{ + SessionLock *lock = wl_container_of(listener, lock, unlock); + destroylock(lock, 1); +} + void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { @@ -2334,6 +2481,7 @@ updatemons(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, m->wlr_output); /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); + wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) continue; @@ -2351,16 +2499,27 @@ updatemons(struct wl_listener *listener, void *data) wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + if (m->lock_surface) { + struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; + wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); + wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, + m->m.height); + } + config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; config_head->state.y = m->m.y; } - if (selmon && selmon->wlr_output->enabled) + 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); + if (selmon->lock_surface) + client_notify_enter(selmon->lock_surface->surface, + wlr_seat_get_keyboard(seat)); + } wlr_output_manager_v1_set_configuration(output_mgr, config); } @@ -2421,7 +2580,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, Client *c = NULL; LayerSurface *l = NULL; const int *layer; - int focus_order[] = { LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; + int focus_order[] = { LyrBlock, LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; for (layer = focus_order; layer < END(focus_order); layer++) { if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { From c60f65195186e6c72ec66ba7f10139a420a595a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Dec 2022 08:46:22 -0600 Subject: [PATCH 11/62] Revert "force line-buffered stdout if stdout is not a tty" This reverts commit deb48ff48b186ff77a7e9d3b3ab724ff4c3c340f. Fixes: https://github.com/djpohly/dwl/issues/253 --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 9ee3c76..2f7f2bf 100644 --- a/dwl.c +++ b/dwl.c @@ -1803,6 +1803,7 @@ printstatus(void) sel, urg); printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); } + fflush(stdout); } void @@ -2081,9 +2082,6 @@ 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 94c8bd604870365bc201524b63158623e6f32a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Dec 2022 20:55:58 -0600 Subject: [PATCH 12/62] get `sel` from focustop() in focusstack() Fixes: https://github.com/djpohly/dwl/issues/354 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 2f7f2bf..5add915 100644 --- a/dwl.c +++ b/dwl.c @@ -1261,7 +1261,7 @@ void focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ - Client *c, *sel = selclient(); + Client *c, *sel = focustop(selmon); if (!sel || sel->isfullscreen) return; if (arg->i > 0) { From a39a46c908011de913b142dbd1dd427eb7fbca0a Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Thu, 15 Dec 2022 17:34:03 -0500 Subject: [PATCH 13/62] Check width and height are not negative in client_set_bounds() --- client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.h b/client.h index dbf018f..06c2073 100644 --- a/client.h +++ b/client.h @@ -141,7 +141,7 @@ client_set_bounds(Client *c, int32_t width, int32_t height) return 0; #endif if (c->surface.xdg->client->shell->version >= - XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0) return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); return 0; } From 803a9ba98d6976c71e92973e3af6096476984fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 16 Dec 2022 16:31:31 -0600 Subject: [PATCH 14/62] Revert "Revert "Check that inhibitor scene tree is not null"" This reverts commit 035bb99d67b59a84cfc2e911d222fb597591a8be. Not checking `tree != NULL` result in a segfault if the surface doesn't have a role (for example because it is a newly created surface) Closes: https://github.com/djpohly/dwl/issues/359 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5add915..2bcb8b1 100644 --- a/dwl.c +++ b/dwl.c @@ -628,7 +628,7 @@ checkidleinhibitor(struct wlr_surface *exclude) struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); struct wlr_scene_tree *tree = surface->data; if (bypass_surface_visibility || (exclude != surface - && tree->node.enabled)) { + && tree && tree->node.enabled)) { inhibited = 1; break; } From 7b1fe7e5f2b92f025063cc98ebdb1791945e2f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 16 Dec 2022 17:24:45 -0600 Subject: [PATCH 15/62] fix checking idle inhibit state checking `bypass_surface_visibility` first, could cause that even if the idle inhibitor is being destroyed it will disable idle tracking and if we couldn't get its scene tree, then assume that the surface is visible --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 2bcb8b1..f535baf 100644 --- a/dwl.c +++ b/dwl.c @@ -627,8 +627,8 @@ checkidleinhibitor(struct wlr_surface *exclude) wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); struct wlr_scene_tree *tree = surface->data; - if (bypass_surface_visibility || (exclude != surface - && tree && tree->node.enabled)) { + if (exclude != surface && (bypass_surface_visibility || (!tree + || tree->node.enabled))) { inhibited = 1; break; } From 1a3d89e5b2c14aa4aebe73a0a0804d14c30386ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 16 Dec 2022 18:54:33 -0600 Subject: [PATCH 16/62] call checkidleinhibitor() in arrange() and not in focusclient() --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index f535baf..6e3b034 100644 --- a/dwl.c +++ b/dwl.c @@ -477,6 +477,7 @@ arrange(Monitor *m) if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); + checkidleinhibitor(NULL); } void @@ -1226,9 +1227,7 @@ focusclient(Client *c, int lift) client_activate_surface(old, 0); } } - printstatus(); - checkidleinhibitor(NULL); if (!c) { /* With no client, all we have left is to clear focus */ From 686958a4cc599fe212d8e1111999cd59a54e9ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 17 Dec 2022 13:46:04 -0600 Subject: [PATCH 17/62] fix unset fullscreen for all visible clients when mapping a new one this also changes our policy about when we unset fullscreen: dwl will unset fullscreen for clients who share tags (and monitor) with a newly mapped client, it does not matter if the clients are visible or not --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6e3b034..4c045c2 100644 --- a/dwl.c +++ b/dwl.c @@ -1526,7 +1526,7 @@ mapnotify(struct wl_listener *listener, void *data) unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) - if (w != c && w->isfullscreen && VISIBLEON(w, m)) + if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags)) setfullscreen(w, 0); } From dd9d8d543cc511df44035c0e3fe32a5f17a31c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Dec 2022 11:39:50 -0600 Subject: [PATCH 18/62] remove selclient() selclient() does not work well when dealing newly mapped clients (specifically those mapped on invisible tags). This fixes various bugs related to things not working because selclient() would return NULL. References: 94c8bd604870365bc201524b63158623e6f32a8f --- dwl.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/dwl.c b/dwl.c index 4c045c2..f189139 100644 --- a/dwl.c +++ b/dwl.c @@ -280,7 +280,6 @@ static void rendermon(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); 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); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); @@ -1055,7 +1054,7 @@ destroydragicon(struct wl_listener *listener, void *data) struct wlr_drag_icon *icon = data; wlr_scene_node_destroy(icon->data); /* Focus enter isn't sent during drag, so refocus the focused node. */ - focusclient(selclient(), 1); + focusclient(focustop(selmon), 1); motionnotify(0); } @@ -1417,7 +1416,7 @@ keypressmod(struct wl_listener *listener, void *data) void killclient(const Arg *arg) { - Client *sel = selclient(); + Client *sel = focustop(selmon); if (sel) client_send_close(sel); } @@ -1940,15 +1939,6 @@ run(char *startup_cmd) wl_display_run(dpy); } -Client * -selclient(void) -{ - Client *c = wl_container_of(fstack.next, c, flink); - if (wl_list_empty(&fstack) || !VISIBLEON(c, selmon)) - return NULL; - return c; -} - void setcursor(struct wl_listener *listener, void *data) { @@ -2292,7 +2282,7 @@ startdrag(struct wl_listener *listener, void *data) void tag(const Arg *arg) { - Client *sel = selclient(); + Client *sel = focustop(selmon); if (sel && arg->ui & TAGMASK) { sel->tags = arg->ui & TAGMASK; focusclient(focustop(selmon), 1); @@ -2304,7 +2294,7 @@ tag(const Arg *arg) void tagmon(const Arg *arg) { - Client *sel = selclient(); + Client *sel = focustop(selmon); if (sel) setmon(sel, dirtomon(arg->i), 0); } @@ -2345,7 +2335,7 @@ tile(Monitor *m) void togglefloating(const Arg *arg) { - Client *sel = selclient(); + Client *sel = focustop(selmon); /* return if fullscreen */ if (sel && !sel->isfullscreen) setfloating(sel, !sel->isfloating); @@ -2354,7 +2344,7 @@ togglefloating(const Arg *arg) void togglefullscreen(const Arg *arg) { - Client *sel = selclient(); + Client *sel = focustop(selmon); if (sel) setfullscreen(sel, !sel->isfullscreen); } @@ -2363,7 +2353,7 @@ void toggletag(const Arg *arg) { unsigned int newtags; - Client *sel = selclient(); + Client *sel = focustop(selmon); if (!sel) return; newtags = sel->tags ^ (arg->ui & TAGMASK); @@ -2409,7 +2399,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) arrangelayers(layersurface->mon); if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) - focusclient(selclient(), 1); + focusclient(focustop(selmon), 1); motionnotify(0); } @@ -2430,7 +2420,7 @@ unmapnotify(struct wl_listener *listener, void *data) if (c == exclusive_focus) exclusive_focus = NULL; if (client_surface(c) == seat->keyboard_state.focused_surface) - focusclient(selclient(), 1); + focusclient(focustop(selmon), 1); } else { wl_list_remove(&c->link); setmon(c, NULL, 0); @@ -2535,7 +2525,7 @@ urgent(struct wl_listener *listener, void *data) struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *c = NULL; int type = toplevel_from_wlr_surface(event->surface, &c, NULL); - if (type >= 0 && type != LayerShell && c != selclient()) { + if (type >= 0 && type != LayerShell && c != focustop(selmon)) { c->isurgent = 1; printstatus(); } @@ -2605,7 +2595,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, void zoom(const Arg *arg) { - Client *c, *sel = selclient(); + Client *c, *sel = focustop(selmon); if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) return; @@ -2699,7 +2689,7 @@ void sethints(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_hints); - if (c != selclient()) { + if (c != focustop(selmon)) { c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); printstatus(); } From afacc9b0b50fe9c63700e62f7d2083c6edb9d17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 19 Dec 2022 21:43:15 -0600 Subject: [PATCH 19/62] force SSD when creating an xdg_toplevel_decoration object Closes: https://github.com/djpohly/dwl/issues/366 Not sure why GLFW apps do not get mapped when we do not tell them the decoration method --- dwl.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index f189139..2b4aa64 100644 --- a/dwl.c +++ b/dwl.c @@ -231,6 +231,7 @@ static void cleanupmon(struct wl_listener *listener, void *data); static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); +static void createdecoration(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); static void createlayersurface(struct wl_listener *listener, void *data); @@ -327,6 +328,7 @@ static struct wlr_compositor *compositor; static struct wlr_xdg_shell *xdg_shell; static struct wlr_xdg_activation_v1 *activation; +static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; @@ -369,6 +371,7 @@ static struct wl_listener new_input = {.notify = inputdevice}; static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; static struct wl_listener new_output = {.notify = createmon}; static struct wl_listener new_xdg_surface = {.notify = createnotify}; +static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; @@ -770,6 +773,13 @@ commitnotify(struct wl_listener *listener, void *data) c->resize = 0; } +void +createdecoration(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *dec = data; + wlr_xdg_toplevel_decoration_v1_set_mode(dec, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + void createidleinhibitor(struct wl_listener *listener, void *data) { @@ -2181,7 +2191,8 @@ setup(void) wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(dpy), WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - wlr_xdg_decoration_manager_v1_create(dpy); + xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); + wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); /* * Creates a cursor, which is a wlroots utility for tracking the cursor From 66828780094280064f5d3c0cb2982d28b0557e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 12 Dec 2022 10:51:03 -0600 Subject: [PATCH 20/62] call arrange() or resize() depending on c->isfloating in commitnotify --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 2b4aa64..4fb8f49 100644 --- a/dwl.c +++ b/dwl.c @@ -764,7 +764,7 @@ commitnotify(struct wl_listener *listener, void *data) 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); + c->isfloating ? resize(c, c->geom, 1) : arrange(c->mon); /* mark a pending resize as completed */ if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial From 92e7752203eb7812f2d333f8c6af1963fa743c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Dec 2022 16:26:37 -0600 Subject: [PATCH 21/62] disable client's scene node after create it (only XDGShell) will be enabled when setting up its monitor and arrange it Bug: https://github.com/djpohly/dwl/issues/306 --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 4fb8f49..196c34d 100644 --- a/dwl.c +++ b/dwl.c @@ -1474,6 +1474,7 @@ mapnotify(struct wl_listener *listener, void *data) /* Create scene tree for this client and its border */ c->scene = wlr_scene_tree_create(layers[LyrTile]); + wlr_scene_node_set_enabled(&c->scene->node, 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)); From 7eaa01ac1f074511ae1013326172d51c6fdf8866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Dec 2022 14:47:55 -0600 Subject: [PATCH 22/62] Revert "Revert "fix flickering when resizing/spawning windows"" This reverts commit 4a32293548667e68cd9a103e22368b8db1754deb. --- client.h | 15 +++++++++++++++ dwl.c | 29 ++++++----------------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/client.h b/client.h index 06c2073..064e093 100644 --- a/client.h +++ b/client.h @@ -240,6 +240,21 @@ client_is_mapped(Client *c) return c->surface.xdg->mapped; } +static inline int +client_is_rendered_on_mon(Client *c, Monitor *m) +{ + /* This is needed for when you don't want to check formal assignment, + * but rather actual displaying of the pixels. + * Usually VISIBLEON suffices and is also faster. */ + struct wlr_surface_output *s; + if (!c->scene->node.enabled) + return 0; + wl_list_for_each(s, &client_surface(c)->current_outputs, link) + if (s->output == m->wlr_output) + return 1; + return 0; +} + static inline int client_is_unmanaged(Client *c) { diff --git a/dwl.c b/dwl.c index 196c34d..8a21342 100644 --- a/dwl.c +++ b/dwl.c @@ -185,7 +185,6 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; - int un_map; /* If a map/unmap happened on this monitor, then this should be true */ }; typedef struct { @@ -1531,8 +1530,6 @@ mapnotify(struct wl_listener *listener, void *data) } printstatus(); - c->mon->un_map = 1; - unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) @@ -1834,30 +1831,19 @@ rendermon(struct wl_listener *listener, void *data) * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); Client *c; - int skip = 0; struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - /* Render if no XDG clients have an outstanding resize and are visible on * this monitor. */ - /* Checking m->un_map for every client is not optimal but works */ - wl_list_for_each(c, &clients, link) { - if ((c->resize && m->un_map) || (c->type == XDGShell - && (c->surface.xdg->pending.geometry.width != - c->surface.xdg->current.geometry.width - || c->surface.xdg->pending.geometry.height != - c->surface.xdg->current.geometry.height))) { - /* Lie */ - wlr_surface_send_frame_done(client_surface(c), &now); - skip = 1; - } - } - if (!skip && !wlr_scene_output_commit(m->scene_output)) + wl_list_for_each(c, &clients, link) + if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize)) + goto skip; + if (!wlr_scene_output_commit(m->scene_output)) return; +skip: /* Let clients know a frame has been rendered */ + clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(m->scene_output, &now); - m->un_map = 0; } void @@ -2425,9 +2411,6 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } - if (c->mon) - c->mon->un_map = 1; - if (client_is_unmanaged(c)) { if (c == exclusive_focus) exclusive_focus = NULL; From 6ca011430a18980f12f7314cdeeff36051268a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 21 Dec 2022 14:28:27 -0600 Subject: [PATCH 23/62] do not skip frames if a client is stopped and have a pending resize --- client.h | 26 ++++++++++++++++++++++++++ dwl.c | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 064e093..295e8ff 100644 --- a/client.h +++ b/client.h @@ -255,6 +255,32 @@ client_is_rendered_on_mon(Client *c, Monitor *m) return 0; } +static inline int +client_is_stopped(Client *c) +{ + int pid; + siginfo_t in = {0}; +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { + /* This process is not our child process, while is very unluckely that + * it is stopped, in order to do not skip frames assume that it is. */ + if (errno == ECHILD) + return 1; + } else if (in.si_pid) { + if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) + return 1; + if (in.si_code == CLD_CONTINUED) + return 0; + } + + return 0; +} + static inline int client_is_unmanaged(Client *c) { diff --git a/dwl.c b/dwl.c index 8a21342..43603db 100644 --- a/dwl.c +++ b/dwl.c @@ -1836,7 +1836,7 @@ rendermon(struct wl_listener *listener, void *data) /* Render if no XDG clients have an outstanding resize and are visible on * this monitor. */ wl_list_for_each(c, &clients, link) - if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize)) + if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize) && !client_is_stopped(c)) goto skip; if (!wlr_scene_output_commit(m->scene_output)) return; From be854cab35bc090ab3f6fbad3a0f93013294226d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Dec 2022 23:21:58 -0600 Subject: [PATCH 24/62] do not try to resize if size wouldn't change --- client.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client.h b/client.h index 295e8ff..5a45edc 100644 --- a/client.h +++ b/client.h @@ -345,6 +345,9 @@ client_set_size(Client *c, uint32_t width, uint32_t height) return 0; } #endif + if (width == c->surface.xdg->toplevel->current.width + && height ==c->surface.xdg->toplevel->current.height) + return 0; return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height); } From 05f4e23c43aa0d6e8fb8673a3b0d71653dc6dbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 24 Dec 2022 17:54:19 -0600 Subject: [PATCH 25/62] bump version to 0.4-rc3 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 86b90ab..01aad14 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.4-rc2 +_VERSION = 0.4-rc3 VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From 5347ed663de57f624abe887dc761949eb7169986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:14:06 -0600 Subject: [PATCH 26/62] only mark pending resizes as completed checking the configure serial --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 43603db..9b6be9f 100644 --- a/dwl.c +++ b/dwl.c @@ -766,9 +766,7 @@ commitnotify(struct wl_listener *listener, void *data) c->isfloating ? resize(c, c->geom, 1) : arrange(c->mon); /* mark a pending resize as completed */ - 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))) + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) c->resize = 0; } From 6d0e3a51987ebda89193cf52996227110ad7068c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:15:21 -0600 Subject: [PATCH 27/62] check if a client is resizing before checking if it's visible It's not like it's noticeable, but theoretically this is faster --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 9b6be9f..5189757 100644 --- a/dwl.c +++ b/dwl.c @@ -1834,7 +1834,7 @@ rendermon(struct wl_listener *listener, void *data) /* Render if no XDG clients have an outstanding resize and are visible on * this monitor. */ wl_list_for_each(c, &clients, link) - if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize) && !client_is_stopped(c)) + if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; if (!wlr_scene_output_commit(m->scene_output)) return; From e523c2b82b835aa27e6ad5d015ed38d6a5cae0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:19:47 -0600 Subject: [PATCH 28/62] update comment about client_set_size() as no-op --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5189757..7ae2032 100644 --- a/dwl.c +++ b/dwl.c @@ -1875,7 +1875,7 @@ resize(Client *c, struct wlr_box geo, int interact) wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); - /* wlroots makes this a no-op if size hasn't changed */ + /* this is a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); } From 72d29f165449a28f84e476803543f30f11e366e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:21:46 -0600 Subject: [PATCH 29/62] add blank lines to make updatemons() more readable --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 7ae2032..a0b2ca8 100644 --- a/dwl.c +++ b/dwl.c @@ -2459,9 +2459,12 @@ updatemons(struct wl_listener *listener, void *data) if (m->wlr_output->enabled && !wlr_output_layout_get(output_layout, m->wlr_output)) wlr_output_layout_add_auto(output_layout, m->wlr_output); + /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); + wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); + wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) continue; From 71c7e4e1e5d2181d58fba3ce14a4457885523452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:25:19 -0600 Subject: [PATCH 30/62] also update locked_bg node position in updatemons() --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index a0b2ca8..f80219d 100644 --- a/dwl.c +++ b/dwl.c @@ -2463,6 +2463,8 @@ updatemons(struct wl_listener *listener, void *data) /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); + /* Make sure the clients are hidden when dwl is locked */ + wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); wl_list_for_each(m, &mons, link) { From 56114f700ffabc7f0f69a0f98053cfb629e0d521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:26:53 -0600 Subject: [PATCH 31/62] arrange monitor after updating fullscreen background and lock surfaces --- dwl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index f80219d..e4ad8cf 100644 --- a/dwl.c +++ b/dwl.c @@ -2476,10 +2476,6 @@ updatemons(struct wl_listener *listener, void *data) wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); - /* Calculate the effective monitor geometry to use for clients */ - arrangelayers(m); - /* Don't move clients to the left output when plugging monitors */ - arrange(m); wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); @@ -2491,6 +2487,11 @@ updatemons(struct wl_listener *listener, void *data) m->m.height); } + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); + config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; From 0b2c33248c57d8d6366f292d421f86f664ca3c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:29:19 -0600 Subject: [PATCH 32/62] simplify check in urgent() we only care if it returned a client or not --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index e4ad8cf..1f0db88 100644 --- a/dwl.c +++ b/dwl.c @@ -2523,8 +2523,8 @@ urgent(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *c = NULL; - int type = toplevel_from_wlr_surface(event->surface, &c, NULL); - if (type >= 0 && type != LayerShell && c != focustop(selmon)) { + toplevel_from_wlr_surface(event->surface, &c, NULL); + if (c && c != focustop(selmon)) { c->isurgent = 1; printstatus(); } From dbe44e48c8b0434565fa9322fda4d493b0ae25ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:31:56 -0600 Subject: [PATCH 33/62] return early if selmon is not part of the output layout in dirtomon() instead of checking twice --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 1f0db88..19bb6ce 100644 --- a/dwl.c +++ b/dwl.c @@ -1168,12 +1168,12 @@ Monitor * dirtomon(enum wlr_direction dir) { struct wlr_output *next; - if (wlr_output_layout_get(output_layout, selmon->wlr_output) - && (next = wlr_output_layout_adjacent_output(output_layout, + if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) + return selmon; + if ((next = wlr_output_layout_adjacent_output(output_layout, dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) return next->data; - if (wlr_output_layout_get(output_layout, selmon->wlr_output) - && (next = wlr_output_layout_farthest_output(output_layout, + if ((next = wlr_output_layout_farthest_output(output_layout, dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), selmon->wlr_output, selmon->m.x, selmon->m.y))) return next->data; From 932c1d45f279a78cac021f7f643fc65460245b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:45:03 -0600 Subject: [PATCH 34/62] remove `--long` from git-describe command --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 01aad14..36dc49b 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ _VERSION = 0.4-rc3 -VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` +VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From 8653b276927b6622d3c50f98d05380b27b9b007c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Dec 2022 14:38:03 -0600 Subject: [PATCH 35/62] bump version to 0.4 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 36dc49b..f50156f 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.4-rc3 +_VERSION = 0.4 VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From f7d6a34cd98e3c090956c8a263a44972c3ffa05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 00:54:48 -0500 Subject: [PATCH 36/62] use sigaction(2) for signal handling References: http://git.suckless.org/dwm/commit/712d6639ff8e863560328131bbb92b248dc9cde7.html --- dwl.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index 19bb6ce..c2273ba 100644 --- a/dwl.c +++ b/dwl.c @@ -1885,6 +1885,8 @@ run(char *startup_cmd) { /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_IGN}; + sigemptyset(&sa.sa_mask); if (!socket) die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); @@ -1913,7 +1915,7 @@ run(char *startup_cmd) close(piperw[0]); } /* If nobody is reading the status output, don't terminate */ - signal(SIGPIPE, SIG_IGN); + sigaction(SIGPIPE, &sa, NULL); printstatus(); /* At this point the outputs are initialized, choose initial selmon based on @@ -2066,18 +2068,26 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { + struct sigaction sa_term = {.sa_flags = SA_RESTART, .sa_handler = quitsignal}; + struct sigaction sa_sigchld = { +#ifdef XWAYLAND + .sa_flags = SA_RESTART, + .sa_handler = sigchld, +#else + .sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART, + .sa_handler = SIG_IGN, +#endif + }; + sigemptyset(&sa_term.sa_mask); + sigemptyset(&sa_sigchld.sa_mask); /* 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(); /* Set up signal handlers */ -#ifdef XWAYLAND - sigchld(0); -#else - signal(SIGCHLD, SIG_IGN); -#endif - signal(SIGINT, quitsignal); - signal(SIGTERM, quitsignal); + sigaction(SIGCHLD, &sa_sigchld, NULL); + sigaction(SIGINT, &sa_term, NULL); + sigaction(SIGTERM, &sa_term, NULL); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable @@ -2699,12 +2709,11 @@ sigchld(int unused) { siginfo_t in; /* We should be able to remove this function in favor of a simple - * signal(SIGCHLD, SIG_IGN); + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); * but the Xwayland implementation in wlroots currently prevents us from * setting our own disposition for SIGCHLD. */ - if (signal(SIGCHLD, sigchld) == SIG_ERR) - die("can't install SIGCHLD handler:"); /* WNOWAIT leaves the child in a waitable state, in case this is the * XWayland process */ From 23ede80f741d8452dbf223226974476ef8860541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 12:24:13 -0500 Subject: [PATCH 37/62] allow configure x and y of outputs --- config.def.h | 6 +++--- dwl.c | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config.def.h b/config.def.h index a4f7c13..419e6ef 100644 --- a/config.def.h +++ b/config.def.h @@ -29,12 +29,12 @@ static const Layout layouts[] = { /* monitors */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect */ + /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL -1, -1 }, */ /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, }; /* keyboard */ diff --git a/dwl.c b/dwl.c index c2273ba..57870fe 100644 --- a/dwl.c +++ b/dwl.c @@ -194,6 +194,7 @@ typedef struct { float scale; const Layout *lt; enum wl_output_transform rr; + int x, y; } MonitorRule; typedef struct { @@ -908,6 +909,8 @@ createmon(struct wl_listener *listener, void *data) wlr_xcursor_manager_load(cursor_mgr, r->scale); m->lt[0] = m->lt[1] = r->lt; wlr_output_set_transform(wlr_output, r->rr); + m->m.x = r->x; + m->m.y = r->y; break; } } @@ -953,7 +956,10 @@ createmon(struct wl_listener *listener, void *data) * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - wlr_output_layout_add_auto(output_layout, wlr_output); + if (m->m.x < 0 || m->m.y < 0) + wlr_output_layout_add_auto(output_layout, wlr_output); + else + wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); } void From ab8334bd8a85c5c63a2d06bc68bf0b5f5e1c2923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 26 Dec 2022 16:45:38 -0600 Subject: [PATCH 38/62] implement repeatable keybindings --- dwl.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/dwl.c b/dwl.c index 57870fe..ac741d2 100644 --- a/dwl.c +++ b/dwl.c @@ -139,6 +139,11 @@ typedef struct { struct wl_list link; struct wlr_keyboard *wlr_keyboard; + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; + struct wl_listener modifiers; struct wl_listener key; struct wl_listener destroy; @@ -259,6 +264,7 @@ static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); +static int keyrepeat(void *data); static void killclient(const Arg *arg); static void locksession(struct wl_listener *listener, void *data); static void maplayersurfacenotify(struct wl_listener *listener, void *data); @@ -667,6 +673,7 @@ cleanupkeyboard(struct wl_listener *listener, void *data) { Keyboard *kb = wl_container_of(listener, kb, destroy); + wl_event_source_remove(kb->key_repeat_source); wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); wl_list_remove(&kb->key.link); @@ -812,6 +819,9 @@ createkeyboard(struct wlr_keyboard *keyboard) wlr_seat_set_keyboard(seat, keyboard); + kb->key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, kb); + /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); } @@ -1400,6 +1410,17 @@ keypress(struct wl_listener *listener, void *data) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; + if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { + kb->mods = mods; + kb->keysyms = syms; + kb->nsyms = nsyms; + wl_event_source_timer_update(kb->key_repeat_source, + kb->wlr_keyboard->repeat_info.delay); + } else { + kb->nsyms = 0; + wl_event_source_timer_update(kb->key_repeat_source, 0); + } + if (!handled) { /* Pass unhandled keycodes along to the client. */ wlr_seat_set_keyboard(seat, kb->wlr_keyboard); @@ -1426,6 +1447,22 @@ keypressmod(struct wl_listener *listener, void *data) &kb->wlr_keyboard->modifiers); } +int +keyrepeat(void *data) +{ + Keyboard *kb = data; + int i; + if (kb->nsyms && kb->wlr_keyboard->repeat_info.rate > 0) { + wl_event_source_timer_update(kb->key_repeat_source, + 1000 / kb->wlr_keyboard->repeat_info.rate); + + for (i = 0; i < kb->nsyms; i++) + keybinding(kb->mods, kb->keysyms[i]); + } + + return 0; +} + void killclient(const Arg *arg) { From 7f9a21247613a0d8ba6575869220e29071a40c64 Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Wed, 23 Nov 2022 21:55:04 +1000 Subject: [PATCH 39/62] Add appid field to printstatus() output Adds an appid field to printstatus which can be used to monitor the currently active application. --- dwl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ac741d2..efd6977 100644 --- a/dwl.c +++ b/dwl.c @@ -1823,6 +1823,7 @@ printstatus(void) Monitor *m = NULL; Client *c; unsigned int occ, urg, sel; + const char *appid, *title; wl_list_for_each(m, &mons, link) { occ = urg = 0; @@ -1834,12 +1835,16 @@ printstatus(void) urg |= c->tags; } if ((c = focustop(m))) { - printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); + title = client_get_title(c); + appid = client_get_appid(c); + printf("%s title %s\n", m->wlr_output->name, title ? title : broken); + printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen); printf("%s floating %u\n", m->wlr_output->name, c->isfloating); sel = c->tags; } else { printf("%s title \n", m->wlr_output->name); + printf("%s appid \n", m->wlr_output->name); printf("%s fullscreen \n", m->wlr_output->name); printf("%s floating \n", m->wlr_output->name); sel = 0; From f8373ccf2581fa481602bbb7528ba8871f6d5c85 Mon Sep 17 00:00:00 2001 From: pino-desktop Date: Sun, 8 Jan 2023 17:37:24 +0100 Subject: [PATCH 40/62] Fixed 'unused variable' compiler warning. --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index efd6977..27d051f 100644 --- a/dwl.c +++ b/dwl.c @@ -1526,7 +1526,6 @@ mapnotify(struct wl_listener *listener, void *data) } c->scene->node.data = c->scene_surface->node.data = c; -#ifdef XWAYLAND /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); @@ -1540,7 +1539,6 @@ mapnotify(struct wl_listener *listener, void *data) } goto unset_fullscreen; } -#endif for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); From 737688a6b1da09c4276d3e26989305f287389505 Mon Sep 17 00:00:00 2001 From: godalming123 Date: Fri, 17 Feb 2023 19:33:44 +0000 Subject: [PATCH 41/62] fix spelling --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 27d051f..ac262b2 100644 --- a/dwl.c +++ b/dwl.c @@ -423,8 +423,8 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); - /* Some clients set them max size to INT_MAX, which does not violates - * the protocol but its innecesary, they can set them max size to zero. */ + /* Some clients set their max size to INT_MAX, which does not violate the + * protocol but its unnecesary, as they can set their max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ From c69a2bec3ff417fbc4ea8fec0a49096773e01e7d Mon Sep 17 00:00:00 2001 From: godalming123 Date: Sat, 18 Feb 2023 16:15:07 +0000 Subject: [PATCH 42/62] Fix spacing and replace it with tabs --- dwl.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dwl.c b/dwl.c index ac262b2..8043bf9 100644 --- a/dwl.c +++ b/dwl.c @@ -98,7 +98,7 @@ typedef struct Monitor Monitor; typedef struct { /* Must keep these three elements in this order */ unsigned int type; /* XDGShell or X11* */ - struct wlr_box geom; /* layout-relative, includes border */ + struct wlr_box geom; /* layout-relative, includes border */ Monitor *mon; struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ @@ -116,7 +116,7 @@ typedef struct { struct wl_listener destroy; struct wl_listener set_title; struct wl_listener fullscreen; - struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box prev; /* layout-relative, includes border */ #ifdef XWAYLAND struct wl_listener activate; struct wl_listener configure; @@ -181,8 +181,8 @@ struct Monitor { struct wl_listener destroy; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; - struct wlr_box m; /* monitor area, layout-relative */ - struct wlr_box w; /* window area, layout-relative */ + struct wlr_box m; /* monitor area, layout-relative */ + struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ const Layout *lt[2]; unsigned int seltags; @@ -423,8 +423,8 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); - /* Some clients set their max size to INT_MAX, which does not violate the - * protocol but its unnecesary, as they can set their max size to zero. */ + /* Some clients set their max size to INT_MAX, which does not violate the + * protocol but its unnecesary, as they can set their max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ @@ -1020,7 +1020,7 @@ void createpointer(struct wlr_pointer *pointer) { if (wlr_input_device_is_libinput(&pointer->base)) { - struct libinput_device *libinput_device = (struct libinput_device*) + struct libinput_device *libinput_device = (struct libinput_device*) wlr_libinput_get_device_handle(&pointer->base); if (libinput_device_config_tap_get_finger_count(libinput_device)) { @@ -1288,16 +1288,16 @@ focusstack(const Arg *arg) if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { if (&c->link == &clients) - continue; /* wrap past the sentinel node */ + continue; /* wrap past the sentinel node */ if (VISIBLEON(c, selmon)) - break; /* found it */ + break; /* found it */ } } else { wl_list_for_each_reverse(c, &sel->link, link) { if (&c->link == &clients) - continue; /* wrap past the sentinel node */ + continue; /* wrap past the sentinel node */ if (VISIBLEON(c, selmon)) - break; /* found it */ + break; /* found it */ } } /* If only one client is visible on selmon, then c == sel */ @@ -1729,7 +1729,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { /* * Called when a client such as wlr-randr requests a change in output - * configuration. This is only one way that the layout can be changed, + * configuration. This is only one way that the layout can be changed, * so any Monitor information should be updated by updatemons() after an * output_layout.change event, not here. */ @@ -1969,7 +1969,7 @@ run(char *startup_cmd) selmon = xytomon(cursor->x, cursor->y); /* TODO hack to get cursor to display in its initial location (100, 100) - * instead of (0, 0) and then jumping. still may not be fully + * instead of (0, 0) and then jumping. still may not be fully * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); @@ -2487,7 +2487,7 @@ updatemons(struct wl_listener *listener, void *data) { /* * Called whenever the output layout changes: adding or removing a - * monitor, changing an output's mode or position, etc. This is where + * monitor, changing an output's mode or position, etc. This is where * the change officially happens and we update geometry, window * positions, focus, and the stored configuration in wlroots' * output-manager implementation. @@ -2755,8 +2755,8 @@ sigchld(int unused) { siginfo_t in; /* We should be able to remove this function in favor of a simple - * struct sigaction sa = {.sa_handler = SIG_IGN}; - * sigaction(SIGCHLD, &sa, NULL); + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); * but the Xwayland implementation in wlroots currently prevents us from * setting our own disposition for SIGCHLD. */ @@ -2779,7 +2779,7 @@ xwaylandready(struct wl_listener *listener, void *data) return; } - /* Collect atoms we are interested in. If getatom returns 0, we will + /* Collect atoms we are interested in. If getatom returns 0, we will * not detect that window type. */ netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); From e4921fad28081f36fa0daa61b4bef7022a21b340 Mon Sep 17 00:00:00 2001 From: gan-of-culture <53971163+gan-of-culture@users.noreply.github.com> Date: Sat, 25 Feb 2023 22:59:23 +0100 Subject: [PATCH 43/62] add missing comma in "MonitorRule" add a missing comma for the example --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 419e6ef..a1a6795 100644 --- a/config.def.h +++ b/config.def.h @@ -31,7 +31,7 @@ static const Layout layouts[] = { static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL -1, -1 }, + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */ /* defaults */ { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, From 6722a8953243387545a6bab23514b84cffd6a3bf Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 28 Feb 2023 21:32:35 -0600 Subject: [PATCH 44/62] Missing apostrophe --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8043bf9..fbe4c24 100644 --- a/dwl.c +++ b/dwl.c @@ -424,7 +424,7 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); /* Some clients set their max size to INT_MAX, which does not violate the - * protocol but its unnecesary, as they can set their max size to zero. */ + * protocol but it's unnecesary, as they can set their max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ From 21930621eec5bc4acc3ae5c42cffd6a9422dc615 Mon Sep 17 00:00:00 2001 From: Palanix Date: Mon, 13 Mar 2023 12:00:46 +0100 Subject: [PATCH 45/62] Remove rootcolor --- config.def.h | 1 - 1 file changed, 1 deletion(-) diff --git a/config.def.h b/config.def.h index a1a6795..f98eab2 100644 --- a/config.def.h +++ b/config.def.h @@ -2,7 +2,6 @@ static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ From bbdf2a913b72e7a308ee0dfde6518a4285d4a775 Mon Sep 17 00:00:00 2001 From: Yves Zoundi Date: Tue, 21 Feb 2023 13:00:10 -0500 Subject: [PATCH 46/62] display clients count in monocle symbol - Replicate missing functionality from dwl to display the client count in monocle mode - Add ltsymbol field to Monitor struct - Display client count in monocle mode when greater than zero - Tested with somebar and dwlb --- dwl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index fbe4c24..1b59c21 100644 --- a/dwl.c +++ b/dwl.c @@ -190,6 +190,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + char ltsymbol[16]; }; typedef struct { @@ -482,6 +483,8 @@ arrange(Monitor *m) wlr_scene_node_set_enabled(&m->fullscreen_bg->node, (c = focustop(m)) && c->isfullscreen); + if (m) + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); @@ -970,6 +973,7 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); } void @@ -1592,12 +1596,16 @@ void monocle(Monitor *m) { Client *c; + int n = 0; wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) continue; resize(c, m->w, 0); + n++; } + if (n) + snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); if ((c = focustop(m))) wlr_scene_node_raise_to_top(&c->scene->node); } @@ -1851,7 +1859,7 @@ printstatus(void) printf("%s selmon %u\n", m->wlr_output->name, m == selmon); printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); - printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); + printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); } fflush(stdout); } @@ -2044,7 +2052,7 @@ setlayout(const Arg *arg) selmon->sellt ^= 1; if (arg && arg->v) selmon->lt[selmon->sellt] = (Layout *)arg->v; - /* TODO change layout symbol? */ + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); arrange(selmon); printstatus(); } From 9d68554c59a886b641d27a364884fb461af2d4f1 Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Thu, 23 Mar 2023 09:38:48 +1000 Subject: [PATCH 47/62] remove tag labels from dwl Tag labels are not used in dwl. Only the number of tags is important. Tag labels should be defined for each tag in whatever status bar is used. --- config.def.h | 4 ++-- dwl.c | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/config.def.h b/config.def.h index f98eab2..c6a4950 100644 --- a/config.def.h +++ b/config.def.h @@ -7,8 +7,8 @@ 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" }; +/* tagging - tagcount must be no greater than 31 */ +static const int tagcount = 9; static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ diff --git a/dwl.c b/dwl.c index 1b59c21..fbdf096 100644 --- a/dwl.c +++ b/dwl.c @@ -67,7 +67,7 @@ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TAGMASK ((1u << tagcount) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) @@ -411,9 +411,6 @@ static Atom netatom[NetLast]; /* attempt to encapsulate suck into one file */ #include "client.h" -/* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; - /* function implementations */ void applybounds(Client *c, struct wlr_box *bbox) From 20f61a59afeb4634dbdccfcbead95ec5852ef456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Apr 2023 11:29:18 -0600 Subject: [PATCH 48/62] use fixed-size type for client tags while the size of `int` in most compilers is 32-bits, the size of int and all other integer types are implementation defined, so make sure we can use up to 32-bits --- dwl.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index fbdf096..6c34e32 100644 --- a/dwl.c +++ b/dwl.c @@ -123,7 +123,7 @@ typedef struct { struct wl_listener set_hints; #endif unsigned int bw; - unsigned int tags; + uint32_t tags; int isfloating, isurgent, isfullscreen; uint32_t resize; /* configure serial of a pending resize */ } Client; @@ -187,7 +187,7 @@ struct Monitor { const Layout *lt[2]; unsigned int seltags; unsigned int sellt; - unsigned int tagset[2]; + uint32_t tagset[2]; double mfact; int nmaster; char ltsymbol[16]; @@ -206,7 +206,7 @@ typedef struct { typedef struct { const char *id; const char *title; - unsigned int tags; + uint32_t tags; int isfloating; int monitor; } Rule; @@ -293,7 +293,7 @@ static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); -static void setmon(Client *c, Monitor *m, unsigned int newtags); +static void setmon(Client *c, Monitor *m, uint32_t newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); @@ -444,7 +444,7 @@ applyrules(Client *c) { /* rule matching */ const char *appid, *title; - unsigned int i, newtags = 0; + uint32_t i, newtags = 0; const Rule *r; Monitor *mon = selmon, *m; @@ -1825,7 +1825,7 @@ printstatus(void) { Monitor *m = NULL; Client *c; - unsigned int occ, urg, sel; + uint32_t occ, urg, sel; const char *appid, *title; wl_list_for_each(m, &mons, link) { @@ -2070,7 +2070,7 @@ setmfact(const Arg *arg) } void -setmon(Client *c, Monitor *m, unsigned int newtags) +setmon(Client *c, Monitor *m, uint32_t newtags) { Monitor *oldmon = c->mon; @@ -2409,7 +2409,7 @@ togglefullscreen(const Arg *arg) void toggletag(const Arg *arg) { - unsigned int newtags; + uint32_t newtags; Client *sel = focustop(selmon); if (!sel) return; @@ -2425,7 +2425,7 @@ toggletag(const Arg *arg) void toggleview(const Arg *arg) { - unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; + uint32_t newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; From da77e34ee55ef4d2f92f632fea880610e8fc7fda Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Sun, 9 Apr 2023 14:48:55 +1000 Subject: [PATCH 49/62] Use uint32_t for ui Arg --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6c34e32..e59eae4 100644 --- a/dwl.c +++ b/dwl.c @@ -82,7 +82,7 @@ enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, typedef union { int i; - unsigned int ui; + uint32_t ui; float f; const void *v; } Arg; From 3c760bcd4ae640ec27229da8c75e9539bfd0d5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 12 Apr 2023 19:31:55 -0600 Subject: [PATCH 50/62] remove unneeded check of `m` in arrange() arrange must never be called with a NULL argument --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index e59eae4..3442dcb 100644 --- a/dwl.c +++ b/dwl.c @@ -480,9 +480,9 @@ arrange(Monitor *m) wlr_scene_node_set_enabled(&m->fullscreen_bg->node, (c = focustop(m)) && c->isfullscreen); - if (m) - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); - if (m && m->lt[m->sellt]->arrange) + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + + if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); checkidleinhibitor(NULL); From 797e0c74b2cbf4a49f83c9269abec06f3293d00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 12 Apr 2023 21:37:19 -0600 Subject: [PATCH 51/62] correctly check if a scene node is enabled checking only wlr_scene_node.enabled may result in a false positive because it does not consider if its ancestors are enabled as well. --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 3442dcb..b7436bb 100644 --- a/dwl.c +++ b/dwl.c @@ -631,13 +631,13 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { - int inhibited = 0; + int inhibited = 0, unused_lx, unused_ly; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); struct wlr_scene_tree *tree = surface->data; if (exclude != surface && (bypass_surface_visibility || (!tree - || tree->node.enabled))) { + || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { inhibited = 1; break; } @@ -1201,7 +1201,7 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - int i; + int i, unused_lx, unused_ly; if (locked) return; @@ -1236,7 +1236,7 @@ focusclient(Client *c, int lift) Client *w = NULL; LayerSurface *l = NULL; int type = toplevel_from_wlr_surface(old, &w, &l); - if (type == LayerShell && l->scene->node.enabled + if (type == LayerShell && wlr_scene_node_coords(&l->scene->node, &unused_lx, &unused_ly) && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { return; } else if (w && w == exclusive_focus && client_wants_focus(w)) { From 0729f18dce85cb79b8aaac325a43dba0c5e96ab3 Mon Sep 17 00:00:00 2001 From: Micah Gorrell Date: Wed, 24 May 2023 10:20:30 -0600 Subject: [PATCH 52/62] Prevent using a wlr_layer_surface after destroying it, due to no available outputs --- dwl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index b7436bb..1ad3d05 100644 --- a/dwl.c +++ b/dwl.c @@ -836,8 +836,10 @@ createlayersurface(struct wl_listener *listener, void *data) if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; - if (!wlr_layer_surface->output) + if (!wlr_layer_surface->output) { wlr_layer_surface_v1_destroy(wlr_layer_surface); + return; + } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; From 72adab621f27f9daed87ea1b0068679e39fb3f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Apr 2023 14:44:34 -0600 Subject: [PATCH 53/62] destroy old client popups when focusing another client Closes: https://github.com/djpohly/dwl/issues/408 --- dwl.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index 1ad3d05..aec7427 100644 --- a/dwl.c +++ b/dwl.c @@ -1203,7 +1203,9 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - int i, unused_lx, unused_ly; + int i, unused_lx, unused_ly, old_client_type; + Client *old_c = NULL; + LayerSurface *old_l = NULL; if (locked) return; @@ -1215,6 +1217,12 @@ focusclient(Client *c, int lift) if (c && client_surface(c) == old) return; + if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) { + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) + wlr_xdg_popup_destroy(popup); + } + /* Put the new client atop the focus stack and select its monitor */ if (c && !client_is_unmanaged(c)) { wl_list_remove(&c->flink); @@ -1235,19 +1243,17 @@ focusclient(Client *c, int lift) /* If an overlay is focused, don't focus or activate the client, * but only update its position in fstack to render its border with focuscolor * and focus it after the overlay is closed. */ - Client *w = NULL; - LayerSurface *l = NULL; - int type = toplevel_from_wlr_surface(old, &w, &l); - if (type == LayerShell && wlr_scene_node_coords(&l->scene->node, &unused_lx, &unused_ly) - && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + if (old_client_type == LayerShell && wlr_scene_node_coords( + &old_l->scene->node, &unused_lx, &unused_ly) + && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { return; - } else if (w && w == exclusive_focus && client_wants_focus(w)) { + } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { return; /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg * and probably other clients */ - } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { + } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(w->border[i], bordercolor); + wlr_scene_rect_set_color(old_c->border[i], bordercolor); client_activate_surface(old, 0); } From a5e45924edeaeb9b763cdc75fd4ec413b2ec2ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 28 May 2023 00:20:20 -0600 Subject: [PATCH 54/62] remove note about contact me for patch issues I am no longer able to spend much time developing dwl let alone maintaining other's patches :) --- .github/ISSUE_TEMPLATE/bug_report.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6b60803..cd9bd8d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,9 +14,4 @@ wlroots version: From f8884ffc2b7a4c0401f0a6710b679cd18b6b097d Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Sun, 28 May 2023 19:09:38 +0200 Subject: [PATCH 55/62] Set XCURSOR_SIZE --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index aec7427..cd27c7c 100644 --- a/dwl.c +++ b/dwl.c @@ -2260,6 +2260,7 @@ setup(void) * images are available at all scale factors on the screen (necessary for * HiDPI support). Scaled cursors will be loaded with each output. */ cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + setenv("XCURSOR_SIZE", "24", 1); /* * wlr_cursor *only* displays an image on screen. It does not move around From 3d98907b98e2ff978cc30614b739f1f4b8f7f8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 25 May 2023 22:19:29 -0600 Subject: [PATCH 56/62] send frame done even if output commit fails Bug: https://github.com/djpohly/dwl/issues/420 Fixes: https://github.com/djpohly/dwl/issues/353 --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index cd27c7c..02c761c 100644 --- a/dwl.c +++ b/dwl.c @@ -1895,8 +1895,8 @@ rendermon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; - if (!wlr_scene_output_commit(m->scene_output)) - return; + wlr_scene_output_commit(m->scene_output); + skip: /* Let clients know a frame has been rendered */ clock_gettime(CLOCK_MONOTONIC, &now); From 9b9b79b35ebaed7a5897f748c51b2d5c4ec1ddfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 25 May 2023 22:20:12 -0600 Subject: [PATCH 57/62] activate lock surface in updatemons Fixes an issue when swaylock does not receive input after turn off and then turn on the outputs --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 02c761c..918852e 100644 --- a/dwl.c +++ b/dwl.c @@ -2572,9 +2572,12 @@ updatemons(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (!c->mon && client_is_mapped(c)) setmon(c, selmon, c->tags); - if (selmon->lock_surface) + focusclient(focustop(selmon), 1); + if (selmon->lock_surface) { client_notify_enter(selmon->lock_surface->surface, wlr_seat_get_keyboard(seat)); + client_activate_surface(selmon->lock_surface->surface, 1); + } } wlr_output_manager_v1_set_configuration(output_mgr, config); From 5215712cabce273f76a5381de244c58a7d1f54f9 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Wed, 7 Jun 2023 16:24:28 -0500 Subject: [PATCH 58/62] Stray whitespace fixes --- config.def.h | 6 +++--- dwl.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config.def.h b/config.def.h index c6a4950..447ba00 100644 --- a/config.def.h +++ b/config.def.h @@ -65,9 +65,9 @@ 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 +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; diff --git a/dwl.c b/dwl.c index 918852e..d741cbd 100644 --- a/dwl.c +++ b/dwl.c @@ -1047,7 +1047,7 @@ createpointer(struct wlr_pointer *pointer) 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); From df11b7a7864b416bba52e00d6ad7997d9a7c19b0 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Jun 2023 15:42:54 -0500 Subject: [PATCH 59/62] fix startup_cmd SIGCHLD handler Ignored handlers are not reset by exec() calls --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index d741cbd..19adafe 100644 --- a/dwl.c +++ b/dwl.c @@ -1963,6 +1963,8 @@ run(char *startup_cmd) if ((child_pid = fork()) < 0) die("startup: fork:"); if (child_pid == 0) { + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); From 9c592da01f7648ff1efb69e851ced554b3231096 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Jun 2023 23:57:16 -0500 Subject: [PATCH 60/62] Reset ignored signal handler in spawn() as well --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 19adafe..9402935 100644 --- a/dwl.c +++ b/dwl.c @@ -2327,6 +2327,9 @@ void spawn(const Arg *arg) { if (fork() == 0) { + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_DFL}; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, NULL); dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); From 68a17f962e05895603d0f409fb8da4493cbe52aa Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 16 Jun 2023 00:22:11 -0500 Subject: [PATCH 61/62] Don't bother with ignoring SIGCHLD It added complexity, especially with the differences in behavior between handled and ignored signals across an exec(). --- dwl.c | 73 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/dwl.c b/dwl.c index 9402935..da3a516 100644 --- a/dwl.c +++ b/dwl.c @@ -297,6 +297,7 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); +static void sigchld(int unused); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); @@ -397,7 +398,6 @@ static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); -static void sigchld(int unused); static void xwaylandready(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; @@ -1963,8 +1963,6 @@ run(char *startup_cmd) if ((child_pid = fork()) < 0) die("startup: fork:"); if (child_pid == 0) { - sa.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &sa, NULL); dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); @@ -2129,27 +2127,19 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { - struct sigaction sa_term = {.sa_flags = SA_RESTART, .sa_handler = quitsignal}; - struct sigaction sa_sigchld = { -#ifdef XWAYLAND - .sa_flags = SA_RESTART, - .sa_handler = sigchld, -#else - .sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART, - .sa_handler = SIG_IGN, -#endif - }; - sigemptyset(&sa_term.sa_mask); - sigemptyset(&sa_sigchld.sa_mask); + /* Set up signal handlers */ + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = sigchld}; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, NULL); + + sa.sa_handler = quitsignal; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + /* 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(); - /* Set up signal handlers */ - sigaction(SIGCHLD, &sa_sigchld, NULL); - sigaction(SIGINT, &sa_term, NULL); - sigaction(SIGTERM, &sa_term, NULL); - /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable * backend based on the current environment, such as opening an X11 window @@ -2323,13 +2313,32 @@ setup(void) #endif } +void +sigchld(int unused) +{ +#ifdef XWAYLAND + siginfo_t in; + /* We should be able to remove this function in favor of a simple + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + /* WNOWAIT leaves the child in a waitable state, in case this is the + * XWayland process + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); +#else + while (waitpid(-1, NULL, WNOHANG) > 0); +#endif +} + void spawn(const Arg *arg) { if (fork() == 0) { - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_DFL}; - sigemptyset(&sa.sa_mask); - sigaction(SIGCHLD, &sa, NULL); dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); @@ -2772,24 +2781,6 @@ sethints(struct wl_listener *listener, void *data) } } -void -sigchld(int unused) -{ - siginfo_t in; - /* We should be able to remove this function in favor of a simple - * struct sigaction sa = {.sa_handler = SIG_IGN}; - * sigaction(SIGCHLD, &sa, NULL); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - /* WNOWAIT leaves the child in a waitable state, in case this is the - * XWayland process - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -} - void xwaylandready(struct wl_listener *listener, void *data) { From a41d81797944346868ce362c5bbf938ebddd339e Mon Sep 17 00:00:00 2001 From: Abanoub Date: Wed, 21 Jun 2023 18:11:09 +0300 Subject: [PATCH 62/62] Use focustop(selmon) instead of selclient() in the push patch --- Makefile | 2 +- dwl.c | 2 ++ push.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ push.h | 4 ++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 push.c create mode 100644 push.h diff --git a/Makefile b/Makefile index ccca079..078ced5 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ -dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +dwl.o: dwl.c push.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland diff --git a/dwl.c b/dwl.c index da3a516..df8f32d 100644 --- a/dwl.c +++ b/dwl.c @@ -406,7 +406,9 @@ static Atom netatom[NetLast]; #endif /* configuration, allows nested code to access above variables */ +#include "push.h" #include "config.h" +#include "push.c" /* attempt to encapsulate suck into one file */ #include "client.h" diff --git a/push.c b/push.c new file mode 100644 index 0000000..323c317 --- /dev/null +++ b/push.c @@ -0,0 +1,63 @@ +static Client * +nexttiled(Client *sel) { + Client *c; + wl_list_for_each(c, &sel->link, link) { + if (&c->link == &clients) + break; /* don't wrap */ + if (!c->isfloating && VISIBLEON(c, selmon)) + return c; + } + return NULL; +} + +static Client * +prevtiled(Client *sel) { + Client *c; + wl_list_for_each_reverse(c, &sel->link, link) { + if (&c->link == &clients) + break; /* don't wrap */ + if (!c->isfloating && VISIBLEON(c, selmon)) + return c; + } + return NULL; +} + +static void +pushup(const Arg *arg) { + Client *sel = focustop(selmon); + Client *c; + + if(!sel || sel->isfloating) + return; + if((c = prevtiled(sel))) { + /* attach before c */ + wl_list_remove(&sel->link); + wl_list_insert(c->link.prev, &sel->link); + } else { + /* move to the end */ + wl_list_remove(&sel->link); + wl_list_insert(clients.prev, &sel->link); + } + focusclient(sel, 1); + arrange(selmon); +} + +static void +pushdown(const Arg *arg) { + Client *sel = focustop(selmon); + Client *c; + + if(!sel || sel->isfloating) + return; + if((c = nexttiled(sel))) { + /* attach after c */ + wl_list_remove(&sel->link); + wl_list_insert(&c->link, &sel->link); + } else { + /* move to the front */ + wl_list_remove(&sel->link); + wl_list_insert(&clients, &sel->link); + } + focusclient(sel, 1); + arrange(selmon); +} diff --git a/push.h b/push.h new file mode 100644 index 0000000..59c0f80 --- /dev/null +++ b/push.h @@ -0,0 +1,4 @@ +static Client *nexttiled(Client *sel); +static Client *prevtiled(Client *sel); +static void pushdown(const Arg *arg); +static void pushup(const Arg *arg);