commit f73a8d5b2cb0a181e725cb9a594e45780a38e234 Author: Ashish Kumar Yadav Date: Sat Jul 4 02:34:11 2020 +0530 Initializing git repository diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..de41651 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +#PREFIX = /usr/local +PREFIX = ${HOME}/.local +CC = gcc +CFLAGS = -Wall -Wextra -Os +CFLAGSEXTRA = -Wno-unused-parameter -Wno-missing-field-initializers + +build: dwmblocks sigdwmblocks + +dwmblocks: dwmblocks.c blocks.h + ${CC} ${CFLAGS} ${CFLAGSEXTRA} -lX11 dwmblocks.c -o dwmblocks + +sigdwmblocks: sigdwmblocks.c + ${CC} ${CFLAGS} sigdwmblocks.c -o sigdwmblocks + +xgetrootname: xgetrootname.c + ${CC} ${CFLAGS} xgetrootname.c -o xgetrootname + +clean: + rm -f dwmblocks sigdwmblocks + +install: build + mkdir -p ${DESTDIR}${PREFIX}/bin + install -m 0755 dwmblocks ${DESTDIR}${PREFIX}/bin/dwmblocks + install -m 0755 sigdwmblocks ${DESTDIR}${PREFIX}/bin/sigdwmblocks + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks ${DESTDIR}${PREFIX}/bin/sigdwmblocks + +.PHONY: build clean install uninstall diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa9afab --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# dwmblocks + +Modular status monitor for dwm written in C. + +# Usage + +`dwmblocks [-d delimiter]` + +# Modifying blocks + +Blocks are added and removed by editing the blocks.h file. Read it for more +info. + +# Colored output and clickability + +The patches folder contains a patch for dwm which is required for dwmblocks to +function properly. It adds support for colored text, clickability and cursor +hinting when hovering on text output of clickable blocks (inspired by polybar). + +Clickability is inspired by the statuscmd patch for dwm. On clicking on text +corresponding to a clickable block, the program specified to handle clicks for +that block is executed with the first argument specifying which button was +clicked (1 for left, 2 for middle and 3 for right by default). + +Colored output is inspired by the statuscolors patch for dwm. To add colors, +have your programs for the blocks output raw characters from '\x11' to '\x31'. +'\x11' in status text switches the active colorscheme to the first one in the +scheme array in dwm and so on. See +[statuscolors patch](https://dwm.suckless.org/patches/statuscolors/) +for more info. Keep in mind that you have to start from '\x11' instead of '\x01' +as instructed on the page. + +# Signaling changes + +To signal a specific block to update, run `sigdwmblocks signal [sigval]`. +`sigval` is optional and must be an integer. When not provided it defaults to 0. +`sigval` is passed as the first argument to the program specified for updating +the block. + +# xgetrootname + +It is a small program to get the current root name. May prove helpful in +debugging. + +# Installation + +Clone the repository and run `make clean install` after getting in the project +directory. By default the program is installed in `$HOME/.local/bin`. If +xgetrootname is required run `make xgetrootname`. + +# Acknowledgements + +Some ideas and code was taken from other projects. Credits for those go to - + +* torrinfail ([original dwmblocks implementation](https://github.com/torrinfail/dwmblocks)) +* Daniel Bylinka ([statuscmd patch for dwm](https://dwm.suckless.org/patches/statuscmd/)) +* Jeremy Jay ([statuscolors patch for dwm](https://dwm.suckless.org/patches/statuscolors/)) diff --git a/blocks.h b/blocks.h new file mode 100644 index 0000000..69e8867 --- /dev/null +++ b/blocks.h @@ -0,0 +1,33 @@ +/* time interval in seconds to sleep before looking for updates in the main loop */ +#define SLEEPINTERVAL 30 + +#define PATH(name) "/home/ashish/.scripts/statusbar/"name + +/* If multiple realtime signals are pending, then the lowest numbered signal is delivered first. + * If interval of a block is set to 0, the block will only be updated once at startup. + * If interval is set to a negative value, the block will never be updated in the main loop. + * Set signal to 0 if signalling is not required for the block. + * Keep signal for clickable blocks less than 10. */ + +/* pathu - path of the program whose output is to be used for status text + * patch - path of the program to be executed on clicks */ +static Block blocks[] = { +/* pathu pathc interval signal */ + { PATH("hotspot.sh"), PATH("hotspot_button.sh"), -1, 1}, + + { PATH("time.sh"), NULL, 30, 0}, + + { PATH("calendar.sh"), PATH("calendar_button.sh"), 60, 2}, + +// { PATH("mail.sh"), PATH("mail_button.sh"), 30, 3}, + + { PATH("volume.sh"), PATH("volume_button.sh"), 0, 4}, + + { PATH("cpu_temp.sh"), PATH("cpu_temp_button.sh"), 30, 5}, + + { PATH("battery.sh"), PATH("battery_button.sh"), 0, 6}, + + { NULL } /* just to mark the end of the array */ +}; + +static const char *delim = " | "; diff --git a/dwmblocks.c b/dwmblocks.c new file mode 100644 index 0000000..40f017b --- /dev/null +++ b/dwmblocks.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define CMDLENGTH 25 /* must be positive */ +#define STTLENGTH 256 /* must be big enough */ +#define LOCKFILE "/tmp/dwmblocks.pid" + +#define EMPTYCMDOUT(block) (block->cmdoutcur[0] == '\n' || block->cmdoutcur[0] == '\0') +#define NOTATCMDOUTEND(block, i) (i < CMDLENGTH && block->cmdoutcur[i] != '\n' && block->cmdoutcur[i] != '\0') + +typedef struct { + char *pathu; + char *pathc; + const int interval; + const int signal; + char cmdoutcur[CMDLENGTH]; + char cmdoutprv[CMDLENGTH]; +} Block; + +static void buttonhandler(int signal, siginfo_t *si, void *ucontext); +static void getcmd(Block *block, int *sigval); +static void setroot(); +static void setupsignals(); +static void sighandler(int signum, siginfo_t *si, void *ucontext); +static void statusloop(); +static void termhandler(int signum); +static int updatestatus(); +static void writepid(); + +#include "blocks.h" + +static int statusContinue = 1; +static char statusstr[STTLENGTH]; +static size_t delimlength; +static Display *dpy; +static Window root; + +void +buttonhandler(int signal, siginfo_t *si, void *ucontext) +{ + signal = si->si_value.sival_int >> 8; + switch (fork()) { + case -1: + perror("buttonhandler - fork"); + exit(1); + case 0: + for (Block *current = blocks; current->pathu; current++) { + if (current->signal == signal) { + char button[] = { '0' + (si->si_value.sival_int & 0xff), '\0' }; + char *arg[] = { current->pathc, button, NULL }; + + setsid(); + execv(arg[0], arg); + perror("buttonhandler - execv"); + _exit(127); + } + } + exit(0); + } +} + +void +getcmd(Block *block, int *sigval) +{ + int fd[2]; + + if (pipe(fd) == -1) { + perror("getcmd - pipe"); + exit(1); + } + switch (fork()) { + case -1: + perror("getcmd - fork"); + exit(1); + case 0: + close(fd[0]); + if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { + perror("getcmd - dup2"); + exit(1); + } + close(fd[1]); + if (sigval) { + char buf[12]; + char *arg[] = { block->pathu, buf, NULL }; + + snprintf(buf, sizeof buf, "%d", *sigval); + execv(arg[0], arg); + } else { + char *arg[] = { block->pathu, NULL }; + + execv(arg[0], arg); + } + perror("getcmd - execv"); + _exit(127); + default: + close(fd[1]); + if (read(fd[0], block->cmdoutcur, CMDLENGTH) == -1) { + perror("getcmd - read"); + exit(1); + } + close(fd[0]); + } +} + +void +setroot() +{ + if (updatestatus()) /* only set root if block outputs have changed */ + return; + XStoreName(dpy, root, statusstr); + XFlush(dpy); +} + +void +setupsignals() +{ + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + /* to handle INT, HUP and TERM */ + sa.sa_handler = termhandler; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + /* to ignore unused realtime signals */ + sa.sa_handler = SIG_IGN; + for (int i = SIGRTMIN; i <= SIGRTMAX; i++) + sigaction(i, &sa, NULL); + /* to handle signals generated by dwm on click events */ + sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_sigaction = buttonhandler; + sigaction(SIGRTMIN, &sa, NULL); + /* to handle update signals for individual blocks */ + sa.sa_sigaction = sighandler; + for (Block *current = blocks; current->pathu; current++) + if (current->signal > 0) + sigaction(SIGRTMIN + current->signal, &sa, NULL); + /* to prevent forked children from becoming zombies */ + sa.sa_flags = SA_NOCLDWAIT | SA_RESTART; + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); +} + +void +sighandler(int signum, siginfo_t *si, void *ucontext) +{ + signum -= SIGRTMIN; + for (Block *current = blocks; current->pathu; current++) { + if (current->signal == signum) + getcmd(current, &(si->si_value.sival_int)); + } + setroot(); +} + +void +statusloop() +{ + int i; + + setupsignals(); + for (Block *current = blocks; current->pathu; current++) + if (current->interval >= 0) + getcmd(current, NULL); + setroot(); + sleep(SLEEPINTERVAL); + i = SLEEPINTERVAL; + while (statusContinue) { + for (Block *current = blocks; current->pathu; current++) + if (current->interval > 0 && i % current->interval == 0) + getcmd(current, NULL); + setroot(); + sleep(SLEEPINTERVAL); + i += SLEEPINTERVAL; + } +} + +void +termhandler(int signum) +{ + statusContinue = 0; +} + +/* returns whether block outputs have changed and updates statusstr if they have */ +int +updatestatus() +{ + int i; + char *str = statusstr; + Block *current; + + for (current = blocks; current->pathu; current++) { + if (EMPTYCMDOUT(current)) { + if (current->cmdoutprv[0] != current->cmdoutcur[0]) + goto updatestrstrt; + continue; + } + i = 0; + do { + if (current->cmdoutcur[i] == current->cmdoutprv[i]) { + i++; + continue; + } else { + str += i; + goto updatestrmddl; + } + } while (NOTATCMDOUTEND(current, i)); + str += i; + if (current->pathc && current->signal) + str++; + str += delimlength; + } + return 1; +updatestrstrt: + current->cmdoutprv[0] = current->cmdoutcur[0]; + for (current++; current->pathu; current++) { + if (EMPTYCMDOUT(current)) { + current->cmdoutprv[0] = current->cmdoutcur[0]; + continue; + } + i = 0; +updatestrmddl: + do { + *(str++) = current->cmdoutcur[i]; + current->cmdoutprv[i] = current->cmdoutcur[i]; + i++; + } while (NOTATCMDOUTEND(current, i)); + if (current->pathc && current->signal) + *(str++) = current->signal; + for (i = 0; delim[i]; i++) + *(str++) = delim[i]; + *(str++) = '\n'; + } + if (str != statusstr) + *(str - delimlength) = '\0'; + return 0; +} + +void +writepid() +{ + int fd; + char buf[20]; + struct flock fl; + ssize_t len; + + fd = open(LOCKFILE, O_RDWR|O_CREAT, 0644); + if (fd == -1) { + perror("writepid - fd"); + exit(1); + } + fl.l_type = F_WRLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + if (fcntl(fd, F_SETLK, &fl) == -1) { + if (errno == EACCES || errno == EAGAIN) { + fputs("Error: another instance of dwmblocks is already running.\n", stderr); + exit(2); + } + perror("lockfile - fcntl"); + exit(1); + } + if (ftruncate(fd, 0) == -1) { + perror("writepid - ftruncate"); + exit(1); + } + snprintf(buf, sizeof buf, "%ld", (long)getpid()); + len = strlen(buf); + if (write(fd, buf, len) != len) { + perror("writepid - write"); + exit(1); + } +} + +int +main(int argc, char *argv[]) +{ + writepid(); + if (argc > 2) { + if (strcmp("-d", argv[1]) == 0) + delim = argv[2]; + } + delimlength = strlen(delim) + 1; + if (!(dpy = XOpenDisplay(NULL))) { + fputs("Error: could not open display.\n", stderr); + return 1; + } + root = RootWindow(dpy, DefaultScreen(dpy)); + statusloop(); + unlink(LOCKFILE); + XStoreName(dpy, root, ""); + XCloseDisplay(dpy); + return 0; +} diff --git a/patches/dwm-dwmblocks-6.2.diff b/patches/dwm-dwmblocks-6.2.diff new file mode 100644 index 0000000..c77c7c7 --- /dev/null +++ b/patches/dwm-dwmblocks-6.2.diff @@ -0,0 +1,341 @@ +diff -ruN dwm-6.2-ori/config.def.h dwm-6.2/config.def.h +--- dwm-6.2-ori/config.def.h 2019-02-02 18:25:28.000000000 +0530 ++++ dwm-6.2/config.def.h 2020-07-02 22:13:34.676860032 +0530 +@@ -12,10 +12,34 @@ + static const char col_gray3[] = "#bbbbbb"; + static const char col_gray4[] = "#eeeeee"; + static const char col_cyan[] = "#005577"; ++static const char col1[] = "#ffffff"; ++static const char col2[] = "#ffffff"; ++static const char col3[] = "#ffffff"; ++static const char col4[] = "#ffffff"; ++static const char col5[] = "#ffffff"; ++static const char col6[] = "#ffffff"; ++static const char col7[] = "#ffffff"; ++static const char col8[] = "#ffffff"; ++static const char col9[] = "#ffffff"; ++static const char col10[] = "#ffffff"; ++static const char col11[] = "#ffffff"; ++static const char col12[] = "#ffffff"; + static const char *colors[][3] = { + /* fg bg border */ +- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, +- [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, ++ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++ [SchemeCol1] = { col1, col_gray1, col_gray2 }, ++ [SchemeCol2] = { col2, col_gray1, col_gray2 }, ++ [SchemeCol3] = { col3, col_gray1, col_gray2 }, ++ [SchemeCol4] = { col4, col_gray1, col_gray2 }, ++ [SchemeCol5] = { col5, col_gray1, col_gray2 }, ++ [SchemeCol6] = { col6, col_gray1, col_gray2 }, ++ [SchemeCol7] = { col7, col_gray1, col_gray2 }, ++ [SchemeCol8] = { col8, col_gray1, col_gray2 }, ++ [SchemeCol9] = { col8, col_gray1, col_gray2 }, ++ [SchemeCol10] = { col10, col_gray1, col_gray2 }, ++ [SchemeCol11] = { col11, col_gray1, col_gray2 }, ++ [SchemeCol12] = { col12, col_gray1, col_gray2 }, + }; + + /* tagging */ +@@ -103,7 +127,9 @@ + { 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, sigdwmblocks, {.i = 1} }, ++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, ++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff -ruN dwm-6.2-ori/dwm.c dwm-6.2/dwm.c +--- dwm-6.2-ori/dwm.c 2019-02-02 18:25:28.000000000 +0530 ++++ dwm-6.2/dwm.c 2020-07-02 22:29:22.207225539 +0530 +@@ -40,6 +40,8 @@ + #include + #endif /* XINERAMA */ + #include ++#include ++#include + + #include "drw.h" + #include "util.h" +@@ -56,10 +58,15 @@ + #define HEIGHT(X) ((X)->h + 2 * (X)->bw) + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) ++#define TTEXTW(X) drw_fontset_getwidth(drw, (X)) ++ ++#define DWMBLOCKSLOCKFILE "/tmp/dwmblocks.pid" + + /* enums */ +-enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel }; /* color schemes */ ++enum { CurNormal, CurHand, CurResize, CurMove, CurLast }; /* cursor */ ++enum { SchemeNorm, SchemeSel, SchemeCol1, SchemeCol2, SchemeCol3, ++ SchemeCol4, SchemeCol5, SchemeCol6, SchemeCol7, SchemeCol8, ++ SchemeCol9, SchemeCol10, SchemeCol11, SchemeCol12 }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -205,6 +212,7 @@ + static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); ++static void sigdwmblocks(const Arg *arg); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); +@@ -216,9 +224,11 @@ + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); ++static void updatebarcursor(int cursorpos); + static void updatebarpos(Monitor *m); + static void updatebars(void); + static void updateclientlist(void); ++static void updatedwmblockssig(int x, int e); + static int updategeom(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); +@@ -236,7 +246,10 @@ + + /* variables */ + static const char broken[] = "broken"; +-static char stext[256]; ++static char stextc[256]; ++static char stexts[256]; ++static int wstext; ++static int dwmblockssig; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -439,10 +452,14 @@ + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) +- click = ClkStatusText; +- else +- click = ClkWinTitle; ++ else if (ev->x < selmon->ww - wstext) ++ click = ClkWinTitle; ++// else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= (x = selmon->ww - wstext + lrpad / 2)) { ++ else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= selmon->ww - wstext + lrpad / 2) { ++ click = ClkStatusText; ++// updatedwmblockssig(x, ev->x); ++ } else ++ return; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); +@@ -695,7 +712,7 @@ + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; ++ int x, w; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; +@@ -703,9 +720,30 @@ + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ +- drw_setscheme(drw, scheme[SchemeNorm]); +- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++ char *ts = stextc; ++ char *tp = stextc; ++ char ctmp; ++ ++ drw_setscheme(drw, scheme[SchemeNorm]); ++ x = drw_text(drw, m->ww - wstext, 0, lrpad / 2, bh, 0, "", 0); /* to keep left padding clean */ ++loopbegin: ++ /* + 10 and stextc, stexts to avoid conflict b/w statusclr and statussig */ ++ if ((unsigned char)*ts > LENGTH(colors) + 10 ) { ++ ts++; ++ goto loopbegin; ++ } ++ ctmp = *ts; ++ *ts = '\0'; ++ x = drw_text(drw, x, 0, TTEXTW(tp), bh, 0, tp, 0); ++ if (ctmp == '\0') ++ goto loopend; ++ /* - 11 due to + 10 above */ ++ drw_setscheme(drw, scheme[(unsigned char)ctmp - 11]); ++ *ts = ctmp; ++ tp = ++ts; ++ goto loopbegin; ++loopend: ++ drw_text(drw, x, 0, m->ww - x, bh, 0, "", 0); /* to keep right padding clean */ + } + + for (c = m->clients; c; c = c->next) { +@@ -728,7 +766,7 @@ + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + +- if ((w = m->ww - sw - x) > bh) { ++ if ((w = m->ww - wstext - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +@@ -1122,8 +1160,11 @@ + Monitor *m; + XMotionEvent *ev = &e->xmotion; + +- if (ev->window != root) ++ if (ev->window != root) { ++ if (ev->window == selmon->barwin) ++ updatebarcursor(ev->x); + return; ++ } + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; +@@ -1564,6 +1605,7 @@ + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); ++ cursor[CurHand] = drw_cur_create(drw, XC_hand2); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ +@@ -1637,6 +1679,28 @@ + } + + void ++sigdwmblocks(const Arg *arg) ++{ ++ int fd; ++ struct flock fl; ++ union sigval sv; ++ ++ if (dwmblockssig <= 0 || dwmblockssig >= 10) ++ return; ++ sv.sival_int = (dwmblockssig << 8) | arg->i; ++ fd = open(DWMBLOCKSLOCKFILE, O_RDONLY); ++ if (fd == -1) ++ return; ++ fl.l_type = F_WRLCK; ++ fl.l_start = 0; ++ fl.l_whence = SEEK_SET; ++ fl.l_len = 0; ++ if (fcntl(fd, F_GETLK, &fl) == -1 || fl.l_type == F_UNLCK) ++ return; ++ sigqueue(fl.l_pid, SIGRTMIN, sv); ++} ++ ++void + spawn(const Arg *arg) + { + if (arg->v == dmenucmd) +@@ -1805,7 +1869,7 @@ + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, +- .event_mask = ButtonPressMask|ExposureMask ++ .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { +@@ -1821,6 +1885,33 @@ + } + + void ++updatebarcursor(int cursorpos) ++{ ++ static int currentcursor = 0; ++ int x; ++ ++ if (BETWEEN(cursorpos, (x = selmon->ww - wstext + lrpad / 2), x + wstext - lrpad)) { ++ updatedwmblockssig(x, cursorpos); ++ if (currentcursor) { ++ if (dwmblockssig <= 0 || dwmblockssig >= 10) { ++ currentcursor = 0; ++ XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); ++ } ++ } else { ++ if (dwmblockssig > 0 && dwmblockssig < 10) { ++ currentcursor = 1; ++ XDefineCursor(dpy, selmon->barwin, cursor[CurHand]->cursor); ++ } ++ } ++ } else { ++ if (currentcursor) { ++ currentcursor = 0; ++ XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); ++ } ++ } ++} ++ ++void + updatebarpos(Monitor *m) + { + m->wy = m->my; +@@ -1847,6 +1938,31 @@ + (unsigned char *) &(c->win), 1); + } + ++void ++updatedwmblockssig(int x, int e) ++{ ++ char *ts = stexts; ++ char *tp = stexts; ++ char ctmp; ++ ++ while (*ts) { ++ if ((unsigned char)*ts > 10) { ++ ts++; ++ continue; ++ } ++ ctmp = *ts; ++ *ts = '\0'; ++ x += TTEXTW(tp); ++ *ts = ctmp; ++ if (x >= e) { ++ dwmblockssig = (unsigned char)ctmp; ++ return; ++ } ++ tp = ++ts; ++ } ++ dwmblockssig = 0; ++} ++ + int + updategeom(void) + { +@@ -1987,9 +2103,28 @@ + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) +- strcpy(stext, "dwm-"VERSION); +- drawbar(selmon); ++ char rawstext[256]; ++ ++ if (gettextprop(root, XA_WM_NAME, rawstext, sizeof rawstext)) { ++ int i = -1, j = 0, k = 0, l = 0; ++ char stextf[256]; ++ ++ while (rawstext[++i]) { ++ if ((unsigned char)rawstext[i] >= ' ') ++ stextf[j++] = stextc[k++] = stexts[l++] = rawstext[i]; ++ else if ((unsigned char)rawstext[i] > 10) ++ stextc[k++] = rawstext[i]; ++ else ++ stexts[l++] = rawstext[i]; ++ } ++ stextf[j] = stextc[k] = stexts[l] = '\0'; ++ wstext = TEXTW(stextf); ++ } else { ++ strcpy(stextc, "dwm-"VERSION); ++ strcpy(stexts, stextc); ++ wstext = TEXTW(stextc); ++ } ++ drawbar(selmon); + } + + void diff --git a/sigdwmblocks.c b/sigdwmblocks.c new file mode 100644 index 0000000..711335e --- /dev/null +++ b/sigdwmblocks.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include + +#define LOCKFILE "/tmp/dwmblocks.pid" + +void +sendsignal(int signum, union sigval sv) +{ + int fd; + struct flock fl; + + fd = open(LOCKFILE, O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) { + fputs("Error: no running instance of dwmblocks.", stderr); + exit(2); + } + perror("sendsignal - fd"); + exit(1); + } + fl.l_type = F_WRLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + if (fcntl(fd, F_GETLK, &fl) == -1) { + perror("sendsignal - fcntl"); + exit(1); + } + if (fl.l_type == F_UNLCK) { + fputs("Error: no running instance of dwmblocks.", stderr); + exit(2); + } + if (sigqueue(fl.l_pid, signum, sv) == -1) { + if (errno == EINVAL) { + fputs("Error: invalid signal provided in argument.", stderr); + exit(3); + } else if (errno == ESRCH) { + fputs("Error: no running instance of dwmblocks.", stderr); + exit(2); + } else { + perror("sendsignal - sigqueue"); + exit(1); + } + } +} + +int +main(int argc, char *argv[]) +{ + if (argc > 1) { + int signal; + union sigval sv; + + if (sscanf(argv[1], "%d", &signal) == 1 && + signal > 0 && (signal += SIGRTMIN) <= SIGRTMAX) { + if (argc == 2) { + sv.sival_int = 0; + sendsignal(signal, sv); + return 0; + } else if (argc == 3 && + sscanf(argv[2], "%d", &(sv.sival_int)) == 1) { + sendsignal(signal, sv); + return 0; + } + } + } + + fprintf(stderr, "Usage: %s signal [sigval]\n", argv[0]); + return 3; +} diff --git a/xgetrootname b/xgetrootname new file mode 100755 index 0000000..cc56a04 Binary files /dev/null and b/xgetrootname differ diff --git a/xgetrootname.c b/xgetrootname.c new file mode 100644 index 0000000..532484f --- /dev/null +++ b/xgetrootname.c @@ -0,0 +1,23 @@ +#include +#include + +int +main() +{ + Display *dpy; + Window root; + char *name; + + if (!(dpy = XOpenDisplay(NULL))) { + fputs("Error: could not open display.\n", stderr); + return 1; + } + root = RootWindow(dpy, DefaultScreen(dpy)); + if (XFetchName(dpy, root, &name) && name[0]) + printf("%s\n", name); + else + puts("No name has been set for the root window."); + XFree(name); + XCloseDisplay(dpy); + return 0; +}