arg@327: /* arg@327: * (C)opyright MMVI Anselm R. Garbe arg@327: * See LICENSE file for license details. arg@327: */ arg@327: #include "dwm.h" arg@327: arg@380: /* static */ arg@380: arg@382: static Client * arg@487: minclient(void) { arg@382: Client *c, *min; arg@382: arg@443: if((clients && clients->isfloat) || arrange == dofloat) arg@443: return clients; /* don't touch floating order */ arg@382: for(min = c = clients; c; c = c->next) arg@382: if(c->weight < min->weight) arg@382: min = c; arg@382: return min; arg@382: } arg@382: arg@480: static Client * arg@480: nexttiled(Client *c) { arg@480: for(c = getnext(c); c && c->isfloat; c = getnext(c->next)); arg@480: return c; arg@480: } arg@480: arg@442: static void arg@487: reorder(void) { arg@382: Client *c, *newclients, *tail; arg@380: arg@382: newclients = tail = NULL; arg@382: while((c = minclient())) { arg@381: detach(c); arg@382: if(tail) { arg@382: c->prev = tail; arg@382: tail->next = c; arg@382: tail = c; arg@381: } arg@381: else arg@382: tail = newclients = c; arg@380: } arg@382: clients = newclients; arg@380: } arg@380: arg@480: static void arg@480: togglemax(Client *c) arg@480: { arg@481: XEvent ev; arg@480: if((c->ismax = !c->ismax)) { arg@480: c->rx = c->x; c->x = sx; arg@480: c->ry = c->y; c->y = bh; arg@502: c->rw = c->w; c->w = sw - 2 * BORDERPX; arg@502: c->rh = c->h; c->h = sh - bh - 2 * BORDERPX; arg@480: } arg@480: else { arg@480: c->x = c->rx; arg@480: c->y = c->ry; arg@481: c->w = c->rw; arg@481: c->h = c->rh; arg@480: } arg@480: resize(c, True, TopLeft); arg@480: while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); arg@430: } arg@430: arg@327: /* extern */ arg@327: arg@327: void (*arrange)(Arg *) = DEFMODE; arg@505: StackPos stackpos = STACKPOS; arg@327: arg@327: void arg@461: detach(Client *c) { arg@378: if(c->prev) arg@378: c->prev->next = c->next; arg@378: if(c->next) arg@378: c->next->prev = c->prev; arg@378: if(c == clients) arg@378: clients = c->next; arg@378: c->next = c->prev = NULL; arg@378: } arg@378: arg@378: void arg@461: dofloat(Arg *arg) { arg@402: Client *c; arg@400: arg@327: for(c = clients; c; c = c->next) { arg@327: if(isvisible(c)) { arg@327: resize(c, True, TopLeft); arg@327: } arg@327: else arg@327: ban(c); arg@327: } arg@446: if(!sel || !isvisible(sel)) { arg@450: for(c = stack; c && !isvisible(c); c = c->snext); arg@450: focus(c); arg@446: } arg@327: restack(); arg@327: } arg@327: arg@504: /* This algorithm is based on a (M)aster area and a (S)tacking area. arg@504: * It supports following arrangements: arg@507: * SSMMM MMMMM MMMSS arg@507: * SSMMM SSSSS MMMSS arg@504: */ arg@327: void arg@461: dotile(Arg *arg) { arg@526: unsigned int i, n, md, stackw, stackh, tw, th; arg@402: Client *c; arg@400: arg@488: for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) arg@488: n++; arg@327: arg@507: if(stackpos == StackBottom) { arg@528: md = ((sh - bh) * master) / 1000; arg@507: stackw = sw; arg@524: stackh = sh - bh - md; arg@507: } arg@507: else { arg@528: md = (sw * master) / 1000; arg@524: stackw = sw - md; arg@507: stackh = sh - bh; arg@507: } arg@507: arg@511: tw = stackw; arg@511: if(n > 1) arg@511: th = stackh / (n - 1); arg@511: else arg@507: th = stackh; arg@327: arg@327: for(i = 0, c = clients; c; c = c->next) { arg@327: if(isvisible(c)) { arg@327: if(c->isfloat) { arg@327: resize(c, True, TopLeft); arg@327: continue; arg@327: } arg@488: c->ismax = False; arg@523: c->x = sx; arg@523: c->y = sy + bh; arg@507: if(n == 1) { /* only 1 window */ arg@502: c->w = sw - 2 * BORDERPX; arg@502: c->h = sh - 2 * BORDERPX - bh; arg@327: } arg@507: else if(i == 0) { /* master window */ arg@522: if(stackpos == StackLeft) arg@522: c->x += stackw; arg@508: switch(stackpos) { arg@508: case StackLeft: arg@522: case StackRight: arg@524: c->w = md - 2 * BORDERPX; arg@508: c->h = sh - bh - 2 * BORDERPX; arg@508: break; arg@508: case StackBottom: arg@508: c->w = sw - 2 * BORDERPX; arg@524: c->h = md - 2 * BORDERPX; arg@508: break; arg@507: } arg@507: } arg@523: else { /* tile window */ arg@522: if(stackpos == StackRight) arg@524: c->x += md; arg@523: if(th > bh) { arg@523: switch(stackpos) { arg@523: case StackLeft: arg@523: case StackRight: arg@523: c->y = sy + (i - 1) * th + bh; arg@523: if(i + 1 == n) arg@523: c->h = sh - c->y - 2 * BORDERPX; arg@523: break; arg@523: case StackBottom: arg@524: c->y = sy + md + (i - 1) * th + bh; arg@523: if(i + 1 == n) arg@523: c->h = sh - c->y - 2 * BORDERPX; arg@523: break; arg@523: } arg@523: c->w = tw - 2 * BORDERPX; arg@523: c->h = th - 2 * BORDERPX; arg@507: } arg@523: else { /* fallback if th < bh */ arg@523: if(stackpos == StackBottom) arg@524: c->y += md; arg@523: c->w = stackw - 2 * BORDERPX; arg@523: c->h = stackh - 2 * BORDERPX; arg@523: } arg@327: } arg@327: resize(c, False, TopLeft); arg@327: i++; arg@327: } arg@327: else arg@327: ban(c); arg@327: } arg@446: if(!sel || !isvisible(sel)) { arg@450: for(c = stack; c && !isvisible(c); c = c->snext); arg@450: focus(c); arg@446: } arg@327: restack(); arg@327: } arg@327: arg@327: void arg@461: focusnext(Arg *arg) { arg@327: Client *c; arg@327: arg@327: if(!sel) arg@327: return; arg@327: arg@327: if(!(c = getnext(sel->next))) arg@327: c = getnext(clients); arg@327: if(c) { arg@327: focus(c); arg@327: restack(); arg@327: } arg@327: } arg@327: arg@327: void arg@461: focusprev(Arg *arg) { arg@327: Client *c; arg@327: arg@327: if(!sel) arg@327: return; arg@327: arg@327: if(!(c = getprev(sel->prev))) { arg@327: for(c = clients; c && c->next; c = c->next); arg@327: c = getprev(c); arg@327: } arg@327: if(c) { arg@327: focus(c); arg@327: restack(); arg@327: } arg@327: } arg@327: arg@420: Bool arg@461: isvisible(Client *c) { arg@420: unsigned int i; arg@420: arg@420: for(i = 0; i < ntags; i++) arg@420: if(c->tags[i] && seltag[i]) arg@420: return True; arg@420: return False; arg@420: } arg@420: arg@415: void arg@461: resizecol(Arg *arg) { arg@423: unsigned int n; arg@423: Client *c; arg@418: arg@430: for(n = 0, c = clients; c; c = c->next) arg@430: if(isvisible(c) && !c->isfloat) arg@423: n++; arg@486: if(!sel || sel->isfloat || n < 2 || (arrange == dofloat)) arg@415: return; arg@423: arg@415: if(sel == getnext(clients)) { arg@529: if(master + arg->i > 950 || master + arg->i < 50) arg@415: return; arg@505: master += arg->i; arg@415: } arg@415: else { arg@529: if(master - arg->i > 950 || master - arg->i < 50) arg@415: return; arg@505: master -= arg->i; arg@415: } arg@415: arrange(NULL); arg@415: } arg@415: arg@327: void arg@487: restack(void) { arg@327: Client *c; arg@327: XEvent ev; arg@481: arg@437: if(!sel) { arg@437: drawstatus(); arg@436: return; arg@437: } arg@436: if(sel->isfloat || arrange == dofloat) { arg@436: XRaiseWindow(dpy, sel->win); arg@436: XRaiseWindow(dpy, sel->twin); arg@436: } arg@512: if(arrange != dofloat) { arg@512: if(!sel->isfloat) { arg@512: XLowerWindow(dpy, sel->twin); arg@512: XLowerWindow(dpy, sel->win); arg@512: } arg@436: for(c = nexttiled(clients); c; c = nexttiled(c->next)) { arg@512: if(c == sel) arg@512: continue; arg@436: XLowerWindow(dpy, c->twin); arg@436: XLowerWindow(dpy, c->win); arg@327: } arg@512: } arg@327: drawall(); arg@327: XSync(dpy, False); arg@327: while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); arg@327: } arg@327: arg@327: void arg@461: togglemode(Arg *arg) { arg@333: arrange = (arrange == dofloat) ? dotile : dofloat; arg@327: if(sel) arg@327: arrange(NULL); arg@327: else arg@327: drawstatus(); arg@327: } arg@327: arg@327: void arg@461: toggleview(Arg *arg) { arg@327: unsigned int i; arg@327: arg@327: seltag[arg->i] = !seltag[arg->i]; arg@327: for(i = 0; i < ntags && !seltag[i]; i++); arg@327: if(i == ntags) arg@327: seltag[arg->i] = True; /* cannot toggle last view */ arg@381: reorder(); arg@327: arrange(NULL); arg@327: } arg@327: arg@327: void arg@508: togglestackpos(Arg *arg) { arg@508: if(arrange == dofloat) arg@508: return; arg@508: if(stackpos == StackBottom) arg@508: stackpos = STACKPOS; arg@508: else arg@508: stackpos = StackBottom; arg@508: arrange(NULL); arg@508: } arg@508: arg@508: void arg@461: view(Arg *arg) { arg@327: unsigned int i; arg@327: arg@327: for(i = 0; i < ntags; i++) arg@327: seltag[i] = False; arg@327: seltag[arg->i] = True; arg@381: reorder(); arg@327: arrange(NULL); arg@327: } arg@327: arg@327: void arg@461: viewall(Arg *arg) { arg@395: unsigned int i; arg@395: arg@395: for(i = 0; i < ntags; i++) arg@395: seltag[i] = True; arg@397: reorder(); arg@395: arrange(NULL); arg@395: } arg@395: arg@508: arg@508: arg@395: void arg@461: zoom(Arg *arg) { arg@423: unsigned int n; arg@423: Client *c; arg@473: arg@473: if(!sel) arg@473: return; arg@473: arg@473: if(sel->isfloat || (arrange == dofloat)) { arg@480: togglemax(sel); arg@473: return; arg@473: } arg@327: arg@430: for(n = 0, c = clients; c; c = c->next) arg@430: if(isvisible(c) && !c->isfloat) arg@423: n++; arg@486: if(n < 2 || (arrange == dofloat)) arg@327: return; arg@327: arg@430: if((c = sel) == nexttiled(clients)) arg@433: if(!(c = nexttiled(c->next))) arg@429: return; arg@443: detach(c); arg@443: if(clients) arg@443: clients->prev = c; arg@443: c->next = clients; arg@443: clients = c; arg@378: focus(c); arg@327: arrange(NULL); arg@327: }