wmclockmon: update change-log
[dockapps.git] / wmbatteries / src / main.c
blob6d9820b899a20892e9ec4f3fe08c5a8289a065f8
1 /*
2 * wmbatteries - A dockapp to monitor ACPI status of two batteries
3 * Copyright (C) 2003 Florian Krohs <krohs@uni.de>
5 * Based on work by Thomas Nemeth <tnemeth@free.fr>
6 * Copyright (C) 2002 Thomas Nemeth <tnemeth@free.fr>
7 * and on work by Seiichi SATO <ssato@sh.rim.or.jp>
8 * Copyright (C) 2001,2002 Seiichi SATO <ssato@sh.rim.or.jp>
9 * and on work by Mark Staggs <me@markstaggs.net>
10 * Copyright (C) 2002 Mark Staggs <me@markstaggs.net>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
32 #include "files.h"
33 #include <signal.h>
34 #include "dockapp.h"
35 #include "backlight_on.xpm"
36 #include "backlight_off.xpm"
37 #include "parts.xpm"
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <string.h>
42 #ifdef linux
43 #include <sys/stat.h>
44 #endif
46 #define WMBATTERIES_VERSION "0.1.3"
48 #define FREE(data) {if (data) free (data); data = NULL;}
50 #define RATE_HISTORY 10
51 #define BLINK_ONLOADING_TIMEOUT 500
52 #define SIZE 58
53 #define MAXSTRLEN 512
54 #define WINDOWED_BG ". c #AEAAAE"
55 #define MAX_HISTORY 16
56 #define CPUNUM_NONE -1
58 #define CHARGING 3
59 #define DISCHARGING 1
60 #define UNKNOWN 0
62 #define TOGGLEMODE 1
63 #define TOGGLESPEED 2
65 #define DEFAULT_UPDATE_INTERVAL 5
67 #define RATE 0
68 #define TEMP 1
70 #define NONE 0
71 #define STATE_OK 1
72 #define INFO_OK 2
73 #define BAT_OK 3
75 #ifdef DEBUG
76 #define DEBUGSTRING(STRING) printf("DEBUG: %s\n",STRING);
77 #endif
79 #ifndef DEBUG
80 #define DEBUGSTRING(STRING)
81 #endif
83 # ifdef linux
84 # define ACPIDEV "/proc/acpi/info"
85 # endif
87 typedef struct AcpiInfos {
88 const char driver_version[10];
89 int ac_line_status;
90 int battery_status[2];
91 int battery_percentage[2];
92 long rate[2];
93 long remain[2];
94 long currcap[2];
95 int thermal_temp;
96 int thermal_state;
97 int hours_left;
98 int minutes_left;
99 int low;
100 } AcpiInfos;
102 typedef struct RateListElem {
103 long rate[2];
104 struct RateListElem *next;
105 } RateListElem;
107 typedef enum { LIGHTOFF, LIGHTON } light;
110 Pixmap pixmap;
111 Pixmap backdrop_on;
112 Pixmap backdrop_off;
113 Pixmap parts;
114 Pixmap mask;
115 static char *display_name = "";
116 static char light_color[256] = ""; /* back-light color */
117 char tmp_string[256];
118 static char *config_file = NULL; /* name of configfile */
119 static unsigned update_interval = DEFAULT_UPDATE_INTERVAL;
120 static light backlight = LIGHTOFF;
121 static unsigned switch_authorized = True;
122 static unsigned alarm_level = 20;
123 static unsigned alarm_level_temp = 70;
124 static char *notif_cmd = NULL;
125 static char *suspend_cmd = NULL;
126 static char *standby_cmd = NULL;
127 static int mode = TEMP;
128 static int togglemode = TOGGLEMODE;
129 static int togglespeed = TOGGLESPEED;
130 static int animationspeed = 500;
131 static AcpiInfos cur_acpi_infos;
132 static number_of_batteries = 2;
133 static char state_files[2][256]={BAT0_STATE_FILE,BAT1_STATE_FILE};
134 static char info_files[2][256]={BAT0_INFO_FILE,BAT1_INFO_FILE};
135 static char thermal[256]=THERMAL_FILE;
136 static char ac_state[256]=AC_STATE_FILE;
137 static int history_size = RATE_HISTORY;
139 static RateListElem *rateElements;
140 static RateListElem *firstRateElem;
142 #ifdef linux
143 # ifndef ACPI_32_BIT_SUPPORT
144 # define ACPI_32_BIT_SUPPORT 0x0002
145 # endif
146 #endif
149 /* prototypes */
150 static void parse_config_file(char *config);
151 static void update();
152 static void switch_light();
153 static void draw_remaining_time(AcpiInfos infos);
154 static void draw_batt(AcpiInfos infos);
155 static void draw_low();
156 static void draw_rate(AcpiInfos infos);
157 static void draw_temp(AcpiInfos infos);
158 static void draw_statusdigit(AcpiInfos infos);
159 static void draw_pcgraph(AcpiInfos infos);
160 static void parse_arguments(int argc, char **argv);
161 static void print_help(char *prog);
162 static void acpi_getinfos(AcpiInfos *infos);
163 static int acpi_exists();
164 static int my_system (char *cmd);
165 static void blink_batt();
166 static void draw_all();
168 static void debug(char *debug_string);
169 #ifdef linux
170 int acpi_read(AcpiInfos *i);
171 int init_stats(AcpiInfos *k);
172 #endif
174 int count;
175 int blink_pos=0;
177 static void debug(char *debug_string){
178 printf("DEBUG: %s\n",debug_string);
181 int main(int argc, char **argv) {
183 XEvent event;
184 XpmColorSymbol colors[2] = { {"Back0", NULL, 0}, {"Back1", NULL, 0} };
185 int ncolor = 0;
186 struct sigaction sa;
187 long counter=0;
188 long timeout;
189 int charging;
190 long togglecounter=0;
191 long animationcounter=0;
193 sa.sa_handler = SIG_IGN;
194 #ifdef SA_NOCLDWAIT
195 sa.sa_flags = SA_NOCLDWAIT;
196 #else
197 sa.sa_flags = 0;
198 #endif
201 printf("wmbatteries %s (c) Florian Krohs\n"
202 "<florian.krohs@informatik.uni-oldenburg.de>\n\n"
203 "This Software comes with absolut no warranty.\n"
204 "Use at your own risk!\n\n",WMBATTERIES_VERSION);
206 sigemptyset(&sa.sa_mask);
207 sigaction(SIGCHLD, &sa, NULL);
209 /* Parse CommandLine */
210 parse_arguments(argc, argv);
212 /* Check for ACPI support */
213 if (!acpi_exists()) {
214 #ifdef linux
215 fprintf(stderr, "No ACPI support in kernel\n");
216 #else
217 fprintf(stderr, "Unable to access ACPI info\n");
218 #endif
219 exit(1);
222 /* Initialize Application */
224 init_stats(&cur_acpi_infos);
225 //acpi_getinfos(&cur_acpi_infos);
226 //update();
227 dockapp_open_window(display_name, PACKAGE, SIZE, SIZE, argc, argv);
228 dockapp_set_eventmask(ButtonPressMask);
230 if (strcmp(light_color,"")) {
231 colors[0].pixel = dockapp_getcolor(light_color);
232 colors[1].pixel = dockapp_blendedcolor(light_color, -24, -24, -24, 1.0);
233 ncolor = 2;
236 /* change raw xpm data to pixmap */
237 if (dockapp_iswindowed)
238 backlight_on_xpm[1] = backlight_off_xpm[1] = WINDOWED_BG;
240 if (!dockapp_xpm2pixmap(backlight_on_xpm, &backdrop_on, &mask, colors, ncolor)) {
241 fprintf(stderr, "Error initializing backlit background image.\n");
242 exit(1);
244 if (!dockapp_xpm2pixmap(backlight_off_xpm, &backdrop_off, NULL, NULL, 0)) {
245 fprintf(stderr, "Error initializing background image.\n");
246 exit(1);
248 if (!dockapp_xpm2pixmap(parts_xpm, &parts, NULL, colors, ncolor)) {
249 fprintf(stderr, "Error initializing parts image.\n");
250 exit(1);
253 /* shape window */
254 if (!dockapp_iswindowed) dockapp_setshape(mask, 0, 0);
255 if (mask) XFreePixmap(display, mask);
257 /* pixmap : draw area */
258 pixmap = dockapp_XCreatePixmap(SIZE, SIZE);
260 /* Initialize pixmap */
261 if (backlight == LIGHTON)
262 dockapp_copyarea(backdrop_on, pixmap, 0, 0, SIZE, SIZE, 0, 0);
263 else
264 dockapp_copyarea(backdrop_off, pixmap, 0, 0, SIZE, SIZE, 0, 0);
266 dockapp_set_background(pixmap);
267 update();
268 dockapp_show();
269 long update_timeout = update_interval*1000;
270 long animation_timeout = animationspeed;
271 long toggle_timeout = togglespeed*1000;
272 int show = 0;
273 /* Main loop */
274 while (1) {
275 if (cur_acpi_infos.battery_status[0]==CHARGING || cur_acpi_infos.battery_status[1]==CHARGING)
276 charging = 1;
277 else
278 charging = 0;
279 timeout = update_timeout;
280 if( charging && animation_timeout<update_timeout){
281 if(animation_timeout<toggle_timeout)
282 timeout = animation_timeout;
283 else if(togglemode) timeout = toggle_timeout;
284 } else if(update_timeout<toggle_timeout)
285 timeout = update_timeout;
286 else if(togglemode) timeout = toggle_timeout;
287 if (dockapp_nextevent_or_timeout(&event, timeout)) {
288 /* Next Event */
289 switch (event.type) {
290 case ButtonPress:
291 switch (event.xbutton.button) {
292 case 1: switch_light(); break;
293 case 3: mode=!mode; draw_all();dockapp_copy2window(pixmap);break;
294 default: break;
296 break;
297 default: break;
299 } else {
300 /* Time Out */
301 update_timeout -= timeout;
302 animation_timeout -= timeout;
303 toggle_timeout -= timeout;
304 if(toggle_timeout<=0){
305 toggle_timeout = togglespeed*1000;
306 if(togglemode){
307 mode=!mode;
308 show = 1;
311 if(animation_timeout<=0){
312 animation_timeout = animationspeed;
313 if(charging){
314 blink_batt();
315 show = 1;
318 if(update_timeout<=0){
319 update();
320 show = 1;
321 update_timeout = update_interval*1000;
323 if(show) {
324 /* show */
325 draw_all();
326 if(charging) {
327 blink_pos--;
328 blink_batt();
330 dockapp_copy2window(pixmap);
331 show = 0;
336 return 0;
340 int init_stats(AcpiInfos *k) {
341 int bat_status[2]={NONE,NONE};
342 FILE *fd;
343 char *buf;
344 char *ptr;
345 char present;
346 int bat;
347 int hist;
348 int i;
350 buf=(char *)malloc(sizeof(char)*512);
351 if(buf == NULL)
352 exit(-1);
353 /* get info about existing batteries */
354 number_of_batteries=0;
355 for(i=0;i<2;i++){
356 if((fd = fopen(state_files[i], "r"))){
357 fread(buf,512,1,fd);
358 fclose(fd);
359 if(ptr = strstr(buf,"present:")) {
360 present=*(ptr+25);
361 if(present == 'y'){
362 bat_status[i]|=STATE_OK;
365 if(ptr = strstr(buf,"present rate:")) {
366 present=*(ptr+25);
367 sscanf(ptr,"%d",&k->rate[bat]);
370 if((fd = fopen(info_files[i], "r"))){
371 fread(buf,512,1,fd);
372 fclose(fd);
373 if(ptr = strstr(buf,"present:")) {
374 present=*(ptr+25);
375 if(present == 'y'){
376 bat_status[i]|=INFO_OK;
379 if(ptr = strstr(buf,"last full capacity:")) {
380 present=*(ptr+25);
381 sscanf(ptr,"%d",&k->currcap[bat]);
387 if(bat_status[0]==BAT_OK && bat_status[1]==BAT_OK){
388 printf("BAT0 and BAT1 ok\n");
389 number_of_batteries=2;
390 } else if(bat_status[0]==BAT_OK) {
391 printf("BAT0 ok\n");
392 number_of_batteries=1;
393 } else if(bat_status[1]==BAT_OK) {
394 printf("BAT1 ok\n");
395 number_of_batteries=1;
396 strcpy(state_files[0],state_files[1]);
397 strcpy(info_files[0],info_files[1]);
398 k->currcap[0] = k->currcap[1];
399 k->rate[0] = k->rate[1];
402 printf("%i batter%s found in system\n",number_of_batteries,number_of_batteries==1 ? "y" : "ies");
404 // initialize buffer
405 if ((rateElements = (RateListElem *) malloc(history_size * sizeof(RateListElem))) == NULL)
406 exit(-1);
408 firstRateElem = rateElements;
411 /* get info about full battery charge */
413 for(bat=0;bat<number_of_batteries;bat++){
414 if ((fd = fopen(info_files[bat], "r"))) {
415 fread(buf,512,1,fd);
416 fclose(fd);
417 if(ptr = strstr(buf,"last full capacity:")) {
418 ptr += 25;
419 sscanf(ptr,"%d",&k->currcap[bat]);
422 if ((fd = fopen(state_files[bat], "r"))) {
423 fread(buf,512,1,fd);
424 fclose(fd);
425 if(ptr = strstr(buf,"present rate:")) {
426 ptr += 25;
427 sscanf(ptr,"%d",&k->rate[bat]);
432 for(i=0;i<2;i++){
433 /* link rateElements */
434 for(hist=0;hist<(history_size-1);hist++){
435 (*(rateElements+hist)).next = rateElements+hist+1;
436 (*(rateElements+hist)).rate[i] = k->rate[i];
438 (*(rateElements+history_size-1)).next = rateElements;
439 (*(rateElements+history_size-1)).rate[i] = k->rate[i];
441 free(buf);
442 k->ac_line_status = 0;
443 k->battery_status[0] = 0;
444 k->battery_percentage[0] = 0;
445 k->remain[0] = 0;
446 k->battery_status[1] = 0;
447 k->battery_percentage[1] = 0;
448 k->remain[1] = 0;
449 k->thermal_temp = 0;
450 k->thermal_state = 0;
451 DEBUGSTRING("end of init_stats()");
454 /* called by timer */
455 static void update() {
456 static light pre_backlight;
457 static Bool in_alarm_mode = False;
459 /* get current battery usage in percent */
460 acpi_getinfos(&cur_acpi_infos);
462 /* alarm mode */
463 if (cur_acpi_infos.low || (cur_acpi_infos.thermal_temp > alarm_level_temp)) {
464 if (!in_alarm_mode) {
465 in_alarm_mode = True;
466 pre_backlight = backlight;
467 my_system(notif_cmd);
469 if ( (switch_authorized) ||
470 ( (! switch_authorized) && (backlight != pre_backlight) ) ) {
471 switch_light();
472 return;
475 else {
476 if (in_alarm_mode) {
477 in_alarm_mode = False;
478 if (backlight != pre_backlight) {
479 switch_light();
480 return;
484 draw_all();
487 static void parse_config_file(char *config){
489 FILE *fd=NULL;
490 char *buf;
491 char stringbuffer[256];
492 char *ptr;
493 char line[256] ;
494 char *item;
495 char *value;
496 extern int errno;
497 int linenr=0;
498 int tmp;
499 char *test;
500 buf=(char *)malloc(sizeof(char)*512);
501 if(buf == NULL)
502 exit(-1);
503 if(config != NULL) { //config file by command line
504 DEBUGSTRING("using command line given config file name");
505 DEBUGSTRING(config);
506 if((fd = fopen(config, "r"))){
507 DEBUGSTRING("config file found\n");
508 } else {
509 DEBUGSTRING("config file NOT found\n");
510 DEBUGSTRING("falling back to default config file\n");
513 if(fd==NULL) { // no config file found yet
514 strcpy(stringbuffer,getenv("HOME"));
515 strcat(stringbuffer,"/.wmbatteriesrc");
516 DEBUGSTRING("trying config file in your $HOME dir\n");
517 DEBUGSTRING(stringbuffer);
518 if((fd = fopen(stringbuffer, "r"))){
519 DEBUGSTRING("config file found\n");
520 } else {
521 DEBUGSTRING("config file in $HOME dir nonexistant\n");
522 DEBUGSTRING("trying global one in /etc\n");
523 if((fd = fopen("/etc/wmbatteries", "r"))){
524 DEBUGSTRING("config file found\n");
526 else {
527 DEBUGSTRING("no config file found. ignoring\n");
532 if(fd!=NULL){ // some config file was found, try parsing
533 DEBUGSTRING("begin parsing\n");
534 while( fgets( line, 255, fd ) != NULL )
537 item = strtok( line, "\t =\n\r" ) ;
538 if( item != NULL && item[0] != '#' )
540 value = strtok( NULL, "\t =\n\r" ) ;
541 if(!strcmp(item,"backlight")){
542 if(strcasecmp(value,"yes") && strcasecmp(value,"true") && strcasecmp(value,"false") && strcasecmp(value,"no")) {
543 printf("backlight option wrong in line %i,use yes/no or true/false\n",linenr);
544 } else {
545 if(!strcasecmp(value,"true") || !strcasecmp(value,"yes")){
546 backlight = LIGHTON;
547 } else {
548 backlight = LIGHTOFF;
553 if(!strcmp(item,"lightcolor")){
554 strcpy(light_color,value);
557 if(!strcmp(item,"temperature")){
558 strcpy(thermal,value);
561 if(!strcmp(item,"bat0_state")){
562 strcpy(state_files[0],value);
565 if(!strcmp(item,"bat1_state")){
566 strcpy(state_files[1],value);
569 if(!strcmp(item,"bat0_info")){
570 strcpy(info_files[0],value);
573 if(!strcmp(item,"bat1_info")){
574 strcpy(info_files[1],value);
577 if(!strcmp(item,"ac_state")){
578 strcpy(ac_state,value);
582 if(!strcmp(item,"updateinterval")){
583 tmp=atoi(value);
584 if(tmp<1) {
585 printf("update interval is out of range in line %i,must be > 0\n",linenr);
586 } else {
587 update_interval=tmp;
591 if(!strcmp(item,"alarm")){
592 tmp=atoi(value);
593 if(tmp<1 || tmp>100) {
594 printf("alarm is out of range in line %i,must be > 0 and <= 100\n",linenr);
595 } else {
596 alarm_level=tmp;
600 if(!strcmp(item,"togglespeed")){
601 tmp=atoi(value);
602 if(tmp<1) {
603 printf("togglespeed variable is out of range in line %i,must be > 0\n",linenr);
604 } else {
605 togglespeed=tmp;
609 if(!strcmp(item,"animationspeed")){
610 tmp=atoi(value);
611 if(tmp<100) {
612 printf("animationspeed variable is out of range in line %i,must be >= 100\n",linenr);
613 } else {
614 animationspeed=tmp;
618 if(!strcmp(item,"historysize")){
619 tmp=atoi(value);
620 if(tmp<1 || tmp>1000) {
621 printf("historysize variable is out of range in line %i,must be >=1 and <=1000\n",linenr);
622 } else {
623 history_size=tmp;
627 if(!strcmp(item,"mode")){
628 if(strcmp(value,"rate") && strcmp(value,"toggle") && strcmp(value,"toggle")) {
629 printf("mode must be one of rate,temp,toggle in line %i\n",linenr);
630 } else {
631 if(strcmp(value,"rate")) mode=RATE;
632 if(strcmp(value,"temp")) mode=TEMP;
633 if(strcmp(value,"toggle")) togglemode=1;
640 linenr++;
642 fclose(fd);
643 DEBUGSTRING("end parsing\n");
648 static void draw_all(){
649 int bat;
650 long allremain=0;
651 long allcapacity=0;
652 /* all clear */
653 if (backlight == LIGHTON)
654 dockapp_copyarea(backdrop_on, pixmap, 0, 0, 58, 58, 0, 0);
655 else
656 dockapp_copyarea(backdrop_off, pixmap, 0, 0, 58, 58, 0, 0);
657 /* draw digit */
658 draw_remaining_time(cur_acpi_infos);
659 if(mode==RATE) draw_rate(cur_acpi_infos);
660 else if(mode==TEMP) draw_temp(cur_acpi_infos);
661 draw_statusdigit(cur_acpi_infos);
662 draw_pcgraph(cur_acpi_infos);
664 if(cur_acpi_infos.low) draw_low();
666 draw_batt(cur_acpi_infos);
670 /* called when mouse button pressed */
672 static void switch_light() {
673 switch (backlight) {
674 case LIGHTOFF:
675 backlight = LIGHTON;
676 dockapp_copyarea(backdrop_on, pixmap, 0, 0, 58, 58, 0, 0);
677 break;
678 case LIGHTON:
679 backlight = LIGHTOFF;
680 dockapp_copyarea(backdrop_off, pixmap, 0, 0, 58, 58, 0, 0);
681 break;
684 draw_remaining_time(cur_acpi_infos);
685 if(mode==RATE) draw_rate(cur_acpi_infos);
686 else if(mode==TEMP) draw_temp(cur_acpi_infos);
687 draw_statusdigit(cur_acpi_infos);
688 draw_pcgraph(cur_acpi_infos);
689 if(cur_acpi_infos.battery_status[0]==CHARGING || cur_acpi_infos.battery_status[1]==CHARGING){
690 blink_batt();
691 } else draw_batt(cur_acpi_infos);
692 if(cur_acpi_infos.low){
693 draw_low();
695 /* show */
696 dockapp_copy2window(pixmap);
699 static void draw_batt(AcpiInfos infos){
700 int y = 0;
701 int i=0;
702 if (backlight == LIGHTON) y = 28;
703 for(i=0;i<number_of_batteries;i++){
704 if(infos.battery_status[i]==DISCHARGING){
705 dockapp_copyarea(parts, pixmap,33+y , 63, 9, 5, 16+i*11, 39);
710 static void draw_remaining_time(AcpiInfos infos) {
711 int y = 0;
712 if (backlight == LIGHTON) y = 20;
713 if (infos.ac_line_status == 1 && !(cur_acpi_infos.battery_status[0]==CHARGING || cur_acpi_infos.battery_status[1]==CHARGING)){
714 dockapp_copyarea(parts, pixmap, 0, 68+68+y, 10, 20, 17, 5);
715 dockapp_copyarea(parts, pixmap, 10, 68+68+y, 10, 20, 32, 5);
716 } else {
718 dockapp_copyarea(parts, pixmap, (infos.hours_left / 10) * 10, 68+y, 10, 20, 5, 5);
719 dockapp_copyarea(parts, pixmap, (infos.hours_left % 10) * 10, 68+y, 10, 20, 17, 5);
720 dockapp_copyarea(parts, pixmap, (infos.minutes_left / 10) * 10, 68+y, 10, 20, 32, 5);
721 dockapp_copyarea(parts, pixmap, (infos.minutes_left % 10) * 10, 68+y, 10, 20, 44, 5);
726 static void draw_low() {
727 int y = 0;
728 if (backlight == LIGHTON) y = 28;
729 dockapp_copyarea(parts, pixmap,42+y , 58, 17, 7, 38, 38);
733 static void draw_temp(AcpiInfos infos) {
734 int temp = infos.thermal_temp;
735 int light_offset=0;
736 if (backlight == LIGHTON) {
737 light_offset=50;
740 if (temp < 0 || temp>99) temp = 0;
741 dockapp_copyarea(parts, pixmap, (temp/10)*5 + light_offset, 40, 5, 9, 23, 46);
742 dockapp_copyarea(parts, pixmap, (temp%10)*5 + light_offset, 40, 5, 9, 29, 46);
744 dockapp_copyarea(parts, pixmap, 10 + light_offset, 49, 5, 9, 36, 46); //o
745 dockapp_copyarea(parts, pixmap, 15 + light_offset, 49, 5, 9, 42, 46); //C
749 static void blink_batt(){
750 int light_offset=0;
751 int bat=0;
752 if (backlight == LIGHTON) {
753 light_offset=50;
755 blink_pos=(blink_pos+1)%5;
756 for(bat=0;bat<number_of_batteries;bat++){
757 if(cur_acpi_infos.battery_status[bat]==CHARGING){
758 dockapp_copyarea(parts, pixmap, blink_pos*9+light_offset , 117, 9, 5, 16+bat*11, 39);
764 static void draw_statusdigit(AcpiInfos infos) {
765 int light_offset=0;
766 if (backlight == LIGHTON) {
767 light_offset=28;
769 if (infos.ac_line_status == 1){
770 dockapp_copyarea(parts, pixmap,33+light_offset , 58, 9, 5, 5, 39);
774 static void draw_rate(AcpiInfos infos) {
775 int light_offset=0;
776 long rate = infos.rate[0]+infos.rate[1];
777 if (backlight == LIGHTON) {
778 light_offset=50;
781 dockapp_copyarea(parts, pixmap, (rate/10000)*5 + light_offset, 40, 5, 9, 5, 46);
782 dockapp_copyarea(parts, pixmap, ((rate/1000)%10)*5 + light_offset, 40, 5, 9, 11, 46);
783 dockapp_copyarea(parts, pixmap, ((rate/100)%10)*5 + light_offset, 40, 5, 9, 17, 46);
784 dockapp_copyarea(parts, pixmap, ((rate/10)%10)*5 + light_offset, 40, 5, 9, 23, 46);
785 dockapp_copyarea(parts, pixmap, (rate%10)*5 + light_offset, 40, 5, 9, 29, 46);
787 dockapp_copyarea(parts, pixmap, 0 + light_offset, 49, 5, 9, 36, 46); //m
788 dockapp_copyarea(parts, pixmap, 5 + light_offset, 49, 5, 9, 42, 46); //W
792 static void draw_pcgraph(AcpiInfos infos) {
793 int num[2];
794 int bat;
795 int width;
796 int light_offset=0;
797 if (backlight == LIGHTON) {
798 light_offset=5;
800 for(bat=0;bat<number_of_batteries;bat++){
801 width = (infos.battery_percentage[bat]*32)/100;
802 dockapp_copyarea(parts, pixmap, 0, 58+light_offset, width, 5, 5, 26+6*bat);
803 if(infos.battery_percentage[bat] == 100){ // don't display leading 0
804 dockapp_copyarea(parts, pixmap, 4*(infos.battery_percentage[bat]/100), 126+light_offset, 3, 5, 38, 26+6*bat);
806 if(infos.battery_percentage[bat] > 9){ //don't display leading 0
807 dockapp_copyarea(parts, pixmap, 4*((infos.battery_percentage[bat]%100)/10), 126+light_offset, 3, 5, 42, 26+6*bat);
809 dockapp_copyarea(parts, pixmap, 4*(infos.battery_percentage[bat]%10), 126+light_offset, 3, 5, 46, 26+6*bat);
815 static void parse_arguments(int argc, char **argv) {
816 int i;
817 int integer;
818 char character;
820 for (i = 1; i < argc; i++) { // first search for config file option
821 if (!strcmp(argv[i], "--config") || !strcmp(argv[i], "-c")) {
822 config_file = argv[i + 1];
823 i++;
826 // parse config file before other command line options, to allow overriding
827 parse_config_file(config_file);
828 for (i = 1; i < argc; i++) {
829 if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
830 print_help(argv[0]), exit(0);
831 } else if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "-v")) {
832 printf("%s version %s\n", PACKAGE, VERSION), exit(0);
833 } else if (!strcmp(argv[i], "--display") || !strcmp(argv[i], "-d")) {
834 display_name = argv[i + 1];
835 i++;
836 } else if (!strcmp(argv[i], "--backlight") || !strcmp(argv[i], "-bl")) {
837 backlight = LIGHTON;
838 } else if (!strcmp(argv[i], "--light-color") || !strcmp(argv[i], "-lc")) {
839 strcpy(light_color,argv[i + 1]);
840 i++;
841 } else if (!strcmp(argv[i], "--config") || !strcmp(argv[i], "-c")) {
842 config_file = argv[i + 1];
843 i++;
844 } else if (!strcmp(argv[i], "--interval") || !strcmp(argv[i], "-i")) {
845 if (argc == i + 1)
846 fprintf(stderr, "%s: error parsing argument for option %s\n",
847 argv[0], argv[i]), exit(1);
848 if (sscanf(argv[i + 1], "%i", &integer) != 1)
849 fprintf(stderr, "%s: error parsing argument for option %s\n",
850 argv[0], argv[i]), exit(1);
851 if (integer < 1)
852 fprintf(stderr, "%s: argument %s must be >=1\n",
853 argv[0], argv[i]), exit(1);
854 update_interval = integer;
855 i++;
856 } else if (!strcmp(argv[i], "--alarm") || !strcmp(argv[i], "-a")) {
857 if (argc == i + 1)
858 fprintf(stderr, "%s: error parsing argument for option %s\n",
859 argv[0], argv[i]), exit(1);
860 if (sscanf(argv[i + 1], "%i", &integer) != 1)
861 fprintf(stderr, "%s: error parsing argument for option %s\n",
862 argv[0], argv[i]), exit(1);
863 if ( (integer < 0) || (integer > 100) )
864 fprintf(stderr, "%s: argument %s must be >=0 and <=100\n",
865 argv[0], argv[i]), exit(1);
866 alarm_level = integer;
867 i++;
868 } else if (!strcmp(argv[i], "--windowed") || !strcmp(argv[i], "-w")) {
869 dockapp_iswindowed = True;
870 } else if (!strcmp(argv[i], "--broken-wm") || !strcmp(argv[i], "-bw")) {
871 dockapp_isbrokenwm = True;
872 } else if (!strcmp(argv[i], "--notify") || !strcmp(argv[i], "-n")) {
873 notif_cmd = argv[i + 1];
874 i++;
875 } else if (!strcmp(argv[i], "--suspend") || !strcmp(argv[i], "-s")) {
876 suspend_cmd = argv[i + 1];
877 i++;
878 } else if (!strcmp(argv[i], "--togglespeed") || !strcmp(argv[i], "-ts")) {
879 if (argc == i + 1)
880 fprintf(stderr, "%s: error parsing argument for option %s\n",
881 argv[0], argv[i]), exit(1);
882 if (sscanf(argv[i + 1], "%i", &integer) != 1)
883 fprintf(stderr, "%s: error parsing argument for option %s\n",
884 argv[0], argv[i]), exit(1);
885 if ( integer < 1)
886 fprintf(stderr, "%s: argument %s must be positive integer\n",
887 argv[0], argv[i],update_interval), exit(1);
888 togglespeed=integer;
889 i++;
890 } else if (!strcmp(argv[i], "--animationspeed") || !strcmp(argv[i], "-as")) {
891 if (argc == i + 1)
892 fprintf(stderr, "%s: error parsing argument for option %s\n",
893 argv[0], argv[i]), exit(1);
894 if (sscanf(argv[i + 1], "%i", &integer) != 1)
895 fprintf(stderr, "%s: error parsing argument for option %s\n",
896 argv[0], argv[i]), exit(1);
897 if (integer < 100)
898 fprintf(stderr, "%s: argument %s must be >=100\n",
899 argv[0], argv[i]), exit(1);
900 animationspeed=integer;
901 i++;
902 } else if (!strcmp(argv[i], "--historysize") || !strcmp(argv[i], "-hs")) {
903 if (argc == i + 1)
904 fprintf(stderr, "%s: error parsing argument for option %s\n",
905 argv[0], argv[i]), exit(1);
906 if (sscanf(argv[i + 1], "%i", &integer) != 1)
907 fprintf(stderr, "%s: error parsing argument for option %s\n",
908 argv[0], argv[i]), exit(1);
909 if (integer < 1 || integer > 1000)
910 fprintf(stderr, "%s: argument %s must be >=1 && <=1000\n",
911 argv[0], argv[i]), exit(1);
912 history_size=integer;
913 i++;
914 } else if (!strcmp(argv[i], "--mode") || !strcmp(argv[i], "-m")) {
915 if (argc == i + 1)
916 fprintf(stderr, "%s: error parsing argument for option %s\n",
917 argv[0], argv[i]), exit(1);
918 if (sscanf(argv[i + 1], "%c", &character) != 1)
919 fprintf(stderr, "%s: error parsing argument for option %s\n",
920 argv[0], argv[i]), exit(1);
921 if (!(character=='t' || character=='r' || character=='s'))
922 fprintf(stderr, "%s: argument %s must be t,r or s\n",
923 argv[0], argv[i]), exit(1);
924 if(character=='s') togglemode=1;
925 else if(character=='t') mode=TEMP;
926 else if(character=='r') mode=RATE;
927 i++;
928 } else if (!strcmp(argv[i], "--standby") || !strcmp(argv[i], "-S")) {
929 standby_cmd = argv[i + 1];
930 i++;
931 } else {
932 fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[i]);
933 print_help(argv[0]), exit(1);
939 static void print_help(char *prog)
941 printf("Usage : %s [OPTIONS]\n"
942 "%s - Window Maker mails monitor dockapp\n"
943 " -d, --display <string> display to use\n"
944 " -bl, --backlight turn on back-light\n"
945 " -lc, --light-color <string> back-light color(rgb:6E/C6/3B is default)\n"
946 " -c, --config <string> set filename of config file\n"
947 " -i, --interval <number> number of secs between updates (1 is default)\n"
948 " -a, --alarm <number> low battery level when to raise alarm\n"
949 " (20 is default)\n"
950 " -h, --help show this help text and exit\n"
951 " -v, --version show program version and exit\n"
952 " -w, --windowed run the application in windowed mode\n"
953 " -bw, --broken-wm activate broken window manager fix\n"
954 " -n, --notify <string> command to launch when alarm is on\n"
955 " -s, --suspend <string> set command for acpi suspend\n"
956 " -S, --standby <string> set command for acpi standby\n"
957 " -m, --mode [t|r|s] set mode for the lower row , \n"
958 " t=temperature,r=current rate,s=toggle\n"
959 " -ts --togglespeed <int> set toggle speed in seconds\n"
960 " -as --animationspeed <int> set speed for charging animation in msec\n"
961 " -hs --historysize <int> set size of history for calculating\n"
962 " average power consumption rate\n",
963 prog, prog);
964 /* OPTIONS SUPP :
965 * ? -f, --file : configuration file
970 static void acpi_getinfos(AcpiInfos *infos) {
971 DEBUGSTRING("acpi_getinfos\n")
972 if (
973 #if defined(linux) || defined(solaris)
974 (acpi_read(infos))
975 #else
976 # ifdef freebsd
977 (acpi_read(&temp_info))
978 # endif
979 #endif
981 fprintf(stderr, "Cannot read ACPI information: %i\n");
982 exit(1);
987 int acpi_exists() {
988 if (access(ACPIDEV, R_OK))
989 return 0;
990 else
991 return 1;
995 static int my_system (char *cmd) {
996 int pid;
997 extern char **environ;
999 if (cmd == 0) return 1;
1000 pid = fork ();
1001 if (pid == -1) return -1;
1002 if (pid == 0) {
1003 pid = fork ();
1004 if (pid == 0) {
1005 char *argv[4];
1006 argv[0] = "sh";
1007 argv[1] = "-c";
1008 argv[2] = cmd;
1009 argv[3] = 0;
1010 execve ("/bin/sh", argv, environ);
1011 exit (0);
1013 exit (0);
1015 return 0;
1019 #ifdef linux
1021 int acpi_read(AcpiInfos *i) {
1022 FILE *fd;
1023 int retcode = 0;
1024 int capacity[2],remain[2];
1025 int bat;
1026 char *buf;
1027 char *ptr;
1028 char stat;
1029 buf=(char *)malloc(sizeof(char)*512);
1030 RateListElem currRateElement;
1031 int hist;
1032 long rate;
1033 float time;
1034 long allcapacity=0;
1035 long allremain=0;
1037 rate = 0;
1040 DEBUGSTRING("acpi_read()\n")
1042 /* get acpi thermal cpu info */
1043 if ((fd = fopen(thermal, "r"))) {
1044 fscanf(fd, "temperature: %d", &i->thermal_temp);
1045 fclose(fd);
1047 if ((fd = fopen(ac_state, "r"))) {
1048 bzero(buf, 512);
1049 fscanf(fd, "state: %s", buf);
1050 fclose(fd);
1051 if(strstr(buf, "on-line") != NULL) i->ac_line_status=1;
1052 if(strstr(buf, "off-line") != NULL) i->ac_line_status=0;
1054 for(bat=0;bat<number_of_batteries;bat++){
1056 if ((fd = fopen(state_files[bat], "r"))) {
1057 bzero(buf, 512);
1058 fread(buf,512,1,fd);
1059 fclose(fd);
1060 if(( ptr = strstr(buf,"charging state:"))) {
1061 stat = *(ptr + 25);
1062 switch (stat)
1064 case 'd':
1065 i->battery_status[bat]=1;
1066 break;
1067 case 'c':
1068 i->battery_status[bat]=3;
1069 break;
1070 case 'u':
1071 i->battery_status[bat]=0;
1072 break;
1075 if ((ptr = strstr (buf, "remaining capacity:"))) {
1076 ptr += 25;
1077 sscanf(ptr,"%d",&i->remain[bat]);
1079 if ((ptr = strstr (buf, "present rate:"))) {
1080 ptr += 25;
1081 sscanf(ptr,"%d",&((*firstRateElem).rate[bat]));
1085 i->battery_percentage[bat] = (((float)(i->remain[bat])*100)/cur_acpi_infos.currcap[bat]);
1089 currRateElement = *firstRateElem;
1090 if(currRateElement.rate[bat]!=0){
1091 for(hist=0;hist<history_size;hist++){
1092 if(currRateElement.rate[bat]!=0){
1093 rate += currRateElement.rate[bat];
1094 } else rate+= (*firstRateElem).rate[bat];
1095 currRateElement = *currRateElement.next;
1097 } else {
1098 rate=0;
1099 i->rate[bat]=0;
1104 /* calc average */
1105 rate = rate / history_size;
1106 i->rate[bat] = rate;
1109 if((i->battery_status[0]==1 || i->battery_status[1]==1) && (i->rate[0]+i->rate[1])>0){
1110 time = (float)(i->remain[0]+i->remain[1])/(float)(i->rate[0]+i->rate[1]);
1111 i->hours_left=(int)time;
1112 i->minutes_left=(int)((time-(int)time)*60);
1114 if(i->battery_status[0]==0 && i->battery_status[1]==0){
1115 i->hours_left=0;
1116 i->minutes_left=0;
1118 if((i->battery_status[0]==3||i->battery_status[1]==3) && (i->rate[0]>0 || i->rate[1]>0)){
1119 time = (float)(cur_acpi_infos.currcap[0] - i->remain[0] + cur_acpi_infos.currcap[1] - i->remain[1])/(float)(i->rate[0]+i->rate[1]);
1120 i->hours_left=(int)time;
1121 i->minutes_left=(int)(60*(time-(int)time));
1123 for(bat=0;bat<number_of_batteries;bat++){
1124 allremain += i->remain[bat];
1125 allcapacity += cur_acpi_infos.currcap[bat];
1128 cur_acpi_infos.low=0;
1129 if(allcapacity>0){
1130 if(((double)allremain/(double)allcapacity)*100<alarm_level){
1131 cur_acpi_infos.low=1;
1135 DEBUGSTRING("MID acpi_read()\n")
1136 firstRateElem = ((*firstRateElem).next);
1137 free(buf);
1138 DEBUGSTRING("END acpi_read()\n")
1139 return retcode;
1141 #endif