diff -urN battstat.orig/acpi-linux.c battstat/acpi-linux.c
--- battstat.orig/acpi-linux.c	2003-07-26 17:28:17.000000000 -0400
+++ battstat/acpi-linux.c	2003-09-07 16:30:45.000000000 -0400
@@ -36,6 +36,8 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <unistd.h>
@@ -136,38 +138,59 @@
   return g_hash_table_lookup (hash, key);
 }
 
-/*
- * Fills out a classic apm_info structure with the data gathered from
- * the ACPI kernel interface in /proc
- */
-gboolean acpi_linux_read(struct apm_info *apminfo)
+/* Reads the current status of the AC adapter and stores the
+ * result in acpiinfo->ac_online. */
+static gboolean update_ac_info(struct acpi_info * acpiinfo)
 {
-  guint32 max_capacity, low_capacity, critical_capacity, remain;
-  gboolean charging, ac_online;
-  gulong acpi_ver;
+  char ac_state[60];
+  DIR * procdir;
+  struct dirent * procdirentry;
   char buf[BUFSIZ];
   GHashTable *hash;
-  const char *ac_state_state, *charging_state;
-  const char *batt_state_state;
-  char batt_info[60], batt_state[60], ac_state[60];
+
+  acpiinfo->ac_online = FALSE;
+
+  procdir=opendir("/proc/acpi/ac_adapter/");
+  if (!procdir)
+    return FALSE;
+
+  while ((procdirentry=readdir(procdir)))
+   {
+    if (procdirentry->d_name[0]!='.')
+     {
+      strcpy(ac_state,"/proc/acpi/ac_adapter/");
+      strcat(ac_state,procdirentry->d_name);
+      strcat(ac_state,"/");
+      strcat(ac_state,acpiinfo->ac_state_state);
+      hash = read_file (ac_state, buf, sizeof (buf));
+      if (hash && !acpiinfo->ac_online)
+       {
+        const char *s;
+        s = read_string (hash, acpiinfo->ac_state_state);
+        acpiinfo->ac_online = s ? (strcmp (s, "on-line") == 0) : 0;
+        g_hash_table_destroy (hash);
+       }
+     }
+   }
+  closedir(procdir);
+
+  return TRUE;
+}
+
+/* Reads the ACPI info for the system batteries, and finds
+ * the total capacity, which is stored in acpiinfo. */
+static gboolean update_battery_info(struct acpi_info * acpiinfo)
+{
+  char batt_info[60];
+  gulong acpi_ver;
+  GHashTable *hash;
   DIR * procdir;
   struct dirent * procdirentry;
+  char buf[BUFSIZ];
 
-  /*
-   * apminfo.ac_line_status must be one when on ac power
-   * apminfo.battery_status must be 0 for high, 1 for low, 2 for critical, 3 for charging
-   * apminfo.battery_percentage must contain batter charge percentage
-   * apminfo.battery_flags & 0x8 must be nonzero when charging
-   */
-  
-  g_assert(apminfo);
-
-  max_capacity = 0;
-  low_capacity = 0;
-  critical_capacity = 0;
-  charging = FALSE;
-  remain = 0;
-  ac_online = FALSE;
+  acpiinfo->max_capacity = 0;
+  acpiinfo->low_capacity = 0;
+  acpiinfo->critical_capacity = 0;
 
   hash = read_file ("/proc/acpi/info", buf, sizeof (buf));
   if (!hash)
@@ -177,13 +200,13 @@
   g_hash_table_destroy (hash);
 
   if (acpi_ver < (gulong)20020208) {
-    ac_state_state = "status";
-    batt_state_state = "status";
-    charging_state = "state";
+    acpiinfo->ac_state_state = "status";
+    acpiinfo->batt_state_state = "status";
+    acpiinfo->charging_state = "state";
   } else {
-    ac_state_state = "state";
-    batt_state_state = "state";
-    charging_state = "charging state";
+    acpiinfo->ac_state_state = "state";
+    acpiinfo->batt_state_state = "state";
+    acpiinfo->charging_state = "charging state";
   }
 
   procdir=opendir("/proc/acpi/battery/");
@@ -200,64 +223,207 @@
       hash = read_file (batt_info, buf, sizeof (buf));
       if (hash)
        {
-        max_capacity += read_long (hash, "last full capacity");
-        low_capacity += read_long (hash, "design capacity warning");
-        critical_capacity += read_long (hash, "design capacity low");
-        g_hash_table_destroy (hash);
-       }
-      strcpy(batt_state,"/proc/acpi/battery/");
-      strcat(batt_state,procdirentry->d_name);
-      strcat(batt_state,"/");
-      strcat(batt_state,batt_state_state);
-      hash = read_file (batt_state, buf, sizeof (buf));
-      if (hash)
-       {
-        const char *s;
-        if (!charging)
-         {
-          s = read_string (hash, charging_state);
-          charging = s ? (strcmp (s, "charging") == 0) : 0;
-         }
-        remain += read_long (hash, "remaining capacity");
+        acpiinfo->max_capacity += read_long (hash, "last full capacity");
+        acpiinfo->low_capacity += read_long (hash, "design capacity warning");
+        acpiinfo->critical_capacity += read_long (hash, "design capacity low");
         g_hash_table_destroy (hash);
        }
      }
    }
   closedir(procdir);
 
