commit 6b795aac38dd2793e9139a332861a3aa04e36887
parent 16fe76f7934965a50deb93aca049769bf77ed697
Author: Jan Christoph Ebersbach <jceb@e-jc.de>
Date: Sun, 9 Feb 2014 20:07:51 +0100
update single tagset patch
Diffstat:
2 files changed, 571 insertions(+), 3 deletions(-)
diff --git a/dwm.suckless.org/patches/dwm-6.1-single_tagset.diff b/dwm.suckless.org/patches/dwm-6.1-single_tagset.diff
@@ -0,0 +1,567 @@
+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!
+
+Index: dwm/dwm.c
+===================================================================
+--- dwm/dwm.c.orig 2014-02-09 15:24:26.156117354 +0100
++++ dwm/dwm.c 2014-02-09 15:24:26.148117354 +0100
+@@ -48,7 +48,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)
+@@ -110,6 +110,7 @@
+ void (*arrange)(Monitor *);
+ } Layout;
+
++typedef struct Clientlist Clientlist;
+ struct Monitor {
+ char ltsymbol[16];
+ float mfact;
+@@ -123,9 +124,8 @@
+ unsigned int tagset[2];
+ Bool showbar;
+ Bool topbar;
+- Client *clients;
++ Clientlist *cl;
+ Client *sel;
+- Client *stack;
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
+@@ -140,12 +140,18 @@
+ int monitor;
+ } Rule;
+
++struct Clientlist {
++ Client *clients;
++ Client *stack;
++};
++
+ /* function declarations */
+ static void applyrules(Client *c);
+ static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
+ 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);
+@@ -183,7 +189,7 @@
+ 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);
+@@ -266,6 +272,7 @@
+ static Fnt *fnt;
+ static Monitor *mons, *selmon;
+ static Window root;
++static Clientlist *cl;
+
+ /* configuration, allows nested code to access above variables */
+ #include "config.h"
+@@ -296,7 +303,7 @@
+ {
+ 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;
+ }
+@@ -377,9 +384,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);
+@@ -396,14 +403,47 @@
+
+ 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 |= m->tagset[m->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
+@@ -466,8 +506,8 @@
+ view(&a);
+ selmon->lt[selmon->sellt] = &foo;
+ for(m = mons; m; m = m->next)
+- while(m->stack)
+- unmanage(m->stack, False);
++ while(m->cl->stack)
++ unmanage(m->cl->stack, False);
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ while(mons)
+ cleanupmon(mons);
+@@ -527,7 +567,7 @@
+ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+ }
+ else if(cme->message_type == netatom[NetActiveWindow]) {
+- if(!ISVISIBLE(c)) {
++ if(!ISVISIBLE(c, c->mon)) {
+ c->mon->seltags ^= 1;
+ c->mon->tagset[c->mon->seltags] = c->tags;
+ }
+@@ -609,7 +649,7 @@
+ 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
+@@ -630,11 +670,18 @@
+
+ Monitor *
+ createmon(void) {
+- Monitor *m;
++ Monitor *m, *tm;
++ int i;
+
+ if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
+- m->tagset[0] = m->tagset[1] = 1;
++ m->cl = cl;
++ /* reassing tags when creating a new monitor */
++ for(i=1, tm = mons; tm; tm = tm->next, i++) {
++ tm->seltags ^= 1;
++ tm->tagset[tm->seltags] = i;
++ }
++ m->tagset[0] = m->tagset[1] = i;
+ m->mfact = mfact;
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+@@ -658,7 +705,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;
+ }
+
+@@ -666,11 +713,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;
+ }
+ }
+@@ -696,7 +743,7 @@
+ unsigned int i, occ = 0, urg = 0;
+ Client *c;
+
+- 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;
+@@ -779,8 +826,8 @@
+
+ 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);
+ /* was if(selmon->sel) */
+ if(selmon->sel && selmon->sel != c)
+ unfocus(selmon->sel, False);
+@@ -832,17 +879,17 @@
+ if(!selmon->sel)
+ 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) {
+@@ -1092,12 +1139,12 @@
+ 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, False);
+ }
+
+@@ -1175,8 +1222,8 @@
+ }
+
+ Client *
+-nexttiled(Client *c) {
+- for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
++nexttiled(Client *c, Monitor *m) {
++ for(; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next);
+ return c;
+ }
+
+@@ -1328,8 +1375,8 @@
+ 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;
+ }
+@@ -1379,7 +1426,6 @@
+ if(c->mon == m)
+ return;
+ unfocus(c, True);
+- detach(c);
+ detachstack(c);
+ c->mon = m;
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
+@@ -1501,6 +1547,8 @@
+ sw = DisplayWidth(dpy, screen);
+ sh = DisplayHeight(dpy, screen);
+ bh = fnt->h + 2;
++ if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist))))
++ die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist));
+ drw = drw_create(dpy, screen, root, sw, sh);
+ drw_setfont(drw, fnt);
+ updategeom();
+@@ -1549,9 +1597,11 @@
+ showhide(Client *c) {
+ if(!c)
+ return;
+- if(ISVISIBLE(c)) { /* show clients top down */
++ 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)
++ if(c->isfloating)
++ keepfloatingposition(c);
+ resize(c, c->x, c->y, c->w, c->h, False);
+ showhide(c->snext);
+ }
+@@ -1585,7 +1635,22 @@
+
+ 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);
+@@ -1604,7 +1669,7 @@
+ 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;
+
+@@ -1612,7 +1677,7 @@
+ 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), False);
+@@ -1648,12 +1713,17 @@
+
+ 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);
+@@ -1662,9 +1732,14 @@
+
+ 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);
+@@ -1703,6 +1778,7 @@
+ XUngrabServer(dpy);
+ }
+ free(c);
++ attachclients(selmon);
+ focus(NULL);
+ updateclientlist();
+ arrange(m);
+@@ -1760,7 +1836,7 @@
+
+ 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);
+@@ -1790,8 +1866,10 @@
+ if(n <= nn) {
+ for(i = 0; i < (nn - n); i++) { /* new monitors available */
+ for(m = mons; m && m->next; m = m->next);
+- if(m)
++ if(m) {
+ m->next = createmon();
++ attachclients(m->next);
++ }
+ else
+ mons = createmon();
+ }
+@@ -1812,17 +1890,13 @@
+ else { /* less monitors available nn < n */
+ for(i = nn; i < n; i++) {
+ for(m = mons; m && m->next; m = m->next);
+- while(m->clients) {
+- dirty = True;
+- c = m->clients;
+- 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);
+ }
+ }
+@@ -1960,11 +2034,31 @@
+
+ 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->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;
++ attachclients(selmon);
+ focus(NULL);
+ arrange(selmon);
+ }
+@@ -1975,7 +2069,7 @@
+ 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;
+@@ -2037,8 +2131,8 @@
+ 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);
+ }
+Index: dwm/config.def.h
+===================================================================
+--- dwm/config.def.h.orig 2014-02-09 15:24:26.156117354 +0100
++++ dwm/config.def.h 2014-02-09 15:24:26.148117354 +0100
+@@ -54,6 +54,7 @@
+ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
+ static const char *termcmd[] = { "st", NULL };
+
++#include "keepfloatingposition.c"
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+Index: dwm/keepfloatingposition.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ dwm/keepfloatingposition.c 2014-02-09 15:24:26.148117354 +0100
+@@ -0,0 +1,30 @@
++static void
++keepfloatingposition(Client *c) {
++ Monitor *m;
++ int cmmx = c->mon->mx;
++ int cmmy = c->mon->my;
++ int cmmw = c->mon->mw;
++ int cmmh = c->mon->mh;
++ int mmx, mmy;
++ if(!(cmmx <= c->x &&
++ cmmx + cmmw - 1 >= c->x &&
++ cmmy <= c->y &&
++ cmmy + cmmh - 1 >= c->y))
++ for(m = mons; m; m = m->next) {
++ mmx = m->mx;
++ mmy = m->my;
++ if(mmx <= c->x &&
++ mmx + m->mw - 1 >= c->x &&
++ mmy <= c->y &&
++ mmy + m->mh - 1 >= c->y) {
++ c->x = c->x - mmx + cmmx;
++ c->y = c->y - mmy + cmmy;
++ if(c->x + c->w + 2 * c->bw > cmmx + cmmw - 1)
++ c->x -= c->x + c->w + 2 * c->bw - cmmx - cmmw;
++ if(c->y + c->h + 2 * c->bw > cmmy + cmmh - 1)
++ c->y -= c->y + c->h + 2 * c->bw - cmmy - cmmh;
++ resizeclient(c, c->x, c->y, c->w, c->h);
++ break;
++ }
++ }
++}
diff --git a/dwm.suckless.org/patches/single_tagset.md b/dwm.suckless.org/patches/single_tagset.md
@@ -22,8 +22,9 @@ Download
Please be aware that this patch probably breaks any other patch!
Patches against different versions of dwm are available at
-[dwm-clean-patches](https://bitbucket.org/jceb81/dwm-clean-patches/src).
+[dwm-clean-patches](https://github.com/jceb/dwm-clean-patches).
+ * [dwm-6.1-single_tagset.diff](dwm-6.1-single_tagset.diff) (16634b) (20140209)
* [dwm-10e232f9ace7-single_tagset.diff](dwm-10e232f9ace7-single_tagset.diff) (14748b) (20120406)
* [dwm-6.0-single_tagset.diff](dwm-6.0-single_tagset.diff) (14417b) (20120406)
@@ -32,7 +33,7 @@ Special Version
This is a special version of the patch that was created with following patches being applied:
* [attachabove](attachabove)
* [float_border_color](float_border_color)
- * [focusmaster](https://bitbucket.org/jceb81/dwm-patches/src/90fb0feedff9/focusmaster.patch)
+ * [focusmaster](https://raw.github.com/jceb/dwm-patches/master/patches/focusmaster.patch)
* [moveresize](moveresize)
* [noborder](noborder)
* [pertag](pertag)
@@ -43,7 +44,7 @@ This is a special version of the patch that was created with following patches b
* [tagall](tagall)
* [zoomswap](zoomswap)
-[dwm-6.0-single_tagset_all.diff](https://bitbucket.org/jceb81/dwm-patches/raw/cc88093b8acb/single_tagset_all.patch)
+[dwm-6.1-single_tagset_all.diff](https://raw.github.com/jceb/dwm-patches/master/patches/single_tagset_all.patch)
Authors
-------