Add support for a battery level changed callback for actions and drivers

This will allow actions and drivers to react to battery level changes.
This commit is contained in:
Mario Limonciello 2024-07-17 12:08:55 -05:00
parent 3c2d072231
commit 69e90eeb50
5 changed files with 153 additions and 7 deletions

View file

@ -41,6 +41,9 @@
#define UPOWER_DBUS_PATH "/org/freedesktop/UPower"
#define UPOWER_DBUS_INTERFACE "org.freedesktop.UPower"
#define UPOWER_DBUS_DISPLAY_DEVICE_PATH "/org/freedesktop/UPower/devices/DisplayDevice"
#define UPOWER_DBUS_DEVICE_INTERFACE "org.freedesktop.UPower.Device"
#define LOGIND_DBUS_NAME "org.freedesktop.login1"
#define LOGIND_DBUS_PATH "/org/freedesktop/login1"
#define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager"
@ -82,8 +85,11 @@ typedef struct {
GHashTable *profile_holds;
GDBusProxy *upower_proxy;
GDBusProxy *upower_display_proxy;
gulong upower_watch_id;
gulong upower_display_watch_id;
gulong upower_properties_id;
gulong upower_display_properties_id;
PpdPowerChangedReason power_changed_reason;
guint logind_sleep_signal_id;
@ -1023,8 +1029,8 @@ bus_acquired_handler (GDBusConnection *connection,
}
static void
upower_battery_update_state_from_value (PpdApp *data,
GVariant *battery_val)
upower_source_update_from_value (PpdApp *data,
GVariant *battery_val)
{
PpdPowerChangedReason reason;
@ -1039,12 +1045,62 @@ upower_battery_update_state_from_value (PpdApp *data,
}
static void
upower_battery_update_state (PpdApp *data)
upower_source_update (PpdApp *data)
{
g_autoptr(GVariant) battery_val = NULL;
battery_val = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery");
upower_battery_update_state_from_value (data, battery_val);
upower_source_update_from_value (data, battery_val);
}
static void
upower_battery_changed(PpdApp *data, gdouble level)
{
g_info ("Battery level changed to %f", level);
for (guint i = 0; i < data->actions->len; i++) {
g_autoptr(GError) error = NULL;
PpdAction *action;
action = g_ptr_array_index (data->actions, i);
if (!ppd_action_battery_changed (action, level, &error)) {
g_warning ("failed to update action %s: %s",
ppd_action_get_action_name (action),
error->message);
g_clear_error (&error);
continue;
}
}
if (PPD_IS_DRIVER_CPU (data->cpu_driver)) {
g_autoptr(GError) error = NULL;
if (!ppd_driver_battery_changed (PPD_DRIVER (data->cpu_driver), level, &error)) {
g_warning ("failed to update driver %s: %s",
ppd_driver_get_driver_name (PPD_DRIVER (data->cpu_driver)),
error->message);
}
}
if (PPD_IS_DRIVER_PLATFORM (data->platform_driver)) {
g_autoptr(GError) error = NULL;
if (!ppd_driver_battery_changed (PPD_DRIVER (data->platform_driver), level, &error)) {
g_warning ("failed to update driver %s: %s",
ppd_driver_get_driver_name (PPD_DRIVER (data->platform_driver)),
error->message);
}
}
}
static void upower_battery_update (PpdApp *data)
{
g_autoptr(GVariant) val = NULL;
val = g_dbus_proxy_get_cached_property (data->upower_display_proxy, "Percentage");
if (val)
upower_battery_changed(data, g_variant_get_double (val));
}
static void
@ -1055,12 +1111,18 @@ upower_properties_changed (GDBusProxy *proxy,
{
g_auto(GVariantDict) props_dict = G_VARIANT_DICT_INIT (changed_properties);
g_autoptr(GVariant) battery_val = NULL;
g_autoptr(GVariant) percent_val = NULL;
battery_val = g_variant_dict_lookup_value (&props_dict, "OnBattery",
G_VARIANT_TYPE_BOOLEAN);
if (battery_val)
upower_battery_update_state_from_value (data, battery_val);
upower_source_update_from_value (data, battery_val);
percent_val = g_variant_dict_lookup_value (&props_dict, "Percentage",
G_VARIANT_TYPE_DOUBLE);
if (percent_val)
upower_battery_changed(data, g_variant_get_double (percent_val));
}
static void
@ -1123,7 +1185,7 @@ upower_name_owner_changed (GObject *object,
if (name_owner != NULL) {
g_debug ("%s appeared", UPOWER_DBUS_NAME);
upower_battery_update_state (data);
upower_source_update (data);
return;
}
@ -1163,7 +1225,42 @@ on_upower_proxy_cb (GObject *source_object,
G_CALLBACK (upower_name_owner_changed),
data);
upower_battery_update_state (data);
upower_source_update (data);
}
static void
on_upower_display_proxy_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PpdApp *data = user_data;
g_autoptr(GDBusProxy) proxy = NULL;
g_autoptr(GError) error = NULL;
proxy = g_dbus_proxy_new_finish (res, &error);
if (proxy == NULL) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("failed to connect to upower: %s", error->message);
return;
}
g_return_if_fail (data->upower_display_proxy == NULL);
data->upower_display_proxy = g_steal_pointer (&proxy);
data->upower_display_properties_id = g_signal_connect (data->upower_display_proxy,
"g-properties-changed",
G_CALLBACK (upower_properties_changed),
data);
data->upower_display_watch_id = g_signal_connect (data->upower_display_proxy,
"notify::g-name-owner",
G_CALLBACK (upower_name_owner_changed),
data);
upower_battery_update (data);
}
static void
@ -1273,9 +1370,13 @@ stop_profile_drivers (PpdApp *data)
g_ptr_array_set_size (data->actions, 0);
g_clear_signal_handler (&data->upower_watch_id, data->upower_proxy);
g_clear_signal_handler (&data->upower_properties_id, data->upower_proxy);
g_clear_signal_handler (&data->upower_display_watch_id, data->upower_display_proxy);
g_clear_signal_handler (&data->upower_display_properties_id, data->upower_display_proxy);
g_clear_object (&data->cancellable);
maybe_disconnect_object_by_data (data->upower_proxy, data);
g_clear_object (&data->upower_proxy);
maybe_disconnect_object_by_data (data->upower_display_proxy, data);
g_clear_object (&data->upower_display_proxy);
maybe_disconnect_object_by_data (data->cpu_driver, data);
g_clear_object (&data->cpu_driver);
maybe_disconnect_object_by_data (data->platform_driver, data);
@ -1450,6 +1551,16 @@ start_profile_drivers (PpdApp *data)
data->cancellable,
on_upower_proxy_cb,
data);
g_dbus_proxy_new (data->connection,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
UPOWER_DBUS_NAME,
UPOWER_DBUS_DISPLAY_DEVICE_PATH,
UPOWER_DBUS_DEVICE_INTERFACE,
data->cancellable,
on_upower_display_proxy_cb,
data);
} else {
g_debug ("No battery state monitor required by any driver, let's skip it");
}

