#include "battery.h" #include "../util.h" #include #include #include #include #define ADAPTER_BASE_PATH "/sys/class/power_supply/" #define BATTERY_PATH "/sys/class/power_supply/BAT0" static const char *adapter_search_names[] = {"AC0", "ADP1"}; static size_t adapter_search_names_count = sizeof(adapter_search_names) / sizeof(char *); static char *adapter_status_path; static int max_batery_charge; static int show_notifiaction = TRUE; static void find_max_battery_charge() { FILE *max_file = fopen(BATTERY_PATH "/charge_full", "r"); fseeko(max_file, 0, SEEK_END); off_t len = ftello(max_file); rewind(max_file); char text[len + 1]; text[len] = '\0'; fread(text, 1, len, max_file); max_batery_charge = strtoul(text, NULL, 10); fclose(max_file); } static int is_battery_full() { FILE *status_file = fopen(BATTERY_PATH "/status", "r"); if (!status_file) { return FALSE; } fseeko(status_file, 0, SEEK_END); off_t len = ftello(status_file); rewind(status_file); char status_text[len + 1]; status_text[len] = '\0'; fread(status_text, 1, len, status_file); fclose(status_file); return strcmp(status_text, "Full\n") == 0; } static int get_battery_percent() { if (is_battery_full()) { return 100; } FILE *battery_file = fopen(BATTERY_PATH "/charge_now", "r"); if (!battery_file) { return -1; } fseeko(battery_file, 0, SEEK_END); off_t len = ftello(battery_file); rewind(battery_file); char charge_text[len + 1]; charge_text[len] = '\0'; fread(charge_text, 1, len, battery_file); fclose(battery_file); long charge = strtoul(charge_text, NULL, 10); float scale = (float)charge / (float)max_batery_charge; return round(scale * 100.0f); } static int is_adapter_connected() { FILE *adapter_file = fopen(adapter_status_path, "r"); if (!adapter_file) { return -1; } char text[2] = {'\0', '\0'}; fread(text, 1, 1, adapter_file); fclose(adapter_file); return text[0] == '1'; /* 1 means connected, anything else is not */ } static void find_adapter_status_path() { size_t i; for (i = 0; i < adapter_search_names_count; ++i) { size_t name_len = strlen(adapter_search_names[i]); /* -1 is to compensate for '\0' at end of "/online" */ char *name = qtb_malloc(sizeof(ADAPTER_BASE_PATH) + name_len + sizeof("/online") - 1); sprintf(name, "%s%s/online", ADAPTER_BASE_PATH, adapter_search_names[i]); FILE *file = fopen(name, "r"); if (file) { adapter_status_path = name; } else { qtb_free(name); } } } void battery_module_init(void) { find_max_battery_charge(); find_adapter_status_path(); } static const char *get_battery_icon(int percent, int adapter) { if (adapter) { return ""; } else if (percent <= 10) { return ""; } else if (percent <= 20) { return ""; } else if (percent <= 30) { return ""; } else if (percent <= 40) { return ""; } else if (percent <= 50) { return ""; } else if (percent <= 60) { return ""; } else if (percent <= 70) { return ""; } else if (percent <= 90) { return ""; } else if (percent < 100) { return ""; } else { return ""; } } static void warn_low_battery() { #ifdef HAS_X11 if (qtb_get_x_display()) { /* if x is running */ system("notify-send -t 0 'Battery is less than 10%!'"); } else { #endif system("wall -t 0 'Battery is less than 10%!'"); #ifdef HAS_X11 } #endif } char *battery_module_poll() { char *output = qtb_calloc(16, 1); int percent = get_battery_percent(); int adapter = is_adapter_connected(); if (percent == -1 || adapter == -1) { sprintf(output, "?N/A%%"); } else { const char *icon = get_battery_icon(percent, adapter); sprintf(output, "%s%3d%%", icon, percent); if (show_notifiaction && percent <= 10) { warn_low_battery(); show_notifiaction = FALSE; } else if (percent > 10) { show_notifiaction = TRUE; } } return output; }