summaryrefslogtreecommitdiff
path: root/dwl/dwl-patches/patches/singletagset
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
Diffstat (limited to 'dwl/dwl-patches/patches/singletagset')
-rwxr-xr-xdwl/dwl-patches/patches/singletagset/README.md19
-rwxr-xr-xdwl/dwl-patches/patches/singletagset/singletagset-v0.6.patch293
-rwxr-xr-xdwl/dwl-patches/patches/singletagset/singletagset-v0.7.patch312
3 files changed, 624 insertions, 0 deletions
diff --git a/dwl/dwl-patches/patches/singletagset/README.md b/dwl/dwl-patches/patches/singletagset/README.md
new file mode 100755
index 0000000..920d8a4
--- /dev/null
+++ b/dwl/dwl-patches/patches/singletagset/README.md
@@ -0,0 +1,19 @@
+### Description
+Single set of tags shared between multiple monitors.
+
+This patch allows all the tags to be shared between both (or more) monitors.
+So a single set of tags from 1 to 9 can be viewed on any monitor, as opposed to
+having separate tag sets 1 to 9 on each monitor.
+
+Originally based on the dwm single_tagset patch:
+https://dwm.suckless.org/patches/single_tagset/
+
+### Download
+- [git branch (v0.7)](https://codeberg.org/Rutherther/dwl/src/branch/v0.7/singletagset)
+- [git branch (v0.6)](https://codeberg.org/bencc/dwl/src/branch/singletagset)
+- [2024-07-26 (v0.7)](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/singletagset/singletagset-v0.7.patch)
+- [2024-05-16 (v0.6)](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/singletagset/singletagset-v0.6.patch)
+
+### Authors
+- [Ben Collerson](https://codeberg.org/bencc)
+- [Rutherther](https://codeberg.org/Rutherther)
diff --git a/dwl/dwl-patches/patches/singletagset/singletagset-v0.6.patch b/dwl/dwl-patches/patches/singletagset/singletagset-v0.6.patch
new file mode 100755
index 0000000..708774b
--- /dev/null
+++ b/dwl/dwl-patches/patches/singletagset/singletagset-v0.6.patch
@@ -0,0 +1,293 @@
+From 140fe587bf34cf43e44acaf365b16ec3e385f742 Mon Sep 17 00:00:00 2001
+From: Ben Collerson <benc@benc.cc>
+Date: Thu, 16 May 2024 09:56:58 +1000
+Subject: [PATCH] singletagset
+
+---
+ dwl.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 140 insertions(+), 10 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index bf763dfc..5b1d594f 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -72,6 +72,7 @@
+ #define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5)))
+ #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
+ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
++#define SVISIBLEON(C, M) ((M) && (C)->mon && ((C)->tags & (M)->tagset[(M)->seltags]))
+ #define LENGTH(X) (sizeof X / sizeof X[0])
+ #define END(A) ((A) + LENGTH(A))
+ #define TAGMASK ((1u << TAGCOUNT) - 1)
+@@ -246,6 +247,7 @@ static void arrange(Monitor *m);
+ static void arrangelayer(Monitor *m, struct wl_list *list,
+ struct wlr_box *usable_area, int exclusive);
+ static void arrangelayers(Monitor *m);
++static void attachclients(Monitor *m);
+ static void axisnotify(struct wl_listener *listener, void *data);
+ static void buttonpress(struct wl_listener *listener, void *data);
+ static void chvt(const Arg *arg);
+@@ -283,6 +285,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 size_t getunusedtag(void);
+ static void handlesig(int signo);
+ static void incnmaster(const Arg *arg);
+ static void inputdevice(struct wl_listener *listener, void *data);
+@@ -470,7 +473,18 @@ applyrules(Client *c)
+ }
+ }
+ }
++ wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]);
++
++ wl_list_for_each(m, &mons, link) {
++ // tag with different monitor selected by rules
++ if (m->tagset[m->seltags] & newtags) {
++ mon = m;
++ break;
++ }
++ }
++
+ setmon(c, mon, newtags);
++ attachclients(mon);
+ }
+
+ void
+@@ -558,6 +572,45 @@ arrangelayers(Monitor *m)
+ }
+ }
+
++void
++attachclients(Monitor *m)
++{
++ Monitor *tm;
++ unsigned int utags = 0;
++ Client *c;
++ int rmons = 0;
++
++ if (m == NULL) {
++ return;
++ }
++
++ wl_list_for_each(tm, &mons, link) {
++ if (tm != m) {
++ utags |= tm->tagset[tm->seltags];
++ }
++ }
++
++ wl_list_for_each(c, &clients, link) {
++ if (SVISIBLEON(c, m)) {
++ /* if client is also visible on other tags that are displayed on
++ * other monitors, remove these tags */
++ if (c->tags & utags) {
++ c->tags = c->tags & m->tagset[m->seltags];
++ rmons = 1;
++ }
++ setmon(c, m, c->tags);
++ }
++ }
++
++ if (rmons) {
++ wl_list_for_each(tm, &mons, link) {
++ if (tm != m) {
++ arrange(tm);
++ }
++ }
++ }
++}
++
+ void
+ axisnotify(struct wl_listener *listener, void *data)
+ {
+@@ -881,7 +934,7 @@ 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;
++ m->tagset[0] = m->tagset[1] = (1<<getunusedtag()) & TAGMASK;
+ for (r = monrules; r < END(monrules); r++) {
+ if (!r->name || strstr(wlr_output->name, r->name)) {
+ m->m.x = r->x;
+@@ -1354,7 +1407,7 @@ focustop(Monitor *m)
+ {
+ Client *c;
+ wl_list_for_each(c, &fstack, flink) {
+- if (VISIBLEON(c, m))
++ if (SVISIBLEON(c, m))
+ return c;
+ }
+ return NULL;
+@@ -1367,6 +1420,29 @@ fullscreennotify(struct wl_listener *listener, void *data)
+ setfullscreen(c, client_wants_fullscreen(c));
+ }
+
++size_t
++getunusedtag(void)
++{
++ size_t i = 0;
++ Monitor *m;
++ if (wl_list_empty(&mons)) {
++ return i;
++ }
++ for (i=0; i < TAGCOUNT; i++) {
++ int is_used = 0;
++ wl_list_for_each(m, &mons, link) {
++ if ((m->tagset[m->seltags] & (1<<i))) {
++ is_used = 1;
++ }
++ }
++
++ if (!is_used) {
++ return i;
++ }
++ }
++ return i;
++}
++
+ void
+ handlesig(int signo)
+ {
+@@ -1915,8 +1991,6 @@ printstatus(void)
+ wl_list_for_each(m, &mons, link) {
+ occ = urg = 0;
+ wl_list_for_each(c, &clients, link) {
+- if (c->mon != m)
+- continue;
+ occ |= c->tags;
+ if (c->isurgent)
+ urg |= c->tags;
+@@ -2551,6 +2625,7 @@ startdrag(struct wl_listener *listener, void *data)
+ void
+ tag(const Arg *arg)
+ {
++ Monitor *m;
+ Client *sel = focustop(selmon);
+ if (!sel || (arg->ui & TAGMASK) == 0)
+ return;
+@@ -2558,15 +2633,25 @@ tag(const Arg *arg)
+ sel->tags = arg->ui & TAGMASK;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
++ wl_list_for_each(m, &mons, link) {
++ attachclients(m);
++ arrange(m);
++ }
+ printstatus();
+ }
+
+ void
+ tagmon(const Arg *arg)
+ {
++ Monitor *m;
+ Client *sel = focustop(selmon);
+- if (sel)
++ if (sel) {
+ setmon(sel, dirtomon(arg->i), 0);
++ wl_list_for_each(m, &mons, link) {
++ arrange(m);
++ }
++ focusclient(focustop(sel->mon), 1);
++ }
+ }
+
+ void
+@@ -2623,12 +2708,18 @@ togglefullscreen(const Arg *arg)
+ void
+ toggletag(const Arg *arg)
+ {
++ Monitor *m;
+ uint32_t newtags;
+ Client *sel = focustop(selmon);
+ if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
+ return;
+
++ wl_list_for_each(m, &mons, link)
++ if (m != selmon && newtags & m->tagset[m->seltags])
++ return;
++
+ sel->tags = newtags;
++ attachclients(selmon);
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+@@ -2637,11 +2728,17 @@ toggletag(const Arg *arg)
+ void
+ toggleview(const Arg *arg)
+ {
++ Monitor *m;
+ uint32_t newtagset;
+ if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0))
+ return;
+
++ wl_list_for_each(m, &mons, link)
++ if (m !=selmon && newtagset & m->tagset[m->seltags])
++ return;
++
+ selmon->tagset[selmon->seltags] = newtagset;
++ attachclients(selmon);
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+@@ -2759,6 +2856,7 @@ updatemons(struct wl_listener *listener, void *data)
+ wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height);
+ }
+
++ attachclients(m);
+ /* Calculate the effective monitor geometry to use for clients */
+ arrangelayers(m);
+ /* Don't move clients to the left output when plugging monitors */
+@@ -2825,13 +2923,45 @@ urgent(struct wl_listener *listener, void *data)
+ void
+ view(const Arg *arg)
+ {
+- if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
++ Monitor *m, *origm = selmon;
++ unsigned int newtags;
++
++ if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) {
+ return;
+- selmon->seltags ^= 1; /* toggle sel tagset */
++ }
++
++ newtags = origm->tagset[origm->seltags ^ 1];
++
++ /* swap tags when trying to display a tag from another monitor */
++ if (arg->ui & TAGMASK) {
++ newtags = arg->ui & TAGMASK;
++ }
++ wl_list_for_each(m, &mons, link) {
++ if (m != origm && newtags & m->tagset[m->seltags]) {
++ /* prevent displaying all tags (MODKEY-0) when multiple monitors
++ * are connected */
++ if (newtags & origm->tagset[origm->seltags]) {
++ return;
++ }
++ m->seltags ^= 1;
++ m->tagset[m->seltags] = origm->tagset[origm->seltags];
++ attachclients(m);
++ /* Beware: this changes selmon */
++ focusclient(focustop(m), 1);
++ arrange(m);
++ break;
++ }
++ }
++
++ origm->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK)
+- selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+- focusclient(focustop(selmon), 1);
+- arrange(selmon);
++ origm->tagset[origm->seltags] = arg->ui & TAGMASK;
++
++ /* Change selmon back to orig mon */
++ selmon = origm;
++ attachclients(origm);
++ focusclient(focustop(origm), 1);
++ arrange(origm);
+ printstatus();
+ }
+
+--
+2.43.0
+
diff --git a/dwl/dwl-patches/patches/singletagset/singletagset-v0.7.patch b/dwl/dwl-patches/patches/singletagset/singletagset-v0.7.patch
new file mode 100755
index 0000000..9c2f98b
--- /dev/null
+++ b/dwl/dwl-patches/patches/singletagset/singletagset-v0.7.patch
@@ -0,0 +1,312 @@
+From bd90ec504369a69dbefc34cb72265d15c7795944 Mon Sep 17 00:00:00 2001
+From: Rutherther <rutherther@proton.me>
+Date: Fri, 26 Jul 2024 12:36:41 +0200
+Subject: [PATCH] singletagset
+
+---
+ dwl.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 145 insertions(+), 10 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index 5bf995e..40a6e48 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -74,6 +74,7 @@
+ #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 SVISIBLEON(C, M) ((M) && (C)->mon && ((C)->tags & (M)->tagset[(M)->seltags]))
+ #define LENGTH(X) (sizeof X / sizeof X[0])
+ #define END(A) ((A) + LENGTH(A))
+ #define TAGMASK ((1u << TAGCOUNT) - 1)
+@@ -249,6 +250,7 @@ static void arrange(Monitor *m);
+ static void arrangelayer(Monitor *m, struct wl_list *list,
+ struct wlr_box *usable_area, int exclusive);
+ static void arrangelayers(Monitor *m);
++static void attachclients(Monitor *m);
+ static void axisnotify(struct wl_listener *listener, void *data);
+ static void buttonpress(struct wl_listener *listener, void *data);
+ static void chvt(const Arg *arg);
+@@ -291,6 +293,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 size_t getunusedtag(void);
+ static void handlesig(int signo);
+ static void incnmaster(const Arg *arg);
+ static void inputdevice(struct wl_listener *listener, void *data);
+@@ -478,7 +481,17 @@ applyrules(Client *c)
+ }
+ }
+ }
++
++ wl_list_for_each(m, &mons, link) {
++ // tag with different monitor selected by rules
++ if (m->tagset[m->seltags] & newtags) {
++ mon = m;
++ break;
++ }
++ }
++
+ setmon(c, mon, newtags);
++ attachclients(mon);
+ }
+
+ void
+@@ -580,6 +593,45 @@ arrangelayers(Monitor *m)
+ }
+ }
+
++void
++attachclients(Monitor *m)
++{
++ Monitor *tm;
++ unsigned int utags = 0;
++ Client *c;
++ int rmons = 0;
++
++ if (m == NULL) {
++ return;
++ }
++
++ wl_list_for_each(tm, &mons, link) {
++ if (tm != m) {
++ utags |= tm->tagset[tm->seltags];
++ }
++ }
++
++ wl_list_for_each(c, &clients, link) {
++ if (SVISIBLEON(c, m)) {
++ /* if client is also visible on other tags that are displayed on
++ * other monitors, remove these tags */
++ if (c->tags & utags) {
++ c->tags = c->tags & m->tagset[m->seltags];
++ rmons = 1;
++ }
++ setmon(c, m, c->tags);
++ }
++ }
++
++ if (rmons) {
++ wl_list_for_each(tm, &mons, link) {
++ if (tm != m) {
++ arrange(tm);
++ }
++ }
++ }
++}
++
+ void
+ axisnotify(struct wl_listener *listener, void *data)
+ {
+@@ -750,6 +802,9 @@ closemon(Monitor *m)
+ if (c->mon == m)
+ setmon(c, selmon, c->tags);
+ }
++
++ m->tagset[0] = m->tagset[1] = 0;
++
+ focusclient(focustop(selmon), 1);
+ printstatus();
+ }
+@@ -990,7 +1045,7 @@ 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;
++ m->tagset[0] = m->tagset[1] = (1<<getunusedtag()) & TAGMASK;
+ for (r = monrules; r < END(monrules); r++) {
+ if (!r->name || strstr(wlr_output->name, r->name)) {
+ m->m.x = r->x;
+@@ -1456,7 +1511,7 @@ focustop(Monitor *m)
+ {
+ Client *c;
+ wl_list_for_each(c, &fstack, flink) {
+- if (VISIBLEON(c, m))
++ if (SVISIBLEON(c, m))
+ return c;
+ }
+ return NULL;
+@@ -1469,6 +1524,29 @@ fullscreennotify(struct wl_listener *listener, void *data)
+ setfullscreen(c, client_wants_fullscreen(c));
+ }
+
++size_t
++getunusedtag(void)
++{
++ size_t i = 0;
++ Monitor *m;
++ if (wl_list_empty(&mons)) {
++ return i;
++ }
++ for (i=0; i < TAGCOUNT; i++) {
++ int is_used = 0;
++ wl_list_for_each(m, &mons, link) {
++ if ((m->tagset[m->seltags] & (1<<i))) {
++ is_used = 1;
++ }
++ }
++
++ if (!is_used) {
++ return i;
++ }
++ }
++ return i;
++}
++
+ void
+ gpureset(struct wl_listener *listener, void *data)
+ {
+@@ -2042,8 +2120,6 @@ printstatus(void)
+ wl_list_for_each(m, &mons, link) {
+ occ = urg = 0;
+ wl_list_for_each(c, &clients, link) {
+- if (c->mon != m)
+- continue;
+ occ |= c->tags;
+ if (c->isurgent)
+ urg |= c->tags;
+@@ -2669,6 +2745,7 @@ startdrag(struct wl_listener *listener, void *data)
+ void
+ tag(const Arg *arg)
+ {
++ Monitor *m;
+ Client *sel = focustop(selmon);
+ if (!sel || (arg->ui & TAGMASK) == 0)
+ return;
+@@ -2676,15 +2753,25 @@ tag(const Arg *arg)
+ sel->tags = arg->ui & TAGMASK;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
++ wl_list_for_each(m, &mons, link) {
++ attachclients(m);
++ arrange(m);
++ }
+ printstatus();
+ }
+
+ void
+ tagmon(const Arg *arg)
+ {
++ Monitor *m;
+ Client *sel = focustop(selmon);
+- if (sel)
++ if (sel) {
+ setmon(sel, dirtomon(arg->i), 0);
++ wl_list_for_each(m, &mons, link) {
++ arrange(m);
++ }
++ focusclient(focustop(sel->mon), 1);
++ }
+ }
+
+ void
+@@ -2741,12 +2828,18 @@ togglefullscreen(const Arg *arg)
+ void
+ toggletag(const Arg *arg)
+ {
++ Monitor *m;
+ uint32_t newtags;
+ Client *sel = focustop(selmon);
+ if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
+ return;
+
++ wl_list_for_each(m, &mons, link)
++ if (m != selmon && newtags & m->tagset[m->seltags])
++ return;
++
+ sel->tags = newtags;
++ attachclients(selmon);
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+@@ -2755,11 +2848,17 @@ toggletag(const Arg *arg)
+ void
+ toggleview(const Arg *arg)
+ {
++ Monitor *m;
+ uint32_t newtagset;
+ if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0))
+ return;
+
++ wl_list_for_each(m, &mons, link)
++ if (m !=selmon && newtagset & m->tagset[m->seltags])
++ return;
++
+ selmon->tagset[selmon->seltags] = newtagset;
++ attachclients(selmon);
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+@@ -2863,6 +2962,9 @@ updatemons(struct wl_listener *listener, void *data)
+ continue;
+ config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
+
++ if ((m->tagset[0] & TAGMASK) == 0 && (m->tagset[1] & TAGMASK) == 0)
++ m->tagset[0] = m->tagset[1] = (1 << getunusedtag()) & TAGMASK;
++
+ /* Get the effective monitor geometry to use for surfaces */
+ wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
+ m->w = m->m;
+@@ -2877,6 +2979,7 @@ updatemons(struct wl_listener *listener, void *data)
+ wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height);
+ }
+
++ attachclients(m);
+ /* Calculate the effective monitor geometry to use for clients */
+ arrangelayers(m);
+ /* Don't move clients to the left output when plugging monitors */
+@@ -2947,13 +3050,45 @@ urgent(struct wl_listener *listener, void *data)
+ void
+ view(const Arg *arg)
+ {
+- if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
++ Monitor *m, *origm = selmon;
++ unsigned int newtags;
++
++ if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) {
+ return;
+- selmon->seltags ^= 1; /* toggle sel tagset */
++ }
++
++ newtags = origm->tagset[origm->seltags ^ 1];
++
++ /* swap tags when trying to display a tag from another monitor */
++ if (arg->ui & TAGMASK) {
++ newtags = arg->ui & TAGMASK;
++ }
++ wl_list_for_each(m, &mons, link) {
++ if (m != origm && newtags & m->tagset[m->seltags]) {
++ /* prevent displaying all tags (MODKEY-0) when multiple monitors
++ * are connected */
++ if (newtags & origm->tagset[origm->seltags]) {
++ return;
++ }
++ m->seltags ^= 1;
++ m->tagset[m->seltags] = origm->tagset[origm->seltags];
++ attachclients(m);
++ /* Beware: this changes selmon */
++ focusclient(focustop(m), 1);
++ arrange(m);
++ break;
++ }
++ }
++
++ origm->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK)
+- selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+- focusclient(focustop(selmon), 1);
+- arrange(selmon);
++ origm->tagset[origm->seltags] = arg->ui & TAGMASK;
++
++ /* Change selmon back to orig mon */
++ selmon = origm;
++ attachclients(origm);
++ focusclient(focustop(origm), 1);
++ arrange(origm);
+ printstatus();
+ }
+
+--
+2.45.2
+