From 90d6b9c70d74d8bc12dc47529f36debdb9ed5c7b Mon Sep 17 00:00:00 2001 From: PureJoyMind Date: Sat, 29 Aug 2026 00:53:15 +0330 Subject: [PATCH] fix(ui): keep the tray-hidden window renderable on restore A minimized autostart launch hid the main window immediately in its Opened handler, but on Linux and macOS an Avalonia window hidden this way comes back from a later Show() with no content ever drawn - it sits on the desktop as a blank, inert taskbar/dock entry with nothing to interact with, so the only way to get rid of it is closing it from that entry's own menu. Toggling ShowInTaskbar alongside every Hide()/ Show() pair (autostart, the tray icon's manual toggle, and close-to- tray) works around the underlying Avalonia rendering bug (AvaloniaUI/Avalonia#2994, #18148). Windows already hides the taskbar entry on its own, so the extra toggle is a no-op there. --- src/AvaDM.UI/App.axaml.cs | 16 +++++++++++++++- src/AvaDM.UI/Services/TrayIconService.cs | 9 +++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/AvaDM.UI/App.axaml.cs b/src/AvaDM.UI/App.axaml.cs index 2aaedd3..06cbb2f 100644 --- a/src/AvaDM.UI/App.axaml.cs +++ b/src/AvaDM.UI/App.axaml.cs @@ -71,9 +71,23 @@ public override void OnFrameworkInitializationCompleted() // so hiding it in the Opened handler (rather than skipping the MainWindow assignment // above) is what avoids that - it costs a brief window flash instead of a more // invasive change to how MainWindow/TrayIconService are wired up. + // + // ShowInTaskbar = false right after Hide() works around a real Avalonia rendering bug + // on Linux (and, per the upstream reports, macOS) where a window hidden this way comes + // back from the next Show() with no content ever drawn - visible on the desktop only as + // an inert, blank taskbar/dock entry the user has to close by hand, since there's + // nothing on screen to interact with. Windows already hides the taskbar entry itself + // when the window is hidden, so this is a no-op there. See + // https://github.com/AvaloniaUI/Avalonia/issues/2994 and + // https://github.com/AvaloniaUI/Avalonia/issues/18148 - TrayIconService.RestoreWindow + // sets ShowInTaskbar back to true before the matching Show(). if (desktop.Args?.Contains("--minimized") == true) { - window.Opened += (_, _) => window.Hide(); + window.Opened += (_, _) => + { + window.Hide(); + window.ShowInTaskbar = false; + }; } var trayIcon = TrayIcon.GetIcons(this)![0]; diff --git a/src/AvaDM.UI/Services/TrayIconService.cs b/src/AvaDM.UI/Services/TrayIconService.cs index 117d3b0..64e0e92 100644 --- a/src/AvaDM.UI/Services/TrayIconService.cs +++ b/src/AvaDM.UI/Services/TrayIconService.cs @@ -223,6 +223,10 @@ private void UpdateLiveProgress() /// a second launch signals this instance instead of starting its own. public void RestoreWindow() { + // ShowInTaskbar back to true before Show() - the other half of the workaround documented + // on the Hide() calls in this class and in App.axaml.cs, for the Avalonia rendering bug + // that otherwise leaves the restored window blank on Linux/macOS. + _window.ShowInTaskbar = true; _window.Show(); _window.WindowState = WindowState.Normal; _window.Activate(); @@ -241,7 +245,11 @@ private void ToggleWindow() { if (_window.IsVisible && _window.WindowState != WindowState.Minimized) { + // See App.axaml.cs's --minimized handling for why ShowInTaskbar is toggled alongside + // Hide()/Show() - same Avalonia rendering-after-restore bug applies to this manual + // toggle, not just the autostart path. _window.Hide(); + _window.ShowInTaskbar = false; } else { @@ -256,6 +264,7 @@ private void OnWindowClosing(object? sender, WindowClosingEventArgs e) e.Cancel = true; _window.Hide(); + _window.ShowInTaskbar = false; } /// The tray menu's own Exit item - always performs a real shutdown, bypassing the