Hello all,

I've been using dwm for a bit on my laptop in both a docked and mobile
configuration, which involves frequent switching between portrait and
landscape monitor layouts. The default tiling mode isn't quite optimal for
this. As a result I've done a bit of work reviving the original flextile
patch by jo...@freenet.de.

This wasn't a pure update on the patch against 5.8.2. As-is, I manually
took code chunks from the original patch, rewrote it a bit to use the
now-included nmaster code, and rolled the per-tag attributes into a
separate struct (much like the pertag patch) to avoid moving the Monitor
struct definition out of dwm.c.

I've attached the current diff, but have not submitted this patch update to
the original wiki entry as I'm unsure of best practice in this case, and I
may experiment with some enhancements.

Best regards,

Jon
diff --git a/config.def.h b/config.def.h
index 875885b..1e941a1 100644
--- a/config.def.h
+++ b/config.def.h
@@ -30,6 +30,11 @@ static const Rule rules[] = {
 static const float mfact      = 0.55; /* factor of master area size 
[0.05..0.95] */
 static const int nmaster      = 1;    /* number of clients in master area */
 static const Bool resizehints = True; /* True means respect size hints in 
tiled resizals */
+static const int  layoutaxis[] = {
+       1,    /* layout axis: 1 = x, 2 = y; negative values mirror the layout */
+       2,    /* master axis: 1 = x (left to right), 2 = y (top to bottom), 3 = 
z (monocle) */
+       2,    /* stack  axis: 1 = x (left to right), 2 = y (top to bottom), 3 = 
z (monocle) */
+};
 
 static const Layout layouts[] = {
        /* symbol     arrange function */
@@ -79,6 +84,10 @@ static Key keys[] = {
        { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
        { MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
        { MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
+       { MODKEY|ShiftMask,             XK_Tab,    rotatelayoutaxis, {.i = 0} 
},    /* 0 = layout axis */
+       { MODKEY|ControlMask,           XK_Tab,    rotatelayoutaxis, {.i = 1} 
},    /* 1 = master axis */
+       { MODKEY|ControlMask|ShiftMask, XK_Tab,    rotatelayoutaxis, {.i = 2} 
},    /* 2 = stack axis */
+       { MODKEY|ControlMask,           XK_Return, mirrorlayout,     {0} },
        TAGKEYS(                        XK_1,                      0)
        TAGKEYS(                        XK_2,                      1)
        TAGKEYS(                        XK_3,                      2)
diff --git a/dwm.c b/dwm.c
index 1bbb4b3..f758b4e 100644
--- a/dwm.c
+++ b/dwm.c
@@ -110,8 +110,10 @@ typedef struct {
        void (*arrange)(Monitor *);
 } Layout;
 
+typedef struct Pertag Pertag;
 struct Monitor {
        char ltsymbol[16];
+       int ltaxis[3];
        float mfact;
        int nmaster;
        int num;
@@ -129,6 +131,7 @@ struct Monitor {
        Monitor *next;
        Window barwin;
        const Layout *lt[2];
+       Pertag *pertag;
 };
 
 typedef struct {
@@ -180,6 +183,7 @@ static void killclient(const Arg *arg);
 static void manage(Window w, XWindowAttributes *wa);
 static void mappingnotify(XEvent *e);
 static void maprequest(XEvent *e);
+static void mirrorlayout(const Arg *arg);
 static void monocle(Monitor *m);
 static void motionnotify(XEvent *e);
 static void movemouse(const Arg *arg);
@@ -192,6 +196,7 @@ static void resize(Client *c, int x, int y, int w, int h, 
Bool interact);
 static void resizeclient(Client *c, int x, int y, int w, int h);
 static void resizemouse(const Arg *arg);
 static void restack(Monitor *m);
+static void rotatelayoutaxis(const Arg *arg);
 static void run(void);
 static void scan(void);
 static Bool sendevent(Client *c, Atom proto);
@@ -270,6 +275,15 @@ static Window root;
 /* configuration, allows nested code to access above variables */
 #include "config.h"
 
+struct Pertag {
+       unsigned int curtag, prevtag;
+       int ltaxes[LENGTH(tags) + 1][3];
+       int nmasters[LENGTH(tags) + 1];
+       float mfacts[LENGTH(tags) + 1];
+       const Layout *lts[LENGTH(tags) + 1];
+       Bool showbars[LENGTH(tags) + 1];
+};
+
 /* compile-time check if all tags fit into an unsigned int bit array. */
 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
 
@@ -631,6 +645,7 @@ configurerequest(XEvent *e) {
 Monitor *
 createmon(void) {
        Monitor *m;
+       unsigned int i;
 
        if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
                die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
@@ -642,6 +657,22 @@ createmon(void) {
        m->lt[0] = &layouts[0];
        m->lt[1] = &layouts[1 % LENGTH(layouts)];
        strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+       m->ltaxis[0] = layoutaxis[0];
+       m->ltaxis[1] = layoutaxis[1];
+       m->ltaxis[2] = layoutaxis[2];
+       if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
+               die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
+       m->pertag->curtag = m->pertag->prevtag = 1;
+       /* init tags, bars, layouts, axes, nmasters, and mfacts */
+       for(i = 0; i < LENGTH(tags) + 1; i++){
+               m->pertag->showbars[i] = m->showbar;
+               m->pertag->lts[i] = &layouts[0];
+               m->pertag->mfacts[i] = m->mfact;
+               m->pertag->ltaxes[i][0] = m->ltaxis[0];
+               m->pertag->ltaxes[i][1] = m->ltaxis[1];
+               m->pertag->ltaxes[i][2] = m->ltaxis[2];
+               m->pertag->nmasters[i] = m->nmaster;
+       }
        return m;
 }
 
@@ -958,7 +989,13 @@ grabkeys(void) {
 
 void
 incnmaster(const Arg *arg) {
-       selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+       unsigned int n;
+       Client *c;
+
+       for(n = 0, c = nexttiled(selmon->clients); c; c = nexttiled(c->next), 
n++);
+       if(!arg || !selmon->lt[selmon->sellt]->arrange || selmon->nmaster + 
arg->i < 1 || selmon->nmaster + arg->i > n)
+               return;
+       selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = 
MAX(selmon->nmaster + arg->i, 0);
        arrange(selmon);
 }
 
@@ -1088,6 +1125,15 @@ maprequest(XEvent *e) {
 }
 
 void
+mirrorlayout(const Arg *arg) {
+       if(!selmon->lt[selmon->sellt]->arrange)
+               return;
+       selmon->ltaxis[0] *= -1;
+       selmon->pertag->ltaxes[selmon->pertag->curtag][0] = selmon->ltaxis[0];
+       arrange(selmon);
+}
+
+void
 monocle(Monitor *m) {
        unsigned int n = 0;
        Client *c;
@@ -1339,6 +1385,22 @@ restack(Monitor *m) {
 }
 
 void
+rotatelayoutaxis(const Arg *arg) {
+       if(!selmon->lt[selmon->sellt]->arrange)
+               return;
+       if(arg->i == 0) {
+               if(selmon->ltaxis[0] > 0)
+                       selmon->ltaxis[0] = selmon->ltaxis[0] + 1 > 2 ? 1 : 
selmon->ltaxis[0] + 1;
+               else
+                       selmon->ltaxis[0] = selmon->ltaxis[0] - 1 < -2 ? -1 : 
selmon->ltaxis[0] - 1;
+       }
+       else
+               selmon->ltaxis[arg->i] = selmon->ltaxis[arg->i] + 1 > 3 ? 1 : 
selmon->ltaxis[arg->i] + 1;
+       selmon->pertag->ltaxes[selmon->pertag->curtag][arg->i] = 
selmon->ltaxis[arg->i];
+       arrange(selmon);
+}
+
+void
 run(void) {
        XEvent ev;
        /* main event loop */
@@ -1465,7 +1527,7 @@ setlayout(const Arg *arg) {
        if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
                selmon->sellt ^= 1;
        if(arg && arg->v)
-               selmon->lt[selmon->sellt] = (Layout *)arg->v;
+               selmon->lt[selmon->sellt] = 
selmon->pertag->lts[selmon->pertag->curtag] = (Layout *)arg->v;
        strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof 
selmon->ltsymbol);
        if(selmon->sel)
                arrange(selmon);
@@ -1483,7 +1545,7 @@ setmfact(const Arg *arg) {
        f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
        if(f < 0.1 || f > 0.9)
                return;
-       selmon->mfact = f;
+       selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
        arrange(selmon);
 }
 
@@ -1601,33 +1663,93 @@ tagmon(const Arg *arg) {
 
 void
 tile(Monitor *m) {
-       unsigned int i, n, h, mw, my, ty;
+       char sym1 = 61, sym2 = 93, sym3 = 61, sym;
+       int x1 = m->wx, y1 = m->wy, h1 = m->wh, w1 = m->ww, X1 = x1 + w1, Y1 = 
y1 + h1;
+       int x2 = m->wx, y2 = m->wy, h2 = m->wh, w2 = m->ww, X2 = x2 + w2, Y2 = 
y2 + h2;
+       unsigned int i, n, n1, n2;
        Client *c;
 
        for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+       if(m->nmaster > n)
+               m->nmaster = (n == 0) ? 1 : n;
+       /* layout symbol */
+       if(abs(m->ltaxis[0]) == m->ltaxis[1])    /* explicitly: 
((abs(m->ltaxis[0]) == 1 && m->ltaxis[1] == 1) || (abs(m->ltaxis[0]) == 2 && 
m->ltaxis[1] == 2)) */
+               sym1 = 124;
+       if(abs(m->ltaxis[0]) == m->ltaxis[2])
+               sym3 = 124;
+       if(m->ltaxis[1] == 3)
+               sym1 = (n == 0) ? 0 : m->nmaster;
+       if(m->ltaxis[2] == 3)
+               sym3 = (n == 0) ? 0 : n - m->nmaster;
+       if(m->ltaxis[0] < 0) {
+               sym = sym1;
+               sym1 = sym3;
+               sym2 = 91;
+               sym3 = sym;
+       }
+       if(m->nmaster == 1) {
+               if(m->ltaxis[0] > 0)
+                       sym1 = 91;
+               else
+                       sym3 = 93;
+       }
+       if(m->nmaster > 1 && m->ltaxis[1] == 3 && m->ltaxis[2] == 3)
+               snprintf(m->ltsymbol, sizeof m->ltsymbol, "%d%c%d", sym1, sym2, 
sym3);
+       else if((m->nmaster > 1 && m->ltaxis[1] == 3 && m->ltaxis[0] > 0) || 
(m->ltaxis[2] == 3 && m->ltaxis[0] < 0))
+               snprintf(m->ltsymbol, sizeof m->ltsymbol, "%d%c%c", sym1, sym2, 
sym3);
+       else if((m->ltaxis[2] == 3 && m->ltaxis[0] > 0) || (m->nmaster > 1 && 
m->ltaxis[1] == 3 && m->ltaxis[0] < 0))
+               snprintf(m->ltsymbol, sizeof m->ltsymbol, "%c%c%d", sym1, sym2, 
sym3);
+       else
+               snprintf(m->ltsymbol, sizeof m->ltsymbol, "%c%c%c", sym1, sym2, 
sym3);
        if(n == 0)
                return;
-
-       if(n > m->nmaster)
-               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++)
-               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);
-                       my += HEIGHT(c);
-               }
-               else {
-                       h = (m->wh - ty) / (n - i);
-                       resize(c, m->wx + mw, m->wy + ty, m->ww - mw - 
(2*c->bw), h - (2*c->bw), False);
-                       ty += HEIGHT(c);
+       /* master and stack area */
+       if(abs(m->ltaxis[0]) == 1 && n > m->nmaster) {
+               w1 *= m->mfact;
+               w2 -= w1;
+               x1 += (m->ltaxis[0] < 0) ? w2 : 0;
+               x2 += (m->ltaxis[0] < 0) ? 0 : w1;
+               X1 = x1 + w1;
+               X2 = x2 + w2;
+       } else if(abs(m->ltaxis[0]) == 2 && n > m->nmaster) {
+               h1 *= m->mfact;
+               h2 -= h1;
+               y1 += (m->ltaxis[0] < 0) ? h2 : 0;
+               y2 += (m->ltaxis[0] < 0) ? 0 : h1;
+               Y1 = y1 + h1;
+               Y2 = y2 + h2;
+       }
+       /* master */
+       n1 = (m->ltaxis[1] != 1 || w1 / m->nmaster < bh) ? 1 : m->nmaster;
+       n2 = (m->ltaxis[1] != 2 || h1 / m->nmaster < bh) ? 1 : m->nmaster;
+       for(i = 0, c = nexttiled(m->clients); i < m->nmaster; c = 
nexttiled(c->next), i++) {
+               resize(c, x1, y1,
+                       (m->ltaxis[1] == 1 && i + 1 == m->nmaster) ? X1 - x1 - 
2 * c->bw : w1 / n1 - 2 * c->bw,
+                       (m->ltaxis[1] == 2 && i + 1 == m->nmaster) ? Y1 - y1 - 
2 * c->bw : h1 / n2 - 2 * c->bw, False);
+               if(n1 > 1)
+                       x1 = c->x + WIDTH(c);
+               if(n2 > 1)
+                       y1 = c->y + HEIGHT(c);
+       }
+       /* stack */
+       if(n > m->nmaster) {
+               n1 = (m->ltaxis[2] != 1 || w2 / (n - m->nmaster) < bh) ? 1 : n 
- m->nmaster;
+               n2 = (m->ltaxis[2] != 2 || h2 / (n - m->nmaster) < bh) ? 1 : n 
- m->nmaster;
+               for(i = 0; c; c = nexttiled(c->next), i++) {
+                       resize(c, x2, y2,
+                               (m->ltaxis[2] == 1 && i + 1 == n - m->nmaster) 
? X2 - x2 - 2 * c->bw : w2 / n1 - 2 * c->bw,
+                               (m->ltaxis[2] == 2 && i + 1 == n - m->nmaster) 
? Y2 - y2 - 2 * c->bw : h2 / n2 - 2 * c->bw, False);
+                       if(n1 > 1)
+                               x2 = c->x + WIDTH(c);
+                       if(n2 > 1)
+                               y2 = c->y + HEIGHT(c);
                }
+       }
 }
 
 void
 togglebar(const Arg *arg) {
-       selmon->showbar = !selmon->showbar;
+       selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = 
!selmon->showbar;
        updatebarpos(selmon);
        XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, 
selmon->ww, bh);
        arrange(selmon);
@@ -1649,12 +1771,30 @@ togglefloating(const Arg *arg) {
 void
 toggletag(const Arg *arg) {
        unsigned int newtags;
+       unsigned int i;
 
        if(!selmon->sel)
                return;
        newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
        if(newtags) {
                selmon->sel->tags = newtags;
+               if(newtags == ~0) {
+                       selmon->pertag->prevtag = selmon->pertag->curtag;
+                       selmon->pertag->curtag = 0;
+               }
+               if(!(newtags & 1 << (selmon->pertag->curtag - 1))) {
+                       selmon->pertag->prevtag = selmon->pertag->curtag;
+                       for (i = 0; !(newtags & 1 << i); i++); /* get first new 
tag */
+                       selmon->pertag->curtag = i + 1;
+               }
+               selmon->lt[selmon->sellt] = 
selmon->pertag->lts[selmon->pertag->curtag];
+               selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+               selmon->nmaster = 
selmon->pertag->nmasters[selmon->pertag->curtag];
+               selmon->ltaxis[0] = 
selmon->pertag->ltaxes[selmon->pertag->curtag][0];
+               selmon->ltaxis[1] = 
selmon->pertag->ltaxes[selmon->pertag->curtag][1];
+               selmon->ltaxis[2] = 
selmon->pertag->ltaxes[selmon->pertag->curtag][2];
+               if (selmon->showbar != 
selmon->pertag->showbars[selmon->pertag->curtag])
+                       togglebar(NULL);
                focus(NULL);
                arrange(selmon);
        }
@@ -1960,11 +2100,30 @@ updatewmhints(Client *c) {
 
 void
 view(const Arg *arg) {
+       unsigned int i;
        if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
                return;
        selmon->seltags ^= 1; /* toggle sel tagset */
-       if(arg->ui & TAGMASK)
+       if(arg->ui & TAGMASK) {
                selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+               selmon->pertag->prevtag = selmon->pertag->curtag;
+               if(arg->ui == ~0)
+                       selmon->pertag->curtag = 0;
+               else {
+                       for(i = 0; !(arg->ui & 1 << i); i++);
+                       selmon->pertag->curtag = i + 1;
+               }
+       } else {
+               selmon->pertag->prevtag = selmon->pertag->curtag ^ 
selmon->pertag->prevtag;
+               selmon->pertag->curtag ^= selmon->pertag->prevtag;
+               selmon->pertag->prevtag = selmon->pertag->curtag ^ 
selmon->pertag->prevtag;
+       }
+       selmon->lt[selmon->sellt] = selmon->pertag->lts[selmon->pertag->curtag];
+       selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+       selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+       selmon->ltaxis[0] = selmon->pertag->ltaxes[selmon->pertag->curtag][0];
+       selmon->ltaxis[1] = selmon->pertag->ltaxes[selmon->pertag->curtag][1];
+       selmon->ltaxis[2] = selmon->pertag->ltaxes[selmon->pertag->curtag][2];
        focus(NULL);
        arrange(selmon);
 }

Reply via email to