Xinqi Bao's Git

slstatus load_avg format string
[slstatus.git] / slstatus.c
1 /* See LICENSE file for copyright and license details. */
2 #include <dirent.h>
3 #include <err.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <ifaddrs.h>
7 #include <limits.h>
8 #include <linux/wireless.h>
9 #include <netdb.h>
10 #include <pwd.h>
11 #include <signal.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/ioctl.h>
17 #include <sys/stat.h>
18 #include <sys/statvfs.h>
19 #include <sys/socket.h>
20 #include <sys/soundcard.h>
21 #include <sys/sysinfo.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <X11/Xlib.h>
27
28 #include "arg.h"
29
30 #define LEN(x) (sizeof (x) / sizeof *(x))
31
32 struct arg {
33 const char *(*func)();
34 const char *fmt;
35 const char *args;
36 };
37
38 static const char *battery_perc(const char *bat);
39 static const char *battery_power(const char *bat);
40 static const char *battery_state(const char *bat);
41 static const char *cpu_freq(void);
42 static const char *cpu_perc(void);
43 static const char *datetime(const char *fmt);
44 static const char *disk_free(const char *mnt);
45 static const char *disk_perc(const char *mnt);
46 static const char *disk_total(const char *mnt);
47 static const char *disk_used(const char *mnt);
48 static const char *entropy(void);
49 static const char *gid(void);
50 static const char *hostname(void);
51 static const char *ipv4(const char *iface);
52 static const char *ipv6(const char *iface);
53 static const char *kernel_release(void);
54 static const char *keyboard_indicators(void);
55 static const char *load_avg(const char *fmt);
56 static const char *num_files(const char *dir);
57 static const char *ram_free(void);
58 static const char *ram_perc(void);
59 static const char *ram_used(void);
60 static const char *ram_total(void);
61 static const char *run_command(const char *cmd);
62 static const char *swap_free(void);
63 static const char *swap_perc(void);
64 static const char *swap_used(void);
65 static const char *swap_total(void);
66 static const char *temp(const char *file);
67 static const char *uid(void);
68 static const char *uptime(void);
69 static const char *username(void);
70 static const char *vol_perc(const char *card);
71 static const char *wifi_perc(const char *iface);
72 static const char *wifi_essid(const char *iface);
73
74 char *argv0;
75 static unsigned short int done;
76 static Display *dpy;
77
78 #include "config.h"
79
80 static char buf[MAXLEN];
81
82 static const char *
83 bprintf(const char *fmt, ...)
84 {
85 va_list ap;
86 size_t len;
87
88 va_start(ap, fmt);
89 len = vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
90 va_end(ap);
91
92 if (len >= sizeof(buf))
93 buf[sizeof(buf)-1] = '\0';
94
95 return buf;
96 }
97
98 int
99 pscanf(const char *path, const char *fmt, ...)
100 {
101 FILE *fp;
102 va_list ap;
103 int n;
104
105 if (!(fp = fopen(path, "r"))) {
106 warn("fopen %s: %s\n", path, strerror(errno));
107 return -1;
108 }
109 va_start(ap, fmt);
110 n = vfscanf(fp, fmt, ap);
111 va_end(ap);
112 fclose(fp);
113
114 return (n == EOF) ? -1 : n;
115 }
116
117 static const char *
118 battery_perc(const char *bat)
119 {
120 int perc;
121 char path[PATH_MAX];
122
123 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/capacity");
124 return (pscanf(path, "%i", &perc) == 1) ?
125 bprintf("%d", perc) : unknown_str;
126 }
127
128 static const char *
129 battery_power(const char *bat)
130 {
131 int watts;
132 char path[PATH_MAX];
133
134 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/power_now");
135 return (pscanf(path, "%i", &watts) == 1) ?
136 bprintf("%d", (watts + 500000) / 1000000) : unknown_str;
137 }
138
139 static const char *
140 battery_state(const char *bat)
141 {
142 struct {
143 char *state;
144 char *symbol;
145 } map[] = {
146 { "Charging", "+" },
147 { "Discharging", "-" },
148 { "Full", "=" },
149 { "Unknown", "/" },
150 };
151 size_t i;
152 char path[PATH_MAX], state[12];
153
154 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/status");
155 if (pscanf(path, "%12s", state) != 1) {
156 return unknown_str;
157 }
158
159 for (i = 0; i < LEN(map); i++) {
160 if (!strcmp(map[i].state, state)) {
161 break;
162 }
163 }
164 return (i == LEN(map)) ? "?" : map[i].symbol;
165 }
166
167 static const char *
168 cpu_freq(void)
169 {
170 int freq;
171
172 return (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
173 "%i", &freq) == 1) ?
174 bprintf("%d", (freq + 500) / 1000) : unknown_str;
175 }
176
177 static const char *
178 cpu_perc(void)
179 {
180 struct timespec delay;
181 int perc;
182 long double a[4], b[4];
183
184 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2],
185 &a[3]) != 4) {
186 return unknown_str;
187 }
188
189 delay.tv_sec = (interval / 2) / 1000;
190 delay.tv_nsec = ((interval / 2) % 1000) * 1000000;
191 nanosleep(&delay, NULL);
192
193 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2],
194 &b[3]) != 4) {
195 return unknown_str;
196 }
197
198 perc = 100 * ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) /
199 ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3]));
200
201 return bprintf("%d", perc);
202 }
203
204 static const char *
205 datetime(const char *fmt)
206 {
207 time_t t;
208
209 t = time(NULL);
210 if (strftime(buf, sizeof(buf), fmt, localtime(&t)) == 0)
211 return unknown_str;
212
213 return buf;
214 }
215
216 static const char *
217 disk_free(const char *mnt)
218 {
219 struct statvfs fs;
220
221 if (statvfs(mnt, &fs) < 0) {
222 warn("Failed to get filesystem info");
223 return unknown_str;
224 }
225
226 return bprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
227 }
228
229 static const char *
230 disk_perc(const char *mnt)
231 {
232 int perc;
233 struct statvfs fs;
234
235 if (statvfs(mnt, &fs) < 0) {
236 warn("Failed to get filesystem info");
237 return unknown_str;
238 }
239
240 perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
241
242 return bprintf("%d", perc);
243 }
244
245 static const char *
246 disk_total(const char *mnt)
247 {
248 struct statvfs fs;
249
250 if (statvfs(mnt, &fs) < 0) {
251 warn("Failed to get filesystem info");
252 return unknown_str;
253 }
254
255 return bprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
256 }
257
258 static const char *
259 disk_used(const char *mnt)
260 {
261 struct statvfs fs;
262
263 if (statvfs(mnt, &fs) < 0) {
264 warn("Failed to get filesystem info");
265 return unknown_str;
266 }
267
268 return bprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
269 }
270
271 static const char *
272 entropy(void)
273 {
274 int num;
275
276 return (pscanf("/proc/sys/kernel/random/entropy_avail", "%d", &num) == 1) ?
277 bprintf("%d", num) : unknown_str;
278 }
279
280 static const char *
281 gid(void)
282 {
283 return bprintf("%d", getgid());
284 }
285
286 static const char *
287 hostname(void)
288 {
289 if (gethostname(buf, sizeof(buf)) == -1) {
290 warn("hostname");
291 return unknown_str;
292 }
293
294 return buf;
295 }
296
297 static const char *
298 ipv4(const char *iface)
299 {
300 struct ifaddrs *ifaddr, *ifa;
301 int s;
302 char host[NI_MAXHOST];
303
304 if (getifaddrs(&ifaddr) == -1) {
305 warn("Failed to get IPv4 address for interface %s", iface);
306 return unknown_str;
307 }
308
309 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
310 if (ifa->ifa_addr == NULL) {
311 continue;
312 }
313 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
314 if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
315 if (s != 0) {
316 warnx("Failed to get IPv4 address for interface %s", iface);
317 return unknown_str;
318 }
319 return bprintf("%s", host);
320 }
321 }
322
323 freeifaddrs(ifaddr);
324
325 return unknown_str;
326 }
327
328 static const char *
329 ipv6(const char *iface)
330 {
331 struct ifaddrs *ifaddr, *ifa;
332 int s;
333 char host[NI_MAXHOST];
334
335 if (getifaddrs(&ifaddr) == -1) {
336 warn("Failed to get IPv6 address for interface %s", iface);
337 return unknown_str;
338 }
339
340 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
341 if (ifa->ifa_addr == NULL) {
342 continue;
343 }
344 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
345 if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET6)) {
346 if (s != 0) {
347 warnx("Failed to get IPv6 address for interface %s", iface);
348 return unknown_str;
349 }
350 return bprintf("%s", host);
351 }
352 }
353
354 freeifaddrs(ifaddr);
355
356 return unknown_str;
357 }
358
359 static const char *
360 kernel_release(void)
361 {
362 struct utsname udata;
363
364 if (uname(&udata) < 0) {
365 return unknown_str;
366 }
367
368 return bprintf("%s", udata.release);
369 }
370
371 static const char *
372 keyboard_indicators(void)
373 {
374 Display *dpy = XOpenDisplay(NULL);
375 XKeyboardState state;
376
377 if (dpy == NULL) {
378 warnx("XOpenDisplay failed");
379 return unknown_str;
380 }
381 XGetKeyboardControl(dpy, &state);
382 XCloseDisplay(dpy);
383
384 switch (state.led_mask) {
385 case 1:
386 return "c";
387 case 2:
388 return "n";
389 case 3:
390 return "cn";
391 default:
392 return "";
393 }
394 }
395
396 static const char *
397 load_avg(const char *fmt)
398 {
399 double avgs[3];
400
401 if (getloadavg(avgs, 3) < 0) {
402 warnx("Failed to get the load avg");
403 return unknown_str;
404 }
405
406 return bprintf(fmt, avgs[0], avgs[1], avgs[2]);
407 }
408
409 static const char *
410 num_files(const char *dir)
411 {
412 struct dirent *dp;
413 DIR *fd;
414 int num = 0;
415
416 if ((fd = opendir(dir)) == NULL) {
417 warn("Failed to get number of files in directory %s", dir);
418 return unknown_str;
419 }
420
421 while ((dp = readdir(fd)) != NULL) {
422 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
423 continue; /* skip self and parent */
424 num++;
425 }
426
427 closedir(fd);
428
429 return bprintf("%d", num);
430 }
431
432 static const char *
433 ram_free(void)
434 {
435 long free;
436
437 return (pscanf("/proc/meminfo", "MemFree: %ld kB\n", &free) == 1) ?
438 bprintf("%f", (float)free / 1024 / 1024) : unknown_str;
439 }
440
441 static const char *
442 ram_perc(void)
443 {
444 long total, free, buffers, cached;
445
446 return (pscanf("/proc/meminfo",
447 "MemTotal: %ld kB\n"
448 "MemFree: %ld kB\n"
449 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
450 "Cached: %ld kB\n",
451 &total, &free, &buffers, &buffers, &cached) == 5) ?
452 bprintf("%d", 100 * ((total - free) - (buffers + cached)) / total) :
453 unknown_str;
454 }
455
456 static const char *
457 ram_total(void)
458 {
459 long total;
460
461 return (pscanf("/proc/meminfo", "MemTotal: %ld kB\n", &total) == 1) ?
462 bprintf("%f", (float)total / 1024 / 1024) : unknown_str;
463 }
464
465 static const char *
466 ram_used(void)
467 {
468 long total, free, buffers, cached;
469
470 return (pscanf("/proc/meminfo",
471 "MemTotal: %ld kB\n"
472 "MemFree: %ld kB\n"
473 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
474 "Cached: %ld kB\n",
475 &total, &free, &buffers, &buffers, &cached) == 5) ?
476 bprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024) :
477 unknown_str;
478 }
479
480 static const char *
481 run_command(const char *cmd)
482 {
483 char *p;
484 FILE *fp;
485
486 fp = popen(cmd, "r");
487 if (fp == NULL) {
488 warn("Failed to get command output for %s", cmd);
489 return unknown_str;
490 }
491 p = fgets(buf, sizeof(buf) - 1, fp);
492 pclose(fp);
493 if (!p)
494 return unknown_str;
495 if ((p = strrchr(buf, '\n')) != NULL)
496 p[0] = '\0';
497
498 return buf[0] ? buf : unknown_str;
499 }
500
501 static const char *
502 swap_free(void)
503 {
504 long total, free;
505 FILE *fp;
506 size_t bytes_read;
507 char *match;
508
509 fp = fopen("/proc/meminfo", "r");
510 if (fp == NULL) {
511 warn("Failed to open file /proc/meminfo");
512 return unknown_str;
513 }
514
515 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
516 warn("swap_free: read error");
517 fclose(fp);
518 return unknown_str;
519 }
520 fclose(fp);
521
522 if ((match = strstr(buf, "SwapTotal")) == NULL)
523 return unknown_str;
524 sscanf(match, "SwapTotal: %ld kB\n", &total);
525
526 if ((match = strstr(buf, "SwapFree")) == NULL)
527 return unknown_str;
528 sscanf(match, "SwapFree: %ld kB\n", &free);
529
530 return bprintf("%f", (float)free / 1024 / 1024);
531 }
532
533 static const char *
534 swap_perc(void)
535 {
536 long total, free, cached;
537 FILE *fp;
538 size_t bytes_read;
539 char *match;
540
541 fp = fopen("/proc/meminfo", "r");
542 if (fp == NULL) {
543 warn("Failed to open file /proc/meminfo");
544 return unknown_str;
545 }
546
547 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
548 warn("swap_perc: read error");
549 fclose(fp);
550 return unknown_str;
551 }
552 fclose(fp);
553
554 if ((match = strstr(buf, "SwapTotal")) == NULL)
555 return unknown_str;
556 sscanf(match, "SwapTotal: %ld kB\n", &total);
557
558 if ((match = strstr(buf, "SwapCached")) == NULL)
559 return unknown_str;
560 sscanf(match, "SwapCached: %ld kB\n", &cached);
561
562 if ((match = strstr(buf, "SwapFree")) == NULL)
563 return unknown_str;
564 sscanf(match, "SwapFree: %ld kB\n", &free);
565
566 return bprintf("%d", 100 * (total - free - cached) / total);
567 }
568
569 static const char *
570 swap_total(void)
571 {
572 long total;
573 FILE *fp;
574 size_t bytes_read;
575 char *match;
576
577 fp = fopen("/proc/meminfo", "r");
578 if (fp == NULL) {
579 warn("Failed to open file /proc/meminfo");
580 return unknown_str;
581 }
582 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
583 warn("swap_total: read error");
584 fclose(fp);
585 return unknown_str;
586 }
587 fclose(fp);
588
589 if ((match = strstr(buf, "SwapTotal")) == NULL)
590 return unknown_str;
591 sscanf(match, "SwapTotal: %ld kB\n", &total);
592
593 return bprintf("%f", (float)total / 1024 / 1024);
594 }
595
596 static const char *
597 swap_used(void)
598 {
599 long total, free, cached;
600 FILE *fp;
601 size_t bytes_read;
602 char *match;
603
604 fp = fopen("/proc/meminfo", "r");
605 if (fp == NULL) {
606 warn("Failed to open file /proc/meminfo");
607 return unknown_str;
608 }
609 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
610 warn("swap_used: read error");
611 fclose(fp);
612 return unknown_str;
613 }
614 fclose(fp);
615
616 if ((match = strstr(buf, "SwapTotal")) == NULL)
617 return unknown_str;
618 sscanf(match, "SwapTotal: %ld kB\n", &total);
619
620 if ((match = strstr(buf, "SwapCached")) == NULL)
621 return unknown_str;
622 sscanf(match, "SwapCached: %ld kB\n", &cached);
623
624 if ((match = strstr(buf, "SwapFree")) == NULL)
625 return unknown_str;
626 sscanf(match, "SwapFree: %ld kB\n", &free);
627
628 return bprintf("%f", (float)(total - free - cached) / 1024 / 1024);
629 }
630
631 static const char *
632 temp(const char *file)
633 {
634 int temp;
635
636 return (pscanf(file, "%d", &temp) == 1) ?
637 bprintf("%d", temp / 1000) : unknown_str;
638 }
639
640 static const char *
641 uptime(void)
642 {
643 struct sysinfo info;
644 int h = 0;
645 int m = 0;
646
647 sysinfo(&info);
648 h = info.uptime / 3600;
649 m = (info.uptime - h * 3600 ) / 60;
650
651 return bprintf("%dh %dm", h, m);
652 }
653
654 static const char *
655 username(void)
656 {
657 struct passwd *pw = getpwuid(geteuid());
658
659 if (pw == NULL) {
660 warn("Failed to get username");
661 return unknown_str;
662 }
663
664 return bprintf("%s", pw->pw_name);
665 }
666
667 static const char *
668 uid(void)
669 {
670 return bprintf("%d", geteuid());
671 }
672
673
674 static const char *
675 vol_perc(const char *card)
676 {
677 unsigned int i;
678 int v, afd, devmask;
679 char *vnames[] = SOUND_DEVICE_NAMES;
680
681 afd = open(card, O_RDONLY | O_NONBLOCK);
682 if (afd == -1) {
683 warn("Cannot open %s", card);
684 return unknown_str;
685 }
686
687 if (ioctl(afd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
688 warn("Cannot get volume for %s", card);
689 close(afd);
690 return unknown_str;
691 }
692 for (i = 0; i < LEN(vnames); i++) {
693 if (devmask & (1 << i) && !strcmp("vol", vnames[i])) {
694 if (ioctl(afd, MIXER_READ(i), &v) == -1) {
695 warn("vol_perc: ioctl");
696 close(afd);
697 return unknown_str;
698 }
699 }
700 }
701
702 close(afd);
703
704 return bprintf("%d", v & 0xff);
705 }
706
707 static const char *
708 wifi_perc(const char *iface)
709 {
710 int i, perc;
711 char *p, *datastart;
712 char path[PATH_MAX];
713 char status[5];
714 FILE *fp;
715
716 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface, "/operstate");
717 fp = fopen(path, "r");
718 if (fp == NULL) {
719 warn("Failed to open file %s", path);
720 return unknown_str;
721 }
722 p = fgets(status, 5, fp);
723 fclose(fp);
724 if(!p || strcmp(status, "up\n") != 0) {
725 return unknown_str;
726 }
727
728 fp = fopen("/proc/net/wireless", "r");
729 if (fp == NULL) {
730 warn("Failed to open file /proc/net/wireless");
731 return unknown_str;
732 }
733
734 for (i = 0; i < 3; i++) {
735 if (!(p = fgets(buf, sizeof(buf) - 1, fp)))
736 break;
737 }
738 fclose(fp);
739 if (i < 2 || !p)
740 return unknown_str;
741
742 if ((datastart = strstr(buf, iface)) == NULL)
743 return unknown_str;
744
745 datastart = (datastart+(strlen(iface)+1));
746 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
747
748 return bprintf("%d", perc);
749 }
750
751 static const char *
752 wifi_essid(const char *iface)
753 {
754 static char id[IW_ESSID_MAX_SIZE+1];
755 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
756 struct iwreq wreq;
757
758 memset(&wreq, 0, sizeof(struct iwreq));
759 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
760 snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
761
762 if (sockfd == -1) {
763 warn("Failed to get ESSID for interface %s", iface);
764 return unknown_str;
765 }
766 wreq.u.essid.pointer = id;
767 if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
768 warn("Failed to get ESSID for interface %s", iface);
769 return unknown_str;
770 }
771
772 close(sockfd);
773
774 if (strcmp(id, "") == 0)
775 return unknown_str;
776 else
777 return id;
778 }
779
780 static void
781 terminate(const int signo)
782 {
783 done = 1;
784 }
785
786 static void
787 difftimespec(struct timespec *res, struct timespec *a, struct timespec *b)
788 {
789 res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec);
790 res->tv_nsec = a->tv_nsec - b->tv_nsec +
791 (a->tv_nsec < b->tv_nsec) * 1000000000;
792 }
793
794 static void
795 usage(void)
796 {
797 fprintf(stderr, "usage: %s [-s]\n", argv0);
798 exit(1);
799 }
800
801 int
802 main(int argc, char *argv[])
803 {
804 struct sigaction act;
805 struct timespec start, current, diff, intspec, wait;
806 size_t i, len;
807 int sflag = 0;
808 char status[MAXLEN];
809
810 ARGBEGIN {
811 case 's':
812 sflag = 1;
813 break;
814 default:
815 usage();
816 } ARGEND
817
818 if (argc) {
819 usage();
820 }
821
822 memset(&act, 0, sizeof(act));
823 act.sa_handler = terminate;
824 sigaction(SIGINT, &act, NULL);
825 sigaction(SIGTERM, &act, NULL);
826
827 if (!sflag && !(dpy = XOpenDisplay(NULL))) {
828 fprintf(stderr, "slstatus: cannot open display");
829 return 1;
830 }
831
832 while (!done) {
833 clock_gettime(CLOCK_MONOTONIC, &start);
834
835 status[0] = '\0';
836 for (i = len = 0; i < LEN(args); i++) {
837 len += snprintf(status + len, sizeof(status) - len,
838 args[i].fmt, args[i].func(args[i].args));
839
840 if (len >= sizeof(status)) {
841 status[sizeof(status) - 1] = '\0';
842 }
843 }
844
845 if (sflag) {
846 printf("%s\n", status);
847 } else {
848 XStoreName(dpy, DefaultRootWindow(dpy), status);
849 XSync(dpy, False);
850 }
851
852 if (!done) {
853 clock_gettime(CLOCK_MONOTONIC, &current);
854 difftimespec(&diff, &current, &start);
855
856 intspec.tv_sec = interval / 1000;
857 intspec.tv_nsec = (interval % 1000) * 1000000;
858 difftimespec(&wait, &intspec, &diff);
859
860 if (wait.tv_sec >= 0) {
861 nanosleep(&wait, NULL);
862 }
863 }
864 }
865
866 if (!sflag) {
867 XStoreName(dpy, DefaultRootWindow(dpy), NULL);
868 XCloseDisplay(dpy);
869 }
870
871 return 0;
872 }