Unverified Commit 5158f41e authored by Erik Reider's avatar Erik Reider Committed by GitHub

Add config option and swaync-client command to pick monitor (#579)

* Add preferred output config option * Added swaync-client command to set a temporary output * Updated man pages * Fixed linting complaints * Updated README
parent 4eae2759
......@@ -73,6 +73,7 @@ Post your setup here: [Config flex 💪](https://github.com/ErikReider/SwayNotif
- Basic configuration through a JSON config file
- Hot-reload config through `swaync-client`
- Customizable widgets
- Select the preferred monitor to display on (with swaync-client command for scripting)
## Available Widgets
......@@ -91,7 +92,6 @@ These widgets can be customized, added, removed and even reordered
## Planned Features
- Slick animations 😎
- Other build scripts than a PKGBUILD (debian and/or RHEL systems)
## Install
......
......@@ -50,6 +50,8 @@ _swaync-client() {
--skip-wait
--subscribe
--subscribe-waybar
--change-cc-monitor
--change-noti-monitor
)
case $prev in
-s | --style)
......
......@@ -22,3 +22,5 @@ complete -c swaync-client -s C -l close-all --description "Closes all notificati
complete -c swaync-client -s sw -l skip-wait --description "Doesn't wait when swaync hasn't been started" -r
complete -c swaync-client -s s -l subscribe --description "Subscribe to notification add and close events" -r
complete -c swaync-client -s swb -l subscribe-waybar --description "Subscribe to notification add and close events with waybar support. Read README for example" -r
complete -c swaync-client -l change-cc-monitor --description "Changes the preferred control center monitor (resets on config reload)" -r
complete -c swaync-client -l change-noti-monitor --description "Changes the preferred notification monitor (resets on config reload)" -r
......@@ -24,3 +24,5 @@ _arguments -s \
'(-sw --skip-wait)'{-sw,--skip-wait}"[Doesn't wait when swaync hasn't been started]" \
'(-s --subscribe)'{-s,--subscribe}'[Subscribe to notification add and close events]' \
'(-swb --subscribe-waybar)'{-swb,--subscribe-waybar}'[Subscribe to notification add and close events with waybar support. Read README for example]' \
'(--change-cc-monitor)'--change-cc-monitor'[Changes the preferred control center monitor (resets on config reload)]' \
'(--change-noti-monitor)'--change-noti-monitor'[Changes the preferred notification monitor (resets on config reload)]' \
......@@ -81,3 +81,9 @@ swaync-client - Client executable
*-swb, --subscribe-waybar*
Subscribe to notification add and close events with waybar support. Read README for example
*--change-cc-monitor*
Changes the preferred control center monitor (resets on config reload)
*--change-noti-monitor*
Changes the preferred notification monitor (resets on config reload)
......@@ -106,6 +106,13 @@ config file to be able to detect config errors
description: Max height of the notification in pixels. -1 to use ++
the full amount of space given by the compositor.
*notification-window-preferred-output* ++
type: string ++
default: "" ++
description: The preferred output to open the notification window ++
(popup notifications). If the output is not found, the ++
currently focused one is picked.
*keyboard-shortcuts* ++
type: bool ++
default: true ++
......@@ -164,6 +171,12 @@ config file to be able to detect config errors
default: 500 ++
description: The control center width in pixels
*control-center-preferred-output* ++
type: string ++
default: "" ++
description: The preferred output to open the control center. If the ++
output is not found, the currently focused one is picked.
*notification-visibility* ++
type: object ++
visibility object properties: ++
......
......@@ -32,6 +32,9 @@ interface CcDaemon : Object {
public abstract void latest_invoke_action (uint32 action_index) throws DBusError, IOError;
public abstract bool set_cc_monitor (string monitor) throws DBusError, IOError;
public abstract bool set_noti_window_monitor (string monitor) throws DBusError, IOError;
[DBus (name = "GetSubscribeData")]
public abstract SwayncDaemonData get_subscribe_data () throws Error;
......@@ -76,6 +79,10 @@ private void print_help (string[] args) {
print (" -s, \t --subscribe \t\t\t Subscribe to notification add and close events\n");
print (" -swb, --subscribe-waybar \t\t Subscribe to notification add and close events "
+ "with waybar support. Read README for example\n");
print (" \t --change-cc-monitor \t\t Changes the preferred control center monitor"
+ " (resets on config reload)\n");
print (" \t --change-noti-monitor \t\t Changes the preferred notification monitor"
+ " (resets on config reload)\n");
}
private void on_subscribe (uint count, bool dnd, bool cc_open, bool inhibited) {
......@@ -270,6 +277,28 @@ public int command_line (string[] args) {
print_subscribe_waybar);
loop.run ();
break;
case "--change-cc-monitor":
if (args.length < 3) {
stderr.printf ("Monitor connector name needed!");
Process.exit (1);
}
if (cc_daemon.set_cc_monitor (args[2])) {
print ("Changed monitor to: \"%s\"", args[2]);
break;
}
stderr.printf ("Could not find monitor: \"%s\"!", args[2]);
break;
case "--change-noti-monitor":
if (args.length < 3) {
stderr.printf ("Monitor connector name needed!");
Process.exit (1);
}
if (cc_daemon.set_noti_window_monitor (args[2])) {
print ("Changed monitor to: \"%s\"", args[2]);
break;
}
stderr.printf ("Could not find monitor: \"%s\"!", args[2]);
break;
default:
print_help (args);
break;
......
......@@ -301,7 +301,8 @@ namespace SwayNotificationCenter {
public class ConfigModel : Object, Json.Serializable {
private static ConfigModel _instance;
private static ConfigModel ? previous_config = null;
private static ConfigModel ? _instance = null;
private static string _path = "";
/** Get the static singleton */
......@@ -349,10 +350,15 @@ namespace SwayNotificationCenter {
m = model;
} catch (Error e) {
critical (e.message);
m = new ConfigModel ();
}
_instance = m ?? new ConfigModel ();
previous_config = _instance;
_instance = m;
_path = path;
debug (_instance.to_string ());
app.config_reload (previous_config, m);
}
/* Properties */
......@@ -460,6 +466,12 @@ namespace SwayNotificationCenter {
/** Max height of the notification in pixels */
public int notification_window_height { get; set; default = -1; }
/**
* The preferred output to open the notification window (popup notifications).
* If the output is not found, the currently focused one is picked.
*/
public string notification_window_preferred_output { get; set; default = ""; }
/** Hides the control center after clearing all notifications */
public bool hide_on_clear { get; set; default = false; }
......@@ -598,6 +610,12 @@ namespace SwayNotificationCenter {
}
/**
* The preferred output to open the control center.
* If the output is not found, the currently focused one is picked.
*/
public string control_center_preferred_output { get; set; default = ""; }
/**
* If each notification should display a 'COPY \"1234\"' action
*/
public bool notification_2fa_action { get; set; default = true; }
......
......@@ -138,6 +138,10 @@
"description": "Max height of the notification in pixels. -1 to use the full amount of space given by the compositor.",
"default": -1
},
"notification-window-preferred-output": {
"type": "string",
"description": "The preferred output to open the notification window (popup notifications). If the output is not found, the currently focused one is picked"
},
"fit-to-screen": {
"type": "boolean",
"description": "If the control center should expand to both edges of the screen",
......@@ -160,6 +164,10 @@
"default": 500,
"minimum": 300
},
"control-center-preferred-output": {
"type": "string",
"description": "The preferred output to open the control center. If the output is not found, the currently focused one is picked"
},
"keyboard-shortcuts": {
"type": "boolean",
"description": "If control center should use keyboard shortcuts",
......
......@@ -117,6 +117,8 @@ namespace SwayNotificationCenter {
private Array<Widgets.BaseWidget> widgets = new Array<Widgets.BaseWidget> ();
private const string[] DEFAULT_WIDGETS = { "title", "dnd", "notifications" };
private string ? monitor_name = null;
public ControlCenter (SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
this.swaync_daemon = swaync_daemon;
this.noti_daemon = noti_daemon;
......@@ -219,6 +221,17 @@ namespace SwayNotificationCenter {
stack.set_visible_child_name (STACK_PLACEHOLDER_PAGE);
add_widgets ();
// Change output on config reload
app.config_reload.connect ((old, config) => {
string monitor_name = config.control_center_preferred_output;
if (old == null
|| old.control_center_preferred_output != monitor_name
|| this.monitor_name != monitor_name) {
this.monitor_name = null;
set_anchor ();
}
});
}
// Scroll to the expanded group once said group has fully expanded
......@@ -513,6 +526,13 @@ namespace SwayNotificationCenter {
// Use a custom layout to limit the minimum size above to the size
// of the window so that it doesn't exceed the monitors edge
window.child.set_layout_manager (new FixedViewportLayout (window));
// Set the preferred monitor
string ? monitor_name = ConfigModel.instance.control_center_preferred_output;
if (this.monitor_name != null) {
monitor_name = this.monitor_name;
}
set_monitor (Functions.try_get_monitor (monitor_name));
}
/**
......@@ -782,5 +802,10 @@ namespace SwayNotificationCenter {
public bool get_visibility () {
return this.visible;
}
public void set_monitor (Gdk.Monitor ? monitor) {
this.monitor_name = monitor == null ? null : monitor.connector;
GtkLayerShell.set_monitor (this, monitor);
}
}
}
......@@ -356,5 +356,22 @@ namespace SwayNotificationCenter {
public static double lerp (double a, double b, double t) {
return a * (1.0 - t) + b * t;
}
public static unowned Gdk.Monitor ? try_get_monitor (string name) {
if (name == null || name.length == 0) {
return null;
}
for (int i = 0; i < monitors.get_n_items (); i++) {
Object ? obj = monitors.get_item (i);
if (obj == null || !(obj is Gdk.Monitor)) continue;
unowned Gdk.Monitor monitor = (Gdk.Monitor) obj;
if (monitor.connector == name) {
return monitor;
}
}
return null;
}
}
}
namespace SwayNotificationCenter {
static SwayncDaemon swaync_daemon;
static unowned ListModel ? monitors = null;
static Swaync app;
static Settings self_settings;
// Args
static string ? style_path;
static string ? config_path;
// Dev args
static bool skip_packaged_css = false;
static Settings self_settings;
public class Swaync : Gtk.Application {
static bool activated = false;
public signal void config_reload (
owned ConfigModel ? old_config, ConfigModel new_config);
static bool activated = false;
public int main (string[] args) {
Gtk.init ();
Adw.init ();
Functions.init ();
self_settings = new Settings ("org.erikreider.swaync");
if (args.length > 0) {
for (uint i = 1; i < args.length; i++) {
string arg = args[i];
switch (arg) {
case "-s":
case "--style":
style_path = args[++i];
break;
case "--skip-system-css":
skip_packaged_css = true;
break;
case "-c":
case "--config":
config_path = args[++i];
break;
case "-v":
case "--version":
stdout.printf ("%s\n", Constants.VERSION);
return 0;
case "-h":
case "--help":
print_help (args);
return 0;
default:
print_help (args);
return 1;
public Swaync () {
Object (
application_id: "org.erikreider.swaync",
flags: ApplicationFlags.DEFAULT_FLAGS
);
try {
register ();
if (get_is_remote ()) {
printerr ("An instance of SwayNotificationCenter is already running!\n");
Process.exit (1);
}
} catch (Error e) {
error (e.message);
}
}
var app = new Gtk.Application ("org.erikreider.swaync",
ApplicationFlags.DEFAULT_FLAGS);
app.activate.connect (() => {
public override void activate () {
if (activated) {
return;
}
......@@ -57,7 +42,13 @@ namespace SwayNotificationCenter {
ConfigModel.init (config_path);
Functions.load_css (style_path);
app.hold ();
hold ();
unowned Gdk.Display ? display = Gdk.Display.get_default ();
if (display == null) {
error ("Could not get Display!");
}
monitors = display.get_monitors ();
swaync_daemon = new SwayncDaemon ();
Bus.own_name (BusType.SESSION, "org.erikreider.swaync.cc",
......@@ -70,39 +61,70 @@ namespace SwayNotificationCenter {
Process.exit (1);
});
app.add_window (swaync_daemon.noti_daemon.control_center);
});
add_window (swaync_daemon.noti_daemon.control_center);
}
try {
app.register ();
if (app.get_is_remote ()) {
printerr ("An instance of SwayNotificationCenter is already running!\n");
void on_cc_bus_aquired (DBusConnection conn) {
try {
conn.register_object ("/org/erikreider/swaync/cc", swaync_daemon);
} catch (IOError e) {
stderr.printf ("Could not register CC service\n");
Process.exit (1);
}
} catch (Error e) {
error (e.message);
}
return app.run ();
}
public static int main (string[] args) {
Gtk.init ();
Adw.init ();
if (args.length > 0) {
for (uint i = 1; i < args.length; i++) {
string arg = args[i];
switch (arg) {
case "-s":
case "--style":
style_path = args[++i];
break;
case "--skip-system-css":
skip_packaged_css = true;
break;
case "-c":
case "--config":
config_path = args[++i];
break;
case "-v":
case "--version":
stdout.printf ("%s\n", Constants.VERSION);
return 0;
case "-h":
case "--help":
print_help (args);
return 0;
default:
print_help (args);
return 1;
}
}
}
Functions.init ();
self_settings = new Settings ("org.erikreider.swaync");
void on_cc_bus_aquired (DBusConnection conn) {
try {
conn.register_object ("/org/erikreider/swaync/cc", swaync_daemon);
} catch (IOError e) {
stderr.printf ("Could not register CC service\n");
Process.exit (1);
app = new Swaync ();
return app.run ();
}
}
private void print_help (string[] args) {
print ("Usage:\n");
print ("\t %s <OPTION>\n".printf (args[0]));
print ("Help:\n");
print ("\t -h, --help \t\t Show help options\n");
print ("\t -v, --version \t\t Prints version\n");
print ("Options:\n");
print ("\t -s, --style \t\t Use a custom Stylesheet file\n");
print ("\t -c, --config \t\t Use a custom config file\n");
print ("\t --skip-system-css \t Skip trying to parse the packaged Stylesheet file. Useful for CSS debugging\n");
private static void print_help (string[] args) {
print ("Usage:\n");
print ("\t %s <OPTION>\n".printf (args[0]));
print ("Help:\n");
print ("\t -h, --help \t\t Show help options\n");
print ("\t -v, --version \t\t Prints version\n");
print ("Options:\n");
print ("\t -s, --style \t\t Use a custom Stylesheet file\n");
print ("\t -c, --config \t\t Use a custom config file\n");
print ("\t --skip-system-css \t Skip trying to parse the packaged Stylesheet file."
+ " Useful for CSS debugging\n");
}
}
}
......@@ -38,6 +38,8 @@ namespace SwayNotificationCenter {
Gee.HashSet<uint32> inline_reply_notifications = new Gee.HashSet<uint32> ();
private static string ? monitor_name = null;
private const int MAX_HEIGHT = 600;
private NotificationWindow () {
......@@ -65,6 +67,17 @@ namespace SwayNotificationCenter {
// set_resizable (false);
default_width = ConfigModel.instance.notification_window_width;
// Change output on config reload
app.config_reload.connect ((old, config) => {
string monitor_name = config.notification_window_preferred_output;
if (old == null
|| old.notification_window_preferred_output != monitor_name
|| NotificationWindow.monitor_name != monitor_name) {
NotificationWindow.monitor_name = null;
set_anchor ();
}
});
}
protected override void size_allocate (int w, int h, int baseline) {
......@@ -189,6 +202,13 @@ namespace SwayNotificationCenter {
list.direction = AnimatedListDirection.BOTTOM_TO_TOP;
break;
}
// Set the preferred monitor
string ? monitor_name = ConfigModel.instance.notification_window_preferred_output;
if (NotificationWindow.monitor_name != null) {
monitor_name = NotificationWindow.monitor_name;
}
set_monitor (Functions.try_get_monitor (monitor_name));
}
public void change_visibility (bool value) {
......@@ -327,5 +347,10 @@ namespace SwayNotificationCenter {
noti.click_alt_action (action);
noti.close_notification ();
}
public void set_monitor (Gdk.Monitor ? monitor) {
NotificationWindow.monitor_name = monitor == null ? null : monitor.connector;
GtkLayerShell.set_monitor (this, monitor);
}
}
}
......@@ -17,8 +17,6 @@ namespace SwayNotificationCenter {
public signal void inhibited_changed (uint length);
private Array<BlankWindow> blank_windows = new Array<BlankWindow> ();
private unowned Gdk.Display ? display = Gdk.Display.get_default ();
private unowned GLib.ListModel ? monitors = null;
// Only set on swaync start due to some limitations of GtkLayerShell
[DBus (visible = false)]
......@@ -65,14 +63,21 @@ namespace SwayNotificationCenter {
stderr.printf (e.message + "\n");
}
/// Blank windows
if (display == null) return;
monitors = display.get_monitors ();
monitors.items_changed.connect (() => {
// Blank windows
close_blank_windows ();
bool visibility = noti_daemon.control_center.get_visibility ();
init_blank_windows (visibility);
// Set preferred output
try {
set_cc_monitor (
ConfigModel.instance.control_center_preferred_output);
set_noti_window_monitor (
ConfigModel.instance.notification_window_preferred_output);
} catch (Error e) {
critical (e.message);
}
});
init_blank_windows (false);
}
......@@ -304,5 +309,25 @@ namespace SwayNotificationCenter {
inhibited);
return true;
}
public bool set_cc_monitor (string name) throws DBusError, IOError {
unowned Gdk.Monitor ? monitor = Functions.try_get_monitor (name);
if (monitor == null) {
return false;
}
noti_daemon.control_center.set_monitor (monitor);
return true;
}
public bool set_noti_window_monitor (string name) throws DBusError, IOError {
unowned Gdk.Monitor ? monitor = Functions.try_get_monitor (name);
if (monitor == null) {
return false;
}
NotificationWindow.instance.set_monitor (monitor);
return true;
}
}
}
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