diff --git a/wmbattery/apm.h b/wmbattery/apm.h index 04b6e7f..c9f3f3b 100644 --- a/wmbattery/apm.h +++ b/wmbattery/apm.h @@ -1,3 +1,6 @@ +#ifndef _WMBATTERY_APM_H +#define _WMBATTERY_APM_H + #include "config.h" #ifdef HAVE_MACHINE_APM_BIOS_H /* for FreeBSD */ @@ -54,3 +57,5 @@ typedef struct { int apm_read(apm_info *i); int apm_exists(void); #endif + +#endif diff --git a/wmbattery/envsys.c b/wmbattery/envsys.c new file mode 100644 index 0000000..f2d3846 --- /dev/null +++ b/wmbattery/envsys.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include +#include +#include "envsys.h" + +#define _DEV_SYSMON "/dev/sysmon" +#define ACPIBAT_FMT "acpibat%d" + +int envsys_supported(void) +{ + return 1; /* XXX */ +} + +prop_array_t +get_battery (char * battery_name) +{ + prop_dictionary_t sys_dict; + prop_array_t bat_arr; + int smfd; + + if (battery_name == NULL) return NULL; + + smfd = open(_DEV_SYSMON, O_RDONLY); + if (smfd == -1) return NULL; + + if (prop_dictionary_recv_ioctl(smfd, + ENVSYS_GETDICTIONARY, + &sys_dict) != 0) + { + return NULL; + } + + close(smfd); + + bat_arr = prop_dictionary_get(sys_dict, battery_name); + if (bat_arr == NULL) return NULL; + + // XXX: i think this is how the ref counting works? + // probably should look into that + prop_object_retain (bat_arr); + prop_object_release (sys_dict); + + return bat_arr; +} + +bool +stat_is_valid (prop_dictionary_t stat) +{ + prop_string_t strval; + + if (stat == NULL) return false; + + strval = prop_dictionary_get (stat, "state"); + if (strval == NULL) return false; + + + return prop_string_equals_cstring (strval, "valid"); +} + +int64_t +handle_stat (prop_dictionary_t stat, + char * key) +{ + prop_number_t numval; + + if (stat == NULL || key == NULL) return -1; + + numval = (prop_number_t) prop_dictionary_get (stat, key); + if (numval == NULL) return -1; + + return prop_number_integer_value (numval); +} + +int +envsys_read (int battery, + apm_info *info) +{ + prop_object_iterator_t iter; + prop_dictionary_t id; + prop_string_t desc; + prop_array_t bat_info; + bool is_present = false; + int64_t charge_rate = 0, + max_charge = 0, + cur_charge = 0, + warn_charge = 0, + crit_charge = 0; + char bat_name[] = ACPIBAT_FMT; + int bat_id = battery - 1; + + if (info == NULL || (battery - 1 < 0)) return -1; + + info->battery_flags = 0; + info->using_minutes = 1; + + snprintf (bat_name, strlen (ACPIBAT_FMT), ACPIBAT_FMT, bat_id); + + bat_info = get_battery (bat_name); + if (bat_info == NULL) return -1; + + iter = prop_array_iterator (bat_info); + while ((id = (prop_dictionary_t) prop_object_iterator_next (iter)) != NULL) + { + desc = (prop_string_t) prop_dictionary_get (id, "description"); + if (desc == NULL) continue; + if (prop_string_equals_cstring (desc, "charging")) + { + info->ac_line_status = handle_stat (id, "cur-value"); + } else if (prop_string_equals_cstring (desc, "charge")) { + cur_charge = handle_stat (id, "cur-value"); + max_charge = handle_stat (id, "max-value"); + warn_charge = handle_stat (id, "warning-capacity"); + crit_charge = handle_stat (id, "critical-capacity"); + } else if (prop_string_equals_cstring (desc, "charge rate")) { + if (stat_is_valid (id)) charge_rate = handle_stat (id, "cur-value"); + } else if (prop_string_equals_cstring (desc, "discharge rate")) { + if (stat_is_valid (id)) charge_rate = handle_stat (id, "cur-value"); + } else if (prop_string_equals_cstring (desc, "present")) { + is_present = (handle_stat (id, "cur-value") == 1); + } + } + prop_object_iterator_release (iter); + prop_object_release (bat_info); + + if (max_charge > 1) { + info->battery_percentage = ( cur_charge * 100 ) / max_charge; + if (info->battery_percentage > 100) info->battery_percentage = 100; + } else { + info->battery_percentage = BATTERY_PERCENTAGE_UNKNOWN; + } + + if (info->ac_line_status) { + info->battery_status = BATTERY_STATUS_CHARGING; + /* if charge_rate == 0, then it was either marked invalid or we're charging + * at 0Wh (either way, we're not charging) */ + if (charge_rate > 0) { + info->battery_flags = info->battery_flags | BATTERY_FLAGS_CHARGING; + } + } else { + if (cur_charge < crit_charge) { + info->battery_status = BATTERY_STATUS_CRITICAL; + } else if (cur_charge < warn_charge) { + info->battery_status = BATTERY_STATUS_LOW; + } else { + info->battery_status = BATTERY_STATUS_HIGH; + } + } + + if (!is_present) { + info->battery_percentage = 0; + info->battery_time = 0; + info->battery_status = BATTERY_STATUS_ABSENT; + } + + // calculate time + if (charge_rate == 0) { + info->battery_time = BATTERY_TIME_UNKNOWN; + } else { + info->battery_time = ( (max_charge - cur_charge) * 60) / charge_rate; + } + + return 0; +} diff --git a/wmbattery/envsys.h b/wmbattery/envsys.h new file mode 100644 index 0000000..6dccf95 --- /dev/null +++ b/wmbattery/envsys.h @@ -0,0 +1,4 @@ +#include "apm.h" + +int envsys_supported(void); +int envsys_read(int battery, apm_info *info); diff --git a/wmbattery/wmbattery.c b/wmbattery/wmbattery.c index 7c1a9d4..090e555 100644 --- a/wmbattery/wmbattery.c +++ b/wmbattery/wmbattery.c @@ -49,6 +49,9 @@ #ifdef UPOWER #include "upower.h" #endif +#ifdef ENVSYS +#include "envsys.h" +#endif Pixmap images[NUM_IMAGES]; Window root, iconwin, win; @@ -78,6 +81,9 @@ int use_simplehal = 0; #ifdef UPOWER int use_upower = 0; #endif +#ifdef ENVSYS +int use_envsys = 0; +#endif int use_sonypi = 0; int use_acpi = 0; int delay = 0; @@ -146,7 +152,8 @@ int apm_exists(void) apm_info i; if (access(apm_status_file, R_OK)) - return 0; + return 1; + return apm_read(&i); } #elif !defined(HAVE_LIBAPM) @@ -707,7 +714,6 @@ void alarmhandler(int sig) { apm_info cur_info; int old_status; - #ifdef UPOWER if (use_upower) { if (upower_read(1, &cur_info) != 0) @@ -724,6 +730,12 @@ void alarmhandler(int sig) if (simplehal_read(battnum, &cur_info) != 0) error("Cannot read HAL information."); } +#endif +#ifdef ENVSYS + else if (use_envsys) { + if (envsys_read(battnum, &cur_info) != 0) + error("Cannot read envsys information."); + } #endif else if (!use_sonypi) { if (apm_read(&cur_info) != 0) @@ -789,6 +801,14 @@ int main(int argc, char *argv[]) if (!delay) delay = 1; } +#ifdef ENVSYS + /* Check for envsys support. */ + else if (envsys_supported()) { + use_envsys = 1; + if (!delay) + delay = 2; + } +#endif #ifdef HAL /* Check for hal support. */ else if (simplehal_supported()) { @@ -816,7 +836,7 @@ int main(int argc, char *argv[]) if (!delay) delay = 1; } else { - error("No APM, ACPI, UPOWER, HAL or SPIC support detected."); + error("No APM, ACPI, ENVSYS, UPOWER, HAL or SPIC support detected."); } load_images();