summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2024-02-06 01:26:46 +0100
committerLouis Burda <quent.burda@gmail.com>2024-02-06 01:26:46 +0100
commita67f1c4669f1f015b2b1bf0a69453474f51020c7 (patch)
tree0439876474e88d85840621153be828551fac93d4
parent6aa02a11915923e7fadde44164f299a21d462f93 (diff)
downloadwmsl-a67f1c4669f1f015b2b1bf0a69453474f51020c7.tar.gz
wmsl-a67f1c4669f1f015b2b1bf0a69453474f51020c7.zip
Improve readme and remove some more bloat
-rw-r--r--README37
-rw-r--r--README.rst13
-rw-r--r--sigwmsl.c2
-rw-r--r--wmsl.c255
-rw-r--r--wmslrc14
5 files changed, 132 insertions, 189 deletions
diff --git a/README b/README
deleted file mode 100644
index 0375419..0000000
--- a/README
+++ /dev/null
@@ -1,37 +0,0 @@
-wmsl - window manager status line
-=================================
-
-wmsl is a simple and extensible status line for dwm
-
-
-Features
---------
-- status 'blocks' are updated by timer or unique signal
-- scriptable, blocks can be added dynamically without recompilation
-- simple and extensible <200 lines of C
-
-
-Methodology
------------
-To update blocks independent of the timer, a signal handler is bound to SIGALRM,
-the block to update is specified via id in the SIGVAL. This way, both update
-signals and timers (through alarm()) use the same handler. This results in a
-very simple and neat implementation, where the signals specified for each block
-are also independent of the range of realtime signal for the system. The
-downside is, that the signal value cannot be used to pass information to a
-script, however, this can easily be done via a tmp file with more flexibility.
-
-Instead of waiting the GCD of all timer values (or worse, plainly 1 sec), wmsl
-waits as long as possible, until the next block must be run. This way, given two
-scripts with update intervals 3 and 10, which are coprime, instead of waiting 10
-times in 10 seconds, we wait 4 times e.g. 3s, 3s, 3s, 1s.
-
-The status bar is only updated, if the status has changed. However, a new status
-is compared with the previously set status BY WMSL, not the current, potentially
-changed status.
-
-
-Requirements
-------------
-Xlib header files for setting root window property WM_NAME
-
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..3bee720
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,13 @@
+wmsl - Window Manager Status Line
+=================================
+
+wmsl is a simple status line program for window managers like dwm.
+
+
+Features
+--------
+
+- status *blocks* are updated by timer or unique signal
+- simple runtime config format (see `wmslrc`)
+- extensible source in 350 LOC
+
diff --git a/sigwmsl.c b/sigwmsl.c
index ce182c3..c1e9202 100644
--- a/sigwmsl.c
+++ b/sigwmsl.c
@@ -34,7 +34,7 @@ main(int argc, const char **argv)
pid = atoi(buffer);
sigval.sival_int = block_id;
- if (sigqueue(pid, SIGALRM, sigval) == -1) {
+ if (sigqueue(pid, SIGUSR1, sigval) == -1) {
if (errno == EINVAL) {
errx(1, "invalid signal value");
} else if (errno == ESRCH) {
diff --git a/wmsl.c b/wmsl.c
index 1485ad8..e3527bb 100644
--- a/wmsl.c
+++ b/wmsl.c
@@ -1,5 +1,6 @@
#include <X11/Xlib.h>
+#include <bits/time.h>
#include <sys/poll.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -21,25 +22,21 @@ struct block {
struct block *next;
const char *command;
bool ready;
- int id, sleep_max;
- float sleep_left;
+ int id, sleep;
+ time_t sleep_left;
char output[OUTPUTMAX];
};
-static const char *usage = "Usage: wmsl [-h] [-v]\n";
+static const char *usage = "Usage: wmsl [-C FILE] [-h] [-v]\n";
static const char *pid_file = "/tmp/wmsl.pid";
+static pid_t pid;
static char status_text[OUTPUTMAX];
static size_t status_len;
-static float last_sleep;
-
static Display *dpy;
static Window root;
-static int verbose;
-static pid_t pid;
-
static char config[1024];
static struct block *blocks;
@@ -59,11 +56,22 @@ static void
sigexit(int sig)
{
update_status("");
- exit(128+sig);
+ exit(128 + sig);
+}
+
+static time_t
+now_ms(void)
+{
+ struct timespec now;
+
+ if (clock_gettime(CLOCK_REALTIME, &now))
+ err(1, "clock_gettime REALTIME");
+
+ return now.tv_sec * 1000L + now.tv_nsec / 1000000L;
}
static void
-signal_handler(int sig, siginfo_t *info, void *context)
+sighandler(int sig, siginfo_t *info, void *context)
{
struct block *block;
int block_id;
@@ -80,10 +88,11 @@ signal_handler(int sig, siginfo_t *info, void *context)
}
static void
-concat_status(const char *text, size_t len)
+concat_status(const char *text)
{
+ size_t len = strlen(text);
if (status_len + len + 1 > OUTPUTMAX)
- len = OUTPUTMAX - status_len;
+ len = OUTPUTMAX - status_len - 1;
memcpy(&status_text[status_len], text, len);
status_len += len;
if (status_len == OUTPUTMAX)
@@ -100,14 +109,12 @@ run_block(const char *cmd, pid_t *pid)
err(1, "pipe");
*pid = fork();
- if (*pid < 0)
- err(1, "fork");
+ if (*pid < 0) err(1, "fork");
- if (*pid != 0) {
+ if (*pid) {
close(out[1]);
} else {
- signal(SIGINT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
+ close(0);
dup2(out[1], 1);
close(out[0]);
close(out[1]);
@@ -118,55 +125,47 @@ run_block(const char *cmd, pid_t *pid)
return out[0];
}
-static size_t
+static void
read_block(int fd, char *buf, size_t size)
{
- struct timespec now;
- time_t now_ms, end_ms;
+ time_t start_ms, end_ms;
struct pollfd pollfd;
ssize_t nread;
- char *tok, *end;
+ char *tok;
pollfd.fd = fd;
pollfd.events = POLLIN;
- clock_gettime(CLOCK_REALTIME, &now);
- now_ms = now.tv_nsec / 1000000L + now.tv_sec * 1000L;
+ start_ms = now_ms();
+ end_ms = start_ms + 1000; /* 1 second timeout */
- end_ms = now_ms + 1000; /* 1 second timeout */
-
- end = buf;
- while (end_ms > now_ms) {
- if (poll(&pollfd, 1, (int) (end_ms - now_ms)) <= 0)
+ *buf = '\0';
+ while (end_ms > start_ms) {
+ if (poll(&pollfd, 1, (int) (end_ms - start_ms)) <= 0)
break;
-
- clock_gettime(CLOCK_REALTIME, &now);
- now_ms = now.tv_nsec / 1000000L + now.tv_sec * 1000L;
+ start_ms = now_ms();
if (!(pollfd.revents & POLLIN))
continue;
- nread = read(fd, end, size);
+ nread = read(fd, buf, size);
if (nread <= 0) break;
- tok = memchr(end, '\n', (size_t) nread);
+ tok = memchr(buf, '\n', (size_t) nread);
if (tok) *tok = '\0';
- end += nread;
+ buf += nread;
size -= (size_t) nread;
- if (tok) return strlen(buf);
+ if (tok) break;
}
-
- return 0;
}
static void
update_blocks(void)
{
- size_t output_len;
- char tmp_output[OUTPUTMAX];
struct block *block;
+ char buf[OUTPUTMAX];
pid_t child;
bool update;
int fd;
@@ -174,99 +173,65 @@ update_blocks(void)
status_text[0] = '\0';
status_len = 0;
- concat_status(prefix, strlen(prefix));
+ concat_status(prefix);
update = false;
for (block = blocks; block; block = block->next) {
- if (block->ready || block->sleep_max && block->sleep_left <= 0.2) {
- block->sleep_left = (float) block->sleep_max;
+ if (block->ready || block->sleep && block->sleep_left <= 50) {
+ block->sleep_left = block->sleep * 1000;
block->ready = false;
fd = run_block(block->command, &child);
- memset(tmp_output, 0, sizeof(tmp_output));
- output_len = read_block(fd, tmp_output, sizeof(tmp_output)-1);
-
- if (strcmp(tmp_output, block->output)) {
- strncpy(block->output, tmp_output, OUTPUTMAX);
+ read_block(fd, buf, sizeof(buf)-1);
+ if (strcmp(buf, block->output)) {
+ strncpy(block->output, buf, OUTPUTMAX);
update = true;
}
close(fd);
kill(child, SIGKILL);
waitpid(child, NULL, 0);
- } else {
- output_len = strlen(block->output);
}
- if (output_len) {
+ if (*block->output) {
if (status_len > 0)
- concat_status(delim, strlen(delim));
- concat_status(block->output, output_len);
+ concat_status(delim);
+ concat_status(block->output);
}
}
if (!update) return;
- concat_status(suffix, strlen(suffix));
+ concat_status(suffix);
update_status(status_text);
}
-static float
-get_elapsed(void)
-{
- static struct timespec last = { .tv_nsec = -1 };
- struct timespec cur;
- float diff;
-
- if (clock_gettime(CLOCK_MONOTONIC, &cur) == -1)
- err(1, "clock_gettime");
-
- if (last.tv_nsec == -1)
- diff = 0;
- else
- diff = (float) (cur.tv_sec - last.tv_sec)
- + (float) (cur.tv_nsec - last.tv_nsec) / 1000000000.f;
-
- last = cur;
- return diff;
-}
-
static void
-sleep_till_next(void)
+sleep_next(void)
{
struct block *block;
- unsigned int min_sleep;
-
- last_sleep = 0; /* reset last_sleep in case we return early */
+ time_t min_sleep;
+ time_t start_ms;
+ time_t stop_ms;
min_sleep = 0;
for (block = blocks; block; block = block->next) {
- if (block->ready || block->sleep_max && block->sleep_left <= 0)
+ if (block->ready || block->sleep && block->sleep_left <= 0)
return;
- if (!min_sleep || block->sleep_max && block->sleep_left < min_sleep)
- min_sleep = (unsigned int) ceil(block->sleep_left);
+ if (!min_sleep || block->sleep && block->sleep_left < min_sleep)
+ min_sleep = block->sleep_left;
}
- if (min_sleep < 1)
- min_sleep = 1;
-
- alarm(min_sleep);
- pause();
-
- last_sleep = get_elapsed();
-}
-
-static void
-save_pid(void)
-{
- FILE *file;
+ start_ms = now_ms();
+ poll(NULL, 0, (int) min_sleep);
+ stop_ms = now_ms();
- pid = getpid();
- file = fopen(pid_file, "w+");
- if (!file) err(1, "fopen '%s'", pid_file);
- fprintf(file, "%i", pid);
- fclose(file);
+ for (block = blocks; block; block = block->next) {
+ if (block->sleep) {
+ block->sleep_left -= (stop_ms - start_ms);
+ }
+ }
}
static void
@@ -281,7 +246,7 @@ read_config(void)
block = &blocks;
while (fgets(line, 256, file)) {
- if (strspn(line, " \n\v\t") == strlen(line))
+ if (*line == '#' || strspn(line, " \n\v\t") == strlen(line))
continue;
if ((tok = strchr(line, '\n')))
*tok = '\0';
@@ -298,7 +263,7 @@ read_config(void)
(*block)->command = strdup(line + 6);
(*block)->id = 0;
(*block)->sleep_left = 0;
- (*block)->sleep_max = 0;
+ (*block)->sleep = 0;
(*block)->ready = true;
(*block)->next = NULL;
} else if (!strncmp(line, "block-id=", 9)) {
@@ -306,7 +271,7 @@ read_config(void)
(*block)->id = atoi(line + 9);
} else if (!strncmp(line, "block-sleep=", 12)) {
if (!*block) errx(1, "missing block=");
- (*block)->sleep_max = atoi(line + 12);
+ (*block)->sleep = atoi(line + 12);
} else {
errx(1, "invalid config");
}
@@ -322,47 +287,38 @@ read_config(void)
int
main(int argc, const char **argv)
{
+ const char **arg;
struct sigaction sa;
const char *home;
- struct block *block;
- int i, screen;
-
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-')
- switch (argv[i][1]) {
- case 'C':
- strncpy(config, argv[++i], sizeof(config));
- break;
- case 'v':
- verbose = 1;
- break;
- case 'h':
- fputs(usage, stdout);
- return 0;
- default:
- fputs(usage, stderr);
- return 1;
+ int screen;
+ FILE *file;
+
+ if (argc <= 0) return 1;
+
+ for (arg = argv + 1; *arg; arg++) {
+ if ((*arg)[0] != '-')
+ errx(1, "invalid arg: %s", *arg);
+ switch ((*arg)[1]) {
+ case 'C':
+ strncpy(config, *++arg, sizeof(config));
+ break;
+ case 'h':
+ fputs(usage, stdout);
+ return 0;
+ default:
+ fputs(usage, stderr);
+ return 1;
}
}
- /* get and parse config */
if (!*config) {
home = getenv("HOME");
if (!home) errx(1, "not config");
snprintf(config, sizeof(config),
"%s/.config/wmsl/wmslrc", home);
}
- read_config();
- /* setup signal handlers & cleanup */
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = NULL;
- sa.sa_sigaction = signal_handler;
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- if (sigaction(SIGALRM, &sa, NULL))
- err(1, "sigaction");
- signal(SIGINT, sigexit);
- signal(SIGTERM, sigexit);
+ read_config();
/* get root window */
dpy = XOpenDisplay(NULL);
@@ -370,28 +326,25 @@ main(int argc, const char **argv)
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
- save_pid();
+ /* save pid */
+ pid = getpid();
+ file = fopen(pid_file, "w+");
+ if (!file) err(1, "fopen '%s'", pid_file);
+ fprintf(file, "%i", pid);
+ fclose(file);
- /* check if any blocks require timers */
- for (block = blocks; block; block = block->next) {
- if (block->sleep_max != 0) break;
- }
+ /* setup signal handlers & cleanup */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = NULL;
+ sa.sa_sigaction = sighandler;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (sigaction(SIGUSR1, &sa, NULL))
+ err(1, "sigaction");
+ signal(SIGINT, sigexit);
+ signal(SIGTERM, sigexit);
- if (block) {
- get_elapsed();
- while (1) {
- sleep_till_next();
- for (block = blocks; block; block = block->next) {
- if (block->sleep_max) {
- block->sleep_left -= last_sleep;
- }
- }
- update_blocks();
- }
- } else {
- while (1) {
- pause();
- update_blocks();
- }
+ while (1) {
+ sleep_next();
+ update_blocks();
}
}
diff --git a/wmslrc b/wmslrc
new file mode 100644
index 0000000..ddef5fa
--- /dev/null
+++ b/wmslrc
@@ -0,0 +1,14 @@
+prefix=
+suffix=
+delim= |
+
+# a block that is only updated on signal
+block=date
+block-id=10
+
+# a block that is update every 5 seconds
+block=date
+block-sleep=5
+
+# a block that is only updated on start
+block=date