static const char *
apm_readinfo (BatteryStatus *status)
{
  /* Code for Linux by Thomas Hood <*****@*****.**>. apm_read() will
     read from /proc/... instead and we do not need to open the device
     ourselves.
  */
  if (DEBUG) g_print("apm_readinfo() (Linux)\n");

  /* ACPI support added by Lennart Poettering <*****@*****.**> 10/27/2001
   * Updated by David Moore <*****@*****.**> 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)) {
          acpiwatch = g_io_add_watch (acpiinfo.channel,
              G_IO_IN | G_IO_ERR | G_IO_HUP,
              acpi_callback, NULL);
          acpi_linux_read(&apminfo, &acpiinfo);
      }
  }
  else
    apm_read(&apminfo);

  status->present = TRUE;
  status->on_ac_power = apminfo.ac_line_status ? 1 : 0;
  status->percent = (guint) apminfo.battery_percentage;
  status->charging = (apminfo.battery_flags & 0x8) ? TRUE : FALSE;
  status->minutes = apminfo.battery_time;

  return NULL;
}
static gboolean acpi_callback (GIOChannel * chan, GIOCondition cond, gpointer 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);
  }
  return TRUE;
}
static gboolean
update_apm_status(t_battmon *battmon)
{
#ifdef __OpenBSD__
	struct apm_power_info apm;
#else
	struct apm_info apm;
#endif
	int charge;
	int time_remaining;
	gboolean acline;
	gchar buffer[128];

	if(battmon->method == BM_BROKEN) {
		/* See if ACPI or APM support has been enabled yet */
		if(!detect_battery_info(battmon)) return TRUE;
		if(battmon->timeoutid != 0) g_source_remove(battmon->timeoutid);
		/* Poll only once per minute if using ACPI due to a bug */
		if(battmon->method == BM_USE_ACPI) {
			battmon->timeoutid = g_timeout_add(60 * 1000, (GSourceFunc) update_apm_status, battmon);
		}
	        else {
			battmon->timeoutid = g_timeout_add(2 * 1000, (GSourceFunc) update_apm_status, battmon);
		}
	}

	/* Show initial state if using ACPI rather than waiting a minute */
	if(battmon->flag) {
		battmon->flag = FALSE;
		g_source_remove(battmon->timeoutid);
		battmon->timeoutid = g_timeout_add(60 * 1000, (GSourceFunc) update_apm_status, battmon);
	}

#ifdef __FreeBSD__
  /* This is how I read the information from the APM subsystem under
     FreeBSD.  Each time this functions is called (once every second)
     the APM device is opened, read from and then closed.
  */
  	int fd;

  	battmon->method = BM_BROKEN;
  	fd = open(APMDEVICE, O_RDONLY);
  	if (fd == -1) return TRUE;

  	if (ioctl(fd, APMIO_GETINFO, &apm) == -1)
     		return TRUE;

  	close(fd);

  	acline = apm.ai_acline ? TRUE : FALSE;
  	time_remaining = apm.ai_batt_time;
	time_remaining = time_remaining / 60; /* convert from seconds to minutes */
  	charge = apm.ai_batt_life;
#elif __OpenBSD__
  /* Code for OpenBSD by Joe Ammond <*****@*****.**>. Using the same
     procedure as for FreeBSD.
  */
  	int fd;

  	battmon->method = BM_BROKEN;
  	fd = open(APMDEVICE, O_RDONLY);
  	if (fd == -1) return TRUE;
  	if (ioctl(fd, APM_IOC_GETPOWER, &apminfo) == -1)
    		return TRUE;
  	close(fd);
  	charge = apm.battery_life;
  	time_remaining = apm.minutes_left;
  	acline = apm.ac_state ? TRUE : FALSE;
#elif __linux__
	if(battmon->method == BM_USE_ACPI) acpi_linux_read(&apm);
	else apm_read(&apm);	/* not broken and not using ACPI, assume APM */
	charge = apm.battery_percentage;
	if(battmon->method == BM_USE_ACPI) time_remaining = 0; /* no such info for ACPI :( */
	else time_remaining = apm.battery_time;
	acline = apm.ac_line_status ? TRUE : FALSE;
