From ab81476e27c6e5a85364a28f1237ad24ab9f88da Mon Sep 17 00:00:00 2001 From: ericek111 Date: Sun, 25 Oct 2026 10:50:02 +0000 Subject: [PATCH] Show tool windows without an owner so they can go behind the entry window An owned window is transient-for its owner on X11, so the window manager kept every tool window above the entry window. The windows now have no owner. The entry window closes them when it closes, and minimizes or restores them when its own state changes. Co-Authored-By: Claude Sonnet 5.5 --- src/Nonemm.App/Windows/EntryWindow.Menu.cs | 5 +++- src/Nonemm.App/Windows/EntryWindow.axaml.cs | 28 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Nonemm.App/Windows/EntryWindow.Menu.cs b/src/Nonemm.App/Windows/EntryWindow.Menu.cs index 4d7c72e..bb31722 100644 --- a/src/Nonemm.App/Windows/EntryWindow.Menu.cs +++ b/src/Nonemm.App/Windows/EntryWindow.Menu.cs @@ -749,7 +749,10 @@ public sealed partial class EntryWindow Place(window); openWindows[typeof(T)] = window; window.Closed += (_, _) => openWindows.Remove(typeof(T)); - window.Show(this); + // No owner: an owned window is transient-for the entry window, so the + // window manager keeps it above the entry window and it cannot be + // lowered. Closing the entry window closes these (see the Closed handler in the constructor). + window.Show(); return window; } diff --git a/src/Nonemm.App/Windows/EntryWindow.axaml.cs b/src/Nonemm.App/Windows/EntryWindow.axaml.cs index aaee26e..e647215 100644 --- a/src/Nonemm.App/Windows/EntryWindow.axaml.cs +++ b/src/Nonemm.App/Windows/EntryWindow.axaml.cs @@ -81,6 +81,22 @@ public sealed partial class EntryWindow : Window // the windows are where this operator left them, and that is what he // gets back next time he takes the radio Closing += (_, _) => session.Save(WithLayout(session.Settings)); + PropertyChanged += (_, e) => + { + if (e.Property == WindowStateProperty + && WindowState is WindowState.Minimized or WindowState.Normal) + { + FollowWindowState(WindowState); + } + }; + Closed += (_, _) => + { + foreach (Window window in openWindows.Values.ToList()) + { + window.Close(); + } + secondRadio?.Close(); + }; clock.Tick += (_, _) => UpdateClock(); clock.Start(); session.EntryWiped += (_, wiped) => Dispatcher.UIThread.Post(() => @@ -156,7 +172,7 @@ public sealed partial class EntryWindow : Window { secondRadio = new EntryWindow(session, 2); secondRadio.Closed += (_, _) => secondRadio = null; - secondRadio.Show(this); + secondRadio.Show(); } else if (!wanted && secondRadio is not null) { @@ -166,6 +182,16 @@ public sealed partial class EntryWindow : Window } } + /// The tool windows have no owner, so the window manager does not minimize + /// or restore them with the entry window. This does it. + private void FollowWindowState(WindowState state) + { + foreach (Window window in openWindows.Values.Concat(secondRadio is null ? [] : [secondRadio])) + { + window.WindowState = state; + } + } + /// The keyboard follows the operator to the other radio. private void FollowActiveRadio(int number) {