From 16ae2a3a875ab5e5f807c05d4dfce35b494837d2 Mon Sep 17 00:00:00 2001 From: Dhruva Sambrani <44899822+DhruvaSambrani@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:45:31 +0100 Subject: [PATCH 01/18] fix extrabar not updating status --- patches/extrabar/extrabar.patch | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/patches/extrabar/extrabar.patch b/patches/extrabar/extrabar.patch index 3bdd448..e4a0aae 100644 --- a/patches/extrabar/extrabar.patch +++ b/patches/extrabar/extrabar.patch @@ -1,5 +1,5 @@ diff --git a/dwl.c b/dwl.c -index 7fe9468..4e3272e 100644 +index 7fe9468..2614a25 100644 --- a/dwl.c +++ b/dwl.c @@ -205,6 +205,7 @@ struct Monitor { @@ -95,7 +95,7 @@ index 7fe9468..4e3272e 100644 return; /* draw status first so it can be overdrawn by tags later */ -@@ -1633,13 +1644,52 @@ drawbar(Monitor *m) +@@ -1633,13 +1644,47 @@ drawbar(Monitor *m) wlr_buffer_unlock(&buf->base); } @@ -113,11 +113,6 @@ index 7fe9468..4e3272e 100644 + if (!(buf = bufmon(m, m->extra_pool))) + return; + -+ buf->busy = true; -+ LISTEN(&buf->base.events.release, &buf->release, bufrelease); -+ wlr_buffer_lock(&buf->base); -+ drwl_setimage(m->drw, buf->image); -+ + drwl_setscheme(m->drw, colors[SchemeNorm]); + drwl_rect(m->drw, 0, 0, m->b.width, m->b.height, 1, 1); + @@ -149,7 +144,7 @@ index 7fe9468..4e3272e 100644 } void -@@ -2896,7 +2946,7 @@ startdrag(struct wl_listener *listener, void *data) +@@ -2896,7 +2941,7 @@ startdrag(struct wl_listener *listener, void *data) int statusin(int fd, unsigned int mask, void *data) { @@ -158,7 +153,7 @@ index 7fe9468..4e3272e 100644 ssize_t n; if (mask & WL_EVENT_ERROR) -@@ -2911,7 +2961,18 @@ statusin(int fd, unsigned int mask, void *data) +@@ -2911,7 +2956,18 @@ statusin(int fd, unsigned int mask, void *data) status[n] = '\0'; status[strcspn(status, "\n")] = '\0'; @@ -178,7 +173,7 @@ index 7fe9468..4e3272e 100644 drawbars(); return 0; -@@ -3206,6 +3267,12 @@ updatebar(Monitor *m) +@@ -3206,6 +3262,12 @@ updatebar(Monitor *m) m->pool[i] = NULL; } From 47746314360c82048a791bafd9b0e4afaf2578a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= Date: Sat, 14 Mar 2026 17:44:04 -0300 Subject: [PATCH 02/18] update controlled_fullscreen to dwl 0.8 --- patches/controlled_fullscreen/README.md | 5 +- .../controlled_fullscreen.patch | 30 ++-- .../controlled_fullscreen_2025_11_13.patch | 132 ++++++++++++++++++ 3 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 patches/controlled_fullscreen/controlled_fullscreen_2025_11_13.patch diff --git a/patches/controlled_fullscreen/README.md b/patches/controlled_fullscreen/README.md index e708a00..bb712ea 100644 --- a/patches/controlled_fullscreen/README.md +++ b/patches/controlled_fullscreen/README.md @@ -2,8 +2,9 @@ This patch allows a window to adjust its layout as if it was fullscreen, but it won't change its size and position, and it will stays under the control of dwl. For example a video on a browser can occupy the whole space reserved to the window, but we can still resize it and move it and see the status bar. ### Download -- [git branch](https://codeberg.org/Kana/dwl/src/branch/controlled_fullscreen) -- [main 2025-11-13](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen.patch) +- [dwl 0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen.patch) +- [2025-11-13](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen_2025_11_13.patch) + - [2025-10-08](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/controlled_fullscreen/controlled_fullscreen_2025_10_08.patch) ### Authors diff --git a/patches/controlled_fullscreen/controlled_fullscreen.patch b/patches/controlled_fullscreen/controlled_fullscreen.patch index b3f8325..321f7ec 100644 --- a/patches/controlled_fullscreen/controlled_fullscreen.patch +++ b/patches/controlled_fullscreen/controlled_fullscreen.patch @@ -1,17 +1,17 @@ -From e0cecc228d436425c0d921a1eec5e0370d24613d Mon Sep 17 00:00:00 2001 +From 234dc2774b23d21c647c6967b1dd38e61165fabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= -Date: Thu, 13 Nov 2025 09:09:22 -0300 -Subject: [PATCH] controlled fullscreen fix +Date: Sat, 14 Mar 2026 17:20:21 -0300 +Subject: [PATCH] update to dwl 0.8 --- dwl.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/dwl.c b/dwl.c -index 12f441e..4f124eb 100644 +index 101a45f..0ec8db6 100644 --- a/dwl.c +++ b/dwl.c -@@ -518,9 +518,6 @@ arrange(Monitor *m) +@@ -519,9 +519,6 @@ arrange(Monitor *m) } } @@ -21,7 +21,7 @@ index 12f441e..4f124eb 100644 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); /* We move all clients (except fullscreen and unmanaged) to LyrTile while -@@ -878,7 +875,7 @@ commitnotify(struct wl_listener *listener, void *data) +@@ -879,7 +876,7 @@ commitnotify(struct wl_listener *listener, void *data) return; } @@ -30,7 +30,7 @@ index 12f441e..4f124eb 100644 /* mark a pending resize as completed */ if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) -@@ -1490,7 +1487,7 @@ focusstack(const Arg *arg) +@@ -1491,7 +1488,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = focustop(selmon); @@ -39,7 +39,7 @@ index 12f441e..4f124eb 100644 return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { -@@ -1826,7 +1823,7 @@ monocle(Monitor *m) +@@ -1828,7 +1825,7 @@ monocle(Monitor *m) int n = 0; wl_list_for_each(c, &clients, link) { @@ -48,7 +48,7 @@ index 12f441e..4f124eb 100644 continue; resize(c, m->w, 0); n++; -@@ -1957,7 +1954,7 @@ moveresize(const Arg *arg) +@@ -1959,7 +1956,7 @@ moveresize(const Arg *arg) if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); @@ -57,7 +57,7 @@ index 12f441e..4f124eb 100644 return; /* Float the window and tell motionnotify to grab it */ -@@ -2332,14 +2329,12 @@ setcursorshape(struct wl_listener *listener, void *data) +@@ -2334,14 +2331,12 @@ setcursorshape(struct wl_listener *listener, void *data) void setfloating(Client *c, int floating) { @@ -74,7 +74,7 @@ index 12f441e..4f124eb 100644 arrange(c->mon); printstatus(); } -@@ -2352,12 +2347,12 @@ setfullscreen(Client *c, int fullscreen) +@@ -2354,12 +2349,12 @@ setfullscreen(Client *c, int fullscreen) return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); @@ -90,7 +90,7 @@ index 12f441e..4f124eb 100644 } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ -@@ -2716,7 +2711,7 @@ tile(Monitor *m) +@@ -2719,7 +2714,7 @@ tile(Monitor *m) Client *c; wl_list_for_each(c, &clients, link) @@ -99,7 +99,7 @@ index 12f441e..4f124eb 100644 n++; if (n == 0) return; -@@ -2727,7 +2722,7 @@ tile(Monitor *m) +@@ -2730,7 +2725,7 @@ tile(Monitor *m) mw = m->w.width; i = my = ty = 0; wl_list_for_each(c, &clients, link) { @@ -108,7 +108,7 @@ index 12f441e..4f124eb 100644 continue; if (i < m->nmaster) { resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw, -@@ -2747,7 +2742,7 @@ togglefloating(const Arg *arg) +@@ -2750,7 +2745,7 @@ togglefloating(const Arg *arg) { Client *sel = focustop(selmon); /* return if fullscreen */ @@ -117,7 +117,7 @@ index 12f441e..4f124eb 100644 setfloating(sel, !sel->isfloating); } -@@ -2902,9 +2897,6 @@ updatemons(struct wl_listener *listener, void *data) +@@ -2905,9 +2900,6 @@ updatemons(struct wl_listener *listener, void *data) arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ arrange(m); diff --git a/patches/controlled_fullscreen/controlled_fullscreen_2025_11_13.patch b/patches/controlled_fullscreen/controlled_fullscreen_2025_11_13.patch new file mode 100644 index 0000000..b3f8325 --- /dev/null +++ b/patches/controlled_fullscreen/controlled_fullscreen_2025_11_13.patch @@ -0,0 +1,132 @@ +From e0cecc228d436425c0d921a1eec5e0370d24613d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= +Date: Thu, 13 Nov 2025 09:09:22 -0300 +Subject: [PATCH] controlled fullscreen fix + +--- + dwl.c | 32 ++++++++++++-------------------- + 1 file changed, 12 insertions(+), 20 deletions(-) + +diff --git a/dwl.c b/dwl.c +index 12f441e..4f124eb 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -518,9 +518,6 @@ arrange(Monitor *m) + } + } + +- wlr_scene_node_set_enabled(&m->fullscreen_bg->node, +- (c = focustop(m)) && c->isfullscreen); +- + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + + /* We move all clients (except fullscreen and unmanaged) to LyrTile while +@@ -878,7 +875,7 @@ commitnotify(struct wl_listener *listener, void *data) + return; + } + +- resize(c, c->geom, (c->isfloating && !c->isfullscreen)); ++ resize(c, c->geom, (c->isfloating)); + + /* mark a pending resize as completed */ + if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) +@@ -1490,7 +1487,7 @@ focusstack(const Arg *arg) + { + /* Focus the next or previous client (in tiling order) on selmon */ + Client *c, *sel = focustop(selmon); +- if (!sel || (sel->isfullscreen && !client_has_children(sel))) ++ if (!sel) + return; + if (arg->i > 0) { + wl_list_for_each(c, &sel->link, link) { +@@ -1826,7 +1823,7 @@ monocle(Monitor *m) + int n = 0; + + wl_list_for_each(c, &clients, link) { +- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ if (!VISIBLEON(c, m) || c->isfloating) + continue; + resize(c, m->w, 0); + n++; +@@ -1957,7 +1954,7 @@ moveresize(const Arg *arg) + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); +- if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) ++ if (!grabc || client_is_unmanaged(grabc)) + return; + + /* Float the window and tell motionnotify to grab it */ +@@ -2332,14 +2329,12 @@ setcursorshape(struct wl_listener *listener, void *data) + void + setfloating(Client *c, int floating) + { +- Client *p = client_get_parent(c); + c->isfloating = floating; + /* If in floating layout do not change the client's layer */ + if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) + return; +- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || +- (p && p->isfullscreen) ? LyrFS +- : c->isfloating ? LyrFloat : LyrTile]); ++ wlr_scene_node_reparent(&c->scene->node, ++ layers[c->isfloating ? LyrFloat : LyrTile]); + arrange(c->mon); + printstatus(); + } +@@ -2352,12 +2347,12 @@ setfullscreen(Client *c, int fullscreen) + return; + c->bw = fullscreen ? 0 : borderpx; + client_set_fullscreen(c, fullscreen); +- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen +- ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); + ++ wlr_scene_node_reparent(&c->scene->node, ++ layers[c->isfloating ? LyrFloat : LyrTile]); + if (fullscreen) { + c->prev = c->geom; +- resize(c, c->mon->m, 0); ++ resize(c, c->mon->w, 0); + } else { + /* restore previous size instead of arrange for floating windows since + * client positions are set by the user and cannot be recalculated */ +@@ -2716,7 +2711,7 @@ tile(Monitor *m) + Client *c; + + wl_list_for_each(c, &clients, link) +- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) ++ if (VISIBLEON(c, m) && !c->isfloating) + n++; + if (n == 0) + return; +@@ -2727,7 +2722,7 @@ tile(Monitor *m) + mw = m->w.width; + i = my = ty = 0; + wl_list_for_each(c, &clients, link) { +- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ if (!VISIBLEON(c, m) || c->isfloating) + continue; + if (i < m->nmaster) { + resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw, +@@ -2747,7 +2742,7 @@ togglefloating(const Arg *arg) + { + Client *sel = focustop(selmon); + /* return if fullscreen */ +- if (sel && !sel->isfullscreen) ++ if (sel) + setfloating(sel, !sel->isfloating); + } + +@@ -2902,9 +2897,6 @@ updatemons(struct wl_listener *listener, void *data) + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); +- /* make sure fullscreen clients have the right size */ +- if ((c = focustop(m)) && c->isfullscreen) +- resize(c, m->m, 0); + + /* Try to re-set the gamma LUT when updating monitors, + * it's only really needed when enabling a disabled output, but meh. */ +-- +2.51.0 + From 1b490e51a9874199d936d09bd9246a576305cf44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= Date: Sat, 14 Mar 2026 17:56:12 -0300 Subject: [PATCH 03/18] update focusonurgent patch to dwl 0.8 --- patches/focusonurgent/README.md | 3 +-- patches/focusonurgent/focusonurgent.patch | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/patches/focusonurgent/README.md b/patches/focusonurgent/README.md index 2bef3e4..82927fb 100644 --- a/patches/focusonurgent/README.md +++ b/patches/focusonurgent/README.md @@ -7,8 +7,7 @@ This is the approximately the equivalent of the focusonactive patch of dwm. If you want a more controlled behavior, for example setting which clients can focus, check [activation-rule patch](https://codeberg.org/sevz/dwl-patches/src/branch/activation-rules). ### Download -- [git branch](https://codeberg.org/Kana/dwl/src/branch/focusonurgent) -- [main 2025-10-08](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/focusonurgent/focusonurgent.patch) +- [main dwl 0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/focusonurgent/focusonurgent.patch) ### Authors - [André Desgualdo Pereira](https://codeberg.org/Kana) diff --git a/patches/focusonurgent/focusonurgent.patch b/patches/focusonurgent/focusonurgent.patch index 988090c..c28b652 100644 --- a/patches/focusonurgent/focusonurgent.patch +++ b/patches/focusonurgent/focusonurgent.patch @@ -1,17 +1,17 @@ -From 3613d9a6342fc85279a79ba203f25ff39fc0d8e4 Mon Sep 17 00:00:00 2001 +From 7cdba8df596d59a3ad2883521a65962dcd4fe644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= -Date: Wed, 29 Oct 2025 09:06:00 -0300 -Subject: [PATCH] add focusonurgent patch +Date: Sat, 14 Mar 2026 17:52:25 -0300 +Subject: [PATCH] update --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c -index 12f441e..5620f66 100644 +index 101a45f..6cd2f82 100644 --- a/dwl.c +++ b/dwl.c -@@ -2097,8 +2097,10 @@ printstatus(void) +@@ -2099,8 +2099,10 @@ printstatus(void) if (c->mon != m) continue; occ |= c->tags; From 3ade6519ac69ddb104cb2c926af0f964ab44bbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= Date: Sat, 14 Mar 2026 18:00:23 -0300 Subject: [PATCH 04/18] moved gridall to stale --- {patches => stale-patches}/gridall/README.md | 0 {patches => stale-patches}/gridall/gridall.diff | 0 .../gridall/winview+gaplessgrid+gridall.diff | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {patches => stale-patches}/gridall/README.md (100%) rename {patches => stale-patches}/gridall/gridall.diff (100%) rename {patches => stale-patches}/gridall/winview+gaplessgrid+gridall.diff (100%) diff --git a/patches/gridall/README.md b/stale-patches/gridall/README.md similarity index 100% rename from patches/gridall/README.md rename to stale-patches/gridall/README.md diff --git a/patches/gridall/gridall.diff b/stale-patches/gridall/gridall.diff similarity index 100% rename from patches/gridall/gridall.diff rename to stale-patches/gridall/gridall.diff diff --git a/patches/gridall/winview+gaplessgrid+gridall.diff b/stale-patches/gridall/winview+gaplessgrid+gridall.diff similarity index 100% rename from patches/gridall/winview+gaplessgrid+gridall.diff rename to stale-patches/gridall/winview+gaplessgrid+gridall.diff From 722f0573eb4186dd936ae09f74c2ca1fcc0480f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= Date: Sat, 14 Mar 2026 18:38:42 -0300 Subject: [PATCH 05/18] update winview to dwl 0.8 --- patches/winview/README.md | 3 +- .../{winview.patch => winview_dwl_07.patch} | 0 patches/winview/winview_dwl_08.patch | 55 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) rename patches/winview/{winview.patch => winview_dwl_07.patch} (100%) create mode 100644 patches/winview/winview_dwl_08.patch diff --git a/patches/winview/README.md b/patches/winview/README.md index 1ab4387..0a3471c 100644 --- a/patches/winview/README.md +++ b/patches/winview/README.md @@ -26,7 +26,8 @@ This patch is inspired from . Citing > An example of how to insert this line can be found in the default config file template, config.def.h. ### Download -- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/winview/winview.patch) +- [2026-03-14 dwl 0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/winview/winview_dwl_08.patch) +- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/winview/winview_dwl_07.patch) - [2024-06-06](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/winview/winview-20240606.patch) - [git branch](https://codeberg.org/dhruva_sambrani/dwl/src/branch/winview) diff --git a/patches/winview/winview.patch b/patches/winview/winview_dwl_07.patch similarity index 100% rename from patches/winview/winview.patch rename to patches/winview/winview_dwl_07.patch diff --git a/patches/winview/winview_dwl_08.patch b/patches/winview/winview_dwl_08.patch new file mode 100644 index 0000000..a2b77e1 --- /dev/null +++ b/patches/winview/winview_dwl_08.patch @@ -0,0 +1,55 @@ +From d53f64b3baee1e14c59b9b6cead024b91e185bd7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= +Date: Sat, 14 Mar 2026 18:34:36 -0300 +Subject: [PATCH] update to dwl 0.8 + +--- + config.def.h | 1 + + dwl.c | 12 ++++++++++++ + 2 files changed, 13 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..3c1f16b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -139,6 +139,7 @@ static const Key keys[] = { + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, ++ { MODKEY, XKB_KEY_o, winview, {0}}, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, + { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} }, +diff --git a/dwl.c b/dwl.c +index 101a45f..f3b75e0 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -348,6 +348,7 @@ static void urgent(struct wl_listener *listener, void *data); + static void view(const Arg *arg); + static void virtualkeyboard(struct wl_listener *listener, void *data); + static void virtualpointer(struct wl_listener *listener, void *data); ++static void winview(const Arg *a); + static Monitor *xytomon(double x, double y); + static void xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); +@@ -3006,6 +3007,17 @@ virtualpointer(struct wl_listener *listener, void *data) + wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); + } + ++void ++winview(const Arg *a) { ++ Arg b = {0}; ++ Client *sel = focustop(selmon); ++ if(!sel) ++ return; ++ b.ui = sel -> tags; ++ view(&b); ++ return; ++} ++ + Monitor * + xytomon(double x, double y) + { +-- +2.51.0 + From 000aa7d15c9dbb34a251c767d24c847963b729e4 Mon Sep 17 00:00:00 2001 From: nate zhou Date: Sun, 8 Mar 2026 11:31:44 +0800 Subject: [PATCH 06/18] genericgaps: update for 0.8 --- patches/genericgaps/README.md | 5 +- patches/genericgaps/genericgaps.patch | 292 ++++++++++++++------------ 2 files changed, 161 insertions(+), 136 deletions(-) diff --git a/patches/genericgaps/README.md b/patches/genericgaps/README.md index f27897d..c1d0ee3 100644 --- a/patches/genericgaps/README.md +++ b/patches/genericgaps/README.md @@ -15,10 +15,11 @@ gaps to be as big or bigger than "inner" gaps anyway. ### Download -- [0.7 2025-02-11](/dwl/dwl-patches/raw/branch/main/patches/genericgaps/genericgaps-0.7.patch): +- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/genericgaps/genericgaps.patch) +- [0.7 2025-02-11](https://codeberg.org/dwl/dwl-patches/raw/commit/58e371fcb31bde1e55f99498a77afd9b567a30c8/patches/genericgaps/genericgaps-0.7.patch): added support for `smartgaps` and `monoclegaps` settings and removed the suck from `arrange()` function -- [0.7](/dwl/dwl-patches/raw/branch/main/patches/genericgaps/genericgaps.patch) +- [0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/f8d1cfad116c19c01593f7436468ec0cb7a3297b/patches/genericgaps/genericgaps.patch) ### Authors diff --git a/patches/genericgaps/genericgaps.patch b/patches/genericgaps/genericgaps.patch index aa62b92..5990890 100644 --- a/patches/genericgaps/genericgaps.patch +++ b/patches/genericgaps/genericgaps.patch @@ -1,23 +1,25 @@ -From f2a1b84369266d252fbea57c6f1eb64253617452 Mon Sep 17 00:00:00 2001 -From: Nikita Ivanov -Date: Thu, 12 Dec 2024 22:44:53 +0100 -Subject: [PATCH] Add genericgaps +From ac0b983fef16eb904b77d6b5e98bd61f5cf719f5 Mon Sep 17 00:00:00 2001 +From: nate zhou +Date: Sat, 28 Feb 2026 23:28:08 +0800 +Subject: [PATCH] Patch: genericgaps-0.8.patch --- - config.def.h | 22 +++++++ - dwl.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 190 insertions(+), 3 deletions(-) + config.def.h | 23 ++++++ + dwl.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 220 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h -index 22d2171..930af12 100644 +index 8a6eda0..4adc866 100644 --- a/config.def.h +++ b/config.def.h -@@ -7,6 +7,12 @@ +@@ -6,7 +6,14 @@ + /* appearance */ 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 int enablegaps = 1; /* 1 means gaps are enabled */ +static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ +static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ + static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int gappih = 10; /* horiz inner gap between windows */ +static const unsigned int gappiv = 10; /* vert inner gap between windows */ +static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ @@ -25,45 +27,38 @@ index 22d2171..930af12 100644 static const float rootcolor[] = COLOR(0x222222ff); static const float bordercolor[] = COLOR(0x444444ff); static const float focuscolor[] = COLOR(0x005577ff); -@@ -133,6 +139,22 @@ static const Key keys[] = { - { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, - { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, - { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, -+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} }, -+ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, -+ { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, -+ { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, -+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, -+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } }, -+ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } }, -+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, -+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, - { MODKEY, XKB_KEY_Return, zoom, {0} }, - { MODKEY, XKB_KEY_Tab, view, {0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, +@@ -129,6 +136,22 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, ++ { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, ++ { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} }, diff --git a/dwl.c b/dwl.c -index def2562..c14ae43 100644 +index 44f3ad9..a3164cb 100644 --- a/dwl.c +++ b/dwl.c -@@ -107,6 +107,7 @@ typedef struct Monitor Monitor; - typedef struct { - /* Must keep these three elements in this order */ - unsigned int type; /* XDGShell or X11* */ -+ int interact; - struct wlr_box geom; /* layout-relative, includes border */ - Monitor *mon; - struct wlr_scene_tree *scene; -@@ -200,6 +201,10 @@ struct Monitor { +@@ -197,6 +197,11 @@ struct Monitor { struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface.link */ const Layout *lt[2]; ++ int enablegaps; /* enable gaps, used by togglegaps */ + int gappih; /* horizontal gap between windows */ + int gappiv; /* vertical gap between windows */ + int gappoh; /* horizontal outer gaps */ @@ -71,7 +66,15 @@ index def2562..c14ae43 100644 unsigned int seltags; unsigned int sellt; uint32_t tagset[2]; -@@ -273,6 +278,7 @@ static void createpopup(struct wl_listener *listener, void *data); +@@ -243,6 +248,7 @@ typedef struct { + static void applybounds(Client *c, struct wlr_box *bbox); + static void applyrules(Client *c); + static void arrange(Monitor *m); ++void arrangegaps(Monitor *m); + static void arrangelayer(Monitor *m, struct wl_list *list, + struct wlr_box *usable_area, int exclusive); + static void arrangelayers(Monitor *m); +@@ -271,6 +277,7 @@ static void createpopup(struct wl_listener *listener, void *data); static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorframe(struct wl_listener *listener, void *data); static void cursorwarptohint(void); @@ -79,7 +82,7 @@ index def2562..c14ae43 100644 static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); -@@ -293,6 +299,13 @@ static void fullscreennotify(struct wl_listener *listener, void *data); +@@ -290,6 +297,13 @@ static void fullscreennotify(struct wl_listener *listener, void *data); static void gpureset(struct wl_listener *listener, void *data); static void handlesig(int signo); static void incnmaster(const Arg *arg); @@ -93,24 +96,23 @@ index def2562..c14ae43 100644 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); -@@ -320,13 +333,15 @@ static void rendermon(struct wl_listener *listener, void *data); - static void requestdecorationmode(struct wl_listener *listener, void *data); - static void requeststartdrag(struct wl_listener *listener, void *data); - static void requestmonstate(struct wl_listener *listener, void *data); --static void resize(Client *c, struct wlr_box geo, int interact); -+static void resizeapply(Client *c, struct wlr_box geo, int interact); -+static void resizenoapply(Client *c, struct wlr_box geo, int interact); - static void run(char *startup_cmd); - static void setcursor(struct wl_listener *listener, void *data); +@@ -310,6 +324,7 @@ static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int + static void outputmgrtest(struct wl_listener *listener, void *data); + static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); ++static void preparegaps(Monitor *m); + static void printstatus(void); + static void powermgrsetmode(struct wl_listener *listener, void *data); + static void quit(const Arg *arg); +@@ -323,6 +338,7 @@ static void setcursor(struct wl_listener *listener, void *data); static void setcursorshape(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); - static void setgamma(struct wl_listener *listener, void *data); +static void setgaps(int oh, int ov, int ih, int iv); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, uint32_t newtags); -@@ -340,6 +355,7 @@ static void tagmon(const Arg *arg); +@@ -336,6 +352,7 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void togglefullscreen(const Arg *arg); @@ -118,83 +120,82 @@ index def2562..c14ae43 100644 static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unlocksession(struct wl_listener *listener, void *data); -@@ -413,6 +429,9 @@ static struct wlr_box sgeom; - static struct wl_list mons; - static Monitor *selmon; +@@ -435,6 +452,7 @@ static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; + static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; + static struct wl_listener new_session_lock = {.notify = locksession}; ++static int resizelock = 0; /* do not actually resize during arrange */ -+static int enablegaps = 1; /* enables gaps, used by togglegaps */ -+static void (*resize)(Client *c, struct wlr_box geo, int interact) = resizeapply; -+ #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); - static void associatex11(struct wl_listener *listener, void *data); -@@ -481,9 +500,25 @@ applyrules(Client *c) - setmon(c, mon, newtags); - } - -+void -+applygaps(Client *c) -+{ -+ struct wlr_box geom = c->geom; -+ -+ if (!c->mon) -+ return; -+ -+ geom.x += c->mon->gappih + c->mon->gappoh; -+ geom.y += c->mon->gappiv + c->mon->gappov; -+ geom.width -= c->mon->gappih; -+ geom.height -= c->mon->gappiv; -+ resize(c, geom, 0); -+} -+ - void - arrange(Monitor *m) - { -+ int save_width, save_height; - Client *c; - - if (!m->wlr_output->enabled) -@@ -515,8 +550,26 @@ arrange(Monitor *m) +@@ -537,12 +555,52 @@ arrange(Monitor *m) : c->scene->node.parent); } - if (m->lt[m->sellt]->arrange) + if (m->lt[m->sellt]->arrange) { -+ save_width = m->w.width; -+ save_height = m->w.height; -+ if (enablegaps) { -+ m->w.width -= m->gappih + 2 * m->gappoh; -+ m->w.height -= m->gappiv + 2 * m->gappov; -+ } -+ resize = resizenoapply; ++ preparegaps(m); m->lt[m->sellt]->arrange(m); -+ wl_list_for_each(c, &clients, link) { -+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) -+ continue; -+ if (enablegaps) -+ applygaps(c); -+ resizeapply(c, c->geom, c->interact); -+ } -+ m->w.width = save_width; -+ m->w.height = save_height; -+ resize = resizeapply; ++ arrangegaps(m); + } motionnotify(0, NULL, 0, 0, 0, 0); checkidleinhibitor(NULL); } -@@ -993,6 +1046,11 @@ createmon(struct wl_listener *listener, void *data) - wlr_output_state_init(&state); - /* Initialize monitor state using configured rules */ ++void ++arrangegaps(Monitor *m) ++{ ++ Client *c; ++ int n, gaps; + ++ if (!m->enablegaps) ++ return; ++ ++ resizelock = 0; ++ ++ n = 0; ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ continue; ++ n++; ++ } ++ ++ gaps = !(smartgaps && n == 1) && ++ (monoclegaps || m->lt[m->sellt]->arrange != monocle); ++ if (gaps) { ++ m->w.width += m->gappih + 2 * m->gappoh; ++ m->w.height += m->gappiv + 2 * m->gappov; ++ } ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ continue; ++ if (gaps) { ++ c->geom.x += c->mon->gappih + c->mon->gappoh; ++ c->geom.y += c->mon->gappiv + c->mon->gappov; ++ c->geom.width -= c->mon->gappih; ++ c->geom.height -= c->mon->gappiv; ++ } ++ resize(c, c->geom, 0); ++ } ++} ++ + void + arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) + { +@@ -1055,6 +1113,12 @@ createmon(struct wl_listener *listener, void *data) + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); + ++ m->enablegaps = enablegaps; + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; ++ + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ m->tagset[0] = m->tagset[1] = 1; - for (r = monrules; r < END(monrules); r++) { - if (!r->name || strstr(wlr_output->name, r->name)) { -@@ -1173,6 +1231,12 @@ cursorwarptohint(void) +@@ -1237,6 +1301,12 @@ cursorwarptohint(void) } } @@ -207,7 +208,7 @@ index def2562..c14ae43 100644 void destroydecoration(struct wl_listener *listener, void *data) { -@@ -1526,6 +1590,83 @@ incnmaster(const Arg *arg) +@@ -1575,6 +1645,83 @@ incnmaster(const Arg *arg) arrange(selmon); } @@ -291,31 +292,52 @@ index def2562..c14ae43 100644 void inputdevice(struct wl_listener *listener, void *data) { -@@ -2180,7 +2321,7 @@ requestmonstate(struct wl_listener *listener, void *data) - } - - void --resize(Client *c, struct wlr_box geo, int interact) -+resizeapply(Client *c, struct wlr_box geo, int interact) - { - struct wlr_box *bbox; - struct wlr_box clip; -@@ -2212,6 +2353,13 @@ resize(Client *c, struct wlr_box geo, int interact) - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); +@@ -2085,6 +2232,31 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + wlr_seat_pointer_notify_motion(seat, time, sx, sy); } +void -+resizenoapply(Client *c, struct wlr_box geo, int interact) ++preparegaps(Monitor *m) +{ -+ c->geom = geo; -+ c->interact = interact; ++ Client *c; ++ int n; ++ ++ if (!m->enablegaps) ++ return; ++ ++ n = 0; ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ continue; ++ n++; ++ } ++ ++ resizelock = 1; ++ ++ if ((smartgaps && n == 1) || (!monoclegaps && m->lt[m->sellt]->arrange == monocle)) ++ return; ++ ++ m->w.width -= m->gappih + 2 * m->gappoh; ++ m->w.height -= m->gappiv + 2 * m->gappov; +} + void - run(char *startup_cmd) + printstatus(void) { -@@ -2354,6 +2502,16 @@ setgamma(struct wl_listener *listener, void *data) - wlr_output_schedule_frame(m->wlr_output); +@@ -2208,6 +2380,11 @@ resize(Client *c, struct wlr_box geo, int interact) + struct wlr_box *bbox; + struct wlr_box clip; + ++ if (resizelock) { ++ c->geom = geo; ++ return; ++ } ++ + if (!c->mon || !client_surface(c)->mapped) + return; + +@@ -2368,6 +2545,16 @@ setfullscreen(Client *c, int fullscreen) + printstatus(); } +void @@ -331,14 +353,16 @@ index def2562..c14ae43 100644 void setlayout(const Arg *arg) { -@@ -2741,6 +2899,13 @@ togglefullscreen(const Arg *arg) +@@ -2760,6 +2947,15 @@ togglefullscreen(const Arg *arg) setfullscreen(sel, !sel->isfullscreen); } +void +togglegaps(const Arg *arg) +{ -+ enablegaps = !enablegaps; ++ if (!selmon) ++ return; ++ selmon->enablegaps = !selmon->enablegaps; + arrange(selmon); +} + @@ -346,5 +370,5 @@ index def2562..c14ae43 100644 toggletag(const Arg *arg) { -- -2.47.1 +2.53.0 From ee54a3413cacd705e044fdabb65beef20c370419 Mon Sep 17 00:00:00 2001 From: nate zhou Date: Sun, 15 Mar 2026 14:30:44 +0800 Subject: [PATCH 07/18] bar-modes: show status text when space permits Try to truncate title before hiding status, with longer modes labels. --- patches/bar-modes/bar-modes.patch | 69 ++++++++++++++++++------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/patches/bar-modes/bar-modes.patch b/patches/bar-modes/bar-modes.patch index 8e239a2..dcab50f 100644 --- a/patches/bar-modes/bar-modes.patch +++ b/patches/bar-modes/bar-modes.patch @@ -1,4 +1,4 @@ -From 4f2c8a99720d90a551bf38f2c8d25ad239346eef Mon Sep 17 00:00:00 2001 +From 04b37902e0098fb69250fd25b5afbc610a284529 Mon Sep 17 00:00:00 2001 From: nate zhou Date: Mon, 2 Mar 2026 21:54:03 +0800 Subject: [PATCH] Patch: bar-modes for 0.8 @@ -6,19 +6,22 @@ Subject: [PATCH] Patch: bar-modes for 0.8 Add modes_labels indicator to bar, which behaves like river-classic's dam bar. This patch has to be applied after the bar and modes patch. --- - dwl.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 59 insertions(+), 11 deletions(-) + dwl.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 72 insertions(+), 15 deletions(-) diff --git a/dwl.c b/dwl.c -index ae290ad..df525d3 100644 +index ae290ad..7229034 100644 --- a/dwl.c +++ b/dwl.c -@@ -1585,19 +1585,26 @@ drawbar(Monitor *m) +@@ -1585,19 +1585,29 @@ drawbar(Monitor *m) uint32_t i, occ = 0, urg = 0; Client *c; Buffer *buf; + char mode_text[256] = ""; + int mode_width = 0; ++ int title_width; ++ int remaining; ++ int status_shown = 0; if (!m->scene_buffer->node.enabled) return; @@ -45,7 +48,7 @@ index ae290ad..df525d3 100644 wl_list_for_each(c, &clients, link) { if (c->mon != m) continue; -@@ -1607,6 +1614,8 @@ drawbar(Monitor *m) +@@ -1607,6 +1617,8 @@ drawbar(Monitor *m) } x = 0; c = focustop(m); @@ -54,7 +57,7 @@ index ae290ad..df525d3 100644 for (i = 0; i < LENGTH(tags); i++) { w = TEXTW(m, tags[i]); drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); -@@ -1617,19 +1626,57 @@ drawbar(Monitor *m) +@@ -1617,19 +1629,63 @@ drawbar(Monitor *m) urg & 1 << i); x += w; } @@ -70,30 +73,40 @@ index ae290ad..df525d3 100644 w = TEXTW(m, m->ltsymbol); drwl_setscheme(m->drw, colors[SchemeNorm]); - x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0); +- +- if ((w = m->b.width - tw - x) > m->b.height) { +- if (c) { +- drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]); +- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0); +- if (c && c->isfloating) +- drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0); +- } else { + drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0); + x += w; + -+ int remaining = m->b.width - x; - -- if ((w = m->b.width - tw - x) > m->b.height) { -- if (c) { -+ if (mode_text[0]) { -+ int title_width = remaining; ++ remaining = m->b.width - x; + -+ if (title_width > m->b.height && c) { - drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]); -- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0); -+ drwl_text(m->drw, x, 0, title_width, m->b.height, m->lrpad / 2, -+ client_get_title(c), 0); - if (c && c->isfloating) - drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0); -- } else { -+ } else if (title_width > 0) { -+ drwl_setscheme(m->drw, colors[SchemeNorm]); -+ drwl_rect(m->drw, x, 0, title_width, m->b.height, 1, 1); -+ } -+ /* no status text when in a mode - completely omitted */ -+ } else { ++ if (mode_text[0] && remaining >= tw) { ++ drwl_setscheme(m->drw, colors[SchemeNorm]); ++ drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0); ++ remaining -= tw; ++ status_shown = 1; ++ } ++ ++ title_width = remaining; ++ ++ if (c && title_width > m->b.height) { ++ drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]); ++ drwl_text(m->drw, x, 0, title_width, m->b.height, m->lrpad / 2, ++ client_get_title(c), 0); ++ if (c && c->isfloating) ++ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0); ++ } else if (title_width > 0) { ++ drwl_setscheme(m->drw, colors[SchemeNorm]); ++ drwl_rect(m->drw, x, 0, title_width, m->b.height, 1, 1); ++ } ++ ++ if (!mode_text[0]) { + /* not in a mode - normal behavior with status */ + if (remaining >= tw) { + drwl_setscheme(m->drw, colors[SchemeNorm]); @@ -118,7 +131,7 @@ index ae290ad..df525d3 100644 } } -@@ -3437,6 +3484,7 @@ entermode(const Arg *arg) +@@ -3437,6 +3493,7 @@ entermode(const Arg *arg) { active_mode_index = arg->i; printstatus(); From abba4e9ad02c536ee6679a6309bc1ded6d25923a Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Thu, 26 Feb 2026 17:22:54 -0600 Subject: [PATCH 08/18] simple_scratchpad: Update for 0.8 and for wlroots-next-f4249db --- patches/simple_scratchpad/README.md | 3 +- ...v0.7.patch => simple_scratchpad-0.8.patch} | 66 +++--- ...mple_scratchpad-wlroots-next-f4249db.patch | 219 ++++++++++++++++++ 3 files changed, 254 insertions(+), 34 deletions(-) rename patches/simple_scratchpad/{simple_scratchpad-v0.7.patch => simple_scratchpad-0.8.patch} (75%) create mode 100644 patches/simple_scratchpad/simple_scratchpad-wlroots-next-f4249db.patch diff --git a/patches/simple_scratchpad/README.md b/patches/simple_scratchpad/README.md index 8076d96..d7918bb 100644 --- a/patches/simple_scratchpad/README.md +++ b/patches/simple_scratchpad/README.md @@ -19,7 +19,8 @@ Adds functions to add, toggle and remove clients to/from scratchpad client list. ### Download - [git branch](https://codeberg.org/julmajustus/dwl/src/branch/simple_scratchpad) -- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-v0.7.patch) +- [scratchpad-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-f4249db.patch) +- [scratchpad-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/simple_scratchpad/simple_scratchpad-0.8.patch) ### Authors - [julmajustus](https://codeberg.org/julmajustus) diff --git a/patches/simple_scratchpad/simple_scratchpad-v0.7.patch b/patches/simple_scratchpad/simple_scratchpad-0.8.patch similarity index 75% rename from patches/simple_scratchpad/simple_scratchpad-v0.7.patch rename to patches/simple_scratchpad/simple_scratchpad-0.8.patch index a273559..0d8af99 100644 --- a/patches/simple_scratchpad/simple_scratchpad-v0.7.patch +++ b/patches/simple_scratchpad/simple_scratchpad-0.8.patch @@ -1,34 +1,34 @@ -From a8d29e03f565b54a68c6c2cb2da103366c627825 Mon Sep 17 00:00:00 2001 -From: julmajustus -Date: Sat, 4 Jan 2025 13:22:12 +0200 -Subject: [PATCH] add simple_scratchpad +From 0d603b179ccccbb4270fd202a14a2db18d0a5413 Mon Sep 17 00:00:00 2001 +From: A Frederick Christensen +Date: Thu, 26 Feb 2026 17:09:28 -0600 +Subject: [PATCH] Apply simple_scratchpad patch --- config.def.h | 3 ++ dwl.c | 34 +++++++++++++++++++++-- - simple_scratchpad.c | 67 +++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 102 insertions(+), 2 deletions(-) + simple_scratchpad.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 simple_scratchpad.c diff --git a/config.def.h b/config.def.h -index 22d2171..83f19b3 100644 +index 8a6eda0..6254fc9 100644 --- a/config.def.h +++ b/config.def.h -@@ -136,6 +136,9 @@ static const Key keys[] = { - { MODKEY, XKB_KEY_Return, zoom, {0} }, - { MODKEY, XKB_KEY_Tab, view, {0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, -+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Z, addscratchpad, {0} }, -+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} }, -+ { MODKEY, XKB_KEY_z, removescratchpad, {0} }, - { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, - { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, - { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, +@@ -132,6 +132,9 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z, addscratchpad, {0} }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} }, ++ { MODKEY, XKB_KEY_z, removescratchpad, {0} }, + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, diff --git a/dwl.c b/dwl.c -index a2711f6..85f4a51 100644 +index 44f3ad9..215f630 100644 --- a/dwl.c +++ b/dwl.c -@@ -141,6 +141,7 @@ typedef struct { +@@ -139,6 +139,7 @@ typedef struct { uint32_t tags; int isfloating, isurgent, isfullscreen; uint32_t resize; /* configure serial of a pending resize */ @@ -36,7 +36,7 @@ index a2711f6..85f4a51 100644 } Client; typedef struct { -@@ -243,6 +244,7 @@ typedef struct { +@@ -240,6 +241,7 @@ typedef struct { } SessionLock; /* function declarations */ @@ -44,7 +44,7 @@ index a2711f6..85f4a51 100644 static void applybounds(Client *c, struct wlr_box *bbox); static void applyrules(Client *c); static void arrange(Monitor *m); -@@ -317,6 +319,7 @@ static void printstatus(void); +@@ -314,6 +316,7 @@ static void printstatus(void); static void powermgrsetmode(struct wl_listener *listener, void *data); static void quit(const Arg *arg); static void rendermon(struct wl_listener *listener, void *data); @@ -52,7 +52,7 @@ index a2711f6..85f4a51 100644 static void requestdecorationmode(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); static void requestmonstate(struct wl_listener *listener, void *data); -@@ -340,6 +343,7 @@ static void tagmon(const Arg *arg); +@@ -336,6 +339,7 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void togglefullscreen(const Arg *arg); @@ -60,17 +60,17 @@ index a2711f6..85f4a51 100644 static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unlocksession(struct wl_listener *listener, void *data); -@@ -413,6 +417,9 @@ static struct wlr_box sgeom; +@@ -406,6 +410,9 @@ static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; +static struct wl_list scratchpad_clients; +static int scratchpad_visible = 1; + - #ifdef XWAYLAND - static void activatex11(struct wl_listener *listener, void *data); - static void associatex11(struct wl_listener *listener, void *data); -@@ -432,6 +439,8 @@ static xcb_atom_t netatom[NetLast]; + /* global event handlers */ + static struct wl_listener cursor_axis = {.notify = axisnotify}; + static struct wl_listener cursor_button = {.notify = buttonpress}; +@@ -455,6 +462,8 @@ static struct wlr_xwayland *xwayland; /* attempt to encapsulate suck into one file */ #include "client.h" @@ -79,7 +79,7 @@ index a2711f6..85f4a51 100644 /* function implementations */ void applybounds(Client *c, struct wlr_box *bbox) -@@ -1259,10 +1268,20 @@ void +@@ -1328,10 +1337,20 @@ void destroynotify(struct wl_listener *listener, void *data) { /* Called when the xdg_toplevel is destroyed. */ @@ -101,7 +101,7 @@ index a2711f6..85f4a51 100644 #ifdef XWAYLAND if (c->type != XDGShell) { wl_list_remove(&c->activate.link); -@@ -2306,11 +2325,21 @@ setcursorshape(struct wl_listener *listener, void *data) +@@ -2333,11 +2352,21 @@ setcursorshape(struct wl_listener *listener, void *data) void setfloating(Client *c, int floating) { @@ -124,17 +124,17 @@ index a2711f6..85f4a51 100644 wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || (p && p->isfullscreen) ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); -@@ -2534,6 +2563,7 @@ setup(void) +@@ -2554,6 +2583,7 @@ setup(void) */ wl_list_init(&clients); wl_list_init(&fstack); + wl_list_init(&scratchpad_clients); xdg_shell = wlr_xdg_shell_create(dpy, 6); - LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); + wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel); diff --git a/simple_scratchpad.c b/simple_scratchpad.c new file mode 100644 -index 0000000..381f4b5 +index 0000000..26d6b66 --- /dev/null +++ b/simple_scratchpad.c @@ -0,0 +1,68 @@ @@ -207,5 +207,5 @@ index 0000000..381f4b5 + } +} -- -2.45.2 +2.52.0 diff --git a/patches/simple_scratchpad/simple_scratchpad-wlroots-next-f4249db.patch b/patches/simple_scratchpad/simple_scratchpad-wlroots-next-f4249db.patch new file mode 100644 index 0000000..690fa99 --- /dev/null +++ b/patches/simple_scratchpad/simple_scratchpad-wlroots-next-f4249db.patch @@ -0,0 +1,219 @@ +From 94e649317328c7af091516fe3441ea80a814d1e4 Mon Sep 17 00:00:00 2001 +From: A Frederick Christensen +Date: Thu, 26 Feb 2026 17:18:17 -0600 +Subject: [PATCH] Apply simple_scratchpad patch + +--- + config.def.h | 4 ++- + dwl.c | 34 +++++++++++++++++++++-- + simple_scratchpad.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 103 insertions(+), 3 deletions(-) + create mode 100644 simple_scratchpad.c + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..bd6cb40 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -132,6 +132,9 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z, addscratchpad, {0} }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratchpad, {0} }, ++ { MODKEY, XKB_KEY_z, removescratchpad, {0} }, + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, +@@ -154,7 +157,6 @@ static const Key keys[] = { + TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), + TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} }, +- + /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ + { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, + /* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is +diff --git a/dwl.c b/dwl.c +index 8a9715d..6ae7707 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -141,6 +141,7 @@ typedef struct { + uint32_t tags; + int isfloating, isurgent, isfullscreen; + uint32_t resize; /* configure serial of a pending resize */ ++ struct wl_list link_temp; + } Client; + + typedef struct { +@@ -242,6 +243,7 @@ typedef struct { + } SessionLock; + + /* function declarations */ ++static void addscratchpad(const Arg *arg); + static void applybounds(Client *c, struct wlr_box *bbox); + static void applyrules(Client *c); + static void arrange(Monitor *m); +@@ -316,6 +318,7 @@ static void printstatus(void); + static void powermgrsetmode(struct wl_listener *listener, void *data); + static void quit(const Arg *arg); + static void rendermon(struct wl_listener *listener, void *data); ++static void removescratchpad(const Arg *arg); + static void requestdecorationmode(struct wl_listener *listener, void *data); + static void requeststartdrag(struct wl_listener *listener, void *data); + static void requestmonstate(struct wl_listener *listener, void *data); +@@ -338,6 +341,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); ++static void togglescratchpad(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unlocksession(struct wl_listener *listener, void *data); +@@ -408,6 +412,9 @@ static struct wlr_box sgeom; + static struct wl_list mons; + static Monitor *selmon; + ++static struct wl_list scratchpad_clients; ++static int scratchpad_visible = 1; ++ + /* global event handlers */ + static struct wl_listener cursor_axis = {.notify = axisnotify}; + static struct wl_listener cursor_button = {.notify = buttonpress}; +@@ -457,6 +464,8 @@ static struct wlr_xwayland *xwayland; + /* attempt to encapsulate suck into one file */ + #include "client.h" + ++#include "simple_scratchpad.c" ++ + /* function implementations */ + void + applybounds(Client *c, struct wlr_box *bbox) +@@ -1330,10 +1339,20 @@ void + destroynotify(struct wl_listener *listener, void *data) + { + /* Called when the xdg_toplevel is destroyed. */ +- Client *c = wl_container_of(listener, c, destroy); ++ Client *sc, *c = wl_container_of(listener, c, destroy); + wl_list_remove(&c->destroy.link); + wl_list_remove(&c->set_title.link); + wl_list_remove(&c->fullscreen.link); ++ /* Check if destroyed client was part of scratchpad_clients ++ * and clean it from the list if so. */ ++ if (c && wl_list_length(&scratchpad_clients) > 0) { ++ wl_list_for_each(sc, &scratchpad_clients, link_temp) { ++ if (sc == c) { ++ wl_list_remove(&c->link_temp); ++ break; ++ } ++ } ++ } + #ifdef XWAYLAND + if (c->type != XDGShell) { + wl_list_remove(&c->activate.link); +@@ -2335,11 +2354,21 @@ setcursorshape(struct wl_listener *listener, void *data) + void + setfloating(Client *c, int floating) + { +- Client *p = client_get_parent(c); ++ Client *sc, *p = client_get_parent(c); + c->isfloating = floating; + /* If in floating layout do not change the client's layer */ + if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) + return; ++ /* Check if unfloated client was part of scratchpad_clients ++ * and remove it from scratchpad_clients list if so */ ++ if (!floating && wl_list_length(&scratchpad_clients) > 0) { ++ wl_list_for_each(sc, &scratchpad_clients, link_temp) { ++ if (sc == c) { ++ wl_list_remove(&c->link_temp); ++ break; ++ } ++ } ++ } + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || + (p && p->isfullscreen) ? LyrFS + : c->isfloating ? LyrFloat : LyrTile]); +@@ -2557,6 +2586,7 @@ setup(void) + */ + wl_list_init(&clients); + wl_list_init(&fstack); ++ wl_list_init(&scratchpad_clients); + + xdg_shell = wlr_xdg_shell_create(dpy, 6); + wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel); +diff --git a/simple_scratchpad.c b/simple_scratchpad.c +new file mode 100644 +index 0000000..26d6b66 +--- /dev/null ++++ b/simple_scratchpad.c +@@ -0,0 +1,68 @@ ++/* ************************************************************************** */ ++/* */ ++/* ::: :::::::: */ ++/* simple_scratchpad.c :+: :+: :+: */ ++/* +:+ +:+ +:+ */ ++/* By: jmakkone +#+ +:+ +#+ */ ++/* +#+#+#+#+#+ +#+ */ ++/* Created: 2024/12/19 19:35:02 by jmakkone #+# #+# */ ++/* Updated: 2025/01/04 13:35:50 by jmakkone ### ########.fr */ ++/* */ ++/* ************************************************************************** */ ++ ++void ++addscratchpad(const Arg *arg) ++{ ++ Client *cc, *c = focustop(selmon); ++ ++ if (!c) ++ return; ++ /* Check if the added client is already a scratchpad client */ ++ wl_list_for_each(cc, &scratchpad_clients, link_temp) { ++ if (cc == c) ++ return; ++ } ++ if (!c->isfloating) { ++ setfloating(c, 1); ++ } ++ wl_list_insert(&scratchpad_clients, &c->link_temp); ++} ++ ++void ++togglescratchpad(const Arg *arg) ++{ ++ Client *c; ++ Monitor *m = selmon; ++ ++ scratchpad_visible = !scratchpad_visible; ++ if (scratchpad_visible) { ++ wl_list_for_each(c, &scratchpad_clients, link_temp) { ++ c->mon = m; ++ c->tags = m->tagset[m->seltags]; ++ arrange(m); ++ focusclient(c, 1); ++ } ++ } else { ++ wl_list_for_each(c, &scratchpad_clients, link_temp) { ++ c->tags = 0; ++ focusclient(focustop(m), 1); ++ arrange(m); ++ } ++ } ++} ++ ++void ++removescratchpad(const Arg *arg) ++{ ++ Client *sc, *c = focustop(selmon); ++ ++ if (c && wl_list_length(&scratchpad_clients) > 0) { ++ /* Check if c is in scratchpad_clients */ ++ wl_list_for_each(sc, &scratchpad_clients, link_temp) { ++ if (sc == c) { ++ wl_list_remove(&c->link_temp); ++ break; ++ } ++ } ++ } ++} +-- +2.52.0 + From ca061466553ad820cc578e9a1b7b3f1fdf16c8bf Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 20:27:22 +0100 Subject: [PATCH 09/18] Update snail patch to 0.8 --- patches/snail/README.md | 91 +++++++++- .../snail/{snail.patch => snail-0.7.patch} | 0 patches/snail/snail-0.8.patch | 162 ++++++++++++++++++ 3 files changed, 250 insertions(+), 3 deletions(-) rename patches/snail/{snail.patch => snail-0.7.patch} (100%) create mode 100644 patches/snail/snail-0.8.patch diff --git a/patches/snail/README.md b/patches/snail/README.md index 0c94b79..a33073a 100644 --- a/patches/snail/README.md +++ b/patches/snail/README.md @@ -1,9 +1,94 @@ ### Description -Adds a spiral-inspired layout for wide screens. +This layout is a scalable alternative to the "tile" and "spiral" layouts, optimized for wide monitors. Both the master area and the stack are "spirals", but windows in the master area are split horizontally as long as the master area has enough horizontal space, and the first window in the stack is split vertically unless the stack is wide. + +With one window in the master area and mfact = 0.5, it behaves like the spiral layout: + +┌───────────────┬────────────────┐ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +│ ├───┬───┬────────┤ +│ │ │ │ │ +│ ├───┴───┤ │ +│ │ │ │ +│ │ │ │ +└───────────────┴───────┴────────┘ + +With 2 windows in the master area and 2 in the stack: + +┌───────────────┬────────────────┐ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├───────────────┼────────────────┤ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +└───────────────┴────────────────┘ + +With 3 windows in the master area and 2 in the stack: + +┌───────────────┬────────────────┐ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├───────┬───────┼────────────────┤ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +└───────┴───────┴────────────────┘ + +With many windows in both areas: + +┌───────────────┬────────────────┐ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +├───┬───┬───────┼───┬───┬────────┤ +│ │ │ │ │ │ │ +├───┴───┤ ├───┴───┤ │ +│ │ │ │ │ +│ │ │ │ │ +└───────┴───────┴───────┴────────┘ + +With 2 windows in the master area, many windows in the stack and high mfact: + +┌──────────┬──────────┬──────────┐ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ master ├──┬stack──┤ +│ │ │ │ │ │ +│ │ ├──┴──┤ │ +│ │ │ │ │ +│ │ │ │ │ +└──────────┴──────────┴─────┴────┘ + +With 2 windows in the master area, many windows in the stack and low mfact: + +┌──────────┬──────────┬──────────┐ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +├──master──┤ stack┬──┬────┤ +│ │ │ │ │ │ +│ │ ├──┴──┤ │ +│ │ │ │ │ +│ │ │ │ │ +└──────────┴──────────┴─────┴────┘ ### Download -- [2024-02-11](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/snail/snail.patch) +- [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/snail/snail-0.8.patch) +- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/snail/snail-0.7.patch) ### Authors - [Dima Krasner](https://codeberg.org/dimkr) () -- [Nikita Ivanov](https://github.com/NikitaIvanovV) (fix for flickering) +- [Nikita Ivanov](https://github.com/NikitaIvanovV) diff --git a/patches/snail/snail.patch b/patches/snail/snail-0.7.patch similarity index 100% rename from patches/snail/snail.patch rename to patches/snail/snail-0.7.patch diff --git a/patches/snail/snail-0.8.patch b/patches/snail/snail-0.8.patch new file mode 100644 index 0000000..44de138 --- /dev/null +++ b/patches/snail/snail-0.8.patch @@ -0,0 +1,162 @@ +From 9c97743480e901029fce2a8ccdde4f8b6a34040a Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Tue, 25 Mar 2025 02:49:43 +0100 +Subject: [PATCH] Add snail layout + +--- + config.def.h | 4 +- + dwl.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 105 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..5080a2c 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -33,6 +33,7 @@ static const Layout layouts[] = { + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "@|@", snail }, + }; + + /* monitors */ +@@ -43,7 +44,7 @@ static const MonitorRule monrules[] = { + /* name mfact nmaster scale layout rotate/reflect x y + * example of a HiDPI laptop monitor: + { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */ +- { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, ++ { NULL, 0.64f, 1, 1, &layouts[3], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, + /* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */ + }; + +@@ -135,6 +136,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XKB_KEY_s, setlayout, {.v = &layouts[3]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, +diff --git a/dwl.c b/dwl.c +index 44f3ad9..1250fb7 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -329,6 +329,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 snail(Monitor *m); + static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); + static void tag(const Arg *arg); +@@ -2666,6 +2667,107 @@ setup(void) + #endif + } + ++void ++snail(Monitor *m) ++{ ++ int i = 0, n = 0; ++ unsigned int mw = m->w.width; ++ Client *c, *prev; ++ enum wlr_direction dir = WLR_DIRECTION_RIGHT; ++ ++ wl_list_for_each(c, &clients, link) ++ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) ++ n++; ++ if (n == 0) ++ return; ++ ++ if (n > m->nmaster) ++ mw = m->nmaster ? (int)round(m->w.width * m->mfact) : 0; ++ ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ continue; ++ ++ /* ++ * If the master area exists and this is the first window, fill the ++ * master area with this window ++ */ ++ if (mw > 0 && i == 0) { ++ c->geom = (struct wlr_box){.x = m->w.x, .y = m->w.y, ++ .width = mw, .height = m->w.height}; ++ /* ++ * If the first window in the master area is wide, split it ++ * horizontally and put next one on its right; otherwise, split it ++ * vertically and put the next one below it ++ */ ++ dir = c->geom.width > m->w.height ? WLR_DIRECTION_RIGHT : WLR_DIRECTION_DOWN; ++ /* ++ * If the master area is full or doesn't exist, fill the stack with the ++ * m->nmaster-th window ++ */ ++ } else if (i == m->nmaster) { ++ c->geom = (struct wlr_box){.x = m->w.x + mw, .y = m->w.y, ++ .width = m->w.width - mw, .height = m->w.height}; ++ /* ++ * If the first window in the stack is wide, split it horizontally ++ * and put next one on its right; otherwise, split it vertically and ++ * put the next one below it ++ */ ++ dir = c->geom.width > m->w.height ? WLR_DIRECTION_RIGHT : WLR_DIRECTION_DOWN; ++ /* ++ * Split the previous horizontally and put the current window on the right ++ */ ++ } else if (dir == WLR_DIRECTION_RIGHT) { ++ c->geom = (struct wlr_box){.x = prev->geom.x + prev->geom.width / 2, .y = prev->geom.y, ++ .width = prev->geom.width / 2, .height = prev->geom.height}; ++ prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y, ++ .width = prev->geom.width / 2, .height = prev->geom.height}; ++ /* ++ * If it's a stack window or the first narrow window in the master ++ * area, put the next one below it ++ */ ++ if (i >= m->nmaster || c->geom.width < m->w.height) ++ dir = WLR_DIRECTION_DOWN; ++ /* ++ * Split the previous vertically and put the current window below it ++ */ ++ } else if (dir == WLR_DIRECTION_DOWN) { ++ c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + prev->geom.height / 2, ++ .width = prev->geom.width, .height = prev->geom.height / 2}; ++ prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y, ++ .width = prev->geom.width, .height = prev->geom.height / 2}; ++ dir = WLR_DIRECTION_LEFT; ++ /* ++ * Split the previous horizontally and put the current window on the left ++ */ ++ } else if (dir == WLR_DIRECTION_LEFT) { ++ c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y, ++ .width = prev->geom.width / 2, .height = prev->geom.height}; ++ prev->geom = (struct wlr_box){.x = prev->geom.x + prev->geom.width / 2, .y = prev->geom.y, ++ .width = prev->geom.width / 2, .height = prev->geom.height}; ++ dir = WLR_DIRECTION_UP; ++ /* ++ * Split the previous vertically and put the current window above it ++ */ ++ } else { ++ c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y, ++ .width = prev->geom.width, .height = prev->geom.height / 2}; ++ prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + prev->geom.height / 2, ++ .width = prev->geom.width, .height = prev->geom.height / 2}; ++ dir = WLR_DIRECTION_RIGHT; ++ } ++ i++; ++ prev = c; ++ } ++ ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ continue; ++ ++ resize(c, c->geom, 0); ++ } ++} ++ + void + spawn(const Arg *arg) + { +-- +2.53.0 + From 52a7559a870fb532ed5f03ee5665488a7703311c Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 20:38:06 +0100 Subject: [PATCH 10/18] snail: fix formatting --- patches/snail/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/patches/snail/README.md b/patches/snail/README.md index a33073a..9a4646e 100644 --- a/patches/snail/README.md +++ b/patches/snail/README.md @@ -1,8 +1,9 @@ ### Description This layout is a scalable alternative to the "tile" and "spiral" layouts, optimized for wide monitors. Both the master area and the stack are "spirals", but windows in the master area are split horizontally as long as the master area has enough horizontal space, and the first window in the stack is split vertically unless the stack is wide. -With one window in the master area and mfact = 0.5, it behaves like the spiral layout: +With one window in the master area and `mfact = 0.5`, it behaves like the spiral layout: +``` ┌───────────────┬────────────────┐ │ │ │ │ │ │ @@ -14,9 +15,11 @@ With one window in the master area and mfact = 0.5, it behaves like the spiral l │ │ │ │ │ │ │ │ └───────────────┴───────┴────────┘ +``` With 2 windows in the master area and 2 in the stack: +``` ┌───────────────┬────────────────┐ │ │ │ │ │ │ @@ -28,9 +31,11 @@ With 2 windows in the master area and 2 in the stack: │ │ │ │ │ │ └───────────────┴────────────────┘ +``` With 3 windows in the master area and 2 in the stack: +``` ┌───────────────┬────────────────┐ │ │ │ │ │ │ @@ -42,9 +47,11 @@ With 3 windows in the master area and 2 in the stack: │ │ │ │ │ │ │ │ └───────┴───────┴────────────────┘ +``` With many windows in both areas: +``` ┌───────────────┬────────────────┐ │ │ │ │ │ │ @@ -56,9 +63,11 @@ With many windows in both areas: │ │ │ │ │ │ │ │ │ │ └───────┴───────┴───────┴────────┘ +``` With 2 windows in the master area, many windows in the stack and high mfact: +``` ┌──────────┬──────────┬──────────┐ │ │ │ │ │ │ │ │ @@ -70,9 +79,11 @@ With 2 windows in the master area, many windows in the stack and high mfact: │ │ │ │ │ │ │ │ │ │ └──────────┴──────────┴─────┴────┘ +``` With 2 windows in the master area, many windows in the stack and low mfact: +``` ┌──────────┬──────────┬──────────┐ │ │ │ │ │ │ │ │ @@ -84,6 +95,7 @@ With 2 windows in the master area, many windows in the stack and low mfact: │ │ │ │ │ │ │ │ │ │ └──────────┴──────────┴─────┴────┘ +``` ### Download - [0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/snail/snail-0.8.patch) From 5ccc71e0b58674a2a72913d10e6c3990bf4a75db Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 20:42:50 +0100 Subject: [PATCH 11/18] centeredmaster: update to 0.8 --- patches/centeredmaster/README.md | 3 +- ...dmaster.patch => centeredmaster-0.7.patch} | 0 .../centeredmaster/centeredmaster-0.8.patch | 114 ++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) rename patches/centeredmaster/{centeredmaster.patch => centeredmaster-0.7.patch} (100%) create mode 100644 patches/centeredmaster/centeredmaster-0.8.patch diff --git a/patches/centeredmaster/README.md b/patches/centeredmaster/README.md index 2ba6dd9..10bfc1f 100644 --- a/patches/centeredmaster/README.md +++ b/patches/centeredmaster/README.md @@ -24,7 +24,8 @@ With one and two clients in master respectively this results in: ### Download -- [0.7](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster.patch) +- [0.8](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster-0.8.patch) +- [0.7](/dwl/dwl-patches/raw/branch/main/patches/centeredmaster/centeredmaster-0.7.patch) - [2024-04-11](https://codeberg.org/dwl/dwl-patches/raw/commit/b104a580a80ebaf9f7e8917fe574e3e97ddd019a/centeredmaster/centeredmaster.patch) - [0.5](https://codeberg.org/dwl/dwl-patches/raw/commit/0f4e40fee49d1b8b430778e241b29496ae3b3b70/centeredmaster/centeredmaster.patch) diff --git a/patches/centeredmaster/centeredmaster.patch b/patches/centeredmaster/centeredmaster-0.7.patch similarity index 100% rename from patches/centeredmaster/centeredmaster.patch rename to patches/centeredmaster/centeredmaster-0.7.patch diff --git a/patches/centeredmaster/centeredmaster-0.8.patch b/patches/centeredmaster/centeredmaster-0.8.patch new file mode 100644 index 0000000..fd61aa5 --- /dev/null +++ b/patches/centeredmaster/centeredmaster-0.8.patch @@ -0,0 +1,114 @@ +From 1fb8c15bb02c50279a5ccbd410dc1293abb747f3 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Sat, 8 Feb 2025 16:10:25 +0100 +Subject: [PATCH] Add centeredmaster layout + +--- + config.def.h | 2 ++ + dwl.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..70954cc 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -33,6 +33,7 @@ static const Layout layouts[] = { + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "|M|", centeredmaster }, + }; + + /* monitors */ +@@ -135,6 +136,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XKB_KEY_c, setlayout, {.v = &layouts[3]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, +diff --git a/dwl.c b/dwl.c +index 44f3ad9..bf859b0 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -248,6 +248,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, + static void arrangelayers(Monitor *m); + static void axisnotify(struct wl_listener *listener, void *data); + static void buttonpress(struct wl_listener *listener, void *data); ++static void centeredmaster(Monitor *m); + static void chvt(const Arg *arg); + static void checkidleinhibitor(struct wlr_surface *exclude); + static void cleanup(void); +@@ -672,6 +673,68 @@ buttonpress(struct wl_listener *listener, void *data) + event->time_msec, event->button, event->state); + } + ++void ++centeredmaster(Monitor *m) ++{ ++ int i, n, h, mw, mx, my, oty, ety, tw; ++ Client *c; ++ ++ n = 0; ++ wl_list_for_each(c, &clients, link) ++ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) ++ n++; ++ if (n == 0) ++ return; ++ ++ /* initialize areas */ ++ mw = m->w.width; ++ mx = 0; ++ my = 0; ++ tw = mw; ++ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; ++ tw = m->w.width - mw; ++ ++ if (n - m->nmaster > 1) { ++ /* only one client */ ++ mx = (m->w.width - mw) / 2; ++ tw = (m->w.width - mw) / 2; ++ } ++ } ++ ++ i = 0; ++ oty = 0; ++ ety = 0; ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) ++ continue; ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked vertically, in the center ++ * of the screen */ ++ h = (m->w.height - my) / (MIN(n, m->nmaster) - i); ++ resize(c, (struct wlr_box){.x = m->w.x + mx, .y = m->w.y + my, .width = mw, ++ .height = h}, 0); ++ my += c->geom.height; ++ } else { ++ /* stack clients are stacked vertically */ ++ if ((i - m->nmaster) % 2) { ++ h = (m->w.height - ety) / ( (1 + n - i) / 2); ++ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ety, .width = tw, ++ .height = h}, 0); ++ ety += c->geom.height; ++ } else { ++ h = (m->w.height - oty) / ((1 + n - i) / 2); ++ resize(c, (struct wlr_box){.x = m->w.x + mx + mw, .y = m->w.y + oty, .width = tw, ++ .height = h}, 0); ++ oty += c->geom.height; ++ } ++ } ++ i++; ++ } ++} ++ + void + chvt(const Arg *arg) + { +-- +2.53.0 + From 870a32283199f6cc731eee2eb194b1cd70ed6fa3 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 20:52:50 +0100 Subject: [PATCH 12/18] movestack: update to 0.8 --- patches/movestack/README.md | 4 +- .../{movestack.patch => movestack-0.7.patch} | 0 patches/movestack/movestack-0.8.patch | 87 +++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) rename patches/movestack/{movestack.patch => movestack-0.7.patch} (100%) create mode 100644 patches/movestack/movestack-0.8.patch diff --git a/patches/movestack/README.md b/patches/movestack/README.md index f50bf68..8695374 100644 --- a/patches/movestack/README.md +++ b/patches/movestack/README.md @@ -2,8 +2,8 @@ Allows you to move a window up and down the stack. ### Download -- [git branch](https://codeberg.org/nikitaivanov/dwl/src/branch/movestack) -- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/movestack/movestack.patch) +- [0.8](/dwl/dwl-patches/raw/branch/main/patches/movestack/movestack-0.8.patch) +- [0.7](/dwl/dwl-patches/raw/branch/main/patches/movestack/movestack-0.7.patch) ### Authors - [wochap](https://codeberg.org/wochap) diff --git a/patches/movestack/movestack.patch b/patches/movestack/movestack-0.7.patch similarity index 100% rename from patches/movestack/movestack.patch rename to patches/movestack/movestack-0.7.patch diff --git a/patches/movestack/movestack-0.8.patch b/patches/movestack/movestack-0.8.patch new file mode 100644 index 0000000..cf0c933 --- /dev/null +++ b/patches/movestack/movestack-0.8.patch @@ -0,0 +1,87 @@ +From 7e8de6e79d24114272b22b55c906d7b55c36173a Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Mon, 16 Mar 2026 20:50:44 +0100 +Subject: [PATCH] Add movestack + +--- + config.def.h | 2 ++ + dwl.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..f490e24 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -125,6 +125,8 @@ static const Key keys[] = { + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, + { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, + { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_j, movestack, {.i = +1} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_k, movestack, {.i = -1} }, + { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, +diff --git a/dwl.c b/dwl.c +index 44f3ad9..726fbdd 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -300,6 +300,7 @@ static void locksession(struct wl_listener *listener, void *data); + static void mapnotify(struct wl_listener *listener, void *data); + static void maximizenotify(struct wl_listener *listener, void *data); + static void monocle(Monitor *m); ++static void movestack(const Arg *arg); + static void motionabsolute(struct wl_listener *listener, void *data); + static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, + double sy, double sx_unaccel, double sy_unaccel); +@@ -1838,6 +1839,48 @@ monocle(Monitor *m) + wlr_scene_node_raise_to_top(&c->scene->node); + } + ++void ++movestack(const Arg *arg) ++{ ++ Client *c, *sel = focustop(selmon); ++ ++ if (!sel) { ++ return; ++ } ++ ++ if (wl_list_length(&clients) <= 1) { ++ return; ++ } ++ ++ if (arg->i > 0) { ++ wl_list_for_each(c, &sel->link, link) { ++ if (&c->link == &clients) { ++ c = wl_container_of(&clients, c, link); ++ break; /* wrap past the sentinel node */ ++ } ++ if (VISIBLEON(c, selmon) || &c->link == &clients) { ++ break; /* found it */ ++ } ++ } ++ } else { ++ wl_list_for_each_reverse(c, &sel->link, link) { ++ if (&c->link == &clients) { ++ c = wl_container_of(&clients, c, link); ++ break; /* wrap past the sentinel node */ ++ } ++ if (VISIBLEON(c, selmon) || &c->link == &clients) { ++ break; /* found it */ ++ } ++ } ++ /* backup one client */ ++ c = wl_container_of(c->link.prev, c, link); ++ } ++ ++ wl_list_remove(&sel->link); ++ wl_list_insert(&c->link, &sel->link); ++ arrange(selmon); ++} ++ + void + motionabsolute(struct wl_listener *listener, void *data) + { +-- +2.53.0 + From 36439e54ba54f95a165440fd8c4b64fd22884b90 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 20:58:53 +0100 Subject: [PATCH 13/18] kblayout: update to 0.8 --- patches/kblayout/README.md | 4 +- .../{kblayout.patch => kblayout-0.7.patch} | 0 patches/kblayout/kblayout-0.8.patch | 188 ++++++++++++++++++ 3 files changed, 190 insertions(+), 2 deletions(-) rename patches/kblayout/{kblayout.patch => kblayout-0.7.patch} (100%) create mode 100644 patches/kblayout/kblayout-0.8.patch diff --git a/patches/kblayout/README.md b/patches/kblayout/README.md index 259694c..4f2280d 100644 --- a/patches/kblayout/README.md +++ b/patches/kblayout/README.md @@ -23,8 +23,8 @@ any of these features, just disable it in `config.h`. ### Download -- [git branch](https://codeberg.org/nikitaivanov/dwl/src/branch/kblayout) -- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/kblayout/kblayout.patch) +- [0.8](/dwl/dwl-patches/raw/branch/main/patches/kblayout/kblayout-0.8.patch) +- [0.7](/dwl/dwl-patches/raw/branch/main/patches/kblayout/kblayout-0.7.patch) ### Authors diff --git a/patches/kblayout/kblayout.patch b/patches/kblayout/kblayout-0.7.patch similarity index 100% rename from patches/kblayout/kblayout.patch rename to patches/kblayout/kblayout-0.7.patch diff --git a/patches/kblayout/kblayout-0.8.patch b/patches/kblayout/kblayout-0.8.patch new file mode 100644 index 0000000..81f7058 --- /dev/null +++ b/patches/kblayout/kblayout-0.8.patch @@ -0,0 +1,188 @@ +From c80ab5d3dacc5cf22382f88287eeba5d298be483 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Tue, 4 Feb 2025 23:42:10 +0100 +Subject: [PATCH] Add per client keyboard layout and status bar info + +--- + config.def.h | 3 +++ + dwl.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 73 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..09b6e57 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,9 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */ ++/* keyboard layout change notification for status bar */ ++static const char kblayout_file[] = "/tmp/dwl-keymap"; ++static const char *kblayout_cmd[] = {"pkill", "-RTMIN+3", "someblocks", NULL}; + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +diff --git a/dwl.c b/dwl.c +index 44f3ad9..279571b 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -139,6 +140,7 @@ typedef struct { + uint32_t tags; + int isfloating, isurgent, isfullscreen; + uint32_t resize; /* configure serial of a pending resize */ ++ unsigned int kblayout_idx; + } Client; + + typedef struct { +@@ -291,6 +293,7 @@ static void gpureset(struct wl_listener *listener, void *data); + static void handlesig(int signo); + static void incnmaster(const Arg *arg); + static void inputdevice(struct wl_listener *listener, void *data); ++static void kblayout(KeyboardGroup *kb); + 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); +@@ -436,6 +439,8 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; + static struct wl_listener new_session_lock = {.notify = locksession}; + ++static unsigned int kblayout_idx = -1; ++ + #ifdef XWAYLAND + static void activatex11(struct wl_listener *listener, void *data); + static void associatex11(struct wl_listener *listener, void *data); +@@ -945,6 +950,8 @@ createkeyboard(struct wlr_keyboard *keyboard) + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); ++ ++ kblayout(kb_group); + } + + KeyboardGroup * +@@ -1122,11 +1129,13 @@ createnotify(struct wl_listener *listener, void *data) + /* This event is raised when a client creates a new toplevel (application window). */ + struct wlr_xdg_toplevel *toplevel = data; + Client *c = NULL; ++ struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); + + /* Allocate a Client for this surface */ + c = toplevel->base->data = ecalloc(1, sizeof(*c)); + c->surface.xdg = toplevel->base; + c->bw = borderpx; ++ c->kblayout_idx = kb ? kb->modifiers.group : 0; + + LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); + LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); +@@ -1402,10 +1411,24 @@ dirtomon(enum wlr_direction dir) + void + focusclient(Client *c, int lift) + { ++ /* Copied from wlroots/types/wlr_keyboard_group.c */ ++ struct keyboard_group_device { ++ struct wlr_keyboard *keyboard; ++ struct wl_listener key; ++ struct wl_listener modifiers; ++ struct wl_listener keymap; ++ struct wl_listener repeat_info; ++ struct wl_listener destroy; ++ struct wl_list link; // wlr_keyboard_group.devices ++ }; ++ + struct wlr_surface *old = seat->keyboard_state.focused_surface; + int unused_lx, unused_ly, old_client_type; + Client *old_c = NULL; + LayerSurface *old_l = NULL; ++ struct keyboard_group_device *device; ++ struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); ++ struct wlr_keyboard_group *group = kb ? wlr_keyboard_group_from_wlr_keyboard(kb) : NULL; + + if (locked) + return; +@@ -1457,6 +1480,20 @@ focusclient(Client *c, int lift) + } + printstatus(); + ++ /* Update keyboard layout */ ++ if (group) { ++ // Update the first real device, because kb or group->kb is not a real ++ // keyboard and its effective layout gets overwritten ++ device = wl_container_of(group->devices.next, device, link); ++ if (device->keyboard) ++ wlr_keyboard_notify_modifiers(device->keyboard, ++ device->keyboard->modifiers.depressed, ++ device->keyboard->modifiers.latched, ++ device->keyboard->modifiers.locked, ++ c ? c->kblayout_idx : 0 ++ ); ++ } ++ + if (!c) { + /* With no client, all we have left is to clear focus */ + wlr_seat_keyboard_notify_clear_focus(seat); +@@ -1467,7 +1504,7 @@ focusclient(Client *c, int lift) + motionnotify(0, NULL, 0, 0, 0, 0); + + /* Have a client, so focus its top-level wlr_surface */ +- client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); ++ client_notify_enter(client_surface(c), kb); + + /* Activate the new client */ + client_activate_surface(client_surface(c), 1); +@@ -1605,6 +1642,36 @@ inputdevice(struct wl_listener *listener, void *data) + wlr_seat_set_capabilities(seat, caps); + } + ++void ++kblayout(KeyboardGroup *kb) ++{ ++ FILE *f; ++ Client *c; ++ unsigned int idx = kb->wlr_group->keyboard.modifiers.group; ++ ++ // If layout did not change, do nothing ++ if (kblayout_idx == idx) ++ return; ++ kblayout_idx = idx; ++ ++ // Update client layout ++ if ((c = focustop(selmon))) ++ c->kblayout_idx = kblayout_idx; ++ ++ // Save current layout to kblayout_file ++ if (*kblayout_file && (f = fopen(kblayout_file, "w"))) { ++ fputs(xkb_keymap_layout_get_name(kb->wlr_group->keyboard.keymap, ++ idx), f); ++ fclose(f); ++ } ++ ++ // Run kblayout_cmd ++ if (kblayout_cmd[0] && fork() == 0) { ++ execvp(kblayout_cmd[0], (char *const *)kblayout_cmd); ++ die("dwl: execvp %s failed:", kblayout_cmd[0]); ++ } ++} ++ + int + keybinding(uint32_t mods, xkb_keysym_t sym) + { +@@ -1683,6 +1750,8 @@ keypressmod(struct wl_listener *listener, void *data) + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(seat, + &group->wlr_group->keyboard.modifiers); ++ ++ kblayout(group); + } + + int +-- +2.53.0 + From 05895bbe1b71ab117cbf2b3667502e4404e6f10a Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 21:06:48 +0100 Subject: [PATCH 14/18] en-keycodes: update to 0.8 --- patches/en-keycodes/README.md | 4 +- ...n-keycodes.patch => en-keycodes-0.7.patch} | 0 patches/en-keycodes/en-keycodes-0.8.patch | 75 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) rename patches/en-keycodes/{en-keycodes.patch => en-keycodes-0.7.patch} (100%) create mode 100644 patches/en-keycodes/en-keycodes-0.8.patch diff --git a/patches/en-keycodes/README.md b/patches/en-keycodes/README.md index c089dc2..ac7f564 100644 --- a/patches/en-keycodes/README.md +++ b/patches/en-keycodes/README.md @@ -2,8 +2,8 @@ Always use the English keymap to get keycodes, so key bindings work even when using a non-English keyboard layout. ### Download -- [git branch](https://codeberg.org/ForzCross/dwl/src/branch/en-keycodes.patch) -- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/en-keycodes/en-keycodes.patch) +- [0.8](/dwl/dwl-patches/raw/branch/main/patches/en-keycodes/en-keycodes-0.8.patch) +- [0.7](/dwl/dwl-patches/raw/branch/main/patches/en-keycodes/en-keycodes-0.7.patch) ### Authors - [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV)) diff --git a/patches/en-keycodes/en-keycodes.patch b/patches/en-keycodes/en-keycodes-0.7.patch similarity index 100% rename from patches/en-keycodes/en-keycodes.patch rename to patches/en-keycodes/en-keycodes-0.7.patch diff --git a/patches/en-keycodes/en-keycodes-0.8.patch b/patches/en-keycodes/en-keycodes-0.8.patch new file mode 100644 index 0000000..ec080e2 --- /dev/null +++ b/patches/en-keycodes/en-keycodes-0.8.patch @@ -0,0 +1,75 @@ +From cde0921304c11c2e1341539a5ada4f7b9715b178 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Sun, 30 Nov 2025 23:22:42 +0100 +Subject: [PATCH] Always use the English keymap to get keycodes + +--- + dwl.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/dwl.c b/dwl.c +index 44f3ad9..97ba897 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -436,6 +436,11 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; + static struct wl_listener new_session_lock = {.notify = locksession}; + ++static struct xkb_rule_names en_rules; ++static struct xkb_context *en_context; ++static struct xkb_keymap *en_keymap; ++static struct xkb_state *en_state; ++ + #ifdef XWAYLAND + static void activatex11(struct wl_listener *listener, void *data); + static void associatex11(struct wl_listener *listener, void *data); +@@ -718,6 +723,9 @@ cleanup(void) + wlr_backend_destroy(backend); + + wl_display_destroy(dpy); ++ xkb_state_unref(en_state); ++ xkb_keymap_unref(en_keymap); ++ xkb_context_unref(en_context); + /* Destroy after the wayland display (when the monitors are already destroyed) + to avoid destroying them with an invalid scene output. */ + wlr_scene_node_destroy(&scene->tree.node); +@@ -1632,16 +1640,19 @@ keypress(struct wl_listener *listener, void *data) + /* This event is raised when a key is pressed or released. */ + KeyboardGroup *group = wl_container_of(listener, group, key); + struct wlr_keyboard_key_event *event = data; ++ int nsyms, handled; + + /* Translate libinput keycode -> xkbcommon */ + uint32_t keycode = event->keycode + 8; + /* Get a list of keysyms based on the keymap for this keyboard */ + const xkb_keysym_t *syms; +- int nsyms = xkb_state_key_get_syms( +- group->wlr_group->keyboard.xkb_state, keycode, &syms); +- +- int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); ++ xkb_state_update_key(en_state, keycode, ++ (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) ++ ? XKB_KEY_DOWN : XKB_KEY_UP); ++ nsyms = xkb_state_key_get_syms(en_state, keycode, &syms); ++ ++ handled = 0; + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + +@@ -2624,6 +2635,12 @@ setup(void) + * pointer, touch, and drawing tablet device. We also rig up a listener to + * let us know when new input devices are available on the backend. + */ ++ en_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); ++ en_rules = xkb_rules; ++ en_rules.layout = "us"; ++ en_keymap = xkb_keymap_new_from_names(en_context, &en_rules, ++ XKB_KEYMAP_COMPILE_NO_FLAGS); ++ en_state = xkb_state_new(en_keymap); + wl_signal_add(&backend->events.new_input, &new_input_device); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); + wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, +-- +2.53.0 + From 6abdb9f50c80bc6db091c97a851422990f1a97c8 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 21:17:03 +0100 Subject: [PATCH 15/18] setrule: update to 0.8 --- patches/setrule/README.md | 3 +- .../{setrule.patch => setrule-0.7.patch} | 0 patches/setrule/setrule-0.8.patch | 153 ++++++++++++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) rename patches/setrule/{setrule.patch => setrule-0.7.patch} (100%) create mode 100644 patches/setrule/setrule-0.8.patch diff --git a/patches/setrule/README.md b/patches/setrule/README.md index bdb7408..fda71f3 100644 --- a/patches/setrule/README.md +++ b/patches/setrule/README.md @@ -38,7 +38,8 @@ with dmenu. ### Download -- [v0.7](/dwl/dwl-patches/raw/branch/main/patches/setrule/setrule.patch) +- [0.8](/dwl/dwl-patches/raw/branch/main/patches/setrule/setrule-0.8.patch) +- [0.7](/dwl/dwl-patches/raw/branch/main/patches/setrule/setrule-0.7.patch) - [2025-02-14 v0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/268bee3cee239e5bd52cceed88a52bfc21143cc3/patches/setrule/setrule.patch) ### Authors diff --git a/patches/setrule/setrule.patch b/patches/setrule/setrule-0.7.patch similarity index 100% rename from patches/setrule/setrule.patch rename to patches/setrule/setrule-0.7.patch diff --git a/patches/setrule/setrule-0.8.patch b/patches/setrule/setrule-0.8.patch new file mode 100644 index 0000000..d0a9308 --- /dev/null +++ b/patches/setrule/setrule-0.8.patch @@ -0,0 +1,153 @@ +From b46440c982a5149570bb58369f84ef5082279123 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Sun, 9 Feb 2025 23:12:09 +0100 +Subject: [PATCH] setrule: add/change rules at runtime + +--- + config.def.h | 4 ++++ + dwl.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 68 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..48acf2d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -20,6 +20,9 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca + /* logging */ + static int log_level = WLR_ERROR; + ++/* Max amount of dynamically added rules */ ++#define RULES_MAX 100 ++ + static const Rule rules[] = { + /* app_id title tags mask isfloating monitor */ + { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +@@ -138,6 +141,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, setruleisfloating,{0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, +diff --git a/dwl.c b/dwl.c +index 44f3ad9..3c765d1 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -287,6 +287,7 @@ static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); + static Client *focustop(Monitor *m); + static void fullscreennotify(struct wl_listener *listener, void *data); ++static Rule *getrule(Client *c); + static void gpureset(struct wl_listener *listener, void *data); + static void handlesig(int signo); + static void incnmaster(const Arg *arg); +@@ -327,6 +328,7 @@ static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setmon(Client *c, Monitor *m, uint32_t newtags); + static void setpsel(struct wl_listener *listener, void *data); ++static void setruleisfloating(const Arg *arg); + static void setsel(struct wl_listener *listener, void *data); + static void setup(void); + static void spawn(const Arg *arg); +@@ -436,6 +438,9 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; + static struct wl_listener new_session_lock = {.notify = locksession}; + ++static Rule *drules; ++static size_t druleslen; ++ + #ifdef XWAYLAND + static void activatex11(struct wl_listener *listener, void *data); + static void associatex11(struct wl_listener *listener, void *data); +@@ -486,7 +491,7 @@ applyrules(Client *c) + appid = client_get_appid(c); + title = client_get_title(c); + +- for (r = rules; r < END(rules); r++) { ++ for (r = drules; r < drules + druleslen; r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; +@@ -1532,6 +1537,51 @@ fullscreennotify(struct wl_listener *listener, void *data) + setfullscreen(c, client_wants_fullscreen(c)); + } + ++Rule * ++getrule(Client *c) ++{ ++ Rule *r; ++ const Rule *e; ++ const char *appid, *title; ++ ++ if (!c) ++ return NULL; ++ ++ appid = client_get_appid(c); ++ title = client_get_title(c); ++ ++ for (r = drules + druleslen - 1; r >= drules; r--) ++ if ((!r->title || strstr(title, r->title)) ++ && (!r->id || strstr(appid, r->id))) ++ goto found; ++ ++ if (druleslen >= LENGTH(rules) + RULES_MAX) ++ return NULL; /* No free slots left */ ++ ++ r = drules + druleslen++; ++ ++ /* Use [NULL,NULL] as the default rule if exists */ ++ for (e = rules; e < END(rules); e++) ++ if (!e->title && !e->id) { ++ *r = *e; ++ break; ++ } ++ ++ /* No default rule found, set reasoble defaults */ ++ if (e >= END(rules)) { ++ r->monitor = -1; ++ } ++ ++ /* Only set title if appid is unset */ ++ if (strcmp(appid, "broken") == 0) ++ r->title = strdup(title); ++ else ++ r->id = strdup(appid); ++ ++found: ++ return r; ++} ++ + void + gpureset(struct wl_listener *listener, void *data) + { +@@ -2431,6 +2481,15 @@ setpsel(struct wl_listener *listener, void *data) + wlr_seat_set_primary_selection(seat, event->source, event->serial); + } + ++void ++setruleisfloating(const Arg *arg) ++{ ++ Rule *r = getrule(focustop(selmon)); ++ if (!r) ++ return; ++ r->isfloating = !r->isfloating; ++} ++ + void + setsel(struct wl_listener *listener, void *data) + { +@@ -2664,6 +2723,10 @@ setup(void) + fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); + } + #endif ++ ++ drules = ecalloc(LENGTH(rules) + RULES_MAX, sizeof(Rule)); ++ memcpy(drules, rules, sizeof(rules)); ++ druleslen = LENGTH(rules); + } + + void +-- +2.53.0 + From 79de70e29ef57b62983a026d1602b0c073829f39 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 21:25:48 +0100 Subject: [PATCH 16/18] swallow: update to 0.8 --- patches/swallow/README.md | 3 +- .../{swallow.patch => swallow-0.7.patch} | 0 patches/swallow/swallow-0.8.patch | 350 ++++++++++++++++++ 3 files changed, 352 insertions(+), 1 deletion(-) rename patches/swallow/{swallow.patch => swallow-0.7.patch} (100%) create mode 100644 patches/swallow/swallow-0.8.patch diff --git a/patches/swallow/README.md b/patches/swallow/README.md index 6c16162..f03fa79 100644 --- a/patches/swallow/README.md +++ b/patches/swallow/README.md @@ -22,7 +22,8 @@ scratch to make it more robust and add a few more features: #### swallow.patch -- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swallow/swallow.patch) +- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swallow/swallow-0.8.patch) +- [v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swallow/swallow-0.7.patch) - [2025-03-03 v0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/2e5748edfe1129f95c7bb1bf9dd590a897f55f57/patches/swallow/swallow.patch) (added "dynamic swallowing" support) - [2024-07-13](https://codeberg.org/dwl/dwl-patches/raw/commit/f1ed83eaeba46108f4ee8164094cb431d64a3e68/patches/swallow/swallow.patch) - [2024-07-13](https://codeberg.org/dwl/dwl-patches/raw/commit/f64d701bab2f9f52d3637edd091684f920407d87/patches/swallow/swallow.patch) diff --git a/patches/swallow/swallow.patch b/patches/swallow/swallow-0.7.patch similarity index 100% rename from patches/swallow/swallow.patch rename to patches/swallow/swallow-0.7.patch diff --git a/patches/swallow/swallow-0.8.patch b/patches/swallow/swallow-0.8.patch new file mode 100644 index 0000000..5204467 --- /dev/null +++ b/patches/swallow/swallow-0.8.patch @@ -0,0 +1,350 @@ +From 66efeab90dad4b6702a17b771cb08aeef159506a Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Wed, 5 Feb 2025 02:34:39 +0100 +Subject: [PATCH] swallow: hide the terminal when it spawns a client + +--- + client.h | 12 ++++ + config.def.h | 11 +++- + dwl.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 168 insertions(+), 7 deletions(-) + +diff --git a/client.h b/client.h +index d9f90bb..83e1c57 100644 +--- a/client.h ++++ b/client.h +@@ -131,6 +131,18 @@ client_get_appid(Client *c) + return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken"; + } + ++static inline int ++client_get_pid(Client *c) ++{ ++ pid_t pid; ++#ifdef XWAYLAND ++ if (client_is_x11(c)) ++ return c->surface.xwayland->pid; ++#endif ++ wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); ++ return pid; ++} ++ + static inline void + client_get_clip(Client *c, struct wlr_box *clip) + { +diff --git a/config.def.h b/config.def.h +index 8a6eda0..1a82020 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,8 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */ ++static int enableautoswallow = 1; /* enables autoswallowing newly spawned clients */ ++static float swallowborder = 1.0f; /* add this multiplied by borderpx to border when a client is swallowed */ + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -21,9 +23,10 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca + static int log_level = WLR_ERROR; + + static const Rule rules[] = { +- /* app_id title tags mask isfloating monitor */ +- { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +- { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ ++ /* app_id title tags mask isfloating isterm noswallow monitor */ ++ { "foot", NULL, 0, 0, 1, 1, -1 }, ++ { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ ++ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ + /* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */ + }; + +@@ -138,6 +141,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, ++ { MODKEY, XKB_KEY_a, toggleswallow, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow,{0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, +diff --git a/dwl.c b/dwl.c +index 44f3ad9..066b705 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -74,12 +74,13 @@ + #define MAX(A, B) ((A) > (B) ? (A) : (B)) + #define MIN(A, B) ((A) < (B) ? (A) : (B)) + #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +-#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) ++#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && !(C)->swallowedby) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define END(A) ((A) + LENGTH(A)) + #define TAGMASK ((1u << TAGCOUNT) - 1) + #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) + #define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0) ++#define BORDERPX(C) (borderpx + ((C)->swallowing ? (int)ceilf(swallowborder * (C)->swallowing->bw) : 0)) + + /* enums */ + enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +@@ -101,7 +102,8 @@ typedef struct { + } Button; + + typedef struct Monitor Monitor; +-typedef struct { ++typedef struct Client Client; ++struct Client { + /* Must keep this field first */ + unsigned int type; /* XDGShell or X11* */ + +@@ -138,8 +140,12 @@ typedef struct { + unsigned int bw; + uint32_t tags; + int isfloating, isurgent, isfullscreen; ++ int isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ +-} Client; ++ pid_t pid; ++ Client *swallowing; /* client being hidden */ ++ Client *swallowedby; ++}; + + typedef struct { + uint32_t mod; +@@ -227,6 +233,8 @@ typedef struct { + const char *title; + uint32_t tags; + int isfloating; ++ int isterm; ++ int noswallow; + int monitor; + } Rule; + +@@ -308,6 +316,7 @@ static void moveresize(const Arg *arg); + static void outputmgrapply(struct wl_listener *listener, void *data); + static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); + static void outputmgrtest(struct wl_listener *listener, void *data); ++static pid_t parentpid(pid_t pid); + static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); + static void printstatus(void); +@@ -331,11 +340,15 @@ static void setsel(struct wl_listener *listener, void *data); + static void setup(void); + static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); ++static void swallow(Client *c, Client *toswallow); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(Client *c); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); ++static void toggleswallow(const Arg *arg); ++static void toggleautoswallow(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unlocksession(struct wl_listener *listener, void *data); +@@ -486,11 +499,15 @@ applyrules(Client *c) + appid = client_get_appid(c); + title = client_get_title(c); + ++ c->pid = client_get_pid(c); ++ + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; ++ c->isterm = r->isterm; ++ c->noswallow = r->noswallow; + i = 0; + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) +@@ -500,6 +517,12 @@ applyrules(Client *c) + } + + c->isfloating |= client_is_float_type(c); ++ if (enableautoswallow && !c->noswallow && !c->isfloating && ++ !c->surface.xdg->initial_commit) { ++ Client *p = termforwin(c); ++ if (p) ++ swallow(c, p); ++ } + setmon(c, mon, newtags); + } + +@@ -2057,6 +2080,20 @@ outputmgrtest(struct wl_listener *listener, void *data) + outputmgrapplyortest(config, 1); + } + ++pid_t ++parentpid(pid_t pid) ++{ ++ unsigned int v = 0; ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)pid); ++ if (!(f = fopen(buf, "r"))) ++ return 0; ++ fscanf(f, "%*u %*s %*c %u", &v); ++ fclose(f); ++ return (pid_t)v; ++} ++ + void + pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) +@@ -2351,7 +2388,7 @@ setfullscreen(Client *c, int fullscreen) + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; +- c->bw = fullscreen ? 0 : borderpx; ++ c->bw = fullscreen ? 0 : BORDERPX(c); + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); +@@ -2418,6 +2455,9 @@ setmon(Client *c, Monitor *m, uint32_t newtags) + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); ++ ++ if (c->swallowing) ++ setmon(c->swallowing, m, newtags); + } + + void +@@ -2688,6 +2728,44 @@ startdrag(struct wl_listener *listener, void *data) + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); + } + ++void ++swallow(Client *c, Client *toswallow) ++{ ++ /* Do not allow a client to swallow itself */ ++ if (c == toswallow) ++ return; ++ ++ /* Swallow */ ++ if (toswallow && !c->swallowing) { ++ c->swallowing = toswallow; ++ toswallow->swallowedby = c; ++ toswallow->mon = c->mon; ++ toswallow->mon = c->mon; ++ wl_list_remove(&c->link); ++ wl_list_insert(&c->swallowing->link, &c->link); ++ wl_list_remove(&c->flink); ++ wl_list_insert(&c->swallowing->flink, &c->flink); ++ c->bw = BORDERPX(c); ++ c->tags = toswallow->tags; ++ c->isfloating = toswallow->isfloating; ++ c->geom = toswallow->geom; ++ setfullscreen(toswallow, 0); ++ } ++ ++ /* Unswallow */ ++ else if (c->swallowing) { ++ wl_list_remove(&c->swallowing->link); ++ wl_list_insert(&c->link, &c->swallowing->link); ++ wl_list_remove(&c->swallowing->flink); ++ wl_list_insert(&c->flink, &c->swallowing->flink); ++ c->swallowing->tags = c->tags; ++ c->swallowing->swallowedby = NULL; ++ c->swallowing = NULL; ++ c->bw = BORDERPX(c); ++ setfullscreen(c, 0); ++ } ++} ++ + void + tag(const Arg *arg) + { +@@ -2709,6 +2787,40 @@ tagmon(const Arg *arg) + setmon(sel, dirtomon(arg->i), 0); + } + ++Client * ++termforwin(Client *c) ++{ ++ Client *p; ++ pid_t pid; ++ pid_t pids[32]; ++ size_t i, pids_len; ++ ++ if (!c->pid || c->isterm) ++ return NULL; ++ ++ /* Get all parent pids */ ++ pids_len = 0; ++ pid = c->pid; ++ while (pids_len < LENGTH(pids)) { ++ pid = parentpid(pid); ++ if (!pid) ++ break; ++ pids[pids_len++] = pid; ++ } ++ ++ /* Find closest parent */ ++ for (i = 0; i < pids_len; i++) { ++ wl_list_for_each(p, &clients, link) { ++ if (!p->pid || !p->isterm || p->swallowedby) ++ continue; ++ if (pids[i] == p->pid) ++ return p; ++ } ++ } ++ ++ return NULL; ++} ++ + void + tile(Monitor *m) + { +@@ -2760,6 +2872,32 @@ togglefullscreen(const Arg *arg) + setfullscreen(sel, !sel->isfullscreen); + } + ++void ++toggleswallow(const Arg *arg) ++{ ++ Client *c, *sel = focustop(selmon); ++ if (!sel) ++ return; ++ ++ if (sel->swallowing) { ++ swallow(sel, NULL); ++ } else { ++ wl_list_for_each(c, &sel->flink, flink) { ++ if (&c->flink == &fstack) ++ continue; /* wrap past the sentinel node */ ++ if (VISIBLEON(c, selmon)) ++ break; /* found it */ ++ } ++ swallow(sel, c); ++ } ++} ++ ++void ++toggleautoswallow(const Arg *arg) ++{ ++ enableautoswallow = !enableautoswallow; ++} ++ + void + toggletag(const Arg *arg) + { +@@ -2820,6 +2958,12 @@ unmapnotify(struct wl_listener *listener, void *data) + grabc = NULL; + } + ++ if (c->swallowing) { ++ swallow(c, NULL); ++ } else if (c->swallowedby) { ++ swallow(c->swallowedby, NULL); ++ } ++ + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) { + exclusive_focus = NULL; +-- +2.53.0 + From 50651a80d22b92625e95129cdbfa0faa82c8ad62 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 21:44:32 +0100 Subject: [PATCH 17/18] menu: update to 0.8 --- patches/menu/README.md | 5 +- patches/menu/{menu.patch => menu-0.7.patch} | 0 patches/menu/menu-0.8.patch | 227 ++++++++++++++++++++ 3 files changed, 230 insertions(+), 2 deletions(-) rename patches/menu/{menu.patch => menu-0.7.patch} (100%) create mode 100644 patches/menu/menu-0.8.patch diff --git a/patches/menu/README.md b/patches/menu/README.md index ad37016..9942fe6 100644 --- a/patches/menu/README.md +++ b/patches/menu/README.md @@ -11,8 +11,9 @@ Edit `menus` array in `config.h` to add/change menus and use a different dmenu program (`wmenu` is the default). ### Download -- [2025-03-21 v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/menu/menu.patch) -- [2024-07-13 v0.7](https://codeberg.org/dwl/dwl-patches/raw/commit/65ea99519bbf7a52f48932aea7385f81f8b30867/patches/menu/menu.patch) +- [v0.8](/dwl-patches/raw/branch/main/patches/menu/menu-0.8.patch) +- [2025-03-21 v0.7](/dwl/dwl-patches/raw/branch/main/patches/menu/menu-0.7.patch) +- [2024-07-13 v0.7](/dwl/dwl-patches/raw/commit/65ea99519bbf7a52f48932aea7385f81f8b30867/patches/menu/menu.patch) ### Authors - [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV)) diff --git a/patches/menu/menu.patch b/patches/menu/menu-0.7.patch similarity index 100% rename from patches/menu/menu.patch rename to patches/menu/menu-0.7.patch diff --git a/patches/menu/menu-0.8.patch b/patches/menu/menu-0.8.patch new file mode 100644 index 0000000..ede822c --- /dev/null +++ b/patches/menu/menu-0.8.patch @@ -0,0 +1,227 @@ +From 4347c2fd720166c526384827ef4f586a84d22040 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Fri, 21 Mar 2025 21:48:42 +0100 +Subject: [PATCH] Add menu command + +--- + config.def.h | 8 +++ + dwl.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 164 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 8a6eda0..1de52fa 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca + /* logging */ + static int log_level = WLR_ERROR; + ++static const Menu menus[] = { ++ /* command feed function action function */ ++ { "wmenu -i -l 10 -p Windows", menuwinfeed, menuwinaction }, ++ { "wmenu -i -p Layouts", menulayoutfeed, menulayoutaction }, ++}; ++ + static const Rule rules[] = { + /* app_id title tags mask isfloating monitor */ + { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +@@ -136,6 +142,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, ++ { MODKEY, XKB_KEY_o, menu, {.v = &menus[0]} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, menu, {.v = &menus[1]} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, +diff --git a/dwl.c b/dwl.c +index 44f3ad9..7e0e7b6 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -239,6 +239,12 @@ typedef struct { + struct wl_listener destroy; + } SessionLock; + ++typedef struct { ++ const char *cmd; /* command to run a menu */ ++ void (*feed)(FILE *f); /* feed input to menu */ ++ void (*action)(char *line); /* do action based on menu output */ ++} Menu; ++ + /* function declarations */ + static void applybounds(Client *c, struct wlr_box *bbox); + static void applyrules(Client *c); +@@ -299,6 +305,12 @@ static void killclient(const Arg *arg); + static void locksession(struct wl_listener *listener, void *data); + static void mapnotify(struct wl_listener *listener, void *data); + static void maximizenotify(struct wl_listener *listener, void *data); ++static void menu(const Arg *arg); ++static int menuread(int fd, uint32_t mask, void *data); ++static void menuwinfeed(FILE *f); ++static void menuwinaction(char *line); ++static void menulayoutfeed(FILE *f); ++static void menulayoutaction(char *line); + static void monocle(Monitor *m); + static void motionabsolute(struct wl_listener *listener, void *data); + static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, +@@ -436,6 +448,11 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; + static struct wl_listener new_session_lock = {.notify = locksession}; + ++static const Menu *menu_current; ++static int menu_fd; ++static pid_t menu_pid; ++static struct wl_event_source *menu_source; ++ + #ifdef XWAYLAND + static void activatex11(struct wl_listener *listener, void *data); + static void associatex11(struct wl_listener *listener, void *data); +@@ -1820,6 +1837,145 @@ maximizenotify(struct wl_listener *listener, void *data) + wlr_xdg_surface_schedule_configure(c->surface.xdg); + } + ++void ++menu(const Arg *arg) ++{ ++ FILE *f; ++ int fd_right[2], fd_left[2]; ++ ++ if (menu_current != NULL) { ++ wl_event_source_remove(menu_source); ++ close(menu_fd); ++ kill(menu_pid, SIGTERM); ++ menu_current = NULL; ++ if (!arg->v) ++ return; ++ } ++ ++ if (pipe(fd_right) == -1 || pipe(fd_left) == -1) ++ return; ++ if ((menu_pid = fork()) == -1) ++ return; ++ if (menu_pid == 0) { ++ close(fd_right[1]); ++ close(fd_left[0]); ++ dup2(fd_right[0], STDIN_FILENO); ++ close(fd_right[0]); ++ dup2(fd_left[1], STDOUT_FILENO); ++ close(fd_left[1]); ++ execl("/bin/sh", "/bin/sh", "-c", ((Menu *)(arg->v))->cmd, NULL); ++ die("dwl: execl %s failed:", "/bin/sh"); ++ } ++ ++ close(fd_right[0]); ++ close(fd_left[1]); ++ menu_fd = fd_left[0]; ++ if (fd_set_nonblock(menu_fd) == -1) ++ return; ++ if (!(f = fdopen(fd_right[1], "w"))) ++ return; ++ menu_current = arg->v; ++ menu_current->feed(f); ++ fclose(f); ++ menu_source = wl_event_loop_add_fd(event_loop, ++ menu_fd, WL_EVENT_READABLE, menuread, NULL); ++} ++ ++int ++menuread(int fd, uint32_t mask, void *data) ++{ ++ char *s; ++ int n; ++ static char line[512]; ++ static int i = 0; ++ ++ if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { ++ i = 0; ++ menu(&(const Arg){ .v = NULL }); ++ return 0; ++ } ++ if ((n = read(menu_fd, line + i, LENGTH(line) - 1 - i)) == -1) { ++ if (errno != EAGAIN) { ++ i = 0; ++ menu(&(const Arg){ .v = NULL }); ++ } ++ return 0; ++ } ++ line[i + n] = '\0'; ++ if (!(s = strchr(line + i, '\n'))) { ++ i += n; ++ return 0; ++ } ++ i = 0; ++ *s = '\0'; ++ menu_current->action(line); ++ return 0; ++} ++ ++void ++menuwinfeed(FILE *f) ++{ ++ Client *c; ++ const char *title, *appid; ++ ++ wl_list_for_each(c, &fstack, flink) { ++ if (!(title = client_get_title(c))) ++ continue; ++ fprintf(f, "%s", title); ++ if ((appid = client_get_appid(c))) ++ fprintf(f, " | %s", appid); ++ fputc('\n', f); ++ } ++} ++ ++void ++menuwinaction(char *line) ++{ ++ Client *c; ++ const char *appid, *title; ++ static char buf[512]; ++ ++ wl_list_for_each(c, &fstack, flink) { ++ if (!(title = client_get_title(c))) ++ continue; ++ appid = client_get_appid(c); ++ snprintf(buf, LENGTH(buf) - 1, "%s%s%s", ++ title, appid ? " | " : "", appid ? appid : ""); ++ if (strcmp(line, buf) == 0) ++ goto found; ++ } ++ return; ++ ++found: ++ if (!c->mon) ++ return; ++ wl_list_remove(&c->flink); ++ wl_list_insert(&fstack, &c->flink); ++ selmon = c->mon; ++ view(&(const Arg){ .ui = c->tags }); ++} ++ ++void ++menulayoutfeed(FILE *f) ++{ ++ const Layout *l; ++ for (l = layouts; l < END(layouts); l++) ++ fprintf(f, "%s\n", l->symbol); ++} ++ ++void ++menulayoutaction(char *line) ++{ ++ const Layout *l; ++ for (l = layouts; l < END(layouts); l++) ++ if (strcmp(line, l->symbol) == 0) ++ goto found; ++ return; ++ ++found: ++ setlayout(&(const Arg){ .v = l }); ++} ++ + void + monocle(Monitor *m) + { +-- +2.53.0 + From 8ac41e9d73436aa806437898629166e280a37b10 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 16 Mar 2026 21:49:06 +0100 Subject: [PATCH 18/18] menurule: update to 0.8 --- patches/menurule/README.md | 3 +- .../{menurule.patch => menurule-0.7.patch} | 0 patches/menurule/menurule-0.8.patch | 169 ++++++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) rename patches/menurule/{menurule.patch => menurule-0.7.patch} (100%) create mode 100644 patches/menurule/menurule-0.8.patch diff --git a/patches/menurule/README.md b/patches/menurule/README.md index 8d8b757..64f682c 100644 --- a/patches/menurule/README.md +++ b/patches/menurule/README.md @@ -63,7 +63,8 @@ index 34397fc..f1b31ea 100644 ### Download -- [v0.7](/dwl/dwl-patches/raw/branch/main/patches/menurule/menurule.patch) +- [0.8](/dwl/dwl-patches/raw/branch/main/patches/menurule/menurule-0.8.patch) +- [0.7](/dwl/dwl-patches/raw/branch/main/patches/menurule/menurule-0.7.patch) ### Authors diff --git a/patches/menurule/menurule.patch b/patches/menurule/menurule-0.7.patch similarity index 100% rename from patches/menurule/menurule.patch rename to patches/menurule/menurule-0.7.patch diff --git a/patches/menurule/menurule-0.8.patch b/patches/menurule/menurule-0.8.patch new file mode 100644 index 0000000..eb90158 --- /dev/null +++ b/patches/menurule/menurule-0.8.patch @@ -0,0 +1,169 @@ +From ffbc9d95316ec42e3f8e08816bfcf7b91a6801b6 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Wed, 19 Mar 2025 02:28:46 +0100 +Subject: [PATCH] Add menurule to tweak rules at runtime + +--- + config.def.h | 2 + + dwl.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 120 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 77a72a5..e7601a4 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -24,6 +24,7 @@ static const Menu menus[] = { + /* command feed function action function */ + { "wmenu -i -l 10 -p Windows", menuwinfeed, menuwinaction }, + { "wmenu -i -p Layouts", menulayoutfeed, menulayoutaction }, ++ { "wmenu -i -l 10 -p Rules", menurulefeed, menuruleaction }, + }; + + /* Max amount of dynamically added rules */ +@@ -147,6 +148,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY, XKB_KEY_o, menu, {.v = &menus[0]} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, menu, {.v = &menus[1]} }, ++ { MODKEY, XKB_KEY_r, menu, {.v = &menus[2]} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, setruleisfloating,{0} }, +diff --git a/dwl.c b/dwl.c +index 3d65e16..49daddb 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -312,6 +312,8 @@ static void menuwinfeed(FILE *f); + static void menuwinaction(char *line); + static void menulayoutfeed(FILE *f); + static void menulayoutaction(char *line); ++static void menurulefeed(FILE *f); ++static void menuruleaction(char *line); + static void monocle(Monitor *m); + static void motionabsolute(struct wl_listener *listener, void *data); + static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, +@@ -2026,6 +2028,122 @@ found: + setlayout(&(const Arg){ .v = l }); + } + ++void ++menurulefeed(FILE *f) ++{ ++ Rule t, *p, *r; ++ const char *appid, *title; ++ static char buf[515]; ++ Client *c = focustop(selmon); ++ int n, wid = 0, match; ++ ++ t = (Rule){ 0 }; ++ t.monitor = -1; ++ if (c) { ++ t.id = appid = client_get_appid(c); ++ t.title = title = client_get_title(c); ++ if (strcmp(t.id, "broken") == 0) ++ t.id = NULL; ++ if (strcmp(t.title, "broken") == 0) ++ t.title = NULL; ++ } ++ ++ for (p = drules; p <= drules + druleslen; p++) { ++ r = (p == drules + druleslen) ? &t : p; ++ n = 0; ++ n += strlen(r->id ? r->id : "NULL"); ++ n += strlen(r->title ? r->title : "NULL"); ++ n += 3; ++ wid = MAX(wid, n); ++ } ++ wid = MIN(wid, 40); ++ ++ for (p = drules; p <= drules + druleslen; p++) { ++ match = 0; ++ /* Check if rule applies to the focused client */ ++ if (c && p < drules + druleslen) { ++ match = (!p->title || strstr(title, p->title)) ++ && (!p->id || strstr(appid, p->id)); ++ if (match && p->id) ++ t.id = NULL; ++ if (match && p->title) ++ t.title = NULL; ++ } ++ r = (p == drules + druleslen) ? &t : p; ++ if (r == &t && t.id) ++ t.title = NULL; ++ /* Do not suggest to add a new empty rule */ ++ if (r == &t && !(t.id || t.title)) ++ continue; ++ if (r->id && r->title && ++ strcmp(r->id, "removedrule") == 0 && strcmp(r->title, "removedrule") == 0) ++ continue; ++ snprintf(buf, LENGTH(buf) - 1, "[%s|%s]", ++ r->id ? r->id : "NULL", r->title ? r->title : "NULL"); ++ fprintf(f, "%-*s " ++ " tags:%-4"PRIi32 ++ " isfloating:%-2d" ++ " monitor:%-2d" ++ "%s\n", wid, buf, ++ r->tags, ++ r->isfloating, ++ r->monitor, ++ (r == &t) ? " (NEW)" : match ? " <" : ""); ++ } ++} ++ ++void ++menuruleaction(char *line) ++{ ++ Rule r, *f; ++ static char appid[256], title[256]; ++ int del = 0, end; ++ ++ if (line[0] == '-') { ++ del = 1; ++ line++; ++ } ++ end = 0; ++ sscanf(line, "[%255[^|]|%255[^]]]" ++ " tags:%"SCNu32 ++ " isfloating:%d" ++ " monitor:%d" ++ "%n", appid, title, ++ &r.tags, ++ &r.isfloating, ++ &r.monitor, ++ &end); ++ ++ /* Full line was not parsed, exit */ ++ if (!end) ++ return; ++ ++ r.id = (strcmp(appid, "NULL") != 0) ? appid : NULL; ++ r.title = (strcmp(title, "NULL") != 0) ? title : NULL; ++ ++ /* Find which rule we are trying to edit */ ++ for (f = drules; f < drules + druleslen; f++) ++ if (((!r.title && !f->title) || (r.title && f->title && !strcmp(r.title, f->title))) ++ && (((!r.id && !f->id) || (r.id && f->id && !strcmp(r.id, f->id))))) ++ goto found; ++ ++ if (druleslen >= LENGTH(rules) + RULES_MAX) ++ return; /* No free slots left */ ++ ++ f = drules + druleslen++; ++ f->id = r.id ? strdup(r.id) : NULL; ++ f->title = r.title ? strdup(r.title) : NULL; ++ ++found: ++ if (del) { ++ f->id = f->title = "removedrule"; ++ return; ++ } ++ r.id = f->id; ++ r.title = f->title; ++ *f = r; ++} ++ + void + monocle(Monitor *m) + { +-- +2.53.0 +