sites

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

commit 4bebceb71fc1d9e78cf1a04a7fd55b4bb5e8680d
parent 8bc6f6a05b2b3dd67df30a5d5296833a59bce0d5
Author: Justinas Grigas <dev@jstnas.com>
Date:   Sat, 24 Jan 2026 16:36:32 +0000

dwm statuscmd: support all mouse buttons

Added support for all mouse buttons.
Fixed getstatusbarpid declaration.
Reworded and reformatted the index file.

Diffstat:
Adwm.suckless.org/patches/statuscmd/dwm-statuscmd-20260124-a9aa0d8.diff | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/statuscmd/index.md | 170+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
2 files changed, 318 insertions(+), 73 deletions(-)

diff --git a/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-20260124-a9aa0d8.diff b/dwm.suckless.org/patches/statuscmd/dwm-statuscmd-20260124-a9aa0d8.diff @@ -0,0 +1,221 @@ +From 5c4db00890ed6f967dc14b80e704a0cd89faa209 Mon Sep 17 00:00:00 2001 +From: Justinas Grigas <dev@jstnas.com> +Date: Tue, 8 Oct 2024 17:55:11 +0100 +Subject: [PATCH] dwm statuscmd: support all mouse buttons + +This patch enables all mouse buttons to interact with the status bar +script. + +It also fixes getstatusbarpid declaration. +--- + config.def.h | 12 +++++- + dwm.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 110 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 81c3fc0..dbe798b 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -56,6 +56,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 }; +@@ -105,7 +107,15 @@ static const 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} }, ++ { ClkStatusText, 0, Button4, sigstatusbar, {.i = 4} }, ++ { ClkStatusText, 0, Button5, sigstatusbar, {.i = 5} }, ++ { ClkStatusText, 0, 6, sigstatusbar, {.i = 6} }, ++ { ClkStatusText, 0, 7, sigstatusbar, {.i = 7} }, ++ { ClkStatusText, 0, 8, sigstatusbar, {.i = 8} }, ++ { ClkStatusText, 0, 9, sigstatusbar, {.i = 9} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index 53b393e..dbaef27 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -171,6 +171,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(void); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -204,6 +205,7 @@ static void setmfact(const Arg *arg); + static void setup(void); + static void seturgent(Client *c, int urg); + static void showhide(Client *c); ++static void sigstatusbar(const Arg *arg); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); +@@ -236,6 +238,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; /* bar height */ +@@ -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,27 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + TEXTW(selmon->ltsymbol)) + 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; ++ /* End clickable section on a matching signal raw byte */ ++ if (statussig == ch) ++ statussig = 0; ++ else ++ statussig = ch; ++ } ++ } ++ } else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); +@@ -708,9 +732,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) { +@@ -877,6 +916,30 @@ getatomprop(Client *c, Atom prop) + return atom; + } + ++pid_t ++getstatusbarpid(void) ++{ ++ 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); ++ pclose(fp); ++ return strtol(buf, NULL, 10); ++} ++ + int + getrootptr(int *x, int *y) + { +@@ -1644,6 +1707,20 @@ showhide(Client *c) + } + } + ++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) + { +@@ -2005,8 +2082,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.52.0 + diff --git a/dwm.suckless.org/patches/statuscmd/index.md b/dwm.suckless.org/patches/statuscmd/index.md @@ -1,111 +1,135 @@ -statuscmd -========= - -Description ------------ -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 ------ -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. +# statuscmd + +Add clickable status bar sections. + +## Description + +This patch sends mouse button events to a +[status monitor](https://dwm.suckless.org/status_monitor/). When clicking or +scrolling on a section, dwm detects the section number and mouse button, then +sends them to the status monitor via a signal. + +The nosignal version executes shell commands defined in config.h instead of +using signals. + +## Usage + +Both the status monitor and nosignal versions will run their respective shell +commands/scripts with the environment variable `BUTTON` set to the pressed +button. ### 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. +Apply the corresponding statuscmd patch to your status monitor if there is one, +or create one yourself. Feel free to add patches for other status monitors. #### Patching status monitors -* Associate 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. -* With the 20241009 patch, printing the raw byte again at the end of block - output will end the clickable region. -* 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); + +1. Associate each section with a signal number in the range of 1-31. +2. Print each section's signal number as a raw byte before its text. + * Print the signal number again after the text to end the clickable region. +3. Create a signal handler: + + void sighandler(int signum, siginfo_t *si, void *ucontext) + { + int signal = signum - SIGRTMIN; + /* if button is zero, the signal is not from a button press */ + int button = si->si_value.sival_int; + ... /* do whatever you want */ + } + +4. Register the signal handler for each section, with `signal` set to the + section number: + + 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. -When setting the status, print the integer identifier as a raw byte before its +When setting the status, print the section number 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 }, - }; + static const StatusCmd statuscmds[] = { + { "volume", 1 }, + { "cpu", 2 }, + { "battery", 3 }, + }; And root name set like this: - xsetroot -name "$(printf '\x01 Volume \x01|\x02 CPU \x02|\x03 Battery\x03')" + xsetroot -name "$(printf '\01 Volume \01|\02 CPU \02|\03 Battery \03')" -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`. + +## Example -Example -------- A script run from dwm or dwmblocks with this patch might look like this: - #!/bin/sh + #!/bin/sh + + case $BUTTON in + 1) notify-send 'CPU usage' "$(ps axch -o cmd,%cpu --sort=-%cpu | head)" ;; + 3) st -e htop ;; + esac - case $BUTTON in - 1) notify-send "CPU usage" "$(ps axch -o cmd,%cpu --sort=-%cpu | head)" ;; - 3) st -e htop ;; - esac + printf '\01Click Me!\01' - printf '\x01Click Me!\x01' +* Handle mouse buttons in a switch statement: + * `1`: left button + * `2`: middle button (pressing the scroll wheel) + * `3`: right button + * `4`: scrolling up + * `5`: scrolling down + * `6`: scrolling left + * `7`: scrolling right + * `8`: 4th button (backward) + * `9`: 5th button (forwards) +* Print the status text surrounded by its section number as a raw byte. + * If using printf, use octal codes as they're POSIX compliant. To represent + signal 30, use `\036`. -Notes ------ -The signal version is not compatible with OpenBSD since it relies on `sigqueue`. +## Notes -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. +* The signal patch doesn't work on OpenBSD since it relies on `sigqueue`. +* Newline characters (`\n`, `\012`, `\x0a`) get interpreted as a valid signal + number 10. +* This patch skips over undrawable characters when rendering the status bar + text, which fixes a problem that makes dwm lag when trying to draw them. + +## Download -Download --------- ### dwm patches -* [dwm-statuscmd-20210405-67d76bd.diff](dwm-statuscmd-20210405-67d76bd.diff) + +* [dwm-statuscmd-20260124-a9aa0d8.diff](./dwm-statuscmd-20260124-a9aa0d8.diff) * [dwm-statuscmd-20241009-8933ebc.diff](./dwm-statuscmd-20241009-8933ebc.diff) -* [dwm-statuscmd-nosignal-20210402-67d76bd.diff](dwm-statuscmd-nosignal-20210402-67d76bd.diff) +* [dwm-statuscmd-20210405-67d76bd.diff](./dwm-statuscmd-20210405-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: +When using [status2d](https://dwm.suckless.org/patches/status2d/), apply these +patches instead after patching status2d: -* [dwm-statuscmd-status2d-20210405-60bb3df.diff](dwm-statuscmd-status2d-20210405-60bb3df.diff) -* [dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff](dwm-statuscmd-nosignal-status2d-20210402-60bb3df.diff) +* [dwm-statuscmd-status2d-20210405-60bb3df.diff](./dwm-statuscmd-status2d-20210405-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) + +* [dwmblocks-statuscmd-20210402-96cbb45.diff](./dwmblocks-statuscmd-20210402-96cbb45.diff) * [gocaudices](https://github.com/LordRusk/gocaudices/tree/master/patches/statuscmd) -Author ------- +## Authors + * Daniel Bylinka - <daniel.bylinka@gmail.com> -* Justinas Grigas - <dev@jstnas.com> (20241009) +* Justinas Grigas - <dev@jstnas.com>