diff options
Diffstat (limited to 'panels/power/cc-power-panel.c')
-rw-r--r-- | panels/power/cc-power-panel.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/panels/power/cc-power-panel.c b/panels/power/cc-power-panel.c index 92844e495..ab7695256 100644 --- a/panels/power/cc-power-panel.c +++ b/panels/power/cc-power-panel.c @@ -33,6 +33,7 @@ #include "list-box-helper.h" #include "cc-battery-row.h" #include "cc-brightness-scale.h" +#include "cc-power-profile-row.h" #include "cc-power-panel.h" #include "cc-power-resources.h" #include "cc-util.h" @@ -116,6 +117,11 @@ struct _CcPowerPanel GtkWidget *als_switch; GtkWidget *als_row; + GDBusProxy *power_profiles_proxy; + guint power_profiles_prop_id; + GtkWidget *power_profiles_row[NUM_CC_POWER_PROFILES]; + gboolean power_profiles_in_update; + GtkWidget *power_button_combo; GtkWidget *idle_delay_combo; @@ -320,6 +326,7 @@ load_custom_css (CcPowerPanel *self) /* use custom CSS */ provider = gtk_css_provider_new (); gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/power/battery-levels.css"); + gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/power/power-profiles.css"); gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); @@ -1656,6 +1663,314 @@ add_power_saving_section (CcPowerPanel *self) } static void +performance_profile_set_active (CcPowerPanel *self, + const char *profile_str) +{ + CcPowerProfile profile = cc_power_profile_from_str (profile_str); + GtkRadioButton *button; + + button = cc_power_profile_row_get_radio_button (CC_POWER_PROFILE_ROW (self->power_profiles_row[profile])); + g_assert (button); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); +} + +static void +performance_profile_set_inhibited (CcPowerPanel *self, + const char *performance_inhibited) +{ + GtkWidget *row; + + row = self->power_profiles_row[CC_POWER_PROFILE_PERFORMANCE]; + g_assert (row != NULL); + cc_power_profile_row_set_performance_inhibited (CC_POWER_PROFILE_ROW (row), + performance_inhibited); +} + +static void +power_profiles_row_activated_cb (GtkListBox *box, + GtkListBoxRow *box_row, + gpointer user_data) +{ + if (!gtk_widget_is_sensitive (GTK_WIDGET (box_row))) + return; + + cc_power_profile_row_set_active (CC_POWER_PROFILE_ROW(box_row), TRUE); +} + +static gint +perf_profile_list_box_sort (GtkListBoxRow *row1, + GtkListBoxRow *row2, + gpointer user_data) +{ + CcPowerProfile row1_profile, row2_profile; + + row1_profile = cc_power_profile_row_get_profile (CC_POWER_PROFILE_ROW (row1)); + row2_profile = cc_power_profile_row_get_profile (CC_POWER_PROFILE_ROW (row2)); + + if (row1_profile < row2_profile) + return -1; + if (row1_profile > row2_profile) + return 1; + return 0; +} + +static const char * +variant_lookup_string (GVariant *dict, + const char *key) +{ + GVariant *variant; + + variant = g_variant_lookup_value (dict, key, G_VARIANT_TYPE_STRING); + if (!variant) + return NULL; + return g_variant_get_string (variant, NULL); +} + +static void +power_profiles_properties_changed_cb (CcPowerPanel *self, + GVariant *changed_properties, + GStrv invalidated_properties, + GDBusProxy *proxy) +{ + g_autoptr(GVariantIter) iter = NULL; + const char *key; + g_autoptr(GVariant) value = NULL; + + g_variant_get (changed_properties, "a{sv}", &iter); + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) + { + if (g_strcmp0 (key, "PerformanceInhibited") == 0) + { + performance_profile_set_inhibited (self, + g_variant_get_string (value, NULL)); + } + else if (g_strcmp0 (key, "ActiveProfile") == 0) + { + self->power_profiles_in_update = TRUE; + performance_profile_set_active (self, g_variant_get_string (value, NULL)); + self->power_profiles_in_update = FALSE; + } + else + { + g_debug ("Unhandled change on '%s' property", key); + } + } +} + +static void +set_active_profile_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GVariant) variant = NULL; + g_autoptr(GError) error = NULL; + + variant = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, &error); + if (!variant) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Could not set active profile: %s", error->message); + } +} + +static void +power_profile_button_toggled_cb (CcPowerProfileRow *row, + gpointer user_data) +{ + CcPowerPanel *self = user_data; + CcPowerProfile profile; + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GError) error = NULL; + + if (!cc_power_profile_row_get_active (row)) + return; + if (self->power_profiles_in_update) + return; + + profile = cc_power_profile_row_get_profile (row); + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, + cc_panel_get_cancellable (CC_PANEL (self)), + &error); + if (!connection) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("system bus not available: %s", error->message); + return; + } + + g_dbus_connection_call (connection, + "net.hadess.PowerProfiles", + "/net/hadess/PowerProfiles", + "org.freedesktop.DBus.Properties", + "Set", + g_variant_new ("(ssv)", + "net.hadess.PowerProfiles", + "ActiveProfile", + g_variant_new_string (cc_power_profile_to_str (profile))), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cc_panel_get_cancellable (CC_PANEL (self)), + set_active_profile_cb, + NULL); +} + +static void +add_power_profiles_section (CcPowerPanel *self) +{ + GtkWidget *widget, *box, *label, *row; + g_autofree gchar *s = NULL; + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) variant = NULL; + g_autoptr(GVariant) props = NULL; + guint i, num_children; + g_autoptr(GError) error = NULL; + const char *performance_inhibited; + const char *active_profile; + g_autoptr(GVariant) profiles = NULL; + GtkRadioButton *last_button; + + self->power_profiles_proxy = cc_object_storage_create_dbus_proxy_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "net.hadess.PowerProfiles", + "/net/hadess/PowerProfiles", + "net.hadess.PowerProfiles", + NULL, + &error); + + if (!self->power_profiles_proxy) + { + g_debug ("Could not create Power Profiles proxy: %s", error->message); + return; + } + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, + cc_panel_get_cancellable (CC_PANEL (self)), + &error); + if (!connection) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("system bus not available: %s", error->message); + return; + } + + variant = g_dbus_connection_call_sync (connection, + "net.hadess.PowerProfiles", + "/net/hadess/PowerProfiles", + "org.freedesktop.DBus.Properties", + "GetAll", + g_variant_new ("(s)", + "net.hadess.PowerProfiles"), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (!variant) + { + g_debug ("Failed to get properties for Power Profiles: %s", + error->message); + g_clear_object (&self->power_profiles_proxy); + return; + } + + s = g_strdup_printf ("<b>%s</b>", _("Power Mode")); + label = gtk_label_new (s); + gtk_widget_show (label); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_box_pack_start (GTK_BOX (self->vbox_power), label, FALSE, TRUE, 0); + + label = gtk_label_new (_("Affects system performance and power usage.")); + gtk_widget_show (label); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_widget_set_margin_bottom (label, 6); + gtk_box_pack_start (GTK_BOX (self->vbox_power), label, FALSE, TRUE, 0); + + widget = gtk_list_box_new (); + gtk_widget_show (widget); + self->boxes_reverse = g_list_prepend (self->boxes_reverse, widget); + g_signal_connect_object (widget, "keynav-failed", G_CALLBACK (keynav_failed), self, G_CONNECT_SWAPPED); + gtk_list_box_set_selection_mode (GTK_LIST_BOX (widget), GTK_SELECTION_NONE); + gtk_list_box_set_sort_func (GTK_LIST_BOX (widget), + perf_profile_list_box_sort, + NULL, NULL); + g_signal_connect_object (G_OBJECT (widget), "row-activated", + G_CALLBACK (power_profiles_row_activated_cb), NULL, 0); + gtk_list_box_set_header_func (GTK_LIST_BOX (widget), + cc_list_box_update_header_func, + NULL, NULL); + + atk_object_add_relationship (ATK_OBJECT (gtk_widget_get_accessible (label)), + ATK_RELATION_LABEL_FOR, + ATK_OBJECT (gtk_widget_get_accessible (widget))); + atk_object_add_relationship (ATK_OBJECT (gtk_widget_get_accessible (widget)), + ATK_RELATION_LABELLED_BY, + ATK_OBJECT (gtk_widget_get_accessible (label))); + + box = gtk_frame_new (NULL); + gtk_widget_show (box); + gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_IN); + gtk_widget_set_margin_bottom (box, 32); + gtk_container_add (GTK_CONTAINER (box), widget); + gtk_box_pack_start (GTK_BOX (self->vbox_power), box, FALSE, TRUE, 0); + + props = g_variant_get_child_value (variant, 0); + performance_inhibited = variant_lookup_string (props, "PerformanceInhibited"); + active_profile = variant_lookup_string (props, "ActiveProfile"); + + last_button = NULL; + profiles = g_variant_lookup_value (props, "Profiles", NULL); + num_children = g_variant_n_children (profiles); + for (i = 0; i < num_children; i++) + { + g_autoptr(GVariant) profile_variant; + const char *name; + GtkRadioButton *button; + CcPowerProfile profile; + + profile_variant = g_variant_get_child_value (profiles, i); + if (!profile_variant || + !g_variant_is_of_type (profile_variant, G_VARIANT_TYPE ("a{sv}"))) + continue; + + name = variant_lookup_string (profile_variant, "Profile"); + if (!name) + continue; + g_debug ("Adding row for profile '%s' (driver: %s)", + name, variant_lookup_string (profile_variant, "Driver")); + + profile = cc_power_profile_from_str (name); + row = cc_power_profile_row_new (cc_power_profile_from_str (name), + performance_inhibited); + g_signal_connect_object (G_OBJECT (row), "button-toggled", + G_CALLBACK (power_profile_button_toggled_cb), self, + 0); + self->power_profiles_row[profile] = row; + gtk_widget_show (row); + gtk_container_add (GTK_CONTAINER (widget), row); + gtk_size_group_add_widget (self->row_sizegroup, row); + + /* Connect radio button to group */ + button = cc_power_profile_row_get_radio_button (CC_POWER_PROFILE_ROW (row)); + gtk_radio_button_join_group (button, last_button); + last_button = button; + } + + self->power_profiles_in_update = TRUE; + performance_profile_set_active (self, active_profile); + self->power_profiles_in_update = FALSE; + + self->power_profiles_prop_id = g_signal_connect_object (G_OBJECT (self->power_profiles_proxy), "g-properties-changed", + G_CALLBACK (power_profiles_properties_changed_cb), self, G_CONNECT_SWAPPED); +} + +static void add_battery_percentage (CcPowerPanel *self, GtkListBox *listbox) { @@ -1913,6 +2228,7 @@ cc_power_panel_init (CcPowerPanel *self) add_battery_section (self); add_device_section (self); + add_power_profiles_section (self); add_power_saving_section (self); add_general_section (self); |