Hi,

While porting Michael Elkins's ntile() implementation to 5.4.1, I noticed
that it is actually shorter than vanilla tile()!

It would however be useless without the setnmaster() function clocking in
at 13 LOC, same as setmfact(). But the two have most of their code in common:

        1. Verify layout != floating
        2. Verify arg is within bounds
        3. Set global variable (relatively or absolutely)
        4. Call arrange()

How about:
        enum { Abs, Rel };

        void
        tweak(int *var, const int *val, int min, int max) {
                int i;

                i = val[1] + (val[0] == Abs ? 0 : *var);
                if(!lt[sellt]->arrange || i < min || i > max)
                        return;
                *var = i;
                arrange();
        }

Previously setmfact():
        void
        tweakmwp(const Arg *arg) {
                tweak(&mwp, arg->v, 5, 95);
        }

Previously setnmaster():
        void
        tweakmn(const Arg *arg) {
                tweak(&mn, arg->v, 1, wh / (1 + 2 * borderpx));
        }

Configuration example:
        static int mwp = 55;  /* master area width percentage [5..95] */
        static int mn  = 1;   /* number of clients in master area */
        [...]
        { MODKEY,            XK_h,  tweakmwp,  {.v = (int[]){Rel, -10}} },
        { MODKEY|ShiftMask,  XK_n,  tweakmn,   {.v = (int[]){Abs,   2}} },


A complete patch to dwm.c and config.def.h is attached. LOC # (including
the new mn feature) stays about the same if you account for the fact that
more (but much smaller) functions are penalized by whitespace, braces, and
forward declarations.

Note that the patch is on top of my last two patches from the virtual
keyboards thread. It also corrects a discrepancy between documentation and
code: mfact was described as [0.05..0.95], but was actually [0.1..0.9].

Regards,
Peter
diff --git a/config.def.h b/config.def.h
index 03dc235..230e701 100644
--- a/config.def.h
+++ b/config.def.h
@@ -26,7 +26,8 @@ static Rule rules[] = {
 };
 
 /* layout(s) */
