dwm-dwmfifo-20230714-e81f17d.diff (8238B)
1 From 898a3f86703be6fb6f3690916797b80bf1d4dbc8 Mon Sep 17 00:00:00 2001 2 From: Santtu Lakkala <inz@inz.fi> 3 Date: Thu, 13 Jul 2023 15:48:14 +0300 4 Subject: [PATCH] Command FIFO for dwm 5 6 Builds on the previous version of dwmfifo, but: 7 - proper buffering and line detection 8 - basic argument parsing 9 - new commands to show a window by xid or name pattern 10 --- 11 config.def.h | 26 +++++++ 12 dwm.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++- 13 2 files changed, 223 insertions(+), 3 deletions(-) 14 15 diff --git a/config.def.h b/config.def.h 16 index 9efa774..fc4db01 100644 17 --- a/config.def.h 18 +++ b/config.def.h 19 @@ -114,3 +114,29 @@ static const Button buttons[] = { 20 { ClkTagBar, MODKEY, Button3, toggletag, {0} }, 21 }; 22 23 +static const char *dwmfifo = "/tmp/dwm.fifo"; 24 +static Command commands[] = { 25 + { "dmenu", spawn, {.v = dmenucmd} }, 26 + { "term", spawn, {.v = termcmd} }, 27 + { "quit", quit, {0} }, 28 + { "togglebar", togglebar, {0} }, 29 + { "focusstack", focusstack, .parse = parseplusminus }, 30 + { "incnmaster", incnmaster, .parse = parseplusminus }, 31 + { "setmfact", setmfact, .parse = parseplusminus }, 32 + { "zoom", zoom, {0} }, 33 + { "killclient", killclient, {0} }, 34 + { "setlayout-tiled", setlayout, {.v = &layouts[0]} }, 35 + { "setlayout-float", setlayout, {.v = &layouts[1]} }, 36 + { "setlayout-mono", setlayout, {.v = &layouts[2]} }, 37 + { "togglelayout", setlayout, {0} }, 38 + { "togglefloating", togglefloating, {0} }, 39 + { "viewwin", viewwin, .parse = parsexid }, 40 + { "viewname", viewname, .parse = parsestr }, 41 + { "viewall", view, {.ui = ~0} }, 42 + { "focusmon", focusmon, .parse = parseplusminus }, 43 + { "tagmon", tagmon, .parse = parseplusminus }, 44 + { "view", view, .parse = parsetag }, 45 + { "toggleview", toggleview, .parse = parsetag }, 46 + { "tag", tag, .parse = parsetag }, 47 + { "toggletag", toggletag, .parse = parsetag }, 48 +}; 49 diff --git a/dwm.c b/dwm.c 50 index f1d86b2..13537fc 100644 51 --- a/dwm.c 52 +++ b/dwm.c 53 @@ -21,6 +21,7 @@ 54 * To understand everything else, start reading main(). 55 */ 56 #include <errno.h> 57 +#include <fcntl.h> 58 #include <locale.h> 59 #include <signal.h> 60 #include <stdarg.h> 61 @@ -28,6 +29,8 @@ 62 #include <stdlib.h> 63 #include <string.h> 64 #include <unistd.h> 65 +#include <poll.h> 66 +#include <fnmatch.h> 67 #include <sys/types.h> 68 #include <sys/wait.h> 69 #include <X11/cursorfont.h> 70 @@ -141,6 +144,13 @@ typedef struct { 71 int monitor; 72 } Rule; 73 74 +typedef struct { 75 + const char *name; 76 + void (*func)(const Arg *arg); 77 + const Arg arg; 78 + int (*parse)(Arg *arg, const char *s, size_t len); 79 +} Command; 80 + 81 /* function declarations */ 82 static void applyrules(Client *c); 83 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); 84 @@ -161,6 +171,7 @@ static void destroynotify(XEvent *e); 85 static void detach(Client *c); 86 static void detachstack(Client *c); 87 static Monitor *dirtomon(int dir); 88 +static void dispatchcmd(void); 89 static void drawbar(Monitor *m); 90 static void drawbars(void); 91 static void enternotify(XEvent *e); 92 @@ -227,6 +238,8 @@ static void updatetitle(Client *c); 93 static void updatewindowtype(Client *c); 94 static void updatewmhints(Client *c); 95 static void view(const Arg *arg); 96 +static void viewwin(const Arg *arg); 97 +static void viewname(const Arg *arg); 98 static Client *wintoclient(Window w); 99 static Monitor *wintomon(Window w); 100 static int xerror(Display *dpy, XErrorEvent *ee); 101 @@ -267,10 +280,63 @@ static Display *dpy; 102 static Drw *drw; 103 static Monitor *mons, *selmon; 104 static Window root, wmcheckwin; 105 +static int fifofd; 106 + 107 +static int parsetag(Arg *a, const char *s, size_t len); 108 +static int parseplusminus(Arg *a, const char *s, size_t len); 109 +static int parsexid(Arg *a, const char *s, size_t len); 110 +static int parsestr(Arg *a, const char *s, size_t len); 111 112 /* configuration, allows nested code to access above variables */ 113 #include "config.h" 114 115 +static int parsetag(Arg *a, const char *s, size_t len) 116 +{ 117 + char *end; 118 + unsigned int rv = strtoul(s, &end, 10); 119 + if (end == s) 120 + a->ui = 0; 121 + else if (rv > LENGTH(tags)) 122 + return 0; 123 + else if (rv == 0) 124 + a->ui = ~0U; 125 + else 126 + a->ui = 1U << (rv - 1); 127 + 128 + return 1; 129 +} 130 + 131 +static int parseplusminus(Arg *a, const char *s, size_t len) 132 +{ 133 + if (*s == '+') 134 + a->i = +1; 135 + else if (*s == '-') 136 + a->i = -1; 137 + else 138 + return 0; 139 + return 1; 140 +} 141 + 142 +static int parsexid(Arg *a, const char *s, size_t len) 143 +{ 144 + char *end; 145 + unsigned long long sv = strtoull(s, &end, 0); 146 + 147 + if (end == s) 148 + return 0; 149 + 150 + a->v = (void *)(intptr_t)sv; 151 + return 1; 152 +} 153 + 154 +static int parsestr(Arg *a, const char *s, size_t len) 155 +{ 156 + while (*s == ' ' || *s == '\t') 157 + s++; 158 + a->v = s; 159 + return 1; 160 +} 161 + 162 /* compile-time check if all tags fit into an unsigned int bit array. */ 163 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; 164 165 @@ -494,6 +560,7 @@ cleanup(void) 166 XSync(dpy, False); 167 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); 168 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 169 + close(fifofd); 170 } 171 172 void 173 @@ -695,6 +762,71 @@ dirtomon(int dir) 174 return m; 175 } 176 177 +static const char * 178 +strnprefix(const char *haystack, size_t hlen, const char *needle) 179 +{ 180 + while (*needle && hlen--) { 181 + if (*haystack++ != *needle++) 182 + return 0; 183 + } 184 + 185 + if (*needle) 186 + return NULL; 187 + return haystack; 188 +} 189 + 190 +void 191 +dispatchcmd(void) 192 +{ 193 + static char buf[BUFSIZ]; 194 + static char * const bend = 1[&buf]; 195 + static char *bw = buf; 196 + static int longline = 0; 197 + ssize_t n; 198 + char *nl; 199 + char *pl = buf; 200 + char *dend; 201 + Command *i; 202 + 203 + n = read(fifofd, bw, bend - bw); 204 + if (n == -1) 205 + die("Failed to read() from DWM fifo %s:", dwmfifo); 206 + dend = bw + n; 207 + 208 + if (longline) { 209 + if (!(nl = memchr(bw, '\n', dend - bw))) 210 + return; 211 + bw = pl = nl + 1; 212 + longline = 0; 213 + } 214 + 215 + while ((nl = memchr(bw, '\n', dend - bw))) { 216 + for (i = commands; i < 1[&commands]; i++) { 217 + const char *arg; 218 + 219 + if (!(arg = strnprefix(pl, nl - pl, i->name))) 220 + continue; 221 + *nl = '\0'; 222 + if (i->parse) { 223 + Arg a; 224 + if (i->parse(&a, arg, nl - arg)) 225 + i->func(&a); 226 + } else { 227 + i->func(&i->arg); 228 + } 229 + 230 + break; 231 + } 232 + bw = pl = nl + 1; 233 + } 234 + 235 + memmove(buf, pl, dend - pl); 236 + bw = dend - pl + buf; 237 + 238 + if (bw == bend) 239 + bw = buf; 240 +} 241 + 242 void 243 drawbar(Monitor *m) 244 { 245 @@ -1379,15 +1511,31 @@ restack(Monitor *m) 246 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 247 } 248 249 +static Bool evpredicate() 250 +{ 251 + return True; 252 +} 253 + 254 void 255 run(void) 256 { 257 XEvent ev; 258 + struct pollfd fds[2] = { 259 + { .events = POLLIN }, 260 + { .fd = fifofd, .events = POLLIN } 261 + }; 262 /* main event loop */ 263 XSync(dpy, False); 264 - while (running && !XNextEvent(dpy, &ev)) 265 - if (handler[ev.type]) 266 - handler[ev.type](&ev); /* call handler */ 267 + fds[0].fd = ConnectionNumber(dpy); 268 + while (running) { 269 + (void)poll(fds, 1[&fds] - fds, -1); 270 + if (fds[1].revents & POLLIN) 271 + dispatchcmd(); 272 + if (fds[0].revents & POLLIN) 273 + while (XCheckIfEvent(dpy, &ev, evpredicate, NULL)) 274 + if (handler[ev.type]) 275 + handler[ev.type](&ev); /* call handler */ 276 + } 277 } 278 279 void 280 @@ -1611,6 +1759,9 @@ setup(void) 281 XSelectInput(dpy, root, wa.event_mask); 282 grabkeys(); 283 focus(NULL); 284 + fifofd = open(dwmfifo, O_RDWR | O_CLOEXEC | O_NONBLOCK); 285 + if (fifofd < 0) 286 + die("Failed to open() DWM fifo %s:", dwmfifo); 287 } 288 289 void 290 @@ -2062,6 +2213,49 @@ view(const Arg *arg) 291 arrange(selmon); 292 } 293 294 +void 295 +viewclient(Client *c) 296 +{ 297 + if (!(c->tags & c->mon->tagset[c->mon->seltags])) 298 + view(&(Arg){ .ui = c->tags }); 299 + focus(c); 300 +} 301 + 302 +void 303 +viewwin(const Arg *arg) 304 +{ 305 + Client *c = wintoclient((Window)(intptr_t)arg->v); 306 + 307 + if (!c) 308 + return; 309 + 310 + viewclient(c); 311 +} 312 + 313 +Client * 314 +pattoclient(const char *pattern) 315 +{ 316 + Client *c; 317 + Monitor *m; 318 + 319 + for (m = mons; m; m = m->next) 320 + for (c = m->clients; c; c = c->next) 321 + if (!fnmatch(pattern, c->name, 0)) 322 + return c; 323 + return NULL; 324 +} 325 + 326 +void 327 +viewname(const Arg *arg) 328 +{ 329 + Client *c = pattoclient(arg->v); 330 + 331 + if (!c) 332 + return; 333 + 334 + viewclient(c); 335 +} 336 + 337 Client * 338 wintoclient(Window w) 339 { 340 -- 341 2.25.1 342