From f20fe7a1af30d430a48945244a768c9a985bbab2 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 24 Nov 2024 14:43:39 +0100 Subject: [PATCH] ShellClients: Wait and reveal in sync on session start --- src/ShellClients/HideTracker.vala | 8 +++- src/ShellClients/PanelClone.vala | 50 +++++++++++++++++++---- src/ShellClients/ShellClientsManager.vala | 18 ++++++++ src/WindowManager.vala | 6 +-- 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/ShellClients/HideTracker.vala b/src/ShellClients/HideTracker.vala index 46bec180d..0efaa0b5f 100644 --- a/src/ShellClients/HideTracker.vala +++ b/src/ShellClients/HideTracker.vala @@ -147,7 +147,13 @@ public class Gala.HideTracker : Object { }); } - private void update_overlap () { + /** + * Immediately updates the overlap. Usually {@link schedule_update} should be used instead which + * internally calls this but throttles it since it's a somewhat expensive operation. + * On very rare use cases however it is required to update immediately. In that case you can call + * this directly. + */ + public void update_overlap () { overlap = false; focus_overlap = false; focus_maximized_overlap = false; diff --git a/src/ShellClients/PanelClone.vala b/src/ShellClients/PanelClone.vala index 13d7e7587..cd55d636e 100644 --- a/src/ShellClients/PanelClone.vala +++ b/src/ShellClients/PanelClone.vala @@ -9,7 +9,7 @@ public class Gala.PanelClone : Object { private const int ANIMATION_DURATION = 250; public WindowManager wm { get; construct; } - public unowned PanelWindow panel { get; construct; } + public unowned PanelWindow? panel { get; construct; } public Pantheon.Desktop.HideMode hide_mode { get { @@ -35,6 +35,8 @@ public class Gala.PanelClone : Object { private SafeWindowClone clone; private Meta.WindowActor actor; + private bool window_ready = false; + private HideTracker? hide_tracker; public PanelClone (WindowManager wm, PanelWindow panel) { @@ -67,16 +69,38 @@ public class Gala.PanelClone : Object { // https://github.com/elementary/gala/issues/2080 panel.window.focused.connect (update_visible); + panel.window.unmanaging.connect (() => panel = null); + update_visible (); update_clone_position (); - Idle.add_once (() => { - if (hide_mode == NEVER) { - show (); - } else { - hide_tracker.schedule_update (); - } - }); + if (Meta.Util.is_wayland_compositor ()) { + // We want to wait for the window to be actually shown before revealing and then still a bit + // more since at the beginning it might be doing some relayouting (e.g. the dock only knows + // its size after it got a dbus connection to gala) which disrupts the animation. + panel.window.shown.connect (() => Timeout.add (100, () => { + if (panel == null) { + return Source.REMOVE; // The window was unmanaged while we were waiting + } + + window_ready = true; + // In the best case we are ready before the manager stops waiting so the on_ready usually + // doesn't do anything. However if the client stalls for some reason or it crashed and has now + // been restarted it will show immediately. + on_ready (); + + ShellClientsManager.get_instance ().notify_client_ready (); + + return Source.REMOVE; + })); + } else { + // On X the window was already shown when it requests being a panel so just mark it ready + window_ready = true; + on_ready (); + ShellClientsManager.get_instance ().notify_client_ready (); + } + + ShellClientsManager.get_instance ().notify["is-waiting"].connect (on_ready); } private void update_visible () { @@ -142,7 +166,7 @@ public class Gala.PanelClone : Object { } private void show () { - if (!panel_hidden) { + if (!panel_hidden || !window_ready || ShellClientsManager.get_instance ().is_waiting) { return; } @@ -163,4 +187,12 @@ public class Gala.PanelClone : Object { panel_hidden = false; } } + + private void on_ready () { + if (hide_mode == NEVER) { + show (); + } else { + hide_tracker.update_overlap (); + } + } } diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index dfaa8b0ff..1af4e481e 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -20,6 +20,8 @@ public class Gala.ShellClientsManager : Object { return instance; } + public bool is_waiting { get; private set; default = true; } // On session start wait a bit for a synchronized and smooth reveal + public WindowManager wm { get; construct; } private NotificationsClient notifications_client; @@ -28,6 +30,8 @@ public class Gala.ShellClientsManager : Object { private GLib.HashTable panel_windows = new GLib.HashTable (null, null); private GLib.HashTable positioned_windows = new GLib.HashTable (null, null); + private uint currently_starting_panels = 0; + private ShellClientsManager (WindowManager wm) { Object (wm: wm); } @@ -149,6 +153,8 @@ public class Gala.ShellClientsManager : Object { return; } + currently_starting_panels++; + make_dock (window); // TODO: Return if requested by window that's not a trusted client? @@ -207,6 +213,18 @@ public class Gala.ShellClientsManager : Object { return positioned; } + //Called by the WM once it has initialized + public void notify_stage_ready () { + Timeout.add_seconds_once (5, () => is_waiting = false); // Failsafe if a client stalls to still show the others + } + + // Called by the {@link PanelClone} when the window it manages is ready. + public void notify_client_ready () { + currently_starting_panels--; + + is_waiting &= currently_starting_panels > 0; + } + //X11 only private void parse_mutter_hints (Meta.Window window) requires (!Meta.Util.is_wayland_compositor ()) { if (window.mutter_hints == null) { diff --git a/src/WindowManager.vala b/src/WindowManager.vala index 8f47ba215..a8d4f3222 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -367,13 +367,13 @@ namespace Gala { stage.show (); - Idle.add (() => { + Idle.add_once (() => { // let the session manager move to the next phase #if WITH_SYSTEMD Systemd.Daemon.notify (true, "READY=1"); #endif - display.get_context ().notify_ready (); - return GLib.Source.REMOVE; + get_display ().get_context ().notify_ready (); + ShellClientsManager.get_instance ().notify_stage_ready (); }); }