-static float mfact      = 0.55; /* factor of master area size [0.05..0.95] */
+static int mwp          = 55;   /* master area width percentage [5..95] */
+static int mn           = 1;    /* number of clients in master area */
 static Bool resizehints = True; /* False means respect size hints in tiled 
resizals */
 
 static Layout layouts[] = {
@@ -58,8 +59,10 @@ static Key keys[] = {
        { MODKEY,                       XK_b,      togglebar,      {0} },
        { MODKEY,                       XK_j,      selstack,       {.i = +1 } },
        { MODKEY,                       XK_k,      selstack,       {.i = -1 } },
-       { MODKEY,                       XK_h,      setmfact,       {.f = -0.05} 
},
-       { MODKEY,                       XK_l,      setmfact,       {.f = +0.05} 
},
+       { MODKEY,                       XK_h,      tweakmwp,       {.v = 
(int[]){Rel, -5}} },
+       { MODKEY,                       XK_l,      tweakmwp,       {.v = 
(int[]){Rel, +5}} },
+       { MODKEY|ShiftMask,             XK_h,      tweakmn,        {.v = 
(int[]){Rel, -1}} },
+       { MODKEY|ShiftMask,             XK_l,      tweakmn,        {.v = 
(int[]){Rel, +1}} },
        { MODKEY,                       XK_Return, zoom,           {0} },
        { MODKEY,                       XK_Tab,    view,           {0} },
        { MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
diff --git a/dwm.c b/dwm.c
index 0557143..ad1886d 100644
--- a/dwm.c
+++ b/dwm.c
@@ -56,6 +56,7 @@
 #define TEXTW(x)                (textnw(x, strlen(x)) + dc.font.height)
 
 /* enums */
+enum { Abs, Rel };
 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
 enum { NetSupported, NetWMName, NetLast };              /* EWMH atoms */
@@ -178,7 +179,6 @@ static void selclient(Client *c);
 static void selstack(const Arg *arg);
 static void setclientstate(Client *c, long state);
 static void setlayout(const Arg *arg);
-static void setmfact(const Arg *arg);
 static void setup(void);
 static void showhide(Client *c, unsigned int ntiled);
 static void sigchld(int signal);
@@ -186,10 +186,14 @@ static void spawn(const Arg *arg);
 static void tag(const Arg *arg);
 static int textnw(const char *text, unsigned int len);
 static void tile(void);
+static Client *tilecolumn(Client* c, unsigned int n, unsigned int nt, int x, 
int y, int w, int h, unsigned int *maxw);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
+static void tweak(int *var, const int *val, int min, int max);
+static void tweakmwp(const Arg *arg);
+static void tweakmn(const Arg *arg);
 static void unmanage(Client *c);
 static void unmapnotify(XEvent *e);
 static void updatebar(void);
@@ -1271,20 +1275,6 @@ setlayout(const Arg *arg) {
                drawbar();
 }
 
-/* arg > 1.0 will set mfact absolutly */
-void
-setmfact(const Arg *arg) {
-       float f;
-
-       if(!arg || !lt[sellt]->arrange)
-               return;
-       f = arg->f < 1.0 ? arg->f + mfact : arg->f - 1.0;
-       if(f < 0.1 || f > 0.9)
-               return;
-       mfact = f;
-       arrange();
-}
-
 void
 setup(void) {
        unsigned int i;
@@ -1419,38 +1409,33 @@ textnw(const char *text, unsigned int len) {
 
 void
 tile(void) {
-       int x, y, h, w, mw;
-       unsigned int i, n;
        Client *c;
+       unsigned int n, maxw = 0;
 
        for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next), n++);
-       if(n == 0)
-               return;
-
-       /* master */
        c = nexttiled(clients);
-       mw = mfact * ww;
-       adjustborder(c, n == 1 ? 0 : borderpx);
-       resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw, 
resizehints);
+       if(n <= mn)
+               tilecolumn(c, n, n, wx, wy, ww, wh, NULL);
+       else {
+               c = tilecolumn(c, n, mn, wx, wy, (float)mwp/100 * ww, wh, 
&maxw);
+               tilecolumn(c, n, n - mn, wx + maxw, wy, ww - maxw, wh, NULL);
+       }
+}
 
-       if(--n == 0)
-               return;
+Client *
+tilecolumn(Client* c, unsigned int n, unsigned int nt, int x, int y, int w, 
int h, unsigned int *maxw) {
+       unsigned int i, d;
 
-       /* tile stack */
-       x = (wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : wx + mw;
-       y = wy;
-       w = (wx + mw > c->x + c->w) ? wx + ww - x : ww - mw;
-       h = wh / n;
-       if(h < bh)
-               h = wh;
-
-       for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
-               adjustborder(c, borderpx);
-               resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
-                      ? wy + wh - y - 2 * c->bw : h - 2 * c->bw), resizehints);
-               if(h != wh)
-                       y = c->y + HEIGHT(c);
+       for(i = 0; c && i < nt; c = nexttiled(c->next), i++) {
+               adjustborder(c, n == 1 ? 0 : borderpx);
+               resize(c, x, y, w - 2 * c->bw, h / (nt - i) - 2 * c->bw, 
resizehints);
+               d = HEIGHT(c);
+               y += d;
+               h -= d;
+               if(maxw)
+                       *maxw = MAX(*maxw, WIDTH(c));
        }
+       return c;
 }
 
 void
@@ -1496,6 +1481,27 @@ toggleview(const Arg *arg) {
 }
 
 void
+tweak(int *var, const int *val, int min, int max) {
+       int i;
+
+       i = val[1] + (val[0] == Abs ? 0 : *var);
+       if(!lt[sellt]->arrange || i < min || i > max)
+               return;
+       *var = i;
+       arrange();
+}
+
+void
+tweakmn(const Arg *arg) {
+       tweak(&mn, arg->v, 1, wh / (1 + 2 * borderpx));
+}
+
+void
+tweakmwp(const Arg *arg) {
+       tweak(&mwp, arg->v, 5, 95);
+}
+
+void
 unmanage(Client *c) {
        XWindowChanges wc;
 

Reply via email to