Below is a patch for the current release (4.4.1) of dwm which enables multiple columns in the stacking area. It introduces variables nrows and ncols with corresponding default values NROWS and NCOLS in config.h.default, and corresponding setnrows() and setncols() for use in keybindings.
If nrows == ncols == 0, tile() behaves in the normal manner. When nrows > 0, tile() creates an extra column if adding another window to the current one would cause it to exceed nrows clients. If ncols > 0, the maximum number of columns created cannot exceed ncols, overriding the nrows setting. The patch also reintroduces nmaster in a similar way to the existing nmaster patch, but allows it to be zero to simulate a grid mode. Where there are not enough windows to fill all the columns evenly, the extra space is used by the top-most client in the first column. I'd be interested in any feedback. (I use this 'extended tiling' mode myself, and so intend to maintain the patch going forward.) Best wishes, Chris. diff -uNrd dwm-4.4.1.orig/config.default.h dwm-4.4.1/config.default.h --- dwm-4.4.1.orig/config.default.h 2007-08-26 11:53:49.000000000 +0100 +++ dwm-4.4.1/config.default.h 2007-09-09 16:35:23.000000000 +0100 @@ -33,6 +33,9 @@ { "><>", floating }, \ }; #define MWFACT 0.6 /* master width factor [0.1 .. 0.9] */ +#define NMASTER 1 /* clients in master area */ +#define NROWS 2 /* clients per column in stacking area */ +#define NCOLS 3 /* maximum number of stacking area columns */ #define SNAP 32 /* snap pixel */ /* key definitions */ @@ -48,6 +51,12 @@ { MODKEY, XK_k, focusprev, NULL }, \ { MODKEY, XK_h, setmwfact, "-0.05" }, \ { MODKEY, XK_l, setmwfact, "+0.05" }, \ + { MODKEY|ShiftMask, XK_j, setnrows, "-1" }, \ + { MODKEY|ShiftMask, XK_k, setnrows, "+1" }, \ + { MODKEY|ControlMask, XK_j, setncols, "-1" }, \ + { MODKEY|ControlMask, XK_k, setncols, "+1" }, \ + { MODKEY|ShiftMask, XK_h, setnmaster, "-1" }, \ + { MODKEY|ShiftMask, XK_l, setnmaster, "+1" }, \ { MODKEY, XK_m, togglemax, NULL }, \ { MODKEY, XK_Return, zoom, NULL }, \ { MODKEY|ShiftMask, XK_space, togglefloating, NULL }, \ diff -uNrd dwm-4.4.1.orig/tile.c dwm-4.4.1/tile.c --- dwm-4.4.1.orig/tile.c 2007-08-26 11:53:49.000000000 +0100 +++ dwm-4.4.1/tile.c 2007-09-09 16:34:17.000000000 +0100 @@ -5,10 +5,82 @@ /* static */ static double mwfact = MWFACT; +static unsigned int nmaster = NMASTER; +static unsigned int nrows = NROWS; +static unsigned int ncols = NCOLS; /* extern */ void +setnmaster(const char *arg) { + int i; + + if(!isarrange(tile)) + return; + if(!arg) + i = NMASTER; + else if(arg[0] != '+' && arg[0] != '-') + i = atoi(arg); + else + i = nmaster + atoi(arg); + + if(i < 0 || wah <= 2 * BORDERPX * i) + return; + + nmaster = i; + if(sel) + arrange(); + else + drawstatus(); +} + +void +setnrows(const char *arg) { + int i; + + if(!isarrange(tile)) + return; + if(!arg) + i = NROWS; + else if(arg[0] != '+' && arg[0] != '-') + i = atoi(arg); + else + i = nrows + atoi(arg); + + if(i < 0 || wah <= 2 * BORDERPX * i) + return; + nrows = i; + + if(sel) + arrange(); + else + drawstatus(); +} + +void +setncols(const char *arg) { + int i; + + if(!isarrange(tile)) + return; + if(!arg) + i = NCOLS; + else if(arg[0] != '+' && arg[0] != '-') + i = atoi(arg); + else + i = ncols + atoi(arg); + + if((i < 0) || (i >= 1 && waw / i <= 2 * BORDERPX)) + return; + ncols = i; + + if(sel) + arrange(); + else + drawstatus(); +} + +void setmwfact(const char *arg) { double delta; @@ -32,40 +104,79 @@ void tile(void) { - unsigned int i, n, nx, ny, nw, nh, mw, th; + unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th, tw1, cols, rows, rows1; Client *c; for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) n++; + /* calculate correct number of rows */ + if(ncols > 0 && n - nmaster > nrows * ncols) + rows = (n - nmaster) / ncols + ((n - nmaster) % ncols ? 1 : 0); + else + rows = nrows; + /* window geoms */ - mw = (n == 1) ? waw : mwfact * waw; - th = (n > 1) ? wah / (n - 1) : 0; - if(n > 1 && th < bh) - th = wah; + if (nmaster == 0) { + mh = mw = 0; + } + else if (n <= nmaster) { + mh = wah / (n > 0 ? n : 1); + mw = waw; + } + else { + mh = wah / nmaster; + mw = mwfact * waw; + } + + if(rows == 0 || n <= nmaster + rows) { + rows1 = n > nmaster ? n - nmaster : 1; + tw = tw1 = waw - mw; + th = wah / rows1; + } + else { + rows1 = 1 + (n - nmaster - 1) % rows; + cols = (n - nmaster) / rows + ((n - nmaster) % rows ? 1 : 0); + tw = (waw - mw) / cols; + tw1 = waw - mw - (cols - 1) * tw; + th = wah / rows; + } nx = wax; ny = way; + for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) { c->ismax = False; - if(i == 0) { /* master */ + if(i < nmaster) { /* master column */ nw = mw - 2 * c->border; - nh = wah - 2 * c->border; + nh = mh - 2 * c->border; + if(i == 0) + nh += wah - mh * (n < nmaster ? n : nmaster); } - else { /* tile window */ - if(i == 1) { + else if(i < nmaster + rows1) { /* first stack column */ + if(i == nmaster) { /* initialise */ ny = way; nx += mw; + nh = wah - 2*c->border - (rows1 - 1) * th; } - nw = waw - mw - 2 * c->border; - if(i + 1 == n) /* remainder */ - nh = (way + wah) - ny - 2 * c->border; - else + else { nh = th - 2 * c->border; + } + nw = tw1 - 2 * c->border; + } + else { /* successive stack columns - rows > 0 if we reach here */ + if((i - nmaster - rows1) % rows == 0) { /* reinitialise */ + ny = way; + nx += nw + 2 * c-> border; + nh = wah - 2*c->border - (rows - 1) * th; + } + else { + nh = th - 2 * c->border; + } + nw = tw - 2 * c->border; } resize(c, nx, ny, nw, nh, False); - if(n > 1 && th != wah) - ny += nh + 2 * c->border; + ny += nh + 2 * c->border; } } diff -uNrd dwm-4.4.1.orig/tile.h dwm-4.4.1/tile.h --- dwm-4.4.1.orig/tile.h 2007-08-26 11:53:49.000000000 +0100 +++ dwm-4.4.1/tile.h 2007-09-09 15:29:52.000000000 +0100 @@ -1,6 +1,9 @@ /* See LICENSE file for copyright and license details. */ /* tile.c */ +void setnmaster(const char *arg); /* sets nmaster value */ +void setnrows(const char *arg); /* sets nrows value */ +void setncols(const char *arg); /* sets ncols value */ void setmwfact(const char *arg); /* sets master width factor */ void tile(void); /* arranges all windows tiled */ void zoom(const char *arg); /* zooms the focused client to master area, arg is ignored */