[gnome-control-center/wip/hadess/power-profiles: 2/2] power: Add "Power Mode" section
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/hadess/power-profiles: 2/2] power: Add "Power Mode" section
- Date: Tue, 11 Aug 2020 16:23:26 +0000 (UTC)
commit 57c38f321290f9bf1ae2f5c256464e527d6cc6f3
Author: Bastien Nocera <hadess hadess net>
Date: Thu Aug 6 23:33:10 2020 +0200
power: Add "Power Mode" section
Use power-profiles-daemon[1] to implement switchable power profiles.
The performance profile will only be available on systems which provide
this functionality.
[1]: https://gitlab.freedesktop.org/hadess/power-profiles-daemon
panels/power/cc-power-panel.c | 325 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 325 insertions(+)
---
diff --git a/panels/power/cc-power-panel.c b/panels/power/cc-power-panel.c
index e565ee934..03f07b86d 100644
--- a/panels/power/cc-power-panel.c
+++ b/panels/power/cc-power-panel.c
@@ -53,6 +53,14 @@
* #define TEST_UPS
*/
+typedef enum
+{
+ PERF_PROFILE_PERFORMANCE = 0,
+ PERF_PROFILE_BALANCED = 1,
+ PERF_PROFILE_POWER_SAVER = 2,
+ NUM_PERF_PROFILES
+} PowerProfile;
+
struct _CcPowerPanel
{
CcPanel parent_instance;
@@ -118,6 +126,10 @@ struct _CcPowerPanel
GtkWidget *als_switch;
GtkWidget *als_row;
+ GDBusProxy *power_profiles_proxy;
+ guint power_profiles_watch_id;
+ GtkWidget *profile_buttons[NUM_PERF_PROFILES];
+
GtkWidget *power_button_combo;
GtkWidget *idle_delay_combo;
@@ -2306,6 +2318,318 @@ add_power_saving_section (CcPowerPanel *self)
#endif
}
+static GtkWidget *
+performance_row_new (const gchar *title,
+ const gchar *icon_path,
+ const gchar *subtitle,
+ gboolean warning_color,
+ GtkWidget **radio_button)
+{
+ PangoAttrList *attributes;
+ GtkWidget *grid, *button, *label, *image;
+
+ grid = (GtkWidget *) g_object_new (GTK_TYPE_GRID,
+ "margin-top", 6,
+ "margin-bottom", 6,
+ NULL);
+ gtk_widget_show (grid);
+
+ button = (GtkWidget *) g_object_new (GTK_TYPE_RADIO_BUTTON,
+ "margin-right", 12,
+ NULL); //FIXME group
+ gtk_widget_show (button);
+ gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 2);
+ *radio_button = button;
+
+ image = gtk_image_new_from_resource (icon_path);
+ gtk_widget_set_margin_end (image, 6);
+ gtk_widget_show (image);
+ gtk_grid_attach (GTK_GRID (grid), image, 1, 0, 1, 1);
+
+ label = (GtkWidget *) g_object_new (GTK_TYPE_LABEL,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "halign", GTK_ALIGN_START,
+ "expand", TRUE,
+ "label", title,
+ "use-markup", TRUE,
+ "use-underline", TRUE,
+ "visible", TRUE,
+ "xalign", 0.0,
+ NULL);
+ gtk_widget_show (label);
+ gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
+
+ attributes = pango_attr_list_new ();
+ pango_attr_list_insert (attributes, pango_attr_scale_new (0.9));
+
+ label = (GtkWidget *) g_object_new (GTK_TYPE_LABEL,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "halign", GTK_ALIGN_START,
+ "expand", TRUE,
+ "label", subtitle,
+ "use-markup", TRUE,
+ "use-underline", TRUE,
+ "visible", TRUE,
+ "xalign", 0.0,
+ "attributes", attributes,
+ NULL);
+ if (!warning_color)
+ gtk_style_context_add_class (gtk_widget_get_style_context (label),
+ GTK_STYLE_CLASS_DIM_LABEL);
+ else
+ gtk_style_context_add_class (gtk_widget_get_style_context (label),
+ GTK_STYLE_CLASS_ERROR); //FIXME doesn't work
+ gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 2, 1);
+
+ pango_attr_list_unref (attributes);
+
+ return grid;
+}
+
+static const char *
+get_performance_inhibited_text (const char *inhibited)
+{
+ if (!inhibited || *inhibited == '\0')
+ return NULL;
+
+ if (g_str_equal (inhibited, "lap-detected"))
+ return _("Lap detected: performance mode unavailable");
+ return _("Performance mode unavailable");
+}
+
+static PowerProfile
+profile_from_str (const char *profile)
+{
+ if (g_strcmp0 (profile, "power-saver") == 0)
+ return PERF_PROFILE_POWER_SAVER;
+ if (g_strcmp0 (profile, "balanced") == 0)
+ return PERF_PROFILE_BALANCED;
+ if (g_strcmp0 (profile, "performance") == 0)
+ return PERF_PROFILE_PERFORMANCE;
+
+ g_assert_not_reached ();
+}
+
+static GtkWidget *
+add_perf_profile_row (CcPowerPanel *self,
+ const char *profile_str,
+ const char *performance_inhibited)
+{
+ GtkWidget *row, *box, *title, *button;
+ const char *text, *subtext, *icon_path;
+ gboolean warning_color;
+ guint profile;
+
+ warning_color = FALSE;
+ profile = profile_from_str (profile_str);
+ switch (profile)
+ {
+ case PERF_PROFILE_PERFORMANCE:
+ text = _("Performance");
+ subtext = get_performance_inhibited_text (performance_inhibited);
+ if (subtext)
+ warning_color = TRUE;
+ else
+ subtext = _("High performance and power usage.");
+ icon_path = "/org/gnome/control-center/power/performance-symbolic.svg";
+ break;
+ case PERF_PROFILE_BALANCED:
+ text = _("Balanced Power");
+ subtext = _("Standard performance and power usage.");
+ icon_path = "/org/gnome/control-center/power/balanced-symbolic.svg";
+ break;
+ case PERF_PROFILE_POWER_SAVER:
+ text = _("Power Saver");
+ subtext = _("Reduced performance and power usage.");
+ icon_path = "/org/gnome/control-center/power/power-saver-symbolic.svg";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ row = no_prelight_row_new ();
+ gtk_widget_show (row);
+ g_object_set_data (G_OBJECT (row), "rank", GUINT_TO_POINTER (profile));
+ box = row_box_new ();
+ gtk_container_add (GTK_CONTAINER (row), box);
+
+ title = performance_row_new (text, icon_path, subtext, warning_color, &button);
+ self->profile_buttons[profile] = button;
+ gtk_box_pack_start (GTK_BOX (box), title, TRUE, TRUE, 0);
+
+ return row;
+}
+
+static gint
+perf_profile_list_box_sort (GtkListBoxRow *row1,
+ GtkListBoxRow *row2,
+ gpointer user_data)
+{
+ guint row1_rank, row2_rank;
+
+ row1_rank = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (row1), "rank"));
+ row2_rank = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (row2), "rank"));
+
+ if (row1_rank < row2_rank)
+ return -1;
+ if (row1_rank > row2_rank)
+ 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
+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;
+ const char *selected_profile;
+ g_autoptr(GVariant) profiles = NULL;
+
+ 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_widget_set_margin_bottom (label, 12);
+ gtk_box_pack_start (GTK_BOX (self->vbox_power), label, FALSE, TRUE, 0);
+ gtk_widget_show (label);
+
+ 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);
+ 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");
+ selected_profile = variant_lookup_string (props, "SelectedProfile");
+
+ 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;
+ const char *name;
+
+ profile = g_variant_get_child_value (profiles, i);
+ if (!profile ||
+ !g_variant_is_of_type (profile, G_VARIANT_TYPE ("a{sv}")))
+ continue;
+
+ name = variant_lookup_string (profile, "Profile");
+ if (!name)
+ continue;
+ g_debug ("Adding row for profile '%s' (driver: %s)",
+ name, variant_lookup_string (profile, "Driver"));
+
+ row = add_perf_profile_row (self, name, performance_inhibited);
+ gtk_widget_show (row);
+
+ gtk_container_add (GTK_CONTAINER (widget), row);
+ gtk_size_group_add_widget (self->row_sizegroup, row);
+ }
+
+ for (i = 0; i < NUM_PERF_PROFILES; i++)
+ {
+ GtkWidget *source = NULL;
+ if (i >= 1 && self->profile_buttons[i - 1] != NULL)
+ source = self->profile_buttons[i - 1];
+ gtk_radio_button_join_group (GTK_RADIO_BUTTON (self->profile_buttons[i]),
+ GTK_RADIO_BUTTON (source));
+ }
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->profile_buttons[profile_from_str
(selected_profile)]), TRUE);
+
+ //FIXME listen for changes
+}
+
static void
add_battery_percentage (CcPowerPanel *self,
GtkListBox *listbox)
@@ -2581,6 +2905,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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]