Skip to content

fix: never open a second main window from the tray - #492

Merged
KnifeLemon merged 1 commit into
mainfrom
fix/single-main-window
Oct 23, 2026
Merged

KnifeLemon merged 1 commit into
mainfrom
fix/single-main-window

Conversation

@KnifeLemon

Copy link
Copy Markdown
Owner

Summary

Sometimes, after double-clicking the tray icon several times, two main windows were open at once.

  • Cause: Avalonia's Windows tray raises Clicked synchronously from its window procedure (WM_TRAYMOUSE → OnClicked, not posted). ShowMain only set _main after building the view model, the window, the restored placement and the restored page. A tray click handled during that work re-entered ShowMain, saw _main == null and built a second window. The outer call then overwrote _main, so the first window became an orphan that nothing tracked. After the first trip to the tray the build path is longer (placement and last page, e.g. Theme), which fits the bug showing up mid-session rather than on a fresh start.
  • A click that arrived while a window that went to the tray was being closed for good (the posted release, issue Reduce background memory footprint: ~177 MB in the tray, ~500 MB after conversions #119) re-showed that dying window instead of opening a new one, leaving no window.
  • Fix (WindowService.ShowMain):
    • A flag marks that a window is being built. Calls made meanwhile go to that window and keep the page they asked for.
    • A tracked window that is being released (or is already closed) is left to close, and a new one opens.
    • ShowMain keeps a list of every main window it built that isn't closed yet. Any other still alive goes to the tray (and is released), so there is never more than one main window.
  • MainWindow exposes IsReleased and clears _releasing again if the release close is cancelled.
  • Placement restore and releasing the window's memory when it goes to the tray (Reduce background memory footprint: ~177 MB in the tray, ~500 MB after conversions #119) stay as they were.

Test plan

  • New SingleMainWindowTests (headless). All three fail on main and pass with the fix:
    • a tray click handled while the window is built, after a few tray round trips (restored Theme page), with and without a page
    • a tray click while the released window closes
    • seeded random sequences of single and double clicks, title-bar closes, HideToTray, pumped and unpumped, with clicks injected during build and release (3 seeds)
  • MainWindowReleaseTests, CloseActionTests, TrayServiceTests, WhatsNewTests, ToolbarEditorTests, ThemePageTests pass
  • dotnet format Filee.slnx --verify-no-changes, build
  • Windows: double-click the tray icon repeatedly across several close-to-tray cycles; only one window ever appears

🤖 Generated with Claude Code

On Windows the tray icon raises Clicked straight from its window procedure, so a
tray click handled while ShowMain was still building the window (before _main was
set) built a second one; the first then became an orphan nothing tracked. A click
that arrived while a window that went to the tray was being closed for good also
re-showed that dying window instead of opening a new one.

ShowMain now marks that it is building the window and sends calls made meanwhile
to it (keeping the page they asked for), opens a new window when the tracked one
is being released, and sends any other main window still alive to the tray. The
release flag is cleared again if the close is cancelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KnifeLemon KnifeLemon added the bug Something isn't working label Oct 23, 2026
@KnifeLemon KnifeLemon self-assigned this Oct 23, 2026
@KnifeLemon
KnifeLemon merged commit abd9fa4 into main Oct 23, 2026
9 checks passed
KnifeLemon added a commit to gtxPrime/Filee that referenced this pull request Oct 23, 2026
Resolves WindowService.ShowMain against the single-main-window fix (KnifeLemon#492):
the main window is now made in CreateMain, which applies the theme's window
class (PrepareWindow) like the other windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KnifeLemon added a commit to gtxPrime/Filee that referenced this pull request Oct 23, 2026
The app has one WindowService, so tests that open, close or count the main window
share it. Run in parallel, one test's pumping ran another's posted close or open,
and OpenMain/CloseMain found a window that wasn't theirs (main CI failed after
KnifeLemon#492 added the single-main-window tests). They now share a collection that doesn't
run in parallel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant