dwmblocks/main.c

218 lines
4.8 KiB
C
Raw Normal View History

2021-03-20 10:52:45 +01:00
#include <X11/Xlib.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define len(arr) (sizeof(arr) / sizeof(arr[0]))
typedef struct {
char *command;
unsigned int interval;
unsigned int signal;
} Block;
#include "config.h"
void debug();
2021-04-13 07:35:21 +02:00
void setRoot();
2021-03-20 10:52:45 +01:00
static Display *dpy;
static int screen;
static Window root;
static char commands[len(blocks)][256];
static char statusbar[len(blocks)][CMDLENGTH];
static char statusStr[2][len(blocks) * CMDLENGTH +
2021-03-22 06:42:52 +01:00
(len(delimiter) - 1) * (len(blocks) - 1) + 1];
2021-03-20 10:52:45 +01:00
static int statusContinue = 1;
2021-04-13 07:35:21 +02:00
static void (*writeStatus)() = setRoot;
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
}
// Open process *command and store output in *output
void getCommand(const Block *block, char *output) {
// Leave signal in output for dwm
if (block->signal) {
output[0] = block->signal;
output++;
}
char *cmd = block->command;
FILE *cmdFile = popen(cmd, "r");
if (!cmdFile) return;
int fd = fileno(cmdFile);
if (!read(fd, output, CMDLENGTH - 2))
output[0] = '\0';
else {
output[CMDLENGTH - 2] = '\0';
replace(output, '\n', '\0');
}
pclose(cmdFile);
}
void getCommands(int time) {
const Block *current;
for (int i = 0; i < len(blocks); i++) {
current = blocks + i;
if ((current->interval != 0 && time % current->interval == 0) ||
2021-03-22 06:42:52 +01:00
time == -1)
2021-03-20 10:52:45 +01:00
getCommand(current, statusbar[i]);
}
}
2021-04-13 07:35:21 +02:00
void getSignalCommands(int signal) {
const Block *current;
for (int i = 0; i < len(blocks); i++) {
current = blocks + i;
if (current->signal == signal)
getCommand(current, statusbar[i]);
}
}
2021-03-20 10:52:45 +01:00
int getStatus(char *new, char *old) {
strcpy(old, new);
new[0] = '\0';
2021-04-13 07:35:21 +02:00
strcat(new, delimiter);
2021-03-20 10:52:45 +01:00
for (int i = 0; i < len(blocks); i++) {
strcat(new, statusbar[i]);
if (strlen(statusbar[i]) > (blocks[i].signal != 0) &&
2021-03-22 06:42:52 +01:00
i != len(blocks) - 1)
2021-03-20 10:52:45 +01:00
strcat(new, delimiter);
}
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
if (!getStatus(statusStr[0], statusStr[1])) return;
write(STDOUT_FILENO, statusStr[0], strlen(statusStr[0]));
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-03-20 10:52:45 +01:00
if (!getStatus(statusStr[0], statusStr[1])) return;
Display *d = XOpenDisplay(NULL);
if (d) dpy = d;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
XStoreName(dpy, root, statusStr[0]);
XCloseDisplay(dpy);
}
void buttonHandler(int sig, siginfo_t *si, void *ucontext) {
char button[2] = {'0' + si->si_value.sival_int & 0xff, '\0'};
sig = si->si_value.sival_int >> 8;
if (fork() == 0) {
const Block *current;
char *shCommand = NULL;
for (int i = 0; i < len(blocks); i++) {
current = blocks + i;
if (current->signal == sig) {
shCommand = commands[i];
break;
}
}
if (shCommand) {
char *command[] = {"/bin/sh", "-c", shCommand, NULL};
setenv("BLOCK_BUTTON", button, 1);
setsid();
execvp(command[0], command);
}
exit(EXIT_SUCCESS);
}
}
2021-04-13 07:35:21 +02:00
void signalHandler(int signum) {
getSignalCommands(signum - SIGRTMIN);
writeStatus();
}
2021-03-20 10:52:45 +01:00
void termHandler(int sigNum) {
statusContinue = 0;
exit(0);
}
2021-04-13 07:35:21 +02:00
void setupSignals() {
struct sigaction sa;
// Handle block update signals
for (int i = 0; i < len(blocks); i++) {
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);
struct sigaction sigchld_action = {
.sa_handler = SIG_DFL,
.sa_flags = SA_NOCLDWAIT,
};
sigaction(SIGCHLD, &sigchld_action, NULL);
}
void statusLoop() {
setupSignals();
unsigned int sleepInterval = -1;
for (int i = 0; i < len(blocks); i++)
if (blocks[i].interval)
sleepInterval = gcd(blocks[i].interval, sleepInterval);
unsigned int i = 0;
struct timespec sleepTime = {sleepInterval, 0};
struct timespec toSleep = sleepTime;
getCommands(-1);
while (statusContinue) {
// Sleep for `sleepTime` even on being interrupted
if (nanosleep(&toSleep, &toSleep) == -1) continue;
// Write to status after sleeping
getCommands(i);
writeStatus();
// 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) {
const int processID = getpid();
for (int i = 0; i < len(blocks); i++)
sprintf(commands[i], "%s && kill -%d %d", blocks[i].command,
2021-03-22 06:42:52 +01:00
SIGRTMIN + blocks[i].signal, processID);
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
signal(SIGTERM, termHandler);
signal(SIGINT, termHandler);
statusLoop();
}