dwmblocks/main.c

206 lines
4.5 KiB
C
Raw Normal View History

2021-03-20 10:52:45 +01:00
#include <X11/Xlib.h>
2021-04-17 12:17:40 +02:00
#include <fcntl.h>
#include <limits.h>
2021-03-20 10:52:45 +01:00
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "config.h"
2021-04-17 12:17:40 +02:00
#define LEN(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(x, y) (x > y ? y : x)
2021-03-20 10:52:45 +01:00
static Display *dpy;
static int screen;
static Window root;
2021-04-17 12:17:40 +02:00
static char statusBar[2][LEN(blocks) * (CMDLENGTH + LEN(DELIMITER) - 1) + 1];
2021-03-20 10:52:45 +01:00
static int statusContinue = 1;
2021-04-17 12:17:40 +02:00
void (*writeStatus)();
2021-04-13 07:35:21 +02:00
int gcd(int a, int b) {
int temp;
while (b > 0) {
temp = a % b;
a = b;
b = temp;
2021-03-20 10:52:45 +01:00
}
2021-04-13 07:35:21 +02:00
return a;
2021-03-20 10:52:45 +01:00
}
2021-04-13 07:35:21 +02:00
void replace(char *str, char old, char new) {
for (char *ch = str; *ch; ch++)
if (*ch == old)
*ch = new;
2021-03-20 10:52:45 +01:00
}
2021-04-17 12:17:40 +02:00
void getCommand(int i, const char *button) {
Block *block = blocks + i;
2021-03-20 10:52:45 +01:00
2021-04-17 12:17:40 +02:00
if (fork() == 0) {
dup2(block->pipe[1], STDOUT_FILENO);
close(block->pipe[0]);
close(block->pipe[1]);
// Temporary hack
char cmd[1024];
sprintf(cmd, "echo \"_$(%s)\"", block->command);
char *command[] = {"/bin/sh", "-c", cmd, NULL};
if (button) setenv("BLOCK_BUTTON", button, 1);
setsid();
execvp(command[0], command);
2021-03-20 10:52:45 +01:00
}
}
void getCommands(int time) {
2021-04-17 12:17:40 +02:00
for (int i = 0; i < LEN(blocks); i++)
if (time == 0 || (blocks[i].interval != 0 && time % blocks[i].interval == 0))
getCommand(i, NULL);
2021-03-20 10:52:45 +01:00
}
2021-04-17 12:17:40 +02:00
void getSignalCommand(int signal) {
for (int i = 0; i < LEN(blocks); i++)
if (blocks[i].signal == signal)
getCommand(i, NULL);
2021-04-13 07:35:21 +02:00
}
2021-03-20 10:52:45 +01:00
int getStatus(char *new, char *old) {
strcpy(old, new);
new[0] = '\0';
2021-04-17 12:17:40 +02:00
for (int i = 0; i < LEN(blocks); i++) {
Block *block = blocks + i;
if (strlen(block->output) > (block->signal != 0))
strcat(new, DELIMITER);
strcat(new, block->output);
2021-03-20 10:52:45 +01:00
}
new[strlen(new)] = '\0';
return strcmp(new, old);
}
2021-04-13 07:35:21 +02:00
void debug() {
// Only write out if text has changed
2021-04-17 12:17:40 +02:00
if (!getStatus(statusBar[0], statusBar[1])) return;
2021-04-13 07:35:21 +02:00
2021-04-17 12:17:40 +02:00
write(STDOUT_FILENO, statusBar[0], strlen(statusBar[0]));
2021-04-13 07:35:21 +02:00
write(STDOUT_FILENO, "\n", 1);
}
2021-03-20 10:52:45 +01:00
void setRoot() {
2021-03-22 06:42:52 +01:00
// Only set root if text has changed
2021-04-17 12:17:40 +02:00
if (!getStatus(statusBar[0], statusBar[1])) return;
2021-03-20 10:52:45 +01:00
Display *d = XOpenDisplay(NULL);
if (d) dpy = d;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
2021-04-17 12:17:40 +02:00
XStoreName(dpy, root, statusBar[0]);
2021-03-20 10:52:45 +01:00
XCloseDisplay(dpy);
}
void buttonHandler(int sig, siginfo_t *si, void *ucontext) {
sig = si->si_value.sival_int >> 8;
2021-04-17 12:17:40 +02:00
int i = 0;
while (blocks[i].signal != sig) i++;
const char button[2] = {'0' + si->si_value.sival_int & 0xff, '\0'};
getCommand(i, button);
2021-03-20 10:52:45 +01:00
}
2021-04-17 12:17:40 +02:00
void signalHandler(int signal) { getSignalCommand(signal - SIGRTMIN); }
2021-04-13 07:35:21 +02:00
2021-04-17 12:17:40 +02:00
void termHandler(int signal) {
2021-03-20 10:52:45 +01:00
statusContinue = 0;
2021-04-17 12:17:40 +02:00
exit(EXIT_SUCCESS);
}
void childHandler() {
for (int i = 0; i < LEN(blocks); i++) {
Block *block = blocks + i;
int bytesToRead = CMDLENGTH;
char *output = block->output;
if (block->signal) output++, bytesToRead--;
char placebo;
if (read(block->pipe[0], &placebo, 1) == 1) {
char buffer[PIPE_BUF];
read(block->pipe[0], buffer, PIPE_BUF);
replace(buffer, '\n', '\0');
strncpy(output, buffer, bytesToRead);
break;
}
}
writeStatus();
2021-03-20 10:52:45 +01:00
}
2021-04-13 07:35:21 +02:00
void setupSignals() {
2021-04-17 12:17:40 +02:00
signal(SIGTERM, termHandler);
signal(SIGINT, termHandler);
2021-04-13 07:35:21 +02:00
// Handle block update signals
2021-04-17 12:17:40 +02:00
struct sigaction sa;
for (int i = 0; i < LEN(blocks); i++) {
2021-04-13 07:35:21 +02:00
if (blocks[i].signal > 0) {
signal(SIGRTMIN + blocks[i].signal, signalHandler);
sigaddset(&sa.sa_mask, SIGRTMIN + blocks[i].signal);
}
}
// Handle mouse events
sa.sa_sigaction = buttonHandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &sa, NULL);
2021-04-17 12:17:40 +02:00
// Handle exit of forks
2021-04-13 07:35:21 +02:00
struct sigaction sigchld_action = {
2021-04-17 12:17:40 +02:00
.sa_handler = childHandler,
2021-04-13 07:35:21 +02:00
.sa_flags = SA_NOCLDWAIT,
};
sigaction(SIGCHLD, &sigchld_action, NULL);
}
void statusLoop() {
2021-04-17 12:17:40 +02:00
getCommands(0);
2021-04-13 07:35:21 +02:00
unsigned int sleepInterval = -1;
2021-04-17 12:17:40 +02:00
for (int i = 0; i < LEN(blocks); i++)
2021-04-13 07:35:21 +02:00
if (blocks[i].interval)
sleepInterval = gcd(blocks[i].interval, sleepInterval);
unsigned int i = 0;
struct timespec sleepTime = {sleepInterval, 0};
struct timespec toSleep = sleepTime;
while (statusContinue) {
// Sleep for `sleepTime` even on being interrupted
if (nanosleep(&toSleep, &toSleep) == -1) continue;
// Write to status after sleeping
getCommands(i);
// After sleep, reset timer and update counter
toSleep = sleepTime;
i += sleepInterval;
}
}
2021-03-20 10:52:45 +01:00
int main(int argc, char **argv) {
2021-04-17 12:17:40 +02:00
writeStatus = setRoot;
2021-03-20 10:52:45 +01:00
for (int i = 0; i < argc; i++)
2021-04-13 07:35:21 +02:00
if (!strcmp("-d", argv[i])) writeStatus = debug;
2021-03-20 10:52:45 +01:00
2021-04-17 12:17:40 +02:00
for (int i = 0; i < LEN(blocks); i++) {
Block *block = blocks + i;
pipe(block->pipe);
fcntl(block->pipe[0], F_SETFL, O_NONBLOCK);
if (block->signal) block->output[0] = block->signal;
}
setupSignals();
2021-03-20 10:52:45 +01:00
statusLoop();
}