quick-settings: add DND, Dark Style, Power Profiles and Command tiles

parent c5a049f2
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 8 0 c -4.40625 0 -8 3.59375 -8 8 s 3.59375 8 8 8 s 8 -3.59375 8 -8 s -3.59375 -8 -8 -8 z m 0 1.941406 c 3.359375 0 6.058594 2.699219 6.058594 6.058594 s -2.699219 6.058594 -6.058594 6.058594 z m 0 0" fill="#222222"/></svg>
......@@ -5,6 +5,7 @@
<file preprocess="xml-stripblanks">icons/scalable/actions/ximper-shell-notification-center-close-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/ximper-shell-notification-center-up-small-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/ximper-shell-notification-center-down-small-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/dark-mode-symbolic.svg</file>
<file preprocess="xml-stripblanks">ui/notification_window.ui</file>
<file preprocess="xml-stripblanks">ui/notification.ui</file>
......
namespace XimperShellNotificationCenter.Widgets {
public class CommandTile : QuickSettingsTile {
private string command = "";
private string update_command = "";
public CommandTile (Json.Object ?cfg) {
string icon_name = "application-x-executable-symbolic";
string label = "";
if (cfg != null) {
string ?i = cfg.get_string_member_with_default (
"icon", null);
if (i != null) icon_name = i;
string ?l = cfg.get_string_member_with_default (
"label", null);
if (l != null) {
label = l;
} else {
warning ("Command tile missing 'label'");
}
command = cfg.get_string_member_with_default (
"command", "");
update_command = cfg.get_string_member_with_default (
"update-command", "");
active = cfg.get_boolean_member_with_default (
"active", false);
}
base (icon_name, label);
}
public override void on_toggle () {
active = !active;
string[] env = {
"XSNC_TOGGLE_STATE=" + active.to_string ()
};
run_command.begin (command, env);
}
private async void run_command (string cmd, string[] env) {
string msg;
yield Functions.execute_command (cmd, env, out msg);
}
public override void on_cc_visibility_change (bool visible) {
if (!visible || update_command == "") {
return;
}
run_update.begin ();
}
private async void run_update () {
string[] env = {
"XSNC_TOGGLE_STATE=" + active.to_string ()
};
string msg;
yield Functions.execute_command (
update_command, env, out msg);
active = (msg.strip ().up () == "TRUE");
}
}
}
namespace XimperShellNotificationCenter.Widgets {
public class DarkModeTile : QuickSettingsTile {
private Settings interface_settings;
public DarkModeTile (Json.Object ?cfg) {
base ("dark-mode-symbolic",
_("Dark Style"));
interface_settings = new Settings (
"org.gnome.desktop.interface");
sync_state ();
interface_settings.changed["color-scheme"].connect (
() => {
sync_state ();
});
}
private void sync_state () {
string scheme = interface_settings.get_string (
"color-scheme");
active = (scheme == "prefer-dark");
}
public override void on_toggle () {
string new_scheme = active
? "default" : "prefer-dark";
interface_settings.set_string (
"color-scheme", new_scheme);
}
}
}
namespace XimperShellNotificationCenter.Widgets {
public class DndTile : QuickSettingsTile {
public DndTile (Json.Object ?cfg) {
base ("notifications-disabled-symbolic",
_("Do Not Disturb"));
active = noti_daemon.dnd;
update_icon ();
noti_daemon.on_dnd_toggle.connect ((dnd) => {
active = dnd;
update_icon ();
});
}
private void update_icon () {
icon.set_from_icon_name (active
? "notifications-disabled-symbolic"
: "preferences-system-notifications-symbolic");
}
public override void on_toggle () {
noti_daemon.dnd = !noti_daemon.dnd;
}
}
}
namespace XimperShellNotificationCenter.Widgets {
[DBus (name = "net.hadess.PowerProfiles")]
interface PowerProfilesDBus : Object {
public abstract string active_profile { owned get; set; }
public abstract HashTable<string, Variant>[] profiles {
owned get;
}
}
public class PowerProfilesTile : QuickSettingsTile {
private PowerProfilesDBus ?proxy = null;
private DBusProxy ?raw_proxy = null;
private string[] profile_names = {};
public PowerProfilesTile (Json.Object ?cfg) {
base ("power-profile-balanced-symbolic",
_("Power Mode"));
setup_arrow ();
connect_dbus.begin ();
}
private async void connect_dbus () {
try {
proxy = yield Bus.get_proxy (BusType.SYSTEM,
"net.hadess.PowerProfiles",
"/net/hadess/PowerProfiles");
raw_proxy = proxy as DBusProxy;
load_profiles ();
sync_state ();
raw_proxy.g_properties_changed.connect (
on_properties_changed);
} catch (Error e) {
warning ("PowerProfiles D-Bus not available: %s",
e.message);
set_visible (false);
}
}
private void load_profiles () {
if (proxy == null) return;
profile_names = {};
foreach (var profile in proxy.profiles) {
Variant ?v = profile.lookup ("Profile");
if (v != null) {
profile_names += v.get_string ();
}
}
}
private void on_properties_changed (
Variant changed, string[] invalidated) {
var iter = changed.iterator ();
string key;
Variant val;
while (iter.next ("{sv}", out key, out val)) {
if (key == "ActiveProfile") {
sync_state ();
submenu_update_requested ();
} else if (key == "Profiles") {
load_profiles ();
submenu_update_requested ();
}
}
}
private void sync_state () {
if (proxy == null) return;
string profile = proxy.active_profile;
active = (profile != "balanced");
set_subtitle (get_profile_label (profile));
update_icon (profile);
}
private void update_icon (string profile) {
icon.set_from_icon_name (get_profile_icon (profile));
}
private static string get_profile_icon (string profile) {
switch (profile) {
case "performance":
return "power-profile-performance-symbolic";
case "power-saver":
return "power-profile-power-saver-symbolic";
default:
return "power-profile-balanced-symbolic";
}
}
private string get_profile_label (string profile) {
switch (profile) {
case "performance":
return _("Performance");
case "balanced":
return _("Balanced");
case "power-saver":
return _("Power Saver");
default:
return profile;
}
}
public override void on_toggle () {
if (proxy == null) return;
string current = proxy.active_profile;
// Cycle: balanced → performance → power-saver
string next;
if (current == "balanced") {
next = "performance";
} else if (current == "performance") {
next = "power-saver";
} else {
next = "balanced";
}
set_profile.begin (next);
}
private async void set_profile (string profile) {
if (raw_proxy == null) return;
try {
yield raw_proxy.call (
"org.freedesktop.DBus.Properties.Set",
new Variant ("(ssv)",
"net.hadess.PowerProfiles",
"ActiveProfile",
new Variant.string (profile)),
DBusCallFlags.NONE, -1, null);
} catch (Error e) {
warning ("Failed to set power profile: %s",
e.message);
}
}
public override Gtk.Widget ?create_submenu () {
if (proxy == null) return null;
var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
box.add_css_class ("quick-settings-submenu");
string current = proxy.active_profile;
foreach (string name in profile_names) {
var row = new Gtk.Box (
Gtk.Orientation.HORIZONTAL, 8);
row.add_css_class ("submenu-row");
var row_icon = new Gtk.Image.from_icon_name (
get_profile_icon (name));
var row_label = new Gtk.Label (
get_profile_label (name));
row_label.set_hexpand (true);
row_label.set_halign (Gtk.Align.START);
row.append (row_icon);
row.append (row_label);
if (name == current) {
var check = new Gtk.Image.from_icon_name (
"object-select-symbolic");
row.append (check);
}
var btn = new Gtk.Button ();
btn.set_child (row);
btn.add_css_class ("flat");
string profile_name = name;
btn.clicked.connect (() => {
set_profile.begin (profile_name);
});
box.append (btn);
}
return box;
}
}
}
......@@ -54,6 +54,13 @@ widget_sources = [
'controlCenter/widgets/inhibitors/inhibitors.vala',
# Widget: Power Profiles (D-Bus PPD integration for menubar)
'controlCenter/widgets/powerProfiles/powerProfiles.vala',
# Widget: Quick Settings
'controlCenter/widgets/quickSettings/quickSettings.vala',
'controlCenter/widgets/quickSettings/quickSettingsTile.vala',
'controlCenter/widgets/quickSettings/tiles/dndTile.vala',
'controlCenter/widgets/quickSettings/tiles/darkModeTile.vala',
'controlCenter/widgets/quickSettings/tiles/powerProfilesTile.vala',
'controlCenter/widgets/quickSettings/tiles/commandTile.vala',
]
app_sources = [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment