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