dwm-integrated-status-text-6.3.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-integrated-status-text-6.3.diff (16210B)
       ---
            1 From 02f1f07ee4460787c971bd28e934cb5fc319253d Mon Sep 17 00:00:00 2001
            2 From: explosion-mental <explosion0mental@gmail.com>
            3 Date: Thu, 26 May 2022 22:34:14 -0500
            4 Subject: [PATCH] [PATCH] Allows dwm to handle the text by itself. You can
            5  think of it like a dwmblocks integration into dwm itself. This is extracted
            6  from my dwm build[0] in which you can find even more information.
            7 
            8 Example:
            9 ```
           10 /* fg         command             interval  signal */
           11 { "#000000",  "echo 'dwm block!",   10,       3},
           12 ```
           13 
           14 - fg: the foreground color of the individual block, for the background it
           15 uses the bg of SchemeStatus.
           16 
           17 - command: it uses the output of the commands for the status text
           18 interval: in seconds, how much does it have to pass before updating the
           19 block.
           20 
           21 - interval: in seconds, how many seconds until the block it's updated
           22 
           23 - signal: have to be less than 30. This lets you update the block with
           24 `kill` by adding 35 to this value.
           25 For the block above it would be 34 + 3 = 37 -> `kill -37 $(pidof dwm)`.
           26 These signals are linux dependant.
           27 
           28 You can change `$(pidof dwm)` with `$STATUSBAR` to 'fix' signaling
           29 multiple instances of dwm, since this patch also wraps the PID of dwm
           30 into the `$STATUSBAR` enviromental variable.
           31 
           32 Last thing, mouse actions. For this you need to handle the env variable
           33 `$BLOCK_BUTTON` in a script, this is so you can easily reuse the scripts
           34 used in dwmblocks. And remember that mouse actions update the block.
           35 
           36 [0] https://github.com/explosion-mental/Dwm or
           37 https://codeberg.org/explosion-mental/Dwm
           38 ---
           39  config.def.h |  39 ++++++-
           40  dwm.c        | 298 +++++++++++++++++++++++++++++++++++++++++++++++----
           41  2 files changed, 318 insertions(+), 19 deletions(-)
           42 
           43 diff --git a/config.def.h b/config.def.h
           44 index a2ac963..cad178c 100644
           45 --- a/config.def.h
           46 +++ b/config.def.h
           47 @@ -16,8 +16,38 @@ static const char *colors[][3]      = {
           48          /*               fg         bg         border   */
           49          [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
           50          [SchemeSel]  = { col_gray4, col_cyan,  col_cyan  },
           51 +        [SchemeStatus]={ col_cyan, col_gray1,  NULL  },
           52  };
           53  
           54 +
           55 +/* status bar */
           56 +static const Block blocks[] = {
           57 +        /* fg     command                                interval        signal */
           58 +        { col_gray3, "sb-clock",                        20,                1},
           59 +        { col_gray1, "sb-disk",                                9000,                2},
           60 +        { col_gray2, "sb-battery",                        10,                3},
           61 +        { col_gray3, "sb-internet",                        10,                4},
           62 +        { col_cyan, "sb-mailbox",                        0,                5},
           63 +        { "#000001", "sb-moonphase",                        0,                6},
           64 +        { "#1F0077", "sb-forecast",                        0,                7},
           65 +        { "#000077", "sb-volume",                        0,                8},
           66 +        { "#F77000", "sb-pacpackages",                        0,                9},
           67 +        { "#177000", "sb-sync",                                0,                10},
           68 +//        { col_gray1, "sb-mpc",                                0,                26},
           69 +        { col_gray2, "sb-music",                        0,                11},
           70 +//        { col_gray3, "sb-tasks",                        10,                12},
           71 +        { col_gray4, "sb-notes",                        0,                13},
           72 +        { col_cyan, "echo '';cat /tmp/recordingicon",        0,                14},
           73 +};
           74 +
           75 +/* inverse the order of the blocks, comment to disable */
           76 +#define INVERSED        1
           77 +/* delimeter between blocks commands. NULL character ('\0') means no delimeter. */
           78 +static char delimiter[] = " ";
           79 +/* max number of character that one block command can output */
           80 +#define CMDLENGTH        50
           81 +
           82 +
           83  /* tagging */
           84  static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
           85  
           86 @@ -104,7 +134,14 @@ static Button buttons[] = {
           87          { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
           88          { ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
           89          { ClkWinTitle,          0,              Button2,        zoom,           {0} },
           90 -        { ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
           91 +
           92 +        { ClkStatusText,        0,              Button1,        sendstatusbar,   {.i = 1 } },
           93 +        { ClkStatusText,        0,              Button2,        sendstatusbar,   {.i = 2 } },
           94 +        { ClkStatusText,        0,              Button3,        sendstatusbar,   {.i = 3 } },
           95 +        { ClkStatusText,        0,              Button4,        sendstatusbar,   {.i = 4 } },
           96 +        { ClkStatusText,        0,              Button5,        sendstatusbar,   {.i = 5 } },
           97 +        { ClkStatusText,        ShiftMask,      Button1,        sendstatusbar,   {.i = 6 } },
           98 +
           99          { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
          100          { ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
          101          { ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
          102 diff --git a/dwm.c b/dwm.c
          103 index a96f33c..5789f72 100644
          104 --- a/dwm.c
          105 +++ b/dwm.c
          106 @@ -28,6 +28,7 @@
          107  #include <stdlib.h>
          108  #include <string.h>
          109  #include <unistd.h>
          110 +#include <poll.h>
          111  #include <sys/types.h>
          112  #include <sys/wait.h>
          113  #include <X11/cursorfont.h>
          114 @@ -59,7 +60,7 @@
          115  
          116  /* enums */
          117  enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
          118 -enum { SchemeNorm, SchemeSel }; /* color schemes */
          119 +enum { SchemeNorm, SchemeSel, SchemeStatus }; /* color schemes */
          120  enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
          121         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
          122         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
          123 @@ -141,6 +142,13 @@ typedef struct {
          124          int monitor;
          125  } Rule;
          126  
          127 +typedef struct {
          128 +        const char *color;
          129 +        const char *command;
          130 +        const unsigned int interval;
          131 +        const unsigned int signal;
          132 +} Block;
          133 +
          134  /* function declarations */
          135  static void applyrules(Client *c);
          136  static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
          137 @@ -172,6 +180,11 @@ static void focusstack(const Arg *arg);
          138  static Atom getatomprop(Client *c, Atom prop);
          139  static int getrootptr(int *x, int *y);
          140  static long getstate(Window w);
          141 +static void getcmd(int i, char *button);
          142 +static void getcmds(int time);
          143 +static void getsigcmds(int signal);
          144 +static int gcd(int a, int b);
          145 +static int getstatus(int width);
          146  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
          147  static void grabbuttons(Client *c, int focused);
          148  static void grabkeys(void);
          149 @@ -197,14 +210,17 @@ static void run(void);
          150  static void scan(void);
          151  static int sendevent(Client *c, Atom proto);
          152  static void sendmon(Client *c, Monitor *m);
          153 +static void sendstatusbar(const Arg *arg);
          154  static void setclientstate(Client *c, long state);
          155  static void setfocus(Client *c);
          156  static void setfullscreen(Client *c, int fullscreen);
          157  static void setlayout(const Arg *arg);
          158  static void setmfact(const Arg *arg);
          159  static void setup(void);
          160 +static void setsignal(int sig, void (*handler)(int sig));
          161  static void seturgent(Client *c, int urg);
          162  static void showhide(Client *c);
          163 +static void sigalrm(int unused);
          164  static void sigchld(int unused);
          165  static void spawn(const Arg *arg);
          166  static void tag(const Arg *arg);
          167 @@ -237,13 +253,16 @@ static void zoom(const Arg *arg);
          168  
          169  /* variables */
          170  static const char broken[] = "broken";
          171 -static char stext[256];
          172  static int screen;
          173  static int sw, sh;           /* X display screen geometry width, height */
          174  static int bh, blw = 0;      /* bar geometry */
          175  static int lrpad;            /* sum of left and right padding for text */
          176  static int (*xerrorxlib)(Display *, XErrorEvent *);
          177 +static unsigned int blocknum; /* blocks idx in mouse click */
          178 +static unsigned int stsw = 0; /* status width */
          179  static unsigned int numlockmask = 0;
          180 +static unsigned int sleepinterval = 0, maxinterval = 0, count = 0;
          181 +static unsigned int execlock = 0; /* ensure only one child process exists per block at an instance */
          182  static void (*handler[LASTEvent]) (XEvent *) = {
          183          [ButtonPress] = buttonpress,
          184          [ClientMessage] = clientmessage,
          185 @@ -272,6 +291,9 @@ static Window root, wmcheckwin;
          186  /* configuration, allows nested code to access above variables */
          187  #include "config.h"
          188  
          189 +static char blockoutput[LENGTH(blocks)][CMDLENGTH + 1] = {0};
          190 +static int pipes[LENGTH(blocks)][2];
          191 +
          192  /* compile-time check if all tags fit into an unsigned int bit array. */
          193  struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
          194  
          195 @@ -440,9 +462,26 @@ buttonpress(XEvent *e)
          196                          arg.ui = 1 << i;
          197                  } else if (ev->x < x + blw)
          198                          click = ClkLtSymbol;
          199 -                else if (ev->x > selmon->ww - (int)TEXTW(stext))
          200 +                else if (ev->x > (x = selmon->ww - stsw)) {
          201                          click = ClkStatusText;
          202 -                else
          203 +                        int len, i;
          204 +
          205 +                        #if INVERSED
          206 +                        for (i = LENGTH(blocks) - 1; i >= 0; i--)
          207 +                        #else
          208 +                        for (i = 0; i < LENGTH(blocks); i++)
          209 +                        #endif /* INVERSED */
          210 +                        {
          211 +                                if (*blockoutput[i] == '\0') /* ignore command that output NULL or '\0' */
          212 +                                        continue;
          213 +                                len = TEXTW(blockoutput[i]) - lrpad + TEXTW(delimiter) - lrpad;
          214 +                                x += len;
          215 +                                if (ev->x <= x && ev->x >= x - len) { /* if the mouse is between the block area */
          216 +                                        blocknum = i; /* store what block the mouse is clicking */
          217 +                                        break;
          218 +                                }
          219 +                        }
          220 +                } else
          221                          click = ClkWinTitle;
          222          } else if ((c = wintoclient(ev->window))) {
          223                  focus(c);
          224 @@ -706,11 +745,8 @@ drawbar(Monitor *m)
          225                  return;
          226  
          227          /* draw status first so it can be overdrawn by tags later */
          228 -        if (m == selmon) { /* status is only drawn on selected monitor */
          229 -                drw_setscheme(drw, scheme[SchemeNorm]);
          230 -                tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
          231 -                drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
          232 -        }
          233 +        if (m == selmon) /* status is only drawn on selected monitor */
          234 +                tw = getstatus(m->ww);
          235  
          236          for (c = m->clients; c; c = c->next) {
          237                  occ |= c->tags;
          238 @@ -903,6 +939,106 @@ getstate(Window w)
          239          return result;
          240  }
          241  
          242 +void
          243 +getcmd(int i, char *button)
          244 +{
          245 +        if (!selmon->showbar)
          246 +                return;
          247 +
          248 +        if (execlock & 1 << i) { /* block is already running */
          249 +                //fprintf(stderr, "dwm: ignoring block %d, command %s\n", i, blocks[i].command);
          250 +                return;
          251 +        }
          252 +
          253 +        /* lock execution of block until current instance finishes execution */
          254 +        execlock |= 1 << i;
          255 +
          256 +        if (fork() == 0) {
          257 +                if (dpy)
          258 +                        close(ConnectionNumber(dpy));
          259 +                dup2(pipes[i][1], STDOUT_FILENO);
          260 +                close(pipes[i][0]);
          261 +                close(pipes[i][1]);
          262 +
          263 +                if (button)
          264 +                        setenv("BLOCK_BUTTON", button, 1);
          265 +                execlp("/bin/sh", "sh", "-c", blocks[i].command, (char *) NULL);
          266 +                fprintf(stderr, "dwm: block %d, execlp %s", i, blocks[i].command);
          267 +                perror(" failed");
          268 +                exit(EXIT_SUCCESS);
          269 +        }
          270 +}
          271 +
          272 +void
          273 +getcmds(int time)
          274 +{
          275 +        int i;
          276 +        for (i = 0; i < LENGTH(blocks); i++)
          277 +                if ((blocks[i].interval != 0 && time % blocks[i].interval == 0) || time == -1)
          278 +                        getcmd(i, NULL);
          279 +}
          280 +
          281 +void
          282 +getsigcmds(int signal)
          283 +{
          284 +        int i;
          285 +        unsigned int sig = signal - SIGRTMIN;
          286 +        for (i = 0; i < LENGTH(blocks); i++)
          287 +                if (blocks[i].signal == sig)
          288 +                        getcmd(i, NULL);
          289 +}
          290 +
          291 +int
          292 +getstatus(int width)
          293 +{
          294 +        int i, len, all = width, delimlen = TEXTW(delimiter) - lrpad;
          295 +        char fgcol[8];
          296 +                                /* fg                bg */
          297 +        const char *cols[8] =         { fgcol, colors[SchemeStatus][ColBg] };
          298 +        //uncomment to inverse the colors
          299 +        //const char *cols[8] =         { colors[SchemeStatus][ColBg], fgcol };
          300 +
          301 +        #if INVERSED
          302 +        for (i = 0; i < LENGTH(blocks); i++)
          303 +        #else
          304 +        for (i = LENGTH(blocks) - 1; i >= 0; i--)
          305 +        #endif /* INVERSED */
          306 +        {
          307 +                if (*blockoutput[i] == '\0') /* ignore command that output NULL or '\0' */
          308 +                        continue;
          309 +                strncpy(fgcol, blocks[i].color, 8);
          310 +                /* re-load the scheme with the new colors */
          311 +                scheme[SchemeStatus] = drw_scm_create(drw, cols, 3);
          312 +                drw_setscheme(drw, scheme[SchemeStatus]); /* 're-set' the scheme */
          313 +                len = TEXTW(blockoutput[i]) - lrpad;
          314 +                all -= len;
          315 +                drw_text(drw, all, 0, len, bh, 0, blockoutput[i], 0);
          316 +                /* draw delimiter */
          317 +                if (*delimiter == '\0') /* ignore no delimiter */
          318 +                        continue;
          319 +                drw_setscheme(drw, scheme[SchemeNorm]);
          320 +                all -= delimlen;
          321 +                drw_text(drw, all, 0, delimlen, bh, 0, delimiter, 0);
          322 +        }
          323 +
          324 +        return stsw = width - all;
          325 +}
          326 +
          327 +int
          328 +gcd(int a, int b)
          329 +{
          330 +        int temp;
          331 +
          332 +        while (b > 0) {
          333 +                temp = a % b;
          334 +                a = b;
          335 +                b = temp;
          336 +        }
          337 +
          338 +        return a;
          339 +}
          340 +
          341 +
          342  int
          343  gettextprop(Window w, Atom atom, char *text, unsigned int size)
          344  {
          345 @@ -1376,12 +1512,99 @@ restack(Monitor *m)
          346  void
          347  run(void)
          348  {
          349 +        int i;
          350          XEvent ev;
          351 +        struct pollfd fds[LENGTH(blocks) + 1] = {0};
          352 +
          353 +        fds[0].fd = ConnectionNumber(dpy);
          354 +        fds[0].events = POLLIN;
          355 +
          356 +        #if INVERSED
          357 +        for (i = LENGTH(blocks) - 1; i >= 0; i--)
          358 +        #else
          359 +        for (i = 0; i < LENGTH(blocks); i++)
          360 +        #endif /* INVERSED */
          361 +        {
          362 +                pipe(pipes[i]);
          363 +                fds[i + 1].fd = pipes[i][0];
          364 +                fds[i + 1].events = POLLIN;
          365 +                getcmd(i, NULL);
          366 +                if (blocks[i].interval) {
          367 +                        maxinterval = MAX(blocks[i].interval, maxinterval);
          368 +                        sleepinterval = gcd(blocks[i].interval, sleepinterval);
          369 +                }
          370 +        }
          371 +
          372 +        alarm(sleepinterval);
          373          /* main event loop */
          374          XSync(dpy, False);
          375 -        while (running && !XNextEvent(dpy, &ev))
          376 -                if (handler[ev.type])
          377 -                        handler[ev.type](&ev); /* call handler */
          378 +        while (running) {
          379 +
          380 +                /* bar hidden, then skip poll */
          381 +                if (!selmon->showbar) {
          382 +                        XNextEvent(dpy, &ev);
          383 +                        if (handler[ev.type])
          384 +                                handler[ev.type](&ev); /* call handler */
          385 +                        continue;
          386 +                }
          387 +
          388 +                if ((poll(fds, LENGTH(blocks) + 1, -1)) == -1) {
          389 +                        /* FIXME other than SIGALRM and the real time signals,
          390 +                         * there seems to be a signal being que if using
          391 +                         * 'xsetroot -name' sutff */
          392 +                        if (errno == EINTR) /* signal caught */
          393 +                                continue;
          394 +                        fprintf(stderr, "dwm: poll ");
          395 +                        perror("failed");
          396 +                        exit(EXIT_FAILURE);
          397 +                }
          398 +
          399 +                /* handle display fd */
          400 +                if (fds[0].revents & POLLIN) {
          401 +                        while (running && XPending(dpy)) {
          402 +                                XNextEvent(dpy, &ev);
          403 +                                if (handler[ev.type])
          404 +                                        handler[ev.type](&ev); /* call handler */
          405 +                        }
          406 +                } else if (fds[0].revents & POLLHUP) {
          407 +                        fprintf(stderr, "dwm: main event loop, hang up");
          408 +                        perror(" failed");
          409 +                        exit(EXIT_FAILURE);
          410 +                }
          411 +
          412 +                /* handle blocks */
          413 +                for (i = 0; i < LENGTH(blocks); i++) {
          414 +                        if (fds[i + 1].revents & POLLIN) {
          415 +                                /* empty buffer with CMDLENGTH + 1 byte for the null terminator */
          416 +                                int bt = read(fds[i + 1].fd, blockoutput[i], CMDLENGTH);
          417 +                                /* remove lock for the current block */
          418 +                                execlock &= ~(1 << i);
          419 +
          420 +                                if (bt == -1) { /* if read failed */
          421 +                                        fprintf(stderr, "dwm: read failed in block %s\n", blocks[i].command);
          422 +                                        perror(" failed");
          423 +                                        continue;
          424 +                                }
          425 +
          426 +                                if (blockoutput[i][bt - 1] == '\n') /* chop off ending new line, if one is present */
          427 +                                        blockoutput[i][bt - 1] = '\0';
          428 +                                else /* NULL terminate the string */
          429 +                                        blockoutput[i][bt++] = '\0';
          430 +
          431 +                                drawbar(selmon);
          432 +                        } else if (fds[i + 1].revents & POLLHUP) {
          433 +                                fprintf(stderr, "dwm: block %d hangup", i);
          434 +                                perror(" failed");
          435 +                                exit(EXIT_FAILURE);
          436 +                        }
          437 +                }
          438 +        }
          439 +
          440 +        /* close the pipes after running */
          441 +        for (i = 0; i < LENGTH(blocks); i++) {
          442 +                close(pipes[i][0]);
          443 +                close(pipes[i][1]);
          444 +        }
          445  }
          446  
          447  void
          448 @@ -1427,6 +1650,13 @@ sendmon(Client *c, Monitor *m)
          449          arrange(NULL);
          450  }
          451  
          452 +void
          453 +sendstatusbar(const Arg *arg)
          454 +{
          455 +        char button[2] = { '0' + arg->i & 0xff, '\0' };
          456 +        getcmd(blocknum, button);
          457 +}
          458 +
          459  void
          460  setclientstate(Client *c, long state)
          461  {
          462 @@ -1537,8 +1767,20 @@ setup(void)
          463          XSetWindowAttributes wa;
          464          Atom utf8string;
          465  
          466 -        /* clean up any zombies immediately */
          467 -        sigchld(0);
          468 +        setsignal(SIGCHLD, sigchld); /* zombies */
          469 +        setsignal(SIGALRM, sigalrm); /* timer */
          470 +
          471 +        #ifdef __linux__
          472 +        /* handle defined real time signals (linux only) */
          473 +        for (i = 0; i < LENGTH(blocks); i++)
          474 +                if (blocks[i].signal)
          475 +                        setsignal(SIGRTMIN + blocks[i].signal, getsigcmds);
          476 +        #endif /* __linux__ */
          477 +
          478 +        /* pid as an enviromental variable */
          479 +        char envpid[16];
          480 +        snprintf(envpid, LENGTH(envpid), "%d", getpid());
          481 +        setenv("STATUSBAR", envpid, 1);
          482  
          483          /* init screen */
          484          screen = DefaultScreen(dpy);
          485 @@ -1600,6 +1842,21 @@ setup(void)
          486          focus(NULL);
          487  }
          488  
          489 +void
          490 +setsignal(int sig, void (*handler)(int unused))
          491 +{
          492 +        struct sigaction sa;
          493 +
          494 +        sa.sa_handler = handler;
          495 +        sigemptyset(&sa.sa_mask);
          496 +        sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
          497 +
          498 +        if (sigaction(sig, &sa, 0) == -1) {
          499 +                fprintf(stderr, "signal %d ", sig);
          500 +                perror("failed to setup");
          501 +                exit(EXIT_FAILURE);
          502 +        }
          503 +}
          504  
          505  void
          506  seturgent(Client *c, int urg)
          507 @@ -1632,11 +1889,18 @@ showhide(Client *c)
          508          }
          509  }
          510  
          511 +
          512 +void
          513 +sigalrm(int unused)
          514 +{
          515 +        getcmds(count);
          516 +        alarm(sleepinterval);
          517 +        count = (count + sleepinterval - 1) % maxinterval + 1;
          518 +}
          519 +
          520  void
          521  sigchld(int unused)
          522  {
          523 -        if (signal(SIGCHLD, sigchld) == SIG_ERR)
          524 -                die("can't install SIGCHLD handler:");
          525          while (0 < waitpid(-1, NULL, WNOHANG));
          526  }
          527  
          528 @@ -1993,8 +2257,6 @@ updatesizehints(Client *c)
          529  void
          530  updatestatus(void)
          531  {
          532 -        if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
          533 -                strcpy(stext, "dwm-"VERSION);
          534          drawbar(selmon);
          535  }
          536  
          537 -- 
          538 2.36.1
          539