diff --git a/man/swaync.5.scd b/man/swaync.5.scd index ada6f9b..75109a6 100644 --- a/man/swaync.5.scd +++ b/man/swaync.5.scd @@ -135,7 +135,7 @@ config file to be able to detect config errors type: bool ++ default: true ++ description: Display notification timestamps relative to now e.g. \"26 minutes ago\". ++ - If false, a local iso8601-formatted absolute timestamp is displayed. + If false, a local iso8601-formatted absolute timestamp is displayed. *control-center-height* ++ type: integer ++ @@ -231,6 +231,8 @@ config file to be able to detect config errors optional: true ++ *buttons-grid*++ optional: true ++ + *slider*++ + optional: true ++ #START pulse-audio *volume*++ optional: true ++ @@ -470,6 +472,51 @@ config file to be able to detect config errors description: Wether the toggle button is active as default or not ++ description: A list of actions containing a label and a command ++ description: A grid of buttons that execute shell commands ++ + *slider*++ + type: object ++ + css class: widget-slider ++ + properties: ++ + label: ++ + type: string ++ + optional: true ++ + default: "slider" ++ + description: Text displayed in front of the slider ++ + cmd_setter: ++ + type: string ++ + optional: true ++ + default: "" ++ + description: command to set the value ++ + cmd_getter: ++ + type: string ++ + optional: true ++ + default: "" ++ + description: command to get the actual value ++ + min: ++ + type: integer ++ + optional: true ++ + default: 0 ++ + description: minimum value of the slider range ++ + max: ++ + type: integer ++ + optional: true ++ + default: 100 ++ + description: maximum value of the slider range ++ + min_limit: ++ + type: integer ++ + optional: true ++ + default: 0 ++ + description: limit minimum value of the slider ++ + max_limit: ++ + type: integer ++ + optional: true ++ + default: 100 ++ + description: limit maximum value of the slider ++ + value_scale: ++ + type: integer ++ + optional: true ++ + default: 0 ++ + description: scale small value, slider round digits ++ + description: general slider control ++ #START pulse-audio *volume*++ type: object ++ diff --git a/src/configSchema.json b/src/configSchema.json index 6421007..931f20f 100644 --- a/src/configSchema.json +++ b/src/configSchema.json @@ -324,6 +324,9 @@ "^menubar(#[a-zA-Z0-9_-]{1,}){0,1}?$": { "$ref": "#/widgets/menubar" }, + "^slider(#[a-zA-Z0-9_-]{1,}){0,1}?$": { + "$ref": "#/widgets/slider" + }, "^volume(#[a-zA-Z0-9_-]{1,}){0,1}?$": { "$ref": "#/widgets/volume" }, @@ -446,9 +449,9 @@ "default": "" }, "active": { - "type": "boolean", - "description": "Wether the toggle button is active as default or not", - "default": false + "type": "boolean", + "description": "Wether the toggle button is active as default or not", + "default": false } } } @@ -482,13 +485,13 @@ "description": "Animation type for menu", "enum": ["slide_down", "slide_up", "none"] }, - "animation-duration":{ + "animation-duration": { "type": "integer", "default": 250, "description": "Duration of animation in milliseconds" }, "actions": { - "$ref" : "#/widgets/buttons-grid/properties/actions" + "$ref": "#/widgets/buttons-grid/properties/actions" } } }, @@ -504,12 +507,59 @@ "enum": ["right", "left"] }, "actions": { - "$ref" : "#/widgets/buttons-grid/properties/actions" + "$ref": "#/widgets/buttons-grid/properties/actions" } } } } }, + "slider": { + "type": "object", + "description": "general slider control", + "additionalProperties": false, + "properties": { + "label": { + "type": "string", + "description": "Text displayed in front of the slider", + "default": "slider" + }, + "cmd_setter": { + "type": "string", + "description": "command to set the value", + "default": "" + }, + "cmd_getter": { + "type": "string", + "description": "command to get the actual value", + "default": "" + }, + "min": { + "type": "integer", + "description": "minimum value of the slider range", + "default": 0 + }, + "max": { + "type": "integer", + "description": "maximum value of the slider range", + "default": 100 + }, + "min_limit": { + "type": "integer", + "description": "limit minimum value of the slider", + "default": 0 + }, + "max_limit": { + "type": "integer", + "description": "limit maximum value of the slider", + "default": 100 + }, + "value_scale": { + "type": "integer", + "default": 0, + "description": "scale small value, slider round digits" + } + } + }, "volume": { "type": "object", "description": "Slider to control pulse volume", @@ -561,7 +611,7 @@ "description": "Animation type for menu", "enum": ["slide_down", "slide_up", "none"] }, - "animation-duration":{ + "animation-duration": { "type": "integer", "default": 250, "description": "Duration of animation in milliseconds" diff --git a/src/controlCenter/widgets/factory.vala b/src/controlCenter/widgets/factory.vala index 0302c89..e7819d6 100644 --- a/src/controlCenter/widgets/factory.vala +++ b/src/controlCenter/widgets/factory.vala @@ -26,6 +26,9 @@ namespace SwayNotificationCenter.Widgets { case "buttons-grid": widget = new ButtonsGrid (suffix, swaync_daemon, noti_daemon); break; + case "slider": + widget = new Slider (suffix, swaync_daemon, noti_daemon); + break; #if HAVE_PULSE_AUDIO case "volume": widget = new Volume (suffix, swaync_daemon, noti_daemon); diff --git a/src/controlCenter/widgets/slider/slider.vala b/src/controlCenter/widgets/slider/slider.vala new file mode 100644 index 0000000..7ddbae0 --- /dev/null +++ b/src/controlCenter/widgets/slider/slider.vala @@ -0,0 +1,139 @@ +namespace SwayNotificationCenter.Widgets { + public class Slider : BaseWidget { + public override string widget_name { + get { + return "slider"; + } + } + + Gtk.Label label_widget = new Gtk.Label (null); + Gtk.Scale slider = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL, 0, 100, 1); + + private double min_limit; + private double max_limit; + private double ? last_set; + private bool cmd_ing = false; + + private string cmd_setter; + private string cmd_getter; + + public Slider (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) { + base (suffix, swaync_daemon, noti_daemon); + + int ? round_digits = 0; + + Json.Object ? config = get_config (this); + if (config != null) { + string ? label = get_prop (config, "label"); + label_widget.set_label (label ?? "Slider"); + + cmd_setter = get_prop (config, "cmd_setter") ?? ""; + cmd_getter = get_prop (config, "cmd_getter") ?? ""; + + int ? min = get_prop (config, "min"); + int ? max = get_prop (config, "max"); + int ? maxl = get_prop (config, "max_limit"); + int ? minl = get_prop (config, "min_limit"); + round_digits = get_prop (config, "value_scale"); + + if (min == null)min = 0; + if (max == null)max = 100; + if (round_digits == null)round_digits = 0; + + max_limit = maxl != null ? double.min (max, maxl) : max; + + min_limit = minl != null ? double.max (min, minl) : min; + + double scale = Math.pow (10, round_digits); + + min_limit /= scale; + max_limit /= scale; + + slider.set_range (min / scale, max / scale); + } + + slider.set_draw_value (false); + slider.set_round_digits (round_digits); + slider.value_changed.connect (() => { + double value = slider.get_value (); + if (value > max_limit) + value = max_limit; + if (value < min_limit) + value = min_limit; + + slider.set_value (value); + slider.tooltip_text = value.to_string (); + + if (cmd_setter != "" && last_set != value) { + last_set = value; + queue_set.begin (value); + } + }); + + add (label_widget); + pack_start (slider, true, true, 0); + + show_all (); + } + + public string expand_cmd (string cmd, string regex, string value) { + try { + Regex _regx = new Regex (Regex.escape_string (regex)); + return _regx.replace_literal (cmd, -1, 0, value); + } catch (Error e) { + warning ("failed to expand cmd: %s\n", e.message); + return cmd; + } + } + + public async void queue_set (double value) { + if (cmd_ing) + return; + + cmd_ing = true; + var cmd = expand_cmd (cmd_setter, "$value", value.to_string ()); + yield Functions.execute_command (cmd, {}, null); + + cmd_ing = false; + + // make sure the last_set is applied + if (value != last_set) { + yield queue_set (last_set); + } + } + + public async void queue_get (int retry, out string value) { + if (cmd_ing) { + if (retry <= 0) { + value = ""; + return; + } + yield queue_get (retry - 1, out value); + } + + cmd_ing = true; + yield Functions.execute_command (cmd_getter, {}, out value); + + cmd_ing = false; + } + + public async void on_update () { + if (cmd_getter == "") + return; + + string value_str = ""; + yield queue_get (4, out value_str); + + double value = double.parse (value_str); + if (value <= max_limit && value >= min_limit) { + last_set = value; + slider.set_value (value); + } + } + + public override void on_cc_visibility_change (bool value) { + if (value) + on_update.begin (); + } + } +} diff --git a/src/functions.vala b/src/functions.vala index 7429830..eaa03cb 100644 --- a/src/functions.vala +++ b/src/functions.vala @@ -360,6 +360,9 @@ namespace SwayNotificationCenter { string[] argvp = {}; Shell.parse_argv (cmd, out argvp); + if (argvp[0].has_prefix ("~")) + argvp[0] = Environment.get_home_dir () + argvp[0].substring (1); + Pid child_pid; int std_output; Process.spawn_async_with_pipes ( diff --git a/src/meson.build b/src/meson.build index 2c26e4c..6a926f2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -41,6 +41,8 @@ widget_sources = [ 'controlCenter/widgets/menubar/menubar.vala', # Widget: Buttons Grid 'controlCenter/widgets/buttonsGrid/buttonsGrid.vala', + # Widget: Slider + 'controlCenter/widgets/slider/slider.vala', # Widget: Backlight Slider 'controlCenter/widgets/backlight/backlight.vala', 'controlCenter/widgets/backlight/backlightUtil.vala',