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