slstatus.c - slstatus - status monitor | |
git clone git://git.suckless.org/slstatus | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
slstatus.c (2643B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <errno.h> | |
3 #include <signal.h> | |
4 #include <stdio.h> | |
5 #include <stdlib.h> | |
6 #include <string.h> | |
7 #include <time.h> | |
8 #include <X11/Xlib.h> | |
9 | |
10 #include "arg.h" | |
11 #include "slstatus.h" | |
12 #include "util.h" | |
13 | |
14 struct arg { | |
15 const char *(*func)(const char *); | |
16 const char *fmt; | |
17 const char *args; | |
18 }; | |
19 | |
20 char buf[1024]; | |
21 static volatile sig_atomic_t done; | |
22 static Display *dpy; | |
23 | |
24 #include "config.h" | |
25 | |
26 static void | |
27 terminate(const int signo) | |
28 { | |
29 if (signo != SIGUSR1) | |
30 done = 1; | |
31 } | |
32 | |
33 static void | |
34 difftimespec(struct timespec *res, struct timespec *a, struct timespec *… | |
35 { | |
36 res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec); | |
37 res->tv_nsec = a->tv_nsec - b->tv_nsec + | |
38 (a->tv_nsec < b->tv_nsec) * 1E9; | |
39 } | |
40 | |
41 static void | |
42 usage(void) | |
43 { | |
44 die("usage: %s [-v] [-s] [-1]", argv0); | |
45 } | |
46 | |
47 int | |
48 main(int argc, char *argv[]) | |
49 { | |
50 struct sigaction act; | |
51 struct timespec start, current, diff, intspec, wait; | |
52 size_t i, len; | |
53 int sflag, ret; | |
54 char status[MAXLEN]; | |
55 const char *res; | |
56 | |
57 sflag = 0; | |
58 ARGBEGIN { | |
59 case 'v': | |
60 die("slstatus-"VERSION); | |
61 break; | |
62 case '1': | |
63 done = 1; | |
64 /* FALLTHROUGH */ | |
65 case 's': | |
66 sflag = 1; | |
67 break; | |
68 default: | |
69 usage(); | |
70 } ARGEND | |
71 | |
72 if (argc) | |
73 usage(); | |
74 | |
75 memset(&act, 0, sizeof(act)); | |
76 act.sa_handler = terminate; | |
77 sigaction(SIGINT, &act, NULL); | |
78 sigaction(SIGTERM, &act, NULL); | |
79 act.sa_flags |= SA_RESTART; | |
80 sigaction(SIGUSR1, &act, NULL); | |
81 | |
82 if (!sflag && !(dpy = XOpenDisplay(NULL))) | |
83 die("XOpenDisplay: Failed to open display"); | |
84 | |
85 do { | |
86 if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) | |
87 die("clock_gettime:"); | |
88 | |
89 status[0] = '\0'; | |
90 for (i = len = 0; i < LEN(args); i++) { | |
91 if (!(res = args[i].func(args[i].args))) | |
92 res = unknown_str; | |
93 | |
94 if ((ret = esnprintf(status + len, sizeof(status… | |
95 args[i].fmt, res)) < 0) | |
96 break; | |
97 | |
98 len += ret; | |
99 } | |
100 | |
101 if (sflag) { | |
102 puts(status); | |
103 fflush(stdout); | |
104 if (ferror(stdout)) | |
105 die("puts:"); | |
106 } else { | |
107 if (XStoreName(dpy, DefaultRootWindow(dpy), stat… | |
108 die("XStoreName: Allocation failed"); | |
109 XFlush(dpy); | |
110 } | |
111 | |
112 if (!done) { | |
113 if (clock_gettime(CLOCK_MONOTONIC, ¤t) < 0) | |
114 die("clock_gettime:"); | |
115 difftimespec(&diff, ¤t, &start); | |
116 | |
117 intspec.tv_sec = interval / 1000; | |
118 intspec.tv_nsec = (interval % 1000) * 1E6; | |
119 difftimespec(&wait, &intspec, &diff); | |
120 | |
121 if (wait.tv_sec >= 0 && | |
122 nanosleep(&wait, NULL) < 0 && | |
123 errno != EINTR) | |
124 die("nanosleep:"); | |
125 } | |
126 } while (!done); | |
127 | |
128 if (!sflag) { | |
129 XStoreName(dpy, DefaultRootWindow(dpy), NULL); | |
130 if (XCloseDisplay(dpy) < 0) | |
131 die("XCloseDisplay: Failed to close display"); | |
132 } | |
133 | |
134 return 0; | |
135 } |