From 2fc6cd4d402e047ab8282cc3feaff55bb157f2a4 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 15 Aug 2019 09:43:39 -0500 Subject: [PATCH] When the titlebar is clicked, dismiss the new tab flyout Fixes #2028. --- src/cascadia/TerminalApp/App.cpp | 17 ++++++++++ src/cascadia/TerminalApp/App.h | 1 + src/cascadia/TerminalApp/App.idl | 2 ++ src/cascadia/WindowsTerminal/AppHost.cpp | 5 +++ .../WindowsTerminal/NonClientIslandWindow.cpp | 31 ++++++++++++++----- .../WindowsTerminal/NonClientIslandWindow.h | 5 ++- 6 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalApp/App.cpp b/src/cascadia/TerminalApp/App.cpp index 05120c06b2d..f56421e205a 100644 --- a/src/cascadia/TerminalApp/App.cpp +++ b/src/cascadia/TerminalApp/App.cpp @@ -1462,6 +1462,23 @@ namespace winrt::TerminalApp::implementation return connection; } + // Method Description: + // - Used to tell the app that the titlebar has been clicked. The App won't + // actually recieve any clicks in the titlebar area, so this is a helper + // to clue the app in that a click has happened. The App will use this as + // a indicator that it needs to dismiss any open flyouts. + // Arguments: + // - + // Return Value: + // - + void App::TitlebarClicked() + { + if (_newTabButton && _newTabButton.Flyout()) + { + _newTabButton.Flyout().Hide(); + } + } + // -------------------------------- WinRT Events --------------------------------- // Winrt events need a method for adding a callback to the event and removing the callback. // These macros will define them both for you. diff --git a/src/cascadia/TerminalApp/App.h b/src/cascadia/TerminalApp/App.h index 473f220d12c..0d52350357d 100644 --- a/src/cascadia/TerminalApp/App.h +++ b/src/cascadia/TerminalApp/App.h @@ -37,6 +37,7 @@ namespace winrt::TerminalApp::implementation ~App() = default; hstring GetTitle(); + void TitlebarClicked(); // -------------------------------- WinRT Events --------------------------------- DECLARE_EVENT(TitleChanged, _titleChangeHandlers, winrt::Microsoft::Terminal::TerminalControl::TitleChangedEventArgs); diff --git a/src/cascadia/TerminalApp/App.idl b/src/cascadia/TerminalApp/App.idl index 3fe919a697d..3d954850ef7 100644 --- a/src/cascadia/TerminalApp/App.idl +++ b/src/cascadia/TerminalApp/App.idl @@ -30,5 +30,7 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler RequestedThemeChanged; String GetTitle(); + + void TitlebarClicked(); } } diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 5893c1ad9ea..da62173fa3f 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -68,6 +68,11 @@ void AppHost::Initialize() // This has to be done _before_ App::Create, as the app might set the // content in Create. _app.SetTitleBarContent({ this, &AppHost::_UpdateTitleBarContent }); + + // Add an event handler to plumb clicks in the titlebar area down to the + // application layer. + auto pNcWindow = static_cast(_window.get()); + pNcWindow->DragRegionClicked([this]() { _app.TitlebarClicked(); }); } _app.RequestedThemeChanged({ this, &AppHost::_UpdateTheme }); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 9d1cfa7d2d8..840e5db6421 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -263,14 +263,22 @@ void NonClientIslandWindow::_UpdateDragRegion() // - Hit test the frame for resizing and moving. // Arguments: // - ptMouse: the mouse point being tested, in absolute (NOT WINDOW) coordinates. +// - titlebarIsCaption: If true, we want to treat the titlebar area as +// HTCAPTION, otherwise we'll return HTNOWHERE for the titlebar. // Return Value: // - one of the values from // https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-nchittest#return-value // corresponding to the area of the window that was hit // NOTE: -// Largely taken from code on: +// - Largely taken from code on: // https://docs.microsoft.com/en-us/windows/desktop/dwm/customframe -[[nodiscard]] LRESULT NonClientIslandWindow::HitTestNCA(POINT ptMouse) const noexcept +// NOTE[2]: Concerning `titlebarIsCaption` +// - We want HTNOWHERE as the return value for WM_NCHITTEST, so that we can get +// mouse presses in the titlebar area. If we return HTCAPTION there, we won't +// get any mouse WMs. However, when we're handling the mouse events, we need +// to know if the mouse was in that are or not, so we'll return HTCAPTION in +// that handler, to differentiate from the rest of the window. +[[nodiscard]] LRESULT NonClientIslandWindow::HitTestNCA(POINT ptMouse, const bool titlebarIsCaption) const noexcept { // Get the window rectangle. RECT rcWindow = BaseWindow::GetWindowRect(); @@ -311,10 +319,11 @@ void NonClientIslandWindow::_UpdateDragRegion() // clang-format off // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) + const auto topHt = fOnResizeBorder ? HTTOP : (titlebarIsCaption ? HTCAPTION : HTNOWHERE); LRESULT hitTests[3][3] = { - { HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT }, - { HTLEFT, HTNOWHERE, HTRIGHT }, - { HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT }, + { HTTOPLEFT, topHt, HTTOPRIGHT }, + { HTLEFT, HTNOWHERE, HTRIGHT }, + { HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT }, }; // clang-format on @@ -511,8 +520,7 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges // Handle hit testing in the NCA if not handled by DwmDefWindowProc. if (lRet == 0) { - lRet = HitTestNCA({ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }); - + lRet = HitTestNCA({ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }, false); if (lRet != HTNOWHERE) { return lRet; @@ -594,9 +602,14 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges { POINT point1 = {}; ::GetCursorPos(&point1); - const auto region = HitTestNCA(point1); + + const auto region = HitTestNCA(point1, true); if (region == HTCAPTION) { + // If we clicked in the titlebar, raise an event so the app host can + // dispatch an appropriate event. + _DragRegionClickedHandlers(); + const auto longParam = MAKELPARAM(point1.x, point1.y); ::SetActiveWindow(_window.get()); ::PostMessage(_window.get(), WM_SYSCOMMAND, SC_MOVE | HTCAPTION, longParam); @@ -798,3 +811,5 @@ bool NonClientIslandWindow::_HandleWindowPosChanging(WINDOWPOS* const windowPos) } return true; } + +DEFINE_EVENT(NonClientIslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index 6949b5c64a8..08d3869fd00 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -23,6 +23,7 @@ Author(s): #include #include #include +#include "../../cascadia/inc/cppwinrt_utils.h" class NonClientIslandWindow : public IslandWindow { @@ -42,6 +43,8 @@ class NonClientIslandWindow : public IslandWindow void SetContent(winrt::Windows::UI::Xaml::UIElement content) override; void SetTitlebarContent(winrt::Windows::UI::Xaml::UIElement content); + DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>); + private: winrt::TerminalApp::TitlebarControl _titlebar{ nullptr }; winrt::Windows::UI::Xaml::UIElement _clientContent{ nullptr }; @@ -55,7 +58,7 @@ class NonClientIslandWindow : public IslandWindow RECT GetDragAreaRect() const noexcept; - [[nodiscard]] LRESULT HitTestNCA(POINT ptMouse) const noexcept; + [[nodiscard]] LRESULT HitTestNCA(POINT ptMouse, const bool titlebarIsCaption) const noexcept; [[nodiscard]] HRESULT _UpdateFrameMargins() const noexcept;