diff --git a/Makefile b/Makefile index f551a61..f3b82e5 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ SRC = \ mce_proxy.c GEN_SRC = \ com.canonical.Unity.Screen.c \ - org.ayatana.indicator.power.Battery.c + org.freedesktop.UPower.Device.c # mce_inactivity.c \ # diff --git a/spec/org.ayatana.indicator.power.Battery.xml b/spec/org.ayatana.indicator.power.Battery.xml deleted file mode 100644 index 76bbfca..0000000 --- a/spec/org.ayatana.indicator.power.Battery.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - The battery's power level. Possible values: 'ok', 'low', 'very_low', 'critical' - - - - - - - - The battery's power level in percentage. - - - - - - - - Whether or not ayatana-indicator-power-service is warning the user about low battery power. - - - - - - - - Whether or not the battery is discharging - - - - - - \ No newline at end of file diff --git a/spec/org.freedesktop.UPower.Device.xml b/spec/org.freedesktop.UPower.Device.xml new file mode 100644 index 0000000..cd11841 --- /dev/null +++ b/spec/org.freedesktop.UPower.Device.xml @@ -0,0 +1,833 @@ + +]> + + + + + + Objects implementing this interface are usually discovered through + the org.freedesktop.UPower interface on + the /org/freedesktop/UPower object on + the D-Bus system bus service with the well-known + name org.freedesktop.UPower using + the + EnumerateDevices + method. + + + + +$ dbus-send --print-reply \ + --system \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower/devices/battery_BAT0 \ + org.freedesktop.DBus.Properties.GetAll \ + string:org.freedesktop.UPower.Device + +method return sender=:1.386 -> dest=:1.477 reply_serial=2 + array [ + dict entry( + string "native-path" + variant string "/sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0" + ) + dict entry( + string "vendor" + variant string "SONY" + ) + dict entry( + string "model" + variant string "42T4568" + ) + dict entry( + string "serial" + variant string "4179" + ) + dict entry( + string "update-time" + variant uint64 1226417875 + ) + dict entry( + string "type" + variant uint 2 + ) + dict entry( + string "power-supply" + variant boolean true + ) + dict entry( + string "has-history" + variant boolean true + ) + dict entry( + string "has-statistics" + variant boolean true + ) + dict entry( + string "online" + variant boolean false + ) + dict entry( + string "energy" + variant double 72.85 + ) + dict entry( + string "energy-empty" + variant double 0 + ) + dict entry( + string "energy-full" + variant double 74.55 + ) + dict entry( + string "energy-full-design" + variant double 74.88 + ) + dict entry( + string "energy-rate" + variant double 0 + ) + dict entry( + string "voltage" + variant double 16.415 + ) + dict entry( + string "time-to-empty" + variant int64 0 + ) + dict entry( + string "time-to-full" + variant int64 0 + ) + dict entry( + string "percentage" + variant double 97.7197 + ) + dict entry( + string "is-present" + variant boolean true + ) + dict entry( + string "state" + variant uint 3 + ) + dict entry( + string "is-rechargeable" + variant boolean true + ) + dict entry( + string "capacity" + variant double 100 + ) + dict entry( + string "technology" + variant uint 1 + ) + ] + + + + + Unless otherwise noted, an empty string or the value 0 in a + property on this interface means not set. + + + + + + + + + + + + Refreshes the data collected from the power source. + + + Callers will need to make sure that the daemon was started in debug mode + + if an error occured while refreshing + + + + + + + + + The type of history. + Valid types are rate or charge. + + + The amount of data to return in seconds, or 0 for all. + + + + + The approximate number of points to return. + A higher resolution is more accurate, at the expense of plotting speed. + + + + + + The history data for the power device, if the device supports history. + Data is ordered from the earliest in time, to the newest data point. + Each element contains the following members: + + + time + + The time value in seconds from the gettimeofday() method. + + + + value + + The data value, for instance the rate in W or the charge in %. + + + + state + + The state of the device, for instance charging or + discharging. + + + + + + + + + Gets history for the power device that is persistent across reboots. + + + + + + + + + + The mode for the statistics. + Valid types are charging or discharging. + + + + The statistics data for the power device. + Each element contains the following members: + + + value + + The value of the percentage point, usually in seconds + + + + accuracy + + The accuracy of the prediction in percent. + + + + + + + + + Gets statistics for the power device that may be interesting + to show on a graph in the session. + + + + + + + + + + + OS specific native path of the power source. On Linux this + is the sysfs path, for + example /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT0. Is + blank if the device is being driven by a user space + driver. + + + + + + + + + + Name of the vendor of the battery. + + + + + + + + + + Name of the model of this battery. + + + + + + + + + + Unique serial number of the battery. + + + + + + + + + + The point in time (seconds since the Epoch Jan 1, 1970 + 0:00 UTC) that data was read from the power source. + + + + + + + + + + Type of power source. + + + + 0Unknown + + + 1Line Power + + + 2Battery + + + 3Ups + + + 4Monitor + + + 5Mouse + + + 6Keyboard + + + 7Pda + + + 8Phone + + + 9Media Player + + + 10Tablet + + + 11Computer + + + 12Gaming Input + + + 13Pen + + + 14Touchpad + + + 15Modem + + + 16Network + + + 17Headset + + + 18Speakers + + + 19Headphones + + + 20Video + + + 21Other Audio + + + 22Remote Control + + + 23Printer + + + 24Scanner + + + 25Camera + + + 26Wearable + + + 27Toy + + + 28Bluetooth Genreic + + + + If the value is set to "Battery", you will need to verify that the + property power-supply + has the value "true" before considering it as a laptop battery. Otherwise it + will likely be the battery for a device of an unknown type. + + + + + + + + + + If the power device is used to supply the system. + This would be set TRUE for laptop batteries and UPS devices, + but set FALSE for wireless mice or PDAs. + + + + + + + + + + If the power device has history. + + + + + + + + + + If the power device has statistics. + + + + + + + + + + Whether power is currently being provided through line power. + This property is only valid if the property + type + has the value "line-power". + + + + + + + + + + Amount of energy (measured in Wh) currently available in + the power source. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy (measured in Wh) in the power source when + it's considered to be empty. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy (measured in Wh) in the power source when + it's considered full. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy (measured in Wh) the power source is + designed to hold when it's considered full. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Amount of energy being drained from the source, measured + in W. If positive, the source is being discharged, if + negative it's being charged. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Voltage in the Cell or being recorded by the meter. + + + + + + + + + + The number of charge cycles as defined by the TCO certification, or -1 if + that value is unknown or not applicable. + + + + + + + + + + Luminosity being recorded by the meter. + + + + + + + + + + Number of seconds until the power source is considered empty. + Is set to 0 if unknown. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Number of seconds until the power source is considered full. + Is set to 0 if unknown. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + The amount of energy left in the power source expressed as + a percentage between 0 and 100. Typically this is the same as + (energy - + energy-empty) / + (energy-full - + energy-empty). + However, some primitive power sources are capable of only + reporting percentages and in this case the energy-* + properties will be unset while this property is set. + + This property is only valid if the property + type + has the value "battery". + + + The percentage will be an approximation if the battery level + is set to something other than None. The percentage is kept for compatibility reasons. + + + + + + + + + + The temperature of the device in degrees Celsius. This property is + only valid if the property + type + has the value "battery". + + + + + + + + + + If the power source is present in the bay. + This field is required as some batteries are hot-removable, for example + expensive UPS and most laptop batteries. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + The battery power state. + + + + 0Unknown + + + 1Charging + + + 2Discharging + + + 3Empty + + + 4Fully charged + + + 5Pending charge + + + 6Pending discharge + + + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + If the power source is rechargeable. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + The capacity of the power source expressed as a percentage between 0 and 100. + The capacity of the battery will reduce with age. + A capacity value less than 75% is usually a sign that you should renew your battery. + Typically this value is the same as + (full-design / + full) * 100. + However, some primitive power sources are not capable reporting capacity + and in this case the capacity property will be unset. + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Technology used in the battery: + + + + 0Unknown + + + 1Lithium ion + + + 2Lithium polymer + + + 3Lithium iron phosphate + + + 4Lead acid + + + 5Nickel cadmium + + + 6Nickel metal hydride + + + + This property is only valid if the property + type + has the value "battery". + + + + + + + + + + Warning level of the battery: + + + + 0Unknown + + + 1None + + + 2Discharging (only for UPSes) + + + 3Low + + + 4Critical + + + 5Action + + + + + + + + + + + The level of the battery for devices which do not report a percentage but rather a coarse battery level. If the value + is None, then the device does not support coarse battery reporting, and the percentage should be used instead. + + + + 0Unknown + + + 1None (the battery does not use a coarse level of battery reporting) + + + 3Low + + + 4Critical + + + 6Normal + + + 7High + + + 8Full + + + + + + + + + + +

