Add toggle button (#304)
* Add toggle button * Toggle button documentation * Fix issues * Add env variable for toggle button * Add state update command for toggle buttons * Fix Uncrustify * Update README
This commit is contained in:
27
README.md
27
README.md
@@ -38,6 +38,7 @@ Table of Contents
|
|||||||
* [Run](#run)
|
* [Run](#run)
|
||||||
* [Control Center Shortcuts](#control-center-shortcuts)
|
* [Control Center Shortcuts](#control-center-shortcuts)
|
||||||
* [Configuring](#configuring)
|
* [Configuring](#configuring)
|
||||||
|
* [Toggle Buttons](#toggle-buttons)
|
||||||
* [Notification Inhibition](#notification-inhibition)
|
* [Notification Inhibition](#notification-inhibition)
|
||||||
* [Scripting](#scripting)
|
* [Scripting](#scripting)
|
||||||
* [Disable scripting](#disable-scripting)
|
* [Disable scripting](#disable-scripting)
|
||||||
@@ -242,6 +243,32 @@ to your `~/.config/swaync/` folder to customize without needing root access.
|
|||||||
**Tip**: running swaync with `GTK_DEBUG=interactive swaync` will open a inspector
|
**Tip**: running swaync with `GTK_DEBUG=interactive swaync` will open a inspector
|
||||||
window that'll allow you to see all of the CSS classes + other information.
|
window that'll allow you to see all of the CSS classes + other information.
|
||||||
|
|
||||||
|
## Toggle Buttons
|
||||||
|
|
||||||
|
To add toggle buttons to your control center you can set the "type" in any acton to "toggle".
|
||||||
|
The toggle button supports different commands depending on the state of the button and
|
||||||
|
an "update_command" to update the state in case of changes from outside swaync. The update_command
|
||||||
|
is called every time the control center is opened/closed.
|
||||||
|
The active toggle button also gains the css-class ".toggle:checked"
|
||||||
|
|
||||||
|
`config.json` example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"buttons-gird": { // also works with actions in menubar widget
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"label": "WiFi",
|
||||||
|
"type": "toggle",
|
||||||
|
"active": true,
|
||||||
|
"command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && nmcli radio wifi on || nmcli radio wifi off'",
|
||||||
|
"update_command": "sh -c '[[ $(nmcli radio wifi) == \"enabled\" ]] && echo true || echo false'"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Notification Inhibition
|
## Notification Inhibition
|
||||||
|
|
||||||
Notifications can be inhibited through the provided `swaync-client` executable
|
Notifications can be inhibited through the provided `swaync-client` executable
|
||||||
|
@@ -377,6 +377,22 @@ config file to be able to detect config errors
|
|||||||
type: string ++
|
type: string ++
|
||||||
default: "" ++
|
default: "" ++
|
||||||
description: "Command to be executed on click" ++
|
description: "Command to be executed on click" ++
|
||||||
|
type: ++
|
||||||
|
type: string ++
|
||||||
|
default: "normal" ++
|
||||||
|
description: Type of the button. ++
|
||||||
|
Toggle buttons receive the '.active' css class ++
|
||||||
|
enum: ["normal", "toggle"] ++
|
||||||
|
update-command: ++
|
||||||
|
type: string ++
|
||||||
|
default: "" ++
|
||||||
|
description: "Command to be executed on visibility change of ++
|
||||||
|
cc to update the active state of the toggle button (should ++
|
||||||
|
echo true or false)" ++
|
||||||
|
active: ++
|
||||||
|
type: bool ++
|
||||||
|
default: false ++
|
||||||
|
description: Wether the toggle button is active as default or not ++
|
||||||
description: A list of actions containing a label and a command ++
|
description: A list of actions containing a label and a command ++
|
||||||
description: A button to reveal a dropdown with action-buttons ++
|
description: A button to reveal a dropdown with action-buttons ++
|
||||||
buttons#<name>: ++
|
buttons#<name>: ++
|
||||||
@@ -402,6 +418,24 @@ config file to be able to detect config errors
|
|||||||
type: string ++
|
type: string ++
|
||||||
default: "" ++
|
default: "" ++
|
||||||
description: "Command to be executed on click" ++
|
description: "Command to be executed on click" ++
|
||||||
|
type: ++
|
||||||
|
type: string ++
|
||||||
|
default: "normal" ++
|
||||||
|
description: Type of the button ++
|
||||||
|
Toggle buttons receive the '.active' css class and an env ++
|
||||||
|
variable "SWAYNC_TOGGLE_STATE" is set. See example usage in the ++
|
||||||
|
default config.json ++
|
||||||
|
enum: ["normal", "toggle"] ++
|
||||||
|
update-command: ++
|
||||||
|
type: string ++
|
||||||
|
default: "" ++
|
||||||
|
description: "Command to be executed on visibility change of ++
|
||||||
|
cc to update the active state of the toggle button (should ++
|
||||||
|
echo true or false)" ++
|
||||||
|
active: ++
|
||||||
|
type: bool ++
|
||||||
|
default: false ++
|
||||||
|
description: Wether the toggle button is active as default or not ++
|
||||||
description: A list of actions containing a label and a command ++
|
description: A list of actions containing a label and a command ++
|
||||||
description: A list of buttons to be displayed in the menu-button-bar ++
|
description: A list of buttons to be displayed in the menu-button-bar ++
|
||||||
*buttons-grid*++
|
*buttons-grid*++
|
||||||
@@ -422,6 +456,18 @@ config file to be able to detect config errors
|
|||||||
type: string ++
|
type: string ++
|
||||||
default: "" ++
|
default: "" ++
|
||||||
description: "Command to be executed on click" ++
|
description: "Command to be executed on click" ++
|
||||||
|
type: ++
|
||||||
|
type: string ++
|
||||||
|
default: "normal" ++
|
||||||
|
description: Type of the button ++
|
||||||
|
Toggle buttons receive the '.active' css class and an env ++
|
||||||
|
variable "SWAYNC_TOGGLE_STATE" is set. See example usage in the ++
|
||||||
|
default config.json ++
|
||||||
|
enum: ["normal", "toggle"] ++
|
||||||
|
active: ++
|
||||||
|
type: bool ++
|
||||||
|
default: false ++
|
||||||
|
description: Wether the toggle button is active as default or not ++
|
||||||
description: A list of actions containing a label and a command ++
|
description: A list of actions containing a label and a command ++
|
||||||
description: A grid of buttons that execute shell commands ++
|
description: A grid of buttons that execute shell commands ++
|
||||||
#START pulse-audio
|
#START pulse-audio
|
||||||
|
@@ -74,6 +74,17 @@
|
|||||||
"mpris": {
|
"mpris": {
|
||||||
"image-size": 96,
|
"image-size": 96,
|
||||||
"image-radius": 12
|
"image-radius": 12
|
||||||
|
},
|
||||||
|
"buttons-grid": {
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"label": "直",
|
||||||
|
"type": "toggle",
|
||||||
|
"active": true,
|
||||||
|
"command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && nmcli radio wifi on || nmcli radio wifi off'",
|
||||||
|
"update_command": "sh -c '[[ $(nmcli radio wifi) == \"enabled\" ]] && echo true || echo false'"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -427,6 +427,22 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Command to be executed on click",
|
"description": "Command to be executed on click",
|
||||||
"default": ""
|
"default": ""
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Type of the button; toggle buttons receive the .active css class and an env variable 'SWAYNC_TOGGLE_STATE' is set. See example in the default config.json",
|
||||||
|
"default": "normal",
|
||||||
|
"enum": ["normal", "toggle"]
|
||||||
|
},
|
||||||
|
"update-command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Command to be executed on visibility change of cc to update the active state of the toggle button (should echo true or false)",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"type": "bool",
|
||||||
|
"description": "Wether the toggle button is active as default or not",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,20 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
public unowned SwayncDaemon swaync_daemon;
|
public unowned SwayncDaemon swaync_daemon;
|
||||||
public unowned NotiDaemon noti_daemon;
|
public unowned NotiDaemon noti_daemon;
|
||||||
|
|
||||||
|
public enum ButtonType {
|
||||||
|
TOGGLE,
|
||||||
|
NORMAL;
|
||||||
|
|
||||||
|
public static ButtonType parse (string value) {
|
||||||
|
switch (value) {
|
||||||
|
case "toggle":
|
||||||
|
return ButtonType.TOGGLE;
|
||||||
|
default:
|
||||||
|
return ButtonType.NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected BaseWidget (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
protected BaseWidget (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||||
this.suffix = suffix;
|
this.suffix = suffix;
|
||||||
this.key = widget_name + (suffix.length > 0 ? "#%s".printf (suffix) : "");
|
this.key = widget_name + (suffix.length > 0 ? "#%s".printf (suffix) : "");
|
||||||
@@ -91,14 +105,23 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
for (int i = 0; i < actions.get_length (); i++) {
|
for (int i = 0; i < actions.get_length (); i++) {
|
||||||
string label = actions.get_object_element (i).get_string_member_with_default ("label", "label");
|
string label = actions.get_object_element (i).get_string_member_with_default ("label", "label");
|
||||||
string command = actions.get_object_element (i).get_string_member_with_default ("command", "");
|
string command = actions.get_object_element (i).get_string_member_with_default ("command", "");
|
||||||
|
string t = actions.get_object_element (i).get_string_member_with_default ("type", "normal");
|
||||||
|
ButtonType type = ButtonType.parse (t);
|
||||||
|
string update_command =
|
||||||
|
actions.get_object_element (i).get_string_member_with_default ("update-command", "");
|
||||||
|
bool active = actions.get_object_element (i).get_boolean_member_with_default ("active", false);
|
||||||
res[i] = Action () {
|
res[i] = Action () {
|
||||||
label = label,
|
label = label,
|
||||||
command = command
|
command = command,
|
||||||
|
type = type,
|
||||||
|
update_command = update_command,
|
||||||
|
active = active
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected async void execute_command (string cmd, string[] env_additions = {}) {
|
protected async void execute_command (string cmd, string[] env_additions = {}) {
|
||||||
string msg = "";
|
string msg = "";
|
||||||
yield Functions.execute_command (cmd, env_additions, out msg);
|
yield Functions.execute_command (cmd, env_additions, out msg);
|
||||||
|
@@ -10,6 +10,7 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Action[] actions;
|
Action[] actions;
|
||||||
|
List<ToggleButton> toggle_buttons;
|
||||||
|
|
||||||
public ButtonsGrid (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
public ButtonsGrid (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||||
base (suffix, swaync_daemon, noti_daemon);
|
base (suffix, swaync_daemon, noti_daemon);
|
||||||
@@ -26,14 +27,29 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
|
|
||||||
// add action to container
|
// add action to container
|
||||||
foreach (var act in actions) {
|
foreach (var act in actions) {
|
||||||
|
switch (act.type) {
|
||||||
|
case ButtonType.TOGGLE:
|
||||||
|
ToggleButton tb = new ToggleButton (act.label, act.command, act.update_command, act.active);
|
||||||
|
container.insert (tb, -1);
|
||||||
|
toggle_buttons.append (tb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
Gtk.Button b = new Gtk.Button.with_label (act.label);
|
Gtk.Button b = new Gtk.Button.with_label (act.label);
|
||||||
|
|
||||||
b.clicked.connect (() => execute_command.begin (act.command));
|
b.clicked.connect (() => execute_command.begin (act.command));
|
||||||
|
|
||||||
container.insert (b, -1);
|
container.insert (b, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
show_all ();
|
show_all ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void on_cc_visibility_change (bool value) {
|
||||||
|
if (!value) {
|
||||||
|
foreach (var tb in toggle_buttons) {
|
||||||
|
tb.on_update.begin ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,9 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
public struct Action {
|
public struct Action {
|
||||||
string ? label;
|
string ? label;
|
||||||
string ? command;
|
string ? command;
|
||||||
|
BaseWidget.ButtonType ? type;
|
||||||
|
string ? update_command;
|
||||||
|
bool ? active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Menubar : BaseWidget {
|
public class Menubar : BaseWidget {
|
||||||
@@ -38,6 +41,7 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
Gtk.Box topbar_container;
|
Gtk.Box topbar_container;
|
||||||
|
|
||||||
List<ConfigObject ?> menu_objects;
|
List<ConfigObject ?> menu_objects;
|
||||||
|
List<ToggleButton> toggle_buttons;
|
||||||
|
|
||||||
public Menubar (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
public Menubar (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||||
base (suffix, swaync_daemon, noti_daemon);
|
base (suffix, swaync_daemon, noti_daemon);
|
||||||
@@ -74,11 +78,18 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
if (obj.name != null) container.get_style_context ().add_class (obj.name);
|
if (obj.name != null) container.get_style_context ().add_class (obj.name);
|
||||||
|
|
||||||
foreach (Action a in obj.actions) {
|
foreach (Action a in obj.actions) {
|
||||||
|
switch (a.type) {
|
||||||
|
case ButtonType.TOGGLE:
|
||||||
|
ToggleButton tb = new ToggleButton (a.label, a.command, a.update_command, a.active);
|
||||||
|
container.add (tb);
|
||||||
|
toggle_buttons.append (tb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
Gtk.Button b = new Gtk.Button.with_label (a.label);
|
Gtk.Button b = new Gtk.Button.with_label (a.label);
|
||||||
|
|
||||||
b.clicked.connect (() => execute_command.begin (a.command));
|
b.clicked.connect (() => execute_command.begin (a.command));
|
||||||
|
|
||||||
container.add (b);
|
container.add (b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch (obj.position) {
|
switch (obj.position) {
|
||||||
case Position.LEFT:
|
case Position.LEFT:
|
||||||
@@ -210,6 +221,9 @@ namespace SwayNotificationCenter.Widgets {
|
|||||||
foreach (var obj in menu_objects) {
|
foreach (var obj in menu_objects) {
|
||||||
obj.revealer ?.set_reveal_child (false);
|
obj.revealer ?.set_reveal_child (false);
|
||||||
}
|
}
|
||||||
|
foreach (var tb in toggle_buttons) {
|
||||||
|
tb.on_update.begin ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
src/controlCenter/widgets/shared/toggleButton.vala
Normal file
44
src/controlCenter/widgets/shared/toggleButton.vala
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
namespace SwayNotificationCenter.Widgets {
|
||||||
|
class ToggleButton : Gtk.ToggleButton {
|
||||||
|
|
||||||
|
private string command;
|
||||||
|
private string update_command;
|
||||||
|
|
||||||
|
public ToggleButton (string label, string command, string update_command, bool active) {
|
||||||
|
this.command = command;
|
||||||
|
this.update_command = update_command;
|
||||||
|
this.label = label;
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
this.active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggled.connect (on_toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void on_toggle () {
|
||||||
|
string msg = "";
|
||||||
|
string[] env_additions = { "SWAYNC_TOGGLE_STATE=" + this.active.to_string () };
|
||||||
|
yield Functions.execute_command (this.command, env_additions, out msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void on_update () {
|
||||||
|
if (update_command == "") return;
|
||||||
|
string msg = "";
|
||||||
|
string[] env_additions = { "SWAYNC_TOGGLE_STATE=" + this.active.to_string () };
|
||||||
|
yield Functions.execute_command (this.update_command, env_additions, out msg);
|
||||||
|
try {
|
||||||
|
// remove trailing whitespaces
|
||||||
|
Regex regex = new Regex ("\\s+$");
|
||||||
|
string res = regex.replace (msg, msg.length, 0, "");
|
||||||
|
if (res.up () == "TRUE") {
|
||||||
|
this.active = true;
|
||||||
|
} else {
|
||||||
|
this.active = false;
|
||||||
|
}
|
||||||
|
} catch (RegexError e) {
|
||||||
|
stderr.printf ("RegexError: %s\n", e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -313,13 +313,38 @@ namespace SwayNotificationCenter {
|
|||||||
Shell.parse_argv (cmd, out argvp);
|
Shell.parse_argv (cmd, out argvp);
|
||||||
|
|
||||||
Pid child_pid;
|
Pid child_pid;
|
||||||
Process.spawn_async (
|
int std_input;
|
||||||
|
int std_output;
|
||||||
|
int std_err;
|
||||||
|
Process.spawn_async_with_pipes (
|
||||||
"/",
|
"/",
|
||||||
argvp,
|
argvp,
|
||||||
spawn_env,
|
spawn_env,
|
||||||
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
|
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
|
||||||
null,
|
null,
|
||||||
out child_pid);
|
out child_pid,
|
||||||
|
out std_input,
|
||||||
|
out std_output,
|
||||||
|
out std_err);
|
||||||
|
|
||||||
|
// stdout:
|
||||||
|
string res = "";
|
||||||
|
IOChannel output = new IOChannel.unix_new (std_output);
|
||||||
|
output.add_watch (IOCondition.IN | IOCondition.HUP, (channel, condition) => {
|
||||||
|
if (condition == IOCondition.HUP) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
channel.read_line (out res, null, null);
|
||||||
|
return true;
|
||||||
|
} catch (IOChannelError e) {
|
||||||
|
stderr.printf ("stdout: IOChannelError: %s\n", e.message);
|
||||||
|
return false;
|
||||||
|
} catch (ConvertError e) {
|
||||||
|
stderr.printf ("stdout: ConvertError: %s\n", e.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Close the child when the spawned process is idling
|
// Close the child when the spawned process is idling
|
||||||
int end_status = 0;
|
int end_status = 0;
|
||||||
@@ -330,6 +355,7 @@ namespace SwayNotificationCenter {
|
|||||||
});
|
});
|
||||||
// Waits until `run_script.callback()` is called above
|
// Waits until `run_script.callback()` is called above
|
||||||
yield;
|
yield;
|
||||||
|
msg = res;
|
||||||
return end_status == 0;
|
return end_status == 0;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
stderr.printf ("Run_Script Error: %s\n", e.message);
|
stderr.printf ("Run_Script Error: %s\n", e.message);
|
||||||
|
@@ -26,6 +26,7 @@ widget_sources = [
|
|||||||
# Helpers
|
# Helpers
|
||||||
'controlCenter/widgets/baseWidget.vala',
|
'controlCenter/widgets/baseWidget.vala',
|
||||||
'controlCenter/widgets/factory.vala',
|
'controlCenter/widgets/factory.vala',
|
||||||
|
'controlCenter/widgets/shared/toggleButton.vala',
|
||||||
# Widget: Title
|
# Widget: Title
|
||||||
'controlCenter/widgets/title/title.vala',
|
'controlCenter/widgets/title/title.vala',
|
||||||
# Widget: Dnd
|
# Widget: Dnd
|
||||||
|
@@ -282,8 +282,11 @@
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* style given to the active toggle button */
|
||||||
|
.widget-buttons-grid>flowbox>flowboxchild>button.toggle:checked {
|
||||||
|
}
|
||||||
|
|
||||||
.widget-buttons-grid>flowbox>flowboxchild>button:hover {
|
.widget-buttons-grid>flowbox>flowboxchild>button:hover {
|
||||||
background: @noti-bg-hover;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Menubar widget */
|
/* Menubar widget */
|
||||||
|
Reference in New Issue
Block a user