-  if (!max_capacity)
-    return FALSE;
+  return TRUE;
+}
 
-  procdir=opendir("/proc/acpi/ac_adapter/");
+
+/* Initializes the ACPI-reading subsystem by opening a file
+ * descriptor to the ACPI event file.  This can either be the
+ * /proc/acpi/event exported by the kernel, or if it's already
+ * in use, the /var/run/acpid.socket maintained by acpid.  Also
+ * initializes the stored battery and AC adapter information. */
+gboolean acpi_linux_init(struct acpi_info * acpiinfo)
+{
+  int fd;
+
+  g_assert(acpiinfo);
+  
+  fd = open("/proc/acpi/event", 0);
+  if (fd >= 0) {
+    acpiinfo->event_fd = fd;
+    acpiinfo->channel = g_io_channel_unix_new(fd);
+    update_battery_info(acpiinfo);
+    update_ac_info(acpiinfo);
+    return TRUE;
+  }
+
+  fd = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (fd >= 0) {
+    struct sockaddr_un addr;
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, "/var/run/acpid.socket");
+    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == 0) {
+      acpiinfo->event_fd = fd;
+      acpiinfo->channel = g_io_channel_unix_new(fd);
+      update_battery_info(acpiinfo);
+      update_ac_info(acpiinfo);
+      return TRUE;
+    }
+  }
+
+  acpiinfo->event_fd = -1;
+  return FALSE;
+}
+
+/* Cleans up ACPI */
+void acpi_linux_cleanup(struct acpi_info * acpiinfo)
+{
+  g_assert(acpiinfo);
+
+  if (acpiinfo->event_fd >= 0) {
+    g_io_channel_unref(acpiinfo->channel);
+    close(acpiinfo->event_fd);
+    acpiinfo->event_fd = -1;
+  }
+}
+
+#define ACPI_EVENT_IGNORE       0
+#define ACPI_EVENT_DONE         1
+#define ACPI_EVENT_AC           2
+#define ACPI_EVENT_BATTERY_INFO 3
+
+/* Given a string event from the ACPI system, returns the type
+ * of event if we're interested in it.  str is updated to point
+ * to the next event. */
+static int parse_acpi_event(char * event, char ** str)
+{
+  char * end;
+  char * tok[4];
+  int i;
+
+  end = strchr(event, '\n');
+  if (!end)
+    return ACPI_EVENT_DONE;
+
+  *end = '\0';
+  *str = end + 1;
+
+  tok[0] = event;
+  for (i=0; i < 3; i++) {
+    tok[i+1] = strchr(tok[i], ' ');
+    if (!tok[i+1])
+      return ACPI_EVENT_IGNORE;
+    *(tok[i+1]) = '\0';
+    tok[i+1]++;
+  }
+  
+  if (!strcmp(tok[0], "ac_adapter"))
+    return ACPI_EVENT_AC;
+  if (!strcmp(tok[0], "battery") && atoi(tok[2]) == 81)
+    return ACPI_EVENT_BATTERY_INFO;
+
+  return ACPI_EVENT_IGNORE;
+}
+
+/* Handles a new ACPI event by reading it from the event file
+ * and calling any handlers.  Since this does a blocking read,
+ * it should only be called when there is a new event as indicated
+ * by select(). */
+gboolean acpi_process_event(struct acpi_info * acpiinfo)
+{
+    int i;
+    int evt;
+    char * s;
+    char str[256];
+    gboolean result = FALSE;
+
+    i = read(acpiinfo->event_fd, str, sizeof(str)-1);
+    str[i] = '\0';
+    s = str;
+    while ((evt = parse_acpi_event(s, &s)) != ACPI_EVENT_DONE) {
+      switch (evt) {
+        case ACPI_EVENT_AC:
+          update_ac_info(acpiinfo);
+          result = TRUE;
+          break;
+        case ACPI_EVENT_BATTERY_INFO:
+          update_battery_info(acpiinfo);
+          result = TRUE;
+          break;
+      }
+    }
+
+    return result;
+}
+
+/*
+ * Fills out a classic apm_info structure with the data gathered from
+ * the ACPI kernel interface in /proc
+ */
+gboolean acpi_linux_read(struct apm_info *apminfo, struct acpi_info * acpiinfo)
+{
+  guint32 remain;
+  gboolean charging;
+  GHashTable *hash;
+  char batt_state[60];
+  DIR * procdir;
+  struct dirent * procdirentry;
+  char buf[BUFSIZ];
+
+  g_assert(acpiinfo);
+
+  /*
+   * apminfo.ac_line_status must be one when on ac power
+   * apminfo.battery_status must be 0 for high, 1 for low, 2 for critical, 3 for charging
+   * apminfo.battery_percentage must contain batter charge percentage
+   * apminfo.battery_flags & 0x8 must be nonzero when charging
+   */
+  
+  g_assert(apminfo);
+
+  charging = FALSE;
+  remain = 0;
+
+  procdir=opendir("/proc/acpi/battery/");
   if (!procdir)
     return FALSE;
 
+  /* Get the remaining capacity for the batteries.  Other information
+   * such as AC state and battery max capacity are read only when they
+   * change using acpi_process_event(). */
   while ((procdirentry=readdir(procdir)))
    {
     if (procdirentry->d_name[0]!='.')
      {
-      strcpy(ac_state,"/proc/acpi/ac_adapter/");
-      strcat(ac_state,procdirentry->d_name);
-      strcat(ac_state,"/");
-      strcat(ac_state,ac_state_state);
-      hash = read_file (ac_state, buf, sizeof (buf));
-      if (hash && !ac_online)
+      strcpy(batt_state,"/proc/acpi/battery/");
+      strcat(batt_state,procdirentry->d_name);
+      strcat(batt_state,"/");
+      strcat(batt_state,acpiinfo->batt_state_state);
+      hash = read_file (batt_state, buf, sizeof (buf));
+      if (hash)
        {
         const char *s;
-        s = read_string (hash, ac_state_state);
-        ac_online = s ? (strcmp (s, "on-line") == 0) : 0;
+        if (!charging)
+         {
+          s = read_string (hash, acpiinfo->charging_state);
+          charging = s ? (strcmp (s, "charging") == 0) : 0;
+         }
+        remain += read_long (hash, "remaining capacity");
         g_hash_table_destroy (hash);
        }
      }
    }
   closedir(procdir);
 
-  apminfo->ac_line_status = ac_online ? 1 : 0;
-  apminfo->battery_status = remain < low_capacity ? 1 : remain < critical_capacity ? 2 : 0;
-  apminfo->battery_percentage = (int) (remain/(float)max_capacity*100);
+  apminfo->ac_line_status = acpiinfo->ac_online ? 1 : 0;
+  apminfo->battery_status = remain < acpiinfo->low_capacity ? 1 : remain < acpiinfo->critical_capacity ? 2 : 0;
+  if (!acpiinfo->max_capacity)
+    apminfo->battery_percentage = -1;
+  else
+    apminfo->battery_percentage = (int) (remain/(float)acpiinfo->max_capacity*100);
   apminfo->battery_flags = charging ? 0x8 : 0;
 
   return TRUE;
 }
 
