Re: [dev] Re: [dwm] A general approach to master-slave layouts

From: lolilolicon <lolilolicon_AT_gmail.com>
Date: Wed, 2 Nov 2011 20:40:27 +0800

I believe every master-slave layout, i.e., layouts where mfact/nmaster
make sense, should own its own mfact/nmaster value, not to be disturbed
by other layouts. As said before, `col' and `tile' for example just
can't share the same mfact and still both look good.

Consequently, I decided to update the patch so mfact and nmaster are now
monitor- and layout-specific. This should make the master-slave layouts
play nice with each other and thus make the idea more complete.

Also, the nice thing about this approach is that the config.h interface
is left unchanged. mfact and nmaster values of each layout are
initialized to the global value mfact and nmaster; the user can also
implement layouts that force rules on mfact and nmaster if desired.

diff -r 904e923827cb -r 983f8ffd9f7c config.def.h
--- a/config.def.h Mon Oct 31 20:09:27 2011 +0100
+++ b/config.def.h Wed Nov 02 20:15:22 2011 +0800
_AT_@ -32,6 +32,8 @@
         { "[]=", tile }, /* first entry is default */
         { "><>", NULL }, /* no layout function means floating behavior */
         { "[M]", monocle },
+ { "TTT", bstack },
+ { "|||", col },
 };

 /* key definitions */
_AT_@ -66,6 +68,8 @@
         { MODKEY, XK_t, setlayout, {.v =
&layouts[0]} },
         { MODKEY, XK_f, setlayout, {.v =
&layouts[1]} },
         { MODKEY, XK_m, setlayout, {.v =
&layouts[2]} },
+ { MODKEY, XK_s, setlayout, {.v =
&layouts[3]} },
+ { MODKEY, XK_c, setlayout, {.v =
&layouts[4]} },
         { MODKEY, XK_space, setlayout, {0} },
         { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
         { MODKEY, XK_0, view, {.ui = ~0 } },
diff -r 904e923827cb -r 983f8ffd9f7c dwm.c
--- a/dwm.c Mon Oct 31 20:09:27 2011 +0100
+++ b/dwm.c Wed Nov 02 20:15:22 2011 +0800
_AT_@ -122,26 +122,9 @@
         void (*arrange)(Monitor *);
 } Layout;

-struct Monitor {
- char ltsymbol[16];
- float mfact;
- int nmaster;
- int num;
- int by; /* bar geometry */
- int mx, my, mw, mh; /* screen size */
- int wx, wy, ww, wh; /* window area */
- unsigned int seltags;
- unsigned int sellt;
- unsigned int tagset[2];
- Bool showbar;
- Bool topbar;
- Client *clients;
- Client *sel;
- Client *stack;
- Monitor *next;
- Window barwin;
- const Layout *lt[2];
-};
+typedef struct {
+ int x, y, w, h;
+} Rect;

 typedef struct {
         const char *class;
_AT_@ -153,18 +136,23 @@
 } Rule;

 /* function declarations */
+static void apply_mslts(Monitor *m, Bool hsplit,
+ void (*mltf)(Client **, Rect *, unsigned int), /* master layout function */
+ void (*sltf)(Client **, Rect *, unsigned int)); /* slave layout function */
 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 attachstack(Client *c);
+static void bstack(Monitor *);
 static void buttonpress(XEvent *e);
 static void checkotherwm(void);
 static void cleanup(void);
 static void cleanupmon(Monitor *mon);
 static void clearurgent(Client *c);
 static void clientmessage(XEvent *e);
+static void col(Monitor *);
 static void configure(Client *c);
 static void configurenotify(XEvent *e);
 static void configurerequest(XEvent *e);
_AT_@ -185,6 +173,7 @@
 static void focusmon(const Arg *arg);
 static void focusstack(const Arg *arg);
 static unsigned long getcolor(const char *colstr);
+static unsigned int getlayoutindex(const Layout *lt);
 static Bool getrootptr(int *x, int *y);
 static long getstate(Window w);
 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
_AT_@ -194,6 +183,8 @@
 static void initfont(const char *fontstr);
 static void keypress(XEvent *e);
 static void killclient(const Arg *arg);
+static void lt_hstack(Client **c, Rect *r, unsigned int n);
+static void lt_vstack(Client **c, Rect *r, unsigned int n);
 static void manage(Window w, XWindowAttributes *wa);
 static void mappingnotify(XEvent *e);
 static void maprequest(XEvent *e);
_AT_@ -281,11 +272,92 @@
 /* configuration, allows nested code to access above variables */
 #include "config.h"

+struct Monitor {
+ char ltsymbol[16];
+ float mfact[LENGTH(layouts)];
+ int nmaster[LENGTH(layouts)];
+ int num;
+ int by; /* bar geometry */
+ int mx, my, mw, mh; /* screen size */
+ int wx, wy, ww, wh; /* window area */
+ unsigned int seltags;
+ unsigned int sellt;
+ unsigned int tagset[2];
+ Bool showbar;
+ Bool topbar;
+ Client *clients;
+ Client *sel;
+ Client *stack;
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
+};
+
 /* compile-time check if all tags fit into an unsigned int bit array. */
 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };

 /* function implementations */
 void
