Skip to content

Commit 29be856

Browse files
authored
Manually dismiss popups when the window moves, or the SUI scrolls (#10922)
## Summary of the Pull Request BODGY! This solution was suggested in microsoft/microsoft-ui-xaml#4554 (comment). When the window moves, or when a ScrollViewer scrolls, dismiss any popups that are visible. This happens automagically when an app is a real XAML app, but it doesn't work for XAML Islands. ## References * upstream at microsoft/microsoft-ui-xaml#4554 ## PR Checklist * [x] Closes #9320 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments Unfortunately, we've got a bunch of scroll viewers in our SUI. So I did something bodgyx2 to make our life a little easier. `DismissAllPopups` can be used to dismiss all popups for a particular UI element. However, we've got a bunch of pages with scroll viewers that may or may not have popups in them. Rather than define the same exact body for all their `ViewChanging` events, the `HasScrollViewer` struct will just do it for you! Inside the `HasScrollViewer` stuct, we can't get at the `XamlRoot()` that our subclass implements. I mean, _we_ can, but when XAML does it's codegen, _XAML_ won't be able to figure it out. Fortunately for us, we don't need to! The sender is a UIElement, so we can just get _their_ `XamlRoot()`. So, you can fix this for any SUI page with just a simple ```diff - <ScrollViewer> + <ScrollViewer ViewChanging="ViewChanging"> ``` ```diff - struct AddProfile : AddProfileT<AddProfile> + struct AddProfile : public HasScrollViewer<AddProfile>, AddProfileT<AddProfile> ``` ## Validation Steps Performed * the window doesn't close when you move it * the popups _do_ close when you move the window * the popups close when you scroll any SUI page
1 parent 5d36e5d commit 29be856

24 files changed

+231
-155
lines changed

src/cascadia/TerminalSettingsEditor/Actions.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
107107
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr)
108108
};
109109

110-
struct Actions : ActionsT<Actions>
110+
struct Actions : public HasScrollViewer<Actions>, ActionsT<Actions>
111111
{
112112
public:
113113
Actions();

src/cascadia/TerminalSettingsEditor/Actions.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@
374374
</ResourceDictionary>
375375
</Page.Resources>
376376

377-
<ScrollViewer>
377+
<ScrollViewer ViewChanging="ViewChanging">
378378
<StackPanel MaxWidth="600"
379379
Spacing="8"
380380
Style="{StaticResource SettingsStackStyle}">

src/cascadia/TerminalSettingsEditor/AddProfile.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
4343
WINRT_CALLBACK(AddNew, AddNewArgs);
4444
};
4545

46-
struct AddProfile : AddProfileT<AddProfile>
46+
struct AddProfile : public HasScrollViewer<AddProfile>, AddProfileT<AddProfile>
4747
{
4848
public:
4949
AddProfile();

src/cascadia/TerminalSettingsEditor/AddProfile.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
</ResourceDictionary>
2222
</Page.Resources>
2323

24-
<ScrollViewer>
24+
<ScrollViewer ViewChanging="ViewChanging">
2525
<StackPanel Style="{StaticResource SettingsStackStyle}">
2626
<Button x:Uid="AddProfile_AddNewButton"
2727
AutomationProperties.AutomationId="AddProfile_AddNewButton"

src/cascadia/TerminalSettingsEditor/ColorSchemes.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
2020
WINRT_PROPERTY(winrt::hstring, LastSelectedScheme, L"");
2121
};
2222

23-
struct ColorSchemes : ColorSchemesT<ColorSchemes>
23+
struct ColorSchemes : public HasScrollViewer<ColorSchemes>, ColorSchemesT<ColorSchemes>
2424
{
2525
ColorSchemes();
2626

src/cascadia/TerminalSettingsEditor/ColorSchemes.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
</ResourceDictionary>
9494
</Page.Resources>
9595

96-
<ScrollViewer>
96+
<ScrollViewer ViewChanging="ViewChanging">
9797
<StackPanel Margin="{StaticResource StandardIndentMargin}"
9898
Spacing="24">
9999

src/cascadia/TerminalSettingsEditor/GlobalAppearance.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
1818
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
1919
};
2020

21-
struct GlobalAppearance : GlobalAppearanceT<GlobalAppearance>
21+
struct GlobalAppearance : public HasScrollViewer<GlobalAppearance>, GlobalAppearanceT<GlobalAppearance>
2222
{
2323
public:
2424
GlobalAppearance();

src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
</ResourceDictionary>
2525
</Page.Resources>
2626

27-
<ScrollViewer>
27+
<ScrollViewer ViewChanging="ViewChanging">
2828
<StackPanel Style="{StaticResource SettingsStackStyle}">
2929
<!-- Language -->
3030
<local:SettingContainer x:Uid="Globals_Language"

src/cascadia/TerminalSettingsEditor/Interaction.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
1818
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
1919
};
2020

21-
struct Interaction : InteractionT<Interaction>
21+
struct Interaction : public HasScrollViewer<Interaction>, InteractionT<Interaction>
2222
{
2323
Interaction();
2424

src/cascadia/TerminalSettingsEditor/Interaction.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
</ResourceDictionary>
2525
</Page.Resources>
2626

27-
<ScrollViewer>
27+
<ScrollViewer ViewChanging="ViewChanging">
2828
<StackPanel Style="{StaticResource SettingsStackStyle}">
2929
<!-- Copy On Select -->
3030
<local:SettingContainer x:Uid="Globals_CopyOnSelect"

src/cascadia/TerminalSettingsEditor/Launch.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
1818
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr)
1919
};
2020

21-
struct Launch : LaunchT<Launch>
21+
struct Launch : public HasScrollViewer<Launch>, LaunchT<Launch>
2222
{
2323
public:
2424
Launch();

src/cascadia/TerminalSettingsEditor/Launch.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
</ResourceDictionary>
3434
</Page.Resources>
3535

36-
<ScrollViewer>
36+
<ScrollViewer ViewChanging="ViewChanging">
3737
<StackPanel>
3838
<StackPanel Style="{StaticResource SettingsStackStyle}">
3939
<!-- Default Profile -->

src/cascadia/TerminalSettingsEditor/Profiles.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
153153
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> _Schemes;
154154
};
155155

156-
struct Profiles : ProfilesT<Profiles>
156+
struct Profiles : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
157157
{
158158
public:
159159
Profiles();

src/cascadia/TerminalSettingsEditor/Profiles.xaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
SelectionChanged="Pivot_SelectionChanged">
5757
<!-- General Tab -->
5858
<PivotItem x:Uid="Profile_General">
59-
<ScrollViewer>
59+
<ScrollViewer ViewChanging="ViewChanging">
6060
<StackPanel Style="{StaticResource PivotStackStyle}">
6161

6262
<!-- Name -->
@@ -225,7 +225,7 @@
225225

226226
<!-- Appearance Tab -->
227227
<PivotItem x:Uid="Profile_Appearance">
228-
<ScrollViewer>
228+
<ScrollViewer ViewChanging="ViewChanging">
229229
<StackPanel>
230230
<!-- Control Preview -->
231231
<Border x:Name="ControlPreview"
@@ -397,7 +397,7 @@
397397

398398
<!-- Advanced Tab -->
399399
<PivotItem x:Uid="Profile_Advanced">
400-
<ScrollViewer>
400+
<ScrollViewer ViewChanging="ViewChanging">
401401
<StackPanel Style="{StaticResource PivotStackStyle}">
402402
<!-- Suppress Application Title -->
403403
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"

src/cascadia/TerminalSettingsEditor/ReadOnlyActions.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
3232
TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget);
3333
};
3434

35-
struct ReadOnlyActions : ReadOnlyActionsT<ReadOnlyActions>
35+
struct ReadOnlyActions : public HasScrollViewer<ReadOnlyActions>, ReadOnlyActionsT<ReadOnlyActions>
3636
{
3737
public:
3838
ReadOnlyActions();

src/cascadia/TerminalSettingsEditor/ReadOnlyActions.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@
182182
</ResourceDictionary>
183183
</Page.Resources>
184184

185-
<ScrollViewer>
185+
<ScrollViewer ViewChanging="ViewChanging">
186186
<StackPanel Style="{StaticResource SettingsStackStyle}">
187187
<TextBlock x:Uid="Globals_KeybindingsDisclaimer"
188188
Style="{StaticResource DisclaimerStyle}" />

src/cascadia/TerminalSettingsEditor/Rendering.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
1818
WINRT_PROPERTY(Model::GlobalAppSettings, Globals, nullptr)
1919
};
2020