+
 #endif
diff -urN battstat.orig/acpi-linux.h battstat/acpi-linux.h
--- battstat.orig/acpi-linux.h	2001-11-04 18:41:22.000000000 -0500
+++ battstat/acpi-linux.h	2003-09-07 16:30:45.000000000 -0400
@@ -19,6 +19,19 @@
 #ifndef __ACPI_LINUX_H__
 #define __ACPI_LINUX_H__
 
-gboolean acpi_linux_read(struct apm_info *apminfo);
+struct acpi_info {
+  const char *ac_state_state, *batt_state_state, *charging_state;
+  gboolean  ac_online;
+  int       event_fd;
+  int       max_capacity;
+  int       low_capacity;
+  int       critical_capacity;
+  GIOChannel  * channel;
+};
+
+gboolean acpi_linux_read(struct apm_info *apminfo, struct acpi_info * acpiinfo);
+gboolean acpi_process_event(struct acpi_info * acpiinfo);
+gboolean acpi_linux_init(struct acpi_info * acpiinfo);
+void acpi_linux_cleanup(struct acpi_info * acpiinfo);
 
 #endif /* __ACPI_LINUX_H__ */
diff -urN battstat.orig/battstat_applet.c battstat/battstat_applet.c
--- battstat.orig/battstat_applet.c	2003-07-23 22:02:45.000000000 -0400
+++ battstat/battstat_applet.c	2003-09-07 17:52:43.000000000 -0400
@@ -221,9 +221,15 @@
 struct apm_info apminfo;
 #endif
 
