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., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include <libdockapp/dockapp.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/shape.h>
41 #include "master_low.xpm"
42 static char **master_xpm
= master_low_xpm
;
47 static int battery_no
;
49 /* Do NOT change the BASE_PERIOD without reading the code ... */
50 #define BASE_PERIOD 100000 /* base period, 100 ms (in usecs) */
53 int x_fd
; /* X11 fd */
54 Display
*display
; /* display */
55 Window win
; /* main window */
56 Pixmap pixmap
; /* main pixmap */
57 Pixmap mask
; /* mask pixmap */
58 Pixmap text
; /* pixmap for text scroller */
59 unsigned short width
; /* width of pixmap */
60 unsigned short height
; /* height of pixmap */
61 int screen
; /* current screen */
62 int tw
; /* text width inside text pixmap */
63 int update
; /* need to redraw? */
64 int blink
; /* should we blink the LED? (critical battery) */
65 int bell
; /* bell on critical low, or not? */
66 int scroll
; /* scroll message text? */
67 int scroll_reset
; /* reset the scrolling text */
69 int period_length
; /* length of the polling period, multiple of BASE_PERIOD */
73 struct dockapp
*dockapp
;
74 /* global_t *globals; */
76 /* this gives us a variable scroll rate, depending on the importance of the
78 #define DEFAULT_SCROLL_RESET 150;
79 int scroll_reset
= DEFAULT_SCROLL_RESET
;
81 /* copy a chunk of pixmap around the app */
82 static void copy_xpm_area(int x
, int y
, int w
, int h
, int dx
, int dy
)
84 XCopyArea(DADisplay
, dockapp
->pixmap
, dockapp
->pixmap
,
85 DAGC
, x
, y
, w
, h
, dx
, dy
);
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, 14, 31, 11, 7, 32);
125 static void reset_scroll(void) {
126 dockapp
->scroll_reset
= 1;
129 static void clear_text_area(void) {
130 copy_xpm_area(66, 9, 52, 7, 6, 50);
133 static void redraw_window(void)
135 if (dockapp
->update
) {
136 XCopyArea(dockapp
->display
, dockapp
->pixmap
, dockapp
->win
,
137 DAGC
, 0, 0, 64, 64, 0, 0);
142 static void new_window(char *display
, char *name
, int argc
, char **argv
)
146 /* Initialise the dockapp window and appicon */
147 DAOpenDisplay(display
, argc
, argv
);
148 DACreateIcon(name
, 64, 64, argc
, argv
);
149 dockapp
->display
= DADisplay
;
150 dockapp
->x_fd
= XConnectionNumber(dockapp
->display
);
151 dockapp
->win
= DAWindow
;
153 XSelectInput(dockapp
->display
, dockapp
->win
,
154 ExposureMask
| ButtonPressMask
| ButtonReleaseMask
|
155 StructureNotifyMask
);
157 /* create the main pixmap . . . */
158 DAMakePixmapFromData(master_xpm
, &dockapp
->pixmap
, &dockapp
->mask
,
159 &dockapp
->width
, &dockapp
->height
);
160 DASetPixmap(dockapp
->pixmap
);
161 DASetShape(dockapp
->mask
);
163 /* text area is 318x7, or 53 characters long */
164 dockapp
->text
= XCreatePixmap(dockapp
->display
, dockapp
->win
, 318, 7,
165 DefaultDepth(dockapp
->display
,
167 if (!dockapp
->text
) {
168 pfatal("FATAL: Cannot create text scroll pixmap!\n");
172 /* force the window to stay this size - otherwise the user could
173 * resize us and see our panties^Wmaster pixmap . . . */
174 hints
= XAllocSizeHints();
176 hints
->flags
|= PMinSize
| PMaxSize
;
177 hints
->min_width
= 64;
178 hints
->max_width
= 64;
179 hints
->min_height
= 64;
180 hints
->max_height
= 64;
181 XSetWMNormalHints(dockapp
->display
, dockapp
->win
, hints
);
188 static void copy_to_text_buffer(int sx
, int sy
, int w
, int h
, int dx
, int dy
)
190 XCopyArea(dockapp
->display
, dockapp
->pixmap
, dockapp
->text
,
191 DAGC
, sx
, sy
, w
, h
, dx
, dy
);
194 static void copy_to_text_area(int sx
, int sy
, int w
, int h
, int dx
, int dy
)
196 XCopyArea(dockapp
->display
, dockapp
->text
, dockapp
->pixmap
,
197 DAGC
, sx
, sy
, w
, h
, dx
, dy
);
200 static void scroll_text(void)
202 static int start
, end
, stop
;
203 int x
= 6; /* x coord of the start of the text area */
204 int y
= 50; /* y coord */
205 int width
= 51; /* width of the text area */
206 int height
= 7; /* height of the text area */
207 int tw
= dockapp
->tw
; /* width of the rendered text */
210 if (!dockapp
->scroll
)
214 * Conceptually this is viewing the text through a scrolling
215 * window - the window starts out with the end immediately before
216 * the text, and stops when the start of the window is immediately
217 * after the end of the text.
219 * We begin with the start of the window at pixel (0 - width) and
220 * as we scroll we render only the portion of the window above
221 * pixel 0. The destination of the copy during this period starts
222 * out at the end of the text area and works left as more of the
223 * text is being copied, until a full window is being copied.
225 * As the end of the window moves out past the end of the text, we
226 * want to keep the destination at the beginning of the text area,
227 * but copy a smaller and smaller chunk of the text. Eventually the
228 * start of the window will scroll past the end of the text, at
229 * which point we stop doing any work and wait to be reset.
232 if (dockapp
->scroll_reset
) {
237 dockapp
->scroll_reset
= 0;
261 copy_to_text_area(sx
, 0, w
, height
, dx
, y
);
268 static void render_text(char *string
)
272 /* drop out immediately if scrolling is disabled - we don't render
273 * any text at all, since there's not much else we could do
274 * sensibly without scrolling. */
275 if (!dockapp
->scroll
)
278 if (strlen(string
) > 53)
281 /* prepare the text area by clearing it */
282 for (i
= 0; i
< 54; i
++) {
283 copy_to_text_buffer(133, 57, 6, 8, i
* 6, 0);
287 for (i
= 0; string
[i
]; i
++) {
288 c
= toupper(string
[i
]);
289 if (c
>= 'A' && c
<= 'Z') { /* letter */
291 copy_to_text_buffer(c
* 6, 67, 6, 7, k
, 0);
292 } else if (c
>= '0' && c
<= '9') { /* number */
294 copy_to_text_buffer(c
* 6 + 66, 58, 6, 7, k
, 0);
295 } else if (c
== '.') {
296 copy_to_text_buffer(140, 58, 6, 7, k
, 0);
297 } else if (c
== '-') {
298 copy_to_text_buffer(126, 58, 6, 7, k
, 0);
302 dockapp
->tw
= k
; /* length of text segment */
303 /* re-scroll the message */
308 static void clear_percentage(void)
310 /* clear the number */
311 copy_xpm_area(95, 47, 21, 9, 37, 16);
313 copy_xpm_area(66, 18, 54, 8, 5, 5);
315 dockapp
->percent
= -1;
318 static void display_percentage(int percent
)
321 int width
= 54; /* width of the bar */
322 float ratio
= 100.0/width
; /* ratio between the current percentage
323 * and the number of pixels in the bar */
328 if (dockapp
->percent
== percent
)
336 if (dockapp
->percent
== -1)
337 copy_xpm_area(127, 28, 5, 7, 52, 17);
339 if (percent
< 100) { /* 0 - 99 */
340 copy_xpm_area(95, 48, 8, 7, 37, 17);
342 copy_xpm_area((percent
/ 10) * 6 + 67, 28, 5, 7, 40, 17);
343 copy_xpm_area((percent
% 10) * 6 + 67, 28, 5, 7, 46, 17);
345 copy_xpm_area(95, 37, 21, 9, 37, 16); /* 100% */
346 dockapp
->percent
= percent
;
348 bar
= (int)((float)percent
/ ratio
);
350 copy_xpm_area(66, 0, bar
, 8, 5, 5);
352 copy_xpm_area(66 + bar
, 18, 54 - bar
, 8, bar
+ 5, 5);
355 static void display_time(int minutes
)
357 static int ohour
= -1, omin
= -1;
360 if (minutes
<= 0) { /* error - clear the display */
361 invalid_time_display();
366 /* render time on the display */
368 /* our display area only fits %2d:%2d, so we need to make sure
369 * what we're displaying will fit in those constraints. I don't
370 * think we're likely to see any batteries that do more than
371 * 100 hours any time soon, so it's fairly safe. */
378 if (hour
== ohour
&& min
== omin
)
382 copy_xpm_area(tmp
* 7 + 1, 76, 6, 11, 7, 32);
384 copy_xpm_area(tmp
* 7 + 1, 76, 6, 11, 14, 32);
386 copy_xpm_area(tmp
* 7 + 1, 76, 6, 11, 25, 32);
388 copy_xpm_area(tmp
* 7 + 1, 76, 6, 11, 32, 32);
389 copy_xpm_area(71, 76, 3, 11, 21, 32);
395 * The reworked state handling stuff.
398 /* set the current state of the power panel */
405 static void really_blink_power_glyph(void)
407 static int counter
= 0;
410 display_power_glyph();
411 else if (counter
== 20)
413 else if (counter
> 30)
416 counter
+= dockapp
->period_length
;
419 static void blink_power_glyph(void)
422 really_blink_power_glyph();
425 static void really_blink_battery_glyph(void)
427 static int counter
= 0;
430 display_battery_glyph();
431 else if (counter
== 20)
432 kill_battery_glyph();
433 else if (counter
> 30)
436 counter
+= dockapp
->period_length
;
439 static void blink_battery_glyph(void)
442 really_blink_battery_glyph();
445 static void set_power_panel(global_t
*globals
)
447 static enum panel_states power
= PS_NULL
;
448 battery_t
*binfo
= globals
->binfo
;
449 adapter_t
*ap
= &globals
->adapter
;
451 if (ap
->power
== AC
) {
452 if (power
!= PS_AC
) {
454 kill_battery_glyph();
455 display_power_glyph();
457 } else if (ap
->power
== BATT
) {
458 if (power
!= PS_BATT
) {
461 display_battery_glyph();
465 if (globals
->battery_count
> 0) {
466 if (binfo
->charge_state
== CHARGE
)
469 if ((binfo
->state
== CRIT
) && (ap
->power
== BATT
))
470 blink_battery_glyph();
474 void scroll_faster(double factor
) {
475 scroll_reset
= scroll_reset
* factor
;
478 void scroll_slower(double factor
) {
479 scroll_reset
= scroll_reset
* factor
;
482 void reset_scroll_speed(void) {
483 scroll_reset
= DEFAULT_SCROLL_RESET
;
487 * The message that needs to be displayed needs to be decided
488 * according to a heirarchy: a message like not present needs to take
489 * precedence over a global thing like the current power status, and
490 * something like a low battery warning should take precedence over
491 * the "on battery" message. Likewise, a battery charging message
492 * needs to take precedence over the on ac power message. The other
493 * question is how much of a precedence local messages should take
494 * over global ones . . .
496 * So, there are three possible sets of messages: not present, on-line
497 * and off-line messages. We need to decide which of those sets is
498 * appropriate right now, and then decide within them.
501 M_NB
, /* no batteries */
502 M_NP
, /* not present */
503 M_AC
, /* on ac power */
504 M_CH
, /* battery charging */
505 M_BATT
, /* on battery */
506 M_LB
, /* low battery */
507 M_CB
, /* critical low battery */
508 M_HCB
, /* battery reported critical capacity state */
509 M_NULL
, /* empty starting state */
512 static void set_message(global_t
*globals
)
514 static enum messages state
= M_NULL
;
515 battery_t
*binfo
= globals
->binfo
;
516 adapter_t
*ap
= &globals
->adapter
;
518 if (globals
->battery_count
== 0) {
521 reset_scroll_speed();
522 render_text("no batteries");
528 /* battery not present case */
529 if (!binfo
->present
) {
532 reset_scroll_speed();
533 render_text("not present");
535 } else if (ap
->power
== AC
) {
536 if (binfo
->charge_state
== CHARGE
) {
539 reset_scroll_speed();
540 render_text("battery charging");
545 reset_scroll_speed();
546 render_text("on ac power");
550 if (binfo
->state
== CRIT
) {
554 render_text("critical low battery");
556 } else if (binfo
->state
== LOW
) {
560 render_text("low battery");
563 if (state
!= M_BATT
) {
565 reset_scroll_speed();
566 render_text("on battery");
572 void set_time_display(global_t
*globals
)
574 if (globals
->battery_count
== 0) {
575 invalid_time_display();
579 if (globals
->binfo
->charge_state
== CHARGE
)
580 display_time(globals
->binfo
->charge_time
);
581 else if (globals
->binfo
->charge_state
== DISCHARGE
)
582 display_time(globals
->rtime
);
584 invalid_time_display();
587 void clear_batt_id_area(void)
589 copy_xpm_area(125, 40, 7, 11, 51, 32);
592 void set_batt_id_area(int bno
)
594 int w
= 7; /* Width of the number */
595 int h
= 11; /* Height of the number */
596 int dx
= 50; /* x coord of the target area */
597 int dy
= 32; /* y coord of the target area */
598 int sx
= (bno
+ 1) * 7; /* source x coord */
599 int sy
= 76; /* source y coord */
601 copy_xpm_area(sx
, sy
, w
, h
, dx
, dy
);
604 #define VERSION "wmacpi version " WMACPI_VER "\nUsing libacpi version " LIBACPI_VER
606 void cli_wmacpi(global_t
*globals
, int samples
)
608 int i
, j
, sleep_time
= 0;
612 pdebug("samples: %d\n", samples
);
614 sleep_time
= 1000000/samples
;
616 /* we want to acquire samples over some period of time, so . . . */
617 for(i
= 0; i
< samples
+ 2; i
++) {
618 for(j
= 0; j
< globals
->battery_count
; j
++)
619 acquire_batt_info(globals
, j
);
620 acquire_global_info(globals
);
624 ap
= &globals
->adapter
;
625 if(ap
->power
== AC
) {
626 printf("On AC Power");
627 for(i
= 0; i
< globals
->battery_count
; i
++) {
628 binfo
= &batteries
[i
];
629 if(binfo
->present
&& (binfo
->charge_state
== CHARGE
)) {
630 printf("; Battery %s charging", binfo
->name
);
631 printf(", currently at %2d%%", binfo
->percentage
);
632 if(binfo
->charge_time
>= 0)
633 printf(", %2d:%02d remaining",
634 binfo
->charge_time
/60,
635 binfo
->charge_time
%60);
639 } else if(ap
->power
== BATT
) {
640 printf("On Battery");
641 for(i
= 0; i
< globals
->battery_count
; i
++) {
642 binfo
= &batteries
[i
];
643 if(binfo
->present
&& (binfo
->percentage
>= 0))
644 printf(", Battery %s at %d%%", binfo
->name
,
647 if(globals
->rtime
>= 0)
648 printf("; %d:%02d remaining", globals
->rtime
/60,
655 battery_t
*switch_battery(global_t
*globals
, int battno
)
657 globals
->binfo
= &batteries
[battno
];
658 pinfo("changing to monitor battery %s\n", globals
->binfo
->name
);
659 set_batt_id_area(battno
);
662 return globals
->binfo
;
666 int main(int argc
, char **argv
)
668 char *display
= NULL
;
669 int sample_count
= 0;
670 int batt_reinit
, ac_reinit
;
673 int cli
= 0, samples
= 1, critical
= 10;
675 int scroll_count
= 0;
676 enum rtime_mode rt_mode
= RT_RATE
;
678 battery_t
*binfo
= NULL
;
682 struct timeval tv_rate
;
683 struct timeval tv
= {0, 0};
685 DAProgramOption options
[] = {
686 {"-r", "--no-scroll", "disable scrolling message", DONone
, False
, {NULL
}},
687 {"-n", "--no-blink", "disable blinking of various UI elements", DONone
, False
, {NULL
}},
688 {"-x", "--cmdline", "run in command line mode", DONone
, False
, {NULL
}},
689 {"-f", "--force-capacity-mode", "force the use of capacity mode for calculating time remaining", DONone
, False
, {NULL
}},
690 {"-d", "--display", "display or remote display", DOString
, False
, {&display
}},
691 {"-c", "--critical", "set critical low alarm at <number> percent\n (default: 10 percent)", DONatural
, False
, {&critical
}},
692 {"-m", "--battery", "battery number to monitor", DONatural
, False
, {&battery_no
}},
693 {"-s", "--sample-rate", "number of times per minute to sample battery information\n default 20 (once every three seconds)", DONatural
, False
, {&samplerate
}},
694 {"-V", "--verbosity", "Set verbosity", DONatural
, False
, {&verbosity
}},
695 {"-a", "--samples", "number of samples to average over (cli mode only)", DONatural
, False
, {&samples
}},
698 dockapp
= calloc(1, sizeof(struct dockapp
));
699 globals
= calloc(1, sizeof(global_t
));
704 dockapp
->scroll_reset
= 0;
705 globals
->crit_level
= 10;
708 /* after this many samples, we reinit the battery and AC adapter
710 * XXX: make these configurable . . . */
714 /* this needs to be up here because we need to know what batteries
715 * are available /before/ we can decide if the battery we want to
716 * monitor is available. */
717 /* parse command-line options */
718 DAParseArguments(argc
, argv
, options
, 10,
719 "A battery monitor dockapp for ACPI based systems",
728 if (options
[3].used
) {
733 if (samplerate
== 0) samplerate
= 1;
734 if (samplerate
> 600) samplerate
= 600;
736 /* convert to number of base periods */
737 samplerate
= ((60 * 1000000) / samplerate
) / BASE_PERIOD
;
739 if (!dockapp
->scroll
) {
740 if (!dockapp
->blink
) {
741 /* Adapt the period to the sample rate */
742 tv_rate
.tv_usec
= samplerate
* BASE_PERIOD
;
744 tv_rate
.tv_sec
= tv_rate
.tv_usec
/ 1000000;
745 tv_rate
.tv_usec
= tv_rate
.tv_usec
- (tv_rate
.tv_sec
* 1000000);
747 dockapp
->period_length
= samplerate
;
749 /* blinking is every second */
750 tv_rate
.tv_sec
= 1; /* BASE_PERIOD * 10 = 1 sec */
753 dockapp
->period_length
= 10;
756 /* scrolling is every BASE_PERIOD (100 ms) */
758 tv_rate
.tv_usec
= BASE_PERIOD
;
760 dockapp
->period_length
= 1;
763 if (critical
> 100) {
764 fprintf(stderr
, "Please use values between 0 and 100%%\n");
765 fprintf(stderr
, "Using default value of 10%%\n");
768 globals
->crit_level
= critical
;
770 if (battery_no
>= MAXBATT
) {
771 fprintf(stderr
, "Please specify a battery number below %d\n", MAXBATT
);
774 pinfo("Monitoring battery %d\n", battery_no
);
776 if (power_init(globals
))
777 /* power_init functions handle printing error messages */
780 globals
->rt_mode
= rt_mode
;
781 globals
->rt_forced
= rt_forced
;
783 if (battery_no
> globals
->battery_count
) {
784 pinfo("Battery %d not available for monitoring.\n", battery_no
);
787 /* check for cli mode */
789 cli_wmacpi(globals
, samples
);
792 /* check to see if we've got a valid DISPLAY env variable, as a simple check to see if
793 * we're running under X */
794 if (!getenv("DISPLAY")) {
795 pdebug("Not running under X - using cli mode\n");
796 cli_wmacpi(globals
, samples
);
802 /* make new dockapp window */
803 /* Don't even /think/ of asking me why, but if I set the window name to
804 * "acpi", the app refuses to dock properly - it's just plain /weird/.
805 * So, wmacpi it is . . . */
806 new_window(display
, "wmacpi", argc
, argv
);
808 /* get initial statistics */
809 acquire_all_info(globals
);
811 if (globals
->battery_count
> 0) {
812 binfo
= &batteries
[battery_no
];
813 globals
->binfo
= binfo
;
814 set_batt_id_area(battery_no
);
815 pinfo("monitoring battery %s\n", binfo
->name
);
818 clear_time_display();
819 set_power_panel(globals
);
820 set_message(globals
);
827 while (XPending(dockapp
->display
)) {
828 XNextEvent(dockapp
->display
, &event
);
829 switch (event
.type
) {
833 while (XCheckTypedEvent(dockapp
->display
, Expose
, &event
));
837 XCloseDisplay(dockapp
->display
);
843 if (globals
->battery_count
== 0)
846 /* cycle through the known batteries. */
848 battery_no
= battery_no
% globals
->battery_count
;
850 binfo
= switch_battery(globals
, battery_no
);
853 /* what /is/ this crap?
854 * Turns out that libdockapp adds the WM_DELETE_WINDOW atom to
855 * the WM_PROTOCOLS property for the window, which means that
856 * rather than get a simple DestroyNotify message, we get a
857 * nice little message from the WM saying "hey, can you delete
858 * yourself, pretty please?". So, when running as a window
859 * rather than an icon, we're impossible to kill in a friendly
860 * manner, because we're expecting to die from a DestroyNotify
861 * and thus blithely ignoring the WM knocking on our window
864 * This simply checks for that scenario - it may fail oddly if
865 * something else comes to us via a WM_PROTOCOLS ClientMessage
866 * event, but I suspect it's not going to be an issue. */
867 wmdelwin
= XInternAtom(dockapp
->display
, "WM_DELETE_WINDOW", 1);
868 atom
= event
.xclient
.data
.l
[0];
869 if (atom
== wmdelwin
) {
870 XCloseDisplay(dockapp
->display
);
877 /* XXX: some laptops have problems with sampling the battery
878 * regularly - apparently, the BIOS disables interrupts while
879 * reading from the battery, which is generally on a slow bus
880 * and is a slow device, so you get significant periods without
881 * interrupts. This causes interactivity to suffer . . .
883 * So, the workaround/fix for this is to sample at a much
884 * lower rate than we may update/refresh/expose/whatever. The
885 * user specifies how many times they want us to sample per
886 * minute; we use select() on our X events fd to wake up when
887 * there's some display work to be done, with the timeout set
888 * to whatever the time between samples is. When we hit our
889 * select() timeout we update our samples, otherwise we update
892 * Note that this has a wrinkle when blinking and/or scrolling
893 * is enabled, since we need to update the display more
894 * frequently than we sample (most likely). In that case we
895 * set the timeout based on the display update cycle. */
897 /* have we completed our timeout, or were we woken up early? */
898 if ((tv
.tv_sec
!= 0) || (tv
.tv_usec
!= 0))
903 sample_count
+= dockapp
->period_length
;
905 if (sample_count
>= samplerate
) {
906 if (globals
->battery_count
== 0) {
909 reinit_batteries(globals
);
911 /* battery appeared */
912 if (globals
->battery_count
> 0) {
913 if (battery_no
> globals
->battery_count
)
916 binfo
= switch_battery(globals
, battery_no
);
920 acquire_all_info(globals
);
922 /* we need to be able to reinitialise batteries and adapters, because
923 * they change - you can hotplug batteries on most laptops these days
924 * and who knows what kind of shit will be happening soon . . . */
925 if (batt_count
++ >= batt_reinit
) {
926 if(reinit_batteries(globals
))
927 pfatal("Oh my god, the batteries are gone!\n");
931 if (ac_count
++ >= ac_reinit
) {
932 if(reinit_ac_adapters(globals
))
933 pfatal("What happened to our AC adapters?!?\n");
939 if (scroll_count
++ >= scroll_reset
) {
944 /* The old code had some kind of weird crap with timers and the like.
945 * As far as I can tell, it's meaningless - the time we want to display
946 * is the time calculated from the remaining capacity, as per the
947 * ACPI spec. The only thing I'd change is the handling of a charging
948 * state: my best guess, based on the behaviour I'm seeing with my
949 * Lifebook, is that the present rate value when charging is the rate
950 * at which the batteries are being charged, which would mean I'd just
951 * need to reverse the rtime calculation to be able to work out how
952 * much time remained until the batteries were fully charged . . .
953 * That would be rather useful, though given it would vary rather a lot
954 * it seems likely that it'd be little more than a rough guesstimate. */
955 set_time_display(globals
);
956 set_power_panel(globals
);
957 set_message(globals
);
959 if (globals
->battery_count
== 0) {
961 clear_batt_id_area();
963 display_percentage(binfo
->percentage
);
968 /* redraw_window, if anything changed */
972 FD_SET(dockapp
->x_fd
, &fds
);
973 select(FD_SETSIZE
, &fds
, NULL
, NULL
, &tv
);