From 18a2f4aa3ba2c8c9fc3718b15a9ab366fdd35f05 Mon Sep 17 00:00:00 2001 From: Joachim Breitner Date: Mon, 5 Jul 2010 12:20:04 +0200 Subject: [PATCH] [battstat applet] upower support As HAL is being deprecated, the battstat applet is adjusted to talk to upower, using libupower-glib. (Bug #607254) --- battstat/Makefile.am | 6 +- battstat/battstat-upower.c | 330 +++++++++++++++++++++++++++++++++++++++++ battstat/battstat-upower.h | 33 ++++ battstat/battstat_applet.c | 7 +- battstat/docs/C/battstat.xml | 18 ++- battstat/docs/de/battstat.xml | 22 +++- battstat/docs/eu/battstat.xml | 20 ++- battstat/power-management.c | 66 +++++++-- configure.in | 22 +++ 9 files changed, 493 insertions(+), 31 deletions(-) create mode 100644 battstat/battstat-upower.c create mode 100644 battstat/battstat-upower.h Index: gnome-applets-3.4.1/battstat/Makefile.am =================================================================== --- gnome-applets-3.4.1.orig/battstat/Makefile.am 2012-04-13 19:02:29.000000000 +0200 +++ gnome-applets-3.4.1/battstat/Makefile.am 2012-04-19 00:28:17.246029051 +0200 @@ -27,6 +27,7 @@ $(GNOME_APPLETS_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(HAL_CFLAGS) \ + $(UPOWER_CFLAGS) \ $(APMINC) \ $(ACPIINC) \ $(WARN_CFLAGS) \ @@ -48,13 +49,17 @@ acpi-freebsd.c \ acpi-freebsd.h \ battstat-hal.c \ - battstat-hal.h + battstat-hal.h \ + battstat-upower.c \ + battstat-upower.h battstat_applet_2_LDADD = \ $(GNOME_APPLETS_LIBS) \ $(LIBNOTIFY_LIBS) \ $(HAL_LIBS) \ + $(UPOWER_LIBS) \ + $(LIBM) \ $(APMLIB) schemasdir = @GCONF_SCHEMA_FILE_DIR@ Index: gnome-applets-3.4.1/battstat/battstat-upower.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gnome-applets-3.4.1/battstat/battstat-upower.c 2012-04-19 00:28:17.246029051 +0200 @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2010 by Joachim Breitner + * + * Based on battstat-hal.c: + * Copyright (C) 2005 by Ryan Lortie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include + +#ifdef HAVE_UPOWER + +#include +#include + +#include "battstat-upower.h" + +static UpClient *upc; +static void (*status_updated_callback) (void); + + +/* status_updated_callback() can not be called directly because at the time of + * the device-remove signal, the device is not actually removed from the list + * of devices known to the up_client object (see libupower-glib/up-client.c in + * upower). Waiting for the next idle timer works around this issue and has has + * the additionaly benefit of possibly running status_updated_callback only + * once when several events happen very soon after each other. + */ +static gboolean status_update_scheduled; + +static gboolean +update_status_idle (gpointer junk) +{ + if (status_updated_callback) + status_updated_callback (); + + return status_update_scheduled = FALSE; +} + +static void +schedule_status_callback (void) +{ + if (status_update_scheduled) + return; + + status_update_scheduled = TRUE; + g_idle_add (update_status_idle, NULL); +} + +static void +device_cb (UpClient *client, UpDevice *device, gpointer user_data) { + schedule_status_callback(); +} + +/* ---- public functions ---- */ + +char * +battstat_upower_initialise (void (*callback) (void)) +{ + status_updated_callback = callback; + + if( upc != NULL ) + return g_strdup( "Already initialised!" ); + + if( (upc = up_client_new() ) == NULL ) + goto error_out; + + if (! up_client_enumerate_devices_sync( upc, NULL, NULL ) ) { + goto error_shutdownclient; + } + + g_signal_connect_after( upc, "device-changed", device_cb, NULL ); + g_signal_connect_after( upc, "device-added", device_cb, NULL ); + g_signal_connect_after( upc, "device-removed", device_cb, NULL ); + + return NULL; + +error_shutdownclient: + g_object_unref( upc ); + upc = NULL; + +error_out: + return "Can not initialize upower"; +} + +void +battstat_upower_cleanup( void ) +{ + if( upc == NULL ) + return; + + g_object_unref( upc ); + upc = NULL; +} + +#include "battstat.h" + +/* This function currently exists to allow the multiple batteries supported + * by the upower backend to appear as a single composite battery device (since + * at the current time this is all that battstat supports). + * + * This entire function is filled with logic to make multiple batteries + * appear as one "composite" battery. Comments included as appropriate. + * + * For more information about some of the assumptions made in the following + * code please see the following mailing list post and the resulting thread: + * + * http://lists.freedesktop.org/archives/hal/2005-July/002841.html + */ +void +battstat_upower_get_battery_info( BatteryStatus *status ) +{ + + GPtrArray *devices = up_client_get_devices( upc ); + + /* The calculation to get overall percentage power remaining is as follows: + * + * Sum( Current charges ) / Sum( Full Capacities ) + * + * We can't just take an average of all of the percentages since this + * doesn't deal with the case that one battery might have a larger + * capacity than the other. + * + * In order to do this calculation, we need to keep a running total of + * current charge and full capacities. + */ + double current_charge_total = 0, full_capacity_total = 0; + + /* Record the time remaining as reported by upower. This is used in the event + * that the system has exactly one battery (since, then, upower is capable + * of providing an accurate time remaining report and we should trust it.) + */ + gint64 remaining_time = 0; + + /* The total (dis)charge rate of the system is the sum of the rates of + * the individual batteries. + */ + double rate_total = 0; + + /* We need to know if we should report the composite battery as present + * at all. The logic is that if at least one actual battery is installed + * then the composite battery will be reported to exist. + */ + int present = 0; + + /* We need to know if we are on AC power or not. Eventually, we can look + * at the AC adaptor upower devices to determine that. For now, we assume that + * if any battery is discharging then we must not be on AC power. Else, by + * default, we must be on AC. + */ + int on_ac_power = 1; + + /* Finally, we consider the composite battery to be "charging" if at least + * one of the actual batteries in the system is charging. + */ + int charging = 0; + + /* For each physical battery bay... */ + int i; + for( i = 0; i < devices->len; i++ ) + { + UpDevice *upd = g_ptr_array_index( devices, i ); + + int type, state; + double current_charge, full_capacity, rate; + gint64 time_to_full, time_to_empty; + + g_object_get( upd, + "kind", &type, + "state", &state, + "energy", ¤t_charge, + "energy-full", &full_capacity, + "energy-rate", &rate, + "time-to-full", &time_to_full, + "time-to-empty", &time_to_empty, + NULL ); + + /* Only count batteries here */ + + if (type != UP_DEVICE_KIND_BATTERY) + continue; + + /* At least one battery present -> composite battery is present. */ + present++; + + /* At least one battery charging -> composite battery is charging. */ + if( state == UP_DEVICE_STATE_CHARGING ) + charging = 1; + + /* At least one battery is discharging -> we're not on AC. */ + if( state == UP_DEVICE_STATE_DISCHARGING ) + on_ac_power = 0; + + /* Sum the totals for current charge, design capacity, (dis)charge rate. */ + current_charge_total += current_charge; + full_capacity_total += full_capacity; + rate_total += rate; + + /* Record remaining time too, incase this is the only battery. */ + remaining_time = (state == UP_DEVICE_STATE_DISCHARGING ? time_to_empty : time_to_full); + } + + if( !present || full_capacity_total <= 0 || (charging && !on_ac_power) ) + { + /* Either no battery is present or something has gone horribly wrong. + * In either case we must return that the composite battery is not + * present. + */ + status->present = FALSE; + status->percent = 0; + status->minutes = -1; + status->on_ac_power = TRUE; + status->charging = FALSE; + + g_ptr_array_unref( devices ); + return; + } + + /* Else, our composite battery is present. */ + status->present = TRUE; + + /* As per above, overall charge is: + * + * Sum( Current charges ) / Sum( Full Capacities ) + */ + status->percent = ( current_charge_total / full_capacity_total ) * 100.0 + 0.5; + + if( present == 1 ) + { + /* In the case of exactly one battery, report the time remaining figure + * from upower directly since it might have come from an authorative source + * (ie: the PMU or APM subsystem). + * + * upower gives remaining time in seconds with a 0 to mean that the + * remaining time is unknown. Battstat uses minutes and -1 for + * unknown time remaining. + */ + + if( remaining_time == 0 ) + status->minutes = -1; + else + status->minutes = (remaining_time + 30) / 60; + } + /* Rest of cases to deal with multiple battery systems... */ + else if( !on_ac_power && rate_total != 0 ) + { + /* Then we're discharging. Calculate time remaining until at zero. */ + + double remaining; + + remaining = current_charge_total; + remaining /= rate_total; + status->minutes = (int) floor( remaining * 60.0 + 0.5 ); + } + else if( charging && rate_total != 0 ) + { + /* Calculate time remaining until charged. For systems with more than + * one battery, this code is very approximate. The assumption is that if + * one battery reaches full charge before the other that the other will + * start charging faster due to the increase in available power (similar + * to how a laptop will charge faster if you're not using it). + */ + + double remaining; + + remaining = full_capacity_total - current_charge_total; + if( remaining < 0 ) + remaining = 0; + remaining /= rate_total; + + status->minutes = (int) floor( remaining * 60.0 + 0.5 ); + } + else + { + /* On AC power and not charging -or- rate is unknown. */ + status->minutes = -1; + } + + /* These are simple and well-explained above. */ + status->charging = charging; + status->on_ac_power = on_ac_power; + + g_ptr_array_unref( devices ); +} + +#endif /* HAVE_UPOWER */ Index: gnome-applets-3.4.1/battstat/battstat-upower.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gnome-applets-3.4.1/battstat/battstat-upower.h 2012-04-19 00:28:17.254029051 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 by Joachim Breitner + * + * Based on battstat-hal.h: + * Copyright (C) 2005 by Ryan Lortie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef _battstat_upower_h_ +#define _battstat_upower_h_ + +char *battstat_upower_initialise (void (*) (void)); +void battstat_upower_cleanup (void); + +#include "battstat.h" +void battstat_upower_get_battery_info (BatteryStatus *status); + +#endif /* _battstat_upower_h_ */ Index: gnome-applets-3.4.1/battstat/battstat_applet.c =================================================================== --- gnome-applets-3.4.1.orig/battstat/battstat_applet.c 2012-04-13 19:02:29.000000000 +0200 +++ gnome-applets-3.4.1/battstat/battstat_applet.c 2012-04-19 00:28:17.254029051 +0200 @@ -1188,9 +1188,12 @@ char *comments = g_strdup_printf ("%s\n\n%s", _("This utility shows the status of your laptop battery."), - power_management_using_hal () ? + power_management_using_upower () ? + /* true */ _("upower backend enabled.") : + (power_management_using_hal () ? /* true */ _("HAL backend enabled.") : - /* false */ _("Legacy (non-HAL) backend enabled.")); + /* false */ _("Legacy (non-HAL) backend enabled.") + )); gtk_show_about_dialog( NULL, "version", VERSION, Index: gnome-applets-3.4.1/battstat/docs/C/battstat.xml =================================================================== --- gnome-applets-3.4.1.orig/battstat/docs/C/battstat.xml 2012-04-15 15:49:58.000000000 +0200 +++ gnome-applets-3.4.1/battstat/docs/C/battstat.xml 2012-04-19 00:28:17.254029051 +0200 @@ -226,10 +226,13 @@ Power Management Backends - The battery monitor supports a number of power management backends. If it - is available, the monitor will attempt to use the freedesktop.org - HAL (Hardware Abstraction - Layer). If it is unavailable or unsupported on your platform, the + The battery monitor supports a number of power management backends. + If it is available, the monitor will attempt to use the freedesktop.org + upower interface. + If it is unavailable or unsupported on your platform, it will fall back + to the freedesktop.org + HAL (Hardware + Abstraction Layer). If that is also not availble, the battery monitor will attempt direct access to the power management system. @@ -410,10 +413,10 @@ Determining the backend - If you are using the Hardware Abstraction Layer - (see ) then that will be - indicated in the about dialog by placing a star next to the author of the - HAL backend. + If you are using the upower interface, or the the Hardware + Abstraction Layer (see ) then + that will be indicated in the about dialog by placing a star next to the + author of the HAL backend.
Check you're using the HAL backend Index: gnome-applets-3.4.1/battstat/power-management.c =================================================================== --- gnome-applets-3.4.1.orig/battstat/power-management.c 2012-04-13 19:02:29.000000000 +0200 +++ gnome-applets-3.4.1/battstat/power-management.c 2012-04-19 00:28:17.254029051 +0200 @@ -41,6 +41,7 @@ #include "battstat.h" #include "battstat-hal.h" +#include "battstat-upower.h" #define ERR_ACPID _("Can't access ACPI events in /var/run/acpid.socket! " \ "Make sure the ACPI subsystem is working and " \ @@ -66,6 +67,9 @@ #ifdef HAVE_HAL static int using_hal; #endif +#ifdef HAVE_UPOWER +static int using_upower; +#endif /* * What follows is a series of platform-specific apm_readinfo functions @@ -390,6 +394,14 @@ return NULL; } +#ifdef HAVE_UPOWER + if( using_upower ) + { + battstat_upower_get_battery_info( status ); + return NULL; + } +#endif + #ifdef HAVE_HAL if( using_hal ) { @@ -430,27 +442,36 @@ const char * power_management_initialise (int no_hal, void (*callback) (void)) { + char *err; + err = g_strdup( ":(" ); #ifdef __linux__ struct stat statbuf; #endif -#ifdef HAVE_HAL - char *err; +#ifdef HAVE_UPOWER + err = battstat_upower_initialise (callback); - if( no_hal ) - err = g_strdup( ":(" ); - else - err = battstat_hal_initialise (callback); - - - if( err == NULL ) /* HAL is up */ + if( err == NULL ) /* UPOWER is up */ { pm_initialised = 1; - using_hal = TRUE; + using_upower = TRUE; return NULL; + } +#endif + +#ifdef HAVE_HAL + if(! no_hal ) { + err = battstat_hal_initialise (callback); + + if( err == NULL ) /* HAL is up */ + { + pm_initialised = 1; + using_hal = TRUE; + return NULL; + } } - else - /* fallback to legacy methods */ - g_free( err ); + + /* fallback to legacy methods */ + g_free( err ); #endif #ifdef __linux__ @@ -498,6 +519,15 @@ void power_management_cleanup( void ) { +#ifdef HAVE_UPOWER + if( using_upower ) + { + battstat_upower_cleanup(); + pm_initialised = 1; + return; + } +#endif + #ifdef HAVE_HAL if( using_hal ) { @@ -525,6 +555,16 @@ } int +power_management_using_upower( void ) +{ +#ifdef HAVE_UPOWER + return using_upower; +#else + return 0; +#endif +} + +int power_management_using_hal( void ) { #ifdef HAVE_HAL Index: gnome-applets-3.4.1/configure.in =================================================================== --- gnome-applets-3.4.1.orig/configure.in 2012-04-15 15:45:36.000000000 +0200 +++ gnome-applets-3.4.1/configure.in 2012-04-19 00:28:17.254029051 +0200 @@ -23,6 +23,7 @@ LIBWNCK_REQUIRED=2.91.0 LIBNOTIFY_REQUIRED=0.7 HAL_REQUIRED=0.5.3 +UPOWER_REQUIRED=0.9.4 DBUS_REQUIRED=1.1.2 DBUS_GLIB_REQUIRED=0.74 PYGOBJECT_REQUIRED=2.26 @@ -223,6 +224,30 @@ AC_SUBST(HAL_CFLAGS) AC_SUBST(HAL_LIBS) +dnl -- check for libupower-glib (optional) -------------------------------------------- +UPOWER_CFLAGS= +UPOWER_LIBS= +AC_ARG_WITH(upower,[ --without-upower build without upower support]) + +if test "x$with_upower" != xno; then + PKG_CHECK_MODULES(UPOWER, upower-glib >= $UPOWER_REQUIRED, + HAVE_UPOWER="yes", + HAVE_UPOWER="no") + + LT_LIB_M + if test "x$HAVE_UPOWER" = "xyes"; then + AC_DEFINE(HAVE_UPOWER, 1, [UPOWER available]) + fi +else + AC_MSG_WARN(["upower support disabled"]) +fi + +AC_SUBST(UPOWER_CFLAGS) +AC_SUBST(UPOWER_LIBS) +AC_SUBST(LIBM) + + + dnl -- check for gucharmap (optional) ----------------------------------------- PKG_CHECK_MODULES([GUCHARMAP],[gucharmap-2.90 >= $GUCHARMAP3_REQUIRED], @@ -739,5 +764,6 @@ Using DBUS: $HAVE_DBUS Using NetworkManager: $HAVE_NETWORKMANAGER Using HAL: $HAVE_HAL + Using UPOWER: $HAVE_UPOWER Enabling IPv6: $have_ipv6 " >&2