+#ifdef __linux__
+struct acpi_info acpiinfo;
+gboolean using_acpi;
+int acpi_count;
+#endif
+
 #ifdef __FreeBSD__
 void
-apm_readinfo (PanelApplet *applet)
+apm_readinfo (PanelApplet *applet, ProgressData * battstat)
 {
   /* This is how I read the information from the APM subsystem under
      FreeBSD.  Each time this functions is called (once every second)
@@ -242,7 +248,7 @@
 }
 #elif __OpenBSD__
 void
-apm_readinfo (PanelApplet *applet)
+apm_readinfo (PanelApplet *applet, ProgressData * battstat)
 {
   /* Code for OpenBSD by Joe Ammond <jra@twinight.org>. Using the same
      procedure as for FreeBSD.
@@ -259,10 +265,27 @@
 #elif __linux__
 
 // Declared in acpi-linux.c
-gboolean acpi_linux_read(struct apm_info *apminfo);
+gboolean acpi_linux_read(struct apm_info *apminfo, struct acpi_info *acpiinfo);
+
+gboolean acpi_callback (GIOChannel * chan, GIOCondition cond, gpointer data)
+{
+  ProgressData * battstat = (ProgressData *) data;
+
+  if (cond & (G_IO_ERR | G_IO_HUP)) {
+    acpi_linux_cleanup(&acpiinfo);
+    apminfo.battery_percentage = -1;
+    return FALSE;
+  }
+  
+  if (acpi_process_event(&acpiinfo)) {
+    acpi_linux_read(&apminfo, &acpiinfo);
+    pixmap_timeout(data);
+  }
+  return TRUE;
+}
 
 void
-apm_readinfo (PanelApplet *applet)
+apm_readinfo (PanelApplet *applet, ProgressData * battstat)
 {
   /* Code for Linux by Thomas Hood <jdthood@mail.com>. apm_read() will
      read from /proc/... instead and we do not need to open the device
@@ -270,14 +293,34 @@
   */
   if (DEBUG) g_print("apm_readinfo() (Linux)\n");
 
-  // ACPI support added by Lennart Poettering <lennart@poettering.de> 10/27/2001
-  // First try ACPI kernel interface, than fall back on APM
-  if (!acpi_linux_read(&apminfo))
+  /* ACPI support added by Lennart Poettering <lennart@poettering.de> 10/27/2001
+   * Updated by David Moore <dcm@acm.org> 5/29/2003 to poll less and
+   *   use ACPI events. */
+  if (using_acpi && acpiinfo.event_fd >= 0) {
+    if (acpi_count <= 0) {
+      /* Only call this one out of 30 calls to apm_readinfo() (every 30 seconds)
+       * since reading the ACPI system takes CPU cycles. */
+      acpi_count=30;
+      acpi_linux_read(&apminfo, &acpiinfo);
+    }
+    acpi_count--;
+  }
+  /* If we lost the file descriptor with ACPI events, try to get it back. */
+  else if (using_acpi) {
+      if (acpi_linux_init(&acpiinfo)) {
+          battstat->acpiwatch = g_io_add_watch (acpiinfo.channel,
+              G_IO_IN | G_IO_ERR | G_IO_HUP,
+              acpi_callback, battstat);
+          acpi_linux_read(&apminfo, &acpiinfo);
+      }
+  }
+  else
     apm_read(&apminfo);
 }
+
 #else
 void
