# Re: [dwm] The wmii layout and some help bout the mailing list

From: John A. Grahor <jag_AT_techma.com>
Date: Thu, 03 Jul 2008 18:57:33 -0400

Regarding multiple columns, please consider this patch that I wrote for
4.9 which I feel is light weight and handles the question of multiple
columns in the dynamic dwm way. The patch determines the number of
columns which will maximize the average "squareness" of all the clients
to be tiled.

The loop which calculates the maximum figure of merit could be
eliminated if dwm included math.h with a formula like this:

ncolumns = sqrt(numclients*tileareawidth/tileareaheight)

Anyway, I use this layout on a daily basis and it scratches my
multi-column itch.

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->bw;
int H = (j==rows?((ty + th) - y):h) - 2 * c->bw;
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->bw;
y = ty;
j = 1;
} else {
y = c->y + c->h + 2 * c->bw;
}
}
}

dwm-request_AT_suckless.org wrote:
> Date: Wed, 2 Jul 2008 16:02:29 +0200
> From: "Anselm R. Garbe" <arg_AT_suckless.org>
> Subject: Re: [dwm] The wmii layout and some help bout the mailing list
> To: dynamic window manager <dwm_AT_suckless.org>
> Message-ID: <20080702140229.GG15291_AT_suckless.org>
> Content-Type: text/plain; charset=us-ascii
>
> On Wed, Jul 02, 2008 at 02:54:41PM +0200, QUINTIN Guillaume wrote:
>> Each time I want to post I start a new thread, how do I do to answer
>> somebody ?
>
> The Reply-To defaults to the list, so it depends on your MUA.
>
>> Well, adding a void* aux to the Client structure sounds like a good idea
>> but it is a first step towards adding "official" (or simply more
>> advanced) support for plugins, I think. I mean that you will have to add
>> an argument to the function lt->arrange indicating to the layout arrange
>> function what action was performed on the window. This way no
>> modification of the file dwm.c is needed, the patch (or plugin) can hold
>> in a separate .c file with an #include only in the dwm.c. I think that
>> it is a choice that has to be done. Plus, it won't add many lines (well
>> to be sure I should try it !). This way no modification of the dwm.c
>> (just an #include !).
>
> Hmm, how would an action argument to arrange() help? What might
> this argument look like?
>
>> To do with the current version without modifying the dwm.c. It is
>> "simple". I thought of that before. It suffices to add a "compare"
>> algorithm which compare the wtable and the clients linked list to see if
>> some windows were added or deleted or simply moved into another tag, etc
>> ... But such an algorithm is (not complicated to write) long in terms of
>> line of code and it will take much more memory than hooking into the
>> dwm.c (That's why I decided not to implement it). In some way the
>> wlayout function is a beginning of the algorithm. It checks if the
>> windows tag has changed in the clients linked list and report the
>> changes to the wtable.
>
> Well as I told, the wmii column layout is rather static, because
> it keeps certain clients at a fixed position (in a specific
> column, at a specific position).
>
> In contrast to this, dwm is designed for layouts which are totally
> independent from clients itself.
>
> There might be some ways to deal with a wmii-like approach in
> dwm, however they always will end up in heavy patching.
>
> A very simple wmii-like layout in dwm would be independent from
> the actual clients, but remember the basic column/cell
> configuration. First of all I noticed when I used wmii that I
> never used more than 3 columns, so one could restrict the layout
> to 3 columns at maximum. Secondly, there needs to be a column
> which accepts any amount of clients, which could be restricted
> to the last column. So if 1 column is in use, this takes
> arbitrary clients, if two columns are used, the second takes
> arbitrary clients (like current tile()), if 3 are in use the 3rd
> takes arbitrary clients. Then you need a function to restrict
> the number of clients in the first and second column. This could
> be made dependend on the amounts of columns in use, to make it
> even simplier. So one could argue, as long as the number of
> clients in column 1 is not restricted (0) there won't be a
> second column. If it is restricted, a second column will be
> created if at least 2 windows exist and so forth.
> If the second column is restricted as well, a third will be
> created if both, first and second column are full. zoom() will
> always move a client to the top of the first column. The rest
> would work straight-forward with current dwm and without any
> patches.
>
> The patch would contain:
>
> some local static data
> coltile() -- as arrange algorithm
> restrict1() -- restricts column1
> restruct2() -- restricts column2
>
> One would have:
>
> Mod1-c to activate this layout
> Mod1-i restrict1(.i = +1)
> Mod1-d restrict1(.i = -1)
> Mod1-Shift-i restrict2(.i = +1)
> Mod1-Shift-d restrict2(.i = -1)
>