wmbattery: Restore BSD support.
[dockapps.git] / wmbattery / wmbattery.c
blob8f9cbb5901369dc85c45f36abc537529c890b8f6
1 /* wmbattery - display laptop battery info, dockable in WindowMaker
2 * Copyright (C) 1998-2014 Joey Hess <joey@kitenet.net>
3 * Copyright (C) 2014 Window Maker Developers Team
4 * <wmaker-dev@lists.windowmaker.org>
6 * Portions of code derived from:
7 * wmapm - Copyright (C) 1998-1999 Chris D. Faulhaber <jedgar@fxp.org>
8 * wmmon - Copyright (C) 1998 Martijn Pieterse <pieterse@xs4all.nl>
9 * Copyright (C) 1998 Antoine Nulle <warp@xs4all.nl>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public License
13 * as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <X11/xpm.h>
28 #include <X11/extensions/shape.h>
29 #include <stdarg.h>
30 #include <signal.h>
31 #include <time.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include "wmbattery.h"
38 #ifdef HAVE_GETOPT_H
39 #include <getopt.h>
40 #endif
42 #include "mask.xbm"
43 #include "sonypi.h"
44 #include "acpi.h"
45 #ifdef HAL
46 #include "simplehal.h"
47 #endif
48 #ifdef UPOWER
49 #include "upower.h"
50 #endif
52 Pixmap images[NUM_IMAGES];
53 Window root, iconwin, win;
54 int screen;
55 XpmIcon icon;
56 Display *display;
57 GC NormalGC;
58 int pos[2] = {0, 0};
60 #ifdef HAVE__DEV_APM
61 #define APM_STATUS_FILE "/dev/apm"
62 #else
63 #define APM_STATUS_FILE "/proc/apm"
64 #endif
66 char *apm_status_file = APM_STATUS_FILE;
68 char *crit_audio_fn = NULL;
69 char *crit_audio;
70 int crit_audio_size;
71 char *crit_command = NULL;
73 int battnum = 1;
74 #ifdef HAL
75 int use_simplehal = 0;
76 #endif
77 #ifdef UPOWER
78 int use_upower = 0;
79 #endif
80 int use_sonypi = 0;
81 int use_acpi = 0;
82 int delay = 0;
83 int always_estimate_remaining = 0;
84 int granularity_estimate_remaining = 1;
85 int initial_state = WithdrawnState;
87 signed int low_pct = -1;
88 signed int critical_pct = -1;
90 void error(const char *fmt, ...)
92 va_list arglist;
94 va_start(arglist, fmt);
95 fprintf(stderr, "Error: ");
96 vfprintf(stderr, fmt, arglist);
97 fprintf(stderr, "\n");
98 va_end(arglist);
100 exit(1);
103 #if defined (HAVE_MACHINE_APM_BIOS_H) || defined (HAVE_I386_APMVAR_H) /* BSD */
104 int apm_read(apm_info *i)
106 int fd;
107 #ifdef HAVE_MACHINE_APM_BIOS_H /* FreeBSD */
108 unsigned long request = APMIO_GETINFO;
109 struct apm_info info;
110 #else /* NetBSD or OpenBSD */
111 unsigned long request= APM_IOC_GETPOWER;
112 struct apm_power_info info;
113 #endif
115 if ((fd = open(apm_status_file, O_RDONLY)) == -1) {
116 return 0;
118 if (ioctl(fd, request, &info) == -1) {
119 return 0;
121 close(fd);
123 #ifdef HAVE_MACHINE_APM_BIOS_H /* FreeBSD */
124 i->ac_line_status = info.ai_acline;
125 i->battery_status = info.ai_batt_stat;
126 i->battery_flags = (info.ai_batt_stat == 3) ? 8: 0;
127 i->battery_percentage = info.ai_batt_life;
128 i->battery_time = info.ai_batt_time;
129 i->using_minutes = 0;
130 #else /* NetBSD or OpenBSD */
131 i->ac_line_status = info.ac_state;
132 i->battery_status = info.battery_state;
133 i->battery_flags = (info.battery_state == 3) ? 8: 0;
134 i->battery_percentage = info.battery_life;
135 i->battery_time = info.minutes_left;
136 i->using_minutes = 1;
137 #endif
139 return 1;
142 int apm_exists(void)
144 apm_info i;
146 if (access(apm_status_file, R_OK))
147 return 0;
148 return apm_read(&i);
150 #endif
152 int apm_change(apm_info *cur)
154 static int ac_line_status = 0, battery_status = 0, battery_flags = 0,
155 battery_percentage = 0, battery_time = 0, using_minutes = 0;
157 int i = cur->ac_line_status == ac_line_status &&
158 cur->battery_status == battery_status &&
159 cur->battery_flags == battery_flags &&
160 cur->battery_percentage == battery_percentage &&
161 cur->battery_time == battery_time &&
162 cur->using_minutes == using_minutes;
164 ac_line_status = cur->ac_line_status;
165 battery_status = cur->battery_status;
166 battery_flags = cur->battery_flags;
167 battery_percentage = cur->battery_percentage;
168 battery_time = cur->battery_time;
169 using_minutes = cur->using_minutes;
171 return i;
174 /* Calculate battery estimate */
175 void estimate_timeleft(apm_info *cur_info)
177 /* Time of the last estimate */
178 static time_t estimate_time;
179 /* Estimated time left */
180 static time_t estimate;
181 /* Time when we last noticed a battery level change */
182 static time_t battery_change_time;
183 /* The previous estimation we had before the battery level changed */
184 static time_t prev_estimate;
185 /* Percentage at the last estimate */
186 static short percent;
187 /* Where we charging or discharging the last time we were called? */
188 static short was_charging = 1;
189 /* Have we made a guess lately? */
190 static short guessed_lately;
192 time_t t;
193 int interval;
194 short is_charging = cur_info->battery_flags & BATTERY_FLAGS_CHARGING;
196 errno = 0;
197 if (time(&t) == ((time_t)-1) && errno != 0)
198 goto estim_values;
200 if ((
201 /* AC is on and battery is not charging anymore or ... */
202 (cur_info->ac_line_status == AC_LINE_STATUS_ON) && !is_charging
203 ) ||
205 /* ... the charging state has changed */
206 is_charging ^ was_charging
207 )) {
208 /* Reset counters */
209 battery_change_time = t;
210 estimate = -1;
211 guessed_lately = 0;
212 estimate_time = t;
213 prev_estimate = 0;
214 goto estim_values;
217 /* No change: decrease estimate */
218 if ((percent - cur_info->battery_percentage)
219 / granularity_estimate_remaining == 0) {
220 estimate -= t - estimate_time;
221 estimate_time = t;
222 if (guessed_lately && estimate < 0)
223 estimate = 0;
224 goto estim_values;
227 /* The battery level changed: calculate estimate based
228 * on change speed and previous estimate */
229 guessed_lately = 1;
230 estimate_time = t;
231 interval = estimate_time - battery_change_time;
232 prev_estimate = estimate;
233 battery_change_time = estimate_time;
234 estimate = (is_charging
235 ? (cur_info->battery_percentage - 100)
236 : cur_info->battery_percentage)
237 * interval / (percent - cur_info->battery_percentage);
238 if (prev_estimate > 0)
239 estimate = (estimate * 2 + prev_estimate) / 3;
241 estim_values:
242 percent = cur_info->battery_percentage;
243 was_charging = is_charging;
244 cur_info->battery_time = estimate;
245 if (estimate < 0)
246 estimate = 0;
247 cur_info->using_minutes = 0;
250 /* Load up the images this program uses. */
251 void load_images(void)
253 int x;
254 char fn[128]; /* enough? */
256 for (x = 0; x < NUM_IMAGES; x++) {
257 sprintf(fn, "%s/%s.xpm", ICONDIR, image_info[x].filename);
258 if (XpmReadFileToPixmap(display, root, fn, &images[x], NULL, NULL)) {
259 /* Check in current direcotry for fallback. */
260 sprintf(fn, "%s.xpm", image_info[x].filename);
261 if (XpmReadFileToPixmap(display, root, fn, &images[x], NULL, NULL))
262 error("Failed to load %s\n", fn);
267 void load_audio(void)
269 int fd;
270 struct stat s;
272 crit_audio = NULL;
273 if (crit_audio_fn == NULL)
274 return;
275 fd = open(crit_audio_fn, 0);
276 if (fd == -1)
277 error("unable to open audio file");
278 if (fstat(fd, &s) == 0) {
279 crit_audio_size = s.st_size;
280 crit_audio = malloc(crit_audio_size);
281 /* XXX: make this more robust? (loop?) */
282 if (read(fd, crit_audio, crit_audio_size) != crit_audio_size) {
283 free(crit_audio);
284 crit_audio = NULL;
285 error("unable to read audio file");
288 close(fd);
291 /* string replacement function by Laird Shaw, in public domain
292 * http://creativeandcritical.net/str-replace-c */
293 char *replace_str(const char *str, const char *old, const char *new)
295 char *ret, *r;
296 const char *p, *q;
297 size_t oldlen = strlen(old);
298 size_t count, retlen, newlen = strlen(new);
300 if (oldlen != newlen) {
301 for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
302 count++;
303 /* this is undefined if p - str > PTRDIFF_MAX */
304 retlen = p - str + strlen(p) + count * (newlen - oldlen);
305 } else
306 retlen = strlen(str);
308 ret = malloc(retlen + 1);
309 if (!ret)
310 return NULL;
312 for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
313 /* this is undefined if q - p > PTRDIFF_MAX */
314 ptrdiff_t l = q - p;
315 memcpy(r, p, l);
316 r += l;
317 memcpy(r, new, newlen);
318 r += newlen;
320 strcpy(r, p);
322 return ret;
325 void cmd_crit(const char *cmd, int percentage, int time)
327 char prc_str[255] = "";
328 char min_str[255] = "";
329 char sec_str[255] = "";
330 char *tmp_a = NULL;
331 char *tmp_b = NULL;
332 char *command = NULL;
333 int ret;
335 if (!cmd)
336 return;
337 if (percentage > 100 || percentage < 0)
338 return;
339 if (time > 65535 || time < 0)
340 return;
342 sprintf(prc_str, "%i", percentage);
343 sprintf(min_str, "%i", time / 60);
344 sprintf(sec_str, "%i", time % 60);
346 tmp_a = replace_str(cmd, STR_SUB_PERCENT, prc_str);
347 if (!tmp_a)
348 return;
349 tmp_b = replace_str(tmp_a, STR_SUB_MINUTES, min_str);
350 if (!tmp_b)
351 return;
352 command = replace_str(tmp_b, STR_SUB_SECONDS, sec_str);
353 if (!command)
354 return;
356 ret = system(command);
357 if (ret == -1)
358 error("unable to run command: %s", command);
360 free(tmp_a);
361 free(tmp_b);
362 free(command);
365 /* Returns the display to run on (or NULL for default). */
366 char *parse_commandline(int argc, char *argv[])
368 int c = 0;
369 char *ret = NULL;
370 char *s;
372 while (c != -1) {
373 c = getopt(argc, argv, "hd:g:if:b:w:c:l:es:a:x:v");
374 switch (c) {
375 case 'h':
376 printf("Usage: wmbattery [options]\n");
377 printf("\t-d <display>\tselects target display\n");
378 printf("\t-h\t\tdisplay this help\n");
379 printf("\t-g +x+y\t\tposition of the window\n");
380 printf("\t-i start\n");
381 printf("\t-b num\t\tnumber of battery to display\n");
382 printf("\t-w secs\t\tseconds between updates\n");
383 printf("\t-l percent\tlow percentage\n");
384 printf("\t-c percent\tcritical percentage\n");
385 printf("\t-e\t\tuse own time estimates\n");
386 printf("\t-s granularity\tignore fluctuations less than granularity%% (implies -e)\n");
387 printf("\t-a file\t\twhen critical send file to /dev/audio\n");
388 printf("\t-x command\twhen critical execute this command\n");
389 printf("\t-v\t\tdisplay version number\n");
390 exit(0);
391 break;
392 case 'd':
393 ret = strdup(optarg);
394 break;
395 case 'g':
396 s = strtok(optarg, "+");
397 if (s) {
398 pos[0] = atoi(s);
399 s = strtok(NULL, "+");
400 if (s)
401 pos[1] = atoi(s);
402 else
403 pos[0] = 0;
405 break;
406 case 'i':
407 initial_state = IconicState;
408 break;
409 case 'b':
410 battnum = atoi(optarg);
411 break;
412 case 'w':
413 delay = atoi(optarg);
414 break;
415 case 'l':
416 low_pct = atoi(optarg);
417 break;
418 case 'c':
419 critical_pct = atoi(optarg);
420 break;
421 case 'e':
422 always_estimate_remaining = 1;
423 break;
424 case 's':
425 always_estimate_remaining = 1;
426 granularity_estimate_remaining = atoi(optarg);
427 break;
428 case 'a':
429 crit_audio_fn = strdup(optarg);
430 break;
431 case 'x':
432 crit_command = strdup(optarg);
433 break;
434 case 'v':
435 printf("wmbattery "PACKAGE_VERSION"\n");
436 exit(0);
437 break;
441 return ret;
444 /* Sets up the window and icon and all the nasty X stuff. */
445 void make_window(char *display_name, int argc, char *argv[])
447 XClassHint classhint;
448 char *wname = argv[0];
449 XTextProperty name;
450 XGCValues gcv;
451 int dummy = 0, borderwidth = 1;
452 XSizeHints sizehints;
453 XWMHints wmhints;
454 Pixel back_pix, fore_pix;
455 Pixmap pixmask;
457 display = XOpenDisplay(display_name);
458 if (!display)
459 error("can't open display %s", XDisplayName(display_name));
461 screen = DefaultScreen(display);
462 root = RootWindow(display, screen);
464 /* Create window. */
465 sizehints.flags = USSize | USPosition;
466 sizehints.x = 0;
467 sizehints.y = 0;
468 XWMGeometry(display, screen, "", NULL, borderwidth,
469 &sizehints, &sizehints.x, &sizehints.y,
470 &sizehints.width, &sizehints.height, &dummy);
472 sizehints.width = 64;
473 sizehints.height = 64;
474 sizehints.x = pos[0];
475 sizehints.y = pos[1];
476 back_pix = WhitePixel(display, screen);
477 fore_pix = BlackPixel(display, screen);
478 win = XCreateSimpleWindow(display, root, sizehints.x, sizehints.y,
479 sizehints.width, sizehints.height,
480 borderwidth, fore_pix, back_pix);
481 iconwin = XCreateSimpleWindow(display, win, sizehints.x,
482 sizehints.y, sizehints.width,
483 sizehints.height, borderwidth,
484 fore_pix, back_pix);
486 /* Activate hints */
487 XSetWMNormalHints(display, win, &sizehints);
488 classhint.res_name = wname;
489 classhint.res_class = wname;
490 XSetClassHint(display, win, &classhint);
492 if (!XStringListToTextProperty(&wname, 1, &name))
493 error("Can't allocate window name.");
495 XSetWMName(display, win, &name);
497 /* Create GC for drawing */
498 gcv.foreground = fore_pix;
499 gcv.background = back_pix;
500 gcv.graphics_exposures = 0;
501 NormalGC = XCreateGC(display, root,
502 GCForeground | GCBackground | GCGraphicsExposures,
503 &gcv);
505 pixmask = XCreateBitmapFromData(display, win, mask_bits,
506 mask_width, mask_height);
507 XShapeCombineMask(display, win, ShapeBounding, 0, 0,
508 pixmask, ShapeSet);
509 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0,
510 pixmask, ShapeSet);
512 wmhints.initial_state = initial_state;
513 wmhints.icon_window = iconwin;
514 wmhints.icon_x = sizehints.x;
515 wmhints.icon_y = sizehints.y;
516 wmhints.window_group = win;
517 wmhints.flags = StateHint | IconWindowHint |
518 IconPositionHint | WindowGroupHint;
520 XSetWMHints(display, win, &wmhints);
521 XSetCommand(display, win, argv, argc);
523 XSelectInput(display, iconwin, ExposureMask);
524 XSelectInput(display, win, ExposureMask);
526 XMapWindow(display, win);
529 void flush_expose(Window w)
531 XEvent dummy;
533 while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
537 void redraw_window(void)
539 XCopyArea(display, images[FACE], iconwin, NormalGC, 0, 0,
540 image_info[FACE].width, image_info[FACE].height, 0, 0);
541 flush_expose(iconwin);
542 XCopyArea(display, images[FACE], win, NormalGC, 0, 0,
543 image_info[FACE].width, image_info[FACE].height, 0, 0);
544 flush_expose(win);
548 * Display an image, using XCopyArea. Can display only part of an image,
549 * located anywhere.
551 void copy_image(int image, int xoffset, int yoffset,
552 int width, int height, int x, int y)
554 XCopyArea(display, images[image], images[FACE], NormalGC,
555 xoffset, yoffset, width, height, x, y);
559 * Display a letter in one of two fonts, at the specified x position.
560 * Note that 10 is passed for special characters `:' or `1' at the
561 * end of the font.
563 void draw_letter(int letter, int font, int x)
565 copy_image(font, image_info[font].charwidth * letter, 0,
566 image_info[font].charwidth, image_info[font].height,
567 x, image_info[font].y);
570 /* Display an image at its normal location. */
571 void draw_image(int image)
573 copy_image(image, 0, 0,
574 image_info[image].width, image_info[image].height,
575 image_info[image].x, image_info[image].y);
578 void recalc_window(apm_info cur_info)
580 int time_left, hour_left, min_left, digit, x;
581 static int blinked;
583 /* Display if it's plugged in. */
584 switch (cur_info.ac_line_status) {
585 case AC_LINE_STATUS_ON:
586 draw_image(PLUGGED);
587 break;
588 default:
589 draw_image(UNPLUGGED);
592 /* Display the appropriate color battery. */
593 switch (cur_info.battery_status) {
594 case BATTERY_STATUS_HIGH:
595 case BATTERY_STATUS_CHARGING:
596 draw_image(BATTERY_HIGH);
597 break;
598 case BATTERY_STATUS_LOW:
599 draw_image(BATTERY_LOW);
600 break;
601 case BATTERY_STATUS_CRITICAL: /* blinking red battery */
602 if (blinked)
603 draw_image(BATTERY_CRITICAL);
604 else
605 draw_image(BATTERY_BLINK);
606 blinked = !blinked;
607 break;
608 default:
609 draw_image(BATTERY_NONE);
612 /* Show if the battery is charging. */
613 if (cur_info.battery_flags & BATTERY_FLAGS_CHARGING)
614 draw_image(CHARGING);
615 else
616 draw_image(NOCHARGING);
619 * Display the percent left dial. This has the side effect of
620 * clearing the time left field.
622 x = DIAL_MULTIPLIER * cur_info.battery_percentage;
623 if (x >= 0) {
624 /* Start by displaying bright on the dial. */
625 copy_image(DIAL_BRIGHT, 0, 0,
626 x, image_info[DIAL_BRIGHT].height,
627 image_info[DIAL_BRIGHT].x,
628 image_info[DIAL_BRIGHT].y);
630 /* Now display dim on the remainder of the dial. */
631 copy_image(DIAL_DIM, x, 0,
632 image_info[DIAL_DIM].width - x,
633 image_info[DIAL_DIM].height,
634 image_info[DIAL_DIM].x + x,
635 image_info[DIAL_DIM].y);
637 /* Show percent remaining */
638 if (cur_info.battery_percentage >= 0) {
639 digit = cur_info.battery_percentage / 10;
640 if (digit == 10) {
641 /* 11 is the `1' for the hundreds place. */
642 draw_letter(11, SMALLFONT, HUNDREDS_OFFSET);
643 digit = 0;
645 draw_letter(digit, SMALLFONT, TENS_OFFSET);
646 digit = cur_info.battery_percentage % 10;
647 draw_letter(digit, SMALLFONT, ONES_OFFSET);
648 } else {
649 /* There is no battery, so we need to dim out the
650 * percent sign that is normally bright. */
651 draw_letter(10, SMALLFONT, PERCENT_OFFSET);
654 /* Show time left */
656 /* A negative number means that it is unknown. Dim the field. */
657 if (cur_info.battery_time < 0) {
658 draw_letter(10, BIGFONT, COLON_OFFSET);
659 redraw_window();
660 return;
663 if (cur_info.using_minutes)
664 time_left = cur_info.battery_time;
665 else
666 time_left = cur_info.battery_time / 60;
667 hour_left = time_left / 60;
668 min_left = time_left % 60;
669 digit = hour_left / 10;
670 draw_letter(digit, BIGFONT, HOURS_TENS_OFFSET);
671 digit = hour_left % 10;
672 draw_letter(digit, BIGFONT, HOURS_ONES_OFFSET);
673 digit = min_left / 10;
674 draw_letter(digit, BIGFONT, MINUTES_TENS_OFFSET);
675 digit = min_left % 10;
676 draw_letter(digit, BIGFONT, MINUTES_ONES_OFFSET);
678 redraw_window();
681 void snd_crit(void)
683 int audio, n;
685 if (crit_audio) {
686 audio = open("/dev/audio", O_WRONLY);
687 if (audio >= 0) {
688 n = write(audio, crit_audio, crit_audio_size);
689 if (n != crit_audio_size)
690 fprintf(stderr, "write failed (%d/%d bytes)\n", n, crit_audio_size);
691 close(audio);
696 void alarmhandler(int sig)
698 apm_info cur_info;
699 int old_status;
701 #ifdef UPOWER
702 if (use_upower) {
703 if (upower_read(1, &cur_info) != 0)
704 error("Cannot read upower information.");
705 } else if (use_acpi) {
706 #else
707 if (use_acpi) {
708 #endif
709 if (acpi_read(battnum, &cur_info) != 0)
710 error("Cannot read ACPI information.");
712 #ifdef HAL
713 else if (use_simplehal) {
714 if (simplehal_read(battnum, &cur_info) != 0)
715 error("Cannot read HAL information.");
717 #endif
718 else if (!use_sonypi) {
719 if (apm_read(&cur_info) != 0)
720 error("Cannot read APM information.");
721 } else {
722 if (sonypi_read(&cur_info) != 0)
723 error("Cannot read sonypi information.");
726 old_status = cur_info.battery_status;
728 /* Always calculate remaining lifetime? apm and acpi both use a
729 * negative number here to indicate error, missing battery, or
730 * cannot determine time. */
731 if (always_estimate_remaining || cur_info.battery_time < 0)
732 estimate_timeleft(&cur_info);
734 /* Override the battery status? */
735 if ((low_pct > -1 || critical_pct > -1) &&
736 cur_info.ac_line_status != AC_LINE_STATUS_ON) {
737 if (cur_info.battery_percentage <= critical_pct)
738 cur_info.battery_status = BATTERY_STATUS_CRITICAL;
739 else if (cur_info.battery_percentage <= low_pct)
740 cur_info.battery_status = BATTERY_STATUS_LOW;
741 else
742 cur_info.battery_status = BATTERY_STATUS_HIGH;
745 /* If APM data changes redraw and wait for next update */
746 /* Always redraw if the status is critical, to make it blink. */
747 if (!apm_change(&cur_info) || cur_info.battery_status == BATTERY_STATUS_CRITICAL)
748 recalc_window(cur_info);
750 if ((old_status == BATTERY_STATUS_HIGH) &&
751 (cur_info.battery_status == BATTERY_STATUS_LOW)) {
752 snd_crit();
753 } else if (cur_info.battery_status == BATTERY_STATUS_CRITICAL) {
754 snd_crit();
755 cmd_crit(crit_command, cur_info.battery_percentage,
756 cur_info.battery_time);
759 alarm(delay);
762 void check_battery_num(int real, int requested)
764 if (requested > real || requested < 1) {
765 error("There %s only %i batter%s, and you asked for number %i.",
766 real == 1 ? "is" : "are",
767 real,
768 real == 1 ? "y" : "ies",
769 requested);
773 int main(int argc, char *argv[])
775 make_window(parse_commandline(argc, argv), argc, argv);
777 /* Check for APM support (returns 0 on success). */
778 if (apm_exists() == 0) {
779 if (!delay)
780 delay = 1;
782 #ifdef HAL
783 /* Check for hal support. */
784 else if (simplehal_supported()) {
785 use_simplehal = 1;
786 if (!delay)
787 delay = 2;
789 #endif
790 #ifdef UPOWER
791 else if (upower_supported())
792 use_upower = 1;
793 #endif
794 /* Check for ACPI support. */
795 else if (acpi_supported() && acpi_batt_count > 0) {
796 check_battery_num(acpi_batt_count, battnum);
797 use_acpi = 1;
798 if (!delay)
799 delay = 3; /* slow interface! */
800 } else if (sonypi_supported()) {
801 use_sonypi = 1;
802 low_pct = 10;
803 critical_pct = 5;
804 if (!delay)
805 delay = 1;
806 } else {
807 error("No APM, ACPI, UPOWER, HAL or SPIC support detected.");
810 load_images();
811 load_audio();
813 signal(SIGALRM, alarmhandler);
814 alarmhandler(SIGALRM);
816 while (1) {
817 XEvent ev;
818 XNextEvent(display, &ev);
819 if (ev.type == Expose)
820 redraw_window();