summaryrefslogtreecommitdiff
path: root/dwl/dwl-patches/patches/singletagset-pertag
diff options
context:
space:
mode:
authorcoasteen <coasteen@proton.me>2026-07-09 10:42:28 +0330
committercoasteen <coasteen@proton.me>2026-07-09 10:42:28 +0330
commit8cbadb61604667b407b53ee1258433994fa4765a (patch)
tree97765fb29418fd6278fcb4cbb9760893afaf7a58 /dwl/dwl-patches/patches/singletagset-pertag
Diffstat (limited to 'dwl/dwl-patches/patches/singletagset-pertag')
-rwxr-xr-xdwl/dwl-patches/patches/singletagset-pertag/README.md22
-rwxr-xr-xdwl/dwl-patches/patches/singletagset-pertag/singletagset-pertag.patch261
2 files changed, 283 insertions, 0 deletions
diff --git a/dwl/dwl-patches/patches/singletagset-pertag/README.md b/dwl/dwl-patches/patches/singletagset-pertag/README.md
new file mode 100755
index 0000000..13ab951
--- /dev/null
+++ b/dwl/dwl-patches/patches/singletagset-pertag/README.md
@@ -0,0 +1,22 @@
+### Description
+Pertag keeps layouts, mfact and nmaster per tag
+instead of per output.
+
+This adapted version of pertag contains one version of
+the rules per all outputs, instead of one per output.
+This makes switching to tags from other monitors keep
+the window layout.
+
+This patch expects [singletagset](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/singletagset)
+patch to be already in your tree committed. It applies onto it.
+
+This patch is incompatible with [pertag](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/pertag).
+
+### Download
+- [2024-07-26](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/singletagset-pertag/singletagset-pertag.patch)
+- [git branch](https://codeberg.org/Rutherther/dwl/src/branch/v0.7/singletagset-pertag)
+
+### Authors
+- [Rutherther](https://codeberg.org/Rutherther)
+- [wochap (maintainer of pertag patch)](https://codeberg.org/wochap)
+- [Guido Cella (creator of pertag patch)](https://codeberg.org/guidocella)
diff --git a/dwl/dwl-patches/patches/singletagset-pertag/singletagset-pertag.patch b/dwl/dwl-patches/patches/singletagset-pertag/singletagset-pertag.patch
new file mode 100755
index 0000000..5fe4f47
--- /dev/null
+++ b/dwl/dwl-patches/patches/singletagset-pertag/singletagset-pertag.patch
@@ -0,0 +1,261 @@
+From 4f6bdd3ea1fcc83abd962e9a2dc7737519164a6b Mon Sep 17 00:00:00 2001
+From: Rutherther <rutherther@proton.me>
+Date: Fri, 19 Jul 2024 16:25:46 +0200
+Subject: [PATCH] singletagset-pertag
+
+---
+ config.def.h | 12 +++++--
+ dwl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 90 insertions(+), 12 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 22d2171..7feb04d 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -43,12 +43,18 @@ static const Layout layouts[] = {
+ */
+ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */
+ static const MonitorRule monrules[] = {
+- /* name mfact nmaster scale layout rotate/reflect x y */
++ /* name scale rotate/reflect x y */
+ /* example of a HiDPI laptop monitor:
+- { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
++ { "eDP-1", 2, WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
+ */
+ /* defaults */
+- { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
++ { NULL, 1, WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
++};
++
++static const TagRule tagrules[] = {
++ /* tag mfact nmaster layout */
++ /* defaults */
++ { 0, 0.55, 1, &layouts[0] }
+ };
+
+ /* keyboard */
+diff --git a/dwl.c b/dwl.c
+index 40a6e48..465d9dd 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -104,6 +104,7 @@ typedef struct {
+ const Arg arg;
+ } Button;
+
++typedef struct Pertag Pertag;
+ typedef struct Monitor Monitor;
+ typedef struct {
+ /* Must keep these three elements in this order */
+@@ -209,6 +210,7 @@ struct Monitor {
+ int nmaster;
+ char ltsymbol[16];
+ int asleep;
++ unsigned int pertag[2]; /* the tag used for layout via pertag */
+ };
+
+ typedef struct {
+@@ -226,6 +228,13 @@ typedef struct {
+ struct wl_listener destroy;
+ } PointerConstraint;
+
++typedef struct {
++ unsigned int tag;
++ float mfact;
++ int nmaster;
++ const Layout *lt;
++} TagRule;
++
+ typedef struct {
+ const char *id;
+ const char *title;
+@@ -245,6 +254,7 @@ typedef struct {
+
+ /* function declarations */
+ static void applybounds(Client *c, struct wlr_box *bbox);
++static void applypertag(Monitor *m);
+ static void applyrules(Client *c);
+ static void arrange(Monitor *m);
+ static void arrangelayer(Monitor *m, struct wl_list *list,
+@@ -293,6 +303,7 @@ static void focusstack(const Arg *arg);
+ static Client *focustop(Monitor *m);
+ static void fullscreennotify(struct wl_listener *listener, void *data);
+ static void gpureset(struct wl_listener *listener, void *data);
++static unsigned int getpertagtag(unsigned int curtagset);
+ static size_t getunusedtag(void);
+ static void handlesig(int signo);
+ static void incnmaster(const Arg *arg);
+@@ -415,6 +426,7 @@ static struct wlr_output_layout *output_layout;
+ static struct wlr_box sgeom;
+ static struct wl_list mons;
+ static Monitor *selmon;
++static Pertag pertag;
+
+ #ifdef XWAYLAND
+ static void activatex11(struct wl_listener *listener, void *data);
+@@ -435,6 +447,13 @@ static xcb_atom_t netatom[NetLast];
+ /* attempt to encapsulate suck into one file */
+ #include "client.h"
+
++struct Pertag {
++ int nmasters[TAGCOUNT + 1]; /* number of windows in master area */
++ float mfacts[TAGCOUNT + 1]; /* mfacts per tag */
++ unsigned int sellts[TAGCOUNT + 1]; /* selected layouts */
++ const Layout *ltidxs[TAGCOUNT + 1][2]; /* matrix of tags and layouts indexes */
++};
++
+ /* function implementations */
+ void
+ applybounds(Client *c, struct wlr_box *bbox)
+@@ -1023,6 +1042,33 @@ createlocksurface(struct wl_listener *listener, void *data)
+ client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
+ }
+
++unsigned int
++getpertagtag(unsigned int curtagset)
++{
++ size_t i;
++
++ if (curtagset == TAGMASK) {
++ return 0;
++ }
++
++ if ((curtagset & TAGMASK) == 0) {
++ return 0; // What to do in this case?
++ }
++
++ for (i = 0; !(curtagset & 1 << i); i++) ;
++ return i + 1;
++}
++
++void
++applypertag(Monitor *m)
++{
++ m->nmaster = pertag.nmasters[m->pertag[m->seltags]];
++ m->mfact = pertag.mfacts[m->pertag[m->seltags]];
++ m->sellt = pertag.sellts[m->pertag[m->seltags]];
++ m->lt[m->sellt] = pertag.ltidxs[m->pertag[m->seltags]][m->sellt];
++ m->lt[m->sellt^1] = pertag.ltidxs[m->pertag[m->seltags]][m->sellt^1];
++}
++
+ void
+ createmon(struct wl_listener *listener, void *data)
+ {
+@@ -1046,14 +1092,12 @@ createmon(struct wl_listener *listener, void *data)
+ wlr_output_state_init(&state);
+ /* Initialize monitor state using configured rules */
+ m->tagset[0] = m->tagset[1] = (1<<getunusedtag()) & TAGMASK;
++ m->pertag[0] = m->pertag[1] = getpertagtag(m->tagset[0]);
++ applypertag(m);
+ for (r = monrules; r < END(monrules); r++) {
+ if (!r->name || strstr(wlr_output->name, r->name)) {
+ m->m.x = r->x;
+ m->m.y = r->y;
+- m->mfact = r->mfact;
+- m->nmaster = r->nmaster;
+- m->lt[0] = r->lt;
+- m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
+ wlr_output_state_set_scale(&state, r->scale);
+ wlr_output_state_set_transform(&state, r->rr);
+@@ -1597,7 +1641,7 @@ incnmaster(const Arg *arg)
+ {
+ if (!arg || !selmon)
+ return;
+- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
++ selmon->nmaster = pertag.nmasters[selmon->pertag[selmon->seltags]] = MAX(selmon->nmaster + arg->i, 0);
+ arrange(selmon);
+ }
+
+@@ -2433,9 +2477,9 @@ setlayout(const Arg *arg)
+ if (!selmon)
+ return;
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
+- selmon->sellt ^= 1;
++ selmon->sellt = pertag.sellts[selmon->pertag[selmon->seltags]] ^= 1;
+ if (arg && arg->v)
+- selmon->lt[selmon->sellt] = (Layout *)arg->v;
++ selmon->lt[selmon->sellt] = pertag.ltidxs[selmon->pertag[selmon->seltags]][selmon->sellt] = (Layout *)arg->v;
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
+ arrange(selmon);
+ printstatus();
+@@ -2452,7 +2496,7 @@ setmfact(const Arg *arg)
+ f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f;
+ if (f < 0.1 || f > 0.9)
+ return;
+- selmon->mfact = f;
++ selmon->mfact = pertag.mfacts[selmon->pertag[selmon->seltags]] = f;
+ arrange(selmon);
+ }
+
+@@ -2504,6 +2548,10 @@ setsel(struct wl_listener *listener, void *data)
+ void
+ setup(void)
+ {
++ const TagRule *r;
++ struct xkb_context *context;
++ struct xkb_keymap *keymap;
++
+ int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
+ struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
+ sigemptyset(&sa.sa_mask);
+@@ -2596,6 +2644,19 @@ setup(void)
+ LISTEN_STATIC(&output_layout->events.change, updatemons);
+ wlr_xdg_output_manager_v1_create(dpy, output_layout);
+
++ for (i = 0; i <= TAGCOUNT; i++) {
++ for (r = tagrules; r < END(tagrules); r++) {
++ if (!r->tag || r->tag == i) {
++ pertag.mfacts[i] = r->mfact;
++ pertag.nmasters[i] = r->nmaster;
++ pertag.sellts[i] = 0;
++ pertag.ltidxs[i][0] = r->lt;
++ pertag.ltidxs[i][1] = r->lt;
++ break;
++ }
++ }
++ }
++
+ /* Configure a listener to be notified when new outputs are available on the
+ * backend. */
+ wl_list_init(&mons);
+@@ -2857,6 +2918,12 @@ toggleview(const Arg *arg)
+ if (m !=selmon && newtagset & m->tagset[m->seltags])
+ return;
+
++ // set new pertag tag only if the tag we were at was removed, or if all tags are shown.
++ if (!(newtagset & 1 << (selmon->pertag[selmon->seltags] - 1)) || newtagset == TAGMASK) {
++ selmon->pertag[selmon->seltags] = getpertagtag(newtagset);
++ }
++
++ applypertag(selmon);
+ selmon->tagset[selmon->seltags] = newtagset;
+ attachclients(selmon);
+ focusclient(focustop(selmon), 1);
+@@ -3072,6 +3139,8 @@ view(const Arg *arg)
+ }
+ m->seltags ^= 1;
+ m->tagset[m->seltags] = origm->tagset[origm->seltags];
++ m->pertag[m->seltags] = origm->pertag[origm->seltags];
++ applypertag(m);
+ attachclients(m);
+ /* Beware: this changes selmon */
+ focusclient(focustop(m), 1);
+@@ -3081,11 +3150,14 @@ view(const Arg *arg)
+ }
+
+ origm->seltags ^= 1; /* toggle sel tagset */
+- if (arg->ui & TAGMASK)
++ if (arg->ui & TAGMASK) {
+ origm->tagset[origm->seltags] = arg->ui & TAGMASK;
++ origm->pertag[origm->seltags] = getpertagtag(arg->ui & TAGMASK);
++ }
+
+ /* Change selmon back to orig mon */
+ selmon = origm;
++ applypertag(origm);
+ attachclients(origm);
+ focusclient(focustop(origm), 1);
+ arrange(origm);
+--
+2.45.2
+