154 lines
4.2 KiB
C
154 lines
4.2 KiB
C
|
#include "battery.h"
|
|||
|
#include "../util.h"
|
|||
|
|
|||
|
#include <math.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
#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;
|
|||
|
}
|