wmacpi: Bump to version 1.99r7.
[dockapps.git] / wmacpi / wmacpi.c
blob3473541cb5e343400344a84598c500b38b9969c2
1 /* apm/acpi dockapp - phear it 1.34
2 * Copyright (C) 2000, 2001, 2002 timecop@japan.co.jp
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #define _GNU_SOURCE
21 #include <dockapp.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <getopt.h>
28 #include <unistd.h>
29 #include <time.h>
31 #include <X11/X.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/shape.h>
35 #include <X11/xpm.h>
37 #include "libacpi.h"
38 #include "wmacpi.h"
40 #define WMACPI_VER "1.99r7"
42 /* main pixmap */
43 #ifdef LOW_COLOR
44 #include "master_low.xpm"
45 static char **master_xpm = master_low_xpm;
46 #else
47 #include "master.xpm"
48 #endif
50 struct dockapp {
51 Display *display; /* display */
52 Window win; /* main window */
53 Pixmap pixmap; /* main pixmap */
54 Pixmap mask; /* mask pixmap */
55 Pixmap text; /* pixmap for text scroller */
56 unsigned width; /* width of pixmap */
57 unsigned height; /* height of pixmap */
58 int screen; /* current screen */
59 int tw; /* text width inside text pixmap */
60 int update; /* need to redraw? */
61 int blink; /* should we blink the LED? (critical battery) */
62 int bell; /* bell on critical low, or not? */
63 int scroll; /* scroll message text? */
64 int scroll_reset; /* reset the scrolling text */
67 /* globals */
68 struct dockapp *dockapp;
69 /* global_t *globals; */
71 /* this gives us a variable scroll rate, depending on the importance of the
72 * message . . . */
73 #define DEFAULT_SCROLL_RESET 150;
74 int scroll_reset = DEFAULT_SCROLL_RESET;
76 /* copy a chunk of pixmap around the app */
77 static void copy_xpm_area(int x, int y, int w, int h, int dx, int dy)
79 XCopyArea(DADisplay, dockapp->pixmap, dockapp->pixmap,
80 DAGC, x, y, w, h, dx, dy);
81 dockapp->update = 1;
84 /* display AC power symbol */
85 static void display_power_glyph(void)
87 copy_xpm_area(67, 38, 12, 7, 6, 17);
90 /* get rid of AC power symbol */
91 static void kill_power_glyph(void)
93 copy_xpm_area(67, 48, 12, 7, 6, 17);
96 /* display battery symbol */
97 static void display_battery_glyph(void)
99 copy_xpm_area(82, 38, 12, 7, 20, 17);
102 /* get rid of battery symbol */
103 static void kill_battery_glyph(void)
105 copy_xpm_area(82, 48, 12, 7, 20, 17);
108 /* clear the time display */
109 static void clear_time_display(void)
111 copy_xpm_area(114, 76, 31, 11, 7, 32);
114 /* set time display to -- -- */
115 static void invalid_time_display(void)
117 copy_xpm_area(122, 13, 31, 11, 7, 32);
120 static void reset_scroll(void) {
121 dockapp->scroll_reset = 1;
124 static void clear_text_area(void) {
125 copy_xpm_area(66, 9, 52, 7, 6, 50);
128 static void redraw_window(void)
130 if (dockapp->update) {
131 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->win,
132 DAGC, 0, 0, 64, 64, 0, 0);
133 dockapp->update = 0;
137 static void new_window(char *display, char *name, int argc, char **argv)
139 /* Initialise the dockapp window and appicon */
140 DAInitialize(display, name, 64, 64, argc, argv);
141 dockapp->display = DADisplay;
142 dockapp->win = DAWindow;
144 XSelectInput(dockapp->display, dockapp->win,
145 ExposureMask | ButtonPressMask | ButtonReleaseMask |
146 StructureNotifyMask);
148 /* create the main pixmap . . . */
149 DAMakePixmapFromData(master_xpm, &dockapp->pixmap, &dockapp->mask,
150 &dockapp->width, &dockapp->height);
151 DASetPixmap(dockapp->pixmap);
152 DASetShape(dockapp->mask);
154 /* text area is 318x7, or 53 characters long */
155 dockapp->text = XCreatePixmap(dockapp->display, dockapp->win, 318, 7,
156 DefaultDepth(dockapp->display,
157 dockapp->screen));
158 if (!dockapp->text) {
159 pfatal("FATAL: Cannot create text scroll pixmap!\n");
160 exit(1);
162 DAShow();
165 static void copy_to_text_buffer(int sx, int sy, int w, int h, int dx, int dy)
167 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
168 DAGC, sx, sy, w, h, dx, dy);
171 static void copy_to_text_area(int sx, int sy, int w, int h, int dx, int dy)
173 XCopyArea(dockapp->display, dockapp->text, dockapp->pixmap,
174 DAGC, sx, sy, w, h, dx, dy);
177 static void scroll_text(void)
179 static int start, end, stop;
180 int x = 6; /* x coord of the start of the text area */
181 int y = 50; /* y coord */
182 int width = 52; /* width of the text area */
183 int height = 7; /* height of the text area */
184 int tw = dockapp->tw; /* width of the rendered text */
185 int sx, dx, w;
187 if (!dockapp->scroll)
188 return;
191 * Conceptually this is viewing the text through a scrolling
192 * window - the window starts out with the end immediately before
193 * the text, and stops when the start of the window is immediately
194 * after the end of the text.
196 * We begin with the start of the window at pixel (0 - width) and
197 * as we scroll we render only the portion of the window above
198 * pixel 0. The destination of the copy during this period starts
199 * out at the end of the text area and works left as more of the
200 * text is being copied, until a full window is being copied.
202 * As the end of the window moves out past the end of the text, we
203 * want to keep the destination at the beginning of the text area,
204 * but copy a smaller and smaller chunk of the text. Eventually the
205 * start of the window will scroll past the end of the text, at
206 * which point we stop doing any work and wait to be reset.
209 if (dockapp->scroll_reset) {
210 start = 0 - width;
211 end = 0;
212 stop = 0;
213 clear_text_area();
214 dockapp->scroll_reset = 0;
217 if (stop)
218 return;
220 w = 52;
221 if (end < 52)
222 w = end;
223 else if (end > tw)
224 w = 52 - (end - tw);
226 dx = x + 52 - w;
227 if (end > tw)
228 dx = x;
230 sx = start;
231 if (start < 0)
232 sx = 0;
234 if (start > tw)
235 stop = 1;
237 clear_text_area();
238 copy_to_text_area(sx, 0, w, height, dx, y);
239 start += 2;
240 end += 2;
242 dockapp->update = 1;
245 static void render_text(char *string)
247 int i, c, k;
249 /* drop out immediately if scrolling is disabled - we don't render
250 * any text at all, since there's not much else we could do
251 * sensibly without scrolling. */
252 if (!dockapp->scroll)
253 return;
255 if (strlen(string) > 53)
256 return;
258 /* prepare the text area by clearing it */
259 for (i = 0; i < 54; i++) {
260 copy_to_text_buffer(133, 57, 6, 8, i * 6, 0);
262 k = 0;
264 for (i = 0; string[i]; i++) {
265 c = toupper(string[i]);
266 if (c >= 'A' && c <= 'Z') { /* letter */
267 c = c - 'A';
268 copy_to_text_buffer(c * 6, 67, 6, 7, k, 0);
269 } else if (c >= '0' && c <= '9') { /* number */
270 c = c - '0';
271 copy_to_text_buffer(c * 6 + 66, 58, 6, 7, k, 0);
272 } else if (c == '.') {
273 copy_to_text_buffer(140, 58, 6, 7, k, 0);
274 } else if (c == '-') {
275 copy_to_text_buffer(126, 58, 6, 7, k, 0);
277 k += 6;
279 dockapp->tw = k; /* length of text segment */
280 /* re-scroll the message */
281 reset_scroll();
282 scroll_text();
285 static void display_percentage(int percent)
287 static int op = -1;
288 static unsigned int obar;
289 unsigned int bar;
290 int width = 54; /* width of the bar */
291 float ratio = 100.0/width; /* ratio between the current percentage
292 * and the number of pixels in the bar */
294 if (percent == -1)
295 percent = 0;
297 if (op == percent)
298 return;
300 if (percent < 0)
301 percent = 0;
302 if (percent > 100)
303 percent = 100;
305 if (percent < 100) { /* 0 - 99 */
306 copy_xpm_area(95, 48, 8, 7, 37, 17);
307 if (percent >= 10)
308 copy_xpm_area((percent / 10) * 6 + 67, 28, 5, 7, 40, 17);
309 copy_xpm_area((percent % 10) * 6 + 67, 28, 5, 7, 46, 17);
310 } else
311 copy_xpm_area(95, 37, 21, 9, 37, 16); /* 100% */
312 op = percent;
314 bar = (int)((float)percent / ratio);
316 if (bar == obar)
317 return;
319 copy_xpm_area(66, 0, bar, 8, 5, 5);
320 if (bar < 54)
321 copy_xpm_area(66 + bar, 18, 54 - bar, 8, bar + 5, 5);
322 obar = bar;
325 static void display_time(int minutes)
327 static int ohour = -1, omin = -1;
328 int hour, min, tmp;
330 if (minutes <= 0) { /* error - clear the display */
331 invalid_time_display();
332 ohour = omin = -1;
333 return;
336 /* render time on the display */
337 hour = minutes / 60;
338 /* our display area only fits %2d:%2d, so we need to make sure
339 * what we're displaying will fit in those constraints. I don't
340 * think we're likely to see any batteries that do more than
341 * 100 hours any time soon, so it's fairly safe. */
342 if (hour >= 100) {
343 hour = 99;
344 min = 59;
345 } else
346 min = minutes % 60;
348 if (hour == ohour && min == omin)
349 return;
351 tmp = hour / 10;
352 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 7, 32);
353 tmp = hour % 10;
354 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 14, 32);
355 tmp = min / 10;
356 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 25, 32);
357 tmp = min % 10;
358 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 32, 32);
359 copy_xpm_area(71, 76, 3, 11, 21, 32);
360 ohour = hour;
361 omin = min;
365 * The reworked state handling stuff.
368 /* set the current state of the power panel */
369 enum panel_states {
370 PS_AC,
371 PS_BATT,
372 PS_NULL,
375 static void really_blink_power_glyph(void)
377 static int counter = 0;
379 if (counter == 10)
380 display_power_glyph();
381 else if (counter == 20)
382 kill_power_glyph();
383 else if (counter > 30)
384 counter = 0;
385 counter++;
388 static void blink_power_glyph(void)
390 if (dockapp->blink)
391 really_blink_power_glyph();
394 static void really_blink_battery_glyph(void)
396 static int counter = 0;
398 if (counter == 10)
399 display_battery_glyph();
400 else if (counter == 20)
401 kill_battery_glyph();
402 else if (counter > 30)
403 counter = 0;
404 counter++;
407 static void blink_battery_glyph(void)
409 if (dockapp->blink)
410 really_blink_battery_glyph();
413 static void set_power_panel(global_t *globals)
415 enum panel_states power = PS_NULL;
416 battery_t *binfo = globals->binfo;
417 adapter_t *ap = &globals->adapter;
419 if (ap->power == AC) {
420 if (power != PS_AC) {
421 power = PS_AC;
422 kill_battery_glyph();
423 display_power_glyph();
425 } else if (ap->power == BATT) {
426 if (power != PS_BATT) {
427 power = PS_BATT;
428 kill_power_glyph();
429 display_battery_glyph();
433 if (binfo->charge_state == CHARGE)
434 blink_power_glyph();
436 if ((binfo->state == CRIT) && (ap->power == BATT))
437 blink_battery_glyph();
439 if (binfo->state == HARD_CRIT) {
440 really_blink_battery_glyph();
441 /* we only do this here because it'd be obnoxious to
442 * do it anywhere else. */
443 if (dockapp->bell) {
444 XBell(dockapp->display, 100);
449 void scroll_faster(double factor) {
450 scroll_reset = scroll_reset * factor;
453 void scroll_slower(double factor) {
454 scroll_reset = scroll_reset * factor;
457 void reset_scroll_speed(void) {
458 scroll_reset = DEFAULT_SCROLL_RESET;
462 * The message that needs to be displayed needs to be decided
463 * according to a heirarchy: a message like not present needs to take
464 * precedence over a global thing like the current power status, and
465 * something like a low battery warning should take precedence over
466 * the "on battery" message. Likewise, a battery charging message
467 * needs to take precedence over the on ac power message. The other
468 * question is how much of a precedence local messages should take
469 * over global ones . . .
471 * So, there are three possible sets of messages: not present, on-line
472 * and off-line messages. We need to decide which of those sets is
473 * appropriate right now, and then decide within them.
475 enum messages {
476 M_NP, /* not present */
477 M_AC, /* on ac power */
478 M_CH, /* battery charging */
479 M_BATT, /* on battery */
480 M_LB, /* low battery */
481 M_CB, /* critical low battery */
482 M_HCB, /* battery reported critical capacity state */
483 M_NULL, /* empty starting state */
486 static void set_message(global_t *globals)
488 static enum messages state = M_NULL;
489 battery_t *binfo = globals->binfo;
490 adapter_t *ap = &globals->adapter;
492 /* battery not present case */
493 if (!binfo->present) {
494 if (state != M_NP) {
495 state = M_NP;
496 reset_scroll_speed();
497 render_text("not present");
499 } else if (ap->power == AC) {
500 if (binfo->charge_state == CHARGE) {
501 if (state != M_CH) {
502 state = M_CH;
503 reset_scroll_speed();
504 render_text("battery charging");
506 } else {
507 if (state != M_AC) {
508 state = M_AC;
509 reset_scroll_speed();
510 render_text("on ac power");
513 } else {
514 if (binfo->state == CRIT) {
515 if (state != M_CB) {
516 state = M_CB;
517 scroll_faster(0.75);
518 render_text("critical low battery");
520 } else if (binfo->state == HARD_CRIT) {
521 if (state != M_HCB) {
522 state = M_HCB;
523 scroll_faster(0.5);
524 render_text("hard critical low battery");
526 } else if (binfo->state == LOW) {
527 if (state != M_LB) {
528 state = M_LB;
529 scroll_faster(0.85);
530 render_text("low battery");
532 } else {
533 if (state != M_BATT) {
534 state = M_BATT;
535 reset_scroll_speed();
536 render_text("on battery");
542 void set_time_display(global_t *globals)
544 battery_t *binfo = &batteries[battery_no];
546 if (binfo->charge_state == CHARGE)
547 display_time(binfo->charge_time);
548 else if (binfo->charge_state == DISCHARGE)
549 display_time(globals->rtime);
550 else
551 invalid_time_display();
554 void set_batt_id_area(int bno)
556 int w = 7; /* Width of the number */
557 int h = 11; /* Height of the number */
558 int dx = 50; /* x coord of the target area */
559 int dy = 31; /* y coord of the target area */
560 int sx = (bno + 1) * 7; /* source x coord */
561 int sy = 76; /* source y coord */
563 copy_xpm_area(sx, sy, w, h, dx, dy);
566 void usage(char *name)
568 printf("%s - help\t\t[simon@dreamcraft.com.au]\n\n"
569 "-d display\t\tdisplay on remote display <display>\n"
570 "-b\t\t\tenable blinking of various UI elements\n"
571 "-r\t\t\tdisable scrolling message\n"
572 "-c value\t\tset critical low alarm at <value> percent\n"
573 "\t\t\t(default: 10 percent)\n"
574 "-m <battery number>\tbattery number to monitor\n"
575 "-s <sample rate>\tnumber of times per minute to sample battery information\n"
576 "\t\t\tdefault 20 (once every three seconds)\n"
577 "-f\t\t\tforce the use of capacity mode for calculating time remaining\n"
578 "-n\t\t\tdo not blink\n"
579 "-w\t\t\trun in command line mode\n"
580 "-a <samples>\t\tsamples to average over (cli mode only)\n"
581 "-v\t\t\tincrease verbosity\n"
582 "\t\t\tcan be used multiple times to increase verbosity further\n"
583 "-h\t\t\tdisplay this help\n",
584 name);
587 void print_version(void)
589 printf("wmacpi version %s\n", WMACPI_VER);
590 printf(" Using libacpi version %s\n", LIBACPI_VER);
593 void cli_wmacpi(global_t *globals, int samples)
595 int i, j, sleep_time = 0;
596 battery_t *binfo;
597 adapter_t *ap;
599 printf("%d\n", samples);
600 if(samples > 1)
601 sleep_time = 1000000/samples;
603 /* we want to acquire samples over some period of time, so . . . */
604 for(i = 0; i < samples + 2; i++) {
605 for(j = 0; j < globals->battery_count; j++)
606 acquire_batt_info(globals, j);
607 acquire_global_info(globals);
608 usleep(sleep_time);
611 ap = &globals->adapter;
612 if(ap->power == AC) {
613 printf("On AC Power");
614 for(i = 0; i < globals->battery_count; i++) {
615 binfo = &batteries[i];
616 if(binfo->present && (binfo->charge_state == CHARGE)) {
617 printf("; Battery %s charging", binfo->name);
618 printf(", currently at %2d%%", binfo->percentage);
619 if(binfo->charge_time >= 0)
620 printf(", %2d:%02d remaining",
621 binfo->charge_time/60,
622 binfo->charge_time%60);
625 printf("\n");
626 } else if(ap->power == BATT) {
627 printf("On Battery");
628 for(i = 0; i < globals->battery_count; i++) {
629 binfo = &batteries[i];
630 if(binfo->present && (binfo->percentage >= 0))
631 printf(", Battery %s at %d%%", binfo->name,
632 binfo->percentage);
634 if(globals->rtime >= 0)
635 printf("; %d:%02d remaining", globals->rtime/60,
636 globals->rtime%60);
637 printf("\n");
639 return;
642 int main(int argc, char **argv)
644 char *display = NULL;
645 int ch;
646 int sample_count = 0;
647 int batt_reinit, ac_reinit;
648 int batt_count = 0;
649 int ac_count = 0;
650 int cli = 0, samples = 1;
651 int samplerate = 20;
652 int sleep_rate = 10;
653 int sleep_time = 1000000/sleep_rate;
654 int scroll_count = 0;
655 enum rtime_mode rt_mode = RT_RATE;
656 battery_t *binfo;
657 global_t *globals;
659 dockapp = calloc(1, sizeof(struct dockapp));
660 globals = calloc(1, sizeof(global_t));
662 dockapp->blink = 1;
663 dockapp->bell = 0;
664 dockapp->scroll = 1;
665 dockapp->scroll_reset = 0;
666 globals->crit_level = 10;
667 battery_no = 1;
669 /* after this many samples, we reinit the battery and AC adapter
670 * information.
671 * XXX: make these configurable . . . */
672 batt_reinit = 100;
673 ac_reinit = 1000;
675 /* this needs to be up here because we need to know what batteries
676 * are available /before/ we can decide if the battery we want to
677 * monitor is available. */
678 /* parse command-line options */
679 while ((ch = getopt(argc, argv, "d:c:m:s:a:fhnwbrvV")) != EOF) {
680 switch (ch) {
681 case 'c':
682 if (optarg) {
683 globals->crit_level = atoi(optarg);
684 if ((globals->crit_level < 0) || (globals->crit_level > 100)) {
685 fprintf(stderr, "Please use values between 0 and 100%%\n");
686 globals->crit_level = 10;
687 fprintf(stderr, "Using default value of 10%%\n");
690 break;
691 case 'd':
692 if (optarg)
693 display = strdup(optarg);
694 break;
695 case 'm':
696 if (optarg) {
697 battery_no = atoi(optarg);
698 if (battery_no >= MAXBATT) {
699 fprintf(stderr, "Please specify a battery number below %d\n",
700 MAXBATT);
701 return 1;
703 pinfo("Monitoring battery %d\n", battery_no);
705 break;
706 case 's':
707 if (optarg) {
708 samplerate = atoi(optarg);
709 if (samplerate == 0) samplerate = 1;
710 if (samplerate > 600) samplerate = 600;
711 } else {
712 usage(argv[0]);
713 exit(1);
715 break;
716 case 'f':
717 rt_mode = RT_CAP;
718 break;
719 case 'h':
720 usage(argv[0]);
721 return 0;
722 case 'v':
723 verbosity++;
724 break;
725 case 'V':
726 print_version();
727 return 0;
728 case 'n':
729 dockapp->blink = 0;
730 break;
731 case 'w':
732 cli = 1;
733 break;
734 case 'a':
735 if(optarg != NULL) {
736 samples = atoi(optarg);
737 if(samples > 1000 || samples <= 0) {
738 fprintf(stderr, "Please specify a reasonable number of samples\n");
739 exit(1);
742 break;
743 case 'b':
744 dockapp->blink = 1;
745 break;
746 case 'r':
747 dockapp->scroll = 0;
748 break;
749 default:
750 usage(argv[0]);
751 return 1;
756 if (power_init(globals))
757 /* power_init functions handle printing error messages */
758 exit(1);
760 globals->rt_mode = rt_mode;
762 if (battery_no > globals->battery_count) {
763 pfatal("Battery %d not available for monitoring.\n", battery_no);
764 exit(1);
767 /* check for cli mode */
768 if (cli) {
769 cli_wmacpi(globals, samples);
770 exit(0);
773 battery_no--;
775 /* make new dockapp window */
776 /* Don't even /think/ of asking me why, but if I set the window name to
777 * "acpi", the app refuses to dock properly - it's just plain /weird/.
778 * So, wmacpi it is . . . */
779 new_window(display, "wmacpi", argc, argv);
781 /* get initial statistics */
782 acquire_all_info(globals);
783 binfo = &batteries[battery_no];
784 globals->binfo = binfo;
785 pinfo("monitoring battery %s\n", binfo->name);
786 clear_time_display();
787 set_power_panel(globals);
788 set_message(globals);
789 set_batt_id_area(battery_no);
791 /* main loop */
792 while (1) {
793 XEvent event;
794 while (XPending(dockapp->display)) {
795 XNextEvent(dockapp->display, &event);
796 switch (event.type) {
797 case Expose:
798 /* update */
799 dockapp->update = 1;
800 while (XCheckTypedEvent(dockapp->display, Expose, &event));
801 redraw_window();
802 break;
803 case DestroyNotify:
804 XCloseDisplay(dockapp->display);
805 exit(0);
806 break;
807 case ButtonPress:
808 break;
809 case ButtonRelease:
810 /* cycle through the known batteries. */
811 battery_no++;
812 battery_no = battery_no % globals->battery_count;
813 globals->binfo = &batteries[battery_no];
814 binfo = globals->binfo;
815 pinfo("changing to monitor battery %d\n", battery_no + 1);
816 set_batt_id_area(battery_no);
817 dockapp->update = 1;
818 break;
822 /* XXX: some laptops have problems with sampling the battery
823 * regularly - apparently, the BIOS disables interrupts while
824 * reading from the battery, which is generally on a slow bus
825 * and is a slow device, so you get significant periods without
826 * interrupts. This causes interactivity to suffer . . .
828 * My proposed workaround is to allow the user to set the sample
829 * rate - it defaults to ten, but can be set lower (or higher).
831 * The only problem with this is that we need to sample less
832 * frequently, while still allowing the app to update normally.
833 * That means calling redraw_window() and all the set_*() functions
834 * normally, but only calling acquire_all_info() every so often.
835 * As it stands, we only call acquire_all_info() once every three
836 * seconds (once every thirty updates) . . . I'm not entirely sure
837 * /how/ this could cause interactivity problems, but hey . . .
839 * So, given the base rate of once every three seconds, we want to
840 * change this test to . . . */
841 /* Okay, this needs /fixing/ - it's ridiculous. We should be giving
842 * the user the option of saying how many times per minute the
843 * battery should be sampled, defaulting to 20 times.
845 * We sleep for one tenth of a second at a time, so 60 seconds
846 * translates to 600 sleeps. So, we change the default sample
847 * rate to 20, and the calculation below becomes . . .*/
848 if (sample_count++ == ((sleep_rate*60)/samplerate)) {
849 acquire_all_info(globals);
851 /* we need to be able to reinitialise batteries and adapters, because
852 * they change - you can hotplug batteries on most laptops these days
853 * and who knows what kind of shit will be happening soon . . . */
854 if (batt_count++ >= batt_reinit) {
855 if(reinit_batteries(globals))
856 pfatal("Oh my god, the batteries are gone!\n");
857 batt_count = 0;
860 if (ac_count++ >= ac_reinit) {
861 if(reinit_ac_adapters(globals))
862 pfatal("What happened to our AC adapters?!?\n");
863 ac_count = 0;
865 sample_count = 0;
868 if (scroll_count++ >= scroll_reset) {
869 reset_scroll();
870 scroll_count = 0;
873 /* The old code had some kind of weird crap with timers and the like.
874 * As far as I can tell, it's meaningless - the time we want to display
875 * is the time calculated from the remaining capacity, as per the
876 * ACPI spec. The only thing I'd change is the handling of a charging
877 * state: my best guess, based on the behaviour I'm seeing with my
878 * Lifebook, is that the present rate value when charging is the rate
879 * at which the batteries are being charged, which would mean I'd just
880 * need to reverse the rtime calculation to be able to work out how
881 * much time remained until the batteries were fully charged . . .
882 * That would be rather useful, though given it would vary rather a lot
883 * it seems likely that it'd be little more than a rough guesstimate. */
884 set_time_display(globals);
885 set_power_panel(globals);
886 set_message(globals);
887 display_percentage(binfo->percentage);
888 scroll_text();
890 /* redraw_window, if anything changed - determined inside
891 * redraw_window. */
892 redraw_window();
894 usleep(sleep_time);
896 return 0;