diff options
Diffstat (limited to 'dwm.c')
-rw-r--r-- | dwm.c | 461 |
1 files changed, 427 insertions, 34 deletions
@@ -49,7 +49,9 @@ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define ISVISIBLEONTAG(C, T) ((C->tags & T)) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) +/* #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) */ #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -59,7 +61,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ @@ -111,6 +113,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +typedef struct Pertag Pertag; struct Monitor { char ltsymbol[16]; float mfact; @@ -130,6 +133,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; + Pertag *pertag; }; typedef struct { @@ -147,6 +151,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); +static void attachaside(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); @@ -156,7 +161,9 @@ static void clientmessage(XEvent *e); static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); +static void copyvalidchars(char *text, char *rawtext); static Monitor *createmon(void); +static void deck(Monitor *m); static void destroynotify(XEvent *e); static void detach(Client *c); static void detachstack(Client *c); @@ -176,6 +183,7 @@ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); static void incnmaster(const Arg *arg); +static void inplacerotate(const Arg *arg); static void keypress(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); @@ -184,6 +192,7 @@ static void maprequest(XEvent *e); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); +static Client *nexttagged(Client *c); static Client *nexttiled(Client *c); static void pop(Client *c); static void propertynotify(XEvent *e); @@ -200,6 +209,7 @@ static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); @@ -211,6 +221,7 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); +static void togglescratch(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); @@ -233,10 +244,15 @@ static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); +static void centeredmaster(Monitor *m); +static void centeredfloatingmaster(Monitor *m); /* variables */ static const char broken[] = "broken"; static char stext[256]; +static char rawstext[256]; +static int statuscmdn; +static char lastbutton[] = "-"; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ @@ -269,8 +285,22 @@ static Monitor *mons, *selmon; static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ +// TODO: Figure out if there is a better way of doing this +#define TAG_SIZE 9 +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[TAG_SIZE + 1]; /* number of windows in master area */ + float mfacts[TAG_SIZE + 1]; /* mfacts per tag */ + unsigned int sellts[TAG_SIZE + 1]; /* selected layouts */ + const Layout *ltidxs[TAG_SIZE + 1][2]; /* matrix of tags and layouts indexes */ + int showbars[TAG_SIZE + 1]; /* display bar for the current tag */ + int gaps[TAG_SIZE + 1]; /* size of gaps for the current tag*/ +}; + #include "config.h" +static unsigned int scratchtag = 1 << LENGTH(tags); + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -409,6 +439,17 @@ attach(Client *c) } void +attachaside(Client *c) { + Client *at = nexttagged(c); + if(!at) { + attach(c); + return; + } + c->next = at->next; + at->next = c; +} + +void attachstack(Client *c) { c->snext = c->mon->stack; @@ -418,11 +459,12 @@ attachstack(Client *c) void buttonpress(XEvent *e) { - unsigned int i, x, click; - Arg arg = {0}; + unsigned int i, x, click, occ = 0; Client *c; + Arg arg = {0}; Monitor *m; XButtonPressedEvent *ev = &e->xbutton; + *lastbutton = '0' + ev->button; click = ClkRootWin; /* focus monitor if necessary */ @@ -433,9 +475,14 @@ buttonpress(XEvent *e) } if (ev->window == selmon->barwin) { i = x = 0; - do + for (c = m->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + do { + /* do not reserve space for vacant tags */ + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; x += TEXTW(tags[i]); - while (ev->x >= x && ++i < LENGTH(tags)); + } while (ev->x >= x && ++i < LENGTH(tags)); if (i < LENGTH(tags)) { click = ClkTagBar; arg.ui = 1 << i; @@ -445,6 +492,22 @@ buttonpress(XEvent *e) click = ClkStatusText; else click = ClkWinTitle; + char *text = rawstext; + int i = -1; + char ch; + statuscmdn = 0; + while (text[++i]) { + if ((unsigned char)text[i] < ' ') { + ch = text[i]; + text[i] = '\0'; + x += TEXTW(text) - lrpad; + text[i] = ch; + text += i+1; + i = -1; + if (x >= ev->x) break; + if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; + } + } } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -630,10 +693,24 @@ configurerequest(XEvent *e) XSync(dpy, False); } +void +copyvalidchars(char *text, char *rawtext) +{ + int i = -1, j = 0; + + while(rawtext[++i]) { + if ((unsigned char)rawtext[i] >= ' ') { + text[j++] = rawtext[i]; + } + } + text[j] = '\0'; +} + Monitor * createmon(void) { Monitor *m; + unsigned int i; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; @@ -644,6 +721,21 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + m->pertag->gaps[i] = gappx; + } + return m; } @@ -658,6 +750,35 @@ destroynotify(XEvent *e) } void +deck(Monitor *m) { + unsigned int i, n, h, mw, my, ns, gap_size; + 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; + ns = m->nmaster > 0 ? 2 : 1; + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); + } else { + mw = m->ww; + ns = 1; + } + + gap_size = m->pertag->gaps[m->pertag->curtag]; + for(i = 0, my = gap_size, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gap_size; + resize(c, m->wx + gap_size, m->wy + my, mw - (2*c->bw) - gap_size*(5-ns)/2, h - (2*c->bw), False); + my += HEIGHT(c) + gap_size; + } + else + resize(c, m->wx + mw + gap_size/ns, m->wy + gap_size, m->ww - mw - (2*c->bw) - gap_size*(5-ns)/2, m->wh - (2*c->bw) - 2*gap_size, False); +} + +void detach(Client *c) { Client **tc; @@ -709,25 +830,28 @@ drawbar(Monitor *m) /* draw status first so it can be overdrawn by tags later */ if (m == selmon) { /* status is only drawn on selected monitor */ - drw_setscheme(drw, scheme[SchemeNorm]); + drw_setscheme(drw, scheme[SchemeStatus]); tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); } for (c = m->clients; c; c = c->next) { - occ |= c->tags; + occ |= c->tags == 255 ? 0 : c->tags; if (c->isurgent) urg |= c->tags; } x = 0; for (i = 0; i < LENGTH(tags); i++) { + /* do not draw vacant tags */ + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; w = TEXTW(tags[i]); - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); - if (occ & 1 << i) - drw_rect(drw, x + boxs, boxs, boxw, boxw, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); + /* if (occ & 1 << i) */ + /* drw_rect(drw, x + boxs, boxs, boxw, boxw, */ + /* m == selmon && selmon->sel && selmon->sel->tags & 1 << i, */ + /* urg & 1 << i); */ x += w; } w = TEXTW(m->ltsymbol); @@ -736,12 +860,12 @@ drawbar(Monitor *m) if ((w = m->ww - tw - x) > bh) { if (m->sel) { - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); if (m->sel->isfloating) drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); } else { - drw_setscheme(drw, scheme[SchemeNorm]); + drw_setscheme(drw, scheme[SchemeInfoNorm]); drw_rect(drw, x, 0, w, bh, 1, 1); } } @@ -980,7 +1104,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1061,6 +1185,14 @@ manage(Window w, XWindowAttributes *wa) c->y = MAX(c->y, c->mon->wy); c->bw = borderpx; + selmon->tagset[selmon->seltags] &= ~scratchtag; + if (!strcmp(c->name, scratchpadname)) { + c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag; + c->isfloating = True; + c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); + c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); + } + wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); @@ -1074,10 +1206,11 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); + /* attachaside(c); */ attach(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); + (unsigned char *) &(c->win), 1); XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ setclientstate(c, NormalState); if (c->mon == selmon) @@ -1121,8 +1254,12 @@ monocle(Monitor *m) n++; if (n > 0) /* override layout symbol */ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + const int gap_size = m->pertag->gaps[m->pertag->curtag]; 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, 0); + resize(c, m->wx + gap_size, m->wy + gap_size, + m->ww - 2 * c->bw - (2 * gap_size), + m->wh - 2 * c->bw - (2 * gap_size), + 0); } void @@ -1203,6 +1340,16 @@ movemouse(const Arg *arg) } Client * +nexttagged(Client *c) { + Client *walked = c->mon->clients; + for(; + walked && (walked->isfloating || !ISVISIBLEONTAG(walked, c->tags)); + walked = walked->next + ); + return walked; +} + +Client * nexttiled(Client *c) { for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); @@ -1427,6 +1574,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + /* attachaside(c); */ attach(c); attachstack(c); focus(NULL); @@ -1508,12 +1656,23 @@ setfullscreen(Client *c, int fullscreen) } void +setgaps(const Arg *arg) +{ + int *gap_size = &selmon->pertag->gaps[selmon->pertag->curtag]; + if ((arg->i == 0) || ((*gap_size) + arg->i < 0)) + *gap_size = 0; + else + *gap_size += arg->i; + arrange(selmon); +} + +void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1532,7 +1691,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -1648,9 +1807,7 @@ void spawn(const Arg *arg) { struct sigaction sa; - - if (arg->v == dmenucmd) - dmenumon[0] = '0' + selmon->num; + selmon->tagset[selmon->seltags] &= ~scratchtag; if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); @@ -1694,28 +1851,29 @@ tile(Monitor *m) if (n == 0) return; + const int gap_size = m->pertag->gaps[m->pertag->curtag]; 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++) + mw = m->ww - gap_size; + for (i = 0, my = ty = gap_size, 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), 0); + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - gap_size; + resize(c, m->wx + gap_size, m->wy + my, mw - (2*c->bw) - gap_size, h - (2*c->bw), 0); if (my + HEIGHT(c) < m->wh) - my += HEIGHT(c); + my += HEIGHT(c) + gap_size; } 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), 0); + h = (m->wh - ty) / (n - i) - gap_size; + resize(c, m->wx + mw + gap_size, m->wy + ty, m->ww - mw - (2*c->bw) - 2*gap_size, h - (2*c->bw), 0); if (ty + HEIGHT(c) < m->wh) - ty += HEIGHT(c); + ty += HEIGHT(c) + gap_size; } } void togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); @@ -1736,6 +1894,28 @@ togglefloating(const Arg *arg) } void +togglescratch(const Arg *arg) +{ + Client *c; + unsigned int found = 0; + + for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); + if (found) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + if (ISVISIBLE(c)) { + focus(c); + restack(selmon); + } + } else + spawn(arg); +} + +void toggletag(const Arg *arg) { unsigned int newtags; @@ -1754,9 +1934,33 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; + + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2005,8 +2209,10 @@ updatesizehints(Client *c) void updatestatus(void) { - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) strcpy(stext, "dwm-"VERSION); + else + copyvalidchars(stext, rawstext); drawbar(selmon); } @@ -2053,11 +2259,37 @@ updatewmhints(Client *c) void view(const Arg *arg) { + int i; + unsigned int tmptag; + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & TAGMASK) { selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + focus(NULL); arrange(selmon); } @@ -2163,3 +2395,164 @@ main(int argc, char *argv[]) XCloseDisplay(dpy); return EXIT_SUCCESS; } + +void +insertclient(Client *item, Client *insertItem, int after) { + Client *c; + if (item == NULL || insertItem == NULL || item == insertItem) return; + detach(insertItem); + if (!after && selmon->clients == item) { + attach(insertItem); + return; + } + if (after) { + c = item; + } else { + for (c = selmon->clients; c; c = c->next) { if (c->next == item) break; } + } + insertItem->next = c->next; + c->next = insertItem; +} + +void +inplacerotate(const Arg *arg) +{ + if(!selmon->sel || (selmon->sel->isfloating && !arg->f)) return; + + unsigned int selidx = 0, i = 0; + Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; + + // Determine positionings for insertclient + for (c = selmon->clients; c; c = c->next) { + if (ISVISIBLE(c) && !(c->isfloating)) { + if (selmon->sel == c) { selidx = i; } + if (i == selmon->nmaster - 1) { mtail = c; } + if (i == selmon->nmaster) { shead = c; } + if (mhead == NULL) { mhead = c; } + stail = c; + i++; + } + } + + // All clients rotate + if (arg->i == 2) insertclient(selmon->clients, stail, 0); + if (arg->i == -2) insertclient(stail, selmon->clients, 1); + // Stack xor master rotate + if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); + if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); + if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); + if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); + + // Restore focus position + i = 0; + for (c = selmon->clients; c; c = c->next) { + if (!ISVISIBLE(c) || (c->isfloating)) continue; + if (i == selidx) { focus(c); break; } + i++; + } + arrange(selmon); + focus(c); +} + +void +centeredmaster(Monitor *m) +{ + unsigned int i, n, h, mw, mx, my, oty, ety, tw; + Client *c; + + /* count number of clients in the selected monitor */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + /* initialize areas */ + mw = m->ww; + mx = 0; + my = 0; + tw = mw; + + if (n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + mw = m->nmaster ? m->ww * m->mfact : 0; + tw = m->ww - mw; + + if (n - m->nmaster > 1) { + /* only one client */ + mx = (m->ww - mw) / 2; + tw = (m->ww - mw) / 2; + } + } + + oty = 0; + ety = 0; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + /* nmaster clients are stacked vertically, in the center + * of the screen */ + h = (m->wh - my) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), + h - (2*c->bw), 0); + my += HEIGHT(c); + } else { + /* stack clients are stacked vertically */ + if ((i - m->nmaster) % 2 ) { + h = (m->wh - ety) / ( (1 + n - i) / 2); + resize(c, m->wx, m->wy + ety, tw - (2*c->bw), + h - (2*c->bw), 0); + ety += HEIGHT(c); + } else { + h = (m->wh - oty) / ((1 + n - i) / 2); + resize(c, m->wx + mx + mw, m->wy + oty, + tw - (2*c->bw), h - (2*c->bw), 0); + oty += HEIGHT(c); + } + } +} + +void +centeredfloatingmaster(Monitor *m) +{ + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + + /* count number of clients in the selected monitor */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + /* initialize nmaster area */ + if (n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + if (m->ww > m->wh) { + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * 0.9 : 0; + } else { + mh = m->nmaster ? m->wh * m->mfact : 0; + mw = m->nmaster ? m->ww * 0.9 : 0; + } + mx = mxo = (m->ww - mw) / 2; + my = myo = (m->wh - mh) / 2; + } else { + /* go fullscreen if all clients are in the master area */ + mh = m->wh; + mw = m->ww; + mx = mxo = 0; + my = myo = 0; + } + + for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + /* nmaster clients are stacked horizontally, in the center + * of the screen */ + w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), + mh - (2*c->bw), 0); + mx += WIDTH(c); + } else { + /* stack clients are stacked horizontally */ + w = (m->ww - tx) / (n - i); + resize(c, m->wx + tx, m->wy, w - (2*c->bw), + m->wh - (2*c->bw), 0); + tx += WIDTH(c); + } +} |