diff -r 1228e3d45d25 config.def.h --- a/config.def.h Wed Nov 02 12:01:28 2011 +0000 +++ b/config.def.h Sun Nov 06 09:28:12 2011 -0800 @@ -23,15 +23,18 @@ }; /* layout(s) */ +static const Bool vsplit = True; /* True means vertical split between master/slave to start */ 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 */ + { "==", lt_stack_vert }, /* first entry is default */ + { "||", lt_stack_horz }, + { "++", lt_grid }, + { "[]", lt_monocle }, { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, }; /* key definitions */ @@ -63,11 +66,32 @@ { MODKEY, XK_Return, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_c, killclient, {0} }, - { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, - { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, - { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, - { MODKEY, XK_space, setlayout, {0} }, - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY|ShiftMask, XK_t, setmlayout, {.v = &layouts[0]} }, + { MODKEY|ShiftMask, XK_s, setmlayout, {.v = &layouts[1]} }, + { MODKEY|ShiftMask, XK_g, setmlayout, {.v = &layouts[2]} }, + { MODKEY|ShiftMask, XK_m, setmlayout, {.v = &layouts[3]} }, + { MODKEY|ShiftMask, XK_space, setmlayout, {0} }, + { MODKEY|ControlMask, XK_t, setslayout, {.v = &layouts[0]} }, + { MODKEY|ControlMask, XK_s, setslayout, {.v = &layouts[1]} }, + { MODKEY|ControlMask, XK_g, setslayout, {.v = &layouts[2]} }, + { MODKEY|ControlMask, XK_m, setslayout, {.v = &layouts[3]} }, + { MODKEY|ControlMask, XK_space, setslayout, {0} }, + { MODKEY, XK_v, setsplit, {.i = -1} }, + { MODKEY|ControlMask|ShiftMask, XK_space, togglefloating, {0} }, + /* traditional tile */ + { MODKEY, XK_t, setmlayout, {.v = &layouts[0]} }, + { MODKEY, XK_t, setslayout, {.v = &layouts[0]} }, + { MODKEY, XK_t, setsplit, {.i = 1} }, + { MODKEY, XK_t, setnmaster, {.ui = 1} }, + /* traditional monocle */ + { MODKEY, XK_m, setslayout, {.v = &layouts[3]} }, + { MODKEY, XK_m, setnmaster, {.i = 0} }, + /* floating */ + { MODKEY|ShiftMask, XK_f, setmlayout, {.v = &layouts[4]} }, + /* traditional "last layout" */ + { MODKEY, XK_space, setmlayout, {0} }, + { MODKEY, XK_space, setslayout, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, { MODKEY, XK_comma, focusmon, {.i = -1 } }, @@ -90,8 +114,8 @@ /* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ static Button buttons[] = { /* click event mask button function argument */ - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkLtSymbol, 0, Button1, setmlayout, {0} }, + { ClkLtSymbol, 0, Button3, setslayout, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, diff -r 1228e3d45d25 dwm.c --- a/dwm.c Wed Nov 02 12:01:28 2011 +0000 +++ b/dwm.c Sun Nov 06 09:28:12 2011 -0800 @@ -72,6 +72,10 @@ } Arg; typedef struct { + unsigned int x, y, w, h; +} Area; + +typedef struct { unsigned int click; unsigned int mask; unsigned int button; @@ -120,19 +124,20 @@ typedef struct { const char *symbol; - void (*arrange)(Monitor *); + void (*arrange)(Client **, unsigned int, Area *); } Layout; struct Monitor { char ltsymbol[16]; float mfact; int nmaster; + Bool vsplit; /* vertical separation between master/slave */ 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 selltm, sellts; /* sel lt master/slave */ unsigned int tagset[2]; Bool showbar; Bool topbar; @@ -141,7 +146,8 @@ Client *stack; Monitor *next; Window barwin; - const Layout *lt[2]; + const Layout *ltm[2]; /* master */ + const Layout *lts[2]; /* slave */ }; typedef struct { @@ -195,10 +201,13 @@ static void initfont(const char *fontstr); static void keypress(XEvent *e); static void killclient(const Arg *arg); +static void lt_grid(Client **beg, unsigned int num, Area *a); +static void lt_stack_vert(Client **beg, unsigned int num, Area *a); +static void lt_stack_horz(Client **beg, unsigned int num, Area *a); +static void lt_monocle(Client **beg, unsigned int num, Area *a); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); -static void monocle(Monitor *m); static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); static void pop(Client *); @@ -214,8 +223,11 @@ static Bool sendevent(Client *c, Atom proto); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); +static void setnmaster(const Arg *arg); static void setfocus(Client *c); -static void setlayout(const Arg *arg); +static void setmlayout(const Arg *arg); +static void setslayout(const Arg *arg); +static void setsplit(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); static void showhide(Client *c); @@ -224,7 +236,6 @@ static void tag(const Arg *arg); static void tagmon(const Arg *arg); static int textnw(const char *text, unsigned int len); -static void tile(Monitor *); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); @@ -353,7 +364,7 @@ *h = bh; if(*w < bh) *w = bh; - if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + if(resizehints || c->isfloating || !c->mon->ltm[c->mon->selltm]->arrange) { /* see last two sentences in ICCCM 4.1.2.3 */ baseismin = c->basew == c->minw && c->baseh == c->minh; if(!baseismin) { /* temporarily remove base dimensions */ @@ -401,9 +412,32 @@ void arrangemon(Monitor *m) { - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); - if(m->lt[m->sellt]->arrange) - m->lt[m->sellt]->arrange(m); + unsigned int n; + Area a; + Client *c; + + sprintf(m->ltsymbol, "%s%s%s", m->ltm[m->selltm]->symbol, m->vsplit ? "|" : "/", m->lts[m->sellts]->symbol); + + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0 || !m->ltm[m->selltm]->arrange) + return; + + c = m->clients; + + a.x = m->wx; + a.y = m->wy; + a.w = (n > m->nmaster) ? ( m->vsplit ? m->ww * m->mfact : m->ww) : m->ww; + a.h = (n > m->nmaster) ? (!m->vsplit ? m->wh * m->mfact : m->wh) : m->wh; + + m->ltm[m->selltm]->arrange(&c, m->nmaster, &a); /* master */ + + a.x = (m->nmaster) ? ( m->vsplit ? a.x + a.w : a.x) : m->wx; + a.y = (m->nmaster) ? (!m->vsplit ? a.y + a.h : a.y) : m->wy; + a.w = (m->nmaster) ? ( m->vsplit ? m->ww - a.w : a.w) : m->ww; + a.h = (m->nmaster) ? (!m->vsplit ? m->wh - a.h : a.h) : m->wh; + + m->lts[m->sellts]->arrange(&c, -1, &a); /* slave */ + restack(m); } @@ -477,7 +511,8 @@ Monitor *m; view(&a); - selmon->lt[selmon->sellt] = &foo; + selmon->ltm[selmon->selltm] = &foo; + selmon->lts[selmon->sellts] = &foo; for(m = mons; m; m = m->next) while(m->stack) unmanage(m->stack, False); @@ -617,7 +652,7 @@ if((c = wintoclient(ev->window))) { if(ev->value_mask & CWBorderWidth) c->bw = ev->border_width; - else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + else if(c->isfloating || !selmon->ltm[selmon->selltm]->arrange) { m = c->mon; if(ev->value_mask & CWX) { c->oldx = c->x; @@ -668,12 +703,15 @@ die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; m->mfact = mfact; + m->vsplit = vsplit; m->nmaster = nmaster; m->showbar = showbar; m->topbar = topbar; - m->lt[0] = &layouts[0]; - m->lt[1] = &layouts[1 % LENGTH(layouts)]; - strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->ltm[0] = &layouts[0]; + m->lts[0] = &layouts[0]; + m->ltm[1] = &layouts[1 % LENGTH(layouts)]; + m->lts[1] = &layouts[1 % LENGTH(layouts)]; + sprintf(m->ltsymbol, "%s%s%s", layouts[0].symbol, vsplit ? "|" : "/", layouts[0].symbol); return m; } @@ -1198,20 +1236,6 @@ } void -monocle(Monitor *m) { - unsigned int n = 0; - Client *c; - - for(c = m->clients; c; c = c->next) - if(ISVISIBLE(c)) - n++; - if(n > 0) /* override layout symbol */ - snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); - for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) - resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); -} - -void movemouse(const Arg *arg) { int x, y, ocx, ocy, nx, ny; Client *c; @@ -1249,11 +1273,11 @@ ny = selmon->wy; else if(abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) ny = selmon->wy + selmon->wh - HEIGHT(c); - if(!c->isfloating && selmon->lt[selmon->sellt]->arrange + if(!c->isfloating && selmon->ltm[selmon->selltm]->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) togglefloating(NULL); } - if(!selmon->lt[selmon->sellt]->arrange || c->isfloating) + if(!selmon->ltm[selmon->selltm]->arrange || c->isfloating) resize(c, nx, ny, c->w, c->h, True); break; } @@ -1382,11 +1406,11 @@ if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) { - if(!c->isfloating && selmon->lt[selmon->sellt]->arrange + if(!c->isfloating && selmon->ltm[selmon->selltm]->arrange && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) togglefloating(NULL); } - if(!selmon->lt[selmon->sellt]->arrange || c->isfloating) + if(!selmon->ltm[selmon->selltm]->arrange || c->isfloating) resize(c, c->x, c->y, nw, nh, True); break; } @@ -1410,9 +1434,9 @@ drawbar(m); if(!m->sel) return; - if(m->sel->isfloating || !m->lt[m->sellt]->arrange) + if(m->sel->isfloating || !m->ltm[m->selltm]->arrange) XRaiseWindow(dpy, m->sel->win); - if(m->lt[m->sellt]->arrange) { + if(m->ltm[m->selltm]->arrange) { wc.stack_mode = Below; wc.sibling = m->barwin; for(c = m->stack; c; c = c->snext) @@ -1484,6 +1508,12 @@ PropModeReplace, (unsigned char *)data, 2); } +void +setnmaster(const Arg *arg) { + selmon->nmaster = MAX(arg->ui, 0); + arrange(selmon); +} + Bool sendevent(Client *c, Atom proto) { int n; @@ -1516,24 +1546,47 @@ } void -setlayout(const Arg *arg) { - if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; +setmlayout(const Arg *arg) { + if(!arg || !arg->v || arg->v != selmon->ltm[selmon->selltm]) + selmon->selltm ^= 1; if(arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; - strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + selmon->ltm[selmon->selltm] = (Layout *)arg->v; + sprintf(selmon->ltsymbol, "%s%s%s", selmon->ltm[selmon->selltm]->symbol, selmon->vsplit ? "|" : "/", selmon->lts[selmon->sellts]->symbol); if(selmon->sel) arrange(selmon); else drawbar(selmon); } +void +setslayout(const Arg *arg) { + if(!arg || !arg->v || arg->v != selmon->lts[selmon->sellts]) + selmon->sellts ^= 1; + if(arg && arg->v) + selmon->lts[selmon->sellts] = (Layout *)arg->v; + sprintf(selmon->ltsymbol, "%s%s%s", selmon->ltm[selmon->selltm]->symbol, selmon->vsplit ? "|" : "/", selmon->lts[selmon->sellts]->symbol); + if(selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +void +setsplit(const Arg *arg) { + switch (arg->i) { + case 0: selmon->vsplit = False; break; + case 1: selmon->vsplit = True; break; + case -1: selmon->vsplit = !selmon->vsplit; break; + } + arrange(selmon); +} + /* arg > 1.0 will set mfact absolutly */ void setmfact(const Arg *arg) { float f; - if(!arg || !selmon->lt[selmon->sellt]->arrange) + if(!arg || !selmon->ltm[selmon->selltm]->arrange) return; f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if(f < 0.1 || f > 0.9) @@ -1607,7 +1660,7 @@ return; if(ISVISIBLE(c)) { /* show clients top down */ XMoveWindow(dpy, c->win, c->x, c->y); - if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + if((!c->mon->ltm[c->mon->selltm]->arrange || c->isfloating) && !c->isfullscreen) resize(c, c->x, c->y, c->w, c->h, False); showhide(c->snext); } @@ -1665,29 +1718,80 @@ } void -tile(Monitor *m) { - unsigned int i, n, h, mw, my, ty; +lt_grid(Client **beg, unsigned int num, Area *a) { + unsigned int i, n, x, y, w, h, rows, cols; Client *c; - for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + for(n = 0, c = nexttiled(*beg); 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); - } + n = (num >= 0) ? MIN(n, num) : n; + + for(cols = 0; cols * cols < n; cols++); + rows = n / cols + !!(n % cols); + + w = a->w / cols; + h = a->h / rows; + + for(i = 0, c = nexttiled(*beg); c && i != num; c = nexttiled(c->next), i++) { + x = a->x + i / rows * w; + y = a->y + i % rows * h; + resize(c, x, y, w - (2*c->bw), h - (2*c->bw), False); + } + + *beg = c; +} + +void +lt_stack_vert(Client **beg, unsigned int num, Area *a) { + unsigned int i, n, y, h; + Client *c; + + for(n = 0, c = nexttiled(*beg); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + n = (num >= 0) ? MIN(n, num) : n; + + for(i = y = 0, c = nexttiled(*beg); c && i != num; c = nexttiled(c->next), i++) { + h = (a->h - y) / (n - i); + resize(c, a->x, a->y + y, a->w - (2*c->bw), h - (2*c->bw), False); + y += HEIGHT(c); + } + + *beg = c; +} + +void +lt_stack_horz(Client **beg, unsigned int num, Area *a) { + unsigned int i, n, x, w; + Client *c; + + for(n = 0, c = nexttiled(*beg); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + n = (num >= 0) ? MIN(n, num) : n; + + for(i = x = 0, c = nexttiled(*beg); c && i != num; c = nexttiled(c->next), i++) { + w = (a->w - x) / (n - i); + resize(c, a->x + x, a->y, w - (2*c->bw), a->h - (2*c->bw), False); + x += WIDTH(c); + } + + *beg = c; +} + +void +lt_monocle(Client **beg, unsigned int num, Area *a) { + unsigned int i; + Client *c; + + for(i = 0, c = nexttiled(*beg); c && i != num; c = nexttiled(c->next), i++) + resize(c, a->x, a->y, a->w - (2*c->bw), a->h - (2*c->bw), False); + + *beg = c; } void @@ -2087,7 +2191,7 @@ zoom(const Arg *arg) { Client *c = selmon->sel; - if(!selmon->lt[selmon->sellt]->arrange + if(!selmon->ltm[selmon->selltm]->arrange || (selmon->sel && selmon->sel->isfloating)) return; if(c == nexttiled(selmon->clients))