From 93613cf6c81432d0f1c3bf3e2b088e955247edef Mon Sep 17 00:00:00 2001 From: Rory Fewell Date: Wed, 2 Jul 2025 22:15:38 +0100 Subject: [PATCH] Bugfix: Fixes #484, taskband - UPower battery state crash --- icons/luna/mappings | 2 +- .../luna/res/16x16/battery_full_charging.png | 1 + .../luna/res/32x32/battery_full_charging.png | Bin 0 -> 868 bytes shell/taskband/src/systray/power.c | 379 +++++++++--------- 4 files changed, 187 insertions(+), 195 deletions(-) create mode 120000 icons/luna/res/16x16/battery_full_charging.png create mode 100644 icons/luna/res/32x32/battery_full_charging.png diff --git a/icons/luna/mappings b/icons/luna/mappings index 9376903..3d34b35 100644 --- a/icons/luna/mappings +++ b/icons/luna/mappings @@ -316,7 +316,7 @@ status/battery-empty-->battery_empty status/battery-empty-charging-->battery_low_charging status/battery-full-->battery_full status/battery-full-charged-->battery_full_on_ac -status/battery-full-charging-->battery_full_on_ac +status/battery-full-charging-->battery_full_charging status/battery-good-->battery_medium status/battery-good-charging-->battery_medium_charging status/battery-low-->battery_low diff --git a/icons/luna/res/16x16/battery_full_charging.png b/icons/luna/res/16x16/battery_full_charging.png new file mode 120000 index 0000000..b925467 --- /dev/null +++ b/icons/luna/res/16x16/battery_full_charging.png @@ -0,0 +1 @@ +battery_charging.png \ No newline at end of file diff --git a/icons/luna/res/32x32/battery_full_charging.png b/icons/luna/res/32x32/battery_full_charging.png new file mode 100644 index 0000000000000000000000000000000000000000..3604e9e6a13a625b7102d0fd3ff9631dad5c8e48 GIT binary patch literal 868 zcmV-q1DpJbP)>)=vEs)Da2iG2uZ4M~cKtKi}wIEXI3 z2LA(H1y=<@Py`WIS6_>icy3c@k$S_;`SIQR9ZtSLC}Ej7w_yx&dCy5s#*Cae*+KwkI(~wyAY{fgm9cETv z5k3|kbYwu`8>JfozbeiI{HfTPO-?{a_0%#|Y*ewCb#lT3!o4}GV3y}mU(%Y&&&^2f zlHH9ZjDsD=5l14xA-P6X zkuCuVYOT$2=Uko(@UXtjiOjxjW}79z;0(;!2HR+3fJc)1yNcZIa+kd%BC`*q@|@zH zo(XG3yooiCz>>SFja>tMmO}Cb>AEZV#iW3dF3jG-jwoj8A0$tOsIX zPV1!=06Otxwm>ylrhNhK^Z;uet6%H>U;pt7sY?JQc=8OW0>`&acW0pzAyXY z9%z9V*MRp4sK1KqazomYML}`3NCp(AUe26P!(rz73XE9PT3@~gJ_wH0yI>_a^az;q uM+3@6sAWIiKiQ}Wp&n6N&d>d*zO_FI0!qV#=IlxU0000constructed = wintc_notification_power_constructed; - object_class->finalize = wintc_notification_power_finalize; + object_class->dispose = wintc_notification_power_dispose; } static void wintc_notification_power_init( @@ -102,72 +96,57 @@ static void wintc_notification_power_constructed( GObject* object ) { + (G_OBJECT_CLASS(wintc_notification_power_parent_class)) + ->constructed(object); + WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(object); // Connect to upower, enumerate existing devices and attach signals for // picking up new ones // - GPtrArray* all_devices; - UpDevice* device; - power->up_client = up_client_new(); - if (power->up_client) + + if (!power->up_client) { - WINTC_LOG_DEBUG("Connected to upower"); - - all_devices = up_client_get_devices2(power->up_client); - - for (guint i = 0; i < all_devices->len; i++) - { - device = all_devices->pdata[i]; - - check_and_register_battery(power, device); - } - - g_signal_connect( - power->up_client, - "device-added", - G_CALLBACK(on_up_client_device_added), - power - ); - g_signal_connect( - power->up_client, - "device-removed", - G_CALLBACK(on_up_client_device_removed), - power - ); - g_signal_connect( - power->up_client, - "notify::on-battery", - G_CALLBACK(on_up_client_battery_notify), - power - ); - - update_client_on_battery(power, power->up_client); - - g_ptr_array_unref(all_devices); - } - else - { - g_warning("Failed to connect to upower"); + g_warning("%s", "taskband: power: Failed to connect to upower"); + return; } - (G_OBJECT_CLASS( - wintc_notification_power_parent_class - ))->constructed(object); + WINTC_LOG_DEBUG("taskband: power: Connected to upower"); + + wintc_notification_power_register_main_battery(power); + + g_signal_connect( + power->up_client, + "device-added", + G_CALLBACK(on_up_client_device_added), + power + ); + g_signal_connect( + power->up_client, + "device-removed", + G_CALLBACK(on_up_client_device_removed), + power + ); + g_signal_connect( + power->up_client, + "notify::on-battery", + G_CALLBACK(on_up_client_battery_notify), + power + ); } -static void wintc_notification_power_finalize( +static void wintc_notification_power_dispose( GObject* object ) { WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(object); - g_free(power->up_last_battery_path); + g_clear_object(&(power->up_device_battery)); + g_clear_object(&(power->up_client)); - (G_OBJECT_CLASS( - wintc_notification_power_parent_class - ))->finalize(object); + (G_OBJECT_CLASS(wintc_notification_power_parent_class)) + ->dispose(object); } // @@ -189,104 +168,137 @@ WinTCNotificationPower* wintc_notification_power_new( // // PRIVATE FUNCTIONS // -static UpDeviceLevel battery_pct_to_enum( - gdouble percentage +static void wintc_notification_power_register_main_battery( + WinTCNotificationPower* power ) { - // FIXME: Not checked against Windows XP + // Reset state (for our sanity really) // - if (percentage <= 15.0f) - { - return UP_DEVICE_LEVEL_CRITICAL; - } - else if (percentage <= 25.0f) - { - return UP_DEVICE_LEVEL_LOW; - } - else if (percentage <= 75.0f) - { - return UP_DEVICE_LEVEL_NORMAL; - } - else if (percentage <= 90.0f) - { - return UP_DEVICE_LEVEL_HIGH; - } - else - { - return UP_DEVICE_LEVEL_FULL; - } -} + g_clear_object(&(power->up_device_battery)); -static void check_and_register_battery( - WinTCNotificationPower* power, - UpDevice* device -) -{ - guint device_kind; + // ATM we can only raise one notification icon so just try to find 'a' + // battery and make that the main one + // + GPtrArray* all_devices = up_client_get_devices2(power->up_client); + gboolean on_battery = up_client_get_on_battery(power->up_client); - g_object_get( - device, - "kind", &device_kind, - NULL - ); + for (guint i = 0; i < all_devices->len; i++) + { + UpDevice* device = (UpDevice*) all_devices->pdata[i]; + guint device_kind; + gboolean power_supply; + guint state; - if (device_kind != UP_DEVICE_KIND_BATTERY) + g_object_get( + device, + "kind", &device_kind, + "power-supply", &power_supply, + "state", &state, + NULL + ); + + if (device_kind == UP_DEVICE_KIND_BATTERY) + { + // This is the battery we want if: + // - We're on battery, and this is the battery providing power + // - We're not on battery, and this battery is charging + // + if ( + (on_battery && power_supply) || + ( + !on_battery && + ( + state == UP_DEVICE_STATE_CHARGING || + state == UP_DEVICE_STATE_FULLY_CHARGED + ) + ) + ) + { + power->up_device_battery = g_object_ref(device); + break; + } + } + } + + g_ptr_array_unref(all_devices); + + // Update the icon for current battery state + // + wintc_notification_power_update_icon(power); + + // Connect up signals to monitor battery, assuming we have one? + // + if (!(power->up_device_battery)) { return; } - update_battery_battery_level(power, device); - g_signal_connect( - device, + power->up_device_battery, "notify::percentage", G_CALLBACK(on_up_device_battery_notify), power ); g_signal_connect( - device, + power->up_device_battery, "notify::power-supply", G_CALLBACK(on_up_device_battery_notify), power ); g_signal_connect( - device, + power->up_device_battery, "notify::state", G_CALLBACK(on_up_device_battery_notify), power ); } -static void update_battery_battery_level( - WinTCNotificationPower* power, - UpDevice* device +static void wintc_notification_power_update_icon( + WinTCNotificationPower* power ) { - gdouble percentage; - gboolean power_supply; - guint state; - - g_object_get( - device, - "percentage", &percentage, - "power-supply", &power_supply, - "state", &state, - NULL - ); - - if (!power_supply) + // Handle the situation where we have no battery, even if we're supposedly + // on battery supply + // + if (!(power->up_device_battery)) { + if (up_client_get_on_battery(power->up_client)) + { + g_object_set( + power, + "icon-name", "battery-missing", + NULL + ); + } + else + { + g_object_set( + power, + "icon-name", "ac-adapter", + NULL + ); + } + return; } - // Update icon based on levels + // Okay we have a battery, so update the icon for it // // We do not use 'battery-level' from the upower API, because it's not // reliable (reports UP_DEVICE_LEVEL_NONE) -- so just use percentage // - const gchar* icon_name; + gdouble percentage; + guint state; + + g_object_get( + power->up_device_battery, + "percentage", &percentage, + "state", &state, + NULL + ); UpDeviceLevel battery_level = battery_pct_to_enum(percentage); + const gchar* icon_name; gboolean is_charging = state == UP_DEVICE_STATE_CHARGING; switch (battery_level) @@ -330,50 +342,33 @@ static void update_battery_battery_level( "icon-name", icon_name, NULL ); - - // Keep track of last battery, for when switching to-from AC power - // - const gchar* this_battery_path = up_device_get_object_path(device); - - if (g_strcmp0(power->up_last_battery_path, this_battery_path) != 0) - { - g_free(power->up_last_battery_path); - - power->up_last_battery = device; - power->up_last_battery_path = g_strdup(this_battery_path); - } } -static void update_client_on_battery( - WinTCNotificationPower* power, - UpClient* client +static UpDeviceLevel battery_pct_to_enum( + gdouble percentage ) { - if (up_client_get_on_battery(client)) + // FIXME: Not checked against Windows XP + // + if (percentage <= 15.0f) { - if (power->up_last_battery) - { - update_battery_battery_level(power, power->up_last_battery); - } - else - { - g_object_set( - power, - "icon-name", "battery-missing", - NULL - ); - } + return UP_DEVICE_LEVEL_CRITICAL; + } + else if (percentage <= 25.0f) + { + return UP_DEVICE_LEVEL_LOW; + } + else if (percentage <= 75.0f) + { + return UP_DEVICE_LEVEL_NORMAL; + } + else if (percentage <= 90.0f) + { + return UP_DEVICE_LEVEL_HIGH; } else { - if (!power->up_last_battery) - { - g_object_set( - power, - "icon-name", "ac-adapter", - NULL - ); - } + return UP_DEVICE_LEVEL_FULL; } } @@ -382,48 +377,44 @@ static void update_client_on_battery( // static void on_up_client_device_added( WINTC_UNUSED(UpClient* up_client), - UpDevice* up_device, - gpointer user_data + WINTC_UNUSED(UpDevice* up_device), + gpointer user_data ) { WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(user_data); - check_and_register_battery(power, up_device); + wintc_notification_power_register_main_battery(power); } static void on_up_client_device_removed( - WINTC_UNUSED(UpClient* up_client), - const gchar* object_path, - gpointer user_data + WINTC_UNUSED(UpClient* up_client), + WINTC_UNUSED(const gchar* object_path), + gpointer user_data ) { WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(user_data); - if (g_strcmp0(power->up_last_battery_path, object_path)) - { - power->up_last_battery = NULL; - g_free(power->up_last_battery_path); - } + wintc_notification_power_register_main_battery(power); } static void on_up_client_battery_notify( - UpClient* up_client, + WINTC_UNUSED(UpClient* up_client), WINTC_UNUSED(GParamSpec* pspec), - gpointer user_data + gpointer user_data ) { WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(user_data); - update_client_on_battery(power, up_client); + wintc_notification_power_register_main_battery(power); } static void on_up_device_battery_notify( - UpDevice* up_device, + WINTC_UNUSED(UpDevice* up_device), WINTC_UNUSED(GParamSpec* pspec), - gpointer user_data + gpointer user_data ) { WinTCNotificationPower* power = WINTC_NOTIFICATION_POWER(user_data); - update_battery_battery_level(power, up_device); + wintc_notification_power_update_icon(power); }