sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 6d161b55f4cd0079d0d2353728979e9762f24ee1
parent 50bf11b82adb1f64500fe611bdc901d6380c04a4
Author: Daniel Bylinka <daniel.bylinka@gmail.com>
Date:   Fri,  2 Apr 2021 19:44:36 +0200

[dwm][patch][statuscmd] Add various tweaks, fixes and updates

The signal version is now the default and the dwmblocks patch is now up
to date and forks the commands it runs.

The signal-less version is now simpler to use because it now uses an
array of command and number pairs instead of relying on the correct
index being specified.

There are also compatibility patches for status2d now.

Diffstat:
Adwm.suckless.org/patches/statuscmd/dwm-statuscmd-20210402-67d76bd.diff | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddwm.suckless.org/patches/statuscmd/dwm-statuscmd-6.2.diff | 142-------------------------------------------------------------------------------
Adwm.suckless.org/patches/statuscmd/dwm-statuscmd-nosignal-20210402-67d76bd.diff | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/statuscmd/dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddwm.suckless.org/patches/statuscmd/dwm-statuscmd-signal-6.2.diff | 157-------------------------------------------------------------------------------
Adwm.suckless.org/patches/statuscmd/dwm-statuscmd-status2d-20210402-60bb3df.diff | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/statuscmd/dwmblocks-statuscmd-20210402-96cbb45.diff | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddwm.suckless.org/patches/statuscmd/dwmblocks-statuscmd.diff | 80-------------------------------------------------------------------------------
Mdwm.suckless.org/patches/statuscmd/index.md | 114+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
9 files changed, 933 insertions(+), 419 deletions(-)

diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-20210402-67d76bd.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-20210402-67d76bd.diff @@ -0,0 +1,207 @@ +From bac80422bffa972ea300b52f51436f772188cbbd Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Fri, 2 Apr 2021 19:02:58 +0200 +Subject: [PATCH] [statuscmd] Signal mouse button and click location to status + monitor + +--- + config.def.h | 6 +++- + dwm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 99 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..154a59b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -54,6 +54,8 @@ static const Layout layouts[] = { + /* helper for spawning shell commands in the pre dwm-5.0 fashion */ + #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + ++#define STATUSBAR "dwmblocks" ++ + /* commands */ + static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ + static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +@@ -103,7 +105,9 @@ static Button buttons[] = { + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, +- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++ { ClkStatusText, 0, Button1, sigstatusbar, {.i = 1} }, ++ { ClkStatusText, 0, Button2, sigstatusbar, {.i = 2} }, ++ { ClkStatusText, 0, Button3, sigstatusbar, {.i = 3} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index b0b3466..cf2550a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -172,6 +172,7 @@ static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static pid_t getstatusbarpid(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -206,6 +207,7 @@ static void setup(void); + static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); ++static void sigstatusbar(const Arg *arg); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); +@@ -238,6 +240,9 @@ static void zoom(const Arg *arg); + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; ++static int statusw; ++static int statussig; ++static pid_t statuspid = -1; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -422,6 +427,7 @@ buttonpress(XEvent *e) + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; ++ char *text, *s, ch; + + click = ClkRootWin; + /* focus monitor if necessary */ +@@ -440,9 +446,23 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - statusw) { ++ x = selmon->ww - statusw; + click = ClkStatusText; +- else ++ statussig = 0; ++ for (text = s = stext; *s && x <= ev->x; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ x += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ if (x >= ev->x) ++ break; ++ statussig = ch; ++ } ++ } ++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); +@@ -704,9 +724,24 @@ drawbar(Monitor *m) + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ ++ char *text, *s, ch; + drw_setscheme(drw, scheme[SchemeNorm]); +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ ++ x = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ tw = TEXTW(text) - lrpad; ++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); ++ x += tw; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ tw = TEXTW(text) - lrpad + 2; ++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); ++ tw = statusw; + } + + for (c = m->clients; c; c = c->next) { +@@ -872,6 +907,29 @@ getatomprop(Client *c, Atom prop) + return atom; + } + ++pid_t ++getstatusbarpid() ++{ ++ char buf[32], *str = buf, *c; ++ FILE *fp; ++ ++ if (statuspid > 0) { ++ snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid); ++ if ((fp = fopen(buf, "r"))) { ++ fgets(buf, sizeof(buf), fp); ++ while ((c = strchr(str, '/'))) ++ str = c + 1; ++ fclose(fp); ++ if (!strcmp(str, STATUSBAR)) ++ return statuspid; ++ } ++ } ++ if (!(fp = popen("pidof -s "STATUSBAR, "r"))) ++ return -1; ++ fgets(buf, sizeof(buf), fp); ++ return pclose(fp) == 0 ? strtol(buf, NULL, 10) : -1; ++} ++ + int + getrootptr(int *x, int *y) + { +@@ -1637,6 +1695,20 @@ sigchld(int unused) + while (0 < waitpid(-1, NULL, WNOHANG)); + } + ++void ++sigstatusbar(const Arg *arg) ++{ ++ union sigval sv; ++ ++ if (!statussig) ++ return; ++ sv.sival_int = arg->i; ++ if ((statuspid = getstatusbarpid()) < 0) ++ return; ++ ++ sigqueue(statuspid, SIGRTMIN+statussig, sv); ++} ++ + void + spawn(const Arg *arg) + { +@@ -1990,8 +2062,25 @@ updatesizehints(Client *c) + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { + strcpy(stext, "dwm-"VERSION); ++ statusw = TEXTW(stext) - lrpad + 2; ++ } else { ++ char *text, *s, ch; ++ ++ statusw = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ statusw += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ statusw += TEXTW(text) - lrpad + 2; ++ ++ } + drawbar(selmon); + } + +-- +2.31.0 + diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-6.2.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-6.2.diff @@ -1,142 +0,0 @@ -From 2761ad72b4b8a80e434e7eba1a24676119ab666d Mon Sep 17 00:00:00 2001 -From: Daniel Bylinka <daniel.bylinka@gmail.com> -Date: Sat, 18 Apr 2020 01:41:03 +0200 -Subject: [PATCH] statuscmd: run shell commands based on mouse button and - position when clicking statusbar - ---- - config.def.h | 8 +++++++- - dwm.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- - 2 files changed, 51 insertions(+), 4 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 1c0b587..5cd7efa 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -59,6 +59,10 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() - static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; - static const char *termcmd[] = { "st", NULL }; - -+/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */ -+static char *statuscmds[] = { "notify-send Mouse$BUTTON" }; -+static char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL }; -+ - static Key keys[] = { - /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, -@@ -103,7 +107,9 @@ static Button buttons[] = { - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, - { ClkWinTitle, 0, Button2, zoom, {0} }, -- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, -+ { ClkStatusText, 0, Button1, spawn, {.v = statuscmd } }, -+ { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } }, -+ { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } }, - { ClkClientWin, MODKEY, Button1, movemouse, {0} }, - { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, - { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, -diff --git a/dwm.c b/dwm.c -index 4465af1..d35d173 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -156,6 +156,7 @@ static void clientmessage(XEvent *e); - static void configure(Client *c); - static void configurenotify(XEvent *e); - static void configurerequest(XEvent *e); -+static void copyvalidchars(char *text, char *rawtext); - static Monitor *createmon(void); - static void destroynotify(XEvent *e); - static void detach(Client *c); -@@ -237,6 +238,9 @@ static void zoom(const Arg *arg); - /* variables */ - static const char broken[] = "broken"; - static char stext[256]; -+static char rawstext[256]; -+static int statuscmdn; -+static char lastbutton[] = "-"; - static int screen; - static int sw, sh; /* X display screen geometry width, height */ - static int bh, blw = 0; /* bar geometry */ -@@ -421,6 +425,7 @@ buttonpress(XEvent *e) - Client *c; - Monitor *m; - XButtonPressedEvent *ev = &e->xbutton; -+ *lastbutton = '0' + ev->button; - - click = ClkRootWin; - /* focus monitor if necessary */ -@@ -439,9 +444,26 @@ buttonpress(XEvent *e) - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - TEXTW(stext)) -+ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad)) { - click = ClkStatusText; -- else -+ -+ char *text = rawstext; -+ int i = -1; -+ char ch; -+ statuscmdn = 0; -+ while (text[++i]) { -+ if ((unsigned char)text[i] < ' ') { -+ ch = text[i]; -+ text[i] = '\0'; -+ x += TEXTW(text) - lrpad; -+ text[i] = ch; -+ text += i+1; -+ i = -1; -+ if (x >= ev->x) break; -+ if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; -+ } -+ } -+ } else - click = ClkWinTitle; - } else if ((c = wintoclient(ev->window))) { - focus(c); -@@ -627,6 +649,19 @@ configurerequest(XEvent *e) - XSync(dpy, False); - } - -+void -+copyvalidchars(char *text, char *rawtext) -+{ -+ int i = -1, j = 0; -+ -+ while(rawtext[++i]) { -+ if ((unsigned char)rawtext[i] >= ' ') { -+ text[j++] = rawtext[i]; -+ } -+ } -+ text[j] = '\0'; -+} -+ - Monitor * - createmon(void) - { -@@ -1641,6 +1676,10 @@ spawn(const Arg *arg) - { - if (arg->v == dmenucmd) - dmenumon[0] = '0' + selmon->num; -+ else if (arg->v == statuscmd) { -+ statuscmd[2] = statuscmds[statuscmdn]; -+ setenv("BUTTON", lastbutton, 1); -+ } - if (fork() == 0) { - if (dpy) - close(ConnectionNumber(dpy)); -@@ -1987,8 +2026,10 @@ updatesizehints(Client *c) - void - updatestatus(void) - { -- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) -+ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) - strcpy(stext, "dwm-"VERSION); -+ else -+ copyvalidchars(stext, rawstext); - drawbar(selmon); - } - --- -2.26.1 - diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-nosignal-20210402-67d76bd.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-nosignal-20210402-67d76bd.diff @@ -0,0 +1,167 @@ +From 02c4a28dd7f3a88eef3a4e533ace35f79cf09d57 Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Fri, 2 Apr 2021 19:34:38 +0200 +Subject: [PATCH] [statuscmd] Run shell commands based on mouse location and + button + +--- + config.def.h | 10 ++++++- + dwm.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 81 insertions(+), 5 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..8f88366 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -59,6 +59,12 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() + static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; + static const char *termcmd[] = { "st", NULL }; + ++/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */ ++static const StatusCmd statuscmds[] = { ++ { "notify-send Mouse$BUTTON", 1 }, ++}; ++static const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL }; ++ + static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +@@ -103,7 +109,9 @@ static Button buttons[] = { + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, +- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++ { ClkStatusText, 0, Button1, spawn, {.v = statuscmd } }, ++ { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } }, ++ { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index b0b3466..eb478a5 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -141,6 +141,11 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct { ++ const char *cmd; ++ int id; ++} StatusCmd; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -238,6 +243,9 @@ static void zoom(const Arg *arg); + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; ++static int statusw; ++static int statuscmdn; ++static char lastbutton[] = "-"; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -440,8 +448,27 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - statusw) { ++ char *text, *s, ch; ++ *lastbutton = '0' + ev->button; ++ ++ x = selmon->ww - statusw; + click = ClkStatusText; ++ ++ statuscmdn = 0; ++ for (text = s = stext; *s && x <= ev->x; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ x += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ if (x >= ev->x) ++ break; ++ statuscmdn = ch; ++ } ++ } ++ } + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { +@@ -704,9 +731,24 @@ drawbar(Monitor *m) + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ ++ char *text, *s, ch; + drw_setscheme(drw, scheme[SchemeNorm]); +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ ++ x = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ tw = TEXTW(text) - lrpad; ++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); ++ x += tw; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ tw = TEXTW(text) - lrpad + 2; ++ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); ++ tw = statusw; + } + + for (c = m->clients; c; c = c->next) { +@@ -1645,6 +1687,17 @@ spawn(const Arg *arg) + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); ++ if (arg->v == statuscmd) { ++ for (int i = 0; i < LENGTH(statuscmds); i++) { ++ if (statuscmdn == statuscmds[i].id) { ++ statuscmd[2] = statuscmds[i].cmd; ++ setenv("BUTTON", lastbutton, 1); ++ break; ++ } ++ } ++ if (!statuscmd[2]) ++ exit(EXIT_SUCCESS); ++ } + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); +@@ -1990,8 +2043,23 @@ updatesizehints(Client *c) + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { + strcpy(stext, "dwm-"VERSION); ++ statusw = TEXTW(stext) - lrpad + 2; ++ } else { ++ char *text, *s, ch; ++ statusw = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ statusw += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ statusw += TEXTW(text) - lrpad + 2; ++ } + drawbar(selmon); + } + +-- +2.31.0 + diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff @@ -0,0 +1,171 @@ +From df16de3b4457fd6537e6efaa1785183770056ed6 Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Fri, 2 Apr 2021 19:33:35 +0200 +Subject: [PATCH] [statuscmd] status2d compatibility for statuscmd-nosignal + +--- + config.def.h | 10 +++++++- + dwm.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 72 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..8f88366 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -59,6 +59,12 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() + static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; + static const char *termcmd[] = { "st", NULL }; + ++/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */ ++static const StatusCmd statuscmds[] = { ++ { "notify-send Mouse$BUTTON", 1 }, ++}; ++static const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL }; ++ + static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +@@ -103,7 +109,9 @@ static Button buttons[] = { + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, +- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++ { ClkStatusText, 0, Button1, spawn, {.v = statuscmd } }, ++ { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } }, ++ { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index acbe6c9..851b0ed 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -141,6 +141,11 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct { ++ const char *cmd; ++ int id; ++} StatusCmd; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -239,6 +244,9 @@ static void zoom(const Arg *arg); + /* variables */ + static const char broken[] = "broken"; + static char stext[1024]; ++static int statusw; ++static int statuscmdn; ++static char lastbutton[] = "-"; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -441,8 +449,27 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - statusw) { ++ char *text, *s, ch; ++ *lastbutton = '0' + ev->button; ++ ++ x = selmon->ww - statusw; + click = ClkStatusText; ++ ++ statuscmdn = 0; ++ for (text = s = stext; *s && x <= ev->x; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ x += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ if (x >= ev->x) ++ break; ++ statuscmdn = ch; ++ } ++ } ++ } + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { +@@ -696,7 +723,7 @@ dirtomon(int dir) + + int + drawstatusbar(Monitor *m, int bh, char* stext) { +- int ret, i, w, x, len; ++ int ret, i, j, w, x, len; + short isCode = 0; + char *text; + char *p; +@@ -705,7 +732,12 @@ drawstatusbar(Monitor *m, int bh, char* stext) { + if (!(text = (char*) malloc(sizeof(char)*len))) + die("malloc"); + p = text; +- memcpy(text, stext, len); ++ ++ i = -1, j = 0; ++ while (stext[++i]) ++ if ((unsigned char)stext[i] >= ' ') ++ text[j++] = stext[i]; ++ text[j] = '\0'; + + /* compute width of the status text */ + w = 0; +@@ -813,7 +845,7 @@ drawbar(Monitor *m) + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ +- tw = m->ww - drawstatusbar(m, bh, stext); ++ tw = statusw = m->ww - drawstatusbar(m, bh, stext); + } + + for (c = m->clients; c; c = c->next) { +@@ -1753,6 +1785,17 @@ spawn(const Arg *arg) + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); ++ if (arg->v == statuscmd) { ++ for (int i = 0; i < LENGTH(statuscmds); i++) { ++ if (statuscmdn == statuscmds[i].id) { ++ statuscmd[2] = statuscmds[i].cmd; ++ setenv("BUTTON", lastbutton, 1); ++ break; ++ } ++ } ++ if (!statuscmd[2]) ++ exit(EXIT_SUCCESS); ++ } + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); +@@ -2098,8 +2141,23 @@ updatesizehints(Client *c) + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) ++ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { + strcpy(stext, "dwm-"VERSION); ++ statusw = TEXTW(stext) - lrpad + 2; ++ } else { ++ char *text, *s, ch; ++ statusw = 0; ++ for (text = s = stext; *s; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ statusw += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ } ++ } ++ statusw += TEXTW(text) - lrpad + 2; ++ } + drawbar(selmon); + } + +-- +2.31.0 + diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-signal-6.2.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-signal-6.2.diff @@ -1,157 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..b67825e 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -103,7 +103,9 @@ static Button buttons[] = { - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, - { ClkWinTitle, 0, Button2, zoom, {0} }, -- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, -+ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, -+ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, -+ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, - { ClkClientWin, MODKEY, Button1, movemouse, {0} }, - { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, - { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, -diff --git a/dwm.c b/dwm.c -index 4465af1..c600131 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -156,6 +156,7 @@ static void clientmessage(XEvent *e); - static void configure(Client *c); - static void configurenotify(XEvent *e); - static void configurerequest(XEvent *e); -+static void copyvalidchars(char *text, char *rawtext); - static Monitor *createmon(void); - static void destroynotify(XEvent *e); - static void detach(Client *c); -@@ -169,6 +170,7 @@ static void focus(Client *c); - static void focusin(XEvent *e); - static void focusmon(const Arg *arg); - static void focusstack(const Arg *arg); -+static int getdwmblockspid(); - static int getrootptr(int *x, int *y); - static long getstate(Window w); - static int gettextprop(Window w, Atom atom, char *text, unsigned int size); -@@ -205,6 +207,7 @@ static void setup(void); - static void seturgent(Client *c, int urg); - static void showhide(Client *c); - static void sigchld(int unused); -+static void sigdwmblocks(const Arg *arg); - static void spawn(const Arg *arg); - static void tag(const Arg *arg); - static void tagmon(const Arg *arg); -@@ -237,6 +240,9 @@ static void zoom(const Arg *arg); - /* variables */ - static const char broken[] = "broken"; - static char stext[256]; -+static char rawstext[256]; -+static int dwmblockssig; -+pid_t dwmblockspid = 0; - static int screen; - static int sw, sh; /* X display screen geometry width, height */ - static int bh, blw = 0; /* bar geometry */ -@@ -439,9 +445,26 @@ buttonpress(XEvent *e) - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - TEXTW(stext)) -+ else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad)) { - click = ClkStatusText; -- else -+ -+ char *text = rawstext; -+ int i = -1; -+ char ch; -+ dwmblockssig = 0; -+ while (text[++i]) { -+ if ((unsigned char)text[i] < ' ') { -+ ch = text[i]; -+ text[i] = '\0'; -+ x += TEXTW(text) - lrpad; -+ text[i] = ch; -+ text += i+1; -+ i = -1; -+ if (x >= ev->x) break; -+ dwmblockssig = ch; -+ } -+ } -+ } else - click = ClkWinTitle; - } else if ((c = wintoclient(ev->window))) { - focus(c); -@@ -627,6 +650,19 @@ configurerequest(XEvent *e) - XSync(dpy, False); - } - -+void -+copyvalidchars(char *text, char *rawtext) -+{ -+ int i = -1, j = 0; -+ -+ while(rawtext[++i]) { -+ if ((unsigned char)rawtext[i] >= ' ') { -+ text[j++] = rawtext[i]; -+ } -+ } -+ text[j] = '\0'; -+} -+ - Monitor * - createmon(void) - { -@@ -871,6 +907,18 @@ getatomprop(Client *c, Atom prop) - return atom; - } - -+int -+getdwmblockspid() -+{ -+ char buf[16]; -+ FILE *fp = popen("pidof -s dwmblocks", "r"); -+ fgets(buf, sizeof(buf), fp); -+ pid_t pid = strtoul(buf, NULL, 10); -+ pclose(fp); -+ dwmblockspid = pid; -+ return pid != 0 ? 0 : -1; -+} -+ - int - getrootptr(int *x, int *y) - { -@@ -1636,6 +1684,23 @@ sigchld(int unused) - while (0 < waitpid(-1, NULL, WNOHANG)); - } - -+void -+sigdwmblocks(const Arg *arg) -+{ -+ union sigval sv; -+ sv.sival_int = (dwmblockssig << 8) | arg->i; -+ if (!dwmblockspid) -+ if (getdwmblockspid() == -1) -+ return; -+ -+ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { -+ if (errno == ESRCH) { -+ if (!getdwmblockspid()) -+ sigqueue(dwmblockspid, SIGUSR1, sv); -+ } -+ } -+} -+ - void - spawn(const Arg *arg) - { -@@ -1987,8 +2052,10 @@ updatesizehints(Client *c) - void - updatestatus(void) - { -- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) -+ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) - strcpy(stext, "dwm-"VERSION); -+ else -+ copyvalidchars(stext, rawstext); - drawbar(selmon); - } - diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-status2d-20210402-60bb3df.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-status2d-20210402-60bb3df.diff @@ -0,0 +1,187 @@ +From 9e7935657bdea456db3eb858ac44bb0a671c2b7a Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Fri, 2 Apr 2021 19:04:58 +0200 +Subject: [PATCH] [statuscmd] status2d compatibility + +--- + config.def.h | 6 +++- + dwm.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 82 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..154a59b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -54,6 +54,8 @@ static const Layout layouts[] = { + /* helper for spawning shell commands in the pre dwm-5.0 fashion */ + #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + ++#define STATUSBAR "dwmblocks" ++ + /* commands */ + static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ + static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +@@ -103,7 +105,9 @@ static Button buttons[] = { + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, +- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++ { ClkStatusText, 0, Button1, sigstatusbar, {.i = 1} }, ++ { ClkStatusText, 0, Button2, sigstatusbar, {.i = 2} }, ++ { ClkStatusText, 0, Button3, sigstatusbar, {.i = 3} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index acbe6c9..da746a1 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -173,6 +173,7 @@ static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static pid_t getstatusbarpid(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -207,6 +208,7 @@ static void setup(void); + static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); ++static void sigstatusbar(const Arg *arg); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); +@@ -239,6 +241,9 @@ static void zoom(const Arg *arg); + /* variables */ + static const char broken[] = "broken"; + static char stext[1024]; ++static int statussig; ++static int statusw; ++static pid_t statuspid = -1; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -441,9 +446,34 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - statusw) { ++ x = selmon->ww - statusw; + click = ClkStatusText; +- else ++ ++ char *text, *s, ch; ++ statussig = 0; ++ for (text = s = stext; *s && x <= ev->x; s++) { ++ if ((unsigned char)(*s) < ' ') { ++ ch = *s; ++ *s = '\0'; ++ x += TEXTW(text) - lrpad; ++ *s = ch; ++ text = s + 1; ++ if (x >= ev->x) ++ break; ++ statussig = ch; ++ } else if (*s == '^') { ++ *s = '\0'; ++ x += TEXTW(text) - lrpad; ++ *s = '^'; ++ if (*(++s) == 'f') ++ x += atoi(++s); ++ while (*(s++) != '^'); ++ text = s; ++ s--; ++ } ++ } ++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); +@@ -696,7 +726,7 @@ dirtomon(int dir) + + int + drawstatusbar(Monitor *m, int bh, char* stext) { +- int ret, i, w, x, len; ++ int ret, i, j, w, x, len; + short isCode = 0; + char *text; + char *p; +@@ -705,7 +735,12 @@ drawstatusbar(Monitor *m, int bh, char* stext) { + if (!(text = (char*) malloc(sizeof(char)*len))) + die("malloc"); + p = text; +- memcpy(text, stext, len); ++ ++ i = -1, j = 0; ++ while (stext[++i]) ++ if ((unsigned char)stext[i] >= ' ') ++ text[j++] = stext[i]; ++ text[j] = '\0'; + + /* compute width of the status text */ + w = 0; +@@ -813,7 +848,7 @@ drawbar(Monitor *m) + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ +- tw = m->ww - drawstatusbar(m, bh, stext); ++ tw = statusw = m->ww - drawstatusbar(m, bh, stext); + } + + for (c = m->clients; c; c = c->next) { +@@ -979,6 +1014,29 @@ getatomprop(Client *c, Atom prop) + return atom; + } + ++pid_t ++getstatusbarpid() ++{ ++ char buf[32], *str = buf, *c; ++ FILE *fp; ++ ++ if (statuspid > 0) { ++ snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid); ++ if ((fp = fopen(buf, "r"))) { ++ fgets(buf, sizeof(buf), fp); ++ while ((c = strchr(str, '/'))) ++ str = c + 1; ++ fclose(fp); ++ if (!strcmp(str, STATUSBAR)) ++ return statuspid; ++ } ++ } ++ if (!(fp = popen("pidof -s "STATUSBAR, "r"))) ++ return -1; ++ fgets(buf, sizeof(buf), fp); ++ return pclose(fp) == 0 ? strtoul(buf, NULL, 10) : -1; ++} ++ + int + getrootptr(int *x, int *y) + { +@@ -1745,6 +1803,20 @@ sigchld(int unused) + while (0 < waitpid(-1, NULL, WNOHANG)); + } + ++void ++sigstatusbar(const Arg *arg) ++{ ++ union sigval sv; ++ ++ if (!statussig) ++ return; ++ sv.sival_int = arg->i; ++ if ((statuspid = getstatusbarpid()) <= 0) ++ return; ++ ++ sigqueue(statuspid, SIGRTMIN+statussig, sv); ++} ++ + void + spawn(const Arg *arg) + { +-- +2.31.0 + diff --git a/dwm.suckless.org/patches/statuscmd/dwmblocks-statuscmd-20210402-96cbb45.diff b/dwm.suckless.org/patches/statuscmd/dwmblocks-statuscmd-20210402-96cbb45.diff @@ -0,0 +1,127 @@ +From 1669878c08607f481e3f879d6914fc4d3c9d7206 Mon Sep 17 00:00:00 2001 +From: Daniel Bylinka <daniel.bylinka@gmail.com> +Date: Fri, 2 Apr 2021 19:20:17 +0200 +Subject: [PATCH] [statuscmd] Format status text and handle button signals + +--- + dwmblocks.c | 48 +++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 41 insertions(+), 7 deletions(-) + +diff --git a/dwmblocks.c b/dwmblocks.c +index ded717c..78fdeb5 100644 +--- a/dwmblocks.c ++++ b/dwmblocks.c +@@ -3,6 +3,7 @@ + #include<string.h> + #include<unistd.h> + #include<signal.h> ++#include<sys/wait.h> + #ifndef NO_X + #include<X11/Xlib.h> + #endif +@@ -27,14 +28,14 @@ typedef struct { + #ifndef __OpenBSD__ + void dummysighandler(int num); + #endif +-void sighandler(int num); + void getcmds(int time); + void getsigcmds(unsigned int signal); + void setupsignals(); +-void sighandler(int signum); ++void sighandler(int signum, siginfo_t *si, void *ucontext); + int getstatus(char *str, char *last); + void statusloop(); + void termhandler(); ++void chldhandler(); + void pstdout(); + #ifndef NO_X + void setroot(); +@@ -58,6 +59,8 @@ static int returnStatus = 0; + //opens process *cmd and stores output in *output + void getcmd(const Block *block, char *output) + { ++ if (block->signal) ++ *output++ = block->signal; + strcpy(output, block->icon); + FILE *cmdf = popen(block->command, "r"); + if (!cmdf) +@@ -102,15 +105,18 @@ void getsigcmds(unsigned int signal) + + void setupsignals() + { ++ struct sigaction sa = { .sa_sigaction = sighandler, .sa_flags = SA_SIGINFO }; + #ifndef __OpenBSD__ + /* initialize all real time signals with dummy handler */ +- for (int i = SIGRTMIN; i <= SIGRTMAX; i++) ++ for (int i = SIGRTMIN; i <= SIGRTMAX; i++) { + signal(i, dummysighandler); ++ sigaddset(&sa.sa_mask, i); ++ } + #endif + + for (unsigned int i = 0; i < LENGTH(blocks); i++) { + if (blocks[i].signal > 0) +- signal(SIGMINUS+blocks[i].signal, sighandler); ++ sigaction(SIGMINUS+blocks[i].signal, &sa, NULL); + } + + } +@@ -178,10 +184,32 @@ void dummysighandler(int signum) + } + #endif + +-void sighandler(int signum) ++void sighandler(int signum, siginfo_t *si, void *ucontext) + { +- getsigcmds(signum-SIGPLUS); +- writestatus(); ++ if (si->si_value.sival_int) { ++ pid_t parent = getpid(); ++ if (fork() == 0) { ++#ifndef NO_X ++ if (dpy) ++ close(ConnectionNumber(dpy)); ++#endif ++ int i; ++ for (i = 0; i < LENGTH(blocks) && blocks[i].signal != signum-SIGRTMIN; i++); ++ ++ char shcmd[1024]; ++ sprintf(shcmd, "%s; kill -%d %d", blocks[i].command, SIGRTMIN+blocks[i].signal, parent); ++ char *cmd[] = { "/bin/sh", "-c", shcmd, NULL }; ++ char button[2] = { '0' + si->si_value.sival_int, '\0' }; ++ setenv("BUTTON", button, 1); ++ setsid(); ++ execvp(cmd[0], cmd); ++ perror(cmd[0]); ++ exit(EXIT_SUCCESS); ++ } ++ } else { ++ getsigcmds(signum-SIGPLUS); ++ writestatus(); ++ } + } + + void termhandler() +@@ -189,6 +217,11 @@ void termhandler() + statusContinue = 0; + } + ++void chldhandler() ++{ ++ while (0 < waitpid(-1, NULL, WNOHANG)); ++} ++ + int main(int argc, char** argv) + { + for (int i = 0; i < argc; i++) {//Handle command line arguments +@@ -205,6 +238,7 @@ int main(int argc, char** argv) + delim[delimLen++] = '\0'; + signal(SIGTERM, termhandler); + signal(SIGINT, termhandler); ++ signal(SIGCHLD, chldhandler); + statusloop(); + #ifndef NO_X + XCloseDisplay(dpy); +-- +2.31.0 + diff --git a/dwm.suckless.org/patches/statuscmd/dwmblocks-statuscmd.diff b/dwm.suckless.org/patches/statuscmd/dwmblocks-statuscmd.diff @@ -1,80 +0,0 @@ -diff --git a/dwmblocks.c b/dwmblocks.c -index 2f3b774..ba7dbb5 100644 ---- a/dwmblocks.c -+++ b/dwmblocks.c -@@ -14,6 +14,7 @@ typedef struct { - unsigned int signal; - } Block; - void sighandler(int num); -+void buttonhandler(int sig, siginfo_t *si, void *ucontext); - void getcmds(int time); - #ifndef __OpenBSD__ - void getsigcmds(int signal); -@@ -33,15 +34,32 @@ static int screen; - static Window root; - static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; - static char statusstr[2][256]; -+static char button[] = "\0"; - static int statusContinue = 1; - static void (*writestatus) () = setroot; - - //opens process *cmd and stores output in *output - void getcmd(const Block *block, char *output) - { -+ if (block->signal) -+ { -+ output[0] = block->signal; -+ output++; -+ } - strcpy(output, block->icon); - char *cmd = block->command; -- FILE *cmdf = popen(cmd,"r"); -+ FILE *cmdf; -+ if (*button) -+ { -+ setenv("BUTTON", button, 1); -+ cmdf = popen(cmd,"r"); -+ *button = '\0'; -+ unsetenv("BUTTON"); -+ } -+ else -+ { -+ cmdf = popen(cmd,"r"); -+ } - if (!cmdf) - return; - char c; -@@ -79,12 +97,18 @@ void getsigcmds(int signal) - - void setupsignals() - { -+ struct sigaction sa; - for(int i = 0; i < LENGTH(blocks); i++) - { - if (blocks[i].signal > 0) -+ { - signal(SIGRTMIN+blocks[i].signal, sighandler); -+ sigaddset(&sa.sa_mask, SIGRTMIN+blocks[i].signal); // ignore signal when handling SIGUSR1 -+ } - } -- -+ sa.sa_sigaction = buttonhandler; -+ sa.sa_flags = SA_SIGINFO; -+ sigaction(SIGUSR1, &sa, NULL); - } - #endif - -@@ -143,6 +167,13 @@ void sighandler(int signum) - getsigcmds(signum-SIGRTMIN); - writestatus(); - } -+ -+void buttonhandler(int sig, siginfo_t *si, void *ucontext) -+{ -+ *button = '0' + si->si_value.sival_int & 0xff; -+ getsigcmds(si->si_value.sival_int >> 8); -+ writestatus(); -+} - #endif - - void termhandler(int signum) diff --git a/dwm.suckless.org/patches/statuscmd/index.md b/dwm.suckless.org/patches/statuscmd/index.md @@ -3,67 +3,101 @@ statuscmd Description ----------- -This patch adds the ability to execute shell commands based on the mouse -button and position when clicking the status bar. +This patch adds the ability to signal a status monitor program such as +[dwmblocks](https://github.com/torrinfail/dwmblocks) the location and button +when clicking on the status bar. Alternatively, there is a version that +executes shell commands defined in config.h instead of using signals. Usage ----- -Fill 'statuscmds' with commands. Choose which command to run by prefixing -the status text with a raw byte of the command's index in 'statuscmds', -offset by +1 since '\0' terminates strings. statuscmds[0] runs by default -if there is no index to the left of the mouse position. The mouse button -clicked is exported as $BUTTON. +Both the nosignal version and the dwmblocks version will run their respective +shell commands/scripts with the environment variable BUTTON set to the button +that was pressed. -Example -------- -With these commands: +### With signals +Apply the statuscmd patch and set the `STATUSBAR` macro in config.h +to the name of the status monitor. + +Apply the corresponding statuscmd patch to your status monitor if there is +one, or extend the program on your own. Feel free to add patches for other +status monitors. + +#### Patching status monitors +* Assosiate each section with a signal number in the range of 1-31. +* When setting the status text, print each section's respective signal number + as a raw byte before its text. +* Create a signal handler: + + void sighandler(int signum, siginfo_t *si, void *ucontext) + { + int signal = signum - SIGRTMIN; + int button = si->si_value.sival_int; /* if button is zero, the signal is not from a button press */ + ... /* do whatever you want */ + } + +* Register the signal handler for each section in the following way, with + 'signal' being the same signal from the first step: + + struct sigaction sa = { .sa_sigaction = sighandler, .sa_flags = SA_SIGINFO }; + sigaction(SIGRTMIN+signal, &sa, NULL); + +### Without signals +Apply the statuscmd-nosignal patch and fill the `statuscmds` array in config.h +with `StatusCmd` structs, which take a shell command string and an integer +identifier. - static const char *statuscmds[] = { "volume", "cpu", "battery" }; +When setting the status, print the integer identifier as a raw byte before its +respective text. + +For example, with `statuscmds` defined as such: + + static const StatusCmd statuscmds[] = { + { "volume", 1 }, + { "cpu", 2 }, + { "battery", 3 }, + }; And root name set like this: - xsetroot -name "$(echo -e 'volume |\x02 cpu |\x03 battery')" + xsetroot -name "$(printf '\x01Volume |\x02 CPU |\x03 Battery')" -Clicking on 'volume |' would run `volume`, clicking on ' cpu |' -would run `cpu` and clicking on ' battery' would run `battery`. +Clicking on 'Volume |' would run `volume`, clicking on ' CPU |' +would run `cpu` and clicking on ' Battery' would run `battery`. -The `cpu` script could look like this: +Example +------- +A script run from dwm or dwmblocks with this patch might look like this: #!/bin/sh case $BUTTON in - 1) notify-send "CPU usage" "$(ps axch -o cmd,%cpu --sort=-%cpu | head)";; - 3) st -e htop;; + 1) notify-send "CPU usage" "$(ps axch -o cmd,%cpu --sort=-%cpu | head)" ;; + 3) st -e htop ;; esac Notes ----- -If you have 10 or more commands, make sure to be careful when adding or -removing newline characters since '\n' is equal to '\x0a'. The problem -where having certain unprintable characters such as '\n' in the status -string can make dwm laggy is "fixed", since they are not copied to the -string that is actually drawn. - -dwmblocks integration ---------------------- -A program that sets the status for dwm such as -[dwmblocks](https://github.com/torrinfail/dwmblocks) can be patched to manage -the commands while dwm only finds the location clicked in the status bar. -This way, no changes are needed in dwm when adding or reordering modules. - -Instead of running a command from within dwm using the control character -as an index, the dwm-statuscmd-signal patch sends a SIGUSR1 signal to -dwmblocks with the button and control character encoded into the signal value. - -The dwmblocks-statuscmd patch makes dwmblocks put each block's signal in -front of its output text and handles the SIGUSR1 signal by running the -block's command with $BUTTON exported. +The signal version is not compatible with OpenBSD since it relies on `sigqueue`. + +Be careful with newline characters in the status text since '\n' is equal to +'\x0a', which is a valid signal number. The problem where having certain +undrawable characters in the status bar can make dwm laggy is fixed since dwm +will not attempt to draw them with this patch. Download -------- -* [dwm-statuscmd-6.2.diff](dwm-statuscmd-6.2.diff) -* [dwm-statuscmd-signal-6.2.diff](dwm-statuscmd-signal-6.2.diff) -* [dwmblocks-statuscmd.diff](dwmblocks-statuscmd.diff) +### dwm patches +* [dwm-statuscmd-20210402-67d76bd.diff](dwm-statuscmd-20210402-67d76bd.diff) +* [dwm-statuscmd-nosignal-20210402-67d76bd.diff](dwm-statuscmd-nosignal-20210402-67d76bd.diff) + +If using [status2d](https://dwm.suckless.org/patches/status2d/), use these patches instead of the +above ones on top of a build already patched with status2d: + +* [dwm-statuscmd-status2d-20210402-60bb3df.diff](dwm-statuscmd-status2d-20210402-60bb3df.diff) +* [dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff](dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff) + +### Status monitor patches +* [dwmblocks-statuscmd-20210402-96cbb45.diff](dwmblocks-statuscmd-20210402-96cbb45.diff) Author ------