+apply_mslts(Monitor *m, Bool hsplit,
+ void (*mltf)(Client **, Rect *, unsigned int),
+ void (*sltf)(Client **, Rect *, unsigned int)) {
+ unsigned int i, n;
+ Client *c;
+
+ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if(n == 0)
+ return;
+
+ int nm;
+ float f;
+
+ i = getlayoutindex(m->lt[m->sellt]);
+ if(0 <= i && i < LENGTH(layouts)) {
+ f = m->mfact[i];
+ nm = m->nmaster[i];
+ }
+ else {
+ f = mfact;
+ nm = nmaster;
+ }
+
+ nm = MIN(n, nm); /* number of masters */
+
+ if (nm == 0) {
+ /* all slaves */
+ c = m->clients;
+ Rect r = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
+ (*sltf)(&c, &r, n);
+ }
+ else if(n > nm) {
+ /* masters and slaves */
+ c = m->clients;
+ if(hsplit) {
+ /* masters above slaves */
+ Rect r = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh * f };
+ (*mltf)(&c, &r, nm);
+ r.y += r.h;
+ r.h = m->wh - r.h;
+ (*sltf)(&c, &r, n - nm);
+ }
+ else {
+ /* masters at the left of slaves */
+ Rect r = { .x = m->wx, .y = m->wy, .w = m->ww * f, .h = m->wh };
+ (*mltf)(&c, &r, nm);
+ r.x += r.w;
+ r.w = m->ww - r.w;
+ (*sltf)(&c, &r, n - nm);
+ }
+ }
+ else {
+ /* all masters */
+ c = m->clients;
+ Rect r = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
+ (*mltf)(&c, &r, n);
+ }
+}
+
+void
 applyrules(Client *c) {
         const char *class, *instance;
         unsigned int i;
_AT_@ -418,6 +490,11 @@
 }

 void
+bstack(Monitor *m) {
+ apply_mslts(m, True, lt_hstack, lt_hstack);
+}
+
+void
 buttonpress(XEvent *e) {
         unsigned int i, x, click;
         Arg arg = {0};
_AT_@ -565,6 +642,11 @@
 }

 void
+col(Monitor *m) {
+ apply_mslts(m, False, lt_hstack, lt_vstack);
+}
+
+void
 configure(Client *c) {
         XConfigureEvent ce;

_AT_@ -661,12 +743,15 @@
 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));
         m->tagset[0] = m->tagset[1] = 1;
- m->mfact = mfact;
- m->nmaster = nmaster;
+ for(i = 0; i < LENGTH(layouts); ++i) {
+ m->mfact[i] = mfact;
+ m->nmaster[i] = nmaster;
+ }
         m->showbar = showbar;
         m->topbar = topbar;
         m->lt[0] = &layouts[0];
_AT_@ -936,6 +1021,18 @@
         return color.pixel;
 }

+unsigned int
+getlayoutindex(const Layout *lt) {
+ const Layout *l;
+ for(l = layouts; l - layouts < LENGTH(layouts); ++l) {
+ /* We only care about the layout function */
+ if(l->arrange == lt->arrange) {
+ return (l - layouts);
+ }
+ }
+ return (l - layouts); /* the caller shall verify return value */
+}
+
 Bool
 getrootptr(int *x, int *y) {
         int di;
_AT_@ -1028,8 +1125,18 @@

 void
 incnmaster(const Arg *arg) {
- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
- arrange(selmon);
+ if(!arg || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ int n;
+ unsigned int i;
+ i = getlayoutindex(selmon->lt[selmon->sellt]);
+ if(0 <= i && i < LENGTH(layouts)) {
+ n = MAX(selmon->nmaster[i] + arg->i, 0);
+ if(n != selmon->nmaster[i]) {
+ selmon->nmaster[i] = n;
+ arrange(selmon);
+ }
+ }
 }

 void
_AT_@ -1108,6 +1215,36 @@
 }

 void
+lt_hstack(Client **c, Rect *r, unsigned int n) {
+ unsigned int i;
+ int x, y, w, h;
+
+ x = r->x; /* x offset of the next cell */
+ y = r->y;
+ h = r->h;
+ for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) {
+ w = (r->x + r->w - x) / (n - i);
+ resize(*c, x, y, w - 2 * (*c)->bw, h - 2 * (*c)->bw, False);
+ x += WIDTH(*c);
+ }
+}
+
+void
+lt_vstack(Client **c, Rect *r, unsigned int n) {
+ unsigned int i;
+ int x, y, w, h;
+
+ x = r->x;
+ y = r->y; /* y offset of the next cell */
+ w = r->w;
+ for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) {
+ h = (r->y + r->h - y) / (n - i);
+ resize(*c, x, y, w - 2 * (*c)->bw, h - 2 * (*c)->bw, False);
+ y += HEIGHT(*c);
+ }
+}
+
+void
 manage(Window w, XWindowAttributes *wa) {
         Client *c, *t = NULL;
         Window trans = None;
_AT_@ -1526,15 +1663,18 @@
 /* arg > 1.0 will set mfact absolutly */
 void
 setmfact(const Arg *arg) {
- float f;
-
         if(!arg || !selmon->lt[selmon->sellt]->arrange)
                 return;
- f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
- if(f < 0.1 || f > 0.9)
- return;
- selmon->mfact = f;
- arrange(selmon);
+ float f;
+ unsigned int i;
+ i = getlayoutindex(selmon->lt[selmon->sellt]);
+ if(0 <= i && i < LENGTH(layouts)) {
+ f = arg->f < 1.0 ? arg->f + selmon->mfact[i] : arg->f - 1.0;
+ if(f != selmon->mfact[i] && f >= 0.1 && f <= 0.9) {
+ selmon->mfact[i] = f;
+ arrange(selmon);
+ }
+ }
 }

 void
_AT_@ -1659,28 +1799,7 @@

 void
 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++);
- 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);
- }
+ apply_mslts(m, False, lt_vstack, lt_vstack);
 }

 void
Received on Wed Nov 02 2011 - 13:40:27 CET

This archive was generated by hypermail 2.3.0 : Wed Nov 02 2011 - 13:48:03 CET