My dwm build
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

809 lines
25 KiB

  1. diff --git a/config.def.h b/config.def.h
  2. index fd77a07..8cc91c0 100644
  3. --- a/config.def.h
  4. +++ b/config.def.h
  5. @@ -5,6 +5,14 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
  6. static const unsigned int snap = 32; /* snap pixel */
  7. static const int showbar = 1; /* 0 means no bar */
  8. static const int topbar = 1; /* 0 means bottom bar */
  9. +
  10. +/* Display modes of the tab bar: never shown, always shown, shown only in */
  11. +/* monocle mode in presence of several windows. */
  12. +/* Modes after showtab_nmodes are disabled */
  13. +enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
  14. +static const int showtab = showtab_auto; /* Default tab bar show mode */
  15. +static const Bool toptab = False; /* False means bottom tab bar */
  16. +
  17. static const char *fonts[] = { "monospace:size=10" };
  18. static const char dmenufont[] = "monospace:size=10";
  19. static const char col_gray1[] = "#222222";
  20. @@ -18,9 +26,15 @@ static const char *colors[SchemeLast][3] = {
  21. [SchemeSel] = { col_gray4, col_cyan, col_cyan },
  22. };
  23. +
  24. /* tagging */
  25. static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
  26. +/* default layout per tags */
  27. +/* The first element is for all-tag view, following i-th element corresponds to */
  28. +/* tags[i]. Layout is referred using the layouts array index.*/
  29. +static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  30. +
  31. static const Rule rules[] = {
  32. /* xprop(1):
  33. * WM_CLASS(STRING) = instance, class
  34. @@ -64,6 +78,7 @@ static Key keys[] = {
  35. { MODKEY, XK_p, spawn, {.v = dmenucmd } },
  36. { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
  37. { MODKEY, XK_b, togglebar, {0} },
  38. + { MODKEY, XK_w, tabmode, {-1} },
  39. { MODKEY, XK_j, focusstack, {.i = +1 } },
  40. { MODKEY, XK_k, focusstack, {.i = -1 } },
  41. { MODKEY, XK_i, incnmaster, {.i = +1 } },
  42. @@ -111,5 +126,6 @@ static Button buttons[] = {
  43. { ClkTagBar, 0, Button3, toggleview, {0} },
  44. { ClkTagBar, MODKEY, Button1, tag, {0} },
  45. { ClkTagBar, MODKEY, Button3, toggletag, {0} },
  46. + { ClkTabBar, 0, Button1, focuswin, {0} },
  47. };
  48. diff --git a/dwm.1 b/dwm.1
  49. index 6687011..077d92b 100644
  50. --- a/dwm.1
  51. +++ b/dwm.1
  52. @@ -19,14 +19,22 @@ layout applied.
  53. Windows are grouped by tags. Each window can be tagged with one or multiple
  54. tags. Selecting certain tags displays all windows with these tags.
  55. .P
  56. -Each screen contains a small status bar which displays all available tags, the
  57. -layout, the title of the focused window, and the text read from the root window
  58. -name property, if the screen is focused. A floating window is indicated with an
  59. -empty square and a maximised floating window is indicated with a filled square
  60. -before the windows title. The selected tags are indicated with a different
  61. -color. The tags of the focused window are indicated with a filled square in the
  62. -top left corner. The tags which are applied to one or more windows are
  63. -indicated with an empty square in the top left corner.
  64. +Each screen contains two small status bars.
  65. +.P
  66. +One bar displays all available tags, the layout, the title of the focused
  67. +window, and the text read from the root window name property, if the screen is
  68. +focused. A floating window is indicated with an empty square and a maximised
  69. +floating window is indicated with a filled square before the windows title. The
  70. +selected tags are indicated with a different color. The tags of the focused
  71. +window are indicated with a filled square in the top left corner. The tags
  72. +which are applied to one or more windows are indicated with an empty square in
  73. +the top left corner.
  74. +.P
  75. +Another bar contains a tab for each window of the current view and allows
  76. +navigation between windows, especially in the monocle mode. The different
  77. +display modes of this bar are described under the Mod1\-w Keybord command
  78. +section. When a single tag is selected, that tag is indicated in the left corner
  79. +of the tab bar.
  80. .P
  81. dwm draws a small border around windows to indicate the focus state.
  82. .SH OPTIONS
  83. @@ -43,7 +51,8 @@ command.
  84. .TP
  85. .B Button1
  86. click on a tag label to display all windows with that tag, click on the layout
  87. -label toggles between tiled and floating layout.
  88. +label toggles between tiled and floating layout, click on a window name in the
  89. +tab bar brings focus to that window.
  90. .TP
  91. .B Button3
  92. click on a tag label adds/removes all windows with that tag to/from the view.
  93. @@ -104,6 +113,12 @@ Increase master area size.
  94. .B Mod1\-h
  95. Decrease master area size.
  96. .TP
  97. +.B Mod1\-w
  98. +Cycle over the tab bar display modes: never displayed, always displayed,
  99. +displayed only in monocle mode when the view contains than one window (auto
  100. +mode). Some display modes can be disabled in the configuration, config.h. In
  101. +the default configuration only "never" and "auto" display modes are enabled.
  102. +.TP
  103. .B Mod1\-Return
  104. Zooms/cycles focused window to/from master area (tiled layouts only).
  105. .TP
  106. diff --git a/dwm.c b/dwm.c
  107. index b2bc9bd..0c34020 100644
  108. --- a/dwm.c
  109. +++ b/dwm.c
  110. @@ -65,7 +65,7 @@ enum { NetSupported, NetWMName, NetWMState,
  111. NetWMFullscreen, NetActiveWindow, NetWMWindowType,
  112. NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
  113. enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
  114. -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
  115. +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
  116. ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
  117. typedef union {
  118. @@ -112,25 +112,35 @@ typedef struct {
  119. void (*arrange)(Monitor *);
  120. } Layout;
  121. +#define MAXTABS 50
  122. +
  123. +typedef struct Pertag Pertag;
  124. struct Monitor {
  125. char ltsymbol[16];
  126. float mfact;
  127. int nmaster;
  128. int num;
  129. int by; /* bar geometry */
  130. + int ty; /* tab bar geometry */
  131. int mx, my, mw, mh; /* screen size */
  132. int wx, wy, ww, wh; /* window area */
  133. unsigned int seltags;
  134. unsigned int sellt;
  135. unsigned int tagset[2];
  136. int showbar;
  137. + int showtab;
  138. int topbar;
  139. + int toptab;
  140. Client *clients;
  141. Client *sel;
  142. Client *stack;
  143. Monitor *next;
  144. Window barwin;
  145. + Window tabwin;
  146. + int ntabs;
  147. + int tab_widths[MAXTABS];
  148. const Layout *lt[2];
  149. + Pertag *pertag;
  150. };
  151. typedef struct {
  152. @@ -165,12 +175,15 @@ static void detachstack(Client *c);
  153. static Monitor *dirtomon(int dir);
  154. static void drawbar(Monitor *m);
  155. static void drawbars(void);
  156. +static void drawtab(Monitor *m);
  157. +static void drawtabs(void);
  158. static void enternotify(XEvent *e);
  159. static void expose(XEvent *e);
  160. static void focus(Client *c);
  161. static void focusin(XEvent *e);
  162. static void focusmon(const Arg *arg);
  163. static void focusstack(const Arg *arg);
  164. +static void focuswin(const Arg* arg);
  165. static int getrootptr(int *x, int *y);
  166. static long getstate(Window w);
  167. static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
  168. @@ -207,6 +220,7 @@ static void setup(void);
  169. static void showhide(Client *c);
  170. static void sigchld(int unused);
  171. static void spawn(const Arg *arg);
  172. +static void tabmode(const Arg *arg);
  173. static void tag(const Arg *arg);
  174. static void tagmon(const Arg *arg);
  175. static void tile(Monitor *);
  176. @@ -241,6 +255,7 @@ static char stext[256];
  177. static int screen;
  178. static int sw, sh; /* X display screen geometry width, height */
  179. static int bh, blw = 0; /* bar geometry */
  180. +static int th = 0; /* tab bar geometry */
  181. static int lrpad; /* sum of left and right padding for text */
  182. static int (*xerrorxlib)(Display *, XErrorEvent *);
  183. static unsigned int numlockmask = 0;
  184. @@ -272,6 +287,16 @@ static Window root;
  185. /* configuration, allows nested code to access above variables */
  186. #include "config.h"
  187. +struct Pertag {
  188. + unsigned int curtag, prevtag; /* current and previous tag */
  189. + int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
  190. + float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
  191. + unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
  192. + const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
  193. + Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
  194. + Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
  195. +};
  196. +
  197. /* compile-time check if all tags fit into an unsigned int bit array. */
  198. struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
  199. @@ -395,6 +420,8 @@ arrange(Monitor *m)
  200. void
  201. arrangemon(Monitor *m)
  202. {
  203. + updatebarpos(m);
  204. + XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
  205. strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
  206. if (m->lt[m->sellt]->arrange)
  207. m->lt[m->sellt]->arrange(m);
  208. @@ -444,14 +471,33 @@ buttonpress(XEvent *e)
  209. click = ClkStatusText;
  210. else
  211. click = ClkWinTitle;
  212. - } else if ((c = wintoclient(ev->window))) {
  213. + }
  214. + if(ev->window == selmon->tabwin) {
  215. + i = 0; x = 0;
  216. + for(c = selmon->clients; c; c = c->next){
  217. + if(!ISVISIBLE(c)) continue;
  218. + x += selmon->tab_widths[i];
  219. + if (ev->x > x)
  220. + ++i;
  221. + else
  222. + break;
  223. + if(i >= m->ntabs) break;
  224. + }
  225. + if(c) {
  226. + click = ClkTabBar;
  227. + arg.ui = i;
  228. + }
  229. + }
  230. + else if((c = wintoclient(ev->window))) {
  231. focus(c);
  232. click = ClkClientWin;
  233. }
  234. - for (i = 0; i < LENGTH(buttons); i++)
  235. - if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
  236. - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
  237. - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
  238. + for(i = 0; i < LENGTH(buttons); i++)
  239. + if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
  240. + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
  241. + buttons[i].func(((click == ClkTagBar || click == ClkTabBar)
  242. + && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
  243. + }
  244. }
  245. void
  246. @@ -476,8 +522,8 @@ cleanup(void)
  247. view(&a);
  248. selmon->lt[selmon->sellt] = &foo;
  249. for (m = mons; m; m = m->next)
  250. - while (m->stack)
  251. - unmanage(m->stack, 0);
  252. + while(m->stack)
  253. + unmanage(m->stack, False);
  254. XUngrabKey(dpy, AnyKey, AnyModifier, root);
  255. while (mons)
  256. cleanupmon(mons);
  257. @@ -504,6 +550,8 @@ cleanupmon(Monitor *mon)
  258. }
  259. XUnmapWindow(dpy, mon->barwin);
  260. XDestroyWindow(dpy, mon->barwin);
  261. + XUnmapWindow(dpy, mon->tabwin);
  262. + XDestroyWindow(dpy, mon->tabwin);
  263. free(mon);
  264. }
  265. @@ -525,6 +573,7 @@ clientmessage(XEvent *e)
  266. {
  267. XClientMessageEvent *cme = &e->xclient;
  268. Client *c = wintoclient(cme->window);
  269. + int i;
  270. if (!c)
  271. return;
  272. @@ -536,6 +585,8 @@ clientmessage(XEvent *e)
  273. if (!ISVISIBLE(c)) {
  274. c->mon->seltags ^= 1;
  275. c->mon->tagset[c->mon->seltags] = c->tags;
  276. + for(i=0; !(c->tags & 1 << i); i++);
  277. + view(&(Arg){.ui = 1 << i});
  278. }
  279. pop(c);
  280. }
  281. @@ -564,11 +615,10 @@ void
  282. configurenotify(XEvent *e)
  283. {
  284. Monitor *m;
  285. - Client *c;
  286. XConfigureEvent *ev = &e->xconfigure;
  287. int dirty;
  288. - /* TODO: updategeom handling sucks, needs to be simplified */
  289. + // TODO: updategeom handling sucks, needs to be simplified
  290. if (ev->window == root) {
  291. dirty = (sw != ev->width || sh != ev->height);
  292. sw = ev->width;
  293. @@ -576,10 +626,9 @@ configurenotify(XEvent *e)
  294. if (updategeom() || dirty) {
  295. drw_resize(drw, sw, bh);
  296. updatebars();
  297. - for (m = mons; m; m = m->next) {
  298. - for (c = m->clients; c; c = c->next)
  299. - if (c->isfullscreen)
  300. - resizeclient(c, m->mx, m->my, m->mw, m->mh);
  301. + //refreshing display of status bar. The tab bar is handled by the arrange()
  302. + //method, which is called below
  303. + for (m = mons; m; m = m->next){
  304. XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
  305. }
  306. focus(NULL);
  307. @@ -644,16 +693,41 @@ Monitor *
  308. createmon(void)
  309. {
  310. Monitor *m;
  311. + int i;
  312. m = ecalloc(1, sizeof(Monitor));
  313. m->tagset[0] = m->tagset[1] = 1;
  314. m->mfact = mfact;
  315. m->nmaster = nmaster;
  316. m->showbar = showbar;
  317. + m->showtab = showtab;
  318. m->topbar = topbar;
  319. - m->lt[0] = &layouts[0];
  320. + m->toptab = toptab;
  321. + m->ntabs = 0;
  322. + m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)];
  323. m->lt[1] = &layouts[1 % LENGTH(layouts)];
  324. strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
  325. + if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
  326. + die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
  327. + m->pertag->curtag = m->pertag->prevtag = 1;
  328. + for(i=0; i <= LENGTH(tags); i++) {
  329. + /* init nmaster */
  330. + m->pertag->nmasters[i] = m->nmaster;
  331. +
  332. + /* init mfacts */
  333. + m->pertag->mfacts[i] = m->mfact;
  334. +
  335. + /* init layouts */
  336. + m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)];
  337. + m->pertag->ltidxs[i][1] = m->lt[1];
  338. + m->pertag->sellts[i] = m->sellt;
  339. +
  340. + /* init showbar */
  341. + m->pertag->showbars[i] = m->showbar;
  342. +
  343. + /* swap focus and zoomswap*/
  344. + m->pertag->prevzooms[i] = NULL;
  345. + }
  346. return m;
  347. }
  348. @@ -765,6 +839,104 @@ drawbars(void)
  349. }
  350. void
  351. +drawtabs(void) {
  352. + Monitor *m;
  353. +
  354. + for(m = mons; m; m = m->next)
  355. + drawtab(m);
  356. +}
  357. +
  358. +static int
  359. +cmpint(const void *p1, const void *p2) {
  360. + /* The actual arguments to this function are "pointers to
  361. + pointers to char", but strcmp(3) arguments are "pointers
  362. + to char", hence the following cast plus dereference */
  363. + return *((int*) p1) > * (int*) p2;
  364. +}
  365. +
  366. +
  367. +void
  368. +drawtab(Monitor *m) {
  369. + Client *c;
  370. + int i;
  371. + int itag = -1;
  372. + char view_info[50];
  373. + int view_info_w = 0;
  374. + int sorted_label_widths[MAXTABS];
  375. + int tot_width;
  376. + int maxsize = bh;
  377. + int x = 0;
  378. + int w = 0;
  379. +
  380. + //view_info: indicate the tag which is displayed in the view
  381. + for(i = 0; i < LENGTH(tags); ++i){
  382. + if((selmon->tagset[selmon->seltags] >> i) & 1) {
  383. + if(itag >=0){ //more than one tag selected
  384. + itag = -1;
  385. + break;
  386. + }
  387. + itag = i;
  388. + }
  389. + }
  390. + if(0 <= itag && itag < LENGTH(tags)){
  391. + snprintf(view_info, sizeof view_info, "[%s]", tags[itag]);
  392. + } else {
  393. + strncpy(view_info, "[...]", sizeof view_info);
  394. + }
  395. + view_info[sizeof(view_info) - 1 ] = 0;
  396. + view_info_w = TEXTW(view_info);
  397. + tot_width = view_info_w;
  398. +
  399. + /* Calculates number of labels and their width */
  400. + m->ntabs = 0;
  401. + for(c = m->clients; c; c = c->next){
  402. + if(!ISVISIBLE(c)) continue;
  403. + m->tab_widths[m->ntabs] = TEXTW(c->name);
  404. + tot_width += m->tab_widths[m->ntabs];
  405. + ++m->ntabs;
  406. + if(m->ntabs >= MAXTABS) break;
  407. + }
  408. +
  409. + if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated
  410. + memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
  411. + qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
  412. + tot_width = view_info_w;
  413. + for(i = 0; i < m->ntabs; ++i){
  414. + if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
  415. + break;
  416. + tot_width += sorted_label_widths[i];
  417. + }
  418. + maxsize = (m->ww - tot_width) / (m->ntabs - i);
  419. + } else{
  420. + maxsize = m->ww;
  421. + }
  422. + i = 0;
  423. + for(c = m->clients; c; c = c->next){
  424. + if(!ISVISIBLE(c)) continue;
  425. + if(i >= m->ntabs) break;
  426. + if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize;
  427. + w = m->tab_widths[i];
  428. + drw_setscheme(drw, (c == m->sel) ? scheme[SchemeSel] : scheme[SchemeNorm]);
  429. + drw_text(drw, x, 0, w, th, lrpad / 2, c->name, 0);
  430. + x += w;
  431. + ++i;
  432. + }
  433. +
  434. + drw_setscheme(drw, scheme[SchemeNorm]);
  435. +
  436. + /* cleans interspace between window names and current viewed tag label */
  437. + w = m->ww - view_info_w - x;
  438. + drw_text(drw, x, 0, w, th, lrpad / 2, "", 0);
  439. +
  440. + /* view info */
  441. + x += w;
  442. + w = view_info_w;
  443. + drw_text(drw, x, 0, w, th, lrpad / 2, view_info, 0);
  444. +
  445. + drw_map(drw, m->tabwin, 0, 0, m->ww, th);
  446. +}
  447. +
  448. +void
  449. enternotify(XEvent *e)
  450. {
  451. Client *c;
  452. @@ -789,8 +961,10 @@ expose(XEvent *e)
  453. Monitor *m;
  454. XExposeEvent *ev = &e->xexpose;
  455. - if (ev->count == 0 && (m = wintomon(ev->window)))
  456. + if (ev->count == 0 && (m = wintomon(ev->window))){
  457. drawbar(m);
  458. + drawtab(m);
  459. + }
  460. }
  461. void
  462. @@ -817,6 +991,7 @@ focus(Client *c)
  463. }
  464. selmon->sel = c;
  465. drawbars();
  466. + drawtabs();
  467. }
  468. /* there are some broken focus acquiring clients */
  469. @@ -870,6 +1045,19 @@ focusstack(const Arg *arg)
  470. }
  471. }
  472. +void
  473. +focuswin(const Arg* arg){
  474. + int iwin = arg->i;
  475. + Client* c = NULL;
  476. + for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){
  477. + if(ISVISIBLE(c)) --iwin;
  478. + };
  479. + if(c) {
  480. + focus(c);
  481. + restack(selmon);
  482. + }
  483. +}
  484. +
  485. Atom
  486. getatomprop(Client *c, Atom prop)
  487. {
  488. @@ -983,7 +1171,7 @@ grabkeys(void)
  489. void
  490. incnmaster(const Arg *arg)
  491. {
  492. - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
  493. + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
  494. arrange(selmon);
  495. }
  496. @@ -1142,7 +1330,7 @@ motionnotify(XEvent *e)
  497. if (ev->window != root)
  498. return;
  499. if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
  500. - unfocus(selmon->sel, 1);
  501. + unfocus(selmon->sel, True);
  502. selmon = m;
  503. focus(NULL);
  504. }
  505. @@ -1162,11 +1350,13 @@ movemouse(const Arg *arg)
  506. return;
  507. if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
  508. return;
  509. + if(c->isfullscreen) /* no support moving fullscreen windows by mouse */
  510. + return;
  511. restack(selmon);
  512. ocx = c->x;
  513. ocy = c->y;
  514. if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  515. - None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
  516. + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
  517. return;
  518. if (!getrootptr(&x, &y))
  519. return;
  520. @@ -1253,12 +1443,14 @@ propertynotify(XEvent *e)
  521. case XA_WM_HINTS:
  522. updatewmhints(c);
  523. drawbars();
  524. + drawtabs();
  525. break;
  526. }
  527. if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  528. updatetitle(c);
  529. if (c == c->mon->sel)
  530. drawbar(c->mon);
  531. + drawtab(c->mon);
  532. }
  533. if (ev->atom == netatom[NetWMWindowType])
  534. updatewindowtype(c);
  535. @@ -1320,11 +1512,13 @@ resizemouse(const Arg *arg)
  536. return;
  537. if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
  538. return;
  539. + if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */
  540. + return;
  541. restack(selmon);
  542. ocx = c->x;
  543. ocy = c->y;
  544. if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  545. - None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
  546. + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
  547. return;
  548. XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  549. do {
  550. @@ -1372,6 +1566,7 @@ restack(Monitor *m)
  551. XWindowChanges wc;
  552. drawbar(m);
  553. + drawtab(m);
  554. if (!m->sel)
  555. return;
  556. if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
  557. @@ -1480,11 +1675,11 @@ sendevent(Client *c, Atom proto)
  558. void
  559. setfocus(Client *c)
  560. {
  561. - if (!c->neverfocus) {
  562. + if(!c->neverfocus) {
  563. XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  564. XChangeProperty(dpy, root, netatom[NetActiveWindow],
  565. - XA_WINDOW, 32, PropModeReplace,
  566. - (unsigned char *) &(c->win), 1);
  567. + XA_WINDOW, 32, PropModeReplace,
  568. + (unsigned char *) &(c->win), 1);
  569. }
  570. sendevent(c, wmatom[WMTakeFocus]);
  571. }
  572. @@ -1520,10 +1715,13 @@ setfullscreen(Client *c, int fullscreen)
  573. void
  574. setlayout(const Arg *arg)
  575. {
  576. - if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
  577. - selmon->sellt ^= 1;
  578. - if (arg && arg->v)
  579. - selmon->lt[selmon->sellt] = (Layout *)arg->v;
  580. + if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
  581. + selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
  582. + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  583. + }
  584. + if(arg && arg->v)
  585. + selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
  586. + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  587. strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
  588. if (selmon->sel)
  589. arrange(selmon);
  590. @@ -1542,7 +1740,7 @@ setmfact(const Arg *arg)
  591. f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
  592. if (f < 0.1 || f > 0.9)
  593. return;
  594. - selmon->mfact = f;
  595. + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
  596. arrange(selmon);
  597. }
  598. @@ -1564,6 +1762,7 @@ setup(void)
  599. die("no fonts could be loaded.\n");
  600. lrpad = drw->fonts->h;
  601. bh = drw->fonts->h + 2;
  602. + th = bh;
  603. updategeom();
  604. /* init atoms */
  605. wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  606. @@ -1631,10 +1830,10 @@ sigchld(int unused)
  607. void
  608. spawn(const Arg *arg)
  609. {
  610. - if (arg->v == dmenucmd)
  611. + if(arg->v == dmenucmd)
  612. dmenumon[0] = '0' + selmon->num;
  613. - if (fork() == 0) {
  614. - if (dpy)
  615. + if(fork() == 0) {
  616. + if(dpy)
  617. close(ConnectionNumber(dpy));
  618. setsid();
  619. execvp(((char **)arg->v)[0], (char **)arg->v);
  620. @@ -1691,18 +1890,29 @@ tile(Monitor *m)
  621. void
  622. togglebar(const Arg *arg)
  623. {
  624. - selmon->showbar = !selmon->showbar;
  625. + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
  626. updatebarpos(selmon);
  627. XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
  628. arrange(selmon);
  629. }
  630. void
  631. +tabmode(const Arg *arg)
  632. +{
  633. + if(arg && arg->i >= 0)
  634. + selmon->showtab = arg->ui % showtab_nmodes;
  635. + else
  636. + selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes;
  637. + arrange(selmon);
  638. +}
  639. +
  640. +
  641. +void
  642. togglefloating(const Arg *arg)
  643. {
  644. - if (!selmon->sel)
  645. + if(!selmon->sel)
  646. return;
  647. - if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
  648. + if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
  649. return;
  650. selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
  651. if (selmon->sel->isfloating)
  652. @@ -1730,9 +1940,29 @@ void
  653. toggleview(const Arg *arg)
  654. {
  655. unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
  656. + int i;
  657. if (newtagset) {
  658. + if(newtagset == ~0) {
  659. + selmon->pertag->prevtag = selmon->pertag->curtag;
  660. + selmon->pertag->curtag = 0;
  661. + }
  662. + /* test if the user did not select the same tag */
  663. + if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
  664. + selmon->pertag->prevtag = selmon->pertag->curtag;
  665. + for (i=0; !(newtagset & 1 << i); i++) ;
  666. + selmon->pertag->curtag = i + 1;
  667. + }
  668. selmon->tagset[selmon->seltags] = newtagset;
  669. +
  670. + /* apply settings for this view */
  671. + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
  672. + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
  673. + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  674. + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  675. + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
  676. + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
  677. + togglebar(NULL);
  678. focus(NULL);
  679. arrange(selmon);
  680. }
  681. @@ -1808,20 +2038,44 @@ updatebars(void)
  682. CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  683. XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
  684. XMapRaised(dpy, m->barwin);
  685. + m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
  686. + CopyFromParent, DefaultVisual(dpy, screen),
  687. + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  688. + XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
  689. + XMapRaised(dpy, m->tabwin);
  690. }
  691. }
  692. void
  693. updatebarpos(Monitor *m)
  694. {
  695. + Client *c;
  696. + int nvis = 0;
  697. +
  698. m->wy = m->my;
  699. m->wh = m->mh;
  700. if (m->showbar) {
  701. m->wh -= bh;
  702. m->by = m->topbar ? m->wy : m->wy + m->wh;
  703. - m->wy = m->topbar ? m->wy + bh : m->wy;
  704. - } else
  705. + if ( m->topbar )
  706. + m->wy += bh;
  707. + } else {
  708. m->by = -bh;
  709. + }
  710. +
  711. + for(c = m->clients; c; c = c->next){
  712. + if(ISVISIBLE(c)) ++nvis;
  713. + }
  714. +
  715. + if(m->showtab == showtab_always
  716. + || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){
  717. + m->wh -= th;
  718. + m->ty = m->toptab ? m->wy : m->wy + m->wh;
  719. + if ( m->toptab )
  720. + m->wy += th;
  721. + } else {
  722. + m->ty = -th;
  723. + }
  724. }
  725. void
  726. @@ -2003,9 +2257,9 @@ updatewindowtype(Client *c)
  727. Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
  728. if (state == netatom[NetWMFullscreen])
  729. - setfullscreen(c, 1);
  730. + setfullscreen(c, True);
  731. if (wtype == netatom[NetWMWindowTypeDialog])
  732. - c->isfloating = 1;
  733. + c->isfloating = True;
  734. }
  735. void
  736. @@ -2030,11 +2284,33 @@ updatewmhints(Client *c)
  737. void
  738. view(const Arg *arg)
  739. {
  740. - if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  741. + int i;
  742. + unsigned int tmptag;
  743. +
  744. + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  745. return;
  746. selmon->seltags ^= 1; /* toggle sel tagset */
  747. - if (arg->ui & TAGMASK)
  748. + if(arg->ui & TAGMASK) {
  749. + selmon->pertag->prevtag = selmon->pertag->curtag;
  750. selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
  751. + if(arg->ui == ~0)
  752. + selmon->pertag->curtag = 0;
  753. + else {
  754. + for (i=0; !(arg->ui & 1 << i); i++) ;
  755. + selmon->pertag->curtag = i + 1;
  756. + }
  757. + } else {
  758. + tmptag = selmon->pertag->prevtag;
  759. + selmon->pertag->prevtag = selmon->pertag->curtag;
  760. + selmon->pertag->curtag = tmptag;
  761. + }
  762. + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
  763. + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
  764. + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  765. + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  766. + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
  767. + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
  768. + togglebar(NULL);
  769. focus(NULL);
  770. arrange(selmon);
  771. }
  772. @@ -2062,7 +2338,7 @@ wintomon(Window w)
  773. if (w == root && getrootptr(&x, &y))
  774. return recttomon(x, y, 1, 1);
  775. for (m = mons; m; m = m->next)
  776. - if (w == m->barwin)
  777. + if(w == m->barwin || w == m->tabwin)
  778. return m;
  779. if ((c = wintoclient(w)))
  780. return c->mon;