From ad879884b77878e147fe138e22c2e7dc5af196aa Mon Sep 17 00:00:00 2001 From: tiyn Date: Sat, 14 Oct 2023 00:36:33 +0200 Subject: [PATCH] updated version to be based on utkarsh vermas dwmblocks --- Makefile | 67 +++++++++------ README.md | 40 ++++----- blocks.def.h | 15 ---- blocks.h | 15 ---- build/bar.o | Bin 0 -> 2648 bytes build/block.o | Bin 0 -> 4432 bytes build/config.o | Bin 0 -> 3016 bytes build/dwmblocks | Bin 0 -> 24112 bytes build/main.o | Bin 0 -> 7472 bytes build/util.o | Bin 0 -> 1808 bytes build/x11.o | Bin 0 -> 2064 bytes config.c | 16 ++++ config.h | 6 ++ dwmblocks.c | 213 ------------------------------------------------ inc/bar.h | 15 ++++ inc/block.h | 17 ++++ inc/util.h | 8 ++ inc/x11.h | 5 ++ src/bar.c | 62 ++++++++++++++ src/block.c | 72 ++++++++++++++++ src/main.c | 157 +++++++++++++++++++++++++++++++++++ src/util.c | 41 ++++++++++ src/x11.c | 25 ++++++ 23 files changed, 484 insertions(+), 290 deletions(-) delete mode 100644 blocks.def.h delete mode 100644 blocks.h create mode 100644 build/bar.o create mode 100644 build/block.o create mode 100644 build/config.o create mode 100755 build/dwmblocks create mode 100644 build/main.o create mode 100644 build/util.o create mode 100644 build/x11.o create mode 100644 config.c create mode 100644 config.h delete mode 100644 dwmblocks.c create mode 100644 inc/bar.h create mode 100644 inc/block.h create mode 100644 inc/util.h create mode 100644 inc/x11.h create mode 100644 src/bar.c create mode 100644 src/block.c create mode 100644 src/main.c create mode 100644 src/util.c create mode 100644 src/x11.c diff --git a/Makefile b/Makefile index 75109ac..6fab7cd 100644 --- a/Makefile +++ b/Makefile @@ -1,36 +1,53 @@ -PREFIX := /usr/local -CC := cc -CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os -LDFLAGS := -lX11 +.POSIX: -# FreeBSD (uncomment) -#LDFLAGS += -L/usr/local/lib -I/usr/local/include -# # OpenBSD (uncomment) -#LDFLAGS += -L/usr/X11R6/lib -I/usr/X11R6/include +BIN := dwmblocks +BUILD_DIR := build +SRC_DIR := src +INC_DIR := inc -all: options dwmblocks +VERBOSE := 0 -options: - @echo dwmblocks build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" +PREFIX := /usr/local +CFLAGS := -Wall -Wextra -Ofast -I. -I$(INC_DIR) +CFLAGS += -Wall -Wextra -Wno-missing-field-initializers +LDLIBS := -lX11 -dwmblocks: dwmblocks.c blocks.def.h blocks.h - ${CC} -o dwmblocks dwmblocks.c ${CFLAGS} ${LDFLAGS} +VPATH := $(SRC_DIR) +OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(wildcard $(SRC_DIR)/*.c)) +OBJS += $(patsubst %.c,$(BUILD_DIR)/%.o,$(wildcard *.c)) -blocks.h: - cp blocks.def.h $@ +INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin + +# Prettify output +PRINTF := @printf "%-8s %s\n" +ifeq ($(VERBOSE), 0) + Q := @ +endif + +all: $(BUILD_DIR)/$(BIN) + +$(BUILD_DIR)/$(BIN): $(OBJS) + $(PRINTF) "LD" $@ + $Q$(LINK.o) $^ $(LDLIBS) -o $@ + +$(BUILD_DIR)/%.o: %.c config.h | $(BUILD_DIR) + $(PRINTF) "CC" $@ + $Q$(COMPILE.c) -o $@ $< + +$(BUILD_DIR): + $(PRINTF) "MKDIR" $@ + $Qmkdir -p $@ clean: - rm -f *.o *.gch dwmblocks + $(PRINTF) "CLEAN" $(BUILD_DIR) + $Q$(RM) $(BUILD_DIR)/* -install: dwmblocks - mkdir -p ${DESTDIR}${PREFIX}/bin - cp -f dwmblocks ${DESTDIR}${PREFIX}/bin - chmod 755 ${DESTDIR}${PREFIX}/bin/dwmblocks +install: $(BUILD_DIR)/$(BIN) + $(PRINTF) "INSTALL" $(INSTALL_DIR)/$(BIN) + $Qinstall -D -m 755 $< $(INSTALL_DIR)/$(BIN) uninstall: - rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks + $(PRINTF) "RM" $(INSTALL_DIR)/$(BIN) + $Q$(RM) $(INSTALL_DIR)/$(BIN) -.PHONY: all options clean install uninstall +.PHONY: all clean install uninstall diff --git a/README.md b/README.md index e245aa8..627fdcd 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,36 @@ # dwmblocks Modular status bar for dwm written in c. -This build is based on [lukesmithxyz's](https://github.com/lukesmithxyz) build. -It uses my personal scripts you can find in my [dotfiles](https://github.com/tiyn/.dotfiles) in the `~/.local/bin/tools/statusbar` folder. +This build is based on [Utkarsh Vermas](https://github.com/UtkarshVerma/dwmblocks-async) build. +It uses my personal scripts you can find in my [dotfiles](https://github.com/tiyn/.dotfiles) in the +`~/.local/bin/tools/statusbar` folder. # Modifying blocks The statusbar is made from text output from commandline programs. Blocks are -added and removed by editing the config.h file. +added and removed by editing the config.c file. # Signaling changes Most statusbars constantly rerun every script every several seconds to update. -This is an option here, but a superior choice is giving your module a signal -that you can signal to it to update on a relevant event, rather than having it -rerun idly. +This is an option here, but a superior choice is giving your module a signal that you can signal to +it to update on a relevant event, rather than having it rerun idly. -For example, the audio module has the update signal 10 by default. Thus, -running `pkill -RTMIN+10 dwmblocks` will update it. +For example, the audio module has the update signal 10 by default. +Thus, running `pkill -RTMIN+10 dwmblocks` will update it. -You can also run `kill -44 $(pidof dwmblocks)` which will have the same effect, -but is faster. Just add 34 to your typical signal number. +You can also run `kill -44 $(pidof dwmblocks)` which will have the same effect, but is faster. +Just add 34 to your typical signal number. -My volume module *never* updates on its own, instead I have this command run -along side my volume shortcuts in dwm to only update it when relevant. +My volume module *never* updates on its own, instead I have this command run along side my volume +shortcuts in dwm to only update it when relevant. -Note that if you signal an unexpected signal to dwmblocks, it will probably -crash. So if you disable a module, remember to also disable any cronjobs or -other scripts that might signal to that module. +Note that if you signal an unexpected signal to dwmblocks, it will probably crash. +So if you disable a module, remember to also disable any cronjobs or other scripts that might signal +to that module. # Clickable modules -Like i3blocks, this build allows you to build in additional actions into your -scripts in response to click events. See the above linked scripts for examples -of this using the `$BLOCK_BUTTON` variable. - -For this feature to work, you need the appropriate patch in dwm as well. See -[here](https://dwm.suckless.org/patches/statuscmd/). -Credit for those patches goes to Daniel Bylinka (daniel.bylinka@gmail.com). +Like i3blocks, this build allows you to build in additional actions into your scripts in response +to click events. +See the above linked scripts for examples of this using the `$BLOCK_BUTTON` variable. diff --git a/blocks.def.h b/blocks.def.h deleted file mode 100644 index d0a1436..0000000 --- a/blocks.def.h +++ /dev/null @@ -1,15 +0,0 @@ -//Modify this file to change what commands output to your statusbar, and recompile using the make command. -static const Block blocks[] = { - /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/ - {"", "memory", 10, 6}, - {"", "cpu", 10, 5}, - {"", "disk /", 1800, 7}, - {"", "volume", 0, 4}, - {"", "battery BAT0", 5, 2}, - {"", "internet", 5, 3}, - {"", "clock", 60, 1}, -}; - -//sets delimeter between status commands. NULL character ('\0') means no delimeter. -static char delim[] = "|"; -static unsigned int delimLen = 5; diff --git a/blocks.h b/blocks.h deleted file mode 100644 index d0a1436..0000000 --- a/blocks.h +++ /dev/null @@ -1,15 +0,0 @@ -//Modify this file to change what commands output to your statusbar, and recompile using the make command. -static const Block blocks[] = { - /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/ - {"", "memory", 10, 6}, - {"", "cpu", 10, 5}, - {"", "disk /", 1800, 7}, - {"", "volume", 0, 4}, - {"", "battery BAT0", 5, 2}, - {"", "internet", 5, 3}, - {"", "clock", 60, 1}, -}; - -//sets delimeter between status commands. NULL character ('\0') means no delimeter. -static char delim[] = "|"; -static unsigned int delimLen = 5; diff --git a/build/bar.o b/build/bar.o new file mode 100644 index 0000000000000000000000000000000000000000..ae8e081e2cd8cd30c6e6d4dfbafcc20c9666f7ac GIT binary patch literal 2648 zcmb_dO>7%Q6n<;Ft!dJ=K?NDLsEaTtNMUhOB%m$eO=3ER&_+pvs)h*G&bkTlpVnj1 z6rmQG7Ofmh5nMQMs5o&#xs?NlpwMuwI3j_1K@^Hqac)s~Z+6CAt=1RBlV<0=?|tvh zo0+$}mkQIb$21L;Xz(gLuoMcA+4n%t3pEc1U>H)@A0^8=Gtaz#n0J${{&a4xHSbZt`~5a~ab{itn71v=oj9t6*prDCRzd_p{^Y|Jt59_zj)c&z(ja^Vkw z_Zil_b*AXupPyr$zmlx`BI{mC3UaZV$YRFS^*tis$`-G7ZfmUf1evUNFhAWJ-C(`W zO*D(&|CT6fH|{)M*({&SzA-T2lpuuj~~ zP9X-wxbt1=NFFtwO%}T+vaIt%lD1_nipps}B0CoJRHgF@RRgShyuH`oS$Ka7+i-Gn z@|ZDl^3?pZ#@JDF+#EB;bK^&IFXhHCG=amwLAyi>#6a63Oo=9Kb%zI~L%TQ&+J&@s zXn0?81Dzv?AC|sJnu~gRJ!a{dtMNB=qmy`F&schTLQkSAgM$$V+vbwxSFu^k zEPS3GvP6DzMG5UM0e|mC`Qi~BOzrzf02g}}7(hBA3AIfWPIXhB85twa1NG+z@acSr z-<14KIa>qxbk0%ho*sa|Jpf-EfYV)3J%(%$arTH&eNpRP9Dsj10Ed$8nq^q2ukbl; z^L7hL)kb-BveB+{sM%FCpyE1?bdn0~=90}7(&BEpx#mZ;fGnHSRCVgYsx{#Qcco8X za!T#qr|D6Asj0Ip8LkPu)_*vV=K%Uto)ZC_`a(Wp%Efs~&NP9ViH>G_ogsVOUv$a;^ zb_r+h`t!2VT&HTA+_}KP#745gEVWu-mK(L2gH31F8{9GRTlrjz+vQbhpRc#grrT&b zE?)yvWN?<>t+>=Y|A!cugpO)&C|O?Gv+^93o6a~WhtQzA$_GKzZxM*HEaRz%NTnVi zp>H+GGdKuW{ZAOlXQ6d{)aNRl=20A!^S{Q^zlxU1;RuRaU;TTOPnD(SW9U%2;?Vp} z6d1vM12O9JU@xKxn=(FJmpVVLXL8pknI~lxEl;ADoy%#ldmxd~0vVkLSqR3fzjyn)g-j4)1H;wsDLLPYIX4 zRAr$zxx3QJ7>-EJ#G_cWG5Kuezq6wcpTsTX%#c2OK+OGjmO^^@dWg{(6(bS4?|5qE zUOsx+sZzqtZ>$o=N`=szheC}m(nrQ-6rVm^naN~iQ25$w@yVaB{GG`_ys{aWb&v(w z5)kid?Wgthr?CI6SmW{l?J3E5dZ0XS3Ok+}D1-6PRR=%(xzj1D+6psYKF&`~zo7Xo zAHD13`iaR?u({0F=|`=k+fQA*csh6EVhPw$oo{n}Q(IkYOUveF7GpbFpUl69_rRxDOs3gsWIC5NaZiGYlS-oLtj_ zU@RAqbwx~pJr1ozXw3Xtm4`Rw;Wc^qQ+fEhJRFW@&i!o4!(Yh5x98z)d3bvs-kpcP z1svn)!9;_Ix`Tc{v|RCg54g}TgaL@CE$ELx%ccKO9?o`lhXY-%01Ng713nlsm#@AW zzuW@V;k2a`W1(=gi?zoiH7pi1g1v9BNH`MgWuaX`BgP_u?rd%Iz_!)#CsE=n*@k*OL?m)65lbRhju|8B`K4zx}@gws0NL^#!NCH`sNw-bGu z_kO}@-VYE?^Zp^>H19_Ur+NRFa2o%Ml4D2Xb}bM8jrgJQTqN%+d;KgSoUXf!a9SsB z!m0im!fCzr5?%)Hpz3gl@P`OLAUVDU&HD+$aj5)!Mf}ipD?kSY{m77rXP@}aa&_+? zwsYy1xnli2hJPpYM%3y%)F>M4_PdN=pTS&kbNZQUXDr5C(J(%sy4&Suu0Xh_CkVHz zt2b-}UGP_GmAH)M^RC{wD-wmxw1uMno}k>&|LiKj9*-E-I2Dh4xTxM! zKHGo876Zqc@yL1Ay@bgD`2;6H@XX;l5;M#-3jQxaZd-({5iT z?d@*t&u*|qpEb~^D0@7!RMh&a_rN5MtEm!{Q1!z8MDs1l5e@Nxvew z`OmdBn$*g_yb-xE{7uI9wA-Ukd+q_TW2g)=Vs+Es_W0o)o6G)rx&MJ_OKV`a{|7z~ BfkprT literal 0 HcmV?d00001 diff --git a/build/config.o b/build/config.o new file mode 100644 index 0000000000000000000000000000000000000000..a334f9027838bb0a43ceeb1d6ed60dc41b402003 GIT binary patch literal 3016 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 literal 0 HcmV?d00001 diff --git a/build/util.o b/build/util.o new file mode 100644 index 0000000000000000000000000000000000000000..558a9d8c80cff71e9074dffccace1653fd734a56 GIT binary patch literal 1808 zcmbtUO=uHQ5PmO>Hm0!~MKn;Mdr(o(C20j~DVn8!QEDk_@lgCp(@k4UnviTERWOw# zhouyHum^7*3xdZUJmm-4>Ori67f;@*xu{@mtq^B6Z*02cqyzKjn{Q^`n|v8ZP~oESm<&}i^c4^lzj%NzD-{x z_fg6|0W7ulFlH29V!Mw&<#FAfg%z7&JfA6YqfpDI%lt!Tl?Os^uFbm~0pqnQE%R(% zl@?1~PFRb*+4s8r;!gUxy29n$W~v2p%2L=oCy@EVGruajq|SD^W&NwV(&OfAq!d^! zRzS#ASD5U3RbFBJ-QAt?>HfjtGqSH;X;XZ1o42jq+u`*=hah%P8FU{gWHB3bj2sCU zKF#8Y2=E8j8Be)+i>uMG06{nK$3^UnO*Z`s8!{A2VWh3~fHwSbRz>9_D3 zcrhS!UrxZd6}}G?e6uL0K#{NcyFr@WvYcy@uvqD{z~P?%T8}?Z+>`nQXbPQAzcu3N ze6pPoAWS)Ell90txmST}1Qpi>s46K@Z|#fjkMc$VV5+r#Nz}(FQCMsJZQ$$8&m%50 zAnI^_SWERZzj|k5iAOZFgbqj(C~j%3KOlH8dn7OF>HmX*;7E)nOPUFz6;7MZyy8 zb{+Yp*e%g%>LX`!FJ~Y81mkR-h|RlpG~!fuzJvPwquc4+LE72ARZt4M?QDL{ed!;X zB>IHO;&3^Ro$VV;&@Vjthe~mOXX}r%eGQDtCetNK)W&M$8PnzRggHDt`*6gx$E;Dy zHb;x2W5w~J9jCDklLwZ{BI+Qco!T1jJ&ENVoMRneyq+Uty9Cl9UiK$@#<6AT%Syk%7Kq;mThwRiA0NZh zx@}ukT3QKPb$5dT-;W-xG?)BW6nfEWt3s7~Ew4GL($%^jdd!t!g=Ar6j_YRKhDVk8 z$Pc{4ovN>fHJ%s1`vdT%;Qu{HkO#@=;L*uL-eeIZLwM28C-fmN`sW%i`j;9n`ZdKP z?&Tr+H^=BJDgCLG{(XwanMog0@mN2Gprjn(abCcK#KcNgr*lewlJc^2Q%t6}6;U#R$5bJc1Ee#;A@4YJ}6UhU~} zfV2A_Fu4it+)1rjNyQ&EUjJ4HIgc|bX}V#29E|^ z3vC)#I6zOmepiX~^~(Ix1Aj^MEDE8l)XP6l(lWo;2~LPF8rZ#bkn(ly4Cipa(%&59 z`*<+)b?NJ0WDR=i^`@Grh9)WK^-nmLb$$ct;yJ1o=Z9LUm-EY-8zmpq{Nu{v&f*)> i>v1>rvtx?dYD3sx8miqPb%wpH`USQA`k^v$^!k4^SHn>N literal 0 HcmV?d00001 diff --git a/config.c b/config.c new file mode 100644 index 0000000..408d28b --- /dev/null +++ b/config.c @@ -0,0 +1,16 @@ +#include "config.h" + +#include "block.h" +#include "util.h" + +Block blocks[] = { + {"memory", 10, 6}, + {"cpu", 10, 5}, + {"disk /", 1800, 7}, + {"volume", 0, 4}, + {"battery BAT0", 5, 2}, + {"internet", 5, 3}, + {"clock", 60, 1}, +}; + +const unsigned short blockCount = LEN(blocks); diff --git a/config.h b/config.h new file mode 100644 index 0000000..8f47394 --- /dev/null +++ b/config.h @@ -0,0 +1,6 @@ +#pragma once + +#define CLICKABLE_BLOCKS 0 // Enable clickability for blocks +#define CMDLENGTH 45 // Trim block output to this length +#define DELIMITER " " // Delimiter string used to separate blocks +#define LEADING_DELIMITER 0 // Whether a leading separator should be used diff --git a/dwmblocks.c b/dwmblocks.c deleted file mode 100644 index 19df6d0..0000000 --- a/dwmblocks.c +++ /dev/null @@ -1,213 +0,0 @@ -#include -#include -#include -#include -#include -#ifndef NO_X -#include -#endif -#ifdef __OpenBSD__ -#define SIGPLUS SIGUSR1+1 -#define SIGMINUS SIGUSR1-1 -#else -#define SIGPLUS SIGRTMIN -#define SIGMINUS SIGRTMIN -#endif -#define LENGTH(X) (sizeof(X) / sizeof (X[0])) -#define CMDLENGTH 50 -#define MIN( a, b ) ( ( a < b) ? a : b ) -#define STATUSLENGTH (LENGTH(blocks) * CMDLENGTH + 1) - -typedef struct { - char* icon; - char* command; - unsigned int interval; - unsigned int signal; -} Block; -#ifndef __OpenBSD__ -void dummysighandler(int num); -#endif -void sighandler(int num); -void getcmds(int time); -void getsigcmds(unsigned int signal); -void setupsignals(); -void sighandler(int signum); -int getstatus(char *str, char *last); -void statusloop(); -void termhandler(); -void pstdout(); -#ifndef NO_X -void setroot(); -static void (*writestatus) () = setroot; -static int setupX(); -static Display *dpy; -static int screen; -static Window root; -#else -static void (*writestatus) () = pstdout; -#endif - - -#include "blocks.h" - -static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; -static char statusstr[2][STATUSLENGTH]; -static int statusContinue = 1; -static int returnStatus = 0; - -//opens process *cmd and stores output in *output -void getcmd(const Block *block, char *output) -{ - strcpy(output, block->icon); - FILE *cmdf = popen(block->command, "r"); - if (!cmdf) - return; - int i = strlen(block->icon); - fgets(output+i, CMDLENGTH-i-delimLen, cmdf); - i = strlen(output); - if (i == 0) { - //return if block and command output are both empty - pclose(cmdf); - return; - } - //only chop off newline if one is present at the end - i = output[i-1] == '\n' ? i-1 : i; - if (delim[0] != '\0') { - strncpy(output+i, delim, delimLen); - } - else - output[i++] = '\0'; - pclose(cmdf); -} - -void getcmds(int time) -{ - const Block* current; - for (unsigned int i = 0; i < LENGTH(blocks); i++) { - current = blocks + i; - if ((current->interval != 0 && time % current->interval == 0) || time == -1) - getcmd(current,statusbar[i]); - } -} - -void getsigcmds(unsigned int signal) -{ - const Block *current; - for (unsigned int i = 0; i < LENGTH(blocks); i++) { - current = blocks + i; - if (current->signal == signal) - getcmd(current,statusbar[i]); - } -} - -void setupsignals() -{ -#ifndef __OpenBSD__ - /* initialize all real time signals with dummy handler */ - for (int i = SIGRTMIN; i <= SIGRTMAX; i++) - signal(i, dummysighandler); -#endif - - for (unsigned int i = 0; i < LENGTH(blocks); i++) { - if (blocks[i].signal > 0) - signal(SIGMINUS+blocks[i].signal, sighandler); - } - -} - -int getstatus(char *str, char *last) -{ - strcpy(last, str); - str[0] = '\0'; - for (unsigned int i = 0; i < LENGTH(blocks); i++) - strcat(str, statusbar[i]); - str[strlen(str)-strlen(delim)] = '\0'; - return strcmp(str, last);//0 if they are the same -} - -#ifndef NO_X -void setroot() -{ - if (!getstatus(statusstr[0], statusstr[1]))//Only set root if text has changed. - return; - XStoreName(dpy, root, statusstr[0]); - XFlush(dpy); -} - -int setupX() -{ - dpy = XOpenDisplay(NULL); - if (!dpy) { - fprintf(stderr, "dwmblocks: Failed to open display\n"); - return 0; - } - screen = DefaultScreen(dpy); - root = RootWindow(dpy, screen); - return 1; -} -#endif - -void pstdout() -{ - if (!getstatus(statusstr[0], statusstr[1]))//Only write out if text has changed. - return; - printf("%s\n",statusstr[0]); - fflush(stdout); -} - - -void statusloop() -{ - setupsignals(); - int i = 0; - getcmds(-1); - while (1) { - getcmds(i++); - writestatus(); - if (!statusContinue) - break; - sleep(1.0); - } -} - -#ifndef __OpenBSD__ -/* this signal handler should do nothing */ -void dummysighandler(int signum) -{ - return; -} -#endif - -void sighandler(int signum) -{ - getsigcmds(signum-SIGPLUS); - writestatus(); -} - -void termhandler() -{ - statusContinue = 0; -} - -int main(int argc, char** argv) -{ - for (int i = 0; i < argc; i++) {//Handle command line arguments - if (!strcmp("-d",argv[i])) - strncpy(delim, argv[++i], delimLen); - else if (!strcmp("-p",argv[i])) - writestatus = pstdout; - } -#ifndef NO_X - if (!setupX()) - return 1; -#endif - delimLen = MIN(delimLen, strlen(delim)); - delim[delimLen++] = '\0'; - signal(SIGTERM, termhandler); - signal(SIGINT, termhandler); - statusloop(); -#ifndef NO_X - XCloseDisplay(dpy); -#endif - return 0; -} diff --git a/inc/bar.h b/inc/bar.h new file mode 100644 index 0000000..377886e --- /dev/null +++ b/inc/bar.h @@ -0,0 +1,15 @@ +#pragma once +#include "block.h" +#include "config.h" +#include "util.h" + +typedef struct { + char *current; + char *previous; +} BarStatus; + +extern unsigned short debugMode; + +void initStatus(BarStatus *); +void freeStatus(BarStatus *); +void writeStatus(BarStatus *); diff --git a/inc/block.h b/inc/block.h new file mode 100644 index 0000000..f0d264c --- /dev/null +++ b/inc/block.h @@ -0,0 +1,17 @@ +#pragma once +#include "config.h" + +typedef struct { + const char *command; + const unsigned int interval; + const unsigned int signal; + int pipe[2]; + char output[CMDLENGTH * 4 + 1]; +} Block; + +extern Block blocks[]; +extern const unsigned short blockCount; + +void execBlock(const Block *, const char *); +void execBlocks(unsigned int); +void updateBlock(Block *); diff --git a/inc/util.h b/inc/util.h new file mode 100644 index 0000000..bfc030d --- /dev/null +++ b/inc/util.h @@ -0,0 +1,8 @@ +#pragma once + +#define LEN(arr) (sizeof(arr) / sizeof(arr[0])) +#define MAX(a, b) (a > b ? a : b) + +int gcd(int, int); +void closePipe(int[2]); +void trimUTF8(char*, unsigned int); diff --git a/inc/x11.h b/inc/x11.h new file mode 100644 index 0000000..abb4f0f --- /dev/null +++ b/inc/x11.h @@ -0,0 +1,5 @@ +#pragma once + +int setupX(); +int closeX(); +void setXRootName(char *); diff --git a/src/bar.c b/src/bar.c new file mode 100644 index 0000000..9f8261c --- /dev/null +++ b/src/bar.c @@ -0,0 +1,62 @@ +#include "bar.h" + +#include +#include +#include + +#include "block.h" +#include "x11.h" + +void initStatus(BarStatus *status) { + const unsigned int statusLength = + (blockCount * (LEN(blocks[0].output) - 1)) + + (blockCount - 1 + LEADING_DELIMITER) * (LEN(DELIMITER) - 1); + + status->current = (char *)malloc(statusLength); + status->previous = (char *)malloc(statusLength); + status->current[0] = '\0'; + status->previous[0] = '\0'; +} + +void freeStatus(BarStatus *status) { + free(status->current); + free(status->previous); +} + +int updateStatus(BarStatus *status) { + strcpy(status->previous, status->current); + status->current[0] = '\0'; + + for (int i = 0; i < blockCount; i++) { + Block *block = blocks + i; + + if (strlen(block->output)) { +#if LEADING_DELIMITER + strcat(status->current, DELIMITER); +#else + if (status->current[0]) strcat(status->current, DELIMITER); +#endif + +#if CLICKABLE_BLOCKS + if (!debugMode && block->signal) { + char signal[] = {block->signal, '\0'}; + strcat(status->current, signal); + } +#endif + + strcat(status->current, block->output); + } + } + return strcmp(status->current, status->previous); +} + +void writeStatus(BarStatus *status) { + // Only write out if status has changed + if (!updateStatus(status)) return; + + if (debugMode) { + printf("%s\n", status->current); + return; + } + setXRootName(status->current); +} diff --git a/src/block.c b/src/block.c new file mode 100644 index 0000000..ae50ea5 --- /dev/null +++ b/src/block.c @@ -0,0 +1,72 @@ +#include "block.h" + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "util.h" + +static int execLock = 0; + +void execBlock(const Block *block, const char *button) { + unsigned short i = block - blocks; + + // Ensure only one child process exists per block at an instance + if (execLock & 1 << i) return; + // Lock execution of block until current instance finishes execution + execLock |= 1 << i; + + if (fork() == 0) { + close(block->pipe[0]); + dup2(block->pipe[1], STDOUT_FILENO); + close(block->pipe[1]); + + if (button) setenv("BLOCK_BUTTON", button, 1); + + FILE *file = popen(block->command, "r"); + if (!file) { + printf("\n"); + exit(EXIT_FAILURE); + } + + // Buffer will hold both '\n' and '\0' + char buffer[LEN(block->output) + 1]; + if (fgets(buffer, LEN(buffer), file) == NULL) { + // Send an empty line in case of no output + printf("\n"); + exit(EXIT_SUCCESS); + } + pclose(file); + + // Trim to the max possible UTF-8 capacity + trimUTF8(buffer, LEN(buffer)); + + printf("%s\n", buffer); + exit(EXIT_SUCCESS); + } +} + +void execBlocks(unsigned int time) { + for (int i = 0; i < blockCount; i++) { + const Block *block = blocks + i; + if (time == 0 || + (block->interval != 0 && time % block->interval == 0)) { + execBlock(block, NULL); + } + } +} + +void updateBlock(Block *block) { + char buffer[LEN(block->output)]; + int bytesRead = read(block->pipe[0], buffer, LEN(buffer)); + + // String from pipe will always end with '\n' + buffer[bytesRead - 1] = '\0'; + + strcpy(block->output, buffer); + + // Remove execution lock for the current block + execLock &= ~(1 << (block - blocks)); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..8b87b63 --- /dev/null +++ b/src/main.c @@ -0,0 +1,157 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "bar.h" +#include "block.h" +#include "util.h" +#include "x11.h" + +static unsigned short statusContinue = 1; +unsigned short debugMode = 0; +static int epollFD, signalFD; +static unsigned int timerTick = 0, maxInterval = 1; + +void signalHandler() { + struct signalfd_siginfo info; + read(signalFD, &info, sizeof(info)); + unsigned int signal = info.ssi_signo; + + static unsigned int timer = 0; + switch (signal) { + case SIGALRM: + // Schedule the next timer event and execute blocks + alarm(timerTick); + execBlocks(timer); + + // Wrap `timer` to the interval [1, `maxInterval`] + timer = (timer + timerTick - 1) % maxInterval + 1; + return; + case SIGUSR1: + // Update all blocks on receiving SIGUSR1 + execBlocks(0); + return; + } + + for (int j = 0; j < blockCount; j++) { + const Block *block = blocks + j; + if (block->signal == signal - SIGRTMIN) { + char button[4]; // value can't be more than 255; + sprintf(button, "%d", info.ssi_int & 0xff); + execBlock(block, button); + break; + } + } +} + +void termHandler() { + statusContinue = 0; +} + +void setupSignals() { + sigset_t handledSignals; + sigemptyset(&handledSignals); + sigaddset(&handledSignals, SIGUSR1); + sigaddset(&handledSignals, SIGALRM); + + // Append all block signals to `handledSignals` + for (int i = 0; i < blockCount; i++) + if (blocks[i].signal > 0) + sigaddset(&handledSignals, SIGRTMIN + blocks[i].signal); + + // Create a signal file descriptor for epoll to watch + signalFD = signalfd(-1, &handledSignals, 0); + + // Block all realtime and handled signals + for (int i = SIGRTMIN; i <= SIGRTMAX; i++) sigaddset(&handledSignals, i); + sigprocmask(SIG_BLOCK, &handledSignals, NULL); + + // Handle termination signals + signal(SIGINT, termHandler); + signal(SIGTERM, termHandler); + + // Avoid zombie subprocesses + struct sigaction signalAction; + signalAction.sa_handler = SIG_DFL; + sigemptyset(&signalAction.sa_mask); + signalAction.sa_flags = SA_NOCLDWAIT; + sigaction(SIGCHLD, &signalAction, 0); +} + +void statusLoop() { + // Update all blocks initially + raise(SIGALRM); + + BarStatus status; + initStatus(&status); + struct epoll_event events[blockCount + 1]; + while (statusContinue) { + int eventCount = epoll_wait(epollFD, events, LEN(events), 100); + for (int i = 0; i < eventCount; i++) { + unsigned short id = events[i].data.u32; + if (id < blockCount) { + updateBlock(blocks + id); + } else { + signalHandler(); + } + } + + if (eventCount != -1) writeStatus(&status); + } + freeStatus(&status); +} + +void init() { + epollFD = epoll_create(blockCount); + struct epoll_event event = { + .events = EPOLLIN, + }; + + for (int i = 0; i < blockCount; i++) { + // Append each block's pipe's read end to `epollFD` + pipe(blocks[i].pipe); + event.data.u32 = i; + epoll_ctl(epollFD, EPOLL_CTL_ADD, blocks[i].pipe[0], &event); + + // Calculate the max interval and tick size for the timer + if (blocks[i].interval) { + maxInterval = MAX(blocks[i].interval, maxInterval); + timerTick = gcd(blocks[i].interval, timerTick); + } + } + + setupSignals(); + + // Watch signal file descriptor as well + event.data.u32 = blockCount; + epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event); +} + +int main(const int argc, const char *argv[]) { + if (setupX()) { + fprintf(stderr, "%s\n", "dwmblocks: Failed to open display"); + return 1; + } + + for (int i = 0; i < argc; i++) { + if (!strcmp("-d", argv[i])) { + debugMode = 1; + break; + } + } + + init(); + statusLoop(); + + if (closeX()) + fprintf(stderr, "%s\n", "dwmblocks: Failed to close display"); + + close(epollFD); + close(signalFD); + for (int i = 0; i < blockCount; i++) closePipe(blocks[i].pipe); + + return 0; +} diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..157e626 --- /dev/null +++ b/src/util.c @@ -0,0 +1,41 @@ +#include "util.h" + +#include + +int gcd(int a, int b) { + int temp; + while (b > 0) { + temp = a % b; + a = b; + b = temp; + } + return a; +} + +void closePipe(int pipe[2]) { + close(pipe[0]); + close(pipe[1]); +} + +void trimUTF8(char* buffer, unsigned int size) { + int length = (size - 1) / 4; + int count = 0, j = 0; + char ch = buffer[j]; + while (ch != '\0' && ch != '\n' && count < length) { + // Skip continuation bytes, if any + int skip = 1; + while ((ch & 0xc0) > 0x80) { + ch <<= 1; + skip++; + } + + j += skip; + ch = buffer[j]; + count++; + } + + // Trim trailing newline and spaces + buffer[j] = ' '; + while (j >= 0 && buffer[j] == ' ') j--; + buffer[j + 1] = '\0'; +} diff --git a/src/x11.c b/src/x11.c new file mode 100644 index 0000000..63c5d14 --- /dev/null +++ b/src/x11.c @@ -0,0 +1,25 @@ +#include "x11.h" + +#include + +static Display *display; +static Window rootWindow; + +int setupX() { + display = XOpenDisplay(NULL); + if (!display) { + return 1; + } + + rootWindow = DefaultRootWindow(display); + return 0; +} + +int closeX() { + return XCloseDisplay(display); +} + +void setXRootName(char *str) { + XStoreName(display, rootWindow, str); + XFlush(display); +}