Skip to content

Commit

Permalink
When the titlebar is clicked, dismiss the new tab flyout
Browse files Browse the repository at this point in the history
  Fixes #2028.
  • Loading branch information
zadjii-msft committed Aug 15, 2019
1 parent d149177 commit 29e0c5d
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 9 deletions.
17 changes: 17 additions & 0 deletions src/cascadia/TerminalApp/App.cpp
Expand Up @@ -1649,6 +1649,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:
// - <none>
// Return Value:
// - <none>
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.
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/App.h
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/App.idl
Expand Up @@ -30,5 +30,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;

String GetTitle();

void TitlebarClicked();
}
}
5 changes: 5 additions & 0 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Expand Up @@ -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<NonClientIslandWindow*>(_window.get());
pNcWindow->DragRegionClicked([this]() { _app.TitlebarClicked(); });
}
_app.RequestedThemeChanged({ this, &AppHost::_UpdateTheme });

Expand Down
31 changes: 23 additions & 8 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp
Expand Up @@ -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();
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -798,3 +811,5 @@ bool NonClientIslandWindow::_HandleWindowPosChanging(WINDOWPOS* const windowPos)
}
return true;
}

DEFINE_EVENT(NonClientIslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
5 changes: 4 additions & 1 deletion src/cascadia/WindowsTerminal/NonClientIslandWindow.h
Expand Up @@ -23,6 +23,7 @@ Author(s):
#include <dwmapi.h>
#include <windowsx.h>
#include <wil\resource.h>
#include "../../cascadia/inc/cppwinrt_utils.h"

class NonClientIslandWindow : public IslandWindow
{
Expand All @@ -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 };
Expand All @@ -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;

Expand Down

0 comments on commit 29e0c5d

Please sign in to comment.