dwm-6.1-tab-v2b.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-6.1-tab-v2b.diff (15707B) | |
--- | |
1 diff --git a/config.def.h b/config.def.h | |
2 index 7054c06..e784231 100644 | |
3 --- a/config.def.h | |
4 +++ b/config.def.h | |
5 @@ -15,6 +15,12 @@ static const unsigned int borderpx = 1; /* bo… | |
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 +/* Display modes of the tab bar: never shown, always shown, shown onl… | |
10 +/* monocle mode in presence of several windows. … | |
11 +/* Modes after showtab_nmodes are disabled … | |
12 +enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showt… | |
13 +static const int showtab = showtab_auto; /* Default tab bar … | |
14 +static const int toptab = False; /* False means bottom ta… | |
15 | |
16 /* tagging */ | |
17 static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "… | |
18 @@ -62,6 +68,7 @@ static Key keys[] = { | |
19 { MODKEY, XK_p, spawn, {.v … | |
20 { MODKEY|ShiftMask, XK_Return, spawn, {.v … | |
21 { MODKEY, XK_b, togglebar, {0} … | |
22 + { MODKEY, XK_w, tabmode, {-1}… | |
23 { MODKEY, XK_j, focusstack, {.i … | |
24 { MODKEY, XK_k, focusstack, {.i … | |
25 { MODKEY, XK_i, incnmaster, {.i … | |
26 @@ -109,5 +116,6 @@ static Button buttons[] = { | |
27 { ClkTagBar, 0, Button3, togglev… | |
28 { ClkTagBar, MODKEY, Button1, tag, … | |
29 { ClkTagBar, MODKEY, Button3, togglet… | |
30 + { ClkTabBar, 0, Button1, focuswi… | |
31 }; | |
32 | |
33 diff --git a/dwm.1 b/dwm.1 | |
34 index 6687011..9ff827c 100644 | |
35 --- a/dwm.1 | |
36 +++ b/dwm.1 | |
37 @@ -19,14 +19,22 @@ layout applied. | |
38 Windows are grouped by tags. Each window can be tagged with one or mult… | |
39 tags. Selecting certain tags displays all windows with these tags. | |
40 .P | |
41 -Each screen contains a small status bar which displays all available ta… | |
42 -layout, the title of the focused window, and the text read from the roo… | |
43 -name property, if the screen is focused. A floating window is indicated… | |
44 -empty square and a maximised floating window is indicated with a filled… | |
45 -before the windows title. The selected tags are indicated with a diffe… | |
46 -color. The tags of the focused window are indicated with a filled squar… | |
47 -top left corner. The tags which are applied to one or more windows are | |
48 -indicated with an empty square in the top left corner. | |
49 +Each screen contains two small status bars. | |
50 +.P | |
51 +One bar displays all available tags, the layout, the title of the focus… | |
52 +window, and the text read from the root window name property, if the sc… | |
53 +focused. A floating window is indicated with an empty square and a maxi… | |
54 +floating window is indicated with a filled square before the windows ti… | |
55 +selected tags are indicated with a different color. The tags of the foc… | |
56 +window are indicated with a filled square in the top left corner. The … | |
57 +which are applied to one or more windows are indicated with an empty sq… | |
58 +the top left corner. | |
59 +.P | |
60 +Another bar contains a tab for each window of the current view and allo… | |
61 +navigation between windows, especially in the monocle mode. The differe… | |
62 +display modes of this bar are described under the Mod1\-w Keybord comma… | |
63 +section. When a single tag is selected, this tag is indicated in the l… | |
64 +of the tab bar. | |
65 .P | |
66 dwm draws a small border around windows to indicate the focus state. | |
67 .SH OPTIONS | |
68 @@ -43,7 +51,8 @@ command. | |
69 .TP | |
70 .B Button1 | |
71 click on a tag label to display all windows with that tag, click on the… | |
72 -label toggles between tiled and floating layout. | |
73 +label toggles between tiled and floating layout, click on a window name… | |
74 +tab bar brings focus to that window. | |
75 .TP | |
76 .B Button3 | |
77 click on a tag label adds/removes all windows with that tag to/from the… | |
78 @@ -104,6 +113,12 @@ Increase master area size. | |
79 .B Mod1\-h | |
80 Decrease master area size. | |
81 .TP | |
82 +.B Mod1\-w | |
83 +Cycle over the tab bar display modes: never displayed, always displayed, | |
84 +displayed only in monocle mode when the view contains more than one win… | |
85 +mode). Some display modes can be disabled in the configuration, config.… | |
86 +the default configuration only "never" and "auto" display modes are ena… | |
87 +.TP | |
88 .B Mod1\-Return | |
89 Zooms/cycles focused window to/from master area (tiled layouts only). | |
90 .TP | |
91 diff --git a/dwm.c b/dwm.c | |
92 index 0362114..ff06772 100644 | |
93 --- a/dwm.c | |
94 +++ b/dwm.c | |
95 @@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, | |
96 NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |
97 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | |
98 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* defaul… | |
99 -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | |
100 +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | |
101 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ | |
102 | |
103 typedef union { | |
104 @@ -111,24 +111,32 @@ typedef struct { | |
105 void (*arrange)(Monitor *); | |
106 } Layout; | |
107 | |
108 +#define MAXTABS 50 | |
109 + | |
110 struct Monitor { | |
111 char ltsymbol[16]; | |
112 float mfact; | |
113 int nmaster; | |
114 int num; | |
115 int by; /* bar geometry */ | |
116 + int ty; /* tab bar geometry */ | |
117 int mx, my, mw, mh; /* screen size */ | |
118 int wx, wy, ww, wh; /* window area */ | |
119 unsigned int seltags; | |
120 unsigned int sellt; | |
121 unsigned int tagset[2]; | |
122 int showbar; | |
123 + int showtab; | |
124 int topbar; | |
125 + int toptab; | |
126 Client *clients; | |
127 Client *sel; | |
128 Client *stack; | |
129 Monitor *next; | |
130 Window barwin; | |
131 + Window tabwin; | |
132 + int ntabs; | |
133 + int tab_widths[MAXTABS]; | |
134 const Layout *lt[2]; | |
135 }; | |
136 | |
137 @@ -164,12 +172,15 @@ static void detachstack(Client *c); | |
138 static Monitor *dirtomon(int dir); | |
139 static void drawbar(Monitor *m); | |
140 static void drawbars(void); | |
141 +static void drawtab(Monitor *m); | |
142 +static void drawtabs(void); | |
143 static void enternotify(XEvent *e); | |
144 static void expose(XEvent *e); | |
145 static void focus(Client *c); | |
146 static void focusin(XEvent *e); | |
147 static void focusmon(const Arg *arg); | |
148 static void focusstack(const Arg *arg); | |
149 +static void focuswin(const Arg* arg); | |
150 static int getrootptr(int *x, int *y); | |
151 static long getstate(Window w); | |
152 static int gettextprop(Window w, Atom atom, char *text, unsigned int si… | |
153 @@ -206,6 +217,7 @@ static void setup(void); | |
154 static void showhide(Client *c); | |
155 static void sigchld(int unused); | |
156 static void spawn(const Arg *arg); | |
157 +static void tabmode(const Arg *arg); | |
158 static void tag(const Arg *arg); | |
159 static void tagmon(const Arg *arg); | |
160 static void tile(Monitor *); | |
161 @@ -240,6 +252,7 @@ static char stext[256]; | |
162 static int screen; | |
163 static int sw, sh; /* X display screen geometry width, height… | |
164 static int bh, blw = 0; /* bar geometry */ | |
165 +static int th = 0; /* tab bar geometry */ | |
166 static int (*xerrorxlib)(Display *, XErrorEvent *); | |
167 static unsigned int numlockmask = 0; | |
168 static void (*handler[LASTEvent]) (XEvent *) = { | |
169 @@ -391,8 +404,9 @@ arrange(Monitor *m) | |
170 } | |
171 | |
172 void | |
173 -arrangemon(Monitor *m) | |
174 -{ | |
175 +arrangemon(Monitor *m) { | |
176 + updatebarpos(m); | |
177 + XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); | |
178 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbo… | |
179 if (m->lt[m->sellt]->arrange) | |
180 m->lt[m->sellt]->arrange(m); | |
181 @@ -442,14 +456,33 @@ buttonpress(XEvent *e) | |
182 click = ClkStatusText; | |
183 else | |
184 click = ClkWinTitle; | |
185 - } else if ((c = wintoclient(ev->window))) { | |
186 + } | |
187 + if(ev->window == selmon->tabwin) { | |
188 + i = 0; x = 0; | |
189 + for(c = selmon->clients; c; c = c->next){ | |
190 + if(!ISVISIBLE(c)) continue; | |
191 + x += selmon->tab_widths[i]; | |
192 + if (ev->x > x) | |
193 + ++i; | |
194 + else | |
195 + break; | |
196 + if(i >= m->ntabs) break; | |
197 + } | |
198 + if(c) { | |
199 + click = ClkTabBar; | |
200 + arg.ui = i; | |
201 + } | |
202 + } | |
203 + else if((c = wintoclient(ev->window))) { | |
204 focus(c); | |
205 click = ClkClientWin; | |
206 } | |
207 for (i = 0; i < LENGTH(buttons); i++) | |
208 if (click == buttons[i].click && buttons[i].func && but… | |
209 - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) | |
210 - buttons[i].func(click == ClkTagBar && buttons[i… | |
211 + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ | |
212 + buttons[i].func(((click == ClkTagBar || click =… | |
213 + && buttons[i].arg.i == 0) ? &arg : &… | |
214 + } | |
215 } | |
216 | |
217 void | |
218 @@ -505,6 +538,8 @@ cleanupmon(Monitor *mon) | |
219 } | |
220 XUnmapWindow(dpy, mon->barwin); | |
221 XDestroyWindow(dpy, mon->barwin); | |
222 + XUnmapWindow(dpy, mon->tabwin); | |
223 + XDestroyWindow(dpy, mon->tabwin); | |
224 free(mon); | |
225 } | |
226 | |
227 @@ -565,6 +600,7 @@ void | |
228 configurenotify(XEvent *e) | |
229 { | |
230 Monitor *m; | |
231 + Client *c; | |
232 XConfigureEvent *ev = &e->xconfigure; | |
233 int dirty; | |
234 | |
235 @@ -576,8 +612,12 @@ configurenotify(XEvent *e) | |
236 if (updategeom() || dirty) { | |
237 drw_resize(drw, sw, bh); | |
238 updatebars(); | |
239 - for (m = mons; m; m = m->next) | |
240 + for(m = mons; m; m = m->next){ | |
241 + for (c = m->clients; c; c = c->next) | |
242 + if (c->isfullscreen) | |
243 + resizeclient(c, m->mx, … | |
244 XMoveResizeWindow(dpy, m->barwin, m->wx… | |
245 + } | |
246 focus(NULL); | |
247 arrange(NULL); | |
248 } | |
249 @@ -646,7 +686,10 @@ createmon(void) | |
250 m->mfact = mfact; | |
251 m->nmaster = nmaster; | |
252 m->showbar = showbar; | |
253 + m->showtab = showtab; | |
254 m->topbar = topbar; | |
255 + m->toptab = toptab; | |
256 + m->ntabs = 0; | |
257 m->lt[0] = &layouts[0]; | |
258 m->lt[1] = &layouts[1 % LENGTH(layouts)]; | |
259 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); | |
260 @@ -763,6 +806,105 @@ drawbars(void) | |
261 } | |
262 | |
263 void | |
264 +drawtabs(void) { | |
265 + Monitor *m; | |
266 + | |
267 + for(m = mons; m; m = m->next) | |
268 + drawtab(m); | |
269 +} | |
270 + | |
271 +static int | |
272 +cmpint(const void *p1, const void *p2) { | |
273 + /* The actual arguments to this function are "pointers to | |
274 + pointers to char", but strcmp(3) arguments are "pointers | |
275 + to char", hence the following cast plus dereference */ | |
276 + return *((int*) p1) > * (int*) p2; | |
277 +} | |
278 + | |
279 + | |
280 +void | |
281 +drawtab(Monitor *m) { | |
282 + Client *c; | |
283 + int i; | |
284 + int itag = -1; | |
285 + char view_info[50]; | |
286 + int view_info_w = 0; | |
287 + int sorted_label_widths[MAXTABS]; | |
288 + int tot_width; | |
289 + int maxsize = bh; | |
290 + int x = 0; | |
291 + int w = 0; | |
292 + | |
293 + //view_info: indicate the tag which is displayed in the view | |
294 + for(i = 0; i < LENGTH(tags); ++i){ | |
295 + if((selmon->tagset[selmon->seltags] >> i) & 1) { | |
296 + if(itag >=0){ //more than one tag selected | |
297 + itag = -1; | |
298 + break; | |
299 + } | |
300 + itag = i; | |
301 + } | |
302 + } | |
303 + | |
304 + if(0 <= itag && itag < LENGTH(tags)){ | |
305 + snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); | |
306 + } else { | |
307 + strncpy(view_info, "[...]", sizeof view_info); | |
308 + } | |
309 + view_info[sizeof(view_info) - 1 ] = 0; | |
310 + view_info_w = TEXTW(view_info); | |
311 + tot_width = view_info_w; | |
312 + | |
313 + /* Calculates number of labels and their width */ | |
314 + m->ntabs = 0; | |
315 + for(c = m->clients; c; c = c->next){ | |
316 + if(!ISVISIBLE(c)) continue; | |
317 + m->tab_widths[m->ntabs] = TEXTW(c->name); | |
318 + tot_width += m->tab_widths[m->ntabs]; | |
319 + ++m->ntabs; | |
320 + if(m->ntabs >= MAXTABS) break; | |
321 + } | |
322 + | |
323 + if(tot_width > m->ww){ //not enough space to display the labels… | |
324 + memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->n… | |
325 + qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); | |
326 + tot_width = view_info_w; | |
327 + for(i = 0; i < m->ntabs; ++i){ | |
328 + if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m-… | |
329 + break; | |
330 + tot_width += sorted_label_widths[i]; | |
331 + } | |
332 + maxsize = (m->ww - tot_width) / (m->ntabs - i); | |
333 + } else{ | |
334 + maxsize = m->ww; | |
335 + } | |
336 + i = 0; | |
337 + for(c = m->clients; c; c = c->next){ | |
338 + if(!ISVISIBLE(c)) continue; | |
339 + if(i >= m->ntabs) break; | |
340 + if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; | |
341 + w = m->tab_widths[i]; | |
342 + drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &sche… | |
343 + drw_text(drw, x, 0, w, th, c->name, 0); | |
344 + x += w; | |
345 + ++i; | |
346 + } | |
347 + | |
348 + drw_setscheme(drw, &scheme[SchemeNorm]); | |
349 + | |
350 + /* cleans interspace between window names and current viewed ta… | |
351 + w = m->ww - view_info_w - x; | |
352 + drw_text(drw, x, 0, w, th, "", 0); | |
353 + | |
354 + /* view info */ | |
355 + x += w; | |
356 + w = view_info_w; | |
357 + drw_text(drw, x, 0, w, th, view_info, 0); | |
358 + | |
359 + drw_map(drw, m->tabwin, 0, 0, m->ww, th); | |
360 +} | |
361 + | |
362 +void | |
363 enternotify(XEvent *e) | |
364 { | |
365 Client *c; | |
366 @@ -787,8 +929,10 @@ expose(XEvent *e) | |
367 Monitor *m; | |
368 XExposeEvent *ev = &e->xexpose; | |
369 | |
370 - if (ev->count == 0 && (m = wintomon(ev->window))) | |
371 + if(ev->count == 0 && (m = wintomon(ev->window))){ | |
372 drawbar(m); | |
373 + drawtab(m); | |
374 + } | |
375 } | |
376 | |
377 void | |
378 @@ -815,6 +959,7 @@ focus(Client *c) | |
379 } | |
380 selmon->sel = c; | |
381 drawbars(); | |
382 + drawtabs(); | |
383 } | |
384 | |
385 /* there are some broken focus acquiring clients */ | |
386 @@ -868,6 +1013,19 @@ focusstack(const Arg *arg) | |
387 } | |
388 } | |
389 | |
390 +void | |
391 +focuswin(const Arg* arg){ | |
392 + int iwin = arg->i; | |
393 + Client* c = NULL; | |
394 + for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ | |
395 + if(ISVISIBLE(c)) --iwin; | |
396 + }; | |
397 + if(c) { | |
398 + focus(c); | |
399 + restack(selmon); | |
400 + } | |
401 +} | |
402 + | |
403 Atom | |
404 getatomprop(Client *c, Atom prop) | |
405 { | |
406 @@ -1250,12 +1408,14 @@ propertynotify(XEvent *e) | |
407 case XA_WM_HINTS: | |
408 updatewmhints(c); | |
409 drawbars(); | |
410 + drawtabs(); | |
411 break; | |
412 } | |
413 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWM… | |
414 updatetitle(c); | |
415 if (c == c->mon->sel) | |
416 drawbar(c->mon); | |
417 + drawtab(c->mon); | |
418 } | |
419 if (ev->atom == netatom[NetWMWindowType]) | |
420 updatewindowtype(c); | |
421 @@ -1369,6 +1529,7 @@ restack(Monitor *m) | |
422 XWindowChanges wc; | |
423 | |
424 drawbar(m); | |
425 + drawtab(m); | |
426 if (!m->sel) | |
427 return; | |
428 if (m->sel->isfloating || !m->lt[m->sellt]->arrange) | |
429 @@ -1561,6 +1722,8 @@ setup(void) | |
430 if (!drw->fontcount) | |
431 die("no fonts could be loaded.\n"); | |
432 bh = drw->fonts[0]->h + 2; | |
433 + th = bh; | |
434 + | |
435 updategeom(); | |
436 /* init atoms */ | |
437 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); | |
438 @@ -1699,6 +1862,17 @@ togglebar(const Arg *arg) | |
439 } | |
440 | |
441 void | |
442 +tabmode(const Arg *arg) | |
443 +{ | |
444 + if(arg && arg->i >= 0) | |
445 + selmon->showtab = arg->ui % showtab_nmodes; | |
446 + else | |
447 + selmon->showtab = (selmon->showtab + 1 ) % showtab_nmod… | |
448 + arrange(selmon); | |
449 +} | |
450 + | |
451 + | |
452 +void | |
453 togglefloating(const Arg *arg) | |
454 { | |
455 if (!selmon->sel) | |
456 @@ -1809,20 +1983,44 @@ updatebars(void) | |
457 CWOverrideRedirect|CWBackPixm… | |
458 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor… | |
459 XMapRaised(dpy, m->barwin); | |
460 + m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->w… | |
461 + CopyFromParent, DefaultVisual… | |
462 + CWOverrideRedirect|CWBackPixm… | |
463 + XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor… | |
464 + XMapRaised(dpy, m->tabwin); | |
465 } | |
466 } | |
467 | |
468 void | |
469 updatebarpos(Monitor *m) | |
470 { | |
471 + Client *c; | |
472 + int nvis = 0; | |
473 + | |
474 m->wy = m->my; | |
475 m->wh = m->mh; | |
476 if (m->showbar) { | |
477 m->wh -= bh; | |
478 m->by = m->topbar ? m->wy : m->wy + m->wh; | |
479 - m->wy = m->topbar ? m->wy + bh : m->wy; | |
480 - } else | |
481 + if ( m->topbar ) | |
482 + m->wy += bh; | |
483 + } else { | |
484 m->by = -bh; | |
485 + } | |
486 + | |
487 + for(c = m->clients; c; c = c->next){ | |
488 + if(ISVISIBLE(c)) ++nvis; | |
489 + } | |
490 + | |
491 + if(m->showtab == showtab_always | |
492 + || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->… | |
493 + m->wh -= th; | |
494 + m->ty = m->toptab ? m->wy : m->wy + m->wh; | |
495 + if ( m->toptab ) | |
496 + m->wy += th; | |
497 + } else { | |
498 + m->ty = -th; | |
499 + } | |
500 } | |
501 | |
502 void | |
503 @@ -2063,7 +2261,7 @@ wintomon(Window w) | |
504 if (w == root && getrootptr(&x, &y)) | |
505 return recttomon(x, y, 1, 1); | |
506 for (m = mons; m; m = m->next) | |
507 - if (w == m->barwin) | |
508 + if (w == m->barwin || w == m->tabwin) | |
509 return m; | |
510 if ((c = wintoclient(w))) | |
511 return c->mon; |