From b5d5f5289416c1189cf73f4a3421a2207ad17663 Mon Sep 17 00:00:00 2001 From: Marius Gripsgard Date: Thu, 21 Sep 2023 04:02:57 +0200 Subject: [PATCH] treewide: Add support for ayatana battery and charger --- Makefile | 5 +- spec/org.ayatana.indicator.power.Battery.xml | 39 ++++++ src/mce_battery.c | 136 ++++++------------- src/mce_charger.c | 78 +++++------ src/mce_display.c | 10 +- src/mce_proxy.c | 81 ++++++++--- src/mce_proxy.h | 5 +- 7 files changed, 186 insertions(+), 168 deletions(-) create mode 100644 spec/org.ayatana.indicator.power.Battery.xml diff --git a/Makefile b/Makefile index 34dd6c3..f551a61 100644 --- a/Makefile +++ b/Makefile @@ -41,11 +41,12 @@ SRC = \ mce_battery.c \ mce_charger.c \ mce_display.c \ - mce_inactivity.c \ mce_proxy.c GEN_SRC = \ - com.canonical.Unity.Screen.c + com.canonical.Unity.Screen.c \ + org.ayatana.indicator.power.Battery.c +# mce_inactivity.c \ # # Directories # diff --git a/spec/org.ayatana.indicator.power.Battery.xml b/spec/org.ayatana.indicator.power.Battery.xml new file mode 100644 index 0000000..76bbfca --- /dev/null +++ b/spec/org.ayatana.indicator.power.Battery.xml @@ -0,0 +1,39 @@ + + + + + + + + + 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/src/mce_battery.c b/src/mce_battery.c index 1ce4acc..0ee896c 100644 --- a/src/mce_battery.c +++ b/src/mce_battery.c @@ -38,14 +38,16 @@ #include "mce_proxy.h" #include "mce_log_p.h" -#include -#include - #include /* Generated headers */ -#include "com.nokia.mce.request.h" -#include "com.nokia.mce.signal.h" +#include "org.ayatana.indicator.power.Battery.h" + +#define MCE_BATTERY_STATUS_OK "ok" +#define MCE_BATTERY_STATUS_LOW "low" +#define MCE_BATTERY_STATUS_EMPTY "very_low" +#define MCE_BATTERY_STATUS_CRITICAL "critical" +#define MCE_BATTERY_STATUS_UNKNOWN "unknown" enum mce_battery_ind { BATTERY_IND_LEVEL, @@ -65,7 +67,7 @@ struct mce_battery_priv { MceProxy* proxy; BATTERY_FLAGS flags; gulong proxy_valid_id; - gulong battery_ind_id[BATTERY_IND_COUNT]; + gulong battery_ind_id; }; enum mce_battery_signal { @@ -133,13 +135,13 @@ mce_battery_status_update( MceBatteryPriv* priv = self->priv; MCE_BATTERY_STATUS new_status; - if (!g_strcmp0(status, MCE_BATTERY_STATUS_FULL)) { - new_status = MCE_BATTERY_FULL; - } else if (!g_strcmp0(status, MCE_BATTERY_STATUS_OK)) { + if (!g_strcmp0(status, MCE_BATTERY_STATUS_OK)) { new_status = MCE_BATTERY_OK; } else if (!g_strcmp0(status, MCE_BATTERY_STATUS_LOW)) { new_status = MCE_BATTERY_LOW; } else if (!g_strcmp0(status, MCE_BATTERY_STATUS_EMPTY)) { + new_status = MCE_BATTERY_LOW; + } else if (!g_strcmp0(status, MCE_BATTERY_STATUS_CRITICAL)) { new_status = MCE_BATTERY_EMPTY; } else { GASSERT(!g_strcmp0(status, MCE_BATTERY_STATUS_UNKNOWN)); @@ -153,73 +155,31 @@ mce_battery_status_update( mce_battery_check_valid(self); } -static -void -mce_battery_level_query_done( - GObject* proxy, - GAsyncResult* result, - gpointer arg) +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + const gchar* const *invalidated_properties, + gpointer user_data) { - MceBattery* self = MCE_BATTERY(arg); - GError* error = NULL; - gint level; + GVariantIter iter; + const gchar *key; + GVariant *value; - if (com_nokia_mce_request_call_get_battery_level_finish( - COM_NOKIA_MCE_REQUEST(proxy), &level, result, &error)) { - GDEBUG("Battery level is currently %d", level); - mce_battery_level_update(self, level); - } else { - /* Should retry? */ - GWARN("Failed to query battery level %s", GERRMSG(error)); - g_error_free(error); + 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); + 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); } - mce_battery_unref(self); -} - -static -void -mce_battery_status_query_done( - GObject* proxy, - GAsyncResult* result, - gpointer arg) -{ - MceBattery* self = MCE_BATTERY(arg); - GError* error = NULL; - char* status = NULL; - - if (com_nokia_mce_request_call_get_battery_status_finish( - COM_NOKIA_MCE_REQUEST(proxy), &status, result, &error)) { - GDEBUG("Battery is currently %s", status); - mce_battery_status_update(self, status); - g_free(status); - } else { - /* Should retry? */ - GWARN("Failed to query battery status %s", GERRMSG(error)); - g_error_free(error); - } - mce_battery_unref(self); -} - -static -void -mce_battery_level_ind( - ComNokiaMceSignal* proxy, - gint level, - gpointer arg) -{ - GDEBUG("Battery level is %d", level); - mce_battery_level_update(MCE_BATTERY(arg), level); -} - -static -void -mce_battery_status_ind( - ComNokiaMceSignal* proxy, - const char* status, - gpointer arg) -{ - GDEBUG("Battery is %s", status); - mce_battery_status_update(MCE_BATTERY(arg), status); } static @@ -236,24 +196,17 @@ mce_battery_query( * for the valid signal before we can connect the battery state * signal and submit the initial query. */ - if (proxy->signal) { - if (!priv->battery_ind_id[BATTERY_IND_LEVEL]) { - priv->battery_ind_id[BATTERY_IND_LEVEL] = - g_signal_connect(proxy->signal, "battery-level-ind", - G_CALLBACK(mce_battery_level_ind), self); - } - - if (!priv->battery_ind_id[BATTERY_IND_STATUS]) { - priv->battery_ind_id[BATTERY_IND_STATUS] = - g_signal_connect(proxy->signal, "battery-status-ind", - G_CALLBACK(mce_battery_status_ind), self); - } + if (proxy->ayatana_request && !priv->battery_ind_id) { + priv->battery_ind_id = g_signal_connect(proxy->ayatana_request, "g-properties-changed", + G_CALLBACK(on_properties_changed), self); } - if (proxy->request && proxy->valid) { - com_nokia_mce_request_call_get_battery_level(proxy->request, NULL, - mce_battery_level_query_done, mce_battery_ref(self)); - com_nokia_mce_request_call_get_battery_status(proxy->request, NULL, - mce_battery_status_query_done, mce_battery_ref(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); + mce_battery_level_update(self, level); } } @@ -389,8 +342,7 @@ mce_battery_finalize( MceBattery* self = MCE_BATTERY(object); MceBatteryPriv* priv = self->priv; - gutil_disconnect_handlers(priv->proxy->signal, priv->battery_ind_id, - G_N_ELEMENTS(priv->battery_ind_id)); + mce_proxy_remove_handler(priv->proxy, priv->battery_ind_id); mce_proxy_remove_handler(priv->proxy, priv->proxy_valid_id); mce_proxy_unref(priv->proxy); G_OBJECT_CLASS(PARENT_CLASS)->finalize(object); diff --git a/src/mce_charger.c b/src/mce_charger.c index e40aa31..5c44c09 100644 --- a/src/mce_charger.c +++ b/src/mce_charger.c @@ -38,14 +38,14 @@ #include "mce_proxy.h" #include "mce_log_p.h" -#include -#include - #include +#define MCE_CHARGER_STATE_ON "on" +#define MCE_CHARGER_STATE_OFF "off" +#define MCE_CHARGER_STATE_UNKNOWN "unknown" + /* Generated headers */ -#include "com.nokia.mce.request.h" -#include "com.nokia.mce.signal.h" +#include "org.ayatana.indicator.power.Battery.h" struct mce_charger_priv { MceProxy* proxy; @@ -102,44 +102,27 @@ mce_charger_state_update( } } -static -void -mce_charger_state_query_done( - GObject* proxy, - GAsyncResult* result, - gpointer arg) +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + const gchar* const *invalidated_properties, + gpointer user_data) { - GError* error = NULL; - char* state = NULL; - MceCharger* self = MCE_CHARGER(arg); + GVariantIter iter; + const gchar *key; + GVariant *value; - if (com_nokia_mce_request_call_get_charger_state_finish( - COM_NOKIA_MCE_REQUEST(proxy), &state, result, &error)) { - GDEBUG("Charger is currently %s", state); - mce_charger_state_update(self, state); - g_free(state); - } else { - /* - * We could retry but it's probably not worth the trouble - * because the next time charger state changes we receive - * charger_state_ind signal and sync our state with mce. - * Until then, this object stays invalid. - */ - GWARN("Failed to query charger state %s", GERRMSG(error)); - g_error_free(error); + 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); + } + + g_variant_unref (value); } - mce_charger_unref(self); -} - -static -void -mce_charger_state_ind( - ComNokiaMceSignal* proxy, - const char* state, - gpointer arg) -{ - GDEBUG("Charger is %s", state); - mce_charger_state_update(MCE_CHARGER(arg), state); } static @@ -156,13 +139,14 @@ mce_charger_state_query( * for the valid signal before we can connect the charger state * signal and submit the initial query. */ - if (proxy->signal && !priv->charger_state_ind_id) { - priv->charger_state_ind_id = g_signal_connect(proxy->signal, - MCE_CHARGER_STATE_SIG, G_CALLBACK(mce_charger_state_ind), self); + if (proxy->ayatana_request && !priv->charger_state_ind_id) { + priv->charger_state_ind_id = g_signal_connect(proxy->ayatana_request, "g-properties-changed", + G_CALLBACK(on_properties_changed), self); } - if (proxy->request && proxy->valid) { - com_nokia_mce_request_call_get_charger_state(proxy->request, NULL, - mce_charger_state_query_done, mce_charger_ref(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); } } @@ -290,7 +274,7 @@ mce_charger_finalize( MceChargerPriv* priv = self->priv; if (priv->charger_state_ind_id) { - g_signal_handler_disconnect(priv->proxy->signal, + g_signal_handler_disconnect(priv->proxy->ayatana_request, priv->charger_state_ind_id); } mce_proxy_remove_handler(priv->proxy, priv->proxy_valid_id); diff --git a/src/mce_display.c b/src/mce_display.c index fd6634f..ba9e80a 100644 --- a/src/mce_display.c +++ b/src/mce_display.c @@ -149,12 +149,12 @@ mce_display_status_query( * for the valid signal before we can connect the display state * signal and submit the initial query. */ - if (proxy->signal && !priv->display_status_ind_id) { - priv->display_status_ind_id = g_signal_connect(proxy->signal, + if (proxy->unity_request && !priv->display_status_ind_id) { + priv->display_status_ind_id = g_signal_connect(proxy->unity_request, MCE_DISPLAY_SIG, G_CALLBACK(mce_display_power_state_change), self); } - if (proxy->request && proxy->valid) { - com_canonical_unity_screen_call_get_display_power_state(proxy->request, NULL, + if (proxy->unity_request && proxy->valid) { + com_canonical_unity_screen_call_get_display_power_state(proxy->unity_request, NULL, mce_display_status_query_done, mce_display_ref(self)); } } @@ -283,7 +283,7 @@ mce_display_finalize( MceDisplayPriv* priv = self->priv; if (priv->display_status_ind_id) { - g_signal_handler_disconnect(priv->proxy->signal, + g_signal_handler_disconnect(priv->proxy->unity_request, priv->display_status_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 a5f0d3d..e2b279a 100644 --- a/src/mce_proxy.c +++ b/src/mce_proxy.c @@ -39,12 +39,18 @@ /* Generated headers */ #include "com.canonical.Unity.Screen.h" +#include "org.ayatana.indicator.power.Battery.h" GLOG_MODULE_DEFINE("mce"); struct mce_proxy_priv { GDBusConnection* bus; + GDBusConnection* session_bus; guint mce_watch_id; + guint ayatana_watch_id; + + gboolean unity_valid; + gboolean ayatana_valid; }; enum mce_proxy_signal { @@ -56,7 +62,9 @@ enum mce_proxy_signal { #define MCE_SERVICE "com.canonical.Unity.Screen" #define MCE_REQUEST_PATH "/com/canonical/Unity/Screen" -#define MCE_SIGNAL_PATH "/com/canonical/Unity/Screen" + +#define AYATANA_SERVICE "org.ayatana.indicator.power" +#define AYATANA_REQUEST_PATH "/org/ayatana/indicator/power/Battery" static guint mce_proxy_signals[SIGNAL_COUNT] = { 0 }; @@ -107,11 +115,16 @@ mce_proxy_init_check( { MceProxyPriv* priv = self->priv; - if (self->signal && self->request && !priv->mce_watch_id) { + if ( self->unity_request && !priv->mce_watch_id) { priv->mce_watch_id = g_bus_watch_name_on_connection(priv->bus, 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, + mce_name_appeared, mce_name_vanished, self, NULL); + } } static @@ -124,9 +137,9 @@ mce_proxy_request_proxy_new_finished( MceProxy* self = MCE_PROXY(arg); GError* error = NULL; - GASSERT(!self->request); - self->request = com_canonical_unity_screen_proxy_new_finish(result, &error); - if (self->request) { + GASSERT(!self->unity_request); + self->unity_request = com_canonical_unity_screen_proxy_new_finish(result, &error); + if (self->unity_request) { mce_proxy_init_check(self); } else { GERR("Failed to initialize MCE request proxy: %s", GERRMSG(error)); @@ -137,7 +150,7 @@ mce_proxy_request_proxy_new_finished( static void -mce_proxy_signal_proxy_new_finished( +mce_proxy_request_proxy_session_new_finished( GObject* object, GAsyncResult* result, gpointer arg) @@ -145,12 +158,12 @@ mce_proxy_signal_proxy_new_finished( MceProxy* self = MCE_PROXY(arg); GError* error = NULL; - GASSERT(!self->signal); - self->signal = com_canonical_unity_screen_proxy_new_finish(result, &error); - if (self->signal) { + GASSERT(!self->ayatana_request); + self->ayatana_request = org_ayatana_indicator_power_battery_proxy_new_finish(result, &error); + if (self->ayatana_request) { mce_proxy_init_check(self); } else { - GERR("Failed to initialize MCE signal proxy: %s", GERRMSG(error)); + GERR("Failed to initialize MCE ayatana request proxy: %s", GERRMSG(error)); g_error_free(error); } mce_proxy_unref(self); @@ -170,15 +183,10 @@ mce_proxy_bus_get_finished( priv->bus = g_bus_get_finish(result, &error); if (priv->bus) { com_canonical_unity_screen_proxy_new(priv->bus, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + G_DBUS_PROXY_FLAGS_NONE, MCE_SERVICE, MCE_REQUEST_PATH, NULL, mce_proxy_request_proxy_new_finished, mce_proxy_ref(self)); - com_canonical_unity_screen_proxy_new(priv->bus, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - MCE_SERVICE, MCE_SIGNAL_PATH, NULL, - mce_proxy_signal_proxy_new_finished, - mce_proxy_ref(self)); } else { GERR("Failed to attach to system bus: %s", GERRMSG(error)); g_error_free(error); @@ -186,6 +194,31 @@ 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() { @@ -200,6 +233,8 @@ 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)); } @@ -265,15 +300,21 @@ mce_proxy_finalize( if (priv->mce_watch_id) { g_bus_unwatch_name(priv->mce_watch_id); } - if (self->signal) { - g_object_unref(self->signal); + if (priv->ayatana_watch_id) { + g_bus_unwatch_name(priv->ayatana_watch_id); } - if (self->request) { - g_object_unref(self->request); + if (self->unity_request) { + g_object_unref(self->unity_request); + } + if (self->ayatana_request) { + g_object_unref(self->ayatana_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 8aa2641..f02a137 100644 --- a/src/mce_proxy.h +++ b/src/mce_proxy.h @@ -43,13 +43,14 @@ typedef struct mce_proxy_priv MceProxyPriv; struct _ComCanonicalUnityScreen; +struct _OrgAyatanaIndicatorPowerBattery; typedef struct mce_proxy { GObject object; MceProxyPriv* priv; gboolean valid; - struct _ComCanonicalUnityScreen* signal; - struct _ComCanonicalUnityScreen* request; + struct _ComCanonicalUnityScreen* unity_request; + struct _OrgAyatanaIndicatorPowerBattery* ayatana_request; } MceProxy; typedef void