# HG changeset patch # User lolilolicon # Date 1320098001 -28800 # Node ID f35ce5cc96363a813f91e64f6eda30504052eeed # Parent 904e923827cb010abb7a31298264548946616d92 A general approach to master-slave layouts This makes the actual code implementing layout algorithms reusable. Apply two separate layout algorithms to the master area and the slave area. The master and slave areas are separated by either vertical or horizontal split. The `tile' algorithm is split out as `lt_vstack` and the `tile' function is now just a one-liner. Due to the reusability, the `bstack' and `col' layouts are added with few lines of code. Other interesting layout combinations can be easily added in the same manner. Move mfact and nmaster to the Layout structure, so that each layout can have its own mfact and nmaster. This makes sense when using several master-slave layouts, e.g., the `col' layout will usually use a mfact larger than `tile'. diff --git a/config.def.h b/config.def.h --- a/config.def.h +++ b/config.def.h @@ -23,15 +23,15 @@ }; /* layout(s) */ -static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ -static const int nmaster = 1; /* number of clients in master area */ static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ -static const Layout layouts[] = { - /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, +static Layout layouts[] = { + /* symbol arrange function mfact nmaster */ + { "[]=", tile, 0.55, 1 }, /* first entry is default */ + { "><>", NULL, 0.5, 0 }, /* no layout function means floating behavior */ + { "[M]", monocle, 0.5, 0 }, + { "TTT", bstack, 0.55, 1 }, + { "|||", col, 0.75, 2 }, }; /* key definitions */ @@ -66,6 +66,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 --git a/dwm.c b/dwm.c --- a/dwm.c +++ b/dwm.c @@ -71,6 +71,10 @@ } Arg; typedef struct { + int x, y, w, h; +} Booth; + +typedef struct { unsigned int click; unsigned int mask; unsigned int button; @@ -120,12 +124,12 @@ typedef struct { const char *symbol; void (*arrange)(Monitor *); + float mfact; + int nmaster; } Layout; struct Monitor { char ltsymbol[16]; - float mfact; - int nmaster; int num; int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ @@ -140,7 +144,7 @@ Client *stack; Monitor *next; Window barwin; - const Layout *lt[2]; + Layout *lt[2]; }; typedef struct { @@ -153,18 +157,23 @@ } Rule; /* function declarations */ +static void apply_mslts(Monitor *m, Bool hsplit, + void (*mltf)(Client **, Booth *, unsigned int), /* master layout function */ + void (*sltf)(Client **, Booth *, 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); @@ -194,6 +203,8 @@ static void initfont(const char *fontstr); static void keypress(XEvent *e); static void killclient(const Arg *arg); +static void lt_hstack(Client **c, Booth *b, unsigned int n); +static void lt_vstack(Client **c, Booth *b, unsigned int n); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); @@ -286,6 +297,53 @@ /* function implementations */ void +apply_mslts(Monitor *m, Bool hsplit, + void (*mltf)(Client **, Booth *, unsigned int), + void (*sltf)(Client **, Booth *, unsigned int)) { + unsigned int nm, n; + Client *c; + + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + nm = MIN(n, m->lt[m->sellt]->nmaster); /* number of masters */ + + if (nm == 0) { + /* all slaves */ + c = m->clients; + Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh }; + (*sltf)(&c, &b, n); + } + else if(n > nm) { + /* masters and slaves */ + c = m->clients; + if(hsplit) { + /* masters above slaves */ + Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh * m->lt[m->sellt]->mfact }; + (*mltf)(&c, &b, nm); + b.y += b.h; + b.h = m->wh - b.h; + (*sltf)(&c, &b, n - nm); + } + else { + /* masters at the left of slaves */ + Booth b = { .x = m->wx, .y = m->wy, .w = m->ww * m->lt[m->sellt]->mfact, .h = m->wh }; + (*mltf)(&c, &b, nm); + b.x += b.w; + b.w = m->ww - b.w; + (*sltf)(&c, &b, n - nm); + } + } + else { + /* all masters */ + c = m->clients; + Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh }; + (*mltf)(&c, &b, n); + } +} + +void applyrules(Client *c) { const char *class, *instance; unsigned int i; @@ -418,6 +476,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 +628,11 @@ } void +col(Monitor *m) { + apply_mslts(m, False, lt_hstack, lt_vstack); +} + +void configure(Client *c) { XConfigureEvent ce; @@ -665,8 +733,6 @@ 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; m->showbar = showbar; m->topbar = topbar; m->lt[0] = &layouts[0]; @@ -1028,7 +1094,7 @@ void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->lt[selmon->sellt]->nmaster = MAX(selmon->lt[selmon->sellt]->nmaster + arg->i, 0); arrange(selmon); } @@ -1108,6 +1174,36 @@ } void +lt_hstack(Client **c, Booth *b, unsigned int n) { + unsigned int i; + int x, y, w, h; + + x = b->x; /* x offset of the next cell */ + y = b->y; + h = b->h; + for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) { + w = (b->x + b->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, Booth *b, unsigned int n) { + unsigned int i; + int x, y, w, h; + + x = b->x; + y = b->y; /* y offset of the next cell */ + w = b->w; + for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) { + h = (b->y + b->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; @@ -1530,10 +1626,10 @@ if(!arg || !selmon->lt[selmon->sellt]->arrange) return; - f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + f = arg->f < 1.0 ? arg->f + selmon->lt[selmon->sellt]->mfact : arg->f - 1.0; if(f < 0.1 || f > 0.9) return; - selmon->mfact = f; + selmon->lt[selmon->sellt]->mfact = f; arrange(selmon); } @@ -1659,28 +1755,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