From 66acd8ed3890ee237d106d99a85d2a3b9c86f5d0 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 7 Aug 2015 03:21:03 +0200 Subject: [PATCH] Add battery Mains/AC support for Linux Add initial support for mains/ac adapters. This adds the state only to the tooltip, but the code has been prepared to update AC state together with normal battery updates, so that it's possible to forward the state to the normal panel area or trigger something on AC (dis)connection. --- src/battery/linux.c | 136 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 15 deletions(-) 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);