diff --git a/src/battery/linux.c b/src/battery/linux.c index 6234c82..bae3d1a 100644 --- a/src/battery/linux.c +++ b/src/battery/linux.c @@ -24,6 +24,12 @@ #include "common.h" #include "battery.h" +enum psy_type { + PSY_UNKNOWN, + PSY_BATTERY, + PSY_MAINS, +}; + struct psy_battery { /* generic properties */ gchar* name; @@ -44,15 +50,25 @@ struct psy_battery { enum chargestate status; }; +struct psy_mains { + /* generic properties */ + gchar* name; + /* sysfs files */ + gchar* path_online; + /* values */ + gboolean online; +}; + #define RETURN_ON_ERROR(err) if(error) { g_error_free(err); return FALSE; } static GList *batteries = NULL; +static GList *mains = NULL; static guint8 energy_to_percent(gint energy_now, gint energy_full) { return 0.5 + ((energy_now <= energy_full ? energy_now : energy_full) * 100.0) / energy_full; } -static gboolean power_supply_is_battery(const gchar *entryname) { +static enum psy_type power_supply_get_type(const gchar *entryname) { gchar *path_type = g_build_filename("/sys/class/power_supply", entryname, "type", NULL); GError *error = NULL; gchar *type; @@ -60,16 +76,24 @@ static gboolean power_supply_is_battery(const gchar *entryname) { g_file_get_contents(path_type, &type, &typelen, &error); g_free(path_type); - RETURN_ON_ERROR(error); + if (error) { + g_error_free(error); + return PSY_UNKNOWN; + } - if(g_strcmp0(type, "Battery\n")) { + if(!g_strcmp0(type, "Battery\n")) { g_free(type); - return FALSE; + return PSY_BATTERY; + } + + if(!g_strcmp0(type, "Mains\n")) { + g_free(type); + return PSY_MAINS; } g_free(type); - return TRUE; + return PSY_UNKNOWN; } static gboolean init_linux_battery(struct psy_battery *bat) { @@ -134,6 +158,18 @@ err0: return FALSE; } +static gboolean init_linux_mains(struct psy_mains *ac) { + const gchar *entryname = ac->name; + + ac->path_online = g_build_filename("/sys/class/power_supply", entryname, "online", NULL); + if (!g_file_test(ac->path_online, G_FILE_TEST_EXISTS)) { + g_free(ac->path_online); + return FALSE; + } + + return TRUE; +} + void free_linux_batteries() { GList *l = batteries; @@ -152,7 +188,46 @@ void free_linux_batteries() { l = next; } + l = mains; + while (l != NULL) { + GList *next = l->next; + struct psy_mains *ac = l->data; + + g_free(ac->name); + g_free(ac->path_online); + + mains = g_list_delete_link(mains, l); + l = next; + } + batteries = NULL; + mains = NULL; +} + +static void add_battery(const char *entryname) { + struct psy_battery *bat = g_malloc0(sizeof(*bat)); + bat->name = g_strdup(entryname); + + if(init_linux_battery(bat)) { + batteries = g_list_append(batteries, bat); + fprintf(stdout, "found battery \"%s\"\n", bat->name); + } else { + g_free(bat); + fprintf(stderr, RED "failed to initialize battery \"%s\"\n" RESET, entryname); + } +} + +static void add_mains(const char *entryname) { + struct psy_mains *ac = g_malloc0(sizeof(*ac)); + ac->name = g_strdup(entryname); + + if(init_linux_mains(ac)) { + mains = g_list_append(mains, ac); + fprintf(stdout, "found mains \"%s\"\n", ac->name); + } else { + g_free(ac); + fprintf(stderr, RED "failed to initialize mains \"%s\"\n" RESET, entryname); + } } gboolean init_linux_batteries() { @@ -166,17 +241,17 @@ gboolean init_linux_batteries() { RETURN_ON_ERROR(error); while ((entryname = g_dir_read_name(directory))) { - if(!power_supply_is_battery(entryname)) - continue; + enum psy_type type = power_supply_get_type(entryname); - struct psy_battery *bat = g_malloc0(sizeof(*bat)); - bat->name = g_strdup(entryname); - if(init_linux_battery(bat)) { - batteries = g_list_append(batteries, bat); - fprintf(stdout, "found battery \"%s\"\n", bat->name); - } else { - g_free(bat); - fprintf(stderr, RED "failed to initialize battery \"%s\"\n" RESET, entryname); + switch(type) { + case PSY_BATTERY: + add_battery(entryname); + break; + case PSY_MAINS: + add_mains(entryname); + break; + default: + break; } } @@ -241,6 +316,22 @@ static gboolean update_linux_battery(struct psy_battery *bat) { return TRUE; } + +static gboolean update_linux_mains(struct psy_mains *ac) { + GError *error = NULL; + gchar *data; + gsize datalen; + ac->online = FALSE; + + /* online */ + g_file_get_contents(ac->path_online, &data, &datalen, &error); + RETURN_ON_ERROR(error); + ac->online = (atoi(data) == 1); + g_free(data); + + return TRUE; +} + void update_linux_batteries(enum chargestate *state, int8_t *percentage, int *seconds) { GList *l; @@ -265,6 +356,11 @@ void update_linux_batteries(enum chargestate *state, int8_t *percentage, int *se full |= (bat->status == BATTERY_FULL); } + for (l = mains; l != NULL; l = l->next) { + struct psy_mains *ac = l->data; + update_linux_mains(ac); + } + /* build global state */ *state = BATTERY_UNKNOWN; if (charging && !discharging) @@ -353,6 +449,16 @@ char* linux_batteries_get_tooltip() { g_free(energy); } + for (l = mains; l != NULL; l = l->next) { + struct psy_mains *ac = l->data; + + if (tooltip->len) + g_string_append_c(tooltip, '\n'); + + g_string_append_printf(tooltip, "%s\n", ac->name); + g_string_append_printf(tooltip, ac->online ? "\tconnected" : "\tdisconnected"); + } + result = tooltip->str; g_string_free(tooltip, FALSE);