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;