All of these layouts fit in a generalized model. Basically, there're two
things that differentiate one master-slave layout from another:
1. How the master and slave areas are separated. Practically, the most
useful way to do this is simply split the screen in two parts, either
vertically, or horizontally.
2. What layout is used in each of the master and slave areas. We can
use different layouts for the masters and the slaves. We should reuse
the layout algorithms when we can.
With this model in mind, I came up with the function apply_mslts(), i.e.
"apply master-slave layouts", which takes care of the two things stated
above. The actual layout algorithms are defined in the lt_* functions:
lt_hstack tiles windows in a horizontal stack, i.e. columns.
lt_vstack tiles windows in a vertical stack, i.e. rows.
lt_grid tiles windows in a (gapless) grid.
lt_monocle stacks windows, each maximized to fill the "booth".
The "booth" is the box in which the layout is performed. Such functions
are simpler and easier to read. And they are reusable.
To define a master-slave layout is as simple as:
static void
grid(Monitor *m) {
apply_mslts(m, False, lt_vstack, lt_grid);
}
Here `False` means split master and slave areas vertically; lt_vstack is
applied to the master area, and lt_grid to the slaves. I've never seen
such a layout before, you may find it interesting too.
To test this out, simply grab the hg tip, #include mslts.c in config.h,
add some example layouts such as `grid', bind a key combo, `make`, and
run. Adjust the nmaster value with Mod + d/i, and mfact with Mod + h/l
to see the effects.
Also, this approach accepts nmaster being 0, in which case, all windows
are slaves, and are thus tiled using the slaves' layout algorithm. This
should be the case for the current hg tip, too, IMO.
Finally, I'm not really good at C yet, so the code could probably use a
whole lot of improvement. I'd really appreciate it if you could review
the code and help me improve it, because I really like this idea.
The code is in the attachment.
/*
Resend this due to missing [dwm] tag in the subject, and an error in the
code. Sorry for the inconvenience.
*/
*huge facepalm*
Forgot to attach the fixed code. Attached here.
That looks interesting. I have one suggestion for a simplification:
I guess you can get rid of the functions combining the master and
slave layouts by modifying setlayout() to take three arguments (the
two layouts and the direction of master/slave splitting). This way you
could combine any two layouts in the key binding section of config.h.
--
Thomas Dahms
I don't think we can do this with the current Arg. I also don't see the
benefit of this over defining the layouts. If the user wants to combine
two layout algorithms, he can always define a layout in as few as three
lines in config.h. Please elaborate if I misunderstand.
Also, the code is so far in no way in conflict with the dwm code. This
general approach is also more flexible. For example, the example `ntile'
layout can replace `tile' in dwm.c, and `monocle' in dwm.c can be defined
via `apply_lt` using `lt_monocle`.
Actually, `apply_lt` can be removed, since `apply_mslts` does the same
thing when nmaster == 0. I'm thinking of making nmaster a member of
the Layout structure, instead of the current Monitor. This way, we can
make all windows slaves in the `grid' layout, while having two masters
when we switch to `tile'. The same applies to mfact- the `ncol' layout
certainly needs a bigger mfact than `tile', for example. Finally, neither
nmaster nor mfact makes sense in non-master-slave layouts (if you still
use those, that is ;). Oh, and it would be nice if mfact increased when
nmaster increased in the `ncol' layout, too. Maybe another function
as a member of Layout, which would be executed to set mfact as a hook
whenever nmaster changes?
Since the current tile, monocle, and proposed bstack layouts are each a
special case of the mslts approach, and mslts is more powerful (and I do
think is simpler and easier to read), and if you care, mslts will likely
decrease the SLOC due to removal of duplicated code, I think mslts could
be accepted into mainline. What do you think?
>
> --
> Thomas Dahms
>
>
Indeed mfact and nmaster being members of Layout does make more sense, and
I made a patch which includes this change.
Since I don't know much about hg, I just did a `hg export`, and attach the
produced patch as attachment instead of inline. The commit message should
describe what has been done, and the code should explain itself.
Note that this may seem to add some SLOCs, but it actually reduces the
amount of code required to implement the same layouts by avoiding code
duplication. See how tile, bstack and col are each defined using just a
one-liner. By defining two layout algorithms `lt_vstack` and `lt_hstack`,
in combination with the hsplit switch, one can define 2 ** 2 * 2 = 8 such
layouts, and if you count the (masters|slaves)-only layouts as separate
ones, we got 10. Add a third layout algorithm, and you have
3 ** 2 * 2 + 3 = 21. Sure, not all layouts are useful for everyone, but
hopefully this will produce some interesting layouts suitable for your
particular setup.
I don't have much time today, or possibly tomorrow, but I'm interested
in this patch, it sounds almost like it recurses on each sub-section of
the total area, applying a different layout function each time, except
it's limited to two calls, one for the master area and one for the
slave. Either way, I'm hoping to try out your patch(es) at some point
this week, and hoping to mess around with the key bindings, I assume you
can change the master layout while keeping the slave one the same with a
binding, right?
Cheers,
Rob
It's only one patch, which I sent in my last mail, so not much really :)
The core is the `apply_mslts' funtion. It walks all clients like any
tiling layout would do, e.g., the `tile' function defined in the patch
simply calls `apply_mslts(m, False, lt_vstack, lt_vstack)`, and it should
do the layout exactly the same way the original `tile' would do, no extra
wasted work. The code should be clear, but maybe note that the mltf/sltf
functions modify `c'.
> Either way, I'm hoping to try out your patch(es) at some point
> this week, and hoping to mess around with the key bindings, I assume you
> can change the master layout while keeping the slave one the same with a
> binding, right?
Not really. DWM knows only about a single layout per monitor, even if we
set the masters to temporarily use a different layout algorithm, but not
update the currently selected layout name, DWM will rearrange the masters
back to the selected layout whenever arrangemon() is called, which happens
probably before you realize it ;). That said, you can always define two
layouts which differ only in the master layout, (e.g. `tile' and `col').
Or if we feel progressive, let's make DWM aware of the master layout as
well as the slave layout, although I don't see practical need so far.
Similarly, I also considered to enable toggling master/slave splitting
direction, effectively "rotating" the layout, or even allow "flipping",
but then thought it not useful in practice...
>
> Cheers,
> Rob
>
Thanks for you patch, I looked at it and it is indeed interesting.
However it needs further testing and review in order to be a candidate
for mainline at some point.
Some remarks:
The change of the Layout struct makes it a lot harder to define
layouts, as now one also has to understand the variables
nmaster/mfact. Also nmaster/mfact are now layout specific variables
that might not be used by other layouts. This lacks a bit conceptual
clarity imho.
What I'd really prefer is keeping the interface intact we had, a
layout is just a function -- I have no objections that this function
calls other functions or set up some variables to fit its needs. This
would keep it equally simple to the user to define Layouts and leave
the interface to be a function, rather than a function + variables.
Also I'm not absolutely happy about the introduction of the Booth
struct, I would rename that into Rect as we have used a similar name
in other areas. Having said this, I'm in favor of *not* using
XRectangle where possible, in order to keep the core code of dwm X
agnostic (which is one 6.0 goal btw).
Cheers,
Anselm
This progressive approach will lead to two layout actions in a single
view just for a subset of layouts. Overall this will make the usage
much more complicated which is why I would not implement it in
mainline dwm. See my other mail, I suggest making the layout approach
more direct through (re)setting nmaster/mfact in the layout function
as precondition. I'm not totally opposed to have manipulators of
nmaster/mfact optionally though.
> Similarly, I also considered to enable toggling master/slave splitting
> direction, effectively "rotating" the layout, or even allow "flipping",
> but then thought it not useful in practice...
Nah, don't go there. At the end of the day the user applies a
particular layout he feels comfortable with. If the user ends up
fiddling with the layout algorithms all the time then we did something
seriously wrong.
We should never forget that it is the window managers job to manage
the windows, not the users job. Even having a mfact manipulator as of
today does violate this paradigm already a bit.
Cheers,
Anselm
Can't agree more.
> Some remarks:
>
> The change of the Layout struct makes it a lot harder to define
> layouts, as now one also has to understand the variables
> nmaster/mfact. Also nmaster/mfact are now layout specific variables
> that might not be used by other layouts. This lacks a bit conceptual
> clarity imho.
>
I also agree with what you said here, but let me clarify my intention.
I really think it more useful to make mfact/nmaster layout-specific,
otherwise I wounldn't have made the change to the Layout struct. For
example, on my 1280x800 screen, mfact == 0.75 combined with nmaster == 2
in the n?col layout makes a nice layout, but the combination is very
bad for the tile layout. As such, sharing mfact/nmaster across layouts
isn't exactly nice, nor is it "dynamic" enough.
But now I realize another problem with moving mfact/nmaster to Layout.
The issue is two monitors should be able to use different mfact/nmaster
values for the same layout; also, the setmfact/incnmaster functions
will not update the unselected monitor, but will have their effects all
of a sudden next time that monitor is arranged.
This makes me want to make nmaster/mfact specific to the monitor *and*
the layout. And I also prefer achieving this in the least intrusive
way possible.
> What I'd really prefer is keeping the interface intact we had, a
> layout is just a function -- I have no objections that this function
> calls other functions or set up some variables to fit its needs. This
> would keep it equally simple to the user to define Layouts and leave
> the interface to be a function, rather than a function + variables.
>
You are absolutely right. Now that I think of it, we can temporarily
set m->mfact and/or m->nmaster in a layout function before calling
apply_mslts, and restore the values afterwards. For example, define
the col layout like this:
/* int term_width is the width of a terminal (e.g. 80 characters) */
void
col(Monitor *m) {
float mfact = m->mfact;
int nmaster = m->nmaster;
/* masters will be term_width wide */
m->nmaster = MIN(nmaster, m->ww / term_width);
m->mfact = (float)term_width * m->nmaster / m->ww;
apply_mslts(m, False, lt_hstack, lt_vstack);
m->mfact = mfact;
m->nmaster = nmaster;
}
A bit back-and-forth with the mfact calculation (since we will calculate
back to the width in apply_mslts), but it's a fair compromise, I guess.
> Also I'm not absolutely happy about the introduction of the Booth
> struct, I would rename that into Rect as we have used a similar name
> in other areas. Having said this, I'm in favor of *not* using
> XRectangle where possible, in order to keep the core code of dwm X
> agnostic (which is one 6.0 goal btw).
>
Bah, Booth is cute! Just kidding; I knew it would sound strange and
probably have to be renamed. Here we go, Rect it is.
> Cheers,
> Anselm
>
>
Exactly this is the main problem. You could work around it with
changing monitor as follows:
struct Monitor {
char ltsymbol[16];
- float mfact;
- int nmaster;
+ float mfact[LENGTH(layouts)];
+ int nmaster[LENGTH(layouts)];
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
however this would require some reshuffling of the config.h inclusion
and also changes in various places. So I doubt it would be necessary
at all. Just stick with nmaster/mfact in Monitor.
>> What I'd really prefer is keeping the interface intact we had, a
>> layout is just a function -- I have no objections that this function
>> calls other functions or set up some variables to fit its needs. This
>> would keep it equally simple to the user to define Layouts and leave
>> the interface to be a function, rather than a function + variables.
>
> You are absolutely right. Now that I think of it, we can temporarily
> set m->mfact and/or m->nmaster in a layout function before calling
> apply_mslts, and restore the values afterwards. For example, define
> the col layout like this:
>
> /* int term_width is the width of a terminal (e.g. 80 characters) */
> void
> col(Monitor *m) {
> float mfact = m->mfact;
> int nmaster = m->nmaster;
> /* masters will be term_width wide */
> m->nmaster = MIN(nmaster, m->ww / term_width);
> m->mfact = (float)term_width * m->nmaster / m->ww;
> apply_mslts(m, False, lt_hstack, lt_vstack);
> m->mfact = mfact;
> m->nmaster = nmaster;
> }
>
> A bit back-and-forth with the mfact calculation (since we will calculate
> back to the width in apply_mslts), but it's a fair compromise, I guess.
This could work for a patch, but I don't think this is a great way of
programming for mainline, since manipulating and restoring
nmaster/mfact for the time being is quite ugly. ;)
Cheers,
Anselm
Hmm, I think the difficulty is to track the index of the current layout
in the layouts array. I'm not sure how. I'd like to stick with the
current Monitor struct.
>> You are absolutely right. Now that I think of it, we can temporarily
>> set m->mfact and/or m->nmaster in a layout function before calling
>> apply_mslts, and restore the values afterwards. For example, define
>> the col layout like this:
>>
>> /* int term_width is the width of a terminal (e.g. 80 characters) */
>> void
>> col(Monitor *m) {
>> float mfact = m->mfact;
>> int nmaster = m->nmaster;
>> /* masters will be term_width wide */
>> m->nmaster = MIN(nmaster, m->ww / term_width);
>> m->mfact = (float)term_width * m->nmaster / m->ww;
>> apply_mslts(m, False, lt_hstack, lt_vstack);
>> m->mfact = mfact;
>> m->nmaster = nmaster;
>> }
>>
>> A bit back-and-forth with the mfact calculation (since we will calculate
>> back to the width in apply_mslts), but it's a fair compromise, I guess.
>
> This could work for a patch, but I don't think this is a great way of
> programming for mainline, since manipulating and restoring
> nmaster/mfact for the time being is quite ugly. ;)
Well, it's a compromise. Would you feel it's less ugly if I define the
apply_mslts function like this:
tatic void apply_mslts(Monitor *m, Bool hsplit,
float mfact, int nmaster,
void (*mltf)(Client **, Booth *, unsigned int),
void (*sltf)(Client **, Booth *, unsigned int)) {
/* uses mfact instead of m->mfact, nmaster intead of m->nmaster */
}
and define the layouts like:
void
col(Monitor *m) {
int nmaster = MIN(m->nmaster, m->ww / term_width);
float mfact = (float)term_width * nmaster / m->ww;
apply_mslts(m, False, mfact, nmaster, lt_hstack, lt_vstack);
}
void
tile(Monitor *m) {
apply_mslts(m, False, m->mfact, m->nmaster, lt_vstack, lt_vstack);
}
Basically the same thing, I guess it's still ugly, but does it feel less
ugly? :D
>
> Cheers,
> Anselm
>
>
Hmm, ok.
>> This could work for a patch, but I don't think this is a great way of
>> programming for mainline, since manipulating and restoring
>> nmaster/mfact for the time being is quite ugly. ;)
>
> Well, it's a compromise. Would you feel it's less ugly if I define the
> apply_mslts function like this:
>
> tatic void apply_mslts(Monitor *m, Bool hsplit,
> float mfact, int nmaster,
> void (*mltf)(Client **, Booth *, unsigned int),
> void (*sltf)(Client **, Booth *, unsigned int)) {
> /* uses mfact instead of m->mfact, nmaster intead of m->nmaster */
> }
>
> and define the layouts like:
>
> void
> col(Monitor *m) {
> int nmaster = MIN(m->nmaster, m->ww / term_width);
> float mfact = (float)term_width * nmaster / m->ww;
> apply_mslts(m, False, mfact, nmaster, lt_hstack, lt_vstack);
> }
> void
> tile(Monitor *m) {
> apply_mslts(m, False, m->mfact, m->nmaster, lt_vstack, lt_vstack);
> }
>
> Basically the same thing, I guess it's still ugly, but does it feel less
> ugly? :D
I think this is less ugly, because you don't manipulate (like before)
m->{nmaster, mfact}.
Cheers,
Anselm
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
@@ -32,6 +32,8 @@
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
+ { "TTT", bstack },
+ { "|||", col },
};
/* key definitions */
@@ -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
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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;
@@ -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};
@@ -565,6 +642,11 @@
}
void
+col(Monitor *m) {
+ apply_mslts(m, False, lt_hstack, lt_vstack);
+}
+
+void
configure(Client *c) {
XConfigureEvent ce;
@@ -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];
@@ -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;
@@ -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
@@ -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;
@@ -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
@@ -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