+/*
+ * A Simple Battery Status Display
+ *
+ * (c) 2007 Martin Mares <mj@ucw.cz>
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
static xosd *osd;
-static int total_discharge, total_charge, total_full, total_capa;
+static int total_full, total_capa, discharge_rate;
+static int charge_time, discharge_time;
+static int ac_online;
+static unsigned int present_mask, charge_mask, discharge_mask;
-#define CHECK_PERIOD 10
+#define CHECK_PERIOD 60
#define SHOW_DURATION 2
#define WARN_THRESHOLD 600
+static char *parse_line(char *line)
+{
+ char *t = strchr(line, '\n');
+ if (t)
+ *t = 0;
+ char *val = strchr(line, ':');
+ if (!val)
+ return NULL;
+ *val++ = 0;
+ while (*val == ' ' || *val == '\t')
+ *val++ = 0;
+ return val;
+}
+
+static void scan_ac(void)
+{
+ ac_online = 0;
+
+ const char dir[] = "/proc/acpi/ac_adapter";
+ DIR *d = opendir(dir);
+ if (!d)
+ return;
+
+ struct dirent *e;
+ while (e = readdir(d))
+ {
+ if (e->d_name[0] == '.')
+ continue;
+ char n[sizeof(dir) + 1 + strlen(e->d_name) + 6];
+ sprintf(n, "%s/%s/state", dir, e->d_name);
+ FILE *f = fopen(n, "r");
+ if (!f)
+ continue;
+ char line[1024];
+ while (fgets(line, sizeof(line)-1, f))
+ {
+ char *val = parse_line(line);
+ if (!val)
+ continue;
+ if (!strcmp(line, "state") && !strcmp(val, "on-line"))
+ ac_online = 1;
+ }
+ fclose(f);
+ }
+ closedir(d);
+}
+
static void scan_batt(void)
{
- total_discharge = total_charge = 0;
+ charge_time = discharge_time = 0;
total_full = total_capa = 0;
+ discharge_rate = 0;
+ present_mask = charge_mask = discharge_mask = 0;
const char dir[] = "/proc/acpi/battery";
DIR *d = opendir(dir);
int charging = 0;
int remains = 0;
int last_full = 0;
+ int batt_id = -1;
for (int i=0; i<2; i++)
{
sprintf(n, "%s/%s/%s", dir, e->d_name, names[i]);
char line[1024];
while (fgets(line, sizeof(line)-1, f))
{
- char *t = strchr(line, '\n');
- if (t)
- *t = 0;
- char *val = strchr(line, ':');
+ char *val = parse_line(line);
if (!val)
continue;
- *val++ = 0;
- while (*val == ' ' || *val == '\t')
- *val++ = 0;
// printf("<%s> <%s>\n", line, val);
if (!strcmp(line, "present"))
present = !strcmp(val, "yes");
remains = atol(val);
else if (!strcmp(line, "last full capacity"))
last_full = atol(val);
+ else if (!strcmp(line, "serial number"))
+ batt_id = atol(val);
}
fclose(f);
}
if (present)
{
+ if (batt_id < 0 || batt_id > 31)
+ batt_id = 0;
+ present_mask |= 1 << batt_id;
total_full += remains;
total_capa += last_full;
if (charging)
{
+ charge_mask |= 1 << batt_id;
int ch = (last_full - remains)*3600 / rate;
- if (ch > total_charge)
- total_charge = ch;
+ if (ch > charge_time)
+ charge_time = ch;
}
- else
+ else if (rate > 0)
{
- if (rate <= 0)
- total_discharge += 1000000;
- else
- total_discharge += remains*3600 / rate;
+ discharge_mask |= 1 << batt_id;
+ discharge_rate += rate;
}
}
}
+ if (discharge_rate)
+ discharge_time = total_full*3600 / discharge_rate;
+ else
+ discharge_time = 1000000;
closedir(d);
}
+static void scan(void)
+{
+ scan_ac();
+ scan_batt();
+}
+
+static char *batt_mask(char *p, unsigned int mask)
+{
+ if (present_mask & (present_mask-1))
+ {
+ char *p0 = p;
+ for (int i=0; mask; i++)
+ if (mask & (1 << i))
+ {
+ *p = (p == p0) ? ' ' : '+';
+ p++;
+ p += sprintf(p, "B%d", i);
+ mask &= ~(1 << i);
+ }
+ }
+ return p;
+}
+
static void show(void)
{
char status[256];
p += sprintf(p, "%d%%", 100*total_full/total_capa);
else
p += sprintf(p, "??%%");
- if (total_discharge && total_discharge < 1000000)
- p += sprintf(p, " %d:%02d remains", total_discharge/3600, (total_discharge/60)%60);
- else if (total_charge)
- p += sprintf(p, " %d:%02d charging", total_charge/3600, (total_charge/60)%60);
+ if (discharge_mask && discharge_time < 1000000)
+ {
+ p += sprintf(p, " %d:%02d remains", discharge_time/3600, (discharge_time/60)%60);
+ batt_mask(p, discharge_mask);
+ }
+ else if (charge_mask)
+ {
+ p += sprintf(p, " %d:%02d charging", charge_time/3600, (charge_time/60)%60);
+ batt_mask(p, charge_mask);
+ }
+ else if (ac_online)
+ p += sprintf(p, " AC");
+ else
+ p += sprintf(p, " BATT");
xosd_display(osd, 0, XOSD_string, status);
}
static void sig_show(int sig)
{
alarm(0);
- scan_batt();
+ scan();
show();
my_sleep(SHOW_DURATION);
xosd_hide(osd);
static void sig_check(int sig)
{
- scan_batt();
- if (total_discharge && total_discharge < WARN_THRESHOLD)
+ scan();
+ if (discharge_mask && discharge_time < WARN_THRESHOLD)
{
show();
my_sleep(SHOW_DURATION);
if (!watcher)
{
- scan_batt();
+ scan();
show();
my_sleep(SHOW_DURATION);
xosd_destroy(osd);