[dwm] "Optimal" tiling patch for 4.8

From: John A. Grahor <jag_AT_techma.com>
Date: Fri, 28 Mar 2008 05:04:38 -0400

Here is a patch which adds an "Optimal" aspect ratio tiling mode for dwm
4.8.

I call it optimal because it maintains the aspect ratio of all tiled
clients as close to square as possible by changing the number of rows
and columns displayed in the tiled area.

The formula to do this is roughly:

ncolumns = sqrt(numclients*tileareawidth/tileareaheight)

but since dwm doesn't include libm, the algorithm loops from ncolumns =
1 to nclients and finds the number of columns which results in the
average client aspect ratio closest to square.

I remember someone asking for this a few weeks back so here it is.

Also, if you can think of a better name than "Optimal" please let me know.

And there may be some corner cases/ safety things I may have missed.

I'll patch 4.9 when it comes out if anyone likes it.

diff -rupN dwm-4.8/config.anselm.h dwm-4.8-optimal/config.anselm.h
--- dwm-4.8/config.anselm.h 2008-03-13 12:55:43.000000000 -0400
+++ dwm-4.8-optimal/config.anselm.h 2008-03-28 04:38:44.000000000 -0400
@@ -29,6 +29,7 @@ Layout layouts[] = {
         /* symbol function isfloating */
         { "[]|", tileh, False }, /* first entry is default */
         { "[]=", tilev, False },
+ { "[]+", tileoptimal, False },
         { "><>", floating, True },
         { "[M]", monocle, True },
 };
@@ -107,6 +108,7 @@ Key keys[] = {
         { MODKEY, XK_f, setlayout, "><>" },
         { MODKEY, XK_v, setlayout, "[]=" },
         { MODKEY, XK_h, setlayout, "[]|" },
+ { MODKEY, XK_o, setlayout, "[]+" },
         { MODKEY|ShiftMask, XK_space, togglefloating, NULL },
         { MODKEY|ShiftMask, XK_c, killclient, NULL },
         { MODKEY, XK_0, view, NULL },
diff -rupN dwm-4.8/config.def.h dwm-4.8-optimal/config.def.h
--- dwm-4.8/config.def.h 2008-03-13 12:55:43.000000000 -0400
+++ dwm-4.8-optimal/config.def.h 2008-03-28 04:39:05.000000000 -0400
@@ -29,6 +29,7 @@ Layout layouts[] = {
         /* symbol function isfloating */
         { "[]=", tilev, False }, /* first entry is default */
         { "[]|", tileh, False },
+ { "[]+", tileoptimal, False },
         { "><>", floating, True },
         { "[M]", monocle, True },
 };
@@ -49,6 +50,7 @@ Key keys[] = {
         { MODKEY, XK_f, setlayout, "><>" },
         { MODKEY, XK_v, setlayout, "[]=" },
         { MODKEY, XK_h, setlayout, "[]|" },
+ { MODKEY, XK_o, setlayout, "[]+" },
         { MODKEY|ShiftMask, XK_space, togglefloating, NULL },
         { MODKEY|ShiftMask, XK_c, killclient, NULL },
         { MODKEY, XK_0, view, NULL },
diff -rupN dwm-4.8/dwm.1 dwm-4.8-optimal/dwm.1
--- dwm-4.8/dwm.1 2008-03-13 12:55:43.000000000 -0400
+++ dwm-4.8-optimal/dwm.1 2008-03-28 04:40:23.000000000 -0400
@@ -69,6 +69,9 @@ Applies vertical tiled layout.
 .B Mod1\-h
 Applies horizontal tiled layout.
 .TP
+.B Mod1\-o
+Applies "optimal" aspect ratio tiled layout.
+.TP
 .B Mod1\-j
 Focus next window.
 .TP
diff -rupN dwm-4.8/dwm.c dwm-4.8-optimal/dwm.c
--- dwm-4.8/dwm.c 2008-03-13 12:55:43.000000000 -0400
+++ dwm-4.8-optimal/dwm.c 2008-03-28 04:42:04.000000000 -0400
@@ -174,6 +174,7 @@ Client *tilemaster(unsigned int n);
 void tileresize(Client *c, int x, int y, int w, int h);
 void tilev(void);
 void tilevstack(unsigned int n);
+void tileoptimal(void);
 void togglefloating(const char *arg);
 void toggletag(const char *arg);
 void toggleview(const char *arg);
@@ -1615,6 +1616,68 @@ tileh(void) {
         }
 }
 
+double squareness(const double width, const double height) {
+ /* return a number that is 1 if square and less than 1 if not square */
+ return (width<height)?width/height:height/width;
+}
+
+void
+tileoptimal(void) {
+ int x, y, w, h;
+ unsigned int i,j, n = counttiled();
+ unsigned int cols,rows,extra;
+ double fom, maxfom;
+ Client *c;
+
+ if(n == 0)
+ return;
+ c = tilemaster(n);
+ if(--n == 0)
+ return;
+
+ x = tx; y = ty; w = tw; h = th;
+ cols = 1; rows = 1; extra = 0;
+ if (n > 1) {
+ maxfom = 0.0;
+ for (i = 1; i <= n; i++) {
+ rows = n/i;
+ extra = n%i;
+ w = tw/i;
+ fom = ( extra*(rows+1)*squareness(w,th/(rows+1)) +
+ (i-extra)*rows*squareness(w,th/rows) ) / n;
+ if (fom > maxfom) {
+ maxfom = fom;
+ cols = i;
+ }
+ }
+ rows = n/cols;
+ extra = cols - n%cols;
+ w = tw/cols;
+ h = th/rows; /* do columns with fewer rows to the left */
+ }
+
+ i = 1; /* i is column */
+ j = 1; /* j is row */
+ for(c = nexttiled(c->next); c; c = nexttiled(c->next)) {
+ int W = (i==cols?((tx + tw) - x):w) - 2 * c->border;
+ int H = (j==rows?((ty + th) - y):h) - 2 * c->border;
+ tileresize(c, x, y, W, H);
+ if (j++ == rows) {
+ if (i == extra) {
+ /* we're finished with the last column with fewer rows */
+ rows++;
+ h = th/rows;
+ }
+ if (i++ == cols) break;
+ x = c->x + c->w + 2 * c->border;
+ y = ty;
+ j = 1;
+ } else {
+ y = c->y + c->h + 2 * c->border;
+ }
+ }
+}
+
 Client *
 tilemaster(unsigned int n) {
         Client *c = nexttiled(clients);
Received on Fri Mar 28 2008 - 10:04:42 UTC

This archive was generated by hypermail 2.2.0 : Sun Jul 13 2008 - 15:29:11 UTC