Re: ACPI support for battery_applet.



On Tue, 2001-12-11 at 14:21, Justin Buist wrote:
> 
> Most every patch I've seen to put ACPI support into battery_applet only assumed
> that the user would have one battery, so I put together one that should
> accomodate as many batteries as possible.  If APM is there it falls back
> to ACPI rather than have to pick APM or ACPI at compile time.  It's working
> for me, though I admit the CPU usage seems a bit high on it right now.

i've got some acpi code for an applet i wrote over thanksgiving which i
haven't released yet.

the code is very simple; i've attached it in case you want to use it in
a patch to battstat.

jacob
-- 
"In fact, can you imagine anything more terrifying than a zombie clown?"
	-- moby
/*
 * acpi-battery.c: stuff for reading battery status from acpi
 *
 * Copyright 2001 jacob berkman
 *
 * Authors: jacob berkman  <jacob ximian com>
 *
 */

#define _GNU_SOURCE

#include <config.h>

#include "grungy-acpi-applet.h"

#include "thermometer-applet.h"

#include <glib.h>

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>

#define BATTERY_DIR "/proc/acpi/battery"

typedef enum {
	BATTERY_UNKNOWN,
	BATTERY_DISCHARGING,
	BATTERY_CHARGING,
	BATTERY_CRITICALLY_LOW,
} BatteryState;

typedef struct {
	gboolean present;
	long design_capacity;
	long last_full_capacity;
	long remaining_capacity;
	long present_rate;
	long battery_voltage;
	BatteryState state;
} BatteryInfo;

#if 0
static int battery_changed = 1;

static void
handler (int sig, siginfo_t *si, gpointer data)
{
	battery_changed = 1;
}
#endif

#define BATT_BUFSIZE 8192

static GHashTable *
read_file (const char *bname, const char *fname, char *buf, int bufsize)
{
	GHashTable *hash = NULL;

	int fd, len, i;
	char *file;
	char *key, *value;
	gboolean reading_key;

	file = g_strdup_printf (BATTERY_DIR "/%s/%s", bname, fname);
	fd = open (file, O_RDONLY);

	if (fd == -1) {
		g_message ("Couldn't open %s: %s", file, g_strerror (errno));
		g_free (file);
		return hash;
	}

	len = read (fd, buf, bufsize);

	close (fd);

	if (len < 0) {
		g_message ("Error reading %s: %s", file, g_strerror (errno));
		g_free (file);
		return hash;
	}

	hash = g_hash_table_new (g_str_hash, g_str_equal);

	for (i = 0, value = key = buf, reading_key = TRUE; i < len; i++) {
		if (buf[i] == ':' && reading_key) {
			reading_key = FALSE;
			buf[i] = '\0';
			value = buf + i + 1;
		} else if (buf[i] == '\n') {
			reading_key = TRUE;
			buf[i] = '\0';
			/* g_message ("Read: %s => %s\n", key, value); */
			g_hash_table_insert (hash, key, g_strstrip (value));
			key = buf + i + 1;
		}
	}

	return hash;
}

static gboolean
read_bool (GHashTable *hash, const char *key)
{
	char *s;

	g_return_val_if_fail (hash, FALSE);
	g_return_val_if_fail (key, FALSE);

	s = g_hash_table_lookup (hash, key);
	return s && (*s == 'y');
}

static long
read_long (GHashTable *hash, const char *key)
{
	char *s;

	g_return_val_if_fail (hash, FALSE);
	g_return_val_if_fail (key, FALSE);

	s = g_hash_table_lookup (hash, key);
	return s ? strtol (s, NULL, 10) : 0;
}

static BatteryState
read_state (GHashTable *hash, const char *key)
{
	BatteryState state;
	char *s;

	g_return_val_if_fail (hash, FALSE);
	g_return_val_if_fail (key, FALSE);

	s = g_hash_table_lookup (hash, key);
	if (!s)
		state = BATTERY_UNKNOWN;
	else if (!strcmp (s, "charging"))
		state = BATTERY_CHARGING;
	else if (!strcmp (s, "discharging"))
		state = BATTERY_DISCHARGING;
	else if (!strcmp (s, "critically low"))
		state = BATTERY_CRITICALLY_LOW;
	else
		state = BATTERY_UNKNOWN;

	return state;
}

