dwm-integrated-status-text-6.3.diff - sites - public wiki contents of suckless.… | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-integrated-status-text-6.3.diff (16210B) | |
--- | |
1 From 02f1f07ee4460787c971bd28e934cb5fc319253d Mon Sep 17 00:00:00 2001 | |
2 From: explosion-mental <[email protected]> | |
3 Date: Thu, 26 May 2022 22:34:14 -0500 | |
4 Subject: [PATCH] [PATCH] Allows dwm to handle the text by itself. You can | |
5 think of it like a dwmblocks integration into dwm itself. This is extra… | |
6 from my dwm build[0] in which you can find even more information. | |
7 | |
8 Example: | |
9 ``` | |
10 /* fg command interval signal */ | |
11 { "#000000", "echo 'dwm block!", 10, 3}, | |
12 ``` | |
13 | |
14 - fg: the foreground color of the individual block, for the background it | |
15 uses the bg of SchemeStatus. | |
16 | |
17 - command: it uses the output of the commands for the status text | |
18 interval: in seconds, how much does it have to pass before updating the | |
19 block. | |
20 | |
21 - interval: in seconds, how many seconds until the block it's updated | |
22 | |
23 - signal: have to be less than 30. This lets you update the block with | |
24 `kill` by adding 35 to this value. | |
25 For the block above it would be 34 + 3 = 37 -> `kill -37 $(pidof dwm)`. | |
26 These signals are linux dependant. | |
27 | |
28 You can change `$(pidof dwm)` with `$STATUSBAR` to 'fix' signaling | |
29 multiple instances of dwm, since this patch also wraps the PID of dwm | |
30 into the `$STATUSBAR` enviromental variable. | |
31 | |
32 Last thing, mouse actions. For this you need to handle the env variable | |
33 `$BLOCK_BUTTON` in a script, this is so you can easily reuse the scripts | |
34 used in dwmblocks. And remember that mouse actions update the block. | |
35 | |
36 [0] https://github.com/explosion-mental/Dwm or | |
37 https://codeberg.org/explosion-mental/Dwm | |
38 --- | |
39 config.def.h | 39 ++++++- | |
40 dwm.c | 298 +++++++++++++++++++++++++++++++++++++++++++++++---- | |
41 2 files changed, 318 insertions(+), 19 deletions(-) | |
42 | |
43 diff --git a/config.def.h b/config.def.h | |
44 index a2ac963..cad178c 100644 | |
45 --- a/config.def.h | |
46 +++ b/config.def.h | |
47 @@ -16,8 +16,38 @@ static const char *colors[][3] = { | |
48 /* fg bg border */ | |
49 [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, | |
50 [SchemeSel] = { col_gray4, col_cyan, col_cyan }, | |
51 + [SchemeStatus]={ col_cyan, col_gray1, NULL }, | |
52 }; | |
53 | |
54 + | |
55 +/* status bar */ | |
56 +static const Block blocks[] = { | |
57 + /* fg command interval … | |
58 + { col_gray3, "sb-clock", 20, … | |
59 + { col_gray1, "sb-disk", 9000, … | |
60 + { col_gray2, "sb-battery", 10, … | |
61 + { col_gray3, "sb-internet", 10, … | |
62 + { col_cyan, "sb-mailbox", 0, … | |
63 + { "#000001", "sb-moonphase", 0, … | |
64 + { "#1F0077", "sb-forecast", 0, … | |
65 + { "#000077", "sb-volume", 0, … | |
66 + { "#F77000", "sb-pacpackages", 0, … | |
67 + { "#177000", "sb-sync", 0, … | |
68 +// { col_gray1, "sb-mpc", 0, … | |
69 + { col_gray2, "sb-music", 0, … | |
70 +// { col_gray3, "sb-tasks", 10, … | |
71 + { col_gray4, "sb-notes", 0, … | |
72 + { col_cyan, "echo '';cat /tmp/recordingicon", 0, … | |
73 +}; | |
74 + | |
75 +/* inverse the order of the blocks, comment to disable */ | |
76 +#define INVERSED 1 | |
77 +/* delimeter between blocks commands. NULL character ('\0') means no de… | |
78 +static char delimiter[] = " "; | |
79 +/* max number of character that one block command can output */ | |
80 +#define CMDLENGTH 50 | |
81 + | |
82 + | |
83 /* tagging */ | |
84 static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "… | |
85 | |
86 @@ -104,7 +134,14 @@ static Button buttons[] = { | |
87 { ClkLtSymbol, 0, Button1, setlayo… | |
88 { ClkLtSymbol, 0, Button3, setlayo… | |
89 { ClkWinTitle, 0, Button2, zoom, … | |
90 - { ClkStatusText, 0, Button2, spawn, … | |
91 + | |
92 + { ClkStatusText, 0, Button1, sendsta… | |
93 + { ClkStatusText, 0, Button2, sendsta… | |
94 + { ClkStatusText, 0, Button3, sendsta… | |
95 + { ClkStatusText, 0, Button4, sendsta… | |
96 + { ClkStatusText, 0, Button5, sendsta… | |
97 + { ClkStatusText, ShiftMask, Button1, sendsta… | |
98 + | |
99 { ClkClientWin, MODKEY, Button1, movemou… | |
100 { ClkClientWin, MODKEY, Button2, togglef… | |
101 { ClkClientWin, MODKEY, Button3, resizem… | |
102 diff --git a/dwm.c b/dwm.c | |
103 index a96f33c..5789f72 100644 | |
104 --- a/dwm.c | |
105 +++ b/dwm.c | |
106 @@ -28,6 +28,7 @@ | |
107 #include <stdlib.h> | |
108 #include <string.h> | |
109 #include <unistd.h> | |
110 +#include <poll.h> | |
111 #include <sys/types.h> | |
112 #include <sys/wait.h> | |
113 #include <X11/cursorfont.h> | |
114 @@ -59,7 +60,7 @@ | |
115 | |
116 /* enums */ | |
117 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |
118 -enum { SchemeNorm, SchemeSel }; /* color schemes */ | |
119 +enum { SchemeNorm, SchemeSel, SchemeStatus }; /* color schemes */ | |
120 enum { NetSupported, NetWMName, NetWMState, NetWMCheck, | |
121 NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |
122 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | |
123 @@ -141,6 +142,13 @@ typedef struct { | |
124 int monitor; | |
125 } Rule; | |
126 | |
127 +typedef struct { | |
128 + const char *color; | |
129 + const char *command; | |
130 + const unsigned int interval; | |
131 + const unsigned int signal; | |
132 +} Block; | |
133 + | |
134 /* function declarations */ | |
135 static void applyrules(Client *c); | |
136 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, in… | |
137 @@ -172,6 +180,11 @@ static void focusstack(const Arg *arg); | |
138 static Atom getatomprop(Client *c, Atom prop); | |
139 static int getrootptr(int *x, int *y); | |
140 static long getstate(Window w); | |
141 +static void getcmd(int i, char *button); | |
142 +static void getcmds(int time); | |
143 +static void getsigcmds(int signal); | |
144 +static int gcd(int a, int b); | |
145 +static int getstatus(int width); | |
146 static int gettextprop(Window w, Atom atom, char *text, unsigned int si… | |
147 static void grabbuttons(Client *c, int focused); | |
148 static void grabkeys(void); | |
149 @@ -197,14 +210,17 @@ static void run(void); | |
150 static void scan(void); | |
151 static int sendevent(Client *c, Atom proto); | |
152 static void sendmon(Client *c, Monitor *m); | |
153 +static void sendstatusbar(const Arg *arg); | |
154 static void setclientstate(Client *c, long state); | |
155 static void setfocus(Client *c); | |
156 static void setfullscreen(Client *c, int fullscreen); | |
157 static void setlayout(const Arg *arg); | |
158 static void setmfact(const Arg *arg); | |
159 static void setup(void); | |
160 +static void setsignal(int sig, void (*handler)(int sig)); | |
161 static void seturgent(Client *c, int urg); | |
162 static void showhide(Client *c); | |
163 +static void sigalrm(int unused); | |
164 static void sigchld(int unused); | |
165 static void spawn(const Arg *arg); | |
166 static void tag(const Arg *arg); | |
167 @@ -237,13 +253,16 @@ static void zoom(const Arg *arg); | |
168 | |
169 /* variables */ | |
170 static const char broken[] = "broken"; | |
171 -static char stext[256]; | |
172 static int screen; | |
173 static int sw, sh; /* X display screen geometry width, height… | |
174 static int bh, blw = 0; /* bar geometry */ | |
175 static int lrpad; /* sum of left and right padding for text … | |
176 static int (*xerrorxlib)(Display *, XErrorEvent *); | |
177 +static unsigned int blocknum; /* blocks idx in mouse click */ | |
178 +static unsigned int stsw = 0; /* status width */ | |
179 static unsigned int numlockmask = 0; | |
180 +static unsigned int sleepinterval = 0, maxinterval = 0, count = 0; | |
181 +static unsigned int execlock = 0; /* ensure only one child process exis… | |
182 static void (*handler[LASTEvent]) (XEvent *) = { | |
183 [ButtonPress] = buttonpress, | |
184 [ClientMessage] = clientmessage, | |
185 @@ -272,6 +291,9 @@ static Window root, wmcheckwin; | |
186 /* configuration, allows nested code to access above variables */ | |
187 #include "config.h" | |
188 | |
189 +static char blockoutput[LENGTH(blocks)][CMDLENGTH + 1] = {0}; | |
190 +static int pipes[LENGTH(blocks)][2]; | |
191 + | |
192 /* compile-time check if all tags fit into an unsigned int bit array. */ | |
193 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; | |
194 | |
195 @@ -440,9 +462,26 @@ buttonpress(XEvent *e) | |
196 arg.ui = 1 << i; | |
197 } else if (ev->x < x + blw) | |
198 click = ClkLtSymbol; | |
199 - else if (ev->x > selmon->ww - (int)TEXTW(stext)) | |
200 + else if (ev->x > (x = selmon->ww - stsw)) { | |
201 click = ClkStatusText; | |
202 - else | |
203 + int len, i; | |
204 + | |
205 + #if INVERSED | |
206 + for (i = LENGTH(blocks) - 1; i >= 0; i--) | |
207 + #else | |
208 + for (i = 0; i < LENGTH(blocks); i++) | |
209 + #endif /* INVERSED */ | |
210 + { | |
211 + if (*blockoutput[i] == '\0') /* ignore … | |
212 + continue; | |
213 + len = TEXTW(blockoutput[i]) - lrpad + T… | |
214 + x += len; | |
215 + if (ev->x <= x && ev->x >= x - len) { /… | |
216 + blocknum = i; /* store what blo… | |
217 + break; | |
218 + } | |
219 + } | |
220 + } else | |
221 click = ClkWinTitle; | |
222 } else if ((c = wintoclient(ev->window))) { | |
223 focus(c); | |
224 @@ -706,11 +745,8 @@ drawbar(Monitor *m) | |
225 return; | |
226 | |
227 /* draw status first so it can be overdrawn by tags later */ | |
228 - if (m == selmon) { /* status is only drawn on selected monitor … | |
229 - drw_setscheme(drw, scheme[SchemeNorm]); | |
230 - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ | |
231 - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); | |
232 - } | |
233 + if (m == selmon) /* status is only drawn on selected monitor */ | |
234 + tw = getstatus(m->ww); | |
235 | |
236 for (c = m->clients; c; c = c->next) { | |
237 occ |= c->tags; | |
238 @@ -903,6 +939,106 @@ getstate(Window w) | |
239 return result; | |
240 } | |
241 | |
242 +void | |
243 +getcmd(int i, char *button) | |
244 +{ | |
245 + if (!selmon->showbar) | |
246 + return; | |
247 + | |
248 + if (execlock & 1 << i) { /* block is already running */ | |
249 + //fprintf(stderr, "dwm: ignoring block %d, command %s\n… | |
250 + return; | |
251 + } | |
252 + | |
253 + /* lock execution of block until current instance finishes exec… | |
254 + execlock |= 1 << i; | |
255 + | |
256 + if (fork() == 0) { | |
257 + if (dpy) | |
258 + close(ConnectionNumber(dpy)); | |
259 + dup2(pipes[i][1], STDOUT_FILENO); | |
260 + close(pipes[i][0]); | |
261 + close(pipes[i][1]); | |
262 + | |
263 + if (button) | |
264 + setenv("BLOCK_BUTTON", button, 1); | |
265 + execlp("/bin/sh", "sh", "-c", blocks[i].command, (char … | |
266 + fprintf(stderr, "dwm: block %d, execlp %s", i, blocks[i… | |
267 + perror(" failed"); | |
268 + exit(EXIT_SUCCESS); | |
269 + } | |
270 +} | |
271 + | |
272 +void | |
273 +getcmds(int time) | |
274 +{ | |
275 + int i; | |
276 + for (i = 0; i < LENGTH(blocks); i++) | |
277 + if ((blocks[i].interval != 0 && time % blocks[i].interv… | |
278 + getcmd(i, NULL); | |
279 +} | |
280 + | |
281 +void | |
282 +getsigcmds(int signal) | |
283 +{ | |
284 + int i; | |
285 + unsigned int sig = signal - SIGRTMIN; | |
286 + for (i = 0; i < LENGTH(blocks); i++) | |
287 + if (blocks[i].signal == sig) | |
288 + getcmd(i, NULL); | |
289 +} | |
290 + | |
291 +int | |
292 +getstatus(int width) | |
293 +{ | |
294 + int i, len, all = width, delimlen = TEXTW(delimiter) - lrpad; | |
295 + char fgcol[8]; | |
296 + /* fg bg */ | |
297 + const char *cols[8] = { fgcol, colors[SchemeStatus][Col… | |
298 + //uncomment to inverse the colors | |
299 + //const char *cols[8] = { colors[SchemeStatus][ColBg], … | |
300 + | |
301 + #if INVERSED | |
302 + for (i = 0; i < LENGTH(blocks); i++) | |
303 + #else | |
304 + for (i = LENGTH(blocks) - 1; i >= 0; i--) | |
305 + #endif /* INVERSED */ | |
306 + { | |
307 + if (*blockoutput[i] == '\0') /* ignore command that out… | |
308 + continue; | |
309 + strncpy(fgcol, blocks[i].color, 8); | |
310 + /* re-load the scheme with the new colors */ | |
311 + scheme[SchemeStatus] = drw_scm_create(drw, cols, 3); | |
312 + drw_setscheme(drw, scheme[SchemeStatus]); /* 're-set' t… | |
313 + len = TEXTW(blockoutput[i]) - lrpad; | |
314 + all -= len; | |
315 + drw_text(drw, all, 0, len, bh, 0, blockoutput[i], 0); | |
316 + /* draw delimiter */ | |
317 + if (*delimiter == '\0') /* ignore no delimiter */ | |
318 + continue; | |
319 + drw_setscheme(drw, scheme[SchemeNorm]); | |
320 + all -= delimlen; | |
321 + drw_text(drw, all, 0, delimlen, bh, 0, delimiter, 0); | |
322 + } | |
323 + | |
324 + return stsw = width - all; | |
325 +} | |
326 + | |
327 +int | |
328 +gcd(int a, int b) | |
329 +{ | |
330 + int temp; | |
331 + | |
332 + while (b > 0) { | |
333 + temp = a % b; | |
334 + a = b; | |
335 + b = temp; | |
336 + } | |
337 + | |
338 + return a; | |
339 +} | |
340 + | |
341 + | |
342 int | |
343 gettextprop(Window w, Atom atom, char *text, unsigned int size) | |
344 { | |
345 @@ -1376,12 +1512,99 @@ restack(Monitor *m) | |
346 void | |
347 run(void) | |
348 { | |
349 + int i; | |
350 XEvent ev; | |
351 + struct pollfd fds[LENGTH(blocks) + 1] = {0}; | |
352 + | |
353 + fds[0].fd = ConnectionNumber(dpy); | |
354 + fds[0].events = POLLIN; | |
355 + | |
356 + #if INVERSED | |
357 + for (i = LENGTH(blocks) - 1; i >= 0; i--) | |
358 + #else | |
359 + for (i = 0; i < LENGTH(blocks); i++) | |
360 + #endif /* INVERSED */ | |
361 + { | |
362 + pipe(pipes[i]); | |
363 + fds[i + 1].fd = pipes[i][0]; | |
364 + fds[i + 1].events = POLLIN; | |
365 + getcmd(i, NULL); | |
366 + if (blocks[i].interval) { | |
367 + maxinterval = MAX(blocks[i].interval, maxinterv… | |
368 + sleepinterval = gcd(blocks[i].interval, sleepin… | |
369 + } | |
370 + } | |
371 + | |
372 + alarm(sleepinterval); | |
373 /* main event loop */ | |
374 XSync(dpy, False); | |
375 - while (running && !XNextEvent(dpy, &ev)) | |
376 - if (handler[ev.type]) | |
377 - handler[ev.type](&ev); /* call handler */ | |
378 + while (running) { | |
379 + | |
380 + /* bar hidden, then skip poll */ | |
381 + if (!selmon->showbar) { | |
382 + XNextEvent(dpy, &ev); | |
383 + if (handler[ev.type]) | |
384 + handler[ev.type](&ev); /* call handler … | |
385 + continue; | |
386 + } | |
387 + | |
388 + if ((poll(fds, LENGTH(blocks) + 1, -1)) == -1) { | |
389 + /* FIXME other than SIGALRM and the real time s… | |
390 + * there seems to be a signal being que if using | |
391 + * 'xsetroot -name' sutff */ | |
392 + if (errno == EINTR) /* signal caught */ | |
393 + continue; | |
394 + fprintf(stderr, "dwm: poll "); | |
395 + perror("failed"); | |
396 + exit(EXIT_FAILURE); | |
397 + } | |
398 + | |
399 + /* handle display fd */ | |
400 + if (fds[0].revents & POLLIN) { | |
401 + while (running && XPending(dpy)) { | |
402 + XNextEvent(dpy, &ev); | |
403 + if (handler[ev.type]) | |
404 + handler[ev.type](&ev); /* call … | |
405 + } | |
406 + } else if (fds[0].revents & POLLHUP) { | |
407 + fprintf(stderr, "dwm: main event loop, hang up"… | |
408 + perror(" failed"); | |
409 + exit(EXIT_FAILURE); | |
410 + } | |
411 + | |
412 + /* handle blocks */ | |
413 + for (i = 0; i < LENGTH(blocks); i++) { | |
414 + if (fds[i + 1].revents & POLLIN) { | |
415 + /* empty buffer with CMDLENGTH + 1 byte… | |
416 + int bt = read(fds[i + 1].fd, blockoutpu… | |
417 + /* remove lock for the current block */ | |
418 + execlock &= ~(1 << i); | |
419 + | |
420 + if (bt == -1) { /* if read failed */ | |
421 + fprintf(stderr, "dwm: read fail… | |
422 + perror(" failed"); | |
423 + continue; | |
424 + } | |
425 + | |
426 + if (blockoutput[i][bt - 1] == '\n') /* … | |
427 + blockoutput[i][bt - 1] = '\0'; | |
428 + else /* NULL terminate the string */ | |
429 + blockoutput[i][bt++] = '\0'; | |
430 + | |
431 + drawbar(selmon); | |
432 + } else if (fds[i + 1].revents & POLLHUP) { | |
433 + fprintf(stderr, "dwm: block %d hangup",… | |
434 + perror(" failed"); | |
435 + exit(EXIT_FAILURE); | |
436 + } | |
437 + } | |
438 + } | |
439 + | |
440 + /* close the pipes after running */ | |
441 + for (i = 0; i < LENGTH(blocks); i++) { | |
442 + close(pipes[i][0]); | |
443 + close(pipes[i][1]); | |
444 + } | |
445 } | |
446 | |
447 void | |
448 @@ -1427,6 +1650,13 @@ sendmon(Client *c, Monitor *m) | |
449 arrange(NULL); | |
450 } | |
451 | |
452 +void | |
453 +sendstatusbar(const Arg *arg) | |
454 +{ | |
455 + char button[2] = { '0' + arg->i & 0xff, '\0' }; | |
456 + getcmd(blocknum, button); | |
457 +} | |
458 + | |
459 void | |
460 setclientstate(Client *c, long state) | |
461 { | |
462 @@ -1537,8 +1767,20 @@ setup(void) | |
463 XSetWindowAttributes wa; | |
464 Atom utf8string; | |
465 | |
466 - /* clean up any zombies immediately */ | |
467 - sigchld(0); | |
468 + setsignal(SIGCHLD, sigchld); /* zombies */ | |
469 + setsignal(SIGALRM, sigalrm); /* timer */ | |
470 + | |
471 + #ifdef __linux__ | |
472 + /* handle defined real time signals (linux only) */ | |
473 + for (i = 0; i < LENGTH(blocks); i++) | |
474 + if (blocks[i].signal) | |
475 + setsignal(SIGRTMIN + blocks[i].signal, getsigcm… | |
476 + #endif /* __linux__ */ | |
477 + | |
478 + /* pid as an enviromental variable */ | |
479 + char envpid[16]; | |
480 + snprintf(envpid, LENGTH(envpid), "%d", getpid()); | |
481 + setenv("STATUSBAR", envpid, 1); | |
482 | |
483 /* init screen */ | |
484 screen = DefaultScreen(dpy); | |
485 @@ -1600,6 +1842,21 @@ setup(void) | |
486 focus(NULL); | |
487 } | |
488 | |
489 +void | |
490 +setsignal(int sig, void (*handler)(int unused)) | |
491 +{ | |
492 + struct sigaction sa; | |
493 + | |
494 + sa.sa_handler = handler; | |
495 + sigemptyset(&sa.sa_mask); | |
496 + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; | |
497 + | |
498 + if (sigaction(sig, &sa, 0) == -1) { | |
499 + fprintf(stderr, "signal %d ", sig); | |
500 + perror("failed to setup"); | |
501 + exit(EXIT_FAILURE); | |
502 + } | |
503 +} | |
504 | |
505 void | |
506 seturgent(Client *c, int urg) | |
507 @@ -1632,11 +1889,18 @@ showhide(Client *c) | |
508 } | |
509 } | |
510 | |
511 + | |
512 +void | |
513 +sigalrm(int unused) | |
514 +{ | |
515 + getcmds(count); | |
516 + alarm(sleepinterval); | |
517 + count = (count + sleepinterval - 1) % maxinterval + 1; | |
518 +} | |
519 + | |
520 void | |
521 sigchld(int unused) | |
522 { | |
523 - if (signal(SIGCHLD, sigchld) == SIG_ERR) | |
524 - die("can't install SIGCHLD handler:"); | |
525 while (0 < waitpid(-1, NULL, WNOHANG)); | |
526 } | |
527 | |
528 @@ -1993,8 +2257,6 @@ updatesizehints(Client *c) | |
529 void | |
530 updatestatus(void) | |
531 { | |
532 - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) | |
533 - strcpy(stext, "dwm-"VERSION); | |
534 drawbar(selmon); | |
535 } | |
536 | |
537 -- | |
538 2.36.1 | |
539 |