dwm-dwmfifo-20230714-e81f17d.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       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