12 static int total_discharge, total_charge, total_full, total_capa;
14 #define CHECK_PERIOD 60
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 - remains)*3600 / rate;
79 if (ch > total_charge)
85 total_discharge += 1000000;
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, "??%%");
103 if (total_discharge && total_discharge < 1000000)
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);
107 xosd_display(osd, 0, XOSD_string, status);
110 static void my_sleep(int sec)
112 struct timespec ts = { .tv_sec = sec };
113 nanosleep(&ts, NULL);
116 static void sig_show(int sig)
121 my_sleep(SHOW_DURATION);
126 static void sig_time(int sig)
129 time_t now = time(NULL);
130 struct tm *tm = localtime(&now);
132 strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", tm);
134 strcpy(buf, "??:??:??");
135 xosd_display(osd, 0, XOSD_string, buf);
136 my_sleep(SHOW_DURATION);
140 static void sig_check(int sig)
143 if (total_discharge && total_discharge < WARN_THRESHOLD)
146 my_sleep(SHOW_DURATION);
152 int main(int argc, char **argv)
154 // If daemon mode is requested, fork first.
155 int daemon = (argc > 1 && !strcmp(argv[1], "--daemon"));
156 int watcher = daemon || (argc > 1 && !strcmp(argv[1], "--watch"));
162 fprintf(stderr, "batt: Cannot fork: %m\n");
170 // Block SIGALRM and SIGUSR1, because libxosd will start its own thread
171 // and we don't want it to accept these signals later;
172 sigset_t our_signals;
173 sigemptyset(&our_signals);
174 sigaddset(&our_signals, SIGALRM);
175 sigaddset(&our_signals, SIGUSR1);
176 sigaddset(&our_signals, SIGUSR2);
177 sigprocmask(SIG_BLOCK, &our_signals, NULL);
179 osd = xosd_create(1);
182 fprintf(stderr, "batt: Cannot create on-screen display\n");
185 xosd_set_font(osd, "-bitstream-bitstream vera sans-bold-r-normal-*-*-320-*-*-p-*-*");
186 xosd_set_outline_offset(osd, 2);
187 xosd_set_outline_colour(osd, "black");
188 xosd_set_pos(osd, XOSD_middle);
189 xosd_set_align(osd, XOSD_center);
195 my_sleep(SHOW_DURATION);
200 // Set up signal handlers from which we do everything asynchronously.
201 struct sigaction sa = {
202 .sa_handler = sig_show,
203 .sa_mask = our_signals,
205 sigaction(SIGUSR1, &sa, NULL);
206 sa.sa_handler = sig_time;
207 sigaction(SIGUSR2, &sa, NULL);
208 sa.sa_handler = sig_check;
209 sigaction(SIGALRM, &sa, NULL);
210 sigprocmask(SIG_UNBLOCK, &our_signals, NULL);
213 // We use this connection only for detecting that the session has ended.
214 // In such cases, we are terminated automatically by XLib.
215 Display *dpy = XOpenDisplay(NULL);
218 fprintf(stderr, "batt: Cannot open display\n");
224 XNextEvent(dpy, &ev);