-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix dialogs not working across multiple windows
- Loading branch information
Showing
2 changed files
with
41 additions
and
17 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,7 +144,6 @@ namespace winrt::TerminalApp::implementation | |
{ | ||
// Now that we know we can do XAML, build our page. | ||
_root = winrt::make_self<TerminalPage>(*_WindowProperties, _manager); | ||
_dialog = ContentDialog{}; | ||
|
||
// Pass in information about the initial state of the window. | ||
// * If we were supposed to start from serialized "content", do that, | ||
|
@@ -313,6 +312,14 @@ namespace winrt::TerminalApp::implementation | |
{ | ||
return _settings.GlobalSettings().CurrentTheme(); | ||
} | ||
|
||
// WinUI can't show 2 dialogs simultaneously. Yes, really. If you do, you get an exception. | ||
// As such, we must dismiss whatever dialog is currently being shown. | ||
// | ||
// This limit is of course per-thread and not per-window. Yes... really. | ||
// The consequence is that we use a static variable to keep track of the shown dialog. | ||
static ContentDialog s_activeDialog{ nullptr }; | ||
|
||
// Method Description: | ||
// - Show a ContentDialog with buttons to take further action. Uses the | ||
// FrameworkElements provided as the title and content of this dialog, and | ||
|
@@ -328,16 +335,32 @@ namespace winrt::TerminalApp::implementation | |
// - an IAsyncOperation with the dialog result | ||
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalWindow::ShowDialog(winrt::WUX::Controls::ContentDialog dialog) | ||
{ | ||
// DON'T release this lock in a wil::scope_exit. The scope_exit will get | ||
// called when we await, which is not what we want. | ||
std::unique_lock lock{ _dialogLock, std::try_to_lock }; | ||
if (!lock) | ||
// As mentioned on s_activeDialog, dismissing the active dialog is necessary. | ||
// We repeat it a few times in case the resume_foreground failed to work, | ||
// but I found that one iteration will always be enough in practice. | ||
for (int i = 0; i < 3; ++i) | ||
{ | ||
if (!s_activeDialog) | ||
{ | ||
break; | ||
} | ||
|
||
s_activeDialog.Hide(); | ||
|
||
// Wait for the current dialog to be hidden. | ||
co_await wil::resume_foreground(_root->Dispatcher(), CoreDispatcherPriority::Low); | ||
} | ||
|
||
// If two sources call ShowDialog() simultaneously, it may happen that both enter the above loop, | ||
// but it's crucial that only one of them continues below as only 1 dialog can be shown at a time. | ||
// Thankfully, everything runs on the UI thread, so only 1 caller will exit the above loop at a time. | ||
// So, if s_activeDialog is still set at this point, we must've lost the race. | ||
Check failure Code scanning / check-spelling Unrecognized Spelling Error
must've is not a recognized word. (unrecognized-spelling)
|
||
if (s_activeDialog) | ||
{ | ||
// Another dialog is visible. | ||
co_return ContentDialogResult::None; | ||
} | ||
|
||
_dialog = dialog; | ||
s_activeDialog = dialog; | ||
|
||
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs. | ||
// Since we're hosting the dialog in a Xaml island, we need to connect it to the | ||
|
@@ -367,23 +390,26 @@ namespace winrt::TerminalApp::implementation | |
} | ||
} }; | ||
|
||
themingLambda(dialog, nullptr); // if it's already in the tree | ||
auto loadedRevoker{ dialog.Loaded(winrt::auto_revoke, themingLambda) }; // if it's not yet in the tree | ||
auto result = ContentDialogResult::None; | ||
|
||
// Display the dialog. | ||
co_return co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup); | ||
// Extra scope to drop the revoker before resetting the s_activeDialog to null. | ||
{ | ||
themingLambda(dialog, nullptr); // if it's already in the tree | ||
auto loadedRevoker{ dialog.Loaded(winrt::auto_revoke, themingLambda) }; // if it's not yet in the tree | ||
result = co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup); | ||
} | ||
|
||
// After the dialog is dismissed, the dialog lock (held by `lock`) will | ||
// be released so another can be shown | ||
s_activeDialog = nullptr; | ||
co_return result; | ||
} | ||
|
||
// Method Description: | ||
// - Dismiss the (only) visible ContentDialog | ||
void TerminalWindow::DismissDialog() | ||
{ | ||
if (auto localDialog = std::exchange(_dialog, nullptr)) | ||
if (s_activeDialog) | ||
{ | ||
localDialog.Hide(); | ||
s_activeDialog.Hide(); | ||
} | ||
} | ||
|
||
|
This file contains 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
c528a72
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@check-spelling-bot Report
🔴 Please review
See the 📜action log or 📝 job summary for details.
Unrecognized words (1)
must've
These words are not needed and should be removed
abcd ABCDEFGHIJ abcdefghijk ABCDEFGHIJKLMNOPQRS ABCDEFGHIJKLMNOPQRST ABCDEFGHIJKLMNOPQRSTUVWXY allocs appium Argb asan autocrlf backported bytebuffer cac CLE codenav codepath commandline COMMITID componentization constness dealloc deserializers DISPATCHNOTIFY DTest entrypoints EVENTID FINDUP fuzzer hlocal hstring IInput Interner keyscan Munged numlock offboarded pids positionals Productize pseudoterminal remoting renamer roadmap ruleset SELECTALL somefile Stringable tearoff TODOs touchpad TREX Unregistering USERDATA vectorize viewports wslTo accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands
... in a clone of the [email protected]:microsoft/terminal.git repository
on the
dev/lhecker/18599-part1
branch (ℹ️ how do I use this?):Errors (1)
See the 📜action log or 📝 job summary for details.
See ❌ Event descriptions for more information.
✏️ Contributor please read this
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
If the listed items are:
.github/actions/spelling/allow/names.txt
..github/actions/spelling/allow/
..github/actions/spelling/expect/
..github/actions/spelling/patterns/
.See the
README.md
in each directory for more information.🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉
If the flagged items are 🤯 false positives
If items relate to a ...
binary file (or some other file you wouldn't want to check at all).
Please add a file path to the
excludes.txt
file matching the containing file.File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.
^
refers to the file's path from the root of the repository, so^README\.md$
would exclude README.md (on whichever branch you're using).well-formed pattern.
If you can write a pattern that would match it,
try adding it to the
patterns.txt
file.Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.