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

