status

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

status.c (3875B)


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