diff --git a/src/RemSound.App/MainForm.cs b/src/RemSound.App/MainForm.cs index a90523b..9159af4 100644 --- a/src/RemSound.App/MainForm.cs +++ b/src/RemSound.App/MainForm.cs @@ -9911,13 +9911,16 @@ public sealed partial class MainForm : Form // hook (false-NEGATIVE — user changes something via an unhooked path, no prompt // on close) is acceptable; the previous false-POSITIVE behaviour was nagging. { - var result = MessageBox.Show(this, + // Via ForegroundDialog: OnFormClosing fires from tray → Exit (RemSound minimised) and + // OS shutdown, so a plain MessageBox(this) would open behind everything and a blind + // user couldn't reach it to answer (Ed, 2026-07-27 dialog-focus sweep). + var result = ForegroundDialog.Show(owner => MessageBox.Show(owner, "You have unsaved changes to your profile. Save them before exiting?\n\n" + "Yes — save and exit.\nNo — exit without saving.\nCancel — keep RemSound open.", "RemSound — unsaved changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, - MessageBoxDefaultButton.Button3); + MessageBoxDefaultButton.Button3)); if (result == DialogResult.Cancel) { diff --git a/src/RemSound.App/QuickProfileSwitchDialog.cs b/src/RemSound.App/QuickProfileSwitchDialog.cs index 60f698f..b81f787 100644 --- a/src/RemSound.App/QuickProfileSwitchDialog.cs +++ b/src/RemSound.App/QuickProfileSwitchDialog.cs @@ -22,12 +22,13 @@ internal sealed class QuickProfileSwitchDialog var (dialog, list, chosenPath) = Build(profiles); using (dialog) { - dialog.Shown += (_, _) => - { - BringToForeground(dialog); - list.Focus(); - }; - return dialog.ShowDialog() == DialogResult.OK ? chosenPath() : null; + dialog.Shown += (_, _) => list.Focus(); + // Via ForegroundDialog: this is opened by a GLOBAL hotkey, so RemSound is usually + // minimised in the tray when it fires — the old ad-hoc SetForegroundWindow only flashed + // the taskbar there (Windows blocks foreground from a background process), leaving a blind + // user Alt-Tabbing for it. ForegroundDialog's 1×1-owner + foreground-lock dance actually + // surfaces it with focus wherever RemSound is sitting (Ed, 2026-07-27 dialog-focus sweep). + return ForegroundDialog.Show(owner => dialog.ShowDialog(owner)) == DialogResult.OK ? chosenPath() : null; } } @@ -142,20 +143,4 @@ internal sealed class QuickProfileSwitchDialog return (dialog, list, () => chosenPath); } - - private static void BringToForeground(Form form) - { - try - { - form.Activate(); - // The hotkey press is recent user input, so the foreground lock lets us call this - // (same handshake the tray "restore" uses). - SetForegroundWindow(form.Handle); - } - catch { /* foreground-lock race — best effort, the window is still TopMost */ } - } - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool SetForegroundWindow(IntPtr hWnd); }