Created
November 6, 2011 16:18
-
-
Save ropery/1343109 to your computer and use it in GitHub Desktop.
dwm patch: a general approach to master-slave layouts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User lolilolicon <[email protected]> | |
# Date 1320595974 -28800 | |
# Node ID 5776983c49e43b864db2de06225f1450d76bcd89 | |
# Parent 183cedbebe526a782ecf323d46e7f0fad97eb7e9 | |
Import the master-slave layout idea, with new layouts. | |
diff -r 183cedbebe52 -r 5776983c49e4 config.def.h | |
--- a/config.def.h Fri Nov 04 20:02:35 2011 +0100 | |
+++ b/config.def.h Mon Nov 07 00:12:54 2011 +0800 | |
@@ -32,6 +32,9 @@ | |
{ "[]=", tile }, /* first entry is default */ | |
{ "><>", NULL }, /* no layout function means floating behavior */ | |
{ "[M]", monocle }, | |
+ { "TTT", bstack }, | |
+ { "|||", col }, | |
+ { "[]@", spiral }, | |
}; | |
/* key definitions */ | |
@@ -66,6 +69,9 @@ | |
{ 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_e, setlayout, {.v = &layouts[5]} }, | |
{ MODKEY, XK_space, setlayout, {0} }, | |
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} }, | |
{ MODKEY, XK_0, view, {.ui = ~0 } }, | |
diff -r 183cedbebe52 -r 5776983c49e4 dwm.c | |
--- a/dwm.c Fri Nov 04 20:02:35 2011 +0100 | |
+++ b/dwm.c Mon Nov 07 00:12:54 2011 +0800 | |
@@ -123,26 +123,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; | |
@@ -154,18 +137,24 @@ | |
} Rule; | |
/* function declarations */ | |
+static void apply_mslts(Monitor *m, int mpos, | |
+ 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 attachslave(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); | |
@@ -186,6 +175,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); | |
@@ -195,6 +185,9 @@ | |
static void initfont(const char *fontstr); | |
static void keypress(XEvent *e); | |
static void killclient(const Arg *arg); | |
+static void lt_stackh(Client **c, Rect *r, unsigned int n); | |
+static void lt_stackv(Client **c, Rect *r, unsigned int n); | |
+static void lt_spiral(Client **c, Rect *r, unsigned int n); | |
static void manage(Window w, XWindowAttributes *wa); | |
static void mappingnotify(XEvent *e); | |
static void maprequest(XEvent *e); | |
@@ -221,6 +214,7 @@ | |
static void showhide(Client *c); | |
static void sigchld(int unused); | |
static void spawn(const Arg *arg); | |
+static void spiral(Monitor *); | |
static void tag(const Arg *arg); | |
static void tagmon(const Arg *arg); | |
static int textnw(const char *text, unsigned int len); | |
@@ -283,11 +277,98 @@ | |
/* 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, int mpos, | |
+ 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; | |
+ } | |
+ | |
+ Rect rm = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh }; | |
+ Rect rs = rm; | |
+ | |
+ c = m->clients; | |
+ /* all slaves */ | |
+ if(nm == 0 || mltf == NULL) { | |
+ (*sltf)(&c, &rs, n); | |
+ } | |
+ /* masters and slaves */ | |
+ else if(n > nm) { | |
+ switch(mpos) { | |
+ default: | |
+ case 0: /* left */ | |
+ rm.w *= f; | |
+ rs.x += rm.w; | |
+ rs.w -= rm.w; | |
+ break; | |
+ case 1: /* top */ | |
+ rm.h *= f; | |
+ rs.y += rm.h; | |
+ rs.h -= rm.h; | |
+ break; | |
+ case 2: /* right */ | |
+ rs.w *= 1 - f; | |
+ rm.x += rs.w; | |
+ rm.w -= rs.w; | |
+ break; | |
+ case 3: /* bottom */ | |
+ rs.h *= 1 - f; | |
+ rm.y += rs.h; | |
+ rm.h -= rs.h; | |
+ break; | |
+ } | |
+ (*mltf)(&c, &rm, nm); | |
+ (*sltf)(&c, &rs, n - nm); | |
+ } | |
+ /* all masters */ | |
+ else { | |
+ (*mltf)(&c, &rm, n); | |
+ } | |
+} | |
+ | |
+void | |
applyrules(Client *c) { | |
const char *class, *instance; | |
unsigned int i; | |
@@ -419,6 +500,32 @@ | |
c->mon->stack = c; | |
} | |
+/* attach as the first slave, if all master seats are taken */ | |
+void | |
+attachslave(Client *c) { | |
+ Client *tc; | |
+ int i, n; | |
+ | |
+ if(!(tc = nexttiled(c->mon->clients)) || !c->mon->sel || c->isfloating) { | |
+ attach(c); | |
+ return; | |
+ } | |
+ i = getlayoutindex(c->mon->lt[c->mon->sellt]); | |
+ n = 0 <= i && i < LENGTH(layouts) ? c->mon->nmaster[i] : nmaster; | |
+ for(i = 1; tc && i < n; tc = nexttiled(tc->next), i++); | |
+ if(n == 0 || !tc) { | |
+ attach(c); | |
+ return; | |
+ } | |
+ c->next = tc->next; | |
+ tc->next = c; | |
+} | |
+ | |
+void | |
+bstack(Monitor *m) { | |
+ apply_mslts(m, 1, lt_stackh, lt_stackh); | |
+} | |
+ | |
void | |
buttonpress(XEvent *e) { | |
unsigned int i, x, click; | |
@@ -567,6 +674,11 @@ | |
} | |
void | |
+col(Monitor *m) { | |
+ apply_mslts(m, 0, lt_stackh, lt_stackv); | |
+} | |
+ | |
+void | |
configure(Client *c) { | |
XConfigureEvent ce; | |
@@ -663,12 +775,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]; | |
@@ -938,6 +1053,13 @@ | |
return color.pixel; | |
} | |
+unsigned int | |
+getlayoutindex(const Layout *lt) { | |
+ const Layout *l; | |
+ for(l = layouts; l->arrange != lt->arrange && l - layouts < LENGTH(layouts); l++); | |
+ return (l - layouts); /* the caller shall verify return value */ | |
+} | |
+ | |
Bool | |
getrootptr(int *x, int *y) { | |
int di; | |
@@ -1030,8 +1152,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 | |
@@ -1110,6 +1242,84 @@ | |
} | |
void | |
+lt_stackh(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_stackv(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 | |
+lt_spiral(Client **c, Rect *r, unsigned int n) { | |
+ if(!(*c = nexttiled(*c))) | |
+ return; | |
+ | |
+ static int pos = 1; | |
+ const float f = 0.5; | |
+ int w, h; | |
+ | |
+ if(n > 1) { | |
+ switch(pos) { | |
+ case 0: /* left */ | |
+ resize(*c, r->x, r->y, r->w * f - 2 * (*c)->bw, r->h - 2 * (*c)->bw, False); | |
+ w = WIDTH(*c); | |
+ r->x += w; | |
+ r->w -= w; | |
+ pos = 1; | |
+ break; | |
+ case 1: /* top */ | |
+ resize(*c, r->x, r->y, r->w - 2 * (*c)->bw, r->h * f - 2 * (*c)->bw, False); | |
+ h = HEIGHT(*c); | |
+ r->y += h; | |
+ r->h -= h; | |
+ pos = 2; | |
+ break; | |
+ case 2: /* right */ | |
+ w = r->w - r->w * f; | |
+ resize(*c, r->x + w, r->y, r->w * f - 2 * (*c)->bw, r->h - 2 * (*c)->bw, False); | |
+ r->w = w; | |
+ pos = 3; | |
+ break; | |
+ case 3: /* bottom */ | |
+ h = r->h - r->h * f; | |
+ resize(*c, r->x, r->y + h, r->w - 2 * (*c)->bw, r->h * f - 2 * (*c)->bw, False); | |
+ r->h = h; | |
+ pos = 0; | |
+ break; | |
+ } | |
+ *c = (*c)->next; | |
+ lt_spiral(c, r, n - 1); | |
+ } | |
+ else { | |
+ resize(*c, r->x, r->y, r->w - 2 * (*c)->bw, r->h - 2 * (*c)->bw, False); | |
+ *c = (*c)->next; | |
+ pos = 1; /* restore to initial value */ | |
+ } | |
+} | |
+ | |
+void | |
manage(Window w, XWindowAttributes *wa) { | |
Client *c, *t = NULL; | |
Window trans = None; | |
@@ -1163,7 +1373,7 @@ | |
c->isfloating = c->oldstate = trans != None || c->isfixed; | |
if(c->isfloating) | |
XRaiseWindow(dpy, c->win); | |
- attach(c); | |
+ attachslave(c); | |
attachstack(c); | |
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ | |
setclientstate(c, NormalState); | |
@@ -1531,15 +1741,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 | |
@@ -1638,6 +1851,11 @@ | |
} | |
void | |
+spiral(Monitor *m) { | |
+ apply_mslts(m, 2, lt_spiral, lt_stackv); | |
+} | |
+ | |
+void | |
tag(const Arg *arg) { | |
if(selmon->sel && arg->ui & TAGMASK) { | |
selmon->sel->tags = arg->ui & TAGMASK; | |
@@ -1666,28 +1884,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, 0, lt_stackv, lt_stackv); | |
} | |
void |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment