Skip to content

Clear the window on teardown so Start can run again - #422

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/nice-davinci-0bqvja
Sep 17, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/nice-davinci-0bqvja

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #404

What was wrong

Start()'s teardown disposed the window but never cleared the static window field. The guard at the top of Start() reads that field, so every later call threw InvalidOperationException("Application is already running.") for the rest of the process — with nothing actually running. Reset() clears the field, but it is internal and visible only to the test assembly, so consumers had no workaround. Restart-to-apply-settings, and any harness driving sequential sessions in one process, were impossible.

EmbeddedSession.RunLoop's finally block already cleared the field, with a comment saying it does so by design, so the two lifecycle paths had drifted.

The change

Both paths now end in one TeardownWindow(), rather than each carrying its own list of fields to clear:

  • disposes the controller, the input context and the GL context (via the existing Cleanup* helpers, all of which are idempotent — the window's Closing handler has usually run them already), then disposes the window and clears it
  • Start()'s blocking branch is factored into RunWindowLoop(), which runs the loop and then tears down; this also makes the post-loop path reachable from a test without a real window
  • EmbeddedSession.RunLoop's finally calls the same helper, so its teardown now also releases the GL resources on an abnormal exit

The embedded path gains GL/controller/input cleanup it did not have; nothing else changes behaviour.

Tests

New tests/ImGui.App.Tests/WindowTeardownTests.cs:

  • RunWindowLoopDisposesTheWindowAndClearsIt — the window is disposed and the field is null once the loop returns
  • RunWindowLoopReleasesTheResourcesThatHungOffTheWindow — the input context is disposed, and controller, renderer, gl and glProvider are cleared
  • StartIsAllowedAgainOnceTheRunLoopHasReturned — the issue's acceptance criterion: Start → loop returns → Start again succeeds

All three fail against the old teardown (the third with the exact Application is already running. from the issue) and pass with the fix. Full ImGui.App.Tests suite: 431/431 passing on this branch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AZcLBdphhSBSNeUALeVhxB


Generated by Claude Code

Start()'s teardown disposed the window but left the static field set, so
the guard at the top of Start() reported "Application is already running."
for the rest of the process even though nothing was. Reset() clears the
field but is internal to the test assembly, so consumers had no way out:
restart-to-apply-settings, and any harness driving sequential sessions,
were impossible.

EmbeddedSession.RunLoop's finally block already cleared the field, so the
two paths had drifted. Rather than copy the clears into Start(), both now
end in a single TeardownWindow() that disposes the controller, the input
context and the GL context before disposing the window and clearing it.
The cleanups are idempotent, so running after the window's Closing handler
has already done them is a no-op.

Fixes #404

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZcLBdphhSBSNeUALeVhxB
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ImGuiApp.Start() cannot be called again after a clean Stop()/window-close in the same process

1 participant