Compare commits

..

5 Commits

Author SHA1 Message Date
e42bd55e46 Added statuscmd 2025-05-06 22:26:55 +01:00
cfb8627a80 Avoid unsigned integer underflow in drw_text() 2024-10-30 13:02:17 +01:00
fcb2476b69 util.c: output function might override errno and thus affect perror()
Original patch by Raymond Cole with some modifications, thanks!
2024-10-27 20:10:07 +01:00
8933ebcf50 sync drw.{c,h} from dmenu
- drw: minor improvement to the nomatches cache
- overhaul utf8decoding and render invalid utf8 sequences as U+FFFD.

Thanks NRK for these improvements!
2024-10-05 13:06:08 +02:00
5687f46964 Add missing void to updateclientlist definition
Caught by -pedantic implying -Wstrict-prototypes for OpenBSD's 16.0.6 Clang.
2024-06-08 18:21:00 +02:00
6 changed files with 390 additions and 73 deletions

View File

@ -55,6 +55,8 @@ static const Layout layouts[] = {
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
#define STATUSBAR "dwmblocks"
/* commands */ /* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ 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 *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
@ -104,7 +106,9 @@ static const Button buttons[] = {
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} }, { 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, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} },

116
drw.c
View File

@ -9,54 +9,40 @@
#include "util.h" #include "util.h"
#define UTF_INVALID 0xFFFD #define UTF_INVALID 0xFFFD
#define UTF_SIZ 4
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static int
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; utf8decode(const char *s_in, long *u, int *err)
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static long
utf8decodebyte(const char c, size_t *i)
{ {
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) static const unsigned char lens[] = {
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
return (unsigned char)c & ~utfmask[*i]; /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */
return 0; /* 110XX */ 2, 2, 2, 2,
} /* 1110X */ 3, 3,
/* 11110 */ 4,
static size_t /* 11111 */ 0, /* invalid */
utf8validate(long *u, size_t i) };
{ static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 };
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 };
*u = UTF_INVALID;
for (i = 1; *u > utfmax[i]; ++i)
;
return i;
}
static size_t
utf8decode(const char *c, long *u, size_t clen)
{
size_t i, j, len, type;
long udecoded;
const unsigned char *s = (const unsigned char *)s_in;
int len = lens[*s >> 3];
*u = UTF_INVALID; *u = UTF_INVALID;
if (!clen) *err = 1;
return 0; if (len == 0)
udecoded = utf8decodebyte(c[0], &len);
if (!BETWEEN(len, 1, UTF_SIZ))
return 1; return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
if (type)
return j;
}
if (j < len)
return 0;
*u = udecoded;
utf8validate(u, len);
long cp = s[0] & leading_mask[len - 1];
for (int i = 1; i < len; ++i) {
if (s[i] == '\0' || (s[i] & 0xC0) != 0x80)
return i;
cp = (cp << 6) | (s[i] & 0x3F);
}
/* out of range, surrogate, overlong encoding */
if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1])
return len;
*err = 0;
*u = cp;
return len; return len;
} }
@ -238,11 +224,11 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
int int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
{ {
int i, ty, ellipsis_x = 0; int ty, ellipsis_x = 0;
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
XftDraw *d = NULL; XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont; Fnt *usedfont, *curfont, *nextfont;
int utf8strlen, utf8charlen, render = x || y || w || h; int utf8strlen, utf8charlen, utf8err, render = x || y || w || h;
long utf8codepoint = 0; long utf8codepoint = 0;
const char *utf8str; const char *utf8str;
FcCharSet *fccharset; FcCharSet *fccharset;
@ -251,9 +237,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
XftResult result; XftResult result;
int charexists = 0, overflow = 0; int charexists = 0, overflow = 0;
/* keep track of a couple codepoints for which we have no match. */ /* keep track of a couple codepoints for which we have no match. */
enum { nomatches_len = 64 }; static unsigned int nomatches[128], ellipsis_width, invalid_width;
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; static const char invalid[] = "<EFBFBD>";
static unsigned int ellipsis_width = 0;
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
return 0; return 0;
@ -263,6 +248,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} else { } else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
if (w < lpad)
return x + w;
d = XftDrawCreate(drw->dpy, drw->drawable, d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen), DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen)); DefaultColormap(drw->dpy, drw->screen));
@ -273,12 +260,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
usedfont = drw->fonts; usedfont = drw->fonts;
if (!ellipsis_width && render) if (!ellipsis_width && render)
ellipsis_width = drw_fontset_getwidth(drw, "..."); ellipsis_width = drw_fontset_getwidth(drw, "...");
if (!invalid_width && render)
invalid_width = drw_fontset_getwidth(drw, invalid);
while (1) { while (1) {
ew = ellipsis_len = utf8strlen = 0; ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
utf8str = text; utf8str = text;
nextfont = NULL; nextfont = NULL;
while (*text) { while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); utf8charlen = utf8decode(text, &utf8codepoint, &utf8err);
for (curfont = drw->fonts; curfont; curfont = curfont->next) { for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) { if (charexists) {
@ -300,9 +289,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
else else
utf8strlen = ellipsis_len; utf8strlen = ellipsis_len;
} else if (curfont == usedfont) { } else if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen; text += utf8charlen;
ew += tmpw; utf8strlen += utf8err ? 0 : utf8charlen;
ew += utf8err ? 0 : tmpw;
} else { } else {
nextfont = curfont; nextfont = curfont;
} }
@ -310,7 +299,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} }
} }
if (overflow || !charexists || nextfont) if (overflow || !charexists || nextfont || utf8err)
break; break;
else else
charexists = 0; charexists = 0;
@ -325,6 +314,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
x += ew; x += ew;
w -= ew; w -= ew;
} }
if (utf8err && (!render || invalid_width < w)) {
if (render)
drw_text(drw, x, y, w, h, 0, invalid, invert);
x += invalid_width;
w -= invalid_width;
}
if (render && overflow) if (render && overflow)
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
@ -338,11 +333,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
* character must be drawn. */ * character must be drawn. */
charexists = 1; charexists = 1;
for (i = 0; i < nomatches_len; ++i) { hash = (unsigned int)utf8codepoint;
/* avoid calling XftFontMatch if we know we won't find a match */ hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
if (utf8codepoint == nomatches.codepoint[i]) hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
goto no_match; h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
} h1 = (hash >> 17) % LENGTH(nomatches);
/* avoid expensive XftFontMatch call when we know we won't find a match */
if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
goto no_match;
fccharset = FcCharSetCreate(); fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint); FcCharSetAddChar(fccharset, utf8codepoint);
@ -371,7 +369,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
curfont->next = usedfont; curfont->next = usedfont;
} else { } else {
xfont_free(usedfont); xfont_free(usedfont);
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint;
no_match: no_match:
usedfont = drw->fonts; usedfont = drw->fonts;
} }

