From cdc992cc41ae082dd31678e04379cfb207a31195 Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Mon, 27 Jun 2022 02:38:11 +0530 Subject: [PATCH 1/7] Refactor X11 part --- main.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index f101146..43f0452 100644 --- a/main.c +++ b/main.c @@ -163,18 +163,23 @@ void debug() { write(STDOUT_FILENO, "\n", 1); } +int setupX() { + dpy = XOpenDisplay(NULL); + if (!dpy) + return 1; + + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + return 0; +} + void setRoot() { // Only set root if text has changed if (!getStatus(statusBar[0], statusBar[1])) return; - Display* d = XOpenDisplay(NULL); - if (d) - dpy = d; - screen = DefaultScreen(dpy); - root = RootWindow(dpy, screen); XStoreName(dpy, root, statusBar[0]); - XCloseDisplay(dpy); + XFlush(dpy); } void signalHandler() { @@ -284,6 +289,11 @@ void init() { } int main(const int argc, const char* argv[]) { + if (setupX()) { + fprintf(stderr, "dwmblocks: Failed to open display\n"); + return 1; + } + writeStatus = setRoot; for (int i = 0; i < argc; i++) if (!strcmp("-d", argv[i])) @@ -292,6 +302,7 @@ int main(const int argc, const char* argv[]) { init(); statusLoop(); + XCloseDisplay(dpy); close(epollFD); close(signalFD); for (int i = 0; i < LEN(pipes); i++) From be46e8a8bd3c79c052427eb4c4622f3b8bc08207 Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sun, 10 Jul 2022 14:15:32 +0530 Subject: [PATCH 2/7] Set session ID for fork. Fixes #28 --- main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 43f0452..d3e707d 100644 --- a/main.c +++ b/main.c @@ -81,8 +81,9 @@ void execBlock(int i, const char* button) { if (button) setenv("BLOCK_BUTTON", button, 1); + setsid(); execl("/bin/sh", "sh", "-c", blocks[i].command, (char*)NULL); - _exit(1); + exit(EXIT_SUCCESS); } } From 39dc44cf8960abb1b9bf09d4db84455ff8fe9a71 Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sun, 10 Jul 2022 14:21:58 +0530 Subject: [PATCH 3/7] Update README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 3bae144..26b3b64 100644 --- a/README.md +++ b/README.md @@ -125,8 +125,6 @@ To use this feature, define the `CLICKABLE_BLOCKS` feature macro in your `config Apart from that, you need `dwm` to be patched with [statuscmd](https://dwm.suckless.org/patches/statuscmd/). -> Earlier, `dwmblocks-async` used to require a patch to be applied to `dwm`. However, the code has been redone so there's no need to apply that patch anymore. - ## Credits This work would not have been possible without [Luke's build of dwmblocks](https://github.com/LukeSmithxyz/dwmblocks) and [Daniel Bylinka's statuscmd patch](https://dwm.suckless.org/patches/statuscmd/). From f1c037037d0ab60b219ca2c39c1beb77371ca2fe Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Wed, 13 Jul 2022 07:51:16 +0530 Subject: [PATCH 4/7] Minor changes --- main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main.c b/main.c index d3e707d..5a5fbfc 100644 --- a/main.c +++ b/main.c @@ -81,9 +81,8 @@ void execBlock(int i, const char* button) { if (button) setenv("BLOCK_BUTTON", button, 1); - setsid(); execl("/bin/sh", "sh", "-c", blocks[i].command, (char*)NULL); - exit(EXIT_SUCCESS); + exit(EXIT_FAILURE); } } @@ -119,7 +118,7 @@ void updateBlock(int i) { while (buffer[j] != '\n' && count < CMDLENGTH) { count++; - // Skip continuation bytes, if any. + // Skip continuation bytes, if any char ch = buffer[j]; int skip = 1; while ((ch & 0xc0) > 0x80) From 098184d0c35c491e1872d10646f6094c122b8f4f Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Wed, 24 Aug 2022 16:34:53 +0200 Subject: [PATCH 5/7] Improve Makefile --- Makefile | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 99db3d6..7557786 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,21 @@ .POSIX: PREFIX = /usr/local -CC = gcc +CFLAGS = -Ofast +LDLIBS = -lX11 + +BIN = dwmblocks + +$(BIN): main.o + $(CC) $^ -o $@ $(LDLIBS) -dwmblocks: main.o - $(CC) main.o -lX11 -Ofast -o dwmblocks -main.o: main.c config.h - $(CC) -Ofast -c main.c clean: - rm -f *.o *.gch dwmblocks -install: dwmblocks - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp -f dwmblocks $(DESTDIR)$(PREFIX)/bin - chmod 755 $(DESTDIR)$(PREFIX)/bin/dwmblocks + $(RM) *.o $(BIN) + +install: $(BIN) + install -D -m 755 $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN) + uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/dwmblocks + $(RM) $(DESTDIR)$(PREFIX)/bin/$(BIN) .PHONY: clean install uninstall From 647080cbededd01aa78476901be7929e5e20bb6c Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sat, 27 Aug 2022 09:27:26 +0200 Subject: [PATCH 6/7] Add .clang-format --- .clang-format | 2 + main.c | 371 ++++++++++++++++++++++++-------------------------- 2 files changed, 183 insertions(+), 190 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..84f9c6a --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Google +IndentWidth: 4 diff --git a/main.c b/main.c index 5a5fbfc..8eb535f 100644 --- a/main.c +++ b/main.c @@ -12,12 +12,12 @@ #define LEN(arr) (sizeof(arr) / sizeof(arr[0])) #define MAX(a, b) (a > b ? a : b) #define BLOCK(cmd, interval, signal) \ - { "echo \"$(" cmd ")\"", interval, signal } + { "echo \"$(" cmd ")\"", interval, signal } typedef const struct { - const char* command; - const unsigned int interval; - const unsigned int signal; + const char *command; + const unsigned int interval; + const unsigned int signal; } Block; #include "config.h" @@ -35,7 +35,7 @@ typedef const struct { #define LEADING_DELIMITER 0 #endif -static Display* dpy; +static Display *dpy; static int screen; static Window root; static unsigned short statusContinue = 1; @@ -48,265 +48,256 @@ static int execLock = 0; // Longest UTF-8 character is 4 bytes long static char outputs[LEN(blocks)][CMDLENGTH * 4 + 1 + CLICKABLE_BLOCKS]; -static char statusBar[2][LEN(blocks) * (LEN(outputs[0]) - 1) + (LEN(blocks) - 1 + LEADING_DELIMITER) * (LEN(DELIMITER) - 1) + 1]; +static char + statusBar[2] + [LEN(blocks) * (LEN(outputs[0]) - 1) + + (LEN(blocks) - 1 + LEADING_DELIMITER) * (LEN(DELIMITER) - 1) + 1]; void (*writeStatus)(); int gcd(int a, int b) { - int temp; - while (b > 0) { - temp = a % b; - a = b; - b = temp; - } - return a; + int temp; + while (b > 0) { + temp = a % b; + a = b; + b = temp; + } + return a; } -void closePipe(int* pipe) { - close(pipe[0]); - close(pipe[1]); +void closePipe(int *pipe) { + close(pipe[0]); + close(pipe[1]); } -void execBlock(int i, const char* button) { - // 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; +void execBlock(int i, const char *button) { + // 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(pipes[i][0]); - dup2(pipes[i][1], STDOUT_FILENO); - close(pipes[i][1]); + if (fork() == 0) { + close(pipes[i][0]); + dup2(pipes[i][1], STDOUT_FILENO); + close(pipes[i][1]); - if (button) - setenv("BLOCK_BUTTON", button, 1); - execl("/bin/sh", "sh", "-c", blocks[i].command, (char*)NULL); - exit(EXIT_FAILURE); - } + if (button) setenv("BLOCK_BUTTON", button, 1); + execl("/bin/sh", "sh", "-c", blocks[i].command, (char *)NULL); + exit(EXIT_FAILURE); + } } void execBlocks(unsigned int time) { - for (int i = 0; i < LEN(blocks); i++) - if (time == 0 || (blocks[i].interval != 0 && time % blocks[i].interval == 0)) - execBlock(i, NULL); + for (int i = 0; i < LEN(blocks); i++) + if (time == 0 || + (blocks[i].interval != 0 && time % blocks[i].interval == 0)) + execBlock(i, NULL); } -int getStatus(char* new, char* old) { - strcpy(old, new); - new[0] = '\0'; +int getStatus(char *new, char *old) { + strcpy(old, new); + new[0] = '\0'; - for (int i = 0; i < LEN(blocks); i++) { + for (int i = 0; i < LEN(blocks); i++) { #if LEADING_DELIMITER - if (strlen(outputs[i])) + if (strlen(outputs[i])) #else - if (strlen(new) && strlen(outputs[i])) + if (strlen(new) && strlen(outputs[i])) #endif - strcat(new, DELIMITER); - strcat(new, outputs[i]); - } - return strcmp(new, old); + strcat(new, DELIMITER); + strcat(new, outputs[i]); + } + return strcmp(new, old); } void updateBlock(int i) { - char* output = outputs[i]; - char buffer[LEN(outputs[0]) - CLICKABLE_BLOCKS]; - int bytesRead = read(pipes[i][0], buffer, LEN(buffer)); + char *output = outputs[i]; + char buffer[LEN(outputs[0]) - CLICKABLE_BLOCKS]; + int bytesRead = read(pipes[i][0], buffer, LEN(buffer)); - // Trim UTF-8 string to desired length - int count = 0, j = 0; - while (buffer[j] != '\n' && count < CMDLENGTH) { - count++; + // Trim UTF-8 string to desired length + int count = 0, j = 0; + while (buffer[j] != '\n' && count < CMDLENGTH) { + count++; - // Skip continuation bytes, if any - char ch = buffer[j]; - int skip = 1; - while ((ch & 0xc0) > 0x80) - ch <<= 1, skip++; - j += skip; - } + // Skip continuation bytes, if any + char ch = buffer[j]; + int skip = 1; + while ((ch & 0xc0) > 0x80) ch <<= 1, skip++; + j += skip; + } - // Cache last character and replace it with a trailing space - char ch = buffer[j]; - buffer[j] = ' '; + // Cache last character and replace it with a trailing space + char ch = buffer[j]; + buffer[j] = ' '; - // Trim trailing spaces - while (j >= 0 && buffer[j] == ' ') - j--; - buffer[j + 1] = 0; + // Trim trailing spaces + while (j >= 0 && buffer[j] == ' ') j--; + buffer[j + 1] = 0; - // Clear the pipe - if (bytesRead == LEN(buffer)) { - while (ch != '\n' && read(pipes[i][0], &ch, 1) == 1) - ; - } + // Clear the pipe + if (bytesRead == LEN(buffer)) { + while (ch != '\n' && read(pipes[i][0], &ch, 1) == 1) + ; + } #if CLICKABLE_BLOCKS - if (bytesRead > 1 && blocks[i].signal > 0) { - output[0] = blocks[i].signal; - output++; - } + if (bytesRead > 1 && blocks[i].signal > 0) { + output[0] = blocks[i].signal; + output++; + } #endif - strcpy(output, buffer); + strcpy(output, buffer); - // Remove execution lock for the current block - execLock &= ~(1 << i); + // Remove execution lock for the current block + execLock &= ~(1 << i); } void debug() { - // Only write out if text has changed - if (!getStatus(statusBar[0], statusBar[1])) - return; + // Only write out if text has changed + if (!getStatus(statusBar[0], statusBar[1])) return; - write(STDOUT_FILENO, statusBar[0], strlen(statusBar[0])); - write(STDOUT_FILENO, "\n", 1); + write(STDOUT_FILENO, statusBar[0], strlen(statusBar[0])); + write(STDOUT_FILENO, "\n", 1); } int setupX() { - dpy = XOpenDisplay(NULL); - if (!dpy) - return 1; + dpy = XOpenDisplay(NULL); + if (!dpy) return 1; - screen = DefaultScreen(dpy); - root = RootWindow(dpy, screen); - return 0; + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + return 0; } void setRoot() { - // Only set root if text has changed - if (!getStatus(statusBar[0], statusBar[1])) - return; + // Only set root if text has changed + if (!getStatus(statusBar[0], statusBar[1])) return; - XStoreName(dpy, root, statusBar[0]); - XFlush(dpy); + XStoreName(dpy, root, statusBar[0]); + XFlush(dpy); } void signalHandler() { - struct signalfd_siginfo info; - read(signalFD, &info, sizeof(info)); - unsigned int signal = info.ssi_signo; + struct signalfd_siginfo info; + read(signalFD, &info, sizeof(info)); + unsigned int signal = info.ssi_signo; - switch (signal) { - case SIGALRM: - // Schedule the next timer event and execute blocks - alarm(timerTick); - execBlocks(timer); + 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; - } + // 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 < LEN(blocks); j++) { - if (blocks[j].signal == signal - SIGRTMIN) { - char button[] = {'0' + info.ssi_int & 0xff, 0}; - execBlock(j, button); - break; - } - } + for (int j = 0; j < LEN(blocks); j++) { + if (blocks[j].signal == signal - SIGRTMIN) { + char button[] = {'0' + info.ssi_int & 0xff, 0}; + execBlock(j, button); + break; + } + } } -void termHandler() { - statusContinue = 0; -} +void termHandler() { statusContinue = 0; } void setupSignals() { - sigset_t handledSignals; - sigemptyset(&handledSignals); - sigaddset(&handledSignals, SIGUSR1); - sigaddset(&handledSignals, SIGALRM); + sigset_t handledSignals; + sigemptyset(&handledSignals); + sigaddset(&handledSignals, SIGUSR1); + sigaddset(&handledSignals, SIGALRM); - // Append all block signals to `handledSignals` - for (int i = 0; i < LEN(blocks); i++) - if (blocks[i].signal > 0) - sigaddset(&handledSignals, SIGRTMIN + blocks[i].signal); + // Append all block signals to `handledSignals` + for (int i = 0; i < LEN(blocks); 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); - event.data.u32 = LEN(blocks); - epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event); + // Create a signal file descriptor for epoll to watch + signalFD = signalfd(-1, &handledSignals, 0); + event.data.u32 = LEN(blocks); + epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event); - // Block all realtime and handled signals - for (int i = SIGRTMIN; i <= SIGRTMAX; i++) - sigaddset(&handledSignals, i); - sigprocmask(SIG_BLOCK, &handledSignals, NULL); + // 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); + // Handle termination signals + signal(SIGINT, termHandler); + signal(SIGTERM, termHandler); - // Avoid zombie subprocesses - struct sigaction sa; - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDWAIT; - sigaction(SIGCHLD, &sa, 0); + // Avoid zombie subprocesses + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDWAIT; + sigaction(SIGCHLD, &sa, 0); } void statusLoop() { - // Update all blocks initially - raise(SIGALRM); + // Update all blocks initially + raise(SIGALRM); - struct epoll_event events[LEN(blocks) + 1]; - while (statusContinue) { - int eventCount = epoll_wait(epollFD, events, LEN(events), -1); - for (int i = 0; i < eventCount; i++) { - unsigned short id = events[i].data.u32; - if (id < LEN(blocks)) - updateBlock(id); - else - signalHandler(); - } + struct epoll_event events[LEN(blocks) + 1]; + while (statusContinue) { + int eventCount = epoll_wait(epollFD, events, LEN(events), -1); + for (int i = 0; i < eventCount; i++) { + unsigned short id = events[i].data.u32; + if (id < LEN(blocks)) + updateBlock(id); + else + signalHandler(); + } - if (eventCount != -1) - writeStatus(); - } + if (eventCount != -1) writeStatus(); + } } void init() { - epollFD = epoll_create(LEN(blocks)); - event.events = EPOLLIN; + epollFD = epoll_create(LEN(blocks)); + event.events = EPOLLIN; - for (int i = 0; i < LEN(blocks); i++) { - // Append each block's pipe to `epollFD` - pipe(pipes[i]); - event.data.u32 = i; - epoll_ctl(epollFD, EPOLL_CTL_ADD, pipes[i][0], &event); + for (int i = 0; i < LEN(blocks); i++) { + // Append each block's pipe to `epollFD` + pipe(pipes[i]); + event.data.u32 = i; + epoll_ctl(epollFD, EPOLL_CTL_ADD, pipes[i][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); - } - } + // 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(); + setupSignals(); } -int main(const int argc, const char* argv[]) { - if (setupX()) { - fprintf(stderr, "dwmblocks: Failed to open display\n"); - return 1; - } +int main(const int argc, const char *argv[]) { + if (setupX()) { + fprintf(stderr, "dwmblocks: Failed to open display\n"); + return 1; + } - writeStatus = setRoot; - for (int i = 0; i < argc; i++) - if (!strcmp("-d", argv[i])) - writeStatus = debug; + writeStatus = setRoot; + for (int i = 0; i < argc; i++) + if (!strcmp("-d", argv[i])) writeStatus = debug; - init(); - statusLoop(); + init(); + statusLoop(); - XCloseDisplay(dpy); - close(epollFD); - close(signalFD); - for (int i = 0; i < LEN(pipes); i++) - closePipe(pipes[i]); + XCloseDisplay(dpy); + close(epollFD); + close(signalFD); + for (int i = 0; i < LEN(pipes); i++) closePipe(pipes[i]); - return 0; + return 0; } From 6a97f4d0c517d1d1c71fa599b97eb3508710f5a1 Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sat, 3 Sep 2022 09:15:45 +0200 Subject: [PATCH 7/7] Support upto 256 click events on a block. Fixes #32 --- main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 8eb535f..4ed7e00 100644 --- a/main.c +++ b/main.c @@ -201,7 +201,8 @@ void signalHandler() { for (int j = 0; j < LEN(blocks); j++) { if (blocks[j].signal == signal - SIGRTMIN) { - char button[] = {'0' + info.ssi_int & 0xff, 0}; + char button[4]; // value can't be more than 255; + sprintf(button, "%d", info.ssi_int & 0xff); execBlock(j, button); break; }