-apm_readinfo (PanelApplet *applet)
+apm_readinfo (PanelApplet *applet, ProgressData * battstat)
 {
   g_print("apm_readinfo() (Generic)\n");
   g_print(
@@ -342,7 +385,7 @@
       3 = Charging
   */
 
-   apm_readinfo (PANEL_APPLET (battery->applet));
+   apm_readinfo (PANEL_APPLET (battery->applet), battery);
    batterypresent = TRUE;
 #ifdef __FreeBSD__
    acline_status = apminfo.ai_acline ? 1 : 0;
@@ -682,6 +725,14 @@
    gdk_bitmap_unref(pdata->masky);
    gdk_bitmap_unref(pdata->pixmask);
 
+#ifdef __linux__
+   if (using_acpi) {
+     g_source_remove(pdata->acpiwatch);
+     pdata->acpiwatch = 0;
+     acpi_linux_cleanup(&acpiinfo);
+   }
+#endif
+
    if (pdata->suspend_cmd)
    	g_free (pdata->suspend_cmd);
    
@@ -892,7 +943,7 @@
    
    if (DEBUG) g_print("change_orient()\n");
 
-   apm_readinfo(PANEL_APPLET (applet));
+   apm_readinfo(PANEL_APPLET (applet), battstat);
 #ifdef __FreeBSD__
    acline_status = apminfo.ai_acline ? 1 : 0;
    batt_state = apminfo.ai_batt_stat;
@@ -1457,6 +1508,7 @@
 battstat_applet_fill (PanelApplet *applet)
 {
   ProgressData *battstat;
+  struct stat statbuf;
 
   if (DEBUG) g_print("main()\n");
   
@@ -1465,8 +1517,29 @@
   panel_applet_add_preferences (applet, "/schemas/apps/battstat-applet/prefs", NULL);
   panel_applet_set_flags (applet, PANEL_APPLET_EXPAND_MINOR);
 
-  apm_readinfo (applet);
-  
+#ifdef __linux__
+  if (acpi_linux_init(&acpiinfo)) {
+    using_acpi = TRUE;
+    acpi_count = 0;
+  }
+  else
+    using_acpi = FALSE;
+
+  /* If neither ACPI nor APM could be read, but ACPI does seem to be
+   * installed, warn the user how to get ACPI working. */
+  if (!using_acpi && (apm_exists() == 1) &&
+          (stat("/proc/acpi", &statbuf) == 0)) {
+      battstat_error_dialog (
+	       applet,
+	       _("Can't access ACPI events in /var/run/acpid.socket!\n\n"
+		 "Make sure the ACPI subsystem is working and\n"
+		 "the acpid daemon is running."));
+      using_acpi = TRUE;
+      acpi_count = 0;
+  }
+#endif
+  apm_readinfo (applet, NULL);
+
 #ifdef __FreeBSD__
   if(apminfo.ai_status == 0) cleanup (applet, 2);
 #endif
@@ -1500,6 +1573,14 @@
   change_orient (applet, battstat->orienttype, battstat );
 
   battstat->pixtimer = gtk_timeout_add (1000, pixmap_timeout, battstat);
+#ifdef __linux__
+  /* Watch for ACPI events and handle them immediately with acpi_callback(). */
+  if (using_acpi && acpiinfo.event_fd >= 0) {
+    battstat->acpiwatch = g_io_add_watch (acpiinfo.channel,
+        G_IO_IN | G_IO_ERR | G_IO_HUP,
+        acpi_callback, battstat);
+  }
+#endif
 
   gtk_container_add (GTK_CONTAINER (battstat->applet), battstat->hbox1);
 
diff -urN battstat.orig/battstat.h battstat/battstat.h
--- battstat.orig/battstat.h	2003-07-23 22:02:45.000000000 -0400
+++ battstat/battstat.h	2003-09-07 17:18:38.000000000 -0400
@@ -118,6 +118,7 @@
   GtkObject *eorange_adj;
   GtkObject *eyellow_adj;
   int pixtimer;
+  int acpiwatch;
   GtkWidget *font_toggle;
   GtkWidget *lowbatt_toggle;
   GtkWidget *dock_toggle;
@@ -154,7 +155,7 @@
 void prop_cb (BonoboUIComponent *, ProgressData *, const char *);
 int prop_cancel (GtkWidget *, gpointer);
 
-void apm_readinfo(PanelApplet *);
+void apm_readinfo(PanelApplet *, ProgressData *);
 void adj_value_changed_cb(GtkAdjustment *, gpointer);
 void font_set_cb(GtkWidget *, int, gpointer);
 void simul_cb(GtkWidget *, gpointer);
diff -urN battstat.orig/properties.c battstat/properties.c
--- battstat.orig/properties.c	2003-07-23 22:02:45.000000000 -0400
+++ battstat/properties.c	2003-09-07 17:18:56.000000000 -0400
@@ -334,7 +334,7 @@
   guint      percentage;
   gboolean   writable;
 
-  apm_readinfo (PANEL_APPLET (battstat->applet));
+  apm_readinfo (PANEL_APPLET (battstat->applet), battstat);
 
 #ifdef __FreeBSD__
   percentage = apminfo.ai_batt_life;
