Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions src/MainView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class Power.MainView : Switchboard.SettingsPage {
private const string SETTINGS_DAEMON_NAME = "org.gnome.SettingsDaemon.Power";
private const string SETTINGS_DAEMON_PATH = "/org/gnome/SettingsDaemon/Power";

private Gtk.DropDown powerbutton_dropdown;
private AccessibleDropDown powerbutton_dropdown;
private Gtk.Scale scale;
private PowerSettings screen;

Expand Down Expand Up @@ -201,12 +201,9 @@ public class Power.MainView : Switchboard.SettingsPage {
};

// FIXME: Virtual machines can only shutdown or do nothing. Tablets always suspend.
powerbutton_dropdown = new Gtk.DropDown.from_strings ({
_("Do nothing"),
_("Suspend"),
_("Ask to shutdown")
}) {
hexpand = true
string[] strings = {_("_Do nothing"), _("_Suspend"), _("_Ask to shutdown")};
powerbutton_dropdown = new AccessibleDropDown (strings, true) {
hexpand = true,
};

var powerbutton_label = new Gtk.Label (_("Power Button Behavior")) {
Expand Down Expand Up @@ -345,7 +342,7 @@ public class Power.MainView : Switchboard.SettingsPage {
update_powerbutton_dropdown ();
settings.changed["power-button-action"].connect (update_powerbutton_dropdown);

powerbutton_dropdown.notify["selected"].connect (() => {
powerbutton_dropdown.selection_changed.connect (() => {
int[] map = {0, 1, 3};
settings.set_enum (
"power-button-action",
Expand Down
133 changes: 133 additions & 0 deletions src/Widgets/AccessibleDropDown.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* SPDX-License-Identifier: GPL-2.0-or-later
* SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io)
*/

public class Power.AccessibleDropDown : Gtk.Box {
public signal void selection_changed ();

public string[] strings { get; construct; }
public uint selected {
get {
return dropdown.selected;
}

set {
dropdown.selected = value;
}
}

public Object? selected_item {
get {
return dropdown.selected_item;
}
}

public Gtk.DropDown dropdown { get; private set; }
public bool show_selected_icon { get; construct; }
private ListStore model;

// Array parameter can contain strings with a mnenomic character specified by a preceding underscore
public AccessibleDropDown (string[] mnemonic_strings, bool show) {
Object (
strings: mnemonic_strings,
show_selected_icon: show
);
}

construct {
model = new ListStore (typeof (Gtk.StringObject));
foreach (string s in strings) {
model.append (new Gtk.StringObject (s));
}

var f = new Gtk.SignalListItemFactory ();
f.setup.connect ((obj) => {
var li = (Gtk.ListItem)obj;
var widget = new ItemWidget ("", this);
li.set_child (widget);
li.bind_property ("selected", widget, "selected", DEFAULT);
li.bind_property ("position", widget, "pos", DEFAULT);
});
f.bind.connect ((obj) => {
var li = (Gtk.ListItem)obj;
var widget = (ItemWidget)(li.child);
var text = ((Gtk.StringObject)(li.get_item ())).get_string ();
widget.label.set_text_with_mnemonic (text);
});
f.unbind.connect ((obj) => {
// No action required
});
f.teardown.connect ((obj) => {
// Do we need to reverse the property bindings created in setup?
// Probably not because in this usage teardown only occurs when the dropdown closes
});

dropdown = new Gtk.DropDown (model, null) {
factory = f
};

dropdown.notify["selected"].connect (() => {
selection_changed ();
});

dropdown.mnemonic_activate.connect ((group_cycling) => {
warning ("dropdown mnemonic activate - group cycling %s", group_cycling.to_string ());
warning ("selected is %u", selected);
});

append (dropdown);
bind_property ("hexpand", dropdown, "hexpand");
}

public void activate () {
dropdown.activate ();
}

private class ItemWidget : Gtk.Grid {
public Gtk.Label label { get; construct; }
public AccessibleDropDown md { get; construct; }
public bool selected { get; set; }
public uint pos { get; set; }

private Gtk.Button mnemonic_widget;
private Gtk.Image icon;

public ItemWidget (string text, AccessibleDropDown md) {
Object (
label: new Gtk.Label (text) {
use_underline = true,
halign = START,
hexpand = true
},
md: md
);

mnemonic_widget = new Gtk.Button () {
halign = END
};

label.set_mnemonic_widget (this.mnemonic_widget);
mnemonic_widget.mnemonic_activate.connect (() => {
md.selected = pos;
md.activate ();
return false;
});

attach (label, 0, 0);
if (md.show_selected_icon) {
icon = new Gtk.Image.from_icon_name ("emblem-default") {
visible = selected
};

icon.add_css_class ("flat");
attach (icon, 1, 0);
bind_property ("selected", icon, "visible");
}
}

construct {
hexpand = md.hexpand;
}
}
}
37 changes: 20 additions & 17 deletions src/Widgets/LidCloseActionComboBox.vala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Power.LidCloseActionComboBox : Gtk.Widget {

private static Polkit.Permission? permission = null;

private Gtk.DropDown dropdown;
private AccessibleDropDown dropdown;
private uint previous_active;

public LidCloseActionComboBox (bool dock) {
Expand All @@ -37,28 +37,31 @@ class Power.LidCloseActionComboBox : Gtk.Widget {
}

construct {
dropdown = new Gtk.DropDown (null, null) {
hexpand = true
};
dropdown.set_parent (this);

var helper = LogindHelper.get_logind_helper ();
if (helper != null && helper.present) {
dropdown.model = new Gtk.StringList ({
_("Suspend"),
_("Shutdown"),
_("Lock"),
_("Halt"),
_("Do nothing")
});
var helper_present = helper != null && helper.present;
string[] strings;
if (helper_present) {
strings = {
_("_Suspend"),
_("Sh_utdown"),
_("_Lock"),
_("_Halt"),
_("_Do nothing")
};
} else {
dropdown.model = new Gtk.StringList ({_("Not supported")});
dropdown.sensitive = false;
strings = {_("Not supported")};
}

dropdown = new AccessibleDropDown (strings, true) {
hexpand = true,
sensitive = helper_present
};

dropdown.set_parent (this);

update_current_action ();
previous_active = dropdown.selected;
dropdown.notify["selected"].connect (on_changed);
dropdown.selection_changed.connect (on_changed);
}

// Returns true on success
Expand Down
94 changes: 25 additions & 69 deletions src/Widgets/TimeoutComboBox.vala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*/

class Power.TimeoutComboBox : Granite.Bin {
private Greeter.AccountsService? greeter_act = null;
public GLib.Settings schema { get; construct; }
public string key { get; construct; }
public int selected_seconds { get; set; }

private string? _enum_property = null;
public string? enum_property {
Expand Down Expand Up @@ -45,11 +47,9 @@ class Power.TimeoutComboBox : Granite.Bin {
}
}

public GLib.Settings schema { get; construct; }
public string key { get; construct; }
private Greeter.AccountsService? greeter_act = null;
private VariantType key_type;
private Gtk.DropDown dropdown;

private AccessibleDropDown dropdown;
private const int SECS_IN_MINUTE = 60;
private const int[] TIMEOUT = {
0,
Expand All @@ -71,28 +71,25 @@ class Power.TimeoutComboBox : Granite.Bin {
construct {
key_type = schema.get_value (key).get_type ();

var liststore = new GLib.ListStore (typeof (Timeout));
liststore.append (new Timeout (_("Never"), 0, _("(Results in higher energy usage)")));
liststore.append (new Timeout (_("5 min"), 5 * SECS_IN_MINUTE));
liststore.append (new Timeout (_("10 min"), 10 * SECS_IN_MINUTE));
liststore.append (new Timeout (_("15 min"), 15 * SECS_IN_MINUTE));
liststore.append (new Timeout (_("30 min"), 30 * SECS_IN_MINUTE));
liststore.append (new Timeout (_("45 min"), 45 * SECS_IN_MINUTE));
liststore.append (new Timeout (_("1 hour"), 60 * SECS_IN_MINUTE));
liststore.append (new Timeout (_("2 hours"), 120 * SECS_IN_MINUTE));

var factory = new Gtk.SignalListItemFactory ();
factory.bind.connect (bind_factory);

dropdown = new Gtk.DropDown (liststore, null) {
factory = factory
string[] strings = {
_("Never (uses more energy)"),
_("5 min"),
_("10 min"),
_("30 min"),
_("45 min"),
_("1 hour"),
_("2 hours")
};

dropdown = new AccessibleDropDown (strings, true) {
hexpand = true
};

child = dropdown;

setup_accountsservice.begin ();

dropdown.notify["selected"].connect (update_settings);
dropdown.selection_changed.connect (update_settings);
schema.changed[key].connect (update_combo);
}

Expand Down Expand Up @@ -123,10 +120,13 @@ class Power.TimeoutComboBox : Granite.Bin {

schema.changed[key].disconnect (update_combo);

int[] map = {0, 5, 10, 15, 30, 45, 60, 120};
selected_seconds = map[dropdown.selected] * SECS_IN_MINUTE;

if (key_type.equal (VariantType.UINT32)) {
schema.set_uint (key, (uint) ((Timeout) dropdown.selected_item).seconds);
schema.set_uint (key, (uint) selected_seconds);
} else if (key_type.equal (VariantType.INT32)) {
schema.set_int (key, ((Timeout) dropdown.selected_item).seconds);
schema.set_int (key, selected_seconds);
} else {
critical ("Unsupported key type in schema");
}
Expand All @@ -135,10 +135,10 @@ class Power.TimeoutComboBox : Granite.Bin {

if (greeter_act != null) {
if (key == "sleep-inactive-ac-timeout") {
greeter_act.sleep_inactive_ac_timeout = ((Timeout) dropdown.selected_item).seconds;
greeter_act.sleep_inactive_ac_timeout = selected_seconds;
greeter_act.sleep_inactive_ac_type = schema.get_enum (enum_property);
} else if (key == "sleep-inactive-battery-timeout") {
greeter_act.sleep_inactive_battery_timeout = ((Timeout) dropdown.selected_item).seconds;
greeter_act.sleep_inactive_battery_timeout = selected_seconds;
greeter_act.sleep_inactive_battery_type = schema.get_enum (enum_property);
}
}
Expand Down Expand Up @@ -182,48 +182,4 @@ class Power.TimeoutComboBox : Granite.Bin {
dropdown.selected = find_closest (val);
dropdown.notify["selected"].connect (update_settings);
}

private void bind_factory (Object object) {
var list_item = (Gtk.ListItem) object;
var timeout = (Timeout) list_item.item;
list_item.child = timeout.get_widget ();
}

private class Timeout : Object {
public string label { get; construct; }
public string description { get; construct; }
public int seconds { get; construct; }

public Timeout (string label, int seconds, string description = "") {
Object (
label: label,
seconds: seconds,
description: description
);
}

public Gtk.Widget get_widget () {
var title = new Gtk.Label (label) {
valign = BASELINE,
xalign = 0
};

var box = new Granite.Box (HORIZONTAL, HALF);
box.append (title);

if (description != "") {
var description = new Gtk.Label (description) {
valign = BASELINE,
xalign = 0,
wrap = true
};
description.add_css_class (Granite.CssClass.SMALL);
description.add_css_class (Granite.CssClass.WARNING);

box.append (description);
}

return box;
}
}
}
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ plug_files = files(
'Widgets/TimeoutComboBox.vala',
'Widgets/LidCloseActionComboBox.vala',
'Widgets/PowerModeButton.vala',
'Widgets/AccessibleDropDown.vala'
)

switchboard_dep = dependency('switchboard-3')
Expand Down