diff --new-file -u dwm-1.0/config.default.h dwm-1.0.modified/config.default.h --- dwm-1.0/config.default.h 2006-08-24 09:28:56.000000000 +0100 +++ dwm-1.0.modified/config.default.h 2006-08-24 14:57:13.000000000 +0100 @@ -45,6 +45,13 @@ { MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \ { MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \ { MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ + { MODKEY, XK_n, adjustnumbercols, { .i=1 } }, \ + { MODKEY|ShiftMask, XK_n, adjustnumbercols, { .i=-1 } }, \ + { MODKEY, XK_b, adjustcoltypes, { .i=1 } }, \ + { MODKEY|ShiftMask, XK_b, adjustcoltypes, { .i=-1 } }, \ + { MODKEY, XK_s, sortallbytitle, { 0 } }, \ + { MODKEY, XK_p, , { 0 } }, \ + { MODKEY|ShiftMask, XK_p, , { 0 } }, \ }; /* Query class:instance:title for regex matching info with following command: diff --new-file -u dwm-1.0/config.h dwm-1.0.modified/config.h --- dwm-1.0/config.h 2006-08-24 15:17:59.000000000 +0100 +++ dwm-1.0.modified/config.h 2006-08-24 15:19:40.000000000 +0100 @@ -45,6 +45,13 @@ { MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \ { MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \ { MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ + { MODKEY, XK_n, adjustnumbercols, { .i=1 } }, \ + { MODKEY|ShiftMask, XK_n, adjustnumbercols, { .i=-1 } }, \ + { MODKEY, XK_b, adjustcoltypes, { .i=1 } }, \ + { MODKEY|ShiftMask, XK_b, adjustcoltypes, { .i=-1 } }, \ + { MODKEY, XK_s, sortallbytitle, { 0 } }, \ + { MODKEY, XK_p, setwithnexttag, { 0 } }, \ + { MODKEY|ShiftMask, XK_p, zapcurrenttag, { 0 } }, \ }; /* Query class:instance:title for regex matching info with following command: diff --new-file -u dwm-1.0/dwm.h dwm-1.0.modified/dwm.h --- dwm-1.0/dwm.h 2006-08-24 09:28:56.000000000 +0100 +++ dwm-1.0.modified/dwm.h 2006-08-24 15:20:02.000000000 +0100 @@ -134,3 +134,8 @@ extern void toggleview(Arg *arg); extern void view(Arg *arg); extern void zoom(Arg *arg); +extern void adjustnumbercols(Arg *arg); +extern void adjustcoltypes(Arg *arg); +extern void sortallbytitle(Arg *arg); +extern void setwithnexttag(Arg *arg); +extern void zapcurrenttag(Arg *arg); diff --new-file -u dwm-1.0/patchDoc.txt dwm-1.0.modified/patchDoc.txt --- dwm-1.0/patchDoc.txt 1970-01-01 01:00:00.000000000 +0100 +++ dwm-1.0.modified/patchDoc.txt 2006-08-24 15:16:18.000000000 +0100 @@ -0,0 +1,49 @@ +This patch includes some functions I find useful for working with +large setups, particularly xinerama. + +Firstly, the number of +columns on the screen is totally dynamic and can be increased +(with ModKey-n) or decreased (with ModKey-Shift-n). Also, the +number of `full columns' versus `stack columns' can be +increased (with ModKey-b) or decreased (with ModKey-Shift-b). +Other than changing the total number and types of columns, the +actual tiling algorithm is functionally equivalent to the one in +mainstream dwm, with one final exception: when working in +xinerama one would like to have the full-screen columns +(which is what the user is presumably concentrating on) +towards the middle of the arrangement rather than off on +the left (causing the neck to need to be turned). Consequently, +the whole display is `wrapped around' by noCols/4. This means +that, for example, if you have two full and two stack columns +for a total of 4 columns, you'll get the arrangement + +stack full full stack +col 2 col 1 col 2 col 1 + +If you dislike this aspect you can change the + +horizSlide=noCols/4; + +in dotile() in view.c to + +horizSlide=0; + +Secondly, ModKey-s sorts all the clients by title name. + +For the final commands, it will be less confusing if we +define the HI_TAG as the highest tag being currently +viewed. (If only one tag is being viewed, it is the current +tag.) ModKey-p sets HI_TAG+1 on the current client (keeping +any existing tags). This is so that multiple ModKey-p's +pushes the SAME tag onto all the clients. ModKey-Shift-p +removes HI_TAG from all clients UNLESS that is their last tag, +for which clients it does nothing. If it managed to +remove HI_TAG from all clients which have it, it sets +the HI_TAG-1 in the selected views and rearranges. + +This is all rather abstract: the workflow I use it for is +to `push' a subset of the current clients onto a new, +scratch view (eg, to concentrate on something), +work with them for a while, then zap the temporary +view and fall back to the original. + diff --new-file -u dwm-1.0/view.c dwm-1.0.modified/view.c --- dwm-1.0/view.c 2006-08-24 09:28:56.000000000 +0100 +++ dwm-1.0.modified/view.c 2006-08-24 15:28:09.000000000 +0100 @@ -30,22 +30,77 @@ restack(); } +/* begin changes and additions */ +static const int MAX_COLS=8; +static int noCols=2; +static int noFullCols=1; +static int noStackCols=1; + +inline +int +min(int x,int y) +{ + return xi==1 && noCols==MAX_COLS) + || (arg->i==-1 && noCols==1)){ + return; + } + noCols+=arg->i; + noFullCols=1; + noStackCols=noCols-noFullCols; + arrange(NULL); +} + +/* change the balance between number of full and stacked columns */ +void +adjustcoltypes(Arg *arg) +{ + if(!arg || (arg->i==1 && noFullCols==noCols) + || (arg->i==-1 && noFullCols==0)){ + return; + } + noFullCols+=arg->i; + noStackCols-=arg->i; + arrange(NULL); +} + void dotile(Arg *arg) { - int h, i, n, w; + int n, i, horizSlide=noCols/4; Client *c; - - w = sw - mw; + int noPerCol[MAX_COLS],heights[MAX_COLS]; + Bool useTrivialCols=True; + for(n = 0, c = clients; c; c = c->next) if(isvisible(c) && !c->isfloat) n++; - - if(n > 1) - h = (sh - bh) / (n - 1); - else - h = sh - bh; - + for(i = 0; i < noCols; ++i){ /* default to every column full height */ + noPerCol[i] = i; + heights[i] = sh-bh; + } + if(noStackCols>0 && n >= noCols + && (n-noFullCols)*bh <= (sh-bh)*noStackCols){ + /* need to set up non-trivial slave columns */ + int noLongCols = (n-noFullCols)%noStackCols; + int noInShortCol = (n-noFullCols)/noStackCols; + for(i = noFullCols; i < noCols; ++i){ + int no = noInShortCol + (i>=noCols-noLongCols?1:0); + heights[i] = (sh - bh) / no; + /* convert into cumulative total of when new column begins */ + noPerCol[i] = no + (i==0 ? -1 : noPerCol[i - 1]); + } + useTrivialCols = False; + } + mw = sw / noCols; + int colNo = 0; + int cumHgt = sy + bh; for(i = 0, c = clients; c; c = c->next) { c->ismax = False; if(isvisible(c)) { @@ -53,32 +108,26 @@ resize(c, True, TopLeft); continue; } - if(n == 1) { - c->x = sx; + /* fewer clients than total columns OR slave cols are too full */ + if(useTrivialCols) { + int nP = min(n,noCols); + int iP = (min(i,noCols-1)+horizSlide)%nP; + c->x = sx + (iP*sw) / nP; c->y = sy + bh; - c->w = sw - 2; + c->w = sw / nP - 2; c->h = sh - 2 - bh; } - else if(i == 0) { - c->x = sx; - c->y = sy + bh; + else{ /* standard table driven approach to layout */ + c->x = sx + ((colNo+horizSlide)%noCols)*mw; + c->y = cumHgt; c->w = mw - 2; - c->h = sh - 2 - bh; - } - else if(h > bh) { - c->x = sx + mw; - c->y = sy + (i - 1) * h + bh; - c->w = w - 2; - if(i + 1 == n) - c->h = sh - c->y - 2; - else - c->h = h - 2; - } - else { /* fallback if h < bh */ - c->x = sx + mw; - c->y = sy + bh; - c->w = w - 2; - c->h = sh - 2 - bh; + c->h = heights[colNo] - 2; + cumHgt += heights[colNo]; + if(i == noPerCol[colNo]){ /* next client starts a new column */ + c->h = sh - 2 - c->y; + ++colNo; + cumHgt = sy + bh; + } } resize(c, False, TopLeft); i++; @@ -95,6 +144,93 @@ restack(); } +/* sort all the clients (whether displayed or not) by title */ +void +sortallbytitle(Arg *arg) +{ + Client *fst,*snd,*t; + if(!clients || !(clients->next)){ + return; + } + Client fakeRoot; + int len, cnt; + fakeRoot.next=clients; + clients->prev=&fakeRoot; + /* figure how many elements in list */ + t=clients; + for(len=0, t=clients; t ;t=t->next){ + ++len; + } + /* use simple bubble sort as it's easier to figure the pointers*/ + while(--len>0){ + fst=fakeRoot.next; + int cnt=len; + while(--cnt>0){ + snd=fst->next; + if(strncasecmp(fst->name,snd->name,sizeof(fst->name))>0){ + /* set-up external pointers */ + fst->prev->next=snd; + if(snd->next){ + snd->next->prev=fst; + } + /* set-up internal pointers */ + fst->next=snd->next; + snd->prev=fst->prev; + snd->next=fst; + fst->prev=snd; + }else{ + fst=snd; + } + } + } + clients=fakeRoot.next; + arrange(NULL); +} + + +/* find the highest currently viewed tag */ +int +highestTagUsed() +{ + int highestTag=0,i; + for(i=0;itags[min(highestTagUsed()+1,ntags-1)]=True; +} + +void +zapcurrenttag(Arg *arg) +{ + Client *c; + int toZap=highestTagUsed(),i; + Bool ok=True; + for(c = clients; c; c = c->next) { + if(c->tags[toZap]){/* prevent potentially much pointless work */ + c->tags[toZap]=False; + for(i = 0; i < ntags && !c->tags[i]; i++) /*do nothing*/; + if(i == ntags){ /* oops: wiped out last tag */ + c->tags[toZap] = True; + ok=False; + } + } + } + if(ok && toZap>0){ + seltag[toZap]=False; + seltag[toZap-1]=True; + } + arrange(NULL); +} +/* end changes and additions */ + void focusnext(Arg *arg) {