slstatus

My fork of https://tools.suckless.org/slstatus/
git clone https://git.inz.fi/slstatus
Log | Files | Refs | README | LICENSE

commit a4d910945cb842864155e512e9a7641600b3c377
parent 376f9191ee9db202963237d9b994f3131cb9a0c9
Author: Santtu Lakkala <inz@inz.fi>
Date:   Wed, 23 Feb 2022 08:56:03 +0200

Add wintitle module

Wintitle module allows to grab parts of a window's title. The module
argument is a list of comma separated strings that must be present in
the window's title in order. One of the strings should be !, which
indicates the part to capture.

Diffstat:
MMakefile | 3++-
Acomponents/wintitle.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mslstatus.h | 3+++
3 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile @@ -27,7 +27,8 @@ COM =\ components/uptime\ components/user\ components/volume\ - components/wifi + components/wifi\ + components/wintitle all: slstatus diff --git a/components/wintitle.c b/components/wintitle.c @@ -0,0 +1,95 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <regex.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "../util.h" + +static const char *getname(Window); +static const char *grepw(Window, const char *, int *); +const char *rematch(const regex_t *, const char *str, int *cl); +static Display *dpy = NULL; +static Atom netwmname; + +const char * +rematch(const regex_t *re, const char *str, int *cl) +{ + regmatch_t m[2]; + if (regexec(re, str, sizeof(m) / sizeof(*m), m, 0) || + m[1].rm_so == -1) + return NULL; + + *cl = m[1].rm_eo - m[1].rm_so; + return str + m[1].rm_so; +} + +const char * +wintitle(const char *arg) +{ + int rl; + const char *rv; + + if (!dpy) { + if (!(dpy = getdisplay())) { + warn("XOpenDisplay: Failed to open display"); + return NULL; + } + netwmname = XInternAtom(dpy, "_NET_WM_NAME", False); + } + + rv = grepw(DefaultRootWindow(dpy), arg, &rl); + + if (!rv) + return NULL; + + return bprintf("%.*s", rl, rv); +} + +const char * +grepw(Window win, const char *pattern, int *rl) { + unsigned int n; + Window *wins, *w, dw; + XWindowAttributes wa; + const char *rv = NULL; + regex_t re; + + if (regcomp(&re, pattern, REG_EXTENDED)) + goto err1; + if(!XQueryTree(dpy, win, &dw, &dw, &wins, &n)) + goto err2; + for(w = &wins[n-1]; w >= &wins[0]; w--) + if(XGetWindowAttributes(dpy, *w, &wa) + && !wa.override_redirect && wa.map_state == IsViewable) + if ((rv = rematch(&re, getname(*w), rl))) + break; + +err2: + XFree(wins); +err1: + regfree(&re); + + return rv; +} + +const char * +getname(Window win) { + static char buf[BUFSIZ]; + char **list; + int n; + XTextProperty prop; + + if(!XGetTextProperty(dpy, win, &prop, netwmname) || prop.nitems == 0) + if(!XGetWMName(dpy, win, &prop) || prop.nitems == 0) + return ""; + if(!XmbTextPropertyToTextList(dpy, &prop, &list, &n) && n > 0) { + strncpy(buf, list[0], sizeof buf); + XFreeStringList(list); + } else + strncpy(buf, (char *)prop.value, sizeof buf); + XFree(prop.value); + buf[sizeof buf - 1] = '\0'; + return buf; +} diff --git a/slstatus.h b/slstatus.h @@ -82,3 +82,6 @@ const char *vol_perc(const char *card); /* wifi */ const char *wifi_perc(const char *interface); const char *wifi_essid(const char *interface); + +/* wintitle */ +const char *wintitle(const char *pattern);