You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
patches/dwm/dwm-single_tagset-6.3.diff

542 lines
16 KiB
Diff

From 8591e832ea3c584841dfaf71c9e87aea8f01ce9e Mon Sep 17 00:00:00 2001
From: Bakkeby <bakkeby@gmail.com>
Date: Mon, 10 Jan 2022 13:40:01 +0100
Subject: [PATCH] Adding single tagset
Author: Jan Christoph Ebersbach <jceb@e-jc.de>
URL: http://dwm.suckless.org/patches/single_tagset
This patch addresses the multi-monitor setup. Instead of having separate tags
for every monitor there is just one list of tags for all monitors. Instead of
moving windows from one monitor to the other, the desired tag from the
other monitor can just be selected and all windows will be drawn on the
current monitor.
Several deep changes needed to be made:
1. Macro ISVISIBLE expects a second parameter, the monitor
2. Monitor->clients and Monitor->stack were moved to the global variable
Clientlist cl. All monitors refer to this one list.
3. A new method attachclients was added. When changing between tags this
function ensures that all clients are pointing to the right monitor.
Please be aware that this patch probably breaks any other patch!
---
dwm.c | 214 +++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 159 insertions(+), 55 deletions(-)
diff --git a/dwm.c b/dwm.c
index a96f33c..81eec26 100644
--- a/dwm.c
+++ b/dwm.c
@@ -49,7 +49,7 @@
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
-#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+#define ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
@@ -82,6 +82,7 @@ typedef struct {
const Arg arg;
} Button;
+typedef struct Clientlist Clientlist;
typedef struct Monitor Monitor;
typedef struct Client Client;
struct Client {
@@ -124,14 +125,18 @@ struct Monitor {
unsigned int tagset[2];
int showbar;
int topbar;
- Client *clients;
+ Clientlist *cl;
Client *sel;
- Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
};
+struct Clientlist {
+ Client *clients;
+ Client *stack;
+};
+
typedef struct {
const char *class;
const char *instance;
@@ -147,6 +152,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
static void attach(Client *c);
+static void attachclients(Monitor *m);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
@@ -184,7 +190,7 @@ static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
-static Client *nexttiled(Client *c);
+static Client *nexttiled(Client *c, Monitor *m);
static void pop(Client *);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
@@ -268,6 +274,7 @@ static Display *dpy;
static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
+static Clientlist *cl;
/* configuration, allows nested code to access above variables */
#include "config.h"
@@ -300,7 +307,7 @@ applyrules(Client *c)
{
c->isfloating = r->isfloating;
c->tags |= r->tags;
- for (m = mons; m && m->num != r->monitor; m = m->next);
+ for (m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next) ;
if (m)
c->mon = m;
}
@@ -382,9 +389,9 @@ void
arrange(Monitor *m)
{
if (m)
- showhide(m->stack);
+ showhide(m->cl->stack);
else for (m = mons; m; m = m->next)
- showhide(m->stack);
+ showhide(m->cl->stack);
if (m) {
arrangemon(m);
restack(m);
@@ -403,15 +410,48 @@ arrangemon(Monitor *m)
void
attach(Client *c)
{
- c->next = c->mon->clients;
- c->mon->clients = c;
+ c->next = c->mon->cl->clients;
+ c->mon->cl->clients = c;
+}
+
+void
+attachclients(Monitor *m) {
+ /* attach clients to the specified monitor */
+ Monitor *tm;
+ Client *c;
+ unsigned int utags = 0;
+ Bool rmons = False;
+ if (!m)
+ return;
+
+ /* collect information about the tags in use */
+ for (tm = mons; tm; tm = tm->next)
+ if(tm != m)
+ utags |= tm->tagset[tm->seltags];
+
+ for (c = m->cl->clients; c; c = c->next)
+ if (ISVISIBLE(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 = True;
+ }
+ unfocus(c, True);
+ c->mon = m;
+ }
+
+ if (rmons)
+ for (tm = mons; tm; tm = tm->next)
+ if(tm != m)
+ arrange(tm);
}
void
attachstack(Client *c)
{
- c->snext = c->mon->stack;
- c->mon->stack = c;
+ c->snext = c->mon->cl->stack;
+ c->mon->cl->stack = c;
}
void
@@ -478,8 +518,8 @@ cleanup(void)
view(&a);
selmon->lt[selmon->sellt] = &foo;
for (m = mons; m; m = m->next)
- while (m->stack)
- unmanage(m->stack, 0);
+ while (m->cl->stack)
+ unmanage(m->cl->stack, 0);
XUngrabKey(dpy, AnyKey, AnyModifier, root);
while (mons)
cleanupmon(mons);
@@ -565,7 +605,7 @@ configurenotify(XEvent *e)
drw_resize(drw, sw, bh);
updatebars();
for (m = mons; m; m = m->next) {
- for (c = m->clients; c; c = c->next)
+ for (c = m->cl->clients; c; c = c->next)
if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
@@ -611,7 +651,7 @@ configurerequest(XEvent *e)
c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
configure(c);
- if (ISVISIBLE(c))
+ if (ISVISIBLE(c, m))
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
} else
configure(c);
@@ -631,10 +671,32 @@ configurerequest(XEvent *e)
Monitor *
createmon(void)
{
- Monitor *m;
+ Monitor *m, *tm;
+ int i;
+
+ /* bail out if the number of monitors exceeds the number of tags */
+ for (i=1, tm=mons; tm; i++, tm=tm->next);
+ if (i > LENGTH(tags)) {
+ fprintf(stderr, "dwm: failed to add monitor, number of tags exceeded\n");
+ return NULL;
+ }
+ /* find the first tag that isn't in use */
+ for (i=0; i < LENGTH(tags); i++) {
+ for (tm=mons; tm && !(tm->tagset[tm->seltags] & (1<<i)); tm=tm->next);
+ if (!tm)
+ break;
+ }
+ /* reassign all tags to monitors since there's currently no free tag for the
+ * new monitor */
+ if (i >= LENGTH(tags))
+ for (i=0, tm=mons; tm; tm=tm->next, i++) {
+ tm->seltags ^= 1;
+ tm->tagset[tm->seltags] = (1<<i) & TAGMASK;
+ }
m = ecalloc(1, sizeof(Monitor));
- m->tagset[0] = m->tagset[1] = 1;
+ m->cl = cl;
+ m->tagset[0] = m->tagset[1] = (1<<i) & TAGMASK;
m->mfact = mfact;
m->nmaster = nmaster;
m->showbar = showbar;
@@ -660,7 +722,7 @@ detach(Client *c)
{
Client **tc;
- for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
+ for (tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next);
*tc = c->next;
}
@@ -669,11 +731,11 @@ detachstack(Client *c)
{
Client **tc, *t;
- for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
+ for (tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext);
*tc = c->snext;
if (c == c->mon->sel) {
- for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
+ for (t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext);
c->mon->sel = t;
}
}
@@ -712,7 +774,7 @@ drawbar(Monitor *m)
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
}
- for (c = m->clients; c; c = c->next) {
+ for (c = m->cl->clients; c; c = c->next) {
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
@@ -787,8 +849,8 @@ expose(XEvent *e)
void
focus(Client *c)
{
- if (!c || !ISVISIBLE(c))
- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
+ if (!c || !ISVISIBLE(c, selmon))
+ for (c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext);
if (selmon->sel && selmon->sel != c)
unfocus(selmon->sel, 0);
if (c) {
@@ -841,16 +903,16 @@ focusstack(const Arg *arg)
if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
return;
if (arg->i > 0) {
- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
+ for (c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next);
if (!c)
- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
+ for (c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next);
} else {
- for (i = selmon->clients; i != selmon->sel; i = i->next)
- if (ISVISIBLE(i))
+ for (i = selmon->cl->clients; i != selmon->sel; i = i->next)
+ if (ISVISIBLE(i, selmon))
c = i;
if (!c)
for (; i; i = i->next)
- if (ISVISIBLE(i))
+ if (ISVISIBLE(i, selmon))
c = i;
}
if (c) {
@@ -1110,12 +1172,12 @@ monocle(Monitor *m)
unsigned int n = 0;
Client *c;
- for (c = m->clients; c; c = c->next)
- if (ISVISIBLE(c))
+ for (c = m->cl->clients; c; c = c->next)
+ if (ISVISIBLE(c, m))
n++;
if (n > 0) /* override layout symbol */
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
- for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
+ for (c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m))
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
}
@@ -1197,9 +1259,9 @@ movemouse(const Arg *arg)
}
Client *
-nexttiled(Client *c)
+nexttiled(Client *c, Monitor *m)
{
- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
+ for (; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next);
return c;
}
@@ -1363,8 +1425,8 @@ restack(Monitor *m)
if (m->lt[m->sellt]->arrange) {
wc.stack_mode = Below;
wc.sibling = m->barwin;
- for (c = m->stack; c; c = c->snext)
- if (!c->isfloating && ISVISIBLE(c)) {
+ for (c = m->cl->stack; c; c = c->snext)
+ if (!c->isfloating && ISVISIBLE(c, m)) {
XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
wc.sibling = c->win;
}
@@ -1417,11 +1479,9 @@ sendmon(Client *c, Monitor *m)
if (c->mon == m)
return;
unfocus(c, 1);
- detach(c);
detachstack(c);
c->mon = m;
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
- attach(c);
attachstack(c);
focus(NULL);
arrange(NULL);
@@ -1544,6 +1604,8 @@ setup(void)
screen = DefaultScreen(dpy);
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
+ if (!(cl = (Clientlist *)calloc(1, sizeof(Clientlist))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist));
root = RootWindow(dpy, screen);
drw = drw_create(dpy, screen, root, sw, sh);
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
@@ -1619,7 +1681,7 @@ showhide(Client *c)
{
if (!c)
return;
- if (ISVISIBLE(c)) {
+ if (ISVISIBLE(c, c->mon)) {
/* show clients top down */
XMoveWindow(dpy, c->win, c->x, c->y);
if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
@@ -1659,7 +1721,22 @@ spawn(const Arg *arg)
void
tag(const Arg *arg)
{
+ Monitor *m;
+ unsigned int newtags;
if (selmon->sel && arg->ui & TAGMASK) {
+ newtags = arg->ui & TAGMASK;
+ for (m = mons; m; m = m->next)
+ /* if tag is visible on another monitor, move client to the new monitor */
+ if (m != selmon && m->tagset[m->seltags] & newtags) {
+ /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */
+ if(newtags & selmon->tagset[selmon->seltags])
+ return;
+ selmon->sel->tags = newtags;
+ selmon->sel->mon = m;
+ arrange(m);
+ break;
+ }
+ /* workaround in case just one monitor is connected */
selmon->sel->tags = arg->ui & TAGMASK;
focus(NULL);
arrange(selmon);
@@ -1680,7 +1757,7 @@ tile(Monitor *m)
unsigned int i, n, h, mw, my, ty;
Client *c;
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ for (n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++);
if (n == 0)
return;
@@ -1688,7 +1765,7 @@ tile(Monitor *m)
mw = m->nmaster ? m->ww * m->mfact : 0;
else
mw = m->ww;
- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ for (i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++)
if (i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
@@ -1728,12 +1805,17 @@ togglefloating(const Arg *arg)
void
toggletag(const Arg *arg)
{
+ Monitor *m;
unsigned int newtags;
if (!selmon->sel)
return;
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
if (newtags) {
+ /* prevent adding tags that are in use on other monitors */
+ for (m = mons; m; m = m->next)
+ if (m != selmon && newtags & m->tagset[m->seltags])
+ return;
selmon->sel->tags = newtags;
focus(NULL);
arrange(selmon);
@@ -1743,12 +1825,17 @@ toggletag(const Arg *arg)
void
toggleview(const Arg *arg)
{
+ Monitor *m;
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
if (newtagset) {
+ /* prevent displaying the same tags on multiple monitors */
+ for(m = mons; m; m = m->next)
+ if(m != selmon && newtagset & m->tagset[m->seltags])
+ return;
selmon->tagset[selmon->seltags] = newtagset;
focus(NULL);
- arrange(selmon);
+ attachclients(selmon);
}
}
@@ -1847,7 +1934,7 @@ updateclientlist()
XDeleteProperty(dpy, root, netatom[NetClientList]);
for (m = mons; m; m = m->next)
- for (c = m->clients; c; c = c->next)
+ for (c = m->cl->clients; c; c = c->next)
XChangeProperty(dpy, root, netatom[NetClientList],
XA_WINDOW, 32, PropModeAppend,
(unsigned char *) &(c->win), 1);
@@ -1877,8 +1964,10 @@ updategeom(void)
if (n <= nn) { /* new monitors available */
for (i = 0; i < (nn - n); i++) {
for (m = mons; m && m->next; m = m->next);
- if (m)
+ if (m) {
m->next = createmon();
+ attachclients(m->next);
+ }
else
mons = createmon();
}
@@ -1898,16 +1987,13 @@ updategeom(void)
} else { /* less monitors available nn < n */
for (i = nn; i < n; i++) {
for (m = mons; m && m->next; m = m->next);
- while ((c = m->clients)) {
- dirty = 1;
- m->clients = c->next;
- detachstack(c);
- c->mon = mons;
- attach(c);
- attachstack(c);
- }
if (m == selmon)
selmon = mons;
+ for (c = m->cl->clients; c; c = c->next) {
+ dirty = True;
+ if (c->mon == m)
+ c->mon = selmon;
+ }
cleanupmon(m);
}
}
@@ -2041,13 +2127,31 @@ updatewmhints(Client *c)
void
view(const Arg *arg)
{
+ Monitor *m;
+ unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1];
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
+ /* swap tags when trying to display a tag from another monitor */
+ if (arg->ui & TAGMASK)
+ newtagset = arg->ui & TAGMASK;
+ for (m = mons; m; m = m->next)
+ if (m != selmon && newtagset & m->tagset[m->seltags]) {
+ /* prevent displaying all tags (MODKEY-0) when multiple monitors
+ * are connected */
+ if (newtagset & selmon->tagset[selmon->seltags])
+ return;
+ m->sel = selmon->sel;
+ m->seltags ^= 1;
+ m->tagset[m->seltags] = selmon->tagset[selmon->seltags];
+ attachclients(m);
+ arrange(m);
+ break;
+ }
selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
focus(NULL);
- arrange(selmon);
+ attachclients(selmon);
}
Client *
@@ -2057,7 +2161,7 @@ wintoclient(Window w)
Monitor *m;
for (m = mons; m; m = m->next)
- for (c = m->clients; c; c = c->next)
+ for (c = m->cl->clients; c; c = c->next)
if (c->win == w)
return c;
return NULL;
@@ -2124,8 +2228,8 @@ zoom(const Arg *arg)
if (!selmon->lt[selmon->sellt]->arrange
|| (selmon->sel && selmon->sel->isfloating))
return;
- if (c == nexttiled(selmon->clients))
- if (!c || !(c = nexttiled(c->next)))
+ if (c == nexttiled(selmon->cl->clients, selmon))
+ if (!c || !(c = nexttiled(c->next, selmon)))
return;
pop(c);
}
--
2.19.1