static BatteryInfo *
read_battery (const char *bname)
{
	GHashTable *info, *status = NULL;
	BatteryInfo *binfo = NULL;
	char info_buf[BATT_BUFSIZE], status_buf[BATT_BUFSIZE];

	/* g_print ("reading: %s\n", bname); */

	info = read_file (bname, "info", info_buf, BATT_BUFSIZE);

	if (!info)
		goto read_battery_done;

	status = read_file (bname, "status", status_buf, BATT_BUFSIZE);
	if (!status)
		goto read_battery_done;

	binfo = g_new0 (BatteryInfo, 1);

	binfo->present            = read_bool  (info,   "Present");
	binfo->design_capacity    = read_long  (info,   "Design Capacity");
	binfo->last_full_capacity = read_long  (info,   "Last Full Capacity");
	binfo->remaining_capacity = read_long  (status, "Remaining Capacity");
	binfo->present_rate       = read_long  (status, "Present Rate");
	binfo->battery_voltage    = read_long  (status, "Battery Voltage");
	binfo->state              = read_state (status, "State");

 read_battery_done:
	if (info)
		g_hash_table_destroy (info);

	if (status)
		g_hash_table_destroy (status);

	return binfo;
}

static void
print_battery (BatteryInfo *info)
{
	static const char *state_name[] = { "Unknown", "Discharging", "Charging", "Critically Low" };

	g_print ("Present: %s\n"
		 "Charge:  %ld of %ld (%f%%)\n"
		 "State:   %s\n",
		 info->present ? "Yes" : "No",
		 info->remaining_capacity, info->design_capacity,
		 (float)info->remaining_capacity / (float)info->design_capacity,
		 state_name[info->state]);
}

static void
battery_update (ThermometerApplet *applet, gpointer data)
{
	DIR *dir;
	struct dirent *dent;
	BatteryInfo *info = NULL;
	int percent;
	char *s;

	dir = opendir (BATTERY_DIR);
	if (!dir) {
		g_message ("error opending battery dir: %s\n",
			   g_strerror (errno));
		return;
	}

	while ((dent = readdir (dir))) {
		if (*dent->d_name == '.')
			continue;

		info = read_battery (dent->d_name);
		if (info)
			break;
	}

	closedir (dir);

	if (!info)
		return;

	/* print_battery (info); */
	
	if (info->present_rate) {
		int minutes = 60 * info->remaining_capacity / info->present_rate;
		s = g_strdup_printf ("%d:%.2d", minutes / 60, minutes % 60);
	} else {
		s = g_strdup (info->state == BATTERY_CHARGING
			      ? "(AC)" : "");
	}

	percent = info->design_capacity ? 100.0 * ((float)info->remaining_capacity / info->design_capacity) : -1;

	gtk_object_set (GTK_OBJECT (applet),
			"text", s,
			"percent", percent,
			"color", info->state == BATTERY_CHARGING 
			? "black" : "red",
			NULL);
}

GtkWidget *
grungy_acpi_battery_new (const char *goad_id)
{
	GtkWidget *w;

	w = thermometer_applet_new (goad_id);
	if (!w) return NULL;

	battery_update (THERMOMETER_APPLET (w), NULL);

	gtk_object_set (GTK_OBJECT (w),
			"timeout", 10000,
			"timeout_cb", battery_update,
			NULL);

	return w;
}

#if 0
int
main (int argc, char *argv[])
{
	GIOChannel *ioc;
	struct sigaction act;
	int fd;

	act.sa_sigaction = handler;
	sigemptyset (&act.sa_mask);
	act.sa_flags = SA_SIGINFO;
	sigaction (SIGRTMIN, &act, NULL);
	
	fd = open (BATTERY_DIR, O_RDONLY);
	if (fd == -1)
		g_error ("No ACPI Support");
	fcntl (fd, F_SETSIG, SIGRTMIN);
	fcntl (fd, F_NOTIFY, DN_DELETE | DN_CREATE | DN_MULTISHOT);
	
	reload_batteries ();

	return 0;

	while (1) {
		if (battery_changed)
			reload_batteries ();
		pause ();
	}

	return 0;
}
#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]