You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR fixes an initialization order bug when AppBuilder.SetupWithClassicDesktopLifetime() is called instead of StartWithClassicDesktopLifetime().
What is the current behavior?
When SetupWithClassicDesktopLifetime is used, internal events are registered before the AppBuilder initializers run: at that point, many subsystems aren't available yet, causing issues such as ShutdownRequested not being hooked up. Additionally, Startup is called way earlier, or might be called twice if Start() is called manually on the created lifetime.
A related problem arises when calling AppBuilder.SetupWithLifetime() manually without Start: the internal event handlers aren't even initialized.
On macOS, this causes the ShutdownRequested event not to be called when quitting the app from the dock, then triggering a double close of the main window (and hitting a debug assertion).
What is the updated/expected behavior with this PR?
StartWithClassicDesktopLifetime, SetupWithClassicDesktopLifetime and SetupWithLifetime initialize the subsystems and event handlers in the same exact order.
Quitting a macOS application raises the ShutdownRequested event correctly and respects its cancellation.
Unit tests have been added.
How was the solution implemented (if it's not obvious)?
An internal ISetupApplicationLifetime is added and implemented by ClassicDesktopStyleApplicationLifetime. The AppBuilder is responsible for calling it to initialize the lifetime in the correct order properly.
I disagree. The whole point of this PR is to make it consistent: Startup is always raised from the same place, here Setup (unfortunately). There might be no Start() call at all!
In other words, Setup(new ClassicDesktopStyleApplicationLifetime()) and SetupWithClassicDesktopLifetime should have the same behavior with regard to when/if Startup is raised. That's why this PR adds it directly to the base builder instead of special-casing just one path.
In v13, we should remove this hack and take the breaking change that Startup is only called when Start is, solving both issues and respecting the arguments.
Having thought about it more, the fact that Setup was raising Startup is also part of the bug. The whole initialization order was incorrect. I've changed my stance: Startup is now raised only when Start is called, not on Setup.
Users of Setup are few, and such users know when their app starts, so the Startup event is irrelevant there, especially since it was called immediately from Setup, which is user-controlled.
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
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.
What does the pull request do?
This PR fixes an initialization order bug when
AppBuilder.SetupWithClassicDesktopLifetime()is called instead ofStartWithClassicDesktopLifetime().What is the current behavior?
When
SetupWithClassicDesktopLifetimeis used, internal events are registered before theAppBuilderinitializers run: at that point, many subsystems aren't available yet, causing issues such asShutdownRequestednot being hooked up. Additionally,Startupis called way earlier, or might be called twice ifStart()is called manually on the created lifetime.A related problem arises when calling
AppBuilder.SetupWithLifetime()manually withoutStart: the internal event handlers aren't even initialized.On macOS, this causes the
ShutdownRequestedevent not to be called when quitting the app from the dock, then triggering a double close of the main window (and hitting a debug assertion).What is the updated/expected behavior with this PR?
StartWithClassicDesktopLifetime,SetupWithClassicDesktopLifetimeandSetupWithLifetimeinitialize the subsystems and event handlers in the same exact order.Quitting a macOS application raises the
ShutdownRequestedevent correctly and respects its cancellation.Unit tests have been added.
How was the solution implemented (if it's not obvious)?
An internal
ISetupApplicationLifetimeis added and implemented byClassicDesktopStyleApplicationLifetime. TheAppBuilderis responsible for calling it to initialize the lifetime in the correct order properly.Fixed issues
SetupWithClassicDesktopLifetime()is used #20683