[Feature] Click outside Control Center to close (#133)

* Initial implementation

* Fixed linter errors

* Fixed Ubuntu build error

* Added comment to .blank-window css class, formatted file with prettier

* Use packaged css file as backup
This commit is contained in:
Erik Reider 2022-06-16 17:44:57 +02:00 committed by GitHub
parent 8a96948e1b
commit 8425afbfa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 165 additions and 12 deletions

View File

@ -0,0 +1,55 @@
namespace SwayNotificationCenter {
public class BlankWindow : Gtk.Window {
unowned Gdk.Display display;
unowned Gdk.Monitor monitor;
unowned SwayncDaemon daemon;
Gtk.Button button;
public BlankWindow (Gdk.Display disp,
Gdk.Monitor mon,
SwayncDaemon dae) {
display = disp;
monitor = mon;
daemon = dae;
// Use button click event instead of Window button_press_event due
// to Gtk layer shell bug. This would grab focus instead of ControlCenter
button = new Gtk.Button () {
expand = true,
opacity = 0,
relief = Gtk.ReliefStyle.NONE,
visible = true,
};
button.clicked.connect (() => {
try {
daemon.set_visibility (false);
} catch (Error e) {
stderr.printf ("BlankWindow Click Error: %s\n", e.message);
}
});
add (button);
if (!GtkLayerShell.is_supported ()) {
stderr.printf ("GTKLAYERSHELL IS NOT SUPPORTED!\n");
stderr.printf ("Swaync only works on Wayland!\n");
stderr.printf ("If running waylans session, try running:\n");
stderr.printf ("\tGDK_BACKEND=wayland swaync\n");
Process.exit (1);
}
GtkLayerShell.init_for_window (this);
GtkLayerShell.set_monitor (this, monitor);
GtkLayerShell.set_anchor (this, GtkLayerShell.Edge.TOP, true);
GtkLayerShell.set_anchor (this, GtkLayerShell.Edge.BOTTOM, true);
GtkLayerShell.set_anchor (this, GtkLayerShell.Edge.LEFT, true);
GtkLayerShell.set_anchor (this, GtkLayerShell.Edge.RIGHT, true);
GtkLayerShell.set_exclusive_zone (this, -1);
GtkLayerShell.set_layer (this, GtkLayerShell.Layer.TOP);
get_style_context ().add_class ("blank-window");
}
}
}

View File

@ -275,6 +275,7 @@ namespace SwayNotificationCenter {
if (noti != null) noti.set_time (); if (noti != null) noti.set_time ();
} }
} }
swaync_daemon.set_blank_window_visibility (this.visible);
swaync_daemon.subscribe (notification_count (), swaync_daemon.subscribe (notification_count (),
noti_daemon.dnd, noti_daemon.dnd,
this.visible); this.visible);

View File