107
dwm.c
View File

@ -50,7 +50,6 @@
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw) #define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw)
@ -172,6 +171,7 @@ static void focusstack(const Arg *arg);
static Atom getatomprop(Client *c, Atom prop); static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y); static int getrootptr(int *x, int *y);
static long getstate(Window w); static long getstate(Window w);
static pid_t getstatusbarpid();
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused); static void grabbuttons(Client *c, int focused);
static void grabkeys(void); static void grabkeys(void);
@ -205,6 +205,7 @@ static void setmfact(const Arg *arg);
static void setup(void); static void setup(void);
static void seturgent(Client *c, int urg); static void seturgent(Client *c, int urg);
static void showhide(Client *c); static void showhide(Client *c);
static void sigstatusbar(const Arg *arg);
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void tag(const Arg *arg); static void tag(const Arg *arg);
static void tagmon(const Arg *arg); static void tagmon(const Arg *arg);
@ -237,6 +238,9 @@ static void zoom(const Arg *arg);
/* variables */ /* variables */
static const char broken[] = "broken"; static const char broken[] = "broken";
static char stext[256]; static char stext[256];
static int statusw;
static int statussig;
static pid_t statuspid = -1;
static int screen; static int screen;
static int sw, sh; /* X display screen geometry width, height */ static int sw, sh; /* X display screen geometry width, height */
static int bh; /* bar height */ static int bh; /* bar height */
@ -423,6 +427,7 @@ buttonpress(XEvent *e)
Client *c; Client *c;
Monitor *m; Monitor *m;
XButtonPressedEvent *ev = &e->xbutton; XButtonPressedEvent *ev = &e->xbutton;
char *text, *s, ch;
click = ClkRootWin; click = ClkRootWin;
/* focus monitor if necessary */ /* focus monitor if necessary */
@ -441,9 +446,27 @@ buttonpress(XEvent *e)
arg.ui = 1 << i; arg.ui = 1 << i;
} else if (ev->x < x + TEXTW(selmon->ltsymbol)) } else if (ev->x < x + TEXTW(selmon->ltsymbol))
click = ClkLtSymbol; click = ClkLtSymbol;
else if (ev->x > selmon->ww - (int)TEXTW(stext)) else if (ev->x > selmon->ww - statusw) {
x = selmon->ww - statusw;
click = ClkStatusText; 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;
/* reset on matching signal raw byte */
if (ch == statussig)
statussig = 0;
else
statussig = ch;
}
}
} else
click = ClkWinTitle; click = ClkWinTitle;
} else if ((c = wintoclient(ev->window))) { } else if ((c = wintoclient(ev->window))) {
focus(c); focus(c);
@ -709,9 +732,24 @@ drawbar(Monitor *m)
/* draw status first so it can be overdrawn by tags later */ /* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */ if (m == selmon) { /* status is only drawn on selected monitor */
char *text, *s, ch;
drw_setscheme(drw, scheme[SchemeNorm]); 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) { for (c = m->clients; c; c = c->next) {
@ -877,6 +915,30 @@ getatomprop(Client *c, Atom prop)
return atom; 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);
pclose(fp);
return strtol(buf, NULL, 10);
}
int int
getrootptr(int *x, int *y) getrootptr(int *x, int *y)
{ {
@ -1644,6 +1706,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 void
spawn(const Arg *arg) spawn(const Arg *arg)
{ {
@ -1851,7 +1927,7 @@ updatebarpos(Monitor *m)
} }
void void
updateclientlist() updateclientlist(void)
{ {
Client *c; Client *c;
Monitor *m; Monitor *m;
@ -2005,8 +2081,25 @@ updatesizehints(Client *c)
void void
updatestatus(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); 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); drawbar(selmon);
} }

View File

@ -0,0 +1,220 @@
From ca2a2e6386a746ebfc3480787e5d99da11e7abee Mon Sep 17 00:00:00 2001
From: Justinas Grigas <dev@jstnas.com>
Date: Wed, 9 Oct 2024 01:00:20 +0100
Subject: [PATCH] [dwm][statuscmd] better click regions
The main improvement of this patch over the previous version 20210405 is that
the click region now ends on a matching signal raw byte.
The matching byte is optional, and without it dwm will behave as before.
To take advantage of this feature, scripts need to be modified to print the raw
byte at the end as well.
In addition, this patch cleanly applies onto master branch.
---
config.def.h | 6 ++-
dwm.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 104 insertions(+), 6 deletions(-)
diff --git a/config.def.h b/config.def.h
index 9efa774..d008275 100644
--- a/config.def.h
+++ b/config.def.h
@@ -55,6 +55,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 };
@@ -104,7 +106,9 @@ 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} },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
diff --git a/dwm.c b/dwm.c
index 1443802..94ee0c7 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();
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;
+ /* reset on matching signal raw byte */
+ if (ch == statussig)
+ 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) {
@@ -876,6 +915,30 @@ 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);
+ pclose(fp);
+ return strtol(buf, NULL, 10);
+}
+
int
getrootptr(int *x, int *y)
{
@@ -1643,6 +1706,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)
{
@@ -2004,8 +2081,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.46.2

13
util.c
View File

@ -1,4 +1,5 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -10,17 +11,17 @@ void
die(const char *fmt, ...) die(const char *fmt, ...)
{ {
va_list ap; va_list ap;
int saved_errno;
saved_errno = errno;
va_start(ap, fmt); va_start(ap, fmt);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
va_end(ap); va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') { if (fmt[0] && fmt[strlen(fmt)-1] == ':')
fputc(' ', stderr); fprintf(stderr, " %s", strerror(saved_errno));
perror(NULL); fputc('\n', stderr);
} else {
fputc('\n', stderr);
}
exit(1); exit(1);
} }

1
util.h
View File

@ -3,6 +3,7 @@
#define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B))
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
#define LENGTH(X) (sizeof (X) / sizeof (X)[0])
void die(const char *fmt, ...); void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size); void *ecalloc(size_t nmemb, size_t size);