diff -u dwm-2.2/client.c dwm-2.2.modified/client.c --- dwm-2.2/client.c 2006-11-21 08:41:15.000000000 +0000 +++ dwm-2.2.modified/client.c 2006-11-21 11:36:01.000000000 +0000 @@ -193,6 +193,30 @@ XKillClient(dpy, sel->win); } +#include +#include +void +determineIfAspectRatioClient(Client *c) +{ + c->aspectRatio=-1; + XClassHint ch; + if(XGetClassHint(dpy, c->win, &ch) && ch.res_class){ + int i; + for(i=0;iaspectRatio=(double)c->h/(double)c->w; + break; + } + } + if(ch.res_class){ + XFree(ch.res_class); + } + if(ch.res_name){ + XFree(ch.res_name); + } + } +} + void manage(Window w, XWindowAttributes *wa) { Client *c; @@ -208,6 +232,7 @@ c->w = c->tw = wa->width; c->h = wa->height; c->th = bh; + determineIfAspectRatioClient(c);/*modification*/ updatesize(c); if(c->x + c->w + 2 * BORDERPX > sw) c->x = sw - c->w - 2 * BORDERPX; diff -u dwm-2.2/config.default.h dwm-2.2.modified/config.default.h --- dwm-2.2/config.default.h 2006-11-21 08:41:15.000000000 +0000 +++ dwm-2.2.modified/config.default.h 2006-11-21 11:43:20.000000000 +0000 @@ -21,6 +21,8 @@ #define MODKEY Mod1Mask #define SNAP 20 /* pixel */ +#define NO_MONITORS 2 + #define KEYS \ static Key key[] = { \ /* modifier key function arguments */ \ @@ -53,9 +55,15 @@ { MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \ { MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \ { MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \ - { MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ + { MODKEY|ShiftMask, XK_q, quit, { 0 } },\ + { MODKEY|ControlMask, XK_n, adjustnumbercols, { .i=1 } }, \ + { MODKEY|ControlMask|ShiftMask, XK_n, adjustnumbercols, { .i=-1 } }, \ + { MODKEY, XK_n, adjustcoltypes, { .i=1 } }, \ + { MODKEY|ShiftMask, XK_n, adjustcoltypes, { .i=-1 } }, \ }; +static const char* const respectAspectRatio[]={"xine","XVroot","Kview"/*,"XDvi","EVince"*/}; + /* Query class:instance:title for regex matching info with following command: * xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */ #define RULES \ diff -u dwm-2.2/dwm.h dwm-2.2.modified/dwm.h --- dwm-2.2/dwm.h 2006-11-21 08:41:15.000000000 +0000 +++ dwm-2.2.modified/dwm.h 2006-11-21 11:42:11.000000000 +0000 @@ -80,6 +80,7 @@ int rx, ry, rw, rh; /* revert geometry */ int tx, ty, tw, th; /* title window geometry */ int basew, baseh, incw, inch, maxw, maxh, minw, minh; + float aspectRatio; int grav; long flags; unsigned int border, weight; @@ -92,6 +93,19 @@ Window twin; }; +static +inline +int +clamp(int x,int lo,int hi) +{ + if(xhi){ + return hi; + } + return x; +} + extern const char *tags[]; /* all tags */ extern char stext[1024]; /* status text */ extern int bx, by, bw, bh, bmw; /* bar geometry, bar mode label width */ @@ -148,6 +162,7 @@ extern void settags(Client *c, Client *trans); /* sets tags of c */ extern void tag(Arg *arg); /* tags c with arg's index */ extern void toggletag(Arg *arg); /* toggles c tags with arg's index */ +extern int highestTagUsed(); /* util.c */ extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */ @@ -169,3 +184,5 @@ extern void view(Arg *arg); /* views the tag with arg's index */ extern void viewall(Arg *arg); /* views all tags, arg is ignored */ extern void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */ +extern void adjustnumbercols(Arg *arg); /* change number of columns */ +extern void adjustcoltypes(Arg *arg); /* increment/decrement number of full columns */ diff -u dwm-2.2/event.c dwm-2.2.modified/event.c --- dwm-2.2/event.c 2006-11-21 08:41:15.000000000 +0000 +++ dwm-2.2.modified/event.c 2006-11-21 11:33:41.000000000 +0000 @@ -173,7 +173,11 @@ if(ev->value_mask & CWBorderWidth) c->border = ev->border_width; gravitate(c, False); - wc.x = c->x; + /*subtle: no aspect ratio change can set aspectRatio<=0 (yes?)*/ + if(c->aspectRatio>0 && (ev->value_mask & CWWidth) && (ev->value_mask & CWHeight)){ + c->aspectRatio=(double)ev->height/(double)ev->width; + } + wc.x = c->x; wc.y = c->y; wc.width = c->w; wc.height = c->h; diff -u dwm-2.2/tag.c dwm-2.2.modified/tag.c --- dwm-2.2/tag.c 2006-11-21 08:41:15.000000000 +0000 +++ dwm-2.2.modified/tag.c 2006-11-21 11:28:27.000000000 +0000 @@ -133,3 +133,16 @@ sel->weight = (i == ntags) ? arg->i : i; arrange(); } + +/* find the highest currently viewed tag */ +int +highestTagUsed() +{ + int i; + for(i=ntags-1;i>=0;--i){ + if(seltag[i]){ + return i; + } + } + return 0; /*should never happen*/ +} diff -u dwm-2.2/view.c dwm-2.2.modified/view.c --- dwm-2.2/view.c 2006-11-21 08:41:15.000000000 +0000 +++ dwm-2.2.modified/view.c 2006-11-21 11:27:00.000000000 +0000 @@ -97,57 +97,171 @@ restack(); } -void -dotile(void) { - unsigned int i, n, mpx, stackw, th; - Client *c; +/* begin changes and additions */ +#define MAX_TAGS 28 +static const int MAX_COLS=8; +static int noColsArr[MAX_TAGS]={2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; +static int noStackColsArr[MAX_TAGS]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; - for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) - n++; - mpx = (waw * master) / 1000; - stackw = waw - mpx; - - for(i = 0, c = clients; c; c = c->next) - if(isvisible(c)) { - if(c->isfloat) { - resize(c, True, TopLeft); - continue; - } - c->ismax = False; - c->x = wax; - c->y = way; - if(n == 1) { /* only 1 window */ - c->w = waw - 2 * BORDERPX; - c->h = wah - 2 * BORDERPX; - } - else if(i == 0) { /* master window */ - c->w = waw - stackw - 2 * BORDERPX; - c->h = wah - 2 * BORDERPX; - th = wah / (n - 1); - } - else { /* tile window */ - c->x += mpx; - c->w = stackw - 2 * BORDERPX; - if(th > bh) { - c->y = way + (i - 1) * th; - c->h = th - 2 * BORDERPX; - } - else /* fallback if th < bh */ - c->h = wah - 2 * BORDERPX; - } - resize(c, False, TopLeft); - i++; - } - else - ban(c); +/* change the total number of columns */ +void +adjustnumbercols(Arg *arg) +{ + if(arg){ + int tg=highestTagUsed(); + noColsArr[tg]=clamp(noColsArr[tg]+arg->i,1,MAX_COLS); + noStackColsArr[tg]=noColsArr[tg]-1; + arrange(); + } +} - if(!sel || !isvisible(sel)) { - for(c = stack; c && !isvisible(c); c = c->snext); - focus(c); - } - restack(); +/* change the balance between number of full and stacked columns */ +void +adjustcoltypes(Arg *arg) +{ + if(arg){ + int tg=highestTagUsed(); + noStackColsArr[tg]=clamp(noStackColsArr[tg]-arg->i,0,noColsArr[tg]); + arrange(); + } +} + +typedef struct ARCrec { + int idx;/*order position in _visible_ clients*/ + int height; + Client *c; +} ARCrec; + +/***************************************************************************** + * formulae should now be correct for arbitrary NO_MONITORS + * first build width/height tables, then fill them rather than merge two + * into combined code to ease future experiments + * + * all per-column arrays are now indexed from 1 up (rather than 0) + * + * abbreviation ARC: Aspect Ratio Constrained + * + *subtle: we add `roundPixInCol' to the every non-arc client in the + *column, but zero it after the first use so in effect we only use it once + * + ****************************************************************************/ +void +dotile(void) +{ + int n,i,tg=highestTagUsed(); + Client *c; + /*-------------- count visible clients & note aspect ratio ones ---------*/ + + ARCrec arcs[16]; + int arcTop=0; + for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)){ + if(c->aspectRatio>0.05 && arcTop<15){/*drop if too many*/ + arcs[arcTop].idx=n; + arcs[arcTop].c=c; + ++arcTop; + } + n++; + } + arcs[arcTop].idx=65535;/*sentinel larger than possible no of clients*/ + + /*----------- figure how many stack columns we'll need ---------------*/ + + int noCols=noColsArr[tg]; + int stackColsUsed=noStackColsArr[tg]; /* no stacks actually needed this time */ + int noInSCols=n-(noCols-stackColsUsed); /* no clients in stack cols */ + int colsUsed = clamp(n,1,noCols); /* no cols actually used on this view */ + while(!(noInSCols*bh <= wah*stackColsUsed) && noInSCols>0){ /* inc # stack cols until fits */ + ++stackColsUsed; + noInSCols=n-(noCols-stackColsUsed); + } + Bool useNonTrivialCols=stackColsUsed>0 && n >= noCols + && noInSCols*bh <= (wah-2*bh)*stackColsUsed; /* got enough height for at least titles? */ + int noFullCols=noCols-stackColsUsed; + int noOfShortCols = noCols - noInSCols%stackColsUsed; /* x%0==0 as desired */ + int crossCol=colsUsed-(colsUsed%NO_MONITORS)*((colsUsed/NO_MONITORS)+1); + + /*------------- build tables of essential layout parameters ---------------*/ + + int colEndOn[MAX_COLS+1],heights[MAX_COLS+1],widths[MAX_COLS+1],roundPixInCol[MAX_COLS+1]; + Bool arOkInCol[MAX_COLS+1]; /*aspect ratios clients "fit" in col*/ + colEndOn[0]=-1; + int j=0; /* maintain as first "currently unprocessed" aspect ratio client */ + for(i = 1; i <= colsUsed; ++i){ + int div=colsUsed; + if(NO_MONITORS>1 && colsUsed%NO_MONITORS!=0 && colsUsed>1){ + div+=(i>crossCol?NO_MONITORS:0)-1; + } + widths[i]=waw/div;/*set width BEFORE possible aspect ratio clients*/ + int origNo = 1; /* no clients in this col */ + if(useNonTrivialCols && i>noFullCols){/*stack column*/ + origNo=noInSCols/stackColsUsed + (i>noOfShortCols?1:0); + } + int no=origNo; /* becomes no "normal" clients in this col */ + int normClientHgt=wah;/*height left for normal clients*/ + colEndOn[i] = no + colEndOn[i-1];/* col i finishes on this client */ + /* set heights for aspect ratio constrained clients in this column*/ + for(;arcs[j].idx<=colEndOn[i];++j){ + arcs[j].height=(int)((widths[i]-2*BORDERPX)*arcs[j].c->aspectRatio) + +1+2*BORDERPX;/*1 to ensure overestimate*/ + normClientHgt-=arcs[j].height; + --no; + } + arOkInCol[i]=(normClientHgt>=no*bh);/*not too much arc height for col?*/ + if(!arOkInCol[i]){ /*reset so all clients get same height */ + normClientHgt=wah; + no=origNo; + } + heights[i]=normClientHgt/(no>0?no:1); + roundPixInCol[i]=normClientHgt-heights[i]*no; + } + colEndOn[colsUsed]=n-1; /* ensure final column ends with last client*/ + + /*-------- use tables to assign actual client positions in layout ---------*/ + + int colNo = 1, cumHgt = bh, cumWid=0, arcIdx=0; + for(i = 0, c = clients; c; c = c->next) { + if(isvisible(c)) { + if(c->isfloat) { + resize(c, True, TopLeft); + continue; + } + c->ismax = False; + c->x = cumWid; + c->y = cumHgt; + c->w = widths[colNo]-2*BORDERPX; + if(c==arcs[arcIdx].c){ + ++arcIdx; + if(arOkInCol[colNo]){ + c->h = arcs[arcIdx-1].height; + goto HEIGHT_BEEN_SET; + } + } + /*for various possible reasons, client gets normal height*/ + c->h = heights[colNo]+roundPixInCol[colNo]; + roundPixInCol[colNo]=0;/*can only use roundPixInCol once*/ + HEIGHT_BEEN_SET: + if(i == colEndOn[colNo]){ /* next client starts a new column */ + cumWid+=widths[colNo++]; + cumHgt = bh; + }else if(useNonTrivialCols){ + cumHgt += c->h; + } + c->h -= 2*BORDERPX; + resize(c, False, TopLeft); + i++; + } + else + ban(c); + } + if(!sel || !isvisible(sel)) { + for(c = stack; c && !isvisible(c); c = c->snext); + focus(c); + } + restack(); } +/* end changes and additions */ + void focusnext(Arg *arg) { Client *c;