View file

@ -161,6 +161,18 @@ gboolean ppd_action_power_changed (PpdAction *action,
return PPD_ACTION_GET_CLASS (action)->power_changed (action, reason, error);
}
gboolean ppd_action_battery_changed (PpdAction *action,
gdouble val,
GError **error)
{
g_return_val_if_fail (PPD_IS_ACTION (action), FALSE);
if (!PPD_ACTION_GET_CLASS (action)->battery_changed)
return TRUE;
return PPD_ACTION_GET_CLASS (action)->battery_changed (action, val, error);
}
const char *
ppd_action_get_action_name (PpdAction *action)
{

View file

@ -20,6 +20,8 @@ G_DECLARE_DERIVABLE_TYPE (PpdAction, ppd_action, PPD, ACTION, GObject)
* @parent_class: The parent class.
* @probe: Called by the daemon on startup.
* @activate_profile: Called by the daemon when the profile changes.
* @power_changed: Called by the daemon when the power source changes.
* @battery_changed: Called by the daemon when the battery level changes.
*
* New profile actions should derive from #PpdAction and implement
* at least @activate_profile.
@ -35,6 +37,9 @@ struct _PpdActionClass
gboolean (* power_changed) (PpdAction *action,
PpdPowerChangedReason reason,
GError **error);
gboolean (* battery_changed) (PpdAction *action,
gdouble val,
GError **error);
};
@ -42,5 +47,6 @@ struct _PpdActionClass
PpdProbeResult ppd_action_probe (PpdAction *action);
gboolean ppd_action_activate_profile (PpdAction *action, PpdProfile profile, GError **error);
gboolean ppd_action_power_changed (PpdAction *action, PpdPowerChangedReason reason, GError **error);
gboolean ppd_action_battery_changed (PpdAction *action, gdouble val, GError **error);
const char *ppd_action_get_action_name (PpdAction *action);
#endif

View file

@ -251,6 +251,18 @@ ppd_driver_power_changed (PpdDriver *driver,
return PPD_DRIVER_GET_CLASS (driver)->power_changed (driver, reason, error);
}
gboolean ppd_driver_battery_changed (PpdDriver *driver,
gdouble val,
GError **error)
{
g_return_val_if_fail (PPD_IS_DRIVER (driver), FALSE);
if (!PPD_DRIVER_GET_CLASS (driver)->battery_changed)
return TRUE;
return PPD_DRIVER_GET_CLASS (driver)->battery_changed (driver, val, error);
}
gboolean
ppd_driver_prepare_to_sleep (PpdDriver *driver,
gboolean start,

View file

@ -46,6 +46,7 @@ typedef enum{
* @probe: Called by the daemon on startup.
* @activate_profile: Called by the daemon for every profile change.
* @power_changed: Called by the daemon when power adapter status changes
* @battery_changed: Called by the daemon when the battery level changes.
*
* New profile drivers should not derive from #PpdDriver. They should
* derive from the child from #PpdDriverCpu or #PpdDriverPlatform drivers
@ -66,6 +67,9 @@ struct _PpdDriverClass
gboolean (* prepare_to_sleep) (PpdDriver *driver,
gboolean start,
GError **error);
gboolean (* battery_changed) (PpdDriver *driver,
gdouble val,
GError **error);
};
#ifndef __GTK_DOC_IGNORE__
@ -74,6 +78,7 @@ gboolean ppd_driver_activate_profile (PpdDriver *driver,
PpdProfile profile, PpdProfileActivationReason reason, GError **error);
gboolean ppd_driver_power_changed (PpdDriver *driver, PpdPowerChangedReason reason, GError **error);
gboolean ppd_driver_prepare_to_sleep (PpdDriver *driver, gboolean start, GError **error);
gboolean ppd_driver_battery_changed (PpdDriver *driver, gdouble val, GError **error);
const char *ppd_driver_get_driver_name (PpdDriver *driver);
PpdProfile ppd_driver_get_profiles (PpdDriver *driver);
const char *ppd_driver_get_performance_degraded (PpdDriver *driver);