Bring the main window to the front when reopening a collection (BL-16784) - #8268
Open
StephenMcConnel wants to merge 2 commits into
Open
Bring the main window to the front when reopening a collection (BL-16784)#8268StephenMcConnel wants to merge 2 commits into
StephenMcConnel wants to merge 2 commits into
Conversation
…784) Switching collections does not restart Bloom: it closes the Shell and opens a new one in the same process. The only code that forces the main window to the front, Shell.ReallyComeToFront, was reached only through the one-shot StartupScreenManager.DoLastOfAllAfterClosingSplashScreen, which is consumed when the splash screen closes at first startup. So on a reopen nothing brought the new window forward: it had only Show()'s implicit activation, which Windows refuses once another application (Chrome, say) took the foreground as Bloom's previous window closed. Bloom came up invisible behind it. OpenProjectWindow is the one place every way of opening a collection funnels through, so the fix goes there, gated on a new named predicate, WillBringMainWindowToFrontWhenSplashCloses: bring the window forward whenever nothing else is going to. That covers switching collections and the close and reopen after a UI language or Collection Settings change. First startup is excluded, where the one-shot already does it and doing it twice would put the main window over the dialogs startup puts up. Being topmost is not enough by itself. When another application holds the foreground, Windows refuses our Activate(), so the window we raised is not the active one, and dropping topmost lands us behind it again -- measurably: with only the topmost toggle Bloom came up second, directly behind Chrome. So ProcessExtra.ForceWindowToForeground briefly attaches our input queue to the foreground window's thread, the standard way to be allowed the foreground. Along the way, BringToFrontNow is factored out of BringToFrontWhenShown (added for BL-16690) so Shell.ReallyComeToFront shares the topmost-then-drop idiom instead of the instant toggle that BL-16690 already documented as losing this race. Also fixed as a consequence: _finishedLoading is set only in ReallyComeToFront, and Shell_ResizeEnd will not save window bounds until it is true, so after a collection switch Bloom silently stopped saving its window size and position. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…estartsBehindChrome
Contributor
|
| Filename | Overview |
|---|---|
| src/BloomExe/Program.cs | Adds the foreground action after opening a collection when the startup splash one-shot will not perform it. |
| src/BloomExe/Extensions.cs | Extracts the shared delayed TopMost activation behavior and adds explicit Windows foreground activation. |
| src/BloomExe/ToPalaso/ProcessExtra.cs | Adds guarded foreground-window activation using temporary input-thread attachment with cleanup in a finally block. |
| src/BloomExe/MiscUI/StartupScreenManager.cs | Exposes whether the splash-close foreground one-shot remains pending. |
| src/BloomExe/Shell.cs | Reuses the new foreground helper while retaining the loading-complete state transition. |
| src/BloomTests/MiscUI/StartupScreenManagerTests.cs | Verifies that closing the splash consumes the foreground one-shot while temporarily hiding it for a dialog does not. |
Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/Ver..." | Re-trigger Greptile
Contributor
Author
|
[Claude Opus 5 (1M context)] Consulted Devin on 2026-08-31 20:31 UTC up to commit Devin's review completed for this commit with nothing to report: no bugs, no Investigate flags, and no Informational items. Greptile posted a summary with no findings, and both PR checks passed. |
StephenMcConnel
marked this pull request as ready for review
August 31, 2026 21:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Switching collections doesn't restart Bloom — it closes the Shell and opens a new one in the same process. The only code that forces the main window to the front,
Shell.ReallyComeToFront(), was reached only through the one-shotStartupScreenManager.DoLastOfAllAfterClosingSplashScreen, which is consumed when the splash screen closes at first startup. So on a reopen nothing brought the new window forward: it had onlyShow()'s implicit activation, which Windows refuses once another application (Chrome, say) took the foreground as Bloom's previous window closed. The window was displayed behind Chrome.Why it looked new in 6.5 and only off the main monitor: the activation is a race, and
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2)(BL-16269) meansShell_Loadsetting saved bounds onto a different-DPI monitor now triggers a rescale before the window settles — enough extra work to lose a race it used to win.The change
Program.OpenProjectWindow— afterShow(), bring the new Shell forward when nothing else will, using the newStartupScreenManager.WillBringMainWindowToFrontWhenSplashClosespredicate. This is the one place every way of opening a collection funnels through, so it covers switching collections and the close/reopen after a UI-language or Collection Settings change. First startup is excluded, because the splash one-shot does it there and doing it twice would put the main window over the dialogs startup puts up.Extensions— extractedBringToFrontNowfrom the BL-16690BringToFrontWhenShown, so both share the topmost-then-drop idiom.Shell.ReallyComeToFront— uses it, instead of the instant TopMost toggle that BL-16690 already documented as losing this race.ProcessExtra.ForceWindowToForeground— being topmost is not enough on its own: when another application holds the foreground Windows refuses ourActivate(), so the raised window is still not the active one and dropping topmost lands us behind it again. Measured: with only the topmost toggle, Bloom came up second, directly behind Chrome. This briefly attaches our input queue to the foreground window's thread, the standard way to be allowed to take the foreground.Also fixed as a consequence:
Shell._finishedLoadingis set only inReallyComeToFront, andShell_ResizeEndwon't save window bounds until it is true — so after a collection switch Bloom silently stopped saving its window size and position.Testing
Two tests in
StartupScreenManagerTestscover the predicate the fix hangs on: thatCloseSplashScreenconsumes the one-shot (so a reopen answers "nobody will do this"), and thatHideSplashScreenForDialogdeliberately does not (so the startup route that shows the collection chooser still answers "no need").Verified by hand on a two-monitor setup with Bloom and Chrome both maximized on the secondary monitor, switching collections:
Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-16784
Devin review
This change is