21-
struct Rendering : RenderingT<Rendering>
21+
struct Rendering : public HasScrollViewer<Rendering>, RenderingT<Rendering>
2222
{
2323
Rendering();
2424

src/cascadia/TerminalSettingsEditor/Rendering.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</ResourceDictionary>
1919
</Page.Resources>
2020

21-
<ScrollViewer>
21+
<ScrollViewer ViewChanging="ViewChanging">
2222
<StackPanel Style="{StaticResource SettingsStackStyle}">
2323
<TextBlock x:Uid="Globals_RenderingDisclaimer"
2424
Style="{StaticResource DisclaimerStyle}" />

src/cascadia/TerminalSettingsEditor/Utils.h

+38
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,41 @@ namespace winrt::Microsoft::Terminal::Settings
138138
winrt::hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable);
139139
winrt::hstring LocalizedNameForEnumName(const std::wstring_view sectionAndType, const std::wstring_view enumValue, const std::wstring_view propertyType);
140140
}
141+
142+
// BODGY!
143+
//
144+
// The following function and struct are a workaround for GH#9320.
145+
//
146+
// DismissAllPopups can be used to dismiss all popups for a particular UI
147+
// element. However, we've got a bunch of pages with scroll viewers that may or
148+
// may not have popups in them. Rather than define the same exact body for all
149+
// their ViewChanging events, the HasScrollViewer struct will just do it for
150+
// you!
151+
inline void DismissAllPopups(winrt::Windows::UI::Xaml::XamlRoot const& xamlRoot)
152+
{
153+
const auto popups{ winrt::Windows::UI::Xaml::Media::VisualTreeHelper::GetOpenPopupsForXamlRoot(xamlRoot) };
154+
for (const auto& p : popups)
155+
{
156+
p.IsOpen(false);
157+
}
158+
}
159+
160+
template<typename T>
161+
struct HasScrollViewer
162+
{
163+
// When the ScrollViewer scrolls, dismiss any popups we might have.
164+
void ViewChanging(winrt::Windows::Foundation::IInspectable const& sender,
165+
const winrt::Windows::UI::Xaml::Controls::ScrollViewerViewChangingEventArgs& /*e*/)
166+
{
167+
// Inside this struct, we can't get at the XamlRoot() that our subclass
168+
// implements. I mean, _we_ can, but when XAML does it's code
169+
// generation, _XAML_ won't be able to figure it out.
170+
//
171+
// Fortunately for us, we don't need to! The sender is a UIElement, so
172+
// we can just get _their_ XamlRoot().
173+
if (const auto& uielem{ sender.try_as<winrt::Windows::UI::Xaml::UIElement>() })
174+
{
175+
DismissAllPopups(uielem.XamlRoot());
176+
}
177+
}
178+
};

src/cascadia/WindowsTerminal/AppHost.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ AppHost::AppHost() noexcept :
7979
std::placeholders::_2));
8080
_window->MouseScrolled({ this, &AppHost::_WindowMouseWheeled });
8181
_window->WindowActivated({ this, &AppHost::_WindowActivated });
82+
_window->WindowMoved({ this, &AppHost::_WindowMoved });
8283
_window->HotkeyPressed({ this, &AppHost::_GlobalHotkeyPressed });
8384
_window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop());
8485
_window->MakeWindow();
@@ -1095,3 +1096,29 @@ winrt::fire_and_forget AppHost::_HideTrayIconRequested()
10951096
}
10961097
}
10971098
}
1099+
1100+
// Method Description:
1101+
// - BODGY workaround for GH#9320. When the window moves, dismiss all the popups
1102+
// in the UI tree. Xaml Islands unfortunately doesn't do this for us, see
1103+
// microsoft/microsoft-ui-xaml#4554
1104+
// Arguments:
1105+
// - <none>
1106+
// Return Value:
1107+
// - <none>
1108+
void AppHost::_WindowMoved()
1109+
{
1110+
if (_logic)
1111+
{
1112+
const auto root{ _logic.GetRoot() };
1113+
1114+
// This is basically DismissAllPopups which is also in
1115+
// TerminalSettingsEditor/Utils.h
1116+
// There isn't a good place that's shared between these two files, but
1117+
// it's only 5 LOC so whatever.
1118+
const auto popups{ Media::VisualTreeHelper::GetOpenPopupsForXamlRoot(root.XamlRoot()) };
1119+
for (const auto& p : popups)
1120+
{
1121+
p.IsOpen(false);
1122+
}
1123+
}
1124+
}

src/cascadia/WindowsTerminal/AppHost.h

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class AppHost
4848
const winrt::Windows::Foundation::IInspectable& arg);
4949
void _WindowMouseWheeled(const til::point coord, const int32_t delta);
5050
winrt::fire_and_forget _WindowActivated();
51+
void _WindowMoved();
5152

5253
void _DispatchCommandline(winrt::Windows::Foundation::IInspectable sender,
5354
winrt::Microsoft::Terminal::Remoting::CommandlineArgs args);

src/cascadia/WindowsTerminal/IslandWindow.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,11 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
465465
{
466466
return _OnMoving(wparam, lparam);
467467
}
468+
case WM_MOVE:
469+
{
470+
_WindowMovedHandlers();
471+
break;
472+
}
468473
case WM_CLOSE:
469474
{
470475
// If the user wants to close the app by clicking 'X' button,

0 commit comments

Comments
 (0)