status

statusbar program for dwm
git clone anongit@rnpnr.xyz:status.git
Log | Files | Refs | Feed | README | LICENSE

status.c (4303B)


      1 /* See LICENSE for license details. */
      2 #include <signal.h>
      3 #include <stdarg.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <time.h>
      8 #include <unistd.h>
      9 #include <X11/Xlib.h>
     10 
     11 #define ABS(a) ((a) < 0 ? -(a) : (a))
     12 #define LEN(a) (sizeof(a) / sizeof(*a))
     13 #define BLOCKLEN 128
     14 #define BLOCKPAD 4
     15 #define STATUSLEN ((LEN(blks) - 1) * BLOCKLEN + 1)
     16 
     17 struct Block {
     18 	size_t (*fn)(struct Block *b);
     19 	const char *fmt;
     20 	int interval;
     21 	int signal;
     22 	void *arg;
     23 	char curstr[BLOCKLEN];
     24 	char prevstr[BLOCKLEN];
     25 	size_t len;
     26 };
     27 
     28 static char buf[BLOCKLEN - BLOCKPAD];
     29 static Display *dpy;
     30 static int dflag = 0;
     31 static sigset_t blocksigmask;
     32 static struct Block *dirty;
     33 
     34 static void
     35 die(const char *errstr, ...)
     36 {
     37 	va_list ap;
     38 
     39 	va_start(ap, errstr);
     40 	vfprintf(stderr, errstr, ap);
     41 	va_end(ap);
     42 	exit(1);
     43 }
     44 
     45 static int
     46 pscanf(const char *path, const char *fmt, ...)
     47 {
     48 	FILE *fp;
     49 	va_list ap;
     50 	int ret;
     51 
     52 	if (!(fp = fopen(path, "r")))
     53 		return -1;
     54 
     55 	va_start(ap, fmt);
     56 	ret = vfscanf(fp, fmt, ap);
     57 	va_end(ap);
     58 	fclose(fp);
     59 
     60 	return (ret == EOF) ? -1 : ret;
     61 }
     62 
     63 #include "config.h"
     64 
     65 static void
     66 terminate(int signo)
     67 {
     68 	if (!dflag) {
     69 		XStoreName(dpy, DefaultRootWindow(dpy), NULL);
     70 		XCloseDisplay(dpy);
     71 	}
     72 
     73 	exit(0);
     74 }
     75 
     76 static void
     77 updateblock(struct Block *b)
     78 {
     79 	b->len = b->fn(b);
     80 	if ((b->len == 0 && b->prevstr[0] != 0) ||
     81 	    memcmp(b->curstr, b->prevstr, b->len)) {
     82 		if (b->len == 0)
     83 			b->prevstr[0] = b->curstr[0] = 0;
     84 		else
     85 			memcpy(b->prevstr, b->curstr, b->len);
     86 		if (!dirty || b < dirty)
     87 			dirty = b;
     88 	}
     89 }
     90 
     91 static void
     92 updatestatus(void)
     93 {
     94 	static char status[STATUSLEN];
     95 	struct Block *b;
     96 	char *s = status;
     97 
     98 	for (b = blks; b < dirty; b++)
     99 		s += b->len;
    100 
    101 	for (; b->fn; b++) {
    102 		memcpy(s, b->curstr, b->len);
    103 		s += b->len;
    104 	}
    105 	s[0] = '\0';
    106 	dirty = NULL;
    107 
    108 	if (dflag) {
    109 		puts(status);
    110 		return;
    111 	}
    112 
    113 	XStoreName(dpy, DefaultRootWindow(dpy), status);
    114 	XSync(dpy, False);
    115 }
    116 
    117 static void
    118 sighandler(int signo, siginfo_t *info, void *context)
    119 {
    120 	struct Block *b;
    121 
    122 	signo -= SIGRTMIN;
    123 	for (b = blks; b->fn; b++)
    124 		if (b->signal == signo)
    125 			updateblock(b);
    126 	if (dirty)
    127 		updatestatus();
    128 }
    129 
    130 static void
    131 setupsigs(void)
    132 {
    133 	int i;
    134 	struct Block *b;
    135 	struct sigaction sa;
    136 
    137 	/* add signals to blocksigmask */
    138 	sigemptyset(&blocksigmask);
    139 	for (b = blks; b->fn; b++) {
    140 		if (b->signal <= 0)
    141 			continue;
    142 
    143 		if (b->signal > SIGRTMAX - SIGRTMIN)
    144 			die("SIGRTMIN + %d exceeds SIGRTMAX\n", b->signal);
    145 
    146 		sigaddset(&blocksigmask, SIGRTMIN + b->signal);
    147 	}
    148 
    149 	/* handle terminating signals */
    150 	sa.sa_flags = SA_RESTART;
    151 	sigemptyset(&sa.sa_mask);
    152 	sa.sa_handler = terminate;
    153 	sigaction(SIGHUP,  &sa, NULL);
    154 	sigaction(SIGINT,  &sa, NULL);
    155 	sigaction(SIGTERM, &sa, NULL);
    156 
    157 	/* ignore unused realtime signals */
    158 	sa.sa_handler = SIG_IGN;
    159 	for (i = SIGRTMIN + 1; i <= SIGRTMAX; i++)
    160 		sigaction(i, &sa, NULL);
    161 
    162 	/* handle update signals for blocks */
    163 	sa.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
    164 	sa.sa_mask = blocksigmask;
    165 	sa.sa_sigaction = sighandler;
    166 	for (b = blks; b->fn; b++)
    167 		if (b->signal > 0)
    168 			sigaction(SIGRTMIN + b->signal, &sa, NULL);
    169 
    170 	/* start with signals blocked */
    171 	sigprocmask(SIG_BLOCK, &blocksigmask, NULL);
    172 }
    173 
    174 static void
    175 statusinit(void)
    176 {
    177 	struct Block *b;
    178 
    179 	setupsigs();
    180 
    181 	if (!dflag && !(dpy = XOpenDisplay(NULL)))
    182 		die("XOpenDisplay: can't open display\n");
    183 
    184 	/* initialize blocks before first print */
    185 	for (b = blks; b->fn; b++)
    186 		if (b->interval != -1)
    187 			updateblock(b);
    188 	updatestatus();
    189 }
    190 
    191 static void
    192 statusloop(void)
    193 {
    194 	unsigned int i = 0;
    195 	struct Block *b;
    196 	struct timespec t;
    197 
    198 	for (;;) {
    199 		sigprocmask(SIG_UNBLOCK, &blocksigmask, NULL);
    200 		t.tv_sec = INTERVAL_SEC;
    201 		t.tv_nsec = INTERVAL_NANO;
    202 		while (nanosleep(&t, &t) == -1);
    203 		sigprocmask(SIG_BLOCK, &blocksigmask, NULL);
    204 
    205 		for (b = blks; b->fn; b++)
    206 			if (b->interval > 0 && i % b->interval == 0)
    207 				updateblock(b);
    208 		if (dirty)
    209 			updatestatus();
    210 		i++;
    211 	}
    212 }
    213 
    214 int
    215 main(int argc, char *argv[])
    216 {
    217 	int i;
    218 	char *argv0 = *argv;
    219 
    220 	for (argv++; --argc && *argv && argv[0][0] == '-' && argv[0][1]; argv++) {
    221 		if (argv[0][1] == '-' && argv[0][2] == '\0') {
    222 			argv++;
    223 			argc--;
    224 			break;
    225 		}
    226 
    227 		for (i = 1; argv[0][i]; i++)
    228 			switch (argv[0][i]) {
    229 			case 'd':
    230 				dflag = 1;
    231 				break;
    232 			default:
    233 				die("usage: %s [-d]\n", argv0);
    234 			}
    235 	}
    236 
    237 	statusinit();
    238 	statusloop();
    239 
    240 	return 0;
    241 }