Skip to content

Instantly share code, notes, and snippets.

@ropery
Created November 6, 2011 16:18
Show Gist options
  • Save ropery/1343109 to your computer and use it in GitHub Desktop.
Save ropery/1343109 to your computer and use it in GitHub Desktop.
dwm patch: a general approach to master-slave layouts
# HG changeset patch
# User lolilolicon <lolilolicon@gmail.com>
# 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