]> mj.ucw.cz Git - misc.git/blobdiff - batt.c
Added pstopsfix.
[misc.git] / batt.c
diff --git a/batt.c b/batt.c
index d1a2768214a609a8f88cf1a8cd9140cc78566c4d..fa6ff1000fec49d2d3d2d1469c078a3d1b5ca347 100644 (file)
--- a/batt.c
+++ b/batt.c
@@ -1,3 +1,9 @@
+/*
+ *     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);
@@ -37,6 +95,7 @@ static void scan_batt(void)
       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]);
@@ -46,15 +105,9 @@ static void scan_batt(void)
          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");
@@ -66,32 +119,63 @@ static void scan_batt(void)
                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];
@@ -100,10 +184,20 @@ static void show(void)
     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);
 }
 
@@ -116,7 +210,7 @@ static void my_sleep(int sec)
 static void sig_show(int sig)
 {
   alarm(0);
-  scan_batt();
+  scan();
   show();
   my_sleep(SHOW_DURATION);
   xosd_hide(osd);
@@ -139,8 +233,8 @@ static void sig_time(int sig)
 
 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);
@@ -190,7 +284,7 @@ int main(int argc, char **argv)
 
   if (!watcher)
     {
-      scan_batt();
+      scan();
       show();
       my_sleep(SHOW_DURATION);
       xosd_destroy(osd);