sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-6.0-pertag-tab.diff (23754B)


      1 diff -u dwm-6.0-orig/config.def.h dwm-6.0-pertag-tab/config.def.h
      2 --- dwm-6.0-orig/config.def.h	2011-12-19 16:02:46.000000000 +0100
      3 +++ dwm-6.0-pertag-tab/config.def.h	2013-06-23 00:06:48.000000000 +0200
      4 @@ -12,6 +12,9 @@
      5  static const unsigned int snap      = 32;       /* snap pixel */
      6  static const Bool showbar           = True;     /* False means no bar */
      7  static const Bool topbar            = True;     /* False means bottom bar */
      8 +static const Bool showtab           = True;     /* False means no tab bar */
      9 +static const Bool toptab            = False;    /* False means bottom tab bar */
     10 +
     11  
     12  /* tagging */
     13  static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
     14 @@ -25,7 +28,7 @@
     15  /* layout(s) */
     16  static const float mfact      = 0.55; /* factor of master area size [0.05..0.95] */
     17  static const int nmaster      = 1;    /* number of clients in master area */
     18 -static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
     19 +static const Bool resizehints = False; /* True means respect size hints in tiled resizals */
     20  
     21  static const Layout layouts[] = {
     22  	/* symbol     arrange function */
     23 @@ -54,6 +57,7 @@
     24  	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
     25  	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
     26  	{ MODKEY,                       XK_b,      togglebar,      {0} },
     27 +	{ MODKEY,                       XK_w,      toggletab,      {0} },
     28  	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
     29  	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
     30  	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
     31 @@ -101,5 +105,6 @@
     32  	{ ClkTagBar,            0,              Button3,        toggleview,     {0} },
     33  	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
     34  	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
     35 +	{ ClkTabBar,            0,              Button1,        focuswin,       {0} },
     36  };
     37  
     38 diff -u dwm-6.0-orig/dwm.1 dwm-6.0-pertag-tab/dwm.1
     39 --- dwm-6.0-orig/dwm.1	2011-12-19 16:02:46.000000000 +0100
     40 +++ dwm-6.0-pertag-tab/dwm.1	2013-06-23 00:21:16.000000000 +0200
     41 @@ -19,14 +19,16 @@
     42  Windows are grouped by tags. Each window can be tagged with one or multiple
     43  tags. Selecting certain tags displays all windows with these tags.
     44  .P
     45 -Each screen contains a small status bar which displays all available tags, the
     46 -layout, the title of the focused window, and the text read from the root window
     47 -name property, if the screen is focused. A floating window is indicated with an
     48 -empty square and a maximised floating window is indicated with a filled square
     49 -before the windows title.  The selected tags are indicated with a different
     50 -color. The tags of the focused window are indicated with a filled square in the
     51 -top left corner.  The tags which are applied to one or more windows are
     52 -indicated with an empty square in the top left corner.
     53 +Each screen contains two bars. A small status bar displays all available tags,
     54 +the layout, the title of the focused window, and the text read from the root
     55 +window name property, if the screen is focused. A small tab bar lists the
     56 +windows in the current view and allows navigation from window to window,
     57 +especially in the monocle mode. A floating window is indicated with an empty
     58 +square and a maximised floating window is indicated with a filled square before
     59 +the windows title.  The selected tags are indicated with a different color. The
     60 +tags of the focused window are indicated with a filled square in the top left
     61 +corner.  The tags which are applied to one or more windows are indicated with an
     62 +empty square in the top left corner.
     63  .P
     64  dwm draws a small border around windows to indicate the focus state.
     65  .SH OPTIONS
     66 @@ -43,7 +45,8 @@
     67  .TP
     68  .B Button1
     69  click on a tag label to display all windows with that tag, click on the layout
     70 -label toggles between tiled and floating layout.
     71 +label toggles between tiled and floating layout, click on a window name in the
     72 +tab bar brings focus to that window.
     73  .TP
     74  .B Button3
     75  click on a tag label adds/removes all windows with that tag to/from the view.
     76 @@ -104,6 +107,9 @@
     77  .B Mod1\-h
     78  Decrease master area size.
     79  .TP
     80 +.B Mod1\-w
     81 +Toggle the tab bar.
     82 +.TP
     83  .B Mod1\-Return
     84  Zooms/cycles focused window to/from master area (tiled layouts only).
     85  .TP
     86 diff -u dwm-6.0-orig/dwm.c dwm-6.0-pertag-tab/dwm.c
     87 --- dwm-6.0-orig/dwm.c	2011-12-19 16:02:46.000000000 +0100
     88 +++ dwm-6.0-pertag-tab/dwm.c	2013-06-23 16:57:10.000000000 +0200
     89 @@ -62,7 +62,7 @@
     90         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
     91         NetWMWindowTypeDialog, NetLast };     /* EWMH atoms */
     92  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
     93 -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
     94 +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
     95         ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
     96  
     97  typedef union {
     98 @@ -102,6 +102,7 @@
     99  	unsigned long norm[ColLast];
    100  	unsigned long sel[ColLast];
    101  	Drawable drawable;
    102 +	Drawable tabdrawable;
    103  	GC gc;
    104  	struct {
    105  		int ascent;
    106 @@ -124,25 +125,36 @@
    107  	void (*arrange)(Monitor *);
    108  } Layout;
    109  
    110 +typedef struct Pertag Pertag;
    111 +
    112 +#define MAXTABS 50
    113 +
    114  struct Monitor {
    115  	char ltsymbol[16];
    116  	float mfact;
    117  	int nmaster;
    118  	int num;
    119  	int by;               /* bar geometry */
    120 +	int ty;               /* tab bar geometry */
    121  	int mx, my, mw, mh;   /* screen size */
    122  	int wx, wy, ww, wh;   /* window area  */
    123  	unsigned int seltags;
    124  	unsigned int sellt;
    125  	unsigned int tagset[2];
    126  	Bool showbar;
    127 +	Bool showtab;
    128  	Bool topbar;
    129 +	Bool toptab;
    130  	Client *clients;
    131  	Client *sel;
    132  	Client *stack;
    133  	Monitor *next;
    134  	Window barwin;
    135 +	Window tabwin;
    136 +	int ntabs;
    137 +        int tab_widths[MAXTABS];
    138  	const Layout *lt[2];
    139 +	Pertag *pertag;
    140  };
    141  
    142  typedef struct {
    143 @@ -178,11 +190,15 @@
    144  static Monitor *dirtomon(int dir);
    145  static void drawbar(Monitor *m);
    146  static void drawbars(void);
    147 +static void drawtab(Monitor *m);
    148 +static void drawtabs(void);
    149  static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
    150 -static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
    151 +static void drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert);
    152 +//static void drawtabtext(const char *text, unsigned long col[ColLast], Bool invert);
    153  static void enternotify(XEvent *e);
    154  static void expose(XEvent *e);
    155  static void focus(Client *c);
    156 +static void focuswin(const Arg* arg);
    157  static void focusin(XEvent *e);
    158  static void focusmon(const Arg *arg);
    159  static void focusstack(const Arg *arg);
    160 @@ -229,6 +245,7 @@
    161  static int textnw(const char *text, unsigned int len);
    162  static void tile(Monitor *);
    163  static void togglebar(const Arg *arg);
    164 +static void toggletab(const Arg *arg);
    165  static void togglefloating(const Arg *arg);
    166  static void toggletag(const Arg *arg);
    167  static void toggleview(const Arg *arg);
    168 @@ -258,6 +275,7 @@
    169  static int screen;
    170  static int sw, sh;           /* X display screen geometry width, height */
    171  static int bh, blw = 0;      /* bar geometry */
    172 +static int th = 0;           /* tab bar geometry */
    173  static int (*xerrorxlib)(Display *, XErrorEvent *);
    174  static unsigned int numlockmask = 0;
    175  static void (*handler[LASTEvent]) (XEvent *) = {
    176 @@ -287,6 +305,16 @@
    177  /* configuration, allows nested code to access above variables */
    178  #include "config.h"
    179  
    180 +struct Pertag {
    181 +	unsigned int curtag, prevtag; /* current and previous tag */
    182 +	int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
    183 +	float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
    184 +	unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
    185 +	const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes  */
    186 +	Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
    187 +	Bool showtabs[LENGTH(tags) + 1]; /* display tab bar for the current tag */
    188 +};
    189 +
    190  /* compile-time check if all tags fit into an unsigned int bit array. */
    191  struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
    192  
    193 @@ -454,14 +482,32 @@
    194  		else
    195  			click = ClkWinTitle;
    196  	}
    197 +	if(ev->window == selmon->tabwin) {
    198 +		i = 0; x = 0;
    199 +		for(c = selmon->clients; c; c = c->next){
    200 +		  if(!ISVISIBLE(c)) continue;
    201 +		  x += selmon->tab_widths[i];
    202 +		  if (ev->x > x)
    203 +		    ++i;
    204 +		  else
    205 +		    break;
    206 +		  if(i >= m->ntabs) break;
    207 +		}
    208 +		if(c) {
    209 +		  click = ClkTabBar;
    210 +		  arg.ui = i;
    211 +		}
    212 +	}
    213  	else if((c = wintoclient(ev->window))) {
    214  		focus(c);
    215  		click = ClkClientWin;
    216  	}
    217  	for(i = 0; i < LENGTH(buttons); i++)
    218  		if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
    219 -		&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
    220 -			buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
    221 +		   && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
    222 +		  buttons[i].func(((click == ClkTagBar || click == ClkTabBar)
    223 +				   && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
    224 +		}
    225  }
    226  
    227  void
    228 @@ -491,6 +537,7 @@
    229  		XFreeFont(dpy, dc.font.xfont);
    230  	XUngrabKey(dpy, AnyKey, AnyModifier, root);
    231  	XFreePixmap(dpy, dc.drawable);
    232 +	XFreePixmap(dpy, dc.tabdrawable);
    233  	XFreeGC(dpy, dc.gc);
    234  	XFreeCursor(dpy, cursor[CurNormal]);
    235  	XFreeCursor(dpy, cursor[CurResize]);
    236 @@ -513,6 +560,8 @@
    237  	}
    238  	XUnmapWindow(dpy, mon->barwin);
    239  	XDestroyWindow(dpy, mon->barwin);
    240 +	XUnmapWindow(dpy, mon->tabwin);
    241 +	XDestroyWindow(dpy, mon->tabwin);
    242  	free(mon);
    243  }
    244  
    245 @@ -581,9 +630,14 @@
    246  			if(dc.drawable != 0)
    247  				XFreePixmap(dpy, dc.drawable);
    248  			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
    249 +			if(dc.tabdrawable != 0)
    250 +				XFreePixmap(dpy, dc.tabdrawable);
    251 +			dc.tabdrawable = XCreatePixmap(dpy, root, sw, th, DefaultDepth(dpy, screen));
    252  			updatebars();
    253 -			for(m = mons; m; m = m->next)
    254 +			for(m = mons; m; m = m->next){
    255  				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
    256 + 				XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
    257 +			}
    258  			focus(NULL);
    259  			arrange(NULL);
    260  		}
    261 @@ -646,6 +700,7 @@
    262  Monitor *
    263  createmon(void) {
    264  	Monitor *m;
    265 +	int i;
    266  
    267  	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
    268  		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
    269 @@ -653,10 +708,34 @@
    270  	m->mfact = mfact;
    271  	m->nmaster = nmaster;
    272  	m->showbar = showbar;
    273 +	m->showtab = showtab;
    274  	m->topbar = topbar;
    275 +	m->toptab = toptab;
    276 +	m->ntabs = 0;
    277  	m->lt[0] = &layouts[0];
    278  	m->lt[1] = &layouts[1 % LENGTH(layouts)];
    279  	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    280 +	if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
    281 +		die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
    282 +	m->pertag->curtag = m->pertag->prevtag = 1;
    283 +	for(i=0; i <= LENGTH(tags); i++) {
    284 +		/* init nmaster */
    285 +		m->pertag->nmasters[i] = m->nmaster;
    286 +
    287 +		/* init mfacts */
    288 +		m->pertag->mfacts[i] = m->mfact;
    289 +
    290 +		/* init layouts */
    291 +		m->pertag->ltidxs[i][0] = m->lt[0];
    292 +		m->pertag->ltidxs[i][1] = m->lt[1];
    293 +		m->pertag->sellts[i] = m->sellt;
    294 +
    295 +		/* init showbar */
    296 +		m->pertag->showbars[i] = m->showbar;
    297 +
    298 +		/* init showtab */
    299 +		m->pertag->showtabs[i] = m->showtab;
    300 +	}
    301  	return m;
    302  }
    303  
    304 @@ -731,13 +810,13 @@
    305  	for(i = 0; i < LENGTH(tags); i++) {
    306  		dc.w = TEXTW(tags[i]);
    307  		col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
    308 -		drawtext(tags[i], col, urg & 1 << i);
    309 +		drawtext(dc.drawable, tags[i], col, urg & 1 << i);
    310  		drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
    311  		           occ & 1 << i, urg & 1 << i, col);
    312  		dc.x += dc.w;
    313  	}
    314  	dc.w = blw = TEXTW(m->ltsymbol);
    315 -	drawtext(m->ltsymbol, dc.norm, False);
    316 +	drawtext(dc.drawable, m->ltsymbol, dc.norm, False);
    317  	dc.x += dc.w;
    318  	x = dc.x;
    319  	if(m == selmon) { /* status is only drawn on selected monitor */
    320 @@ -747,19 +826,20 @@
    321  			dc.x = x;
    322  			dc.w = m->ww - x;
    323  		}
    324 -		drawtext(stext, dc.norm, False);
    325 +		drawtext(dc.drawable, stext, dc.norm, False);
    326  	}
    327  	else
    328  		dc.x = m->ww;
    329  	if((dc.w = dc.x - x) > bh) {
    330  		dc.x = x;
    331  		if(m->sel) {
    332 -			col = m == selmon ? dc.sel : dc.norm;
    333 -			drawtext(m->sel->name, col, False);
    334 +		  //			col = m == selmon ? dc.sel : dc.norm;
    335 +		  //	drawtext(dc.drawable, m->sel->name, col, False);
    336 +		  drawtext(dc.drawable, m->sel->name, dc.norm, False);
    337  			drawsquare(m->sel->isfixed, m->sel->isfloating, False, col);
    338  		}
    339  		else
    340 -			drawtext(NULL, dc.norm, False);
    341 +		  drawtext(dc.drawable, NULL, dc.norm, False);
    342  	}
    343  	XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0);
    344  	XSync(dpy, False);
    345 @@ -774,6 +854,104 @@
    346  }
    347  
    348  void
    349 +drawtabs(void) {
    350 +	Monitor *m;
    351 +
    352 +	for(m = mons; m; m = m->next)
    353 +		drawtab(m);
    354 +}
    355 +
    356 +static int
    357 +cmpint(const void *p1, const void *p2) {
    358 +  /* The actual arguments to this function are "pointers to
    359 +     pointers to char", but strcmp(3) arguments are "pointers
    360 +     to char", hence the following cast plus dereference */
    361 +  return *((int*) p1) > * (int*) p2;
    362 +}
    363 +
    364 +
    365 +void
    366 +drawtab(Monitor *m) {
    367 +	unsigned long *col;
    368 +	Client *c;
    369 +	int i;
    370 +	int itag = -1;
    371 +	char view_info[50];
    372 +	int view_info_w = 0;
    373 +	int sorted_label_widths[MAXTABS];
    374 +	int tot_width;
    375 +	int maxsize = bh;
    376 +	dc.x = 0;
    377 +
    378 +	//view_info: indicate the tag which is displayed in the view
    379 +	for(i = 0; i < LENGTH(tags); ++i){
    380 +	  if((selmon->tagset[selmon->seltags] >> i) & 1) {
    381 +	    if(itag >=0){ //more than one tag selected
    382 +	      itag = -1;
    383 +	      break;
    384 +	    }
    385 +	    itag = i;
    386 +	  }
    387 +	}
    388 +	if(0 <= itag  && itag < LENGTH(tags)){
    389 +	  snprintf(view_info, sizeof view_info, "[%s]", tags[itag]);
    390 +	} else {
    391 +	  strncpy(view_info, "[...]", sizeof view_info);
    392 +	}
    393 +	view_info[sizeof(view_info) - 1 ] = 0;
    394 +	view_info_w = TEXTW(view_info);
    395 +	tot_width = view_info_w;
    396 +
    397 +	/* Calculates number of labels and their width */
    398 +	m->ntabs = 0;
    399 +	for(c = m->clients; c; c = c->next){
    400 +	  if(!ISVISIBLE(c)) continue;
    401 +	  m->tab_widths[m->ntabs] = TEXTW(c->name);
    402 +	  tot_width += m->tab_widths[m->ntabs];
    403 +	  ++m->ntabs;
    404 +	  if(m->ntabs >= MAXTABS) break;
    405 +	}
    406 +
    407 +	if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated
    408 +	  memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
    409 +	  qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
    410 +	  tot_width = view_info_w;
    411 +	  for(i = 0; i < m->ntabs; ++i){
    412 +	    if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
    413 +	      break;
    414 +	    tot_width += sorted_label_widths[i];
    415 +	  }
    416 +	  maxsize = (m->ww - tot_width) / (m->ntabs - i);
    417 +	} else{
    418 +	  maxsize = m->ww;
    419 +	}
    420 +	i = 0;
    421 +	for(c = m->clients; c; c = c->next){
    422 +	  if(!ISVISIBLE(c)) continue;
    423 +	  if(i >= m->ntabs) break;
    424 +	  if(m->tab_widths[i] >  maxsize) m->tab_widths[i] = maxsize;
    425 +	  dc.w = m->tab_widths[i];
    426 +	  col = (c == m->sel)  ? dc.sel : dc.norm;
    427 +	  drawtext(dc.tabdrawable, c->name, col, 0);
    428 +	  dc.x += dc.w;
    429 +	  ++i;
    430 +	}
    431 +
    432 +	/* cleans interspace between window names and current viewed tag label */
    433 +	dc.w = m->ww - view_info_w - dc.x;
    434 +	drawtext(dc.tabdrawable, NULL, dc.norm, 0);
    435 +
    436 +	/* view info */
    437 +	dc.x += dc.w;
    438 +	dc.w = view_info_w;
    439 +	drawtext(dc.tabdrawable, view_info, dc.norm, 0);
    440 +
    441 +	XCopyArea(dpy, dc.tabdrawable, m->tabwin, dc.gc, 0, 0, m->ww, th, 0, 0);
    442 +	XSync(dpy, False);
    443 +}
    444 +
    445 +
    446 +void
    447  drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
    448  	int x;
    449  
    450 @@ -785,13 +963,14 @@
    451  		XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
    452  }
    453  
    454 +
    455  void
    456 -drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
    457 +drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert) {
    458  	char buf[256];
    459  	int i, x, y, h, len, olen;
    460  
    461  	XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
    462 -	XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
    463 +	XFillRectangle(dpy, drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
    464  	if(!text)
    465  		return;
    466  	olen = strlen(text);
    467 @@ -807,11 +986,12 @@
    468  		for(i = len; i && i > len - 3; buf[--i] = '.');
    469  	XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
    470  	if(dc.font.set)
    471 -		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
    472 +		XmbDrawString(dpy, drawable, dc.font.set, dc.gc, x, y, buf, len);
    473  	else
    474 -		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
    475 +		XDrawString(dpy, drawable, dc.gc, x, y, buf, len);
    476  }
    477  
    478 +
    479  void
    480  enternotify(XEvent *e) {
    481  	Client *c;
    482 @@ -836,8 +1016,10 @@
    483  	Monitor *m;
    484  	XExposeEvent *ev = &e->xexpose;
    485  
    486 -	if(ev->count == 0 && (m = wintomon(ev->window)))
    487 +	if(ev->count == 0 && (m = wintomon(ev->window))){
    488  		drawbar(m);
    489 +		drawtab(m);
    490 +	}
    491  }
    492  
    493  void
    494 @@ -862,6 +1044,7 @@
    495  		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
    496  	selmon->sel = c;
    497  	drawbars();
    498 +	drawtabs();
    499  }
    500  
    501  void
    502 @@ -911,6 +1094,19 @@
    503  	}
    504  }
    505  
    506 +void
    507 +focuswin(const Arg* arg){
    508 +  int iwin = arg->i;
    509 +  Client* c = NULL;
    510 +  for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){
    511 +    if(ISVISIBLE(c)) --iwin;
    512 +  };
    513 +  if(c) {
    514 +    focus(c);
    515 +    restack(selmon);
    516 +  }
    517 +}
    518 +
    519  Atom
    520  getatomprop(Client *c, Atom prop) {
    521  	int di;
    522 @@ -1028,7 +1224,7 @@
    523  
    524  void
    525  incnmaster(const Arg *arg) {
    526 -	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
    527 +	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
    528  	arrange(selmon);
    529  }
    530  
    531 @@ -1311,12 +1507,14 @@
    532  		case XA_WM_HINTS:
    533  			updatewmhints(c);
    534  			drawbars();
    535 +			drawtabs();
    536  			break;
    537  		}
    538  		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
    539  			updatetitle(c);
    540  			if(c == c->mon->sel)
    541  				drawbar(c->mon);
    542 +			drawtab(c->mon);
    543  		}
    544  		if(ev->atom == netatom[NetWMWindowType])
    545  			updatewindowtype(c);
    546 @@ -1418,6 +1616,7 @@
    547  	XWindowChanges wc;
    548  
    549  	drawbar(m);
    550 +	drawtab(m);
    551  	if(!m->sel)
    552  		return;
    553  	if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
    554 @@ -1555,10 +1754,13 @@
    555  
    556  void
    557  setlayout(const Arg *arg) {
    558 -	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
    559 -		selmon->sellt ^= 1;
    560 +	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
    561 +		selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
    562 +		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
    563 +	}
    564  	if(arg && arg->v)
    565 -		selmon->lt[selmon->sellt] = (Layout *)arg->v;
    566 +		selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
    567 +	selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
    568  	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
    569  	if(selmon->sel)
    570  		arrange(selmon);
    571 @@ -1576,7 +1778,7 @@
    572  	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
    573  	if(f < 0.1 || f > 0.9)
    574  		return;
    575 -	selmon->mfact = f;
    576 +	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
    577  	arrange(selmon);
    578  }
    579  
    580 @@ -1594,6 +1796,7 @@
    581  	sw = DisplayWidth(dpy, screen);
    582  	sh = DisplayHeight(dpy, screen);
    583  	bh = dc.h = dc.font.height + 2;
    584 +	th = bh;
    585  	updategeom();
    586  	/* init atoms */
    587  	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
    588 @@ -1619,6 +1822,7 @@
    589  	dc.sel[ColBG] = getcolor(selbgcolor);
    590  	dc.sel[ColFG] = getcolor(selfgcolor);
    591  	dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
    592 +	dc.tabdrawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), th, DefaultDepth(dpy, screen));
    593  	dc.gc = XCreateGC(dpy, root, 0, NULL);
    594  	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
    595  	if(!dc.font.set)
    596 @@ -1729,13 +1933,22 @@
    597  
    598  void
    599  togglebar(const Arg *arg) {
    600 -	selmon->showbar = !selmon->showbar;
    601 +	selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
    602  	updatebarpos(selmon);
    603  	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
    604  	arrange(selmon);
    605  }
    606  
    607  void
    608 +toggletab(const Arg *arg) {
    609 +	selmon->showtab = selmon->pertag->showtabs[selmon->pertag->curtag] = !selmon->showtab;
    610 +	updatebarpos(selmon);
    611 +	XMoveResizeWindow(dpy, selmon->tabwin, selmon->wx, selmon->ty, selmon->ww, th);
    612 +	arrange(selmon);
    613 +}
    614 +
    615 +
    616 +void
    617  togglefloating(const Arg *arg) {
    618  	if(!selmon->sel)
    619  		return;
    620 @@ -1763,9 +1976,31 @@
    621  void
    622  toggleview(const Arg *arg) {
    623  	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
    624 +	int i;
    625  
    626  	if(newtagset) {
    627 +		if(newtagset == ~0) {
    628 +			selmon->pertag->prevtag = selmon->pertag->curtag;
    629 +			selmon->pertag->curtag = 0;
    630 +		}
    631 +		/* test if the user did not select the same tag */
    632 +		if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
    633 +			selmon->pertag->prevtag = selmon->pertag->curtag;
    634 +			for (i=0; !(newtagset & 1 << i); i++) ;
    635 +			selmon->pertag->curtag = i + 1;
    636 +		}
    637  		selmon->tagset[selmon->seltags] = newtagset;
    638 +
    639 +		/* apply settings for this view */
    640 +		selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
    641 +		selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
    642 +		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
    643 +		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
    644 +		selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
    645 +		if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
    646 +			togglebar(NULL);
    647 +		if (selmon->showtab != selmon->pertag->showtabs[selmon->pertag->curtag])
    648 +			toggletab(NULL);
    649  		focus(NULL);
    650  		arrange(selmon);
    651  	}
    652 @@ -1832,6 +2067,11 @@
    653  		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    654  		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
    655  		XMapRaised(dpy, m->barwin);
    656 +		m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
    657 +		                          CopyFromParent, DefaultVisual(dpy, screen),
    658 +		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    659 +		XDefineCursor(dpy, m->tabwin, cursor[CurNormal]);
    660 +		XMapRaised(dpy, m->tabwin);
    661  	}
    662  }
    663  
    664 @@ -1842,10 +2082,20 @@
    665  	if(m->showbar) {
    666  		m->wh -= bh;
    667  		m->by = m->topbar ? m->wy : m->wy + m->wh;
    668 -		m->wy = m->topbar ? m->wy + bh : m->wy;
    669 +		if ( m->topbar )
    670 +			m->wy += bh;
    671 +	} else {
    672 +	        m->by = -bh;
    673 +	}
    674 +
    675 +	if(m->showtab) {
    676 +		m->wh -= th;
    677 +		m->ty = m->toptab ? m->wy : m->wy + m->wh;
    678 +		if ( m->toptab )
    679 +		        m->wy += th;
    680 +	} else {
    681 +	        m->ty = -th;
    682  	}
    683 -	else
    684 -		m->by = -bh;
    685  }
    686  
    687  Bool
    688 @@ -2043,11 +2293,35 @@
    689  
    690  void
    691  view(const Arg *arg) {
    692 +	int i;
    693 +	unsigned int tmptag;
    694 +
    695  	if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
    696  		return;
    697  	selmon->seltags ^= 1; /* toggle sel tagset */
    698 -	if(arg->ui & TAGMASK)
    699 +	if(arg->ui & TAGMASK) {
    700 +		selmon->pertag->prevtag = selmon->pertag->curtag;
    701  		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
    702 +		if(arg->ui == ~0)
    703 +			selmon->pertag->curtag = 0;
    704 +		else {
    705 +			for (i=0; !(arg->ui & 1 << i); i++) ;
    706 +			selmon->pertag->curtag = i + 1;
    707 +		}
    708 +	} else {
    709 +		tmptag = selmon->pertag->prevtag;
    710 +		selmon->pertag->prevtag = selmon->pertag->curtag;
    711 +		selmon->pertag->curtag = tmptag;
    712 +	}
    713 +	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
    714 +	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
    715 +	selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
    716 +	selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
    717 +	selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
    718 +	if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
    719 +		togglebar(NULL);
    720 +	if (selmon->showtab != selmon->pertag->showtabs[selmon->pertag->curtag])
    721 +		toggletab(NULL);
    722  	focus(NULL);
    723  	arrange(selmon);
    724  }
    725 @@ -2073,7 +2347,7 @@
    726  	if(w == root && getrootptr(&x, &y))
    727  		return recttomon(x, y, 1, 1);
    728  	for(m = mons; m; m = m->next)
    729 -		if(w == m->barwin)
    730 +		if(w == m->barwin || w == m->tabwin)
    731  			return m;
    732  	if((c = wintoclient(w)))
    733  		return c->mon;