dwm-tab-i3like-20211121-a786211.diff - sites - public wiki contents of suckless… | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-tab-i3like-20211121-a786211.diff (14158B) | |
--- | |
1 From 5e489a57cdce6517996df26808b58bdd32bbd99f Mon Sep 17 00:00:00 2001 | |
2 From: howoz <[email protected]> | |
3 Date: Sun, 21 Nov 2021 16:23:04 +0300 | |
4 Subject: [PATCH] [dwm][patches][tab] i3 like tabs that cover the whole s… | |
5 width | |
6 | |
7 --- | |
8 config.def.h | 9 +++ | |
9 dwm.1 | 33 ++++++++--- | |
10 dwm.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++---- | |
11 3 files changed, 183 insertions(+), 19 deletions(-) | |
12 | |
13 diff --git a/config.def.h b/config.def.h | |
14 index a2ac963..931d7ae 100644 | |
15 --- a/config.def.h | |
16 +++ b/config.def.h | |
17 @@ -5,6 +5,13 @@ static const unsigned int borderpx = 1; /* bord… | |
18 static const unsigned int snap = 32; /* snap pixel */ | |
19 static const int showbar = 1; /* 0 means no bar */ | |
20 static const int topbar = 1; /* 0 means bottom bar */ | |
21 +/* Display modes of the tab bar: never shown, always shown, shown only… | |
22 +/* monocle mode in the presence of several windows. … | |
23 +/* Modes after showtab_nmodes are disabled. … | |
24 +enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showt… | |
25 +static const int showtab = showtab_auto; … | |
26 +static const int toptab = False; … | |
27 + | |
28 static const char *fonts[] = { "monospace:size=10" }; | |
29 static const char dmenufont[] = "monospace:size=10"; | |
30 static const char col_gray1[] = "#222222"; | |
31 @@ -65,6 +72,7 @@ static Key keys[] = { | |
32 { MODKEY, XK_p, spawn, {.v … | |
33 { MODKEY|ShiftMask, XK_Return, spawn, {.v … | |
34 { MODKEY, XK_b, togglebar, {0} … | |
35 + { MODKEY, XK_w, tabmode, {-1}… | |
36 { MODKEY, XK_j, focusstack, {.i … | |
37 { MODKEY, XK_k, focusstack, {.i … | |
38 { MODKEY, XK_i, incnmaster, {.i … | |
39 @@ -112,5 +120,6 @@ static Button buttons[] = { | |
40 { ClkTagBar, 0, Button3, togglev… | |
41 { ClkTagBar, MODKEY, Button1, tag, … | |
42 { ClkTagBar, MODKEY, Button3, togglet… | |
43 + { ClkTabBar, 0, Button1, focuswi… | |
44 }; | |
45 | |
46 diff --git a/dwm.1 b/dwm.1 | |
47 index ddc8321..7752444 100644 | |
48 --- a/dwm.1 | |
49 +++ b/dwm.1 | |
50 @@ -20,14 +20,22 @@ layout applied. | |
51 Windows are grouped by tags. Each window can be tagged with one or mult… | |
52 tags. Selecting certain tags displays all windows with these tags. | |
53 .P | |
54 -Each screen contains a small status bar which displays all available ta… | |
55 -layout, the title of the focused window, and the text read from the roo… | |
56 -name property, if the screen is focused. A floating window is indicated… | |
57 -empty square and a maximised floating window is indicated with a filled… | |
58 -before the windows title. The selected tags are indicated with a diffe… | |
59 -color. The tags of the focused window are indicated with a filled squar… | |
60 -top left corner. The tags which are applied to one or more windows are | |
61 -indicated with an empty square in the top left corner. | |
62 +Each screen contains two small status bars. | |
63 +.P | |
64 +One bar displays all available tags, the layout, the title of the focus… | |
65 +window, and the text read from the root window name property, if the sc… | |
66 +focused. A floating window is indicated with an empty square and a maxi… | |
67 +floating window is indicated with a filled square before the windows ti… | |
68 +selected tags are indicated with a different color. The tags of the foc… | |
69 +window are indicated with a filled square in the top left corner. The … | |
70 +which are applied to one or more windows are indicated with an empty sq… | |
71 +the top left corner. | |
72 +.P | |
73 +Another bar contains a tab for each window of the current view and allo… | |
74 +navigation between windows, especially in the monocle mode. The differe… | |
75 +display modes of this bar are described under the Mod1\-w Keybord comma… | |
76 +section. When a single tag is selected, this tag is indicated in the l… | |
77 +of the tab bar. | |
78 .P | |
79 dwm draws a small border around windows to indicate the focus state. | |
80 .SH OPTIONS | |
81 @@ -44,7 +52,8 @@ command. | |
82 .TP | |
83 .B Button1 | |
84 click on a tag label to display all windows with that tag, click on the… | |
85 -label toggles between tiled and floating layout. | |
86 +label toggles between tiled and floating layout, click on a window name… | |
87 +tab bar brings focus to that window. | |
88 .TP | |
89 .B Button3 | |
90 click on a tag label adds/removes all windows with that tag to/from the… | |
91 @@ -110,6 +119,12 @@ Increase master area size. | |
92 .B Mod1\-h | |
93 Decrease master area size. | |
94 .TP | |
95 +.B Mod1\-w | |
96 +Cycle over the tab bar display modes: never displayed, always displayed, | |
97 +displayed only in monocle mode when the view contains more than one win… | |
98 +mode). Some display modes can be disabled in the configuration, config.… | |
99 +the default configuration only "never" and "auto" display modes are ena… | |
100 +.TP | |
101 .B Mod1\-Return | |
102 Zooms/cycles focused window to/from master area (tiled layouts only). | |
103 .TP | |
104 diff --git a/dwm.c b/dwm.c | |
105 index 5e4d494..8404747 100644 | |
106 --- a/dwm.c | |
107 +++ b/dwm.c | |
108 @@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, | |
109 NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |
110 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | |
111 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* defaul… | |
112 -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | |
113 +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | |
114 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ | |
115 | |
116 typedef union { | |
117 @@ -111,24 +111,32 @@ typedef struct { | |
118 void (*arrange)(Monitor *); | |
119 } Layout; | |
120 | |
121 +#define MAXTABS 50 | |
122 + | |
123 struct Monitor { | |
124 char ltsymbol[16]; | |
125 float mfact; | |
126 int nmaster; | |
127 int num; | |
128 int by; /* bar geometry */ | |
129 + int ty; /* tab bar geometry */ | |
130 int mx, my, mw, mh; /* screen size */ | |
131 int wx, wy, ww, wh; /* window area */ | |
132 unsigned int seltags; | |
133 unsigned int sellt; | |
134 unsigned int tagset[2]; | |
135 int showbar; | |
136 + int showtab; | |
137 int topbar; | |
138 + int toptab; | |
139 Client *clients; | |
140 Client *sel; | |
141 Client *stack; | |
142 Monitor *next; | |
143 Window barwin; | |
144 + Window tabwin; | |
145 + int ntabs; | |
146 + int tab_widths[MAXTABS]; | |
147 const Layout *lt[2]; | |
148 }; | |
149 | |
150 @@ -169,6 +177,7 @@ static void focus(Client *c); | |
151 static void focusin(XEvent *e); | |
152 static void focusmon(const Arg *arg); | |
153 static void focusstack(const Arg *arg); | |
154 +static void focuswin(const Arg* arg); | |
155 static Atom getatomprop(Client *c, Atom prop); | |
156 static int getrootptr(int *x, int *y); | |
157 static long getstate(Window w); | |
158 @@ -207,6 +216,7 @@ static void seturgent(Client *c, int urg); | |
159 static void showhide(Client *c); | |
160 static void sigchld(int unused); | |
161 static void spawn(const Arg *arg); | |
162 +static void tabmode(const Arg *arg); | |
163 static void tag(const Arg *arg); | |
164 static void tagmon(const Arg *arg); | |
165 static void tile(Monitor *); | |
166 @@ -241,6 +251,7 @@ static char stext[256]; | |
167 static int screen; | |
168 static int sw, sh; /* X display screen geometry width, height… | |
169 static int bh, blw = 0; /* bar geometry */ | |
170 +static int th = 0; /* tab bar geometry */ | |
171 static int lrpad; /* sum of left and right padding for text … | |
172 static int (*xerrorxlib)(Display *, XErrorEvent *); | |
173 static unsigned int numlockmask = 0; | |
174 @@ -393,8 +404,9 @@ arrange(Monitor *m) | |
175 } | |
176 | |
177 void | |
178 -arrangemon(Monitor *m) | |
179 -{ | |
180 +arrangemon(Monitor *m) { | |
181 + updatebarpos(m); | |
182 + XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); | |
183 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbo… | |
184 if (m->lt[m->sellt]->arrange) | |
185 m->lt[m->sellt]->arrange(m); | |
186 @@ -444,7 +456,24 @@ buttonpress(XEvent *e) | |
187 click = ClkStatusText; | |
188 else | |
189 click = ClkWinTitle; | |
190 - } else if ((c = wintoclient(ev->window))) { | |
191 + } | |
192 + if(ev->window == selmon->tabwin) { | |
193 + i = 0; x = 0; | |
194 + for(c = selmon->clients; c; c = c->next){ | |
195 + if(!ISVISIBLE(c)) continue; | |
196 + x += selmon->tab_widths[i]; | |
197 + if (ev->x > x) | |
198 + ++i; | |
199 + else | |
200 + break; | |
201 + if(i >= m->ntabs) break; | |
202 + } | |
203 + if(c) { | |
204 + click = ClkTabBar; | |
205 + arg.ui = i; | |
206 + } | |
207 + } | |
208 + else if((c = wintoclient(ev->window))) { | |
209 focus(c); | |
210 restack(selmon); | |
211 XAllowEvents(dpy, ReplayPointer, CurrentTime); | |
212 @@ -452,8 +481,9 @@ buttonpress(XEvent *e) | |
213 } | |
214 for (i = 0; i < LENGTH(buttons); i++) | |
215 if (click == buttons[i].click && buttons[i].func && but… | |
216 - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) | |
217 - buttons[i].func(click == ClkTagBar && buttons[i… | |
218 + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ | |
219 + buttons[i].func(((click == ClkTagBar || click =… | |
220 + } | |
221 } | |
222 | |
223 void | |
224 @@ -507,6 +537,8 @@ cleanupmon(Monitor *mon) | |
225 } | |
226 XUnmapWindow(dpy, mon->barwin); | |
227 XDestroyWindow(dpy, mon->barwin); | |
228 + XUnmapWindow(dpy, mon->tabwin); | |
229 + XDestroyWindow(dpy, mon->tabwin); | |
230 free(mon); | |
231 } | |
232 | |
233 @@ -638,7 +670,10 @@ createmon(void) | |
234 m->mfact = mfact; | |
235 m->nmaster = nmaster; | |
236 m->showbar = showbar; | |
237 + m->showtab = showtab; | |
238 m->topbar = topbar; | |
239 + m->toptab = toptab; | |
240 + m->ntabs = 0; | |
241 m->lt[0] = &layouts[0]; | |
242 m->lt[1] = &layouts[1 % LENGTH(layouts)]; | |
243 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); | |
244 @@ -752,6 +787,56 @@ drawbars(void) | |
245 drawbar(m); | |
246 } | |
247 | |
248 +void | |
249 +drawtabs(void) { | |
250 + Monitor *m; | |
251 + | |
252 + for(m = mons; m; m = m->next) | |
253 + drawtab(m); | |
254 +} | |
255 + | |
256 +void | |
257 +drawtab(Monitor *m) { | |
258 + Client *c; | |
259 + int i; | |
260 + int maxsize; | |
261 + int remainder = 0; | |
262 + int x = 0; | |
263 + int w = 0; | |
264 + | |
265 + /* Calculates number of labels and their width */ | |
266 + m->ntabs = 0; | |
267 + for(c = m->clients; c; c = c->next){ | |
268 + if(!ISVISIBLE(c)) continue; | |
269 + m->tab_widths[m->ntabs] = (int)TEXTW(c->name); | |
270 + ++m->ntabs; | |
271 + if(m->ntabs >= MAXTABS) break; | |
272 + } | |
273 + | |
274 + if(m->ntabs > 0) remainder = m->mw % m->ntabs; | |
275 + maxsize = (1.0 / (double)m->ntabs) * m->mw; | |
276 + | |
277 + i = 0; | |
278 + int tm; /* middle of the tab*/ | |
279 + for(c = m->clients; c; c = c->next){ | |
280 + if(!ISVISIBLE(c)) continue; | |
281 + if(i >= m->ntabs) break; | |
282 + m->tab_widths[i] = maxsize; | |
283 + /* add the remainder to the last tab so there is no leftover … | |
284 + if(remainder && i == m->ntabs - 1) m->tab_widths[i] += remain… | |
285 + w = m->tab_widths[i]; | |
286 + drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeN… | |
287 + tm = (m->tab_widths[i] - (int)TEXTW(c->name)) / 2; | |
288 + tm = (int)TEXTW(c->name) >= m->tab_widths[i] ? lrpad / 2 : tm; | |
289 + drw_text(drw, x, 0, w, th, tm, c->name, 0); | |
290 + x += w; | |
291 + ++i; | |
292 + } | |
293 + | |
294 + drw_setscheme(drw, scheme[SchemeNorm]); | |
295 + drw_map(drw, m->tabwin, 0, 0, m->mw, th); | |
296 +} | |
297 + | |
298 void | |
299 enternotify(XEvent *e) | |
300 { | |
301 @@ -777,8 +862,10 @@ expose(XEvent *e) | |
302 Monitor *m; | |
303 XExposeEvent *ev = &e->xexpose; | |
304 | |
305 - if (ev->count == 0 && (m = wintomon(ev->window))) | |
306 + if(ev->count == 0 && (m = wintomon(ev->window))){ | |
307 drawbar(m); | |
308 + drawtab(m); | |
309 + } | |
310 } | |
311 | |
312 void | |
313 @@ -804,6 +891,7 @@ focus(Client *c) | |
314 } | |
315 selmon->sel = c; | |
316 drawbars(); | |
317 + drawtabs(); | |
318 } | |
319 | |
320 /* there are some broken focus acquiring clients needing extra handling… | |
321 @@ -856,6 +944,19 @@ focusstack(const Arg *arg) | |
322 } | |
323 } | |
324 | |
325 +void | |
326 +focuswin(const Arg* arg){ | |
327 + int iwin = arg->i; | |
328 + Client* c = NULL; | |
329 + for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ | |
330 + if(ISVISIBLE(c)) --iwin; | |
331 + }; | |
332 + if(c) { | |
333 + focus(c); | |
334 + restack(selmon); | |
335 + } | |
336 +} | |
337 + | |
338 Atom | |
339 getatomprop(Client *c, Atom prop) | |
340 { | |
341 @@ -1234,12 +1335,14 @@ propertynotify(XEvent *e) | |
342 case XA_WM_HINTS: | |
343 updatewmhints(c); | |
344 drawbars(); | |
345 + drawtabs(); | |
346 break; | |
347 } | |
348 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWM… | |
349 updatetitle(c); | |
350 if (c == c->mon->sel) | |
351 drawbar(c->mon); | |
352 + drawtab(c->mon); | |
353 } | |
354 if (ev->atom == netatom[NetWMWindowType]) | |
355 updatewindowtype(c); | |
356 @@ -1353,6 +1456,7 @@ restack(Monitor *m) | |
357 XWindowChanges wc; | |
358 | |
359 drawbar(m); | |
360 + drawtab(m); | |
361 if (!m->sel) | |
362 return; | |
363 if (m->sel->isfloating || !m->lt[m->sellt]->arrange) | |
364 @@ -1547,6 +1651,7 @@ setup(void) | |
365 die("no fonts could be loaded."); | |
366 lrpad = drw->fonts->h; | |
367 bh = drw->fonts->h + 2; | |
368 + th = bh; | |
369 updategeom(); | |
370 /* init atoms */ | |
371 utf8string = XInternAtom(dpy, "UTF8_STRING", False); | |
372 @@ -1708,6 +1813,17 @@ togglebar(const Arg *arg) | |
373 arrange(selmon); | |
374 } | |
375 | |
376 +void | |
377 +tabmode(const Arg *arg) | |
378 +{ | |
379 + if(arg && arg->i >= 0) | |
380 + selmon->showtab = arg->ui % showtab_nmodes; | |
381 + else | |
382 + selmon->showtab = (selmon->showtab + 1 ) % showtab_nmod… | |
383 + arrange(selmon); | |
384 +} | |
385 + | |
386 + | |
387 void | |
388 togglefloating(const Arg *arg) | |
389 { | |
390 @@ -1819,6 +1935,11 @@ updatebars(void) | |
391 CWOverrideRedirect|CWBackPixmap|CWEvent… | |
392 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor… | |
393 XMapRaised(dpy, m->barwin); | |
394 + m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->w… | |
395 + CopyFromParent, Default… | |
396 + CWOverrideRedirect|CWBa… | |
397 + XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor… | |
398 + XMapRaised(dpy, m->tabwin); | |
399 XSetClassHint(dpy, m->barwin, &ch); | |
400 } | |
401 } | |
402 @@ -1826,14 +1947,33 @@ updatebars(void) | |
403 void | |
404 updatebarpos(Monitor *m) | |
405 { | |
406 + Client *c; | |
407 + int nvis = 0; | |
408 + | |
409 m->wy = m->my; | |
410 m->wh = m->mh; | |
411 if (m->showbar) { | |
412 m->wh -= bh; | |
413 m->by = m->topbar ? m->wy : m->wy + m->wh; | |
414 - m->wy = m->topbar ? m->wy + bh : m->wy; | |
415 - } else | |
416 + if ( m->topbar ) | |
417 + m->wy += bh; | |
418 + } else { | |
419 m->by = -bh; | |
420 + } | |
421 + | |
422 + for(c = m->clients; c; c = c->next) { | |
423 + if(ISVISIBLE(c)) ++nvis; | |
424 + } | |
425 + | |
426 + if(m->showtab == showtab_always | |
427 + || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->… | |
428 + m->wh -= th; | |
429 + m->ty = m->toptab ? m->wy : m->wy + m->wh; | |
430 + if ( m->toptab ) | |
431 + m->wy += th; | |
432 + } else { | |
433 + m->ty = -th; | |
434 + } | |
435 } | |
436 | |
437 void | |
438 @@ -2070,7 +2210,7 @@ wintomon(Window w) | |
439 if (w == root && getrootptr(&x, &y)) | |
440 return recttomon(x, y, 1, 1); | |
441 for (m = mons; m; m = m->next) | |
442 - if (w == m->barwin) | |
443 + if (w == m->barwin || w == m->tabwin) | |
444 return m; | |
445 if ((c = wintoclient(w))) | |
446 return c->mon; | |
447 -- | |
448 2.34.0 | |
449 |