summaryrefslogtreecommitdiff
path: root/panels/power/cc-power-panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'panels/power/cc-power-panel.c')
-rw-r--r--panels/power/cc-power-panel.c316
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);