10 #include <sys/types.h>
17 # include <sys/ioctl.h>
18 # include <sys/sysctl.h>
20 # include <machine/apm_bios.h>
25 # include <CFNumber.h>
27 # include <CFDictionary.h>
28 # include <CFRunLoop.h>
29 # include <ps/IOPSKeys.h>
30 # include <ps/IOPowerSources.h>
34 #include <Ecore_File.h>
35 #include <Ecore_Con.h>
37 /* define MAX for all OS, instead of plenty #include */
39 # define MAX(a, b) ((a) < (b) ? (b) : (a))
42 /* supported batery system schemes - irrespective of OS */
47 #define CHECK_SYS_CLASS_POWER_SUPPLY 4
49 static void init(void);
50 static Eina_Bool poll_cb(void *data);
52 static int poll_interval = 512;
53 static Ecore_Poller *poller = NULL;
55 static int mode = CHECK_NONE;
57 static int time_left = -2;
58 static int battery_full = -2;
59 static int have_battery = -2;
60 static int have_power = -2;
64 int_file_get(const char *file)
67 FILE *f = fopen(file, "r");
71 char *str = fgets(buf, sizeof(buf), f);
72 if (str) val = atoi(str);
79 str_file_get(const char *file)
82 FILE *f = fopen(file, "r");
86 char *str = fgets(buf, sizeof(buf), f);
89 size_t len = strlen(str);
90 if ((len > 0) && (str[len - 1] == '\n'))
95 val = malloc(len + 1);
96 if (val) memcpy(val, str, len + 1);
104 int_get(const char *buf)
106 const char *p = strchr(buf, ':');
109 while (*p == ' ') p++;
114 str_get(const char *buf)
116 const char *p = strchr(buf, ':');
122 while (*p == ' ') p++;
124 q = p + strlen(p) - 1;
125 while ((q > p) && ((*q == ' ') || (*q == '\n'))) q--;
127 if (q < p) return NULL;
129 ret = malloc(q - p + 1);
130 if (!ret) return NULL;
131 memcpy(ret, p, q - p);
137 file_str_entry_get(FILE *f,
143 tmp = fgets(buf, sizeof(buf), f);
146 EINA_LOG_ERR("unexpected end of file, expected: '%s'", entry);
149 if (strcmp(tmp, entry) != 0)
151 EINA_LOG_ERR("unexpected file entry, expected: '%s'", entry);
157 EINA_LOG_ERR("unexpected file entry, missing value for '%s'", entry);
165 #define BATTERY_STATE_NONE 0
166 #define BATTERY_STATE_DISCHARGING 1
167 #define BATTERY_STATE_CHARGING 2
168 #define BATTERY_STATE_REMOVED 7
197 /* Read some information on first run. */
199 sysctlnametomib("hw.acpi.battery.state", mib_state, &len);
201 if (sysctl(mib_state, 4, &state, &len, NULL, 0) == -1)
206 sysctlnametomib("hw.acpi.battery.life", mib_life, &len);
208 if (sysctl(mib_life, 4, &life, &len, NULL, 0) == -1)
214 sysctlnametomib("hw.acpi.battery.time", mib_time, &len);
216 if (sysctl(mib_time, 4, &time_min, &len, NULL, 0) == -1)
221 sysctlnametomib("hw.acpi.battery.units", mib_units, &len);
222 len = sizeof(batteries);
223 if (sysctl(mib_time, 4, &batteries, &len, NULL, 0) == -1)
227 if (time_min >= 0) time_left = time_min * 60;
229 if (batteries == 1) /* hw.acpi.battery.units = 1 means NO BATTS */
231 else if ((state == BATTERY_STATE_CHARGING) ||
232 (state == BATTERY_STATE_DISCHARGING))
235 if (state == BATTERY_STATE_CHARGING) have_power = 1;
236 else if (state == BATTERY_STATE_DISCHARGING)
238 if (level == -1) time_left = -1;
239 else if (time_min == -1)
242 battery_full = bat_val;
244 else battery_full = bat_val;
266 int ac_stat, bat_stat, bat_val, time_val;
270 struct apm_info info;
277 apm_fd = open("/dev/apm", O_RDONLY);
278 if ((apm_fd != -1) && (ioctl(apm_fd, APMIO_GETINFO, &info) != -1))
281 ac_stat = info.ai_acline;
282 bat_stat = info.ai_batt_stat;
283 bat_val = info.ai_batt_life;
284 time_val = info.ai_batt_time;
288 if (info.ai_batteries == 1) /* ai_batteries == 1 means NO battery,
289 * ai_batteries == 2 means 1 battery */
295 if (ac_stat) /* Wallpowered */
299 switch (bat_stat) /* On FreeBSD the time_val is -1 when AC ist plugged
300 * in. This means we don't know how long the battery
320 else /* Running on battery */
323 battery_full = bat_val;
324 time_left = time_val;
330 #elif defined(HAVE_CFBASE_H) /* OS X */
332 static void darwin_init(void);
333 static void darwin_check(void);
345 int device_num, device_count;
346 int currentval = 0, maxval = 0;
350 CFDictionaryRef device_dict;
357 /* Retrieve the power source data and the array of sources. */
358 blob = IOPSCopyPowerSourcesInfo();
359 sources = IOPSCopyPowerSourcesList(blob);
360 device_count = CFArrayGetCount(sources);
361 for (device_num = 0; device_num < device_count; device_num++)
365 /* Retrieve a dictionary of values for this device and the count of keys in the dictionary. */
366 ps = CFArrayGetValueAtIndex(sources, device_num);
367 device_dict = IOPSGetPowerSourceDescription(blob, ps);
368 /* Retrieve the charging key and save the present charging value if one exists. */
369 if (CFDictionaryGetValueIfPresent(device_dict,
370 CFSTR(kIOPSIsChargingKey), &values))
373 if (CFBooleanGetValue(values) > 0) have_power = 1;
386 /* Retrieve the current capacity key. */
387 values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSCurrentCapacityKey));
388 CFNumberGetValue(values, kCFNumberSInt32Type, ¤tval);
389 /* Retrieve the max capacity key. */
390 values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSMaxCapacityKey));
391 CFNumberGetValue(values, kCFNumberSInt32Type, &maxval);
392 /* Calculate the percentage charged. */
393 battery_full = (currentval * 100) / maxval;
395 /* Retrieve the remaining battery power or time until charged in minutes. */
398 values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSTimeToEmptyKey));
399 CFNumberGetValue(values, kCFNumberSInt32Type, ¤tval);
400 time_left = currentval * 60;
404 values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSTimeToFullChargeKey));
405 CFNumberGetValue(values, kCFNumberSInt32Type, ¤tval);
406 time_left = currentval * 60;
415 /* new linux power class api to get power info - brand new and this code
416 * may have bugs, but it is a good attempt to get it right */
418 static Eina_Bool linux_sys_class_power_supply_cb_event_fd_active(void *data,
419 Ecore_Fd_Handler *fd_handler);
420 static void linux_sys_class_power_supply_check(void);
422 static void linux_sys_class_power_supply_init(void);
424 typedef struct _Sys_Class_Power_Supply_Uevent Sys_Class_Power_Supply_Uevent;
426 #define BASIS_CHARGE 1
427 #define BASIS_ENERGY 2
428 #define BASIS_VOLTAGE 3
430 struct _Sys_Class_Power_Supply_Uevent
434 Ecore_Fd_Handler *fd_handler;
442 unsigned char have_current_avg : 1;
443 unsigned char have_current_now : 1;
446 static Eina_List *events = NULL;
449 static Ecore_Timer *sys_class_delay_check = NULL;
452 linux_sys_class_power_supply_cb_delay_check(void *data)
454 linux_sys_class_power_supply_init();
456 sys_class_delay_check = NULL;
457 return ECORE_CALLBACK_CANCEL;
460 static Ecore_Timer *re_init_timer = NULL;
463 linux_sys_class_power_supply_cb_re_init(void *data)
465 Sys_Class_Power_Supply_Uevent *sysev;
469 EINA_LIST_FREE(events, sysev)
471 // if (sysev->fd_handler)
472 // ecore_main_fd_handler_del(sysev->fd_handler);
473 // if (sysev->fd >= 0) close(sysev->fd);
478 linux_sys_class_power_supply_init();
479 re_init_timer = NULL;
480 return ECORE_CALLBACK_CANCEL;
484 linux_sys_class_power_supply_cb_event_fd_active(void *data,
485 Ecore_Fd_Handler *fd_handler)
487 Sys_Class_Power_Supply_Uevent *sysev;
490 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
498 if ((num = read(sysev->fd, buf, sizeof(buf))) < 1)
500 lost = ((errno == EIO) ||
511 events = eina_list_remove(events, sysev);
513 // if (sysev->fd_handler)
514 // ecore_main_fd_handler_del(sysev->fd_handler);
515 // if (sysev->fd >= 0) close(sysev->fd);
519 if (re_init_timer) ecore_timer_del(re_init_timer);
520 re_init_timer = ecore_timer_add(1.0, linux_sys_class_power_supply_cb_re_init, NULL);
524 if (sys_class_delay_check) ecore_timer_del(sys_class_delay_check);
525 sys_class_delay_check = ecore_timer_add(0.2, linux_sys_class_power_supply_cb_delay_check, NULL);
528 return ECORE_CALLBACK_CANCEL;
533 linux_sys_class_power_supply_sysev_init(Sys_Class_Power_Supply_Uevent *sysev)
538 sysev->have_current_avg = 0;
539 sysev->have_current_now = 0;
541 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/present", sysev->name);
542 sysev->present = int_file_get(buf);
543 if (!sysev->present) return;
545 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_avg", sysev->name);
546 if (ecore_file_exists(buf)) sysev->have_current_avg = 1;
547 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_now", sysev->name);
548 if (ecore_file_exists(buf)) sysev->have_current_now = 1;
550 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full", sysev->name);
551 if (ecore_file_exists(buf)) sysev->basis = BASIS_VOLTAGE;
552 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full_design", sysev->name);
553 if (ecore_file_exists(buf)) sysev->basis = BASIS_VOLTAGE;
555 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full", sysev->name);
556 if (ecore_file_exists(buf)) sysev->basis = BASIS_ENERGY;
557 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full_design", sysev->name);
558 if (ecore_file_exists(buf)) sysev->basis = BASIS_ENERGY;
560 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full", sysev->name);
561 if (ecore_file_exists(buf)) sysev->basis = BASIS_CHARGE;
562 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full_design", sysev->name);
563 if (ecore_file_exists(buf)) sysev->basis = BASIS_CHARGE;
565 if (sysev->basis == BASIS_CHARGE)
567 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full", sysev->name);
568 sysev->basis_full = int_file_get(buf);
569 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_empty", sysev->name);
570 sysev->basis_empty = int_file_get(buf);
571 if (sysev->basis_full < 0)
573 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full_design", sysev->name);
574 sysev->basis_full = int_file_get(buf);
576 if (sysev->basis_empty < 0)
578 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_empty_design", sysev->name);
579 sysev->basis_empty = int_file_get(buf);
582 else if (sysev->basis == BASIS_ENERGY)
584 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full", sysev->name);
585 sysev->basis_full = int_file_get(buf);
586 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_empty", sysev->name);
587 sysev->basis_empty = int_file_get(buf);
588 if (sysev->basis_full < 0)
590 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full_design", sysev->name);
591 sysev->basis_full = int_file_get(buf);
593 if (sysev->basis_empty < 0)
595 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_empty_design", sysev->name);
596 sysev->basis_empty = int_file_get(buf);
599 else if (sysev->basis == BASIS_VOLTAGE)
601 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full", sysev->name);
602 sysev->basis_full = int_file_get(buf);
603 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_empty", sysev->name);
604 sysev->basis_empty = int_file_get(buf);
605 if (sysev->basis_full < 0)
607 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full_design", sysev->name);
608 sysev->basis_full = int_file_get(buf);
610 if (sysev->basis_empty < 0)
612 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_empty_design", sysev->name);
613 sysev->basis_empty = int_file_get(buf);
619 linux_sys_class_power_supply_is_battery(char *name)
625 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/type", name);
626 fd = open(buf, O_RDONLY);
632 else if (read(fd, buf, sizeof(buf)) < 1)
634 else if (!strncmp(buf, "Battery", 7))
644 linux_sys_class_power_supply_init(void)
650 Sys_Class_Power_Supply_Uevent *sysev;
652 EINA_LIST_FOREACH(events, l, sysev)
653 linux_sys_class_power_supply_sysev_init(sysev);
661 bats = ecore_file_ls("/sys/class/power_supply/");
666 EINA_LIST_FREE(bats, name)
668 Sys_Class_Power_Supply_Uevent *sysev;
670 if (!(linux_sys_class_power_supply_is_battery(name)))
676 sysev = (Sys_Class_Power_Supply_Uevent *)calloc(1, sizeof(Sys_Class_Power_Supply_Uevent));
678 // snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/uevent", name);
679 // sysev->fd = open(buf, O_RDONLY);
680 // if (sysev->fd >= 0)
681 // sysev->fd_handler = ecore_main_fd_handler_add(sysev->fd,
683 // linux_sys_class_power_supply_cb_event_fd_active,
686 events = eina_list_append(events, sysev);
687 linux_sys_class_power_supply_sysev_init(sysev);
694 linux_sys_class_power_supply_check(void)
707 Sys_Class_Power_Supply_Uevent *sysev;
715 EINA_LIST_FOREACH(events, l, sysev)
722 int time_to_full = -1;
723 int time_to_empty = -1;
732 /* fetch more generic info */
734 present = sysev->present;
735 if (!present) continue;
737 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/capacity", name);
738 capacity = int_file_get(buf);
739 if (sysev->have_current_avg)
741 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_avg", name);
742 current = int_file_get(buf);
744 else if (sysev->have_current_now)
746 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_now", name);
747 current = int_file_get(buf);
750 /* FIXME: do we get a uevent on going from charging to full?
751 * if so, move this to init */
752 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/status", name);
753 tmp = str_file_get(buf);
757 if (!strncasecmp("discharging", tmp, 11)) charging = 0;
758 else if (!strncasecmp("unknown", tmp, 7))
760 else if (!strncasecmp("not charging", tmp, 12))
762 else if (!strncasecmp("charging", tmp, 8))
764 else if (!strncasecmp("full", tmp, 4))
771 /* some batteries can/will/want to predict how long they will
772 * last. if so - take what the battery says. too bad if it's
773 * wrong. that's a buggy battery or driver */
779 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/time_to_full_now", name);
780 time_to_full = int_file_get(buf);
784 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/time_to_empty_now", name);
785 time_to_empty = int_file_get(buf);
789 /* now get charge, energy and voltage. take the one that provides
790 * the best info (charge first, then energy, then voltage */
791 if (sysev->basis == BASIS_CHARGE)
792 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_now", name);
793 else if (sysev->basis == BASIS_ENERGY)
794 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_now", name);
795 else if (sysev->basis == BASIS_VOLTAGE)
796 snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_now", name);
797 pwr_now = int_file_get(buf);
798 pwr_empty = sysev->basis_empty;
799 pwr_full = sysev->basis_full;
801 if (pwr_empty < 0) pwr_empty = 0;
803 if (full) pwr_now = pwr_full;
807 pwr_now = (((long long)capacity * ((long long)pwr_full - (long long)pwr_empty)) / 100) + pwr_empty;
810 if (sysev->present) have_battery = 1;
815 if (time_to_full >= 0)
817 if (time_to_full > time_left)
818 time_left = time_to_full;
822 if (current == 0) time_left = 0;
823 else if (current < 0)
827 pwr = (((long long)pwr_full - (long long)pwr_now) * 3600) / -current;
828 if (pwr > time_left) time_left = pwr;
835 if (time_to_empty >= 0) time_left += time_to_empty;
838 if (time_to_empty < 0)
842 pwr = (((long long)pwr_now - (long long)pwr_empty) * 3600) / current;
848 total_pwr_now += pwr_now - pwr_empty;
849 total_pwr_max += pwr_full - pwr_empty;
851 if (total_pwr_max > 0)
852 battery_full = ((long long)total_pwr_now * 100) / total_pwr_max;
859 /* "here and now" ACPI based power checking. is there for linux and most
860 * modern laptops. as of linux 2.6.24 it is replaced with
861 * linux_sys_class_power_supply_init/check() though as this is the new
862 * power class api to poll for power stuff
864 static Eina_Bool linux_acpi_cb_acpid_add(void *data,
867 static Eina_Bool linux_acpi_cb_acpid_del(void *data,
870 static Eina_Bool linux_acpi_cb_acpid_data(void *data,
873 static void linux_acpi_init(void);
874 static void linux_acpi_check(void);
876 static int acpi_max_full = -1;
877 static int acpi_max_design = -1;
878 static Ecore_Con_Server *acpid = NULL;
879 static Ecore_Event_Handler *acpid_handler_add = NULL;
880 static Ecore_Event_Handler *acpid_handler_del = NULL;
881 static Ecore_Event_Handler *acpid_handler_data = NULL;
882 static Ecore_Timer *delay_check = NULL;
883 static int event_fd = -1;
884 static Ecore_Fd_Handler *event_fd_handler = NULL;
887 linux_acpi_cb_delay_check(void *data __UNUSED__)
892 return ECORE_CALLBACK_CANCEL;
896 linux_acpi_cb_acpid_add(void *data __UNUSED__,
898 void *event __UNUSED__)
900 return ECORE_CALLBACK_PASS_ON;
904 linux_acpi_cb_acpid_del(void *data __UNUSED__,
906 void *event __UNUSED__)
908 ecore_con_server_del(acpid);
910 if (acpid_handler_add) ecore_event_handler_del(acpid_handler_add);
911 acpid_handler_add = NULL;
912 if (acpid_handler_del) ecore_event_handler_del(acpid_handler_del);
913 acpid_handler_del = NULL;
914 if (acpid_handler_data) ecore_event_handler_del(acpid_handler_data);
915 acpid_handler_data = NULL;
916 return ECORE_CALLBACK_PASS_ON;
920 linux_acpi_cb_acpid_data(void *data __UNUSED__,
922 void *event __UNUSED__)
924 if (delay_check) ecore_timer_del(delay_check);
925 delay_check = ecore_timer_add(0.2, linux_acpi_cb_delay_check, NULL);
926 return ECORE_CALLBACK_PASS_ON;
930 linux_acpi_cb_event_fd_active(void *data __UNUSED__,
931 Ecore_Fd_Handler *fd_handler)
933 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
941 if ((num = read(event_fd, buf, sizeof(buf))) < 1)
943 lost = ((errno == EIO) ||
953 ecore_main_fd_handler_del(event_fd_handler);
954 event_fd_handler = NULL;
960 if (delay_check) ecore_timer_del(delay_check);
961 delay_check = ecore_timer_add(0.2, linux_acpi_cb_delay_check, NULL);
964 return ECORE_CALLBACK_RENEW;
968 linux_acpi_init(void)
973 bats = ecore_file_ls("/proc/acpi/battery");
979 powers = ecore_file_ls("/proc/acpi/ac_adapter");
984 EINA_LIST_FREE(powers, name)
989 snprintf(buf, sizeof(buf), "/proc/acpi/ac_adapter/%s/state", name);
996 tmp = fgets(buf, sizeof(buf), f);
997 if (tmp) tmp = str_get(tmp);
1000 if (!strcmp(tmp, "on-line")) have_power = 1;
1011 acpi_max_design = 0;
1012 EINA_LIST_FREE(bats, name)
1017 snprintf(buf, sizeof(buf), "/proc/acpi/battery/%s/info", name);
1018 f = fopen(buf, "r");
1024 tmp = fgets(buf, sizeof(buf), f);
1025 if (tmp) tmp = str_get(tmp);
1028 if (!strcmp(tmp, "yes")) have_battery = 1;
1032 tmp = fgets(buf, sizeof(buf), f);
1033 if (tmp) tmp = str_get(tmp);
1036 if (strcmp(tmp, "unknown")) acpi_max_design += atoi(tmp);
1040 tmp = fgets(buf, sizeof(buf), f);
1041 if (tmp) tmp = str_get(tmp);
1044 if (strcmp(tmp, "unknown")) acpi_max_full += atoi(tmp);
1055 acpid = ecore_con_server_connect(ECORE_CON_LOCAL_SYSTEM,
1056 "/var/run/acpid.socket", -1, NULL);
1059 acpid_handler_add = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD,
1060 linux_acpi_cb_acpid_add, NULL);
1061 acpid_handler_del = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL,
1062 linux_acpi_cb_acpid_del, NULL);
1063 acpid_handler_data = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
1064 linux_acpi_cb_acpid_data, NULL);
1070 event_fd = open("/proc/acpi/event", O_RDONLY);
1072 event_fd_handler = ecore_main_fd_handler_add(event_fd,
1074 linux_acpi_cb_event_fd_active,
1083 linux_acpi_check(void)
1092 bats = ecore_file_ls("/proc/acpi/battery");
1099 EINA_LIST_FREE(bats, name)
1105 snprintf(buf, sizeof(buf), "/proc/acpi/battery/%s/state", name);
1107 f = fopen(buf, "r");
1110 tmp = file_str_entry_get(f, "present:");
1111 if (!tmp) goto fclose_and_continue;
1112 if (!strcasecmp(tmp, "yes")) have_battery = 1;
1115 tmp = file_str_entry_get(f, "capacity state:");
1116 if (!tmp) goto fclose_and_continue;
1119 tmp = file_str_entry_get(f, "charging state:");
1120 if (!tmp) goto fclose_and_continue;
1121 if ((have_power == 0) && (!strcasecmp(tmp, "charging")))
1125 tmp = file_str_entry_get(f, "present rate:");
1126 if (!tmp) goto fclose_and_continue;
1127 if (strcasecmp(tmp, "unknown")) rate += atoi(tmp);
1130 tmp = file_str_entry_get(f, "remaining capacity:");
1131 if (!tmp) goto fclose_and_continue;
1132 if (strcasecmp(tmp, "unknown")) capacity += atoi(tmp);
1135 fclose_and_continue:
1139 if (acpi_max_full > 0)
1140 battery_full = 100 * (long long)capacity / acpi_max_full;
1141 else if (acpi_max_design > 0)
1142 battery_full = 100 * (long long)capacity / acpi_max_design;
1145 if (rate <= 0) time_left = -1;
1149 time_left = (3600 * ((long long)acpi_max_full - (long long)capacity)) / rate;
1151 time_left = (3600 * (long long)capacity) / rate;
1157 /* old school apm support - very old laptops and some devices support this.
1158 * this is here for legacy support and i wouldn't suggest spending any
1159 * effort on it as it is complete below as best i know, but could have missed
1160 * one or 2 things, but not worth fixing */
1161 static void linux_apm_init(void);
1162 static void linux_apm_check(void);
1165 linux_apm_init(void)
1171 linux_apm_check(void)
1174 char s1[32], s2[32], s3[32], *endptr;
1175 int apm_flags, ac_stat, bat_stat, bat_flags, bat_val, time_val;
1182 f = fopen("/proc/apm", "r");
1185 if (fscanf(f, "%*s %*s %x %x %x %x %31s %31s %31s",
1186 &apm_flags, &ac_stat, &bat_stat, &bat_flags, s1, s2, s3) != 7)
1193 bat_val = strtol(s1, &endptr, 10);
1200 if (!strcmp(s3, "sec")) time_val = atoi(s2);
1201 else if (!strcmp(s3, "min"))
1202 time_val = atoi(s2) * 60;
1205 if ((bat_flags != 0xff) && (bat_flags & 0x80))
1217 have_power = ac_stat;
1218 battery_full = bat_val;
1219 if (battery_full > 100) battery_full = 100;
1220 if (ac_stat == 1) time_left = -1;
1221 else time_left = time_val;
1229 have_power = ac_stat;
1234 case 1: /* medium */
1236 have_power = ac_stat;
1243 have_power = ac_stat;
1248 case 3: /* charging */
1250 have_power = ac_stat;
1259 /* for older mac powerbooks. legacy as well like linux_apm_init/check. leave
1260 * it alone unless you have to touch it */
1261 static void linux_pmu_init(void);
1262 static void linux_pmu_check(void);
1265 linux_pmu_init(void)
1271 linux_pmu_check(void)
1284 f = fopen("/proc/pmu/info", "r");
1289 tmp = fgets(buf, sizeof(buf), f);
1292 EINA_LOG_ERR("no driver info in /proc/pmu/info");
1293 goto fclose_and_continue;
1296 tmp = fgets(buf, sizeof(buf), f);
1299 EINA_LOG_ERR("no firmware info in /proc/pmu/info");
1300 goto fclose_and_continue;
1303 tmp = fgets(buf, sizeof(buf), f);
1306 EINA_LOG_ERR("no AC info in /proc/pmu/info");
1307 goto fclose_and_continue;
1310 fclose_and_continue:
1313 bats = ecore_file_ls("/proc/pmu");
1318 EINA_LIST_FREE(bats, name)
1320 if (strncmp(name, "battery", 7)) continue;
1321 snprintf(buf, sizeof(buf), "/proc/pmu/%s", name);
1322 f = fopen(buf, "r");
1328 while (fgets(buf, sizeof (buf), f))
1332 if ((token = strtok(buf, ":")))
1334 if (!strncmp("charge", token, 6))
1335 charge = atoi(strtok(0, ": "));
1336 else if (!strncmp("max_charge", token, 9))
1337 max_charge = atoi(strtok(0, ": "));
1338 else if (!strncmp("current", token, 7))
1339 current = atoi(strtok(0, ": "));
1340 else if (!strncmp("time rem", token, 8))
1341 timeleft = atoi(strtok(0, ": "));
1346 curmax += max_charge;
1347 curcharge += charge;
1351 /* Neither charging nor discharging */
1355 /* When on dc, we are discharging */
1356 seconds += timeleft;
1360 /* Charging - works in parallel */
1361 seconds = MAX(timeleft, seconds);
1367 if (max_charge > 0) battery_full = ((long long)charge * 100) / max_charge;
1368 else battery_full = 0;
1369 time_left = seconds;
1383 dir_has_contents(const char *dir)
1389 bats = ecore_file_ls(dir);
1391 count = eina_list_count(bats);
1392 EINA_LIST_FREE(bats, file)
1394 if (count > 0) return 1;
1405 len = sizeof(acline);
1406 if (!sysctlbyname("hw.acpi.acline", &acline, &len, NULL, 0))
1408 int acline_mib[3] = {-1};
1411 if (!sysctlnametomib("hw.acpi.acline", acline_mib, &len))
1420 if (ecore_file_exists("/dev/apm"))
1427 #elif defined(HAVE_CFBASE_H) /* OS X */
1430 if ((ecore_file_is_dir("/sys/class/power_supply")) &&
1431 (dir_has_contents("/sys/class/power_supply")))
1433 mode = CHECK_SYS_CLASS_POWER_SUPPLY;
1434 linux_sys_class_power_supply_init();
1436 else if (ecore_file_is_dir("/proc/acpi")) /* <= 2.6.24 */
1441 else if (ecore_file_exists("/proc/apm"))
1446 else if (ecore_file_is_dir("/proc/pmu"))
1455 poll_cb(void *data __UNUSED__)
1462 ptime_left = time_left;
1463 pbattery_full = battery_full;
1464 phave_battery = have_battery;
1465 phave_power = have_power;
1487 #elif defined(HAVE_CFBASE_H) /* OS X */
1489 return ECORE_CALLBACK_RENEW;
1505 case CHECK_SYS_CLASS_POWER_SUPPLY:
1506 linux_sys_class_power_supply_check();
1517 if ((ptime_left != time_left) ||
1518 (pbattery_full != battery_full) ||
1519 (phave_battery != have_battery) ||
1520 (phave_power != have_power))
1522 if ((time_left < 0) &&
1523 ((have_battery) && (battery_full < 0)))
1526 printf("%i %i %i %i %i\n",
1527 battery_full, time_left, time_left, have_battery, have_power);
1530 return ECORE_CALLBACK_RENEW;
1539 printf("ARGS INCORRECT!\n");
1542 poll_interval = atoi(argv[1]);
1549 poller = ecore_poller_add(ECORE_POLLER_CORE, poll_interval, poll_cb, NULL);
1552 ecore_main_loop_begin();
1554 ecore_con_shutdown();
1555 ecore_file_shutdown();