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;
|
||
}
|