wmacpi: Bump to version 1.99r3.
[dockapps.git] / wmacpi / wmacpi.c
blob9f3b258f58f3c8fb04c9be0c38349731f1167378
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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <getopt.h>
26 #include <unistd.h>
27 #include <time.h>
29 #include <X11/X.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/extensions/shape.h>
33 #include <X11/xpm.h>
35 #include "libacpi.h"
36 #include "wmacpi.h"
38 #define WMACPI_VER "1.99r2"
40 /* main pixmap */
41 #ifdef LOW_COLOR
42 #include "master_low.xpm"
43 #else
44 #include "master.xpm"
45 #endif
47 typedef struct {
48 Display *display; /* X11 display struct */
49 int screen; /* current screen */
50 Window root; /* root window */
51 Window win; /* one window */
52 Window iconwin; /* another one */
53 Pixmap pixmap; /* UI pixmap, window pixmap */
54 Pixmap mask; /* mask pixmap for shape */
55 GC gc; /* main drawing GC */
56 Pixmap text; /* pixmap for text scroller */
57 int tw; /* text width inside text pixmap */
58 int update; /* need to redraw? */
59 int blink; /* should we blink the LED? (critical battery) */
60 int bell; /* bell on critical low, or not? */
61 } Dockapp;
63 /* globals */
64 Dockapp *dockapp;
65 global_t *globals;
66 int count = 0; /* global timer variable */
67 /* extern int verbosity; */
69 /* Time for scroll updates */
70 #define DEFAULT_UPDATE 150
71 static int update_timeout = DEFAULT_UPDATE;
73 /* proto for local stuff */
74 static void new_window(char *name);
75 static int open_display(char *display);
76 static void redraw_window(void);
77 static void render_text(char *string);
78 static void scroll_text(int x, int y, int width, int tw, int reset);
79 static void display_percentage(int percent);
80 static void display_time(int minutes);
82 #define copy_xpm_area(x, y, w, h, dx, dy) \
83 { \
84 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->pixmap, \
85 dockapp->gc, x, y, w, h, dx, dy); \
86 dockapp->update = 1; \
89 /* display AC power symbol */
90 static void display_power_glyph(void)
92 copy_xpm_area(67, 38, 12, 7, 6, 17);
95 /* get rid of AC power symbol */
96 static void kill_power_glyph(void)
98 copy_xpm_area(67, 48, 12, 7, 6, 17);
101 /* display battery symbol */
102 static void display_battery_glyph(void)
104 copy_xpm_area(82, 38, 12, 7, 20, 17);
107 /* get rid of battery symbol */
108 static void kill_battery_glyph(void)
110 copy_xpm_area(82, 48, 12, 7, 20, 17);
113 /* clear the time display */
114 static void clear_time_display(void)
116 copy_xpm_area(114, 76, 31, 11, 7, 32);
119 /* set time display to -- -- */
120 static void invalid_time_display(void)
122 copy_xpm_area(122, 13, 31, 11, 7, 32);
125 static void redraw_window(void)
127 if (dockapp->update) {
128 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->iconwin,
129 dockapp->gc, 0, 0, 64, 64, 0, 0);
130 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->win,
131 dockapp->gc, 0, 0, 64, 64, 0, 0);
132 dockapp->update = 0;
136 static void new_window(char *name)
138 XpmAttributes attr;
139 Pixel fg, bg;
140 XGCValues gcval;
141 XSizeHints sizehints;
142 XClassHint classhint;
143 XWMHints wmhints;
145 dockapp->screen = DefaultScreen(dockapp->display);
146 dockapp->root = DefaultRootWindow(dockapp->display);
148 sizehints.flags = USSize | USPosition;
149 sizehints.width = 64;
150 sizehints.height = 64;
152 fg = BlackPixel(dockapp->display, dockapp->screen);
153 bg = WhitePixel(dockapp->display, dockapp->screen);
155 dockapp->win = XCreateSimpleWindow(dockapp->display, dockapp->root,
156 0, 0, sizehints.width,
157 sizehints.height, 1, fg, bg);
158 dockapp->iconwin =
159 XCreateSimpleWindow(dockapp->display, dockapp->win, 0, 0,
160 sizehints.width, sizehints.height, 1, fg, bg);
162 XSetWMNormalHints(dockapp->display, dockapp->win, &sizehints);
163 classhint.res_name = name;
164 classhint.res_class = name;
165 XSetClassHint(dockapp->display, dockapp->win, &classhint);
167 XSelectInput(dockapp->display, dockapp->win,
168 ExposureMask | ButtonPressMask | ButtonReleaseMask |
169 StructureNotifyMask);
170 XSelectInput(dockapp->display, dockapp->iconwin,
171 ExposureMask | ButtonPressMask | ButtonReleaseMask |
172 StructureNotifyMask);
174 XStoreName(dockapp->display, dockapp->win, name);
175 XSetIconName(dockapp->display, dockapp->win, name);
177 gcval.foreground = fg;
178 gcval.background = bg;
179 gcval.graphics_exposures = False;
181 dockapp->gc =
182 XCreateGC(dockapp->display, dockapp->win,
183 GCForeground | GCBackground | GCGraphicsExposures,
184 &gcval);
186 attr.exactColors = 0;
187 attr.alloc_close_colors = 1;
188 attr.closeness = 1L << 15;
189 attr.valuemask = XpmExactColors | XpmAllocCloseColors | XpmCloseness;
190 if (XpmCreatePixmapFromData(dockapp->display, dockapp->win,
191 master_xpm, &dockapp->pixmap,
192 &dockapp->mask, &attr) != XpmSuccess) {
193 pfatal("FATAL: Not enough colors for main pixmap!\n");
194 exit(1);
197 /* text area is 318x7, or 53 characters long */
198 dockapp->text = XCreatePixmap(dockapp->display, dockapp->win, 318, 7,
199 DefaultDepth(dockapp->display,
200 dockapp->screen));
201 if (!dockapp->text) {
202 pfatal("FATAL: Cannot create text scroll pixmap!\n");
203 exit(1);
206 XShapeCombineMask(dockapp->display, dockapp->win, ShapeBounding, 0, 0,
207 dockapp->mask, ShapeSet);
208 XShapeCombineMask(dockapp->display, dockapp->iconwin, ShapeBounding, 0,
209 0, dockapp->mask, ShapeSet);
211 wmhints.initial_state = WithdrawnState;
212 wmhints.flags = StateHint;
213 wmhints.icon_window = dockapp->iconwin;
214 wmhints.icon_x = sizehints.x;
215 wmhints.icon_y = sizehints.y;
216 wmhints.window_group = dockapp->win;
217 wmhints.flags =
218 StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
219 XSetWMHints(dockapp->display, dockapp->win, &wmhints);
221 XMapWindow(dockapp->display, dockapp->win);
224 static void render_text(char *string)
226 int i, c, k;
228 if (strlen(string) > 53)
229 return;
231 /* prepare the text area by clearing it */
232 for (i = 0; i < 54; i++) {
233 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
234 dockapp->gc, 133, 57, 6, 8, i * 6, 0);
236 k = 0;
238 for (i = 0; string[i]; i++) {
239 c = toupper(string[i]);
240 if (c >= 'A' && c <= 'Z') { /* letter */
241 c = c - 'A';
242 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
243 dockapp->gc, c * 6, 67, 6, 7, k, 0);
244 } else if (c >= '0' && c <= '9') { /* number */
245 c = c - '0';
246 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
247 dockapp->gc, c * 6 + 66, 58, 6, 7, k, 0);
248 } else if (c == '.') {
249 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
250 dockapp->gc, 140, 58, 6, 7, k, 0);
251 } else if (c == '-') {
252 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
253 dockapp->gc, 126, 58, 6, 7, k, 0);
255 k += 6;
257 dockapp->tw = k; /* length of text segment */
258 /* re-scroll the message */
259 scroll_text(6, 50, 52, dockapp->tw, 1);
260 /* reset the scroll repeat counter */
261 count = 0;
264 static int open_display(char *display)
266 dockapp->display = XOpenDisplay(display);
267 if (!dockapp->display) {
268 perr("Unable to open display '%s'\n", display);
269 return 1;
271 return 0;
274 static void scroll_text(int x, int y, int width, int tw, int reset)
276 static int pos, first, stop;
278 if (reset) {
279 pos = 0;
280 first = 0;
281 stop = 0;
282 XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text,
283 dockapp->gc, 0, 0, width, 7, x, y);
286 if (stop) {
287 return;
290 if ((first == 0) && pos == 0) {
291 pos = width;
292 first = 1;
295 if (pos == (0 - tw - 2)) {
296 first = 1;
297 pos = width;
298 stop = 1;
299 return;
301 pos -= 2;
303 if (pos > 0) {
304 copy_xpm_area(66, 9, pos, 7, x, y); /* clear */
305 XCopyArea(dockapp->display, dockapp->text, dockapp->pixmap,
306 dockapp->gc, 0, 0, width - pos, 7, x + pos, y);
307 } else { /* don't need to clear, already in text */
308 XCopyArea(dockapp->display, dockapp->text, dockapp->pixmap,
309 dockapp->gc, abs(pos), 0, width, 7, x, y);
311 dockapp->update = 1;
314 static void display_percentage(int percent)
316 static int op = -1;
317 static unsigned int obar;
318 unsigned int bar;
320 if (percent == -1)
321 percent = 0;
323 if (op == percent)
324 return;
326 if (percent < 0)
327 percent = 0;
328 if (percent > 100)
329 percent = 100;
331 if (percent < 100) { /* 0 - 99 */
332 copy_xpm_area(95, 48, 8, 7, 37, 17);
333 if (percent >= 10)
334 copy_xpm_area((percent / 10) * 6 + 67, 28, 5, 7, 40, 17);
335 copy_xpm_area((percent % 10) * 6 + 67, 28, 5, 7, 46, 17);
336 } else
337 copy_xpm_area(95, 37, 21, 9, 37, 16); /* 100% */
338 op = percent;
340 bar = percent / 1.8518;
342 if (bar == obar)
343 return;
345 copy_xpm_area(66, 0, bar, 8, 5, 5);
346 if (bar < 54)
347 copy_xpm_area(66 + bar, 18, 54 - bar, 8, bar + 5, 5);
348 obar = bar;
351 static void display_time(int minutes)
353 static int ohour = -1, omin = -1;
354 int hour, min, tmp;
356 if (minutes <= 0) { /* error - clear the display */
357 invalid_time_display();
358 ohour = omin = -1;
359 return;
362 /* render time on the display */
363 hour = minutes / 60;
364 /* our display area only fits %2d:%2d, so we need to make sure
365 * what we're displaying will fit in those constraints. I don't
366 * think we're likely to see any batteries that do more than
367 * 100 hours any time soon, so it's fairly safe. */
368 if (hour >= 100) {
369 hour = 99;
370 min = 59;
371 } else
372 min = minutes % 60;
374 if (hour == ohour && min == omin)
375 return;
377 tmp = hour / 10;
378 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 7, 32);
379 tmp = hour % 10;
380 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 14, 32);
381 tmp = min / 10;
382 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 25, 32);
383 tmp = min % 10;
384 copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 32, 32);
385 copy_xpm_area(71, 76, 3, 11, 21, 32);
386 ohour = hour;
387 omin = min;
391 * The reworked state handling stuff.
394 /* set the current state of the power panel */
395 enum panel_states {
396 PS_AC,
397 PS_BATT,
398 PS_NULL,
401 static void really_blink_power_glyph(void)
403 static int counter = 0;
405 if (counter == 10)
406 display_power_glyph();
407 else if (counter == 20)
408 kill_power_glyph();
409 else if (counter > 30)
410 counter = 0;
411 counter++;
414 static void blink_power_glyph(void)
416 if (dockapp->blink)
417 really_blink_power_glyph();
420 static void really_blink_battery_glyph(void)
422 static int counter = 0;
424 if (counter == 10)
425 display_battery_glyph();
426 else if (counter == 20)
427 kill_battery_glyph();
428 else if (counter > 30)
429 counter = 0;
430 counter++;
433 static void blink_battery_glyph(void)
435 if (dockapp->blink)
436 really_blink_battery_glyph();
439 static void set_power_panel(void)
441 enum panel_states power = PS_NULL;
442 battery_t *binfo = globals->binfo;
443 adapter_t *ap = &globals->adapter;
445 if (ap->power == AC) {
446 if (power != PS_AC) {
447 power = PS_AC;
448 kill_battery_glyph();
449 display_power_glyph();
451 } else if (ap->power == BATT) {
452 if (power != PS_BATT) {
453 power = PS_BATT;
454 kill_power_glyph();
455 display_battery_glyph();
459 if (binfo->charge_state == CHARGE)
460 blink_power_glyph();
462 if (binfo->state == CRIT)
463 blink_battery_glyph();
465 if (binfo->state == HARD_CRIT) {
466 really_blink_battery_glyph();
467 /* we only do this here because it'd be obnoxious to
468 * do it anywhere else. */
469 if (dockapp->bell) {
470 XBell(dockapp->display, 100);
476 * The message that needs to be displayed needs to be decided
477 * according to a heirarchy: a message like not present needs to take
478 * precedence over a global thing like the current power status, and
479 * something like a low battery warning should take precedence over
480 * the "on battery" message. Likewise, a battery charging message
481 * needs to take precedence over the on ac power message. The other
482 * question is how much of a precedence local messages should take
483 * over global ones . . .
485 * So, there are three possible sets of messages: not present, on-line
486 * and off-line messages. We need to decide which of those sets is
487 * appropriate right now, and then decide within them.
489 enum messages {
490 M_NP, /* not present */
491 M_AC, /* on ac power */
492 M_CH, /* battery charging */
493 M_BATT, /* on battery */
494 M_LB, /* low battery */
495 M_CB, /* critical low battery */
496 M_HCB, /* battery reported critical capacity state */
497 M_NULL, /* empty starting state */
500 static void set_message(void)
502 static enum messages state = M_NULL;
503 battery_t *binfo = globals->binfo;
504 adapter_t *ap = &globals->adapter;
506 /* battery not present case */
507 if (!binfo->present) {
508 if (state != M_NP) {
509 state = M_NP;
510 render_text("not present");
512 } else if (ap->power == AC) {
513 if (binfo->charge_state == CHARGE) {
514 if (state != M_CH) {
515 state = M_CH;
516 update_timeout = DEFAULT_UPDATE;
517 render_text("battery charging");
519 } else {
520 if (state != M_AC) {
521 state = M_AC;
522 update_timeout = DEFAULT_UPDATE;
523 render_text("on ac power");
526 } else {
527 if (binfo->state == CRIT) {
528 if (state != M_CB) {
529 state = M_CB;
530 update_timeout = 80;
531 render_text("critical low battery");
533 } else if (binfo->state == HARD_CRIT) {
534 if (state != M_HCB) {
535 state = M_HCB;
536 update_timeout = 60;
537 render_text("hard critical low battery");
539 } else if (binfo->state == LOW) {
540 if (state != M_LB) {
541 state = M_LB;
542 update_timeout = 100;
543 render_text("low battery");
545 } else {
546 if (state != M_BATT) {
547 state = M_BATT;
548 update_timeout = DEFAULT_UPDATE;
549 render_text("on battery");
555 void set_time_display(void)
557 battery_t *binfo = &batteries[battery_no];
559 if (binfo->charge_state == CHARGE)
560 display_time(binfo->charge_time);
561 else if (binfo->charge_state == DISCHARGE)
562 display_time(globals->rtime);
563 else
564 invalid_time_display();
568 * This should really be fixed so that it can handle more than two batteries.
571 void set_id_1(void)
573 copy_xpm_area(118, 38, 15, 15, 44, 30);
576 void set_id_2(void)
578 copy_xpm_area(136, 38, 15, 15, 44, 30);
581 void set_batt_id_area(int bno)
583 switch(bno) {
584 case 0:
585 set_id_1();
586 break;
587 case 1:
588 set_id_2();
589 break;
593 void usage(char *name)
595 printf("%s - help\t\t[simon@dreamcraft.com.au]\n\n"
596 "-d display\t\tdisplay on remote display <display>\n"
597 "-b\t\t\tmake noise when battery is critical low (beep)\n"
598 "-c value\t\tset critical low alarm at <value> percent\n"
599 "\t\t\t(default: 10 percent)\n"
600 "-m <battery number>\tbattery number to monitor\n"
601 "-s <sample rate>\trate at which to sample battery status\n"
602 "\t\t\tdefault 100 (once every three seconds)\n"
603 "-n\t\t\tdo not blink\n"
604 "-w\t\t\trun in command line mode\n"
605 "-a <samples>\t\tsamples to average over (cli mode only)\n"
606 "-v\t\t\tincrease verbosity\n"
607 "\t\t\tcan be used multiple times to increase verbosity further\n"
608 "-h\t\t\tdisplay this help\n",
609 name);
612 void print_version(void)
614 printf("wmacpi version %s\n", WMACPI_VER);
615 printf(" Using libacpi version %s\n", LIBACPI_VER);
618 void cli_wmacpi(int samples)
620 int i, j, sleep_time = 0;
621 battery_t *binfo;
622 adapter_t *ap;
624 printf("%d\n", samples);
625 if(samples > 1)
626 sleep_time = 1000000/samples;
628 /* we want to acquire samples over some period of time, so . . . */
629 for(i = 0; i < samples + 2; i++) {
630 for(j = 0; j < batt_count; j++)
631 acquire_batt_info(j);
632 acquire_global_info();
633 usleep(sleep_time);
636 ap = &globals->adapter;
637 if(ap->power == AC) {
638 printf("On AC Power");
639 for(i = 0; i < batt_count; i++) {
640 binfo = &batteries[i];
641 if(binfo->present && (binfo->charge_state == CHARGE)) {
642 printf("; Battery %s charging", binfo->name);
643 printf(", currently at %2d%%", binfo->percentage);
644 if(binfo->charge_time >= 0)
645 printf(", %2d:%02d remaining",
646 binfo->charge_time/60,
647 binfo->charge_time%60);
650 printf("\n");
651 } else if(ap->power == BATT) {
652 printf("On Battery");
653 for(i = 0; i < batt_count; i++) {
654 binfo = &batteries[i];
655 if(binfo->present && (binfo->percentage >= 0))
656 printf(", Battery %s at %d%%", binfo->name,
657 binfo->percentage);
659 if(globals->rtime >= 0)
660 printf("; %d:%02d remaining", globals->rtime/60,
661 globals->rtime%60);
662 printf("\n");
664 return;
667 int main(int argc, char **argv)
669 char *display = NULL;
670 int ch;
671 int update = 0;
672 int cli = 0, samples = 1;
673 int samplerate = 100;
674 battery_t *binfo;
676 dockapp = calloc(1, sizeof(Dockapp));
677 globals = calloc(1, sizeof(global_t));
679 dockapp->blink = 1;
680 dockapp->bell = 0;
681 globals->crit_level = 10;
682 battery_no = 1;
684 /* parse command-line options */
685 while ((ch = getopt(argc, argv, "d:c:m:s:a:hnwbvV")) != EOF) {
686 switch (ch) {
687 case 'c':
688 if (optarg) {
689 globals->crit_level = atoi(optarg);
690 if ((globals->crit_level < 0) || (globals->crit_level > 100)) {
691 fprintf(stderr, "Please use values between 0 and 100%%\n");
692 globals->crit_level = 10;
693 fprintf(stderr, "Using default value of 10%%\n");
696 break;
697 case 'd':
698 if (optarg)
699 display = strdup(optarg);
700 break;
701 case 'm':
702 if (optarg) {
703 battery_no = atoi(optarg);
704 if (battery_no >= MAXBATT) {
705 fprintf(stderr, "Please specify a battery number below %d\n",
706 MAXBATT);
707 return 1;
709 if (battery_no > batt_count) {
710 fprintf(stderr, "Battery %d does not appear to be installed\n",
711 battery_no);
712 return 1;
714 fprintf(stderr, "Monitoring battery %d\n", battery_no);
716 break;
717 case 's':
718 if (optarg) {
719 samplerate = atoi(optarg);
720 if (samplerate == 0) samplerate = 1;
721 if (samplerate > 3000) samplerate = 3000;
722 } else {
723 usage(argv[0]);
724 exit(1);
726 break;
727 case 'h':
728 usage(argv[0]);
729 return 0;
730 case 'v':
731 verbosity++;
732 break;
733 case 'V':
734 print_version();
735 return 0;
736 case 'n':
737 dockapp->blink = 0;
738 break;
739 case 'w':
740 cli = 1;
741 break;
742 case 'a':
743 if(optarg != NULL) {
744 samples = atoi(optarg);
745 if(samples > 1000 || samples <= 0) {
746 fprintf(stderr, "Please specify a reasonable number of samples\n");
747 exit(1);
750 break;
751 case 'b':
752 dockapp->blink = 1;
753 break;
754 default:
755 usage(argv[0]);
756 return 1;
761 /* see if whatever we want to use is supported */
762 if (power_init())
763 /* power_init functions handle printing error messages */
764 exit(1);
766 /* check for cli mode */
767 if (cli) {
768 cli_wmacpi(samples);
769 exit(0);
772 battery_no--;
774 /* open local or command-line specified display */
775 if (open_display(display))
776 exit(1);
778 /* make new dockapp window */
779 /* Don't even /think/ of asking me why, but if I set the window name to
780 * "acpi", the app refuses to dock properly - it's just plain /weird/.
781 * So, wmacpi it is . . . */
782 new_window("wmacpi");
784 /* get initial statistics */
785 acquire_all_info();
786 binfo = &batteries[battery_no];
787 globals->binfo = binfo;
788 pinfo("monitoring battery %s\n", binfo->name);
789 clear_time_display();
790 set_power_panel();
791 set_message();
792 set_batt_id_area(battery_no);
794 /* main loop */
795 while (1) {
796 XEvent event;
797 while (XPending(dockapp->display)) {
798 XNextEvent(dockapp->display, &event);
799 switch (event.type) {
800 case Expose:
801 /* update */
802 dockapp->update = 1;
803 while (XCheckTypedEvent(dockapp->display, Expose, &event));
804 redraw_window();
805 break;
806 case DestroyNotify:
807 XCloseDisplay(dockapp->display);
808 exit(0);
809 break;
810 case ButtonPress:
811 break;
812 case ButtonRelease:
813 /* cycle through the known batteries. */
814 battery_no++;
815 battery_no = battery_no % batt_count;
816 globals->binfo = &batteries[battery_no];
817 binfo = globals->binfo;
818 pinfo("changing to monitor battery %d\n", battery_no + 1);
819 set_batt_id_area(battery_no);
820 break;
824 /* XXX: some laptops have problems with sampling the battery
825 * regularly - apparently, the BIOS disables interrupts while
826 * reading from the battery, which is generally on a slow bus
827 * and is a slow device, so you get significant periods without
828 * interrupts. This causes interactivity to suffer . . .
830 * My proposed workaround is to allow the user to set the sample
831 * rate - it defaults to ten, but can be set lower (or higher).
833 * The only problem with this is that we need to sample less
834 * frequently, while still allowing the app to update normally.
835 * That means calling redraw_window() and all the set_*() functions
836 * normally, but only calling acquire_all_info() every so often.
837 * As it stands, we only call acquire_all_info() once every three
838 * seconds (once every thirty updates) . . . I'm not entirely sure
839 * /how/ this could cause interactivity problems, but hey . . .
841 * So, given the base rate of once every three seconds, we want to
842 * change this test to . . . */
843 if (update++ == (3000/samplerate)) {
844 acquire_all_info();
845 update = 0;
848 if (count++ == update_timeout) {
849 scroll_text(6, 50, 52, dockapp->tw, 1);
850 count = 0;
853 /* the old code had some kind of weird crap with timers and the like.
854 * As far as I can tell, it's meaningless - the time we want to display
855 * is the time calculated from the remaining capacity, as per the
856 * ACPI spec. The only thing I'd change is the handling of a charging
857 * state: my best guess, based on the behaviour I'm seeing with my
858 * Lifebook, is that the present rate value when charging is the rate
859 * at which the batteries are being charged, which would mean I'd just
860 * need to reverse the rtime calculation to be able to work out how
861 * much time remained until the batteries were fully charged . . .
862 * That would be rather useful, though given it would vary rather a lot
863 * it seems likely that it'd be little more than a rough guesstimate. */
864 set_time_display();
865 set_power_panel();
866 set_message();
867 display_percentage(binfo->percentage);
868 scroll_text(6, 50, 52, dockapp->tw, 0);
870 /* redraw_window, if anything changed - determined inside
871 * redraw_window. */
872 redraw_window();
873 usleep(100000);
875 return 0;