diff --git a/daemon-gtk3/DBus.vala b/daemon-gtk3/DBus.vala index b00f4148a..6ccb1f330 100644 --- a/daemon-gtk3/DBus.vala +++ b/daemon-gtk3/DBus.vala @@ -32,6 +32,9 @@ public class Gala.Daemon.DBus : GLib.Object { private List monitor_labels = new List (); + private Gee.HashMap suspend_cookies = new Gee.HashMap (); + private Gee.HashMap idle_cookies = new Gee.HashMap (); + construct { Bus.watch_name (BusType.SESSION, DBUS_NAME, BusNameWatcherFlags.NONE, gala_appeared, lost_gala); } @@ -114,6 +117,69 @@ public class Gala.Daemon.DBus : GLib.Object { } } + public void prevent_sleep (uint64 window_id) throws GLib.DBusError, GLib.IOError { + unowned var application = (Gtk.Application) GLib.Application.get_default (); + + // TODO add gschema setting for disabling auto suspend when fullscreen + if (application != null) { + var window_id_str = window_id.to_string (); + info ("preventing auto-suspend and auto-idle because a window [%s] went fullscreen", window_id_str); + // Ask the session manager to not automatically turn off the screen or put the system to sleep + prevent_sleep_while_fullscreen (window_id_str, application); + } + } + + public void unprevent_sleep (uint64 window_id) throws GLib.DBusError, GLib.IOError { + unowned var application = (Gtk.Application) GLib.Application.get_default (); + + // Inform the session manager we do not want to prevent turning off the screen or sleeping + if (application != null) { + var window_id_str = window_id.to_string (); + info ("unpreventing auto-suspend and auto-idle by window [%s] because it exited fullscreen", + window_id_str); + + if (suspend_cookies.has_key (window_id_str)) { + end_prevent_suspend_while_fullscreen (window_id_str, application); + } + if (idle_cookies.has_key (window_id_str)) { + end_prevent_idle_while_fullscreen (window_id_str, application); + } + } + } + + private void prevent_sleep_while_fullscreen (string window_id_str, Gtk.Application application) { + // If window was already marked as preventing fullscreen, unhinibit before inhibiting + if (suspend_cookies.has_key (window_id_str)) { + end_prevent_suspend_while_fullscreen (window_id_str, application); + } + if (idle_cookies.has_key (window_id_str)) { + end_prevent_idle_while_fullscreen (window_id_str, application); + } + + suspend_cookies.set (window_id_str, application.inhibit ( + null, + Gtk.ApplicationInhibitFlags.SUSPEND, + "Prevent session from suspending while fullscreen" + )); + idle_cookies.set (window_id_str, application.inhibit ( + null, + Gtk.ApplicationInhibitFlags.IDLE, + "Prevent session from idle while fullscreen" + )); + } + + private void end_prevent_suspend_while_fullscreen (string window_id_str, Gtk.Application application) { + uint suspend_cookie = suspend_cookies.get (window_id_str); + application.uninhibit (suspend_cookie); + suspend_cookies.unset (window_id_str); + } + + private void end_prevent_idle_while_fullscreen (string window_id_str, Gtk.Application application) { + uint idle_cookie = idle_cookies.get (window_id_str); + application.uninhibit (idle_cookie); + idle_cookies.unset (window_id_str); + } + public void show_monitor_labels (MonitorLabelInfo[] label_infos) throws GLib.DBusError, GLib.IOError { hide_monitor_labels (); diff --git a/daemon/DBus.vala b/daemon/DBus.vala index 1dedf953c..3c97c8a31 100644 --- a/daemon/DBus.vala +++ b/daemon/DBus.vala @@ -36,6 +36,9 @@ public class Gala.Daemon.DBus : GLib.Object { private List monitor_labels = new List (); + private Gee.HashMap suspend_cookies = new Gee.HashMap (); + private Gee.HashMap idle_cookies = new Gee.HashMap (); + construct { Bus.watch_name (BusType.SESSION, DBUS_NAME, BusNameWatcherFlags.NONE, gala_appeared, lost_gala); @@ -155,6 +158,69 @@ public class Gala.Daemon.DBus : GLib.Object { }); } + public void prevent_sleep (uint64 window_id) throws GLib.DBusError, GLib.IOError { + unowned var application = (Gtk.Application) GLib.Application.get_default (); + + // TODO add gschema setting for disabling auto suspend when fullscreen + if (application != null) { + var window_id_str = window_id.to_string (); + info ("preventing auto-suspend and auto-idle because a window [%s] went fullscreen", window_id_str); + // Ask the session manager to not automatically turn off the screen or put the system to sleep + prevent_sleep_while_fullscreen (window_id_str, application); + } + } + + public void unprevent_sleep (uint64 window_id) throws GLib.DBusError, GLib.IOError { + unowned var application = (Gtk.Application) GLib.Application.get_default (); + + // Inform the session manager we do not want to prevent turning off the screen or sleeping + if (application != null) { + var window_id_str = window_id.to_string (); + info ("unpreventing auto-suspend and auto-idle by window [%s] because it exited fullscreen", + window_id_str); + + if (suspend_cookies.has_key (window_id_str)) { + end_prevent_suspend_while_fullscreen (window_id_str, application); + } + if (idle_cookies.has_key (window_id_str)) { + end_prevent_idle_while_fullscreen (window_id_str, application); + } + } + } + + private void prevent_sleep_while_fullscreen (string window_id_str, Gtk.Application application) { + // If window was already marked as preventing fullscreen, unhinibit before inhibiting + if (suspend_cookies.has_key (window_id_str)) { + end_prevent_suspend_while_fullscreen (window_id_str, application); + } + if (idle_cookies.has_key (window_id_str)) { + end_prevent_idle_while_fullscreen (window_id_str, application); + } + + suspend_cookies.set (window_id_str, application.inhibit ( + null, + Gtk.ApplicationInhibitFlags.SUSPEND, + "Prevent session from suspending while fullscreen" + )); + idle_cookies.set (window_id_str, application.inhibit ( + null, + Gtk.ApplicationInhibitFlags.IDLE, + "Prevent session from idle while fullscreen" + )); + } + + private void end_prevent_suspend_while_fullscreen (string window_id_str, Gtk.Application application) { + uint suspend_cookie = suspend_cookies.get (window_id_str); + application.uninhibit (suspend_cookie); + suspend_cookies.unset (window_id_str); + } + + private void end_prevent_idle_while_fullscreen (string window_id_str, Gtk.Application application) { + uint idle_cookie = idle_cookies.get (window_id_str); + application.uninhibit (idle_cookie); + idle_cookies.unset (window_id_str); + } + public void show_monitor_labels (MonitorLabelInfo[] label_infos) throws GLib.DBusError, GLib.IOError { hide_monitor_labels (); diff --git a/src/DaemonManager.vala b/src/DaemonManager.vala index 472bc0b67..02f667f48 100644 --- a/src/DaemonManager.vala +++ b/src/DaemonManager.vala @@ -14,6 +14,8 @@ public class Gala.DaemonManager : GLib.Object { public interface Daemon: GLib.Object { public abstract async void show_window_menu (WindowFlags flags, int width, int height, int x, int y) throws Error; public abstract async void show_desktop_menu (int display_width, int display_height, int x, int y) throws Error; + public abstract async void prevent_sleep (uint64 window_id) throws Error; + public abstract async void unprevent_sleep (uint64 window_id) throws Error; } public Meta.Display display { get; construct; } @@ -128,4 +130,32 @@ public class Gala.DaemonManager : GLib.Object { warning ("Error invoking MenuManager: %s", e.message); } } + + public async void prevent_sleep (uint64 window_id) { + if (daemon_proxy == null) { + return; + } + + try { + debug ("Sending dbus message to daemon to prevent auto-suspend and auto-idle because a window [%" + + uint64.FORMAT + "] went fullscreen", window_id); + yield daemon_proxy.prevent_sleep (window_id); + } catch (Error e) { + warning ("Error invoking MenuManager: %s", e.message); + } + } + + public async void unprevent_sleep (uint64 window_id) { + if (daemon_proxy == null) { + return; + } + + try { + debug ("Sending dbus message to daemon to unprevent auto-suspend and auto-idle by window [%" + + uint64.FORMAT + "] because it exited fullscreen", window_id); + yield daemon_proxy.unprevent_sleep (window_id); + } catch (Error e) { + warning ("Error invoking MenuManager: %s", e.message); + } + } } diff --git a/src/WindowListener.vala b/src/WindowListener.vala index 5945aca1a..47442fd22 100644 --- a/src/WindowListener.vala +++ b/src/WindowListener.vala @@ -22,13 +22,16 @@ public class Gala.WindowListener : Object { } private static WindowListener? instance = null; + private static unowned DaemonManager shared_daemon_manager; - public static void init (Meta.Display display) { + public static void init (Meta.Display display, DaemonManager daemon_manager) { if (instance != null) return; instance = new WindowListener (); + shared_daemon_manager = daemon_manager; + #if HAS_MUTTER48 unowned List actors = display.get_compositor ().get_window_actors (); #else @@ -92,6 +95,14 @@ public class Gala.WindowListener : Object { break; case "fullscreen": window_fullscreen_changed (window); + if (window.fullscreen) { + // Only prevent sleep for windows on the main monitor + if (window.is_on_primary_monitor ()) { + shared_daemon_manager.prevent_sleep (window.get_id ()); + } + } else { + shared_daemon_manager.unprevent_sleep (window.get_id ()); + } break; } } diff --git a/src/WindowManager.vala b/src/WindowManager.vala index ce9b1dd3b..048d4041d 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -206,7 +206,7 @@ namespace Gala { private void show_stage () { unowned Meta.Display display = get_display (); - WindowListener.init (display); + WindowListener.init (display, daemon_manager); keyboard_manager = new KeyboardManager (display); window_tracker = new WindowTracker (); WindowStateSaver.init (window_tracker);