mirror of
https://github.com/mintycube/dwmblocks.git
synced 2024-10-22 14:05:47 +02:00
Add .clang-format
This commit is contained in:
parent
098184d0c3
commit
647080cbed
2
.clang-format
Normal file
2
.clang-format
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 4
|
371
main.c
371
main.c
@ -12,12 +12,12 @@
|
|||||||
#define LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
#define LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||||
#define MAX(a, b) (a > b ? a : b)
|
#define MAX(a, b) (a > b ? a : b)
|
||||||
#define BLOCK(cmd, interval, signal) \
|
#define BLOCK(cmd, interval, signal) \
|
||||||
{ "echo \"$(" cmd ")\"", interval, signal }
|
{ "echo \"$(" cmd ")\"", interval, signal }
|
||||||
|
|
||||||
typedef const struct {
|
typedef const struct {
|
||||||
const char* command;
|
const char *command;
|
||||||
const unsigned int interval;
|
const unsigned int interval;
|
||||||
const unsigned int signal;
|
const unsigned int signal;
|
||||||
} Block;
|
} Block;
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ typedef const struct {
|
|||||||
#define LEADING_DELIMITER 0
|
#define LEADING_DELIMITER 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Display* dpy;
|
static Display *dpy;
|
||||||
static int screen;
|
static int screen;
|
||||||
static Window root;
|
static Window root;
|
||||||
static unsigned short statusContinue = 1;
|
static unsigned short statusContinue = 1;
|
||||||
@ -48,265 +48,256 @@ static int execLock = 0;
|
|||||||
|
|
||||||
// Longest UTF-8 character is 4 bytes long
|
// Longest UTF-8 character is 4 bytes long
|
||||||
static char outputs[LEN(blocks)][CMDLENGTH * 4 + 1 + CLICKABLE_BLOCKS];
|
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)();
|
void (*writeStatus)();
|
||||||
|
|
||||||
int gcd(int a, int b) {
|
int gcd(int a, int b) {
|
||||||
int temp;
|
int temp;
|
||||||
while (b > 0) {
|
while (b > 0) {
|
||||||
temp = a % b;
|
temp = a % b;
|
||||||
a = b;
|
a = b;
|
||||||
b = temp;
|
b = temp;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void closePipe(int* pipe) {
|
void closePipe(int *pipe) {
|
||||||
close(pipe[0]);
|
close(pipe[0]);
|
||||||
close(pipe[1]);
|
close(pipe[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void execBlock(int i, const char* button) {
|
void execBlock(int i, const char *button) {
|
||||||
// Ensure only one child process exists per block at an instance
|
// Ensure only one child process exists per block at an instance
|
||||||
if (execLock & 1 << i)
|
if (execLock & 1 << i) return;
|
||||||
return;
|
// Lock execution of block until current instance finishes execution
|
||||||
// Lock execution of block until current instance finishes execution
|
execLock |= 1 << i;
|
||||||
execLock |= 1 << i;
|
|
||||||
|
|
||||||
if (fork() == 0) {
|
if (fork() == 0) {
|
||||||
close(pipes[i][0]);
|
close(pipes[i][0]);
|
||||||
dup2(pipes[i][1], STDOUT_FILENO);
|
dup2(pipes[i][1], STDOUT_FILENO);
|
||||||
close(pipes[i][1]);
|
close(pipes[i][1]);
|
||||||
|
|
||||||
if (button)
|
if (button) setenv("BLOCK_BUTTON", button, 1);
|
||||||
setenv("BLOCK_BUTTON", button, 1);
|
execl("/bin/sh", "sh", "-c", blocks[i].command, (char *)NULL);
|
||||||
execl("/bin/sh", "sh", "-c", blocks[i].command, (char*)NULL);
|
exit(EXIT_FAILURE);
|
||||||
exit(EXIT_FAILURE);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void execBlocks(unsigned int time) {
|
void execBlocks(unsigned int time) {
|
||||||
for (int i = 0; i < LEN(blocks); i++)
|
for (int i = 0; i < LEN(blocks); i++)
|
||||||
if (time == 0 || (blocks[i].interval != 0 && time % blocks[i].interval == 0))
|
if (time == 0 ||
|
||||||
execBlock(i, NULL);
|
(blocks[i].interval != 0 && time % blocks[i].interval == 0))
|
||||||
|
execBlock(i, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getStatus(char* new, char* old) {
|
int getStatus(char *new, char *old) {
|
||||||
strcpy(old, new);
|
strcpy(old, new);
|
||||||
new[0] = '\0';
|
new[0] = '\0';
|
||||||
|
|
||||||
for (int i = 0; i < LEN(blocks); i++) {
|
for (int i = 0; i < LEN(blocks); i++) {
|
||||||
#if LEADING_DELIMITER
|
#if LEADING_DELIMITER
|
||||||
if (strlen(outputs[i]))
|
if (strlen(outputs[i]))
|
||||||
#else
|
#else
|
||||||
if (strlen(new) && strlen(outputs[i]))
|
if (strlen(new) && strlen(outputs[i]))
|
||||||
#endif
|
#endif
|
||||||
strcat(new, DELIMITER);
|
strcat(new, DELIMITER);
|
||||||
strcat(new, outputs[i]);
|
strcat(new, outputs[i]);
|
||||||
}
|
}
|
||||||
return strcmp(new, old);
|
return strcmp(new, old);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBlock(int i) {
|
void updateBlock(int i) {
|
||||||
char* output = outputs[i];
|
char *output = outputs[i];
|
||||||
char buffer[LEN(outputs[0]) - CLICKABLE_BLOCKS];
|
char buffer[LEN(outputs[0]) - CLICKABLE_BLOCKS];
|
||||||
int bytesRead = read(pipes[i][0], buffer, LEN(buffer));
|
int bytesRead = read(pipes[i][0], buffer, LEN(buffer));
|
||||||
|
|
||||||
// Trim UTF-8 string to desired length
|
// Trim UTF-8 string to desired length
|
||||||
int count = 0, j = 0;
|
int count = 0, j = 0;
|
||||||
while (buffer[j] != '\n' && count < CMDLENGTH) {
|
while (buffer[j] != '\n' && count < CMDLENGTH) {
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
// Skip continuation bytes, if any
|
// Skip continuation bytes, if any
|
||||||
char ch = buffer[j];
|
char ch = buffer[j];
|
||||||
int skip = 1;
|
int skip = 1;
|
||||||
while ((ch & 0xc0) > 0x80)
|
while ((ch & 0xc0) > 0x80) ch <<= 1, skip++;
|
||||||
ch <<= 1, skip++;
|
j += skip;
|
||||||
j += skip;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Cache last character and replace it with a trailing space
|
// Cache last character and replace it with a trailing space
|
||||||
char ch = buffer[j];
|
char ch = buffer[j];
|
||||||
buffer[j] = ' ';
|
buffer[j] = ' ';
|
||||||
|
|
||||||
// Trim trailing spaces
|
// Trim trailing spaces
|
||||||
while (j >= 0 && buffer[j] == ' ')
|
while (j >= 0 && buffer[j] == ' ') j--;
|
||||||
j--;
|
buffer[j + 1] = 0;
|
||||||
buffer[j + 1] = 0;
|
|
||||||
|
|
||||||
// Clear the pipe
|
// Clear the pipe
|
||||||
if (bytesRead == LEN(buffer)) {
|
if (bytesRead == LEN(buffer)) {
|
||||||
while (ch != '\n' && read(pipes[i][0], &ch, 1) == 1)
|
while (ch != '\n' && read(pipes[i][0], &ch, 1) == 1)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CLICKABLE_BLOCKS
|
#if CLICKABLE_BLOCKS
|
||||||
if (bytesRead > 1 && blocks[i].signal > 0) {
|
if (bytesRead > 1 && blocks[i].signal > 0) {
|
||||||
output[0] = blocks[i].signal;
|
output[0] = blocks[i].signal;
|
||||||
output++;
|
output++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strcpy(output, buffer);
|
strcpy(output, buffer);
|
||||||
|
|
||||||
// Remove execution lock for the current block
|
// Remove execution lock for the current block
|
||||||
execLock &= ~(1 << i);
|
execLock &= ~(1 << i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug() {
|
void debug() {
|
||||||
// Only write out if text has changed
|
// Only write out if text has changed
|
||||||
if (!getStatus(statusBar[0], statusBar[1]))
|
if (!getStatus(statusBar[0], statusBar[1])) return;
|
||||||
return;
|
|
||||||
|
|
||||||
write(STDOUT_FILENO, statusBar[0], strlen(statusBar[0]));
|
write(STDOUT_FILENO, statusBar[0], strlen(statusBar[0]));
|
||||||
write(STDOUT_FILENO, "\n", 1);
|
write(STDOUT_FILENO, "\n", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int setupX() {
|
int setupX() {
|
||||||
dpy = XOpenDisplay(NULL);
|
dpy = XOpenDisplay(NULL);
|
||||||
if (!dpy)
|
if (!dpy) return 1;
|
||||||
return 1;
|
|
||||||
|
|
||||||
screen = DefaultScreen(dpy);
|
screen = DefaultScreen(dpy);
|
||||||
root = RootWindow(dpy, screen);
|
root = RootWindow(dpy, screen);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRoot() {
|
void setRoot() {
|
||||||
// Only set root if text has changed
|
// Only set root if text has changed
|
||||||
if (!getStatus(statusBar[0], statusBar[1]))
|
if (!getStatus(statusBar[0], statusBar[1])) return;
|
||||||
return;
|
|
||||||
|
|
||||||
XStoreName(dpy, root, statusBar[0]);
|
XStoreName(dpy, root, statusBar[0]);
|
||||||
XFlush(dpy);
|
XFlush(dpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void signalHandler() {
|
void signalHandler() {
|
||||||
struct signalfd_siginfo info;
|
struct signalfd_siginfo info;
|
||||||
read(signalFD, &info, sizeof(info));
|
read(signalFD, &info, sizeof(info));
|
||||||
unsigned int signal = info.ssi_signo;
|
unsigned int signal = info.ssi_signo;
|
||||||
|
|
||||||
switch (signal) {
|
switch (signal) {
|
||||||
case SIGALRM:
|
case SIGALRM:
|
||||||
// Schedule the next timer event and execute blocks
|
// Schedule the next timer event and execute blocks
|
||||||
alarm(timerTick);
|
alarm(timerTick);
|
||||||
execBlocks(timer);
|
execBlocks(timer);
|
||||||
|
|
||||||
// Wrap `timer` to the interval [1, `maxInterval`]
|
// Wrap `timer` to the interval [1, `maxInterval`]
|
||||||
timer = (timer + timerTick - 1) % maxInterval + 1;
|
timer = (timer + timerTick - 1) % maxInterval + 1;
|
||||||
return;
|
return;
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
// Update all blocks on receiving SIGUSR1
|
// Update all blocks on receiving SIGUSR1
|
||||||
execBlocks(0);
|
execBlocks(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < LEN(blocks); j++) {
|
for (int j = 0; j < LEN(blocks); j++) {
|
||||||
if (blocks[j].signal == signal - SIGRTMIN) {
|
if (blocks[j].signal == signal - SIGRTMIN) {
|
||||||
char button[] = {'0' + info.ssi_int & 0xff, 0};
|
char button[] = {'0' + info.ssi_int & 0xff, 0};
|
||||||
execBlock(j, button);
|
execBlock(j, button);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void termHandler() {
|
void termHandler() { statusContinue = 0; }
|
||||||
statusContinue = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupSignals() {
|
void setupSignals() {
|
||||||
sigset_t handledSignals;
|
sigset_t handledSignals;
|
||||||
sigemptyset(&handledSignals);
|
sigemptyset(&handledSignals);
|
||||||
sigaddset(&handledSignals, SIGUSR1);
|
sigaddset(&handledSignals, SIGUSR1);
|
||||||
sigaddset(&handledSignals, SIGALRM);
|
sigaddset(&handledSignals, SIGALRM);
|
||||||
|
|
||||||
// Append all block signals to `handledSignals`
|
// Append all block signals to `handledSignals`
|
||||||
for (int i = 0; i < LEN(blocks); i++)
|
for (int i = 0; i < LEN(blocks); i++)
|
||||||
if (blocks[i].signal > 0)
|
if (blocks[i].signal > 0)
|
||||||
sigaddset(&handledSignals, SIGRTMIN + blocks[i].signal);
|
sigaddset(&handledSignals, SIGRTMIN + blocks[i].signal);
|
||||||
|
|
||||||
// Create a signal file descriptor for epoll to watch
|
// Create a signal file descriptor for epoll to watch
|
||||||
signalFD = signalfd(-1, &handledSignals, 0);
|
signalFD = signalfd(-1, &handledSignals, 0);
|
||||||
event.data.u32 = LEN(blocks);
|
event.data.u32 = LEN(blocks);
|
||||||
epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event);
|
epoll_ctl(epollFD, EPOLL_CTL_ADD, signalFD, &event);
|
||||||
|
|
||||||
// Block all realtime and handled signals
|
// Block all realtime and handled signals
|
||||||
for (int i = SIGRTMIN; i <= SIGRTMAX; i++)
|
for (int i = SIGRTMIN; i <= SIGRTMAX; i++) sigaddset(&handledSignals, i);
|
||||||
sigaddset(&handledSignals, i);
|
sigprocmask(SIG_BLOCK, &handledSignals, NULL);
|
||||||
sigprocmask(SIG_BLOCK, &handledSignals, NULL);
|
|
||||||
|
|
||||||
// Handle termination signals
|
// Handle termination signals
|
||||||
signal(SIGINT, termHandler);
|
signal(SIGINT, termHandler);
|
||||||
signal(SIGTERM, termHandler);
|
signal(SIGTERM, termHandler);
|
||||||
|
|
||||||
// Avoid zombie subprocesses
|
// Avoid zombie subprocesses
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
sa.sa_handler = SIG_DFL;
|
sa.sa_handler = SIG_DFL;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_NOCLDWAIT;
|
sa.sa_flags = SA_NOCLDWAIT;
|
||||||
sigaction(SIGCHLD, &sa, 0);
|
sigaction(SIGCHLD, &sa, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void statusLoop() {
|
void statusLoop() {
|
||||||
// Update all blocks initially
|
// Update all blocks initially
|
||||||
raise(SIGALRM);
|
raise(SIGALRM);
|
||||||
|
|
||||||
struct epoll_event events[LEN(blocks) + 1];
|
struct epoll_event events[LEN(blocks) + 1];
|
||||||
while (statusContinue) {
|
while (statusContinue) {
|
||||||
int eventCount = epoll_wait(epollFD, events, LEN(events), -1);
|
int eventCount = epoll_wait(epollFD, events, LEN(events), -1);
|
||||||
for (int i = 0; i < eventCount; i++) {
|
for (int i = 0; i < eventCount; i++) {
|
||||||
unsigned short id = events[i].data.u32;
|
unsigned short id = events[i].data.u32;
|
||||||
if (id < LEN(blocks))
|
if (id < LEN(blocks))
|
||||||
updateBlock(id);
|
updateBlock(id);
|
||||||
else
|
else
|
||||||
signalHandler();
|
signalHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventCount != -1)
|
if (eventCount != -1) writeStatus();
|
||||||
writeStatus();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
epollFD = epoll_create(LEN(blocks));
|
epollFD = epoll_create(LEN(blocks));
|
||||||
event.events = EPOLLIN;
|
event.events = EPOLLIN;
|
||||||
|
|
||||||
for (int i = 0; i < LEN(blocks); i++) {
|
for (int i = 0; i < LEN(blocks); i++) {
|
||||||
// Append each block's pipe to `epollFD`
|
// Append each block's pipe to `epollFD`
|
||||||
pipe(pipes[i]);
|
pipe(pipes[i]);
|
||||||
event.data.u32 = i;
|
event.data.u32 = i;
|
||||||
epoll_ctl(epollFD, EPOLL_CTL_ADD, pipes[i][0], &event);
|
epoll_ctl(epollFD, EPOLL_CTL_ADD, pipes[i][0], &event);
|
||||||
|
|
||||||
// Calculate the max interval and tick size for the timer
|
// Calculate the max interval and tick size for the timer
|
||||||
if (blocks[i].interval) {
|
if (blocks[i].interval) {
|
||||||
maxInterval = MAX(blocks[i].interval, maxInterval);
|
maxInterval = MAX(blocks[i].interval, maxInterval);
|
||||||
timerTick = gcd(blocks[i].interval, timerTick);
|
timerTick = gcd(blocks[i].interval, timerTick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSignals();
|
setupSignals();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(const int argc, const char* argv[]) {
|
int main(const int argc, const char *argv[]) {
|
||||||
if (setupX()) {
|
if (setupX()) {
|
||||||
fprintf(stderr, "dwmblocks: Failed to open display\n");
|
fprintf(stderr, "dwmblocks: Failed to open display\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeStatus = setRoot;
|
writeStatus = setRoot;
|
||||||
for (int i = 0; i < argc; i++)
|
for (int i = 0; i < argc; i++)
|
||||||
if (!strcmp("-d", argv[i]))
|
if (!strcmp("-d", argv[i])) writeStatus = debug;
|
||||||
writeStatus = debug;
|
|
||||||
|
|
||||||
init();
|
init();
|
||||||
statusLoop();
|
statusLoop();
|
||||||
|
|
||||||
XCloseDisplay(dpy);
|
XCloseDisplay(dpy);
|
||||||
close(epollFD);
|
close(epollFD);
|
||||||
close(signalFD);
|
close(signalFD);
|
||||||
for (int i = 0; i < LEN(pipes); i++)
|
for (int i = 0; i < LEN(pipes); i++) closePipe(pipes[i]);
|
||||||
closePipe(pipes[i]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user