#endif
	
	if(charge < 0) charge = 0;
	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(battmon->battstatus), charge / 100.0);

	if(battmon->options.tooltip_display_percentage && battmon->options.tooltip_display_time) {
		if(acline) 
			g_snprintf(buffer, sizeof(buffer), _("%d%% (AC on-line)"), charge);
		else if(time_remaining > 0)
			g_snprintf(buffer, sizeof(buffer), _("%d%% (%d:%.2d) remaining"), charge, time_remaining / 60, time_remaining % 60);
		else
			g_snprintf(buffer, sizeof(buffer), _("%d%% (AC off-line)"), charge);

		add_tooltip(battmon->ebox, buffer);
	}
	else if(battmon->options.tooltip_display_percentage) {
		g_snprintf(buffer, sizeof(buffer), _("%d%%"), charge);
		add_tooltip(battmon->ebox, buffer);
	}
	else if(battmon->options.tooltip_display_time) {
		if(acline) 
			g_snprintf(buffer, sizeof(buffer), _("AC on-line"));
		else if(time_remaining > 0)
			g_snprintf(buffer, sizeof(buffer), _("%d:%.2d remaining"), time_remaining / 60, time_remaining % 60);
		else
			g_snprintf(buffer, sizeof(buffer), _("AC off-line"));

		add_tooltip(battmon->ebox, buffer);
	}
	else add_tooltip(battmon->ebox, NULL);

	if(battmon->options.display_percentage) {
		g_snprintf(buffer, sizeof(buffer), _("%d%%"), charge);
		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(battmon->battstatus), buffer);	
	}
	else gtk_progress_bar_set_text(GTK_PROGRESS_BAR(battmon->battstatus), NULL);

	if(!battmon->critical && charge <= battmon->options.critical_percentage) {
		battmon->critical = TRUE;
		battmon->low = TRUE;
		if(battmon->options.action_on_critical == BM_MESSAGE)
			xfce_warn(_("WARNING: Your battery has reached critical status. You should plug in or shutdown your computer now to avoid possible data loss."));
		if(battmon->options.action_on_critical == BM_COMMAND) {
			if(battmon->options.command_on_critical && battmon->options.command_on_critical[0])
				exec_cmd(battmon->options.command_on_critical, 0, 0);
		}
		if(battmon->options.action_on_critical == BM_COMMAND_TERM) {
			if(battmon->options.command_on_critical && battmon->options.command_on_critical[0])
				exec_cmd(battmon->options.command_on_critical, 1, 0);
		}
	}
	else if(battmon->critical && charge > battmon->options.critical_percentage)
		battmon->critical = FALSE;

	if(!battmon->low && charge <= battmon->options.low_percentage) {
		battmon->low = TRUE;
		if(battmon->options.action_on_low == BM_MESSAGE)
			xfce_warn(_("WARNING: Your battery is running low. You should consider plugging in or shutting down your computer soon to avoid possible data loss."));
		if(battmon->options.action_on_low == BM_COMMAND) {
			if(battmon->options.command_on_low && battmon->options.command_on_low[0])
				exec_cmd(battmon->options.command_on_low, 0, 0);
		}
		if(battmon->options.action_on_low == BM_COMMAND_TERM) {
			if(battmon->options.command_on_low && battmon->options.command_on_low[0])
				exec_cmd(battmon->options.command_on_low, 1, 0);
		}
	}
	else if(battmon->low && charge > battmon->options.low_percentage)
		battmon->low = FALSE;

	return TRUE;
}
gboolean
detect_battery_info(t_battmon *battmon)
{
#ifdef __OpenBSD__
	struct apm_power_info apm;
#else
	struct apm_info apm;
#endif

#ifdef __FreeBSD__
  /* This is how I read the information from the APM subsystem under
     FreeBSD.  Each time this functions is called (once every second)
     the APM device is opened, read from and then closed.
  */
  	int fd;

	battmon->method = BM_BROKEN;
  	fd = open(APMDEVICE, O_RDONLY);
  	if (fd == -1) return FALSE;

  	if (ioctl(fd, APMIO_GETINFO, &apm) == -1)
     		return FALSE;

  	close(fd);
  	battmon->method = BM_USE_APM;

  	return TRUE;
#elif __OpenBSD__
  /* Code for OpenBSD by Joe Ammond <*****@*****.**>. Using the same
     procedure as for FreeBSD.
  */
  	int fd;

  	battmon->method = BM_BROKEN;
  	fd = open(APMDEVICE, O_RDONLY);
  	if (fd == -1) return FALSE;
  	if (ioctl(fd, APM_IOC_GETPOWER, &apm) == -1)
    		return FALSE;
  	close(fd);
  	battmon->method = BM_USE_APM;
  
  	return TRUE;
#elif __linux__
	/* First check to see if ACPI is available */
	if(acpi_linux_read(&apm)) {
		/* ACPI detected and working */
		battmon->method = BM_USE_ACPI;
		return TRUE;
	}
	if(apm_read(&apm) == 0) {
		/* ACPI not detected, but APM works */
		battmon->method = BM_USE_APM;
		return TRUE;
	}

	/* Neither ACPI or APM detected/working */
	battmon->method = BM_BROKEN;

	return FALSE;
#endif	
}