suckless/slstatus

slstatus.c in master
Repositories | Summary | Log | Files | README | LICENSE

slstatus.c (3578B) download


  1/* See LICENSE file for copyright and license details. */
  2#include <errno.h>
  3#include <fcntl.h>
  4#include <signal.h>
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <string.h>
  8#include <time.h>
  9#include <unistd.h>
 10#include <poll.h>
 11#include <X11/Xlib.h>
 12
 13#include "arg.h"
 14#include "slstatus.h"
 15#include "util.h"
 16
 17struct arg {
 18	const char *(*func)(const char *);
 19	int (*doenable)(const char *);
 20	const char *fmt;
 21	const char *args;
 22};
 23
 24char buf[1024];
 25static volatile sig_atomic_t done;
 26static Display *dpy;
 27
 28int always(const char *unused) {
 29	(void)unused;
 30	return 1;
 31}
 32
 33int never(const char *unused) {
 34	(void)unused;
 35	return 0;
 36}
 37
 38#include "config.h"
 39
 40static void
 41terminate(const int signo)
 42{
 43	if (signo != SIGUSR1)
 44		done = 1;
 45}
 46
 47static void
 48difftimespec(struct timespec *res, struct timespec *a, struct timespec *b)
 49{
 50	res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec);
 51	res->tv_nsec = a->tv_nsec - b->tv_nsec +
 52	               (a->tv_nsec < b->tv_nsec) * 1E9;
 53}
 54
 55static int
 56getnotify(int fifo, char* buffer, size_t size)
 57{
 58	struct pollfd fds = { fifo, POLLIN, 0 };
 59
 60	if (poll(&fds, 1, 0) <= 0)
 61		return 0;
 62
 63	int len = 0;
 64	while (read(fifo, buffer + len, 1) > 0 && buffer[len] != '\n' && len < size)
 65		len++;
 66	buffer[len] = '\0';
 67	return len;
 68}
 69
 70static void
 71usage(void)
 72{
 73	die("usage: %s [-v] [-s] [-1] [-p fifo]", argv0);
 74}
 75
 76int
 77main(int argc, char *argv[])
 78{
 79	struct sigaction act;
 80	struct timespec start, current, diff, intspec, wait;
 81	size_t i, len;
 82	int sflag, ret;
 83	int fifo, msgcycle = 0;
 84	char status[MAXLEN];
 85	const char *res;
 86	const char *fifopath = NULL;
 87	char *nl;
 88
 89	sflag = 0;
 90	ARGBEGIN {
 91	case 'v':
 92		die("slstatus-"VERSION);
 93	case '1':
 94		done = 1;
 95		/* FALLTHROUGH */
 96	case 's':
 97		sflag = 1;
 98		break;
 99	case 'p':
100		fifopath = EARGF(usage());
101		break;
102	default:
103		usage();
104	} ARGEND
105
106	if (argc)
107		usage();
108
109	memset(&act, 0, sizeof(act));
110	act.sa_handler = terminate;
111	sigaction(SIGINT,  &act, NULL);
112	sigaction(SIGTERM, &act, NULL);
113	act.sa_flags |= SA_RESTART;
114	sigaction(SIGUSR1, &act, NULL);
115
116	if (fifopath && (fifo = open(fifopath, O_RDONLY)) == -1)
117		die("open(fifo): ");
118
119	if (!sflag && !(dpy = XOpenDisplay(NULL)))
120		die("XOpenDisplay: Failed to open display");
121
122	do {
123		if (clock_gettime(CLOCK_MONOTONIC, &start) < 0)
124			die("clock_gettime:");
125
126		if (msgcycle > 0) {
127			msgcycle--;
128		} else if (fifopath && getnotify(fifo, status, sizeof(status)) > 0) {
129			if (!*status)
130				continue;
131		
132			msgcycle = maxmsgcycle;
133		} else {
134		status[0] = '\0';
135		for (i = len = 0; i < LEN(args); i++) {
136				if (!args[i].doenable(args[i].args))
137					continue;
138
139			if (!(res = args[i].func(args[i].args)))
140				res = unknown_str;
141
142			if ((ret = esnprintf(status + len, sizeof(status) - len,
143			                     args[i].fmt, res)) < 0)
144				break;
145
146			len += ret;
147			}
148		}
149
150		if (sflag) {
151			puts(status);
152			fflush(stdout);
153			if (ferror(stdout))
154				die("puts:");
155		} else {
156			if (XStoreName(dpy, DefaultRootWindow(dpy), status) < 0)
157				die("XStoreName: Allocation failed");
158			XFlush(dpy);
159		}
160
161		if (!done) {
162			if (clock_gettime(CLOCK_MONOTONIC, &current) < 0)
163				die("clock_gettime:");
164			difftimespec(&diff, &current, &start);
165
166			intspec.tv_sec = interval / 1000;
167			intspec.tv_nsec = (interval % 1000) * 1E6;
168			difftimespec(&wait, &intspec, &diff);
169
170			if (wait.tv_sec >= 0 &&
171			    nanosleep(&wait, NULL) < 0 &&
172			    errno != EINTR)
173					die("nanosleep:");
174		}
175	} while (!done);
176
177	if (!sflag) {
178		XStoreName(dpy, DefaultRootWindow(dpy), NULL);
179		if (XCloseDisplay(dpy) < 0)
180			die("XCloseDisplay: Failed to close display");
181	}
182
183	return 0;
184}