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