12 static int total_discharge, total_charge, total_full, total_capa;
14 #define CHECK_PERIOD 10
15 #define SHOW_DURATION 2
16 #define WARN_THRESHOLD 600
18 static void scan_batt(void)
20 total_discharge = total_charge = 0;
21 total_full = total_capa = 0;
23 const char dir[] = "/proc/acpi/battery";
24 DIR *d = opendir(dir);
29 while (e = readdir(d))
31 if (e->d_name[0] == '.')
33 char n[sizeof(dir) + 1 + strlen(e->d_name) + 6];
34 const char * const names[] = { "state", "info" };
40 for (int i=0; i<2; i++)
42 sprintf(n, "%s/%s/%s", dir, e->d_name, names[i]);
43 FILE *f = fopen(n, "r");
47 while (fgets(line, sizeof(line)-1, f))
49 char *t = strchr(line, '\n');
52 char *val = strchr(line, ':');
56 while (*val == ' ' || *val == '\t')
58 // printf("<%s> <%s>\n", line, val);
59 if (!strcmp(line, "present"))
60 present = !strcmp(val, "yes");
61 else if (!strcmp(line, "charging state"))
62 charging = !strcmp(val, "charging");
63 else if (!strcmp(line, "present rate"))
65 else if (!strcmp(line, "remaining capacity"))
67 else if (!strcmp(line, "last full capacity"))
68 last_full = atol(val);
74 total_full += remains;
75 total_capa += last_full;
78 int ch = last_full*3600 / rate;
79 if (ch > total_charge)
85 total_discharge += 359999;
87 total_discharge += remains*3600 / rate;
95 static void show(void)
100 p += sprintf(p, "%d%%", 100*total_full/total_capa);
102 p += sprintf(p, "??%%");
104 p += sprintf(p, " %d:%02d remains", total_discharge/3600, (total_discharge/60)%60);
105 else if (total_charge)
106 p += sprintf(p, " %d:%02d charging", total_charge/3600, (total_charge/60)%60);
108 p += sprintf(p, " ????");
109 xosd_display(osd, 0, XOSD_string, status);
112 static void my_sleep(int sec)
114 struct timespec ts = { .tv_sec = sec };
115 nanosleep(&ts, NULL);
118 static void sig_show(int sig)
123 my_sleep(SHOW_DURATION);
128 static void sig_time(int sig)
131 time_t now = time(NULL);
132 struct tm *tm = localtime(&now);
134 strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", tm);
136 strcpy(buf, "??:??:??");
137 xosd_display(osd, 0, XOSD_string, buf);
138 my_sleep(SHOW_DURATION);
142 static void sig_check(int sig)
145 if (total_discharge && total_discharge < WARN_THRESHOLD)
148 my_sleep(SHOW_DURATION);
154 int main(int argc, char **argv)
156 // If daemon mode is requested, fork first.
157 int daemon = (argc > 1 && !strcmp(argv[1], "--daemon"));
158 int watcher = daemon || (argc > 1 && !strcmp(argv[1], "--watch"));
164 fprintf(stderr, "batt: Cannot fork: %m\n");
172 // Block SIGALRM and SIGUSR1, because libxosd will start its own thread
173 // and we don't want it to accept these signals later;
174 sigset_t our_signals;
175 sigemptyset(&our_signals);
176 sigaddset(&our_signals, SIGALRM);
177 sigaddset(&our_signals, SIGUSR1);
178 sigaddset(&our_signals, SIGUSR2);
179 sigprocmask(SIG_BLOCK, &our_signals, NULL);
181 osd = xosd_create(1);
184 fprintf(stderr, "batt: Cannot create on-screen display\n");
187 xosd_set_font(osd, "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*");
188 xosd_set_outline_offset(osd, 2);
189 xosd_set_outline_colour(osd, "black");
190 xosd_set_pos(osd, XOSD_middle);
191 xosd_set_align(osd, XOSD_center);
197 my_sleep(SHOW_DURATION);
202 // Set up signal handlers from which we do everything asynchronously.
203 struct sigaction sa = {
204 .sa_handler = sig_show,
205 .sa_mask = our_signals,
207 sigaction(SIGUSR1, &sa, NULL);
208 sa.sa_handler = sig_time;
209 sigaction(SIGUSR2, &sa, NULL);
210 sa.sa_handler = sig_check;
211 sigaction(SIGALRM, &sa, NULL);
212 sigprocmask(SIG_UNBLOCK, &our_signals, NULL);
215 // We use this connection only for detecting that the session has ended.
216 // In such cases, we are terminated automatically by XLib.
217 Display *dpy = XOpenDisplay(NULL);
220 fprintf(stderr, "batt: Cannot open display\n");
226 XNextEvent(dpy, &ev);