An icon name, following the Icon Naming Specification

+

Note that the icons might not match end-user expectations in terms of presentation relative to the amount of battery left or perceived to be left. It is recommended that front-ends use the BatteryLevel property first, if available, followed by the Percentage, to present a more realistic battery level to the user.

+
+
+
+
+
+ +
diff --git a/src/mce_battery.c b/src/mce_battery.c index 0ee896c..008b359 100644 --- a/src/mce_battery.c +++ b/src/mce_battery.c @@ -41,7 +41,7 @@ #include /* Generated headers */ -#include "org.ayatana.indicator.power.Battery.h" +#include "org.freedesktop.UPower.Device.h" #define MCE_BATTERY_STATUS_OK "ok" #define MCE_BATTERY_STATUS_LOW "low" @@ -109,23 +109,6 @@ mce_battery_check_valid( } } -static -void -mce_battery_level_update( - MceBattery* self, - gint level) -{ - MceBatteryPriv* priv = self->priv; - const guint new_level = (level < 0) ? 0 : (level > 100) ? 100 : level; - - if (self->level != new_level) { - self->level = new_level; - g_signal_emit(self, mce_battery_signals[SIGNAL_LEVEL_CHANGED], 0); - } - priv->flags |= BATTERY_HAVE_LEVEL; - mce_battery_check_valid(self); -} - static void mce_battery_status_update( @@ -155,6 +138,35 @@ mce_battery_status_update( mce_battery_check_valid(self); } +static +void +mce_battery_level_update( + MceBattery* self, + gdouble level) +{ + // values from ayatana-indicator-power/src/notifier.c + char* status; + if (level <= 2) + status = MCE_BATTERY_STATUS_CRITICAL; + else if (level <= 5) + status = MCE_BATTERY_STATUS_EMPTY; + else if (level <= 10) + status = MCE_BATTERY_STATUS_LOW; + else + status = MCE_BATTERY_STATUS_OK; + mce_battery_status_update(self, status); + + MceBatteryPriv* priv = self->priv; + const guint new_level = (level < 0) ? 0 : (level > 100) ? 100 : level; + + if (self->level != new_level) { + self->level = new_level; + g_signal_emit(self, mce_battery_signals[SIGNAL_LEVEL_CHANGED], 0); + } + priv->flags |= BATTERY_HAVE_LEVEL; + mce_battery_check_valid(self); +} + static void on_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, @@ -168,14 +180,10 @@ on_properties_changed (GDBusProxy *proxy, g_variant_iter_init (&iter, changed_properties); while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) { - if (!g_strcmp0(key, "PowerPercentage")) { - gint level; - g_variant_get (value, "i", &level); + if (!g_strcmp0(key, "Percentage")) { + gdouble level; + g_variant_get (value, "d", &level); mce_battery_level_update(MCE_BATTERY(user_data), level); - } else if (!g_strcmp0(key, "PowerLevel")) { - const char* status; - g_variant_get (value, "s", &status); - mce_battery_status_update(MCE_BATTERY(user_data), status); } g_variant_unref (value); @@ -196,16 +204,13 @@ mce_battery_query( * for the valid signal before we can connect the battery state * signal and submit the initial query. */ - if (proxy->ayatana_request && !priv->battery_ind_id) { - priv->battery_ind_id = g_signal_connect(proxy->ayatana_request, "g-properties-changed", + if (proxy->upower_request && !priv->battery_ind_id) { + priv->battery_ind_id = g_signal_connect(proxy->upower_request, "g-properties-changed", G_CALLBACK(on_properties_changed), self); } - if (proxy->ayatana_request && proxy->valid) { - const char* status = org_ayatana_indicator_power_battery_get_power_level(proxy->ayatana_request); - mce_battery_status_update(self, status); - - u_int32_t level = org_ayatana_indicator_power_battery_get_power_percentage(proxy->ayatana_request); + if (proxy->upower_request && proxy->valid) { + gdouble level = org_freedesktop_upower_device_get_percentage(proxy->upower_request); mce_battery_level_update(self, level); } } diff --git a/src/mce_charger.c b/src/mce_charger.c index 5c44c09..7e1f012 100644 --- a/src/mce_charger.c +++ b/src/mce_charger.c @@ -45,7 +45,18 @@ #define MCE_CHARGER_STATE_UNKNOWN "unknown" /* Generated headers */ -#include "org.ayatana.indicator.power.Battery.h" +#include "org.freedesktop.UPower.Device.h" + +enum upower_state { + UPOWER_STATE_UNKNOWN, + UPOWER_STATE_CHARGING, + UPOWER_STATE_DISCHARGING, + UPOWER_STATE_EMPTY, + UPOWER_STATE_FULLY_CHARGED, + UPOWER_STATE_PENDING_CHARGE, + UPOWER_STATE_PENDING_DISCHARGE, + UPOWER_STATE_COUNT +}; struct mce_charger_priv { MceProxy* proxy; @@ -102,6 +113,24 @@ mce_charger_state_update( } } +static void +mce_charger_update_charging_state ( + MceCharger* self, + enum upower_state state) +{ + gboolean discharging; + switch (state) { + case UPOWER_STATE_CHARGING: + case UPOWER_STATE_FULLY_CHARGED: + discharging = 0; + break; + default: + discharging = 1; + break; + } + mce_charger_state_update(self, discharging ? MCE_CHARGER_STATE_OFF : MCE_CHARGER_STATE_ON); +} + static void on_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, @@ -115,10 +144,10 @@ on_properties_changed (GDBusProxy *proxy, g_variant_iter_init (&iter, changed_properties); while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) { - if (!g_strcmp0(key, "IsDischarging")) { - gboolean state; - g_variant_get (value, "b", &state); - mce_charger_state_update(MCE_CHARGER(user_data), state ? MCE_CHARGER_STATE_OFF : MCE_CHARGER_STATE_ON); + if (!g_strcmp0(key, "State")) { + enum upower_state state; + g_variant_get (value, "u", &state); + mce_charger_update_charging_state(MCE_CHARGER(user_data), state); } g_variant_unref (value); @@ -139,14 +168,14 @@ mce_charger_state_query( * for the valid signal before we can connect the charger state * signal and submit the initial query. */ - if (proxy->ayatana_request && !priv->charger_state_ind_id) { - priv->charger_state_ind_id = g_signal_connect(proxy->ayatana_request, "g-properties-changed", + if (proxy->upower_request && !priv->charger_state_ind_id) { + priv->charger_state_ind_id = g_signal_connect(proxy->upower_request, "g-properties-changed", G_CALLBACK(on_properties_changed), self); } - if (proxy->ayatana_request && proxy->valid) { - gboolean state = org_ayatana_indicator_power_battery_get_is_discharging(proxy->ayatana_request); - mce_charger_state_update(self, state ? MCE_CHARGER_STATE_OFF : MCE_CHARGER_STATE_ON); + if (proxy->upower_request && proxy->valid) { + enum upower_state state = org_freedesktop_upower_device_get_state(proxy->upower_request); + mce_charger_update_charging_state(self, state); } } @@ -274,7 +303,7 @@ mce_charger_finalize( MceChargerPriv* priv = self->priv; if (priv->charger_state_ind_id) { - g_signal_handler_disconnect(priv->proxy->ayatana_request, + g_signal_handler_disconnect(priv->proxy->upower_request, priv->charger_state_ind_id); } mce_proxy_remove_handler(priv->proxy, priv->proxy_valid_id); diff --git a/src/mce_proxy.c b/src/mce_proxy.c index e2b279a..9ff7e07 100644 --- a/src/mce_proxy.c +++ b/src/mce_proxy.c @@ -39,18 +39,17 @@ /* Generated headers */ #include "com.canonical.Unity.Screen.h" -#include "org.ayatana.indicator.power.Battery.h" +#include "org.freedesktop.UPower.Device.h" GLOG_MODULE_DEFINE("mce"); struct mce_proxy_priv { GDBusConnection* bus; - GDBusConnection* session_bus; guint mce_watch_id; - guint ayatana_watch_id; + guint upower_watch_id; gboolean unity_valid; - gboolean ayatana_valid; + gboolean upower_valid; }; enum mce_proxy_signal { @@ -63,8 +62,8 @@ enum mce_proxy_signal { #define MCE_SERVICE "com.canonical.Unity.Screen" #define MCE_REQUEST_PATH "/com/canonical/Unity/Screen" -#define AYATANA_SERVICE "org.ayatana.indicator.power" -#define AYATANA_REQUEST_PATH "/org/ayatana/indicator/power/Battery" +#define UPOWER_SERVICE "org.freedesktop.UPower" +#define UPOWER_REQUEST_PATH "/org/freedesktop/UPower/devices/DisplayDevice" static guint mce_proxy_signals[SIGNAL_COUNT] = { 0 }; @@ -120,9 +119,9 @@ mce_proxy_init_check( MCE_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE, mce_name_appeared, mce_name_vanished, self, NULL); } - if (self->ayatana_request && !priv->ayatana_watch_id) { - priv->ayatana_watch_id = g_bus_watch_name_on_connection(priv->session_bus, - AYATANA_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE, + if (self->upower_request && !priv->upower_watch_id) { + priv->upower_watch_id = g_bus_watch_name_on_connection(priv->bus, + UPOWER_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE, mce_name_appeared, mce_name_vanished, self, NULL); } } @@ -150,7 +149,7 @@ mce_proxy_request_proxy_new_finished( static void -mce_proxy_request_proxy_session_new_finished( +mce_proxy_request_proxy_upower_new_finished( GObject* object, GAsyncResult* result, gpointer arg) @@ -158,12 +157,12 @@ mce_proxy_request_proxy_session_new_finished( MceProxy* self = MCE_PROXY(arg); GError* error = NULL; - GASSERT(!self->ayatana_request); - self->ayatana_request = org_ayatana_indicator_power_battery_proxy_new_finish(result, &error); - if (self->ayatana_request) { + GASSERT(!self->upower_request); + self->upower_request = org_freedesktop_upower_device_proxy_new_finish(result, &error); + if (self->upower_request) { mce_proxy_init_check(self); } else { - GERR("Failed to initialize MCE ayatana request proxy: %s", GERRMSG(error)); + GERR("Failed to initialize MCE upower request proxy: %s", GERRMSG(error)); g_error_free(error); } mce_proxy_unref(self); @@ -187,6 +186,11 @@ mce_proxy_bus_get_finished( MCE_SERVICE, MCE_REQUEST_PATH, NULL, mce_proxy_request_proxy_new_finished, mce_proxy_ref(self)); + org_freedesktop_upower_device_proxy_new(priv->bus, + G_DBUS_PROXY_FLAGS_NONE, + UPOWER_SERVICE, UPOWER_REQUEST_PATH, NULL, + mce_proxy_request_proxy_upower_new_finished, + mce_proxy_ref(self)); } else { GERR("Failed to attach to system bus: %s", GERRMSG(error)); g_error_free(error); @@ -194,31 +198,6 @@ mce_proxy_bus_get_finished( mce_proxy_unref(self); } -static -void -mce_proxy_session_bus_get_finished( - GObject* object, - GAsyncResult* result, - gpointer arg) -{ - MceProxy* self = MCE_PROXY(arg); - MceProxyPriv* priv = self->priv; - GError* error = NULL; - - priv->session_bus = g_bus_get_finish(result, &error); - if (priv->session_bus) { - org_ayatana_indicator_power_battery_proxy_new(priv->session_bus, - G_DBUS_PROXY_FLAGS_NONE, - AYATANA_SERVICE, AYATANA_REQUEST_PATH, NULL, - mce_proxy_request_proxy_session_new_finished, - mce_proxy_ref(self)); - } else{ - GERR("Failed to attach to session bus: %s", GERRMSG(error)); - g_error_free(error); - } - mce_proxy_unref(self); -} - MceProxy* mce_proxy_new() { @@ -233,8 +212,6 @@ mce_proxy_new() mce_proxy_instance = g_object_new(MCE_PROXY_TYPE, NULL); g_bus_get(G_BUS_TYPE_SYSTEM, NULL, mce_proxy_bus_get_finished, mce_proxy_ref(mce_proxy_instance)); - g_bus_get(G_BUS_TYPE_SESSION, NULL, mce_proxy_session_bus_get_finished, - mce_proxy_ref(mce_proxy_instance)); g_object_add_weak_pointer(G_OBJECT(mce_proxy_instance), (gpointer*)(&mce_proxy_instance)); } @@ -300,21 +277,18 @@ mce_proxy_finalize( if (priv->mce_watch_id) { g_bus_unwatch_name(priv->mce_watch_id); } - if (priv->ayatana_watch_id) { - g_bus_unwatch_name(priv->ayatana_watch_id); + if (priv->upower_watch_id) { + g_bus_unwatch_name(priv->upower_watch_id); } if (self->unity_request) { g_object_unref(self->unity_request); } - if (self->ayatana_request) { - g_object_unref(self->ayatana_request); + if (self->upower_request) { + g_object_unref(self->upower_request); } if (priv->bus) { g_object_unref(priv->bus); } - if (priv->session_bus) { - g_object_unref(priv->session_bus); - } G_OBJECT_CLASS(PARENT_CLASS)->finalize(object); } diff --git a/src/mce_proxy.h b/src/mce_proxy.h index f02a137..c8e329c 100644 --- a/src/mce_proxy.h +++ b/src/mce_proxy.h @@ -43,14 +43,14 @@ typedef struct mce_proxy_priv MceProxyPriv; struct _ComCanonicalUnityScreen; -struct _OrgAyatanaIndicatorPowerBattery; +struct _OrgFreedesktopUPowerDevice; typedef struct mce_proxy { GObject object; MceProxyPriv* priv; gboolean valid; struct _ComCanonicalUnityScreen* unity_request; - struct _OrgAyatanaIndicatorPowerBattery* ayatana_request; + struct _OrgFreedesktopUPowerDevice* upower_request; } MceProxy; typedef void