terminal/src/cascadia/WindowsTerminal/IslandWindow.h
Mike Griese 29be8564f6
Manually dismiss popups when the window moves, or the SUI scrolls (#10922)
## Summary of the Pull Request

BODGY!

This solution was suggested in https://github.com/microsoft/microsoft-ui-xaml/issues/4554#issuecomment-887815332.

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 https://github.com/microsoft/microsoft-ui-xaml/issues/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
2021-08-16 13:41:17 +00:00

139 lines
5.8 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "BaseWindow.h"
#include <winrt/TerminalApp.h>
#include "../../cascadia/inc/cppwinrt_utils.h"
class IslandWindow :
public BaseWindow<IslandWindow>
{
public:
IslandWindow() noexcept;
virtual ~IslandWindow() override;
virtual void MakeWindow() noexcept;
void Close();
virtual void OnSize(const UINT width, const UINT height);
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
void OnResize(const UINT width, const UINT height) override;
void OnMinimize() override;
void OnRestore() override;
virtual void OnAppInitialized();
virtual void SetContent(winrt::Windows::UI::Xaml::UIElement content);
virtual void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
virtual RECT GetNonClientFrame(const UINT dpi) const noexcept;
virtual SIZE GetTotalNonClientExclusiveSize(const UINT dpi) const noexcept;
virtual void Initialize();
void SetCreateCallback(std::function<void(const HWND, const RECT, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode)> pfn) noexcept;
void SetSnapDimensionCallback(std::function<float(bool widthOrHeight, float dimension)> pfn) noexcept;
void FocusModeChanged(const bool focusMode);
void FullscreenChanged(const bool fullscreen);
void SetAlwaysOnTop(const bool alwaysOnTop);
void FlashTaskbar();
void SetTaskbarProgress(const size_t state, const size_t progress);
void UnregisterHotKey(const int index) noexcept;
bool RegisterHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept;
winrt::fire_and_forget SummonWindow(winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior args);
bool IsQuakeWindow() const noexcept;
void IsQuakeWindow(bool isQuakeWindow) noexcept;
void HideWindow();
void SetMinimizeToTrayBehavior(bool minimizeToTray) noexcept;
DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
DECLARE_EVENT(WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
WINRT_CALLBACK(MouseScrolled, winrt::delegate<void(til::point, int32_t)>);
WINRT_CALLBACK(WindowActivated, winrt::delegate<void()>);
WINRT_CALLBACK(HotkeyPressed, winrt::delegate<void(long)>);
WINRT_CALLBACK(NotifyTrayIconPressed, winrt::delegate<void()>);
WINRT_CALLBACK(NotifyWindowHidden, winrt::delegate<void()>);
WINRT_CALLBACK(NotifyShowTrayContextMenu, winrt::delegate<void(til::point)>);
WINRT_CALLBACK(NotifyTrayMenuItemSelected, winrt::delegate<void(HMENU, UINT)>);
WINRT_CALLBACK(NotifyReAddTrayIcon, winrt::delegate<void()>);
WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>);
protected:
void ForceResize()
{
// Do a quick resize to force the island to paint
const auto size = GetPhysicalSize();
OnSize(size.cx, size.cy);
}
HWND _interopWindowHandle;
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _source;
winrt::Windows::UI::Xaml::Controls::Grid _rootGrid;
wil::com_ptr<ITaskbarList3> _taskbar;
std::function<void(const HWND, const RECT, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode)> _pfnCreateCallback;
std::function<float(bool, float)> _pfnSnapDimensionCallback;
void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept;
[[nodiscard]] LRESULT _OnSizing(const WPARAM wParam, const LPARAM lParam);
[[nodiscard]] LRESULT _OnMoving(const WPARAM wParam, const LPARAM lParam);
bool _borderless{ false };
bool _alwaysOnTop{ false };
bool _fullscreen{ false };
bool _fWasMaximizedBeforeFullscreen{ false };
RECT _rcWindowBeforeFullscreen{};
RECT _rcWorkBeforeFullscreen{};
UINT _dpiBeforeFullscreen{ 96 };
virtual void _SetIsBorderless(const bool borderlessEnabled);
virtual void _SetIsFullscreen(const bool fullscreenEnabled);
void _RestoreFullscreenPosition(const RECT rcWork);
void _SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork);
LONG _getDesiredWindowStyle() const;
void _OnGetMinMaxInfo(const WPARAM wParam, const LPARAM lParam);
long _calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize);
void _globalActivateWindow(const uint32_t dropdownDuration,
const winrt::Microsoft::Terminal::Remoting::MonitorBehavior toMonitor);
void _dropdownWindow(const uint32_t dropdownDuration,
const winrt::Microsoft::Terminal::Remoting::MonitorBehavior toMonitor);
void _slideUpWindow(const uint32_t dropdownDuration);
void _doSlideAnimation(const uint32_t dropdownDuration, const bool down);
void _globalDismissWindow(const uint32_t dropdownDuration);
static MONITORINFO _getMonitorForCursor();
static MONITORINFO _getMonitorForWindow(HWND foregroundWindow);
void _moveToMonitor(HWND foregroundWindow, const winrt::Microsoft::Terminal::Remoting::MonitorBehavior toMonitor);
void _moveToMonitorOfMouse();
void _moveToMonitorOf(HWND foregroundWindow);
void _moveToMonitor(const MONITORINFO activeMonitor);
bool _isQuakeWindow{ false };
void _enterQuakeMode();
til::rectangle _getQuakeModeSize(HMONITOR hmon);
void _summonWindowRoutineBody(winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior args);
bool _minimizeToTray{ false };
private:
// This minimum width allows for width the tabs fit
static constexpr long minimumWidth = 460L;
// We run with no height requirement for client area,
// though the total height will take into account the non-client area
// and the requirements of components hosted in the client area
static constexpr long minimumHeight = 0L;
};