@ -1,5 +1,15 @@
namespace SwayNotificationCenter { namespace SwayNotificationCenter {
public class Functions { public class Functions {
private static Gtk.CssProvider system_css_provider;
private static Gtk.CssProvider user_css_provider;
private Functions () {}
public static void init () {
system_css_provider = new Gtk.CssProvider ();
user_css_provider = new Gtk.CssProvider ();
}
public static void set_image_path (owned string path, public static void set_image_path (owned string path,
Gtk.Image img, Gtk.Image img,
int icon_size, int icon_size,
@ -55,29 +65,45 @@ namespace SwayNotificationCenter {
img.set_from_surface (surface); img.set_from_surface (surface);
} }
/** Load the package provided CSS file as a base.
* Without this, an empty user CSS file would result in widgets
* with default GTK style properties
*/
public static bool load_css (string ? style_path) { public static bool load_css (string ? style_path) {
try { try {
Gtk.CssProvider css_provider = new Gtk.CssProvider (); // Load packaged CSS as backup
css_provider.load_from_path (get_style_path (style_path)); string system_css = get_style_path (null, true);
system_css_provider.load_from_path (system_css);
Gtk.StyleContext.add_provider_for_screen ( Gtk.StyleContext.add_provider_for_screen (
Gdk.Screen.get_default (), Gdk.Screen.get_default (),
css_provider, system_css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
// Load user CSS
string user_css = get_style_path (style_path);
user_css_provider.load_from_path (user_css);
Gtk.StyleContext.add_provider_for_screen (
Gdk.Screen.get_default (),
user_css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
return true; return true;
} catch (Error e) { } catch (Error e) {
print ("Error: %s\n", e.message); print ("Load CSS Error: %s\n", e.message);
return false;
} }
return false;
} }
public static string get_style_path (string ? custom_path) { public static string get_style_path (string ? custom_path,
bool only_system = false) {
string[] paths = {}; string[] paths = {};
if (custom_path != null && custom_path.length > 0) { if (custom_path != null && custom_path.length > 0) {
paths += custom_path; paths += custom_path;
} }
paths += Path.build_path (Path.DIR_SEPARATOR.to_string (), if (!only_system) {
GLib.Environment.get_user_config_dir (), paths += Path.build_path (Path.DIR_SEPARATOR.to_string (),
"swaync/style.css"); GLib.Environment.get_user_config_dir (),
"swaync/style.css");
}
foreach (var path in GLib.Environment.get_system_config_dirs ()) { foreach (var path in GLib.Environment.get_system_config_dirs ()) {
paths += Path.build_path (Path.DIR_SEPARATOR.to_string (), paths += Path.build_path (Path.DIR_SEPARATOR.to_string (),

View File

@ -6,6 +6,7 @@ namespace SwayNotificationCenter {
public void main (string[] args) { public void main (string[] args) {
Gtk.init (ref args); Gtk.init (ref args);
Hdy.init (); Hdy.init ();
Functions.init ();
if (args.length > 0) { if (args.length > 0) {
for (uint i = 1; i < args.length; i++) { for (uint i = 1; i < args.length; i++) {

View File

@ -33,6 +33,7 @@ app_sources = [
'controlCenter/controlCenter.vala', 'controlCenter/controlCenter.vala',
'controlCenter/topAction/topAction.vala', 'controlCenter/topAction/topAction.vala',
'cacher/cacher.vala', 'cacher/cacher.vala',
'blankWindow/blankWindow.vala',
'functions.vala', 'functions.vala',
constants, constants,
] ]

View File

@ -25,8 +25,7 @@
.notification { .notification {
border-radius: 12px; border-radius: 12px;
margin: 6px 12px; margin: 6px 12px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3), box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.7),
0 1px 3px 1px rgba(0, 0, 0, 0.7),
0 2px 6px 2px rgba(0, 0, 0, 0.3); 0 2px 6px 2px rgba(0, 0, 0, 0.3);
padding: 0; padding: 0;
} }
@ -120,7 +119,8 @@
border-right: 1px solid @noti-border-color; border-right: 1px solid @noti-border-color;
} }
.image {} .image {
}
.body-image { .body-image {
margin-top: 6px; margin-top: 6px;
@ -191,3 +191,8 @@
.floating-notifications { .floating-notifications {
background: transparent; background: transparent;
} }
/* Window behind control center and on all other monitors */
.blank-window {
background: alpha(black, 0.25);
}

View File

@ -11,6 +11,9 @@ namespace SwayNotificationCenter {
public NotiDaemon noti_daemon; public NotiDaemon noti_daemon;
private Array<BlankWindow> blank_windows = new Array<BlankWindow> ();
private unowned Gdk.Display ? display = Gdk.Display.get_default ();
public SwayncDaemon () { public SwayncDaemon () {
this.cache_state = Cacher.instance.get_state_cache (); this.cache_state = Cacher.instance.get_state_cache ();
this.cache_state.notify.connect ((x, r) => { this.cache_state.notify.connect ((x, r) => {
@ -51,6 +54,31 @@ namespace SwayNotificationCenter {
} catch (Error e) { } catch (Error e) {
stderr.printf (e.message + "\n"); stderr.printf (e.message + "\n");
} }
/// Blank windows
if (display == null) return;
init_blank_windows (false);
display.closed.connect ((is_error) => {
clear_blank_windows ();
if (is_error) stderr.printf ("Display closed due to error!\n");
});
display.opened.connect ((d) => {
bool visibility = noti_daemon.control_center.get_visibility ();
init_blank_windows (visibility);
});
display.monitor_added.connect ((d, m) => {
bool visibility = noti_daemon.control_center.get_visibility ();
add_blank_window (d, m, visibility);
});
display.monitor_removed.connect ((monitor) => {
bool visibility = noti_daemon.control_center.get_visibility ();
init_blank_windows (visibility);
});
} }
private void on_noti_bus_aquired (DBusConnection conn) { private void on_noti_bus_aquired (DBusConnection conn) {
@ -63,6 +91,42 @@ namespace SwayNotificationCenter {
} }
} }
private void add_blank_window (Gdk.Display display,
Gdk.Monitor monitor,
bool visible) {
var win = new BlankWindow (display, monitor, this);
win.set_visible (visible);
blank_windows.append_val (win);
}
private void init_blank_windows (bool visible) {
clear_blank_windows ();
// Add a window to all monitors
for (int i = 0; i < display.get_n_monitors (); i++) {
unowned Gdk.Monitor ? monitor = display.get_monitor (i);
if (monitor == null) continue;
add_blank_window (display, monitor, visible);
}
}
private void clear_blank_windows () {
while (blank_windows.length > 0) {
uint i = blank_windows.length - 1;
unowned BlankWindow ? win = blank_windows.index (i);
win.close ();
blank_windows.remove_index (i);
}
}
[DBus (visible = false)]
public void set_blank_window_visibility (bool visibility) {
foreach (unowned BlankWindow win in blank_windows.data) {
win.set_visible (visibility);
}
}
/// DBus
/** Gets subscribe data but in one call */ /** Gets subscribe data but in one call */
[DBus (name = "GetSubscribeData")] [DBus (name = "GetSubscribeData")]
public Data get_subscribe_data () throws Error { public Data get_subscribe_data () throws Error {