From 04145d4fe01492590045690d4c861bc869e387bc Mon Sep 17 00:00:00 2001 From: Chris Swan Date: Fri, 3 Sep 2021 10:29:54 -0700 Subject: [PATCH 01/26] seems to work okay --- src/cascadia/TerminalApp/TitlebarControl.cpp | 10 ++ src/cascadia/TerminalApp/TitlebarControl.h | 3 + src/cascadia/TerminalApp/TitlebarControl.idl | 2 + .../WindowsTerminal/NonClientIslandWindow.cpp | 106 +++++++++++------- 4 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index 05806726c..14fcdb898 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -24,6 +24,16 @@ namespace winrt::TerminalApp::implementation MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click }); } + void TitlebarControl::MaxButtonEntered() + { + MinMaxCloseControl().Opacity(.5); + } + + void TitlebarControl::MaxButtonExited() + { + MinMaxCloseControl().Opacity(1.0); + } + IInspectable TitlebarControl::Content() { return ContentRoot().Content(); diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index a30f347d8..342b59c2c 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -17,6 +17,9 @@ namespace winrt::TerminalApp::implementation { TitlebarControl(uint64_t handle); + void MaxButtonEntered(); + void MaxButtonExited(); + IInspectable Content(); void Content(IInspectable content); diff --git a/src/cascadia/TerminalApp/TitlebarControl.idl b/src/cascadia/TerminalApp/TitlebarControl.idl index 104f7a2f2..6b9892a42 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.idl +++ b/src/cascadia/TerminalApp/TitlebarControl.idl @@ -14,6 +14,8 @@ namespace TerminalApp { TitlebarControl(UInt64 parentWindowHandle); void SetWindowVisualState(WindowVisualState visualState); + void MaxButtonEntered(); + void MaxButtonExited(); IInspectable Content; Windows.UI.Xaml.Controls.Border DragBar { get; }; diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 9b9cbd468..66b733ddf 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -91,47 +91,75 @@ void NonClientIslandWindow::MakeWindow() noexcept // - The window procedure for the drag bar forwards clicks on its client area to its parent as non-client clicks. LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { - std::optional nonClientMessage{ std::nullopt }; - - // translate WM_ messages on the window to WM_NC* on the top level window switch (message) { - case WM_LBUTTONDOWN: - nonClientMessage = WM_NCLBUTTONDOWN; - break; - case WM_LBUTTONDBLCLK: - nonClientMessage = WM_NCLBUTTONDBLCLK; - break; - case WM_LBUTTONUP: - nonClientMessage = WM_NCLBUTTONUP; - break; - case WM_RBUTTONDOWN: - nonClientMessage = WM_NCRBUTTONDOWN; - break; - case WM_RBUTTONDBLCLK: - nonClientMessage = WM_NCRBUTTONDBLCLK; - break; - case WM_RBUTTONUP: - nonClientMessage = WM_NCRBUTTONUP; - break; - } - - if (nonClientMessage.has_value()) + case WM_NCHITTEST: { - const POINT clientPt{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; - POINT screenPt{ clientPt }; - if (ClientToScreen(_dragBarWindow.get(), &screenPt)) + RECT rcParent = GetWindowRect(); + // Consider the entire caption control area (rough estimate) to be the maximize button + // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, + // I just didn't duplicate it here. + if ((rcParent.right - GET_X_LPARAM(lparam)) < 130) { - auto parentWindow{ GetHandle() }; - - const LPARAM newLparam = MAKELPARAM(screenPt.x, screenPt.y); - // Hit test the parent window at the screen coordinates the user clicked in the drag input sink window, - // then pass that click through as an NC click in that location. - const LRESULT hitTest{ SendMessage(parentWindow, WM_NCHITTEST, 0, newLparam) }; - SendMessage(parentWindow, nonClientMessage.value(), hitTest, newLparam); - - return 0; + return HTMAXBUTTON; } + else + { + RECT rcWindow; + winrt::check_bool(::GetWindowRect(_window.get(), &rcWindow)); + + const auto resizeBorderHeight = _GetResizeHandleHeight(); + const auto isOnResizeBorder = GET_Y_LPARAM(lparam) < rcWindow.top + resizeBorderHeight; + + return isOnResizeBorder ? HTTOP : HTCAPTION; + } + } + break; + + case WM_NCMOUSEMOVE: + // Communicate state to the title bar control so that it can update its visuals. + if (wparam == HTMAXBUTTON) + { + _titlebar.MaxButtonEntered(); + } + else + { + _titlebar.MaxButtonExited(); + } + break; + + case WM_NCMOUSELEAVE: + case WM_MOUSELEAVE: + _titlebar.MaxButtonExited(); + break; + + // NB: *Shouldn't be forwarding these* when they're not over the caption because they can inadvertently take action using the system's default metrics instead of our own. + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONUP: + switch (wparam) + { + case HTCAPTION: + { + // Pass caption-related nonclient messages to the parent window. + // The buttons won't work as you'd expect; we need to handle those ourselves. + auto parentWindow{ GetHandle() }; + return SendMessage(parentWindow, message, wparam, lparam); + } + break; + + case HTMAXBUTTON: + case HTMINBUTTON: + case HTCLOSE: + // Forward along to the button state machine. + // As a proof of concept just locally handle the maximize button. + if ((wparam == HTMAXBUTTON) && (message == WM_NCLBUTTONUP)) + { + ShowWindow(GetHandle(), SW_MAXIMIZE); + } + break; + } + return 0; } return DefWindowProc(_dragBarWindow.get(), message, wparam, lparam); @@ -152,7 +180,7 @@ void NonClientIslandWindow::_ResizeDragBarWindow() noexcept rect.width(), rect.height(), SWP_NOACTIVATE | SWP_SHOWWINDOW); - SetLayeredWindowAttributes(_dragBarWindow.get(), 0, 255, LWA_ALPHA); + SetLayeredWindowAttributes(_dragBarWindow.get(), 0 /*RGB(100, 20, 20)*/, 255, LWA_ALPHA); } else { @@ -282,14 +310,14 @@ RECT NonClientIslandWindow::_GetDragAreaRect() const noexcept const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{ 0.0f, 0.0f, - static_cast(_dragBar.ActualWidth()), + static_cast(/*_dragBar*/_rootGrid.ActualWidth()), static_cast(_dragBar.ActualHeight()) }; const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect); RECT dragBarRect = { static_cast(clientDragBarRect.X * scale), static_cast(clientDragBarRect.Y * scale), - static_cast((clientDragBarRect.Width + clientDragBarRect.X) * scale), + static_cast((clientDragBarRect.Width + clientDragBarRect.X + 300) * scale), static_cast((clientDragBarRect.Height + clientDragBarRect.Y) * scale), }; return dragBarRect; From 6c9b3990480d96469b08b741fc36ac8b5c6d93a2 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 09:11:55 -0500 Subject: [PATCH 02/26] some cleanup. Try only hovering the actually hovered button --- .../TerminalApp/MinMaxCloseControl.cpp | 58 ++++++++++++++++- src/cascadia/TerminalApp/MinMaxCloseControl.h | 4 ++ .../TerminalApp/MinMaxCloseControl.idl | 4 ++ src/cascadia/TerminalApp/TitlebarControl.cpp | 14 ++++ src/cascadia/TerminalApp/TitlebarControl.h | 6 +- src/cascadia/TerminalApp/TitlebarControl.idl | 11 ++++ .../WindowsTerminal/NonClientIslandWindow.cpp | 64 +++++++++++++------ .../WindowsTerminal/NonClientIslandWindow.h | 1 + 8 files changed, 137 insertions(+), 25 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 0072b2093..b20868a8f 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // // MinMaxCloseControl.xaml.cpp @@ -95,4 +95,60 @@ namespace winrt::TerminalApp::implementation break; } } + + void MinMaxCloseControl::HoverButton(CaptionButton button) + { + switch (button) + { + case CaptionButton::Minimize: + VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Maximize: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Close: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); + break; + } + } + void MinMaxCloseControl::PressButton(CaptionButton button) + { + switch (button) + { + case CaptionButton::Minimize: + VisualStateManager::GoToState(MinimizeButton(), L"Pressed", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Maximize: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Pressed", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Close: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Pressed", false); + break; + } + } + void MinMaxCloseControl::ReleaseButton(CaptionButton button) + { + switch (button) + { + case CaptionButton::Minimize: + case CaptionButton::Maximize: + case CaptionButton::Close: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + } + } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index 0a8d66654..ab8e34c76 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -20,6 +20,10 @@ namespace winrt::TerminalApp::implementation void SetWindowVisualState(WindowVisualState visualState); + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); + void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender, diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.idl b/src/cascadia/TerminalApp/MinMaxCloseControl.idl index eb8fbd16e..91356743b 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.idl +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.idl @@ -11,6 +11,10 @@ namespace TerminalApp void SetWindowVisualState(WindowVisualState visualState); + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); + event Windows.Foundation.TypedEventHandler MinimizeClick; event Windows.Foundation.TypedEventHandler MaximizeClick; event Windows.Foundation.TypedEventHandler CloseClick; diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index 14fcdb898..61ceeae4a 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -103,4 +103,18 @@ namespace winrt::TerminalApp::implementation { MinMaxCloseControl().SetWindowVisualState(visualState); } + + void TitlebarControl::HoverButton(CaptionButton button) + { + MinMaxCloseControl().HoverButton(button); + } + void TitlebarControl::PressButton(CaptionButton button) + { + MinMaxCloseControl().PressButton(button); + } + void TitlebarControl::ReleaseButton(CaptionButton button) + { + MinMaxCloseControl().ReleaseButton(button); + } + } diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index 342b59c2c..6695e7471 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -6,9 +6,6 @@ #pragma once -#include "winrt/Windows.UI.Xaml.h" -#include "winrt/Windows.UI.Xaml.Markup.h" -#include "winrt/Windows.UI.Xaml.Interop.h" #include "TitlebarControl.g.h" namespace winrt::TerminalApp::implementation @@ -19,6 +16,9 @@ namespace winrt::TerminalApp::implementation void MaxButtonEntered(); void MaxButtonExited(); + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); IInspectable Content(); void Content(IInspectable content); diff --git a/src/cascadia/TerminalApp/TitlebarControl.idl b/src/cascadia/TerminalApp/TitlebarControl.idl index 6b9892a42..515055fcb 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.idl +++ b/src/cascadia/TerminalApp/TitlebarControl.idl @@ -10,10 +10,21 @@ namespace TerminalApp WindowVisualStateIconified }; + enum CaptionButton { + Minimize, + Maximize, + Close + }; + [default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid { TitlebarControl(UInt64 parentWindowHandle); void SetWindowVisualState(WindowVisualState visualState); + + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); + void MaxButtonEntered(); void MaxButtonExited(); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 86b70973f..b98ea3840 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -87,6 +87,30 @@ void NonClientIslandWindow::MakeWindow() noexcept THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow); } +LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) +{ + RECT rcParent = GetWindowRect(); + // Consider the entire caption control area (rough estimate) to be the maximize button + // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, + // I just didn't duplicate it here. + // TODO! this 130 shouldn't be hardcoded + // TODO! other buttons too + if ((rcParent.right - pointer.x()) < 130) + { + return HTMAXBUTTON; + } + else + { + // If we're not on a caption button, then check if we're on the top + // border. If we're not on the top border, then we're just generally in + // the caption area. + const auto resizeBorderHeight = _GetResizeHandleHeight(); + const auto isOnResizeBorder = pointer.y() < rcParent.top + resizeBorderHeight; + + return isOnResizeBorder ? HTTOP : HTCAPTION; + } +} + // Function Description: // - The window procedure for the drag bar forwards clicks on its client area to its parent as non-client clicks. LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept @@ -95,47 +119,44 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR { case WM_NCHITTEST: { - RECT rcParent = GetWindowRect(); - // Consider the entire caption control area (rough estimate) to be the maximize button - // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, - // I just didn't duplicate it here. - if ((rcParent.right - GET_X_LPARAM(lparam)) < 130) - { - return HTMAXBUTTON; - } - else - { - RECT rcWindow; - winrt::check_bool(::GetWindowRect(_window.get(), &rcWindow)); + til::point pointer{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; - const auto resizeBorderHeight = _GetResizeHandleHeight(); - const auto isOnResizeBorder = GET_Y_LPARAM(lparam) < rcWindow.top + resizeBorderHeight; - - return isOnResizeBorder ? HTTOP : HTCAPTION; - } + return _dragBarNcHitTest(pointer); } break; case WM_NCMOUSEMOVE: // Communicate state to the title bar control so that it can update its visuals. + // TODO! other buttons too if (wparam == HTMAXBUTTON) { - _titlebar.MaxButtonEntered(); + _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); + // _titlebar.MaxButtonEntered(); } else { - _titlebar.MaxButtonExited(); + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + // _titlebar.MaxButtonExited(); } break; case WM_NCMOUSELEAVE: case WM_MOUSELEAVE: - _titlebar.MaxButtonExited(); + // _titlebar.MaxButtonExited(); + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); break; // NB: *Shouldn't be forwarding these* when they're not over the caption because they can inadvertently take action using the system's default metrics instead of our own. case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDBLCLK: + switch (wparam) + { + case HTMAXBUTTON: + _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Maximize); + break; + } + return 0; + // TODO!: I think we only want WM_NCLBUTTONUP case WM_NCLBUTTONUP: switch (wparam) { @@ -153,6 +174,7 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR case HTCLOSE: // Forward along to the button state machine. // As a proof of concept just locally handle the maximize button. + // TODO! if ((wparam == HTMAXBUTTON) && (message == WM_NCLBUTTONUP)) { ShowWindow(GetHandle(), SW_MAXIMIZE); @@ -310,7 +332,7 @@ RECT NonClientIslandWindow::_GetDragAreaRect() const noexcept const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{ 0.0f, 0.0f, - static_cast(/*_dragBar*/_rootGrid.ActualWidth()), + static_cast(/*_dragBar*/ _rootGrid.ActualWidth()), static_cast(_dragBar.ActualHeight()) }; const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index cae2bc0da..ac8e7f29c 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -71,6 +71,7 @@ private: int _GetResizeHandleHeight() const noexcept; RECT _GetDragAreaRect() const noexcept; int _GetTopBorderHeight() const noexcept; + LRESULT _dragBarNcHitTest(const til::point& pointer); [[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override; [[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept; From 487edb90719b0d06e2e501753916811d37837b2a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 09:40:34 -0500 Subject: [PATCH 03/26] this is surprisingly close. Doesn't handle the mouse-exit-from-window case, but otherwize :primo: --- .../WindowsTerminal/NonClientIslandWindow.cpp | 90 +++++++++++++++---- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index b98ea3840..ea286025a 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -95,10 +95,20 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) // I just didn't duplicate it here. // TODO! this 130 shouldn't be hardcoded // TODO! other buttons too - if ((rcParent.right - pointer.x()) < 130) + // TODO! Account for DPI scaling + // TODO! ask the titlebar for caption button size? + if ((rcParent.right - pointer.x()) < 46) + { + return HTCLOSE; + } + else if ((rcParent.right - pointer.x()) < (46 * 2)) { return HTMAXBUTTON; } + else if ((rcParent.right - pointer.x()) < (46 * 3)) + { + return HTMINBUTTON; + } else { // If we're not on a caption button, then check if we're on the top @@ -128,22 +138,46 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR case WM_NCMOUSEMOVE: // Communicate state to the title bar control so that it can update its visuals. // TODO! other buttons too - if (wparam == HTMAXBUTTON) + + switch (wparam) { + case HTMINBUTTON: + _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Minimize); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + break; + case HTMAXBUTTON: + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); - // _titlebar.MaxButtonEntered(); - } - else - { - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); - // _titlebar.MaxButtonExited(); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + break; + case HTCLOSE: + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Close); + break; + default: + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); } + + // if (wparam == HTMAXBUTTON) + // { + // _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); + // // _titlebar.MaxButtonEntered(); + // } + // else + // { + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + // // _titlebar.MaxButtonExited(); + // } break; case WM_NCMOUSELEAVE: case WM_MOUSELEAVE: // _titlebar.MaxButtonExited(); - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); break; // NB: *Shouldn't be forwarding these* when they're not over the caption because they can inadvertently take action using the system's default metrics instead of our own. @@ -151,9 +185,22 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR case WM_NCLBUTTONDBLCLK: switch (wparam) { + case HTCAPTION: + { + // Pass caption-related nonclient messages to the parent window. + // The buttons won't work as you'd expect; we need to handle those ourselves. + auto parentWindow{ GetHandle() }; + return SendMessage(parentWindow, message, wparam, lparam); + } + case HTMINBUTTON: + _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Minimize); + break; case HTMAXBUTTON: _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Maximize); break; + case HTCLOSE: + _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Close); + break; } return 0; // TODO!: I think we only want WM_NCLBUTTONUP @@ -169,16 +216,25 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR } break; - case HTMAXBUTTON: + // Forward along to the button state machine. + // As a proof of concept just locally handle the maximize button. + // TODO! case HTMINBUTTON: + // TODO! if we're maximized, restore down! + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); + ShowWindow(GetHandle(), SW_MINIMIZE); + break; + + case HTMAXBUTTON: + // TODO! if we're maximized, restore down! + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + ShowWindow(GetHandle(), SW_MAXIMIZE); + break; + case HTCLOSE: - // Forward along to the button state machine. - // As a proof of concept just locally handle the maximize button. - // TODO! - if ((wparam == HTMAXBUTTON) && (message == WM_NCLBUTTONUP)) - { - ShowWindow(GetHandle(), SW_MAXIMIZE); - } + // TODO! if we're maximized, restore down! + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + Close(); break; } return 0; From be38330ddf102b212750511e19b111e732280669 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 10:47:07 -0500 Subject: [PATCH 04/26] Do the maximize/restore thing --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index ea286025a..c808e7276 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -129,7 +129,7 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR { case WM_NCHITTEST: { - til::point pointer{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + const til::point pointer{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; return _dragBarNcHitTest(pointer); } @@ -218,21 +218,19 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR // Forward along to the button state machine. // As a proof of concept just locally handle the maximize button. - // TODO! case HTMINBUTTON: - // TODO! if we're maximized, restore down! _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); ShowWindow(GetHandle(), SW_MINIMIZE); break; case HTMAXBUTTON: - // TODO! if we're maximized, restore down! _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); - ShowWindow(GetHandle(), SW_MAXIMIZE); + // If we're maximized, restore down. Otherwise, maximize + ShowWindow(GetHandle(), IsZoomed(GetHandle()) ? SW_RESTORE : SW_MAXIMIZE); break; case HTCLOSE: - // TODO! if we're maximized, restore down! + // TODO! this seems to crash unreasonably frequently _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); Close(); break; From 939177bdabdcc8c6e98da85ef28c9238e105ae11 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 10:48:12 -0500 Subject: [PATCH 05/26] This is closer to releasing the buttons when we're not over them, but moving the mouse fast still leaves them hovered. --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index c808e7276..5fd0852b5 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -654,6 +654,9 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept // we didn't change them. LPARAM lParam = MAKELONG(ptMouse.x, ptMouse.y); const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam); + + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + if (originalRet != HTCLIENT) { // If we're the quake window, suppress resizing on any side except the From d32fac4d3f2def1fbd7740c33454b4f8c5343301 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 11:02:07 -0500 Subject: [PATCH 06/26] Same deal, this didn't work either --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 5fd0852b5..1707b0470 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -655,7 +655,7 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept LPARAM lParam = MAKELONG(ptMouse.x, ptMouse.y); const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam); - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); if (originalRet != HTCLIENT) { @@ -867,6 +867,10 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept return _OnNcHitTest({ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }); case WM_PAINT: return _OnPaint(); + case WM_NCMOUSELEAVE: + case WM_MOUSELEAVE: + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + break; case WM_NCRBUTTONUP: // The `DefWindowProc` function doesn't open the system menu for some // reason so we have to do it ourselves. From deb494f6ef77b86ca328c2250bed62e666385552 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 11:28:21 -0500 Subject: [PATCH 07/26] weird, TME_LEAVE | TME_NONCLIENT was actually vital to doing this right. Just TME_LEAVE did not work, it would send the leave when really it should have been sending hovers --- .../WindowsTerminal/NonClientIslandWindow.cpp | 22 +++++++++++++++---- .../WindowsTerminal/NonClientIslandWindow.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 1707b0470..3f92e68c1 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -160,6 +160,19 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); } + if (!_trackingMouse && (wparam == HTMINBUTTON || + wparam == HTMAXBUTTON || + wparam == HTCLOSE)) + { + _trackingMouse = true; + TRACKMOUSEEVENT ev{}; + ev.cbSize = sizeof(TRACKMOUSEEVENT); + ev.dwFlags = TME_LEAVE | TME_NONCLIENT; + ev.hwndTrack = _dragBarWindow.get(); + ev.dwHoverTime = HOVER_DEFAULT; // we don't _really_ care about this. + LOG_IF_WIN32_BOOL_FALSE(TrackMouseEvent(&ev)); + } + // if (wparam == HTMAXBUTTON) // { // _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); @@ -178,6 +191,7 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + _trackingMouse = false; break; // NB: *Shouldn't be forwarding these* when they're not over the caption because they can inadvertently take action using the system's default metrics instead of our own. @@ -867,10 +881,10 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept return _OnNcHitTest({ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }); case WM_PAINT: return _OnPaint(); - case WM_NCMOUSELEAVE: - case WM_MOUSELEAVE: - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); - break; + // case WM_NCMOUSELEAVE: + // case WM_MOUSELEAVE: + // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + // break; case WM_NCRBUTTONUP: // The `DefWindowProc` function doesn't open the system menu for some // reason so we have to do it ourselves. diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index ac8e7f29c..879da45f6 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -62,6 +62,7 @@ private: winrt::Windows::UI::Xaml::ElementTheme _theme; bool _isMaximized; + bool _trackingMouse{ false }; [[nodiscard]] static LRESULT __stdcall _StaticInputSinkWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; [[nodiscard]] LRESULT _InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; From 0ef867319dc29c970402db86bf34abd11d0f57d2 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 12:12:38 -0500 Subject: [PATCH 08/26] tons of cleanup --- .../TerminalApp/MinMaxCloseControl.cpp | 15 +-- src/cascadia/TerminalApp/MinMaxCloseControl.h | 2 +- .../TerminalApp/MinMaxCloseControl.idl | 2 +- src/cascadia/TerminalApp/TitlebarControl.cpp | 29 +++-- src/cascadia/TerminalApp/TitlebarControl.h | 5 +- src/cascadia/TerminalApp/TitlebarControl.idl | 12 +- .../WindowsTerminal/NonClientIslandWindow.cpp | 109 +++++++++++------- 7 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index b20868a8f..e1a315ad1 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -138,17 +138,10 @@ namespace winrt::TerminalApp::implementation break; } } - void MinMaxCloseControl::ReleaseButton(CaptionButton button) + void MinMaxCloseControl::ReleaseButtons() { - switch (button) - { - case CaptionButton::Minimize: - case CaptionButton::Maximize: - case CaptionButton::Close: - VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); - VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); - VisualStateManager::GoToState(CloseButton(), L"Normal", false); - break; - } + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index ab8e34c76..e69616038 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -22,7 +22,7 @@ namespace winrt::TerminalApp::implementation void HoverButton(CaptionButton button); void PressButton(CaptionButton button); - void ReleaseButton(CaptionButton button); + void ReleaseButtons(); void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.idl b/src/cascadia/TerminalApp/MinMaxCloseControl.idl index 91356743b..61600fe27 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.idl +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.idl @@ -13,7 +13,7 @@ namespace TerminalApp void HoverButton(CaptionButton button); void PressButton(CaptionButton button); - void ReleaseButton(CaptionButton button); + void ReleaseButtons(); event Windows.Foundation.TypedEventHandler MinimizeClick; event Windows.Foundation.TypedEventHandler MaximizeClick; diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index 61ceeae4a..d786c7f47 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -24,16 +24,6 @@ namespace winrt::TerminalApp::implementation MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click }); } - void TitlebarControl::MaxButtonEntered() - { - MinMaxCloseControl().Opacity(.5); - } - - void TitlebarControl::MaxButtonExited() - { - MinMaxCloseControl().Opacity(1.0); - } - IInspectable TitlebarControl::Content() { return ContentRoot().Content(); @@ -112,9 +102,24 @@ namespace winrt::TerminalApp::implementation { MinMaxCloseControl().PressButton(button); } - void TitlebarControl::ReleaseButton(CaptionButton button) + void TitlebarControl::ClickButton(CaptionButton button) { - MinMaxCloseControl().ReleaseButton(button); + switch (button) + { + case CaptionButton::Minimize: + Minimize_Click(nullptr, nullptr); + break; + case CaptionButton::Maximize: + Maximize_Click(nullptr, nullptr); + break; + case CaptionButton::Close: + Close_Click(nullptr, nullptr); + break; + } + } + void TitlebarControl::ReleaseButtons() + { + MinMaxCloseControl().ReleaseButtons(); } } diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index 6695e7471..23795a4d3 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -14,11 +14,10 @@ namespace winrt::TerminalApp::implementation { TitlebarControl(uint64_t handle); - void MaxButtonEntered(); - void MaxButtonExited(); void HoverButton(CaptionButton button); void PressButton(CaptionButton button); - void ReleaseButton(CaptionButton button); + void ClickButton(CaptionButton button); + void ReleaseButtons(); IInspectable Content(); void Content(IInspectable content); diff --git a/src/cascadia/TerminalApp/TitlebarControl.idl b/src/cascadia/TerminalApp/TitlebarControl.idl index 515055fcb..21e82eb87 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.idl +++ b/src/cascadia/TerminalApp/TitlebarControl.idl @@ -11,9 +11,9 @@ namespace TerminalApp }; enum CaptionButton { - Minimize, - Maximize, - Close + Minimize = 8, // HTMINBUTTON + Maximize = 9, // HTMAXBUTTON + Close = 20 // HTCLOSE }; [default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid @@ -23,10 +23,8 @@ namespace TerminalApp void HoverButton(CaptionButton button); void PressButton(CaptionButton button); - void ReleaseButton(CaptionButton button); - - void MaxButtonEntered(); - void MaxButtonExited(); + void ClickButton(CaptionButton button); + void ReleaseButtons(); IInspectable Content; Windows.UI.Xaml.Controls.Border DragBar { get; }; diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 3f92e68c1..35091a675 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -122,90 +122,107 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) } // Function Description: -// - The window procedure for the drag bar forwards clicks on its client area to its parent as non-client clicks. +// - The window procedure for the drag bar forwards clicks on its client area to +// its parent as non-client clicks. +// - BODGY: It also _manually_ handles the caption buttons. They exist in the +// titlebar, and work reasonably well with just XAML, if the drag bar isn't +// covering them. +// - However, to get snap layout support (GH#9443), we need to actually return +// HTMAXBUTTON where the maximize button is. If the drag bar doesn't cover the +// caption buttons, then the core input site (which takes up the entirety of +// the XAML island) will steal the WM_NCHITTEST before we get a chance to +// handle it. +// - So, the drag bar covers the caption buttons, and manually handles hovering +// and pressing them when needed. This gives the impression that they're +// getting input as they normally would, even if they're not _really_ getting +// input via XAML. LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { switch (message) { case WM_NCHITTEST: { - const til::point pointer{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; - - return _dragBarNcHitTest(pointer); + // Try to determine what part of the window is being hovered here. This + // is absolutely critical to making sure Snap Layouts (GH#9443) works! + return _dragBarNcHitTest(til::point{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }); } break; case WM_NCMOUSEMOVE: - // Communicate state to the title bar control so that it can update its visuals. - // TODO! other buttons too - + // When we get this message, it's because the mouse moved when it was + // over somewhere we said was the non-client area. + // + // We'll use this to communicate state to the title bar control, so that + // it can update its visuals. + // - If we're over a button, hover it. + // - If we're over _anything else_, stop hovering the buttons. switch (wparam) { case HTMINBUTTON: _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Minimize); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); break; case HTMAXBUTTON: - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); break; case HTCLOSE: - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Close); break; default: - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + _titlebar.ReleaseButtons(); } - if (!_trackingMouse && (wparam == HTMINBUTTON || - wparam == HTMAXBUTTON || - wparam == HTCLOSE)) + // If we haven't previously asked for mouse tracking, request mouse + // tracking. We need to do this so we can get the WM_NCMOUSELEAVE + // message when the mouse leave the titlebar. Otherwise, we won't always + // get that message (especially if the user moves the mouse _real + // fast_). + if (!_trackingMouse && + (wparam == HTMINBUTTON || wparam == HTMAXBUTTON || wparam == HTCLOSE)) { - _trackingMouse = true; TRACKMOUSEEVENT ev{}; ev.cbSize = sizeof(TRACKMOUSEEVENT); + // TME_NONCLIENT is absolutely critical here. In my experimentation, + // we'd get WM_MOUSELEAVE messages after just a HOVER_DEFAULT + // timeout even though we're not requesting TME_HOVER, which kinda + // ruined the whole point of this. ev.dwFlags = TME_LEAVE | TME_NONCLIENT; ev.hwndTrack = _dragBarWindow.get(); ev.dwHoverTime = HOVER_DEFAULT; // we don't _really_ care about this. LOG_IF_WIN32_BOOL_FALSE(TrackMouseEvent(&ev)); + _trackingMouse = true; } - - // if (wparam == HTMAXBUTTON) - // { - // _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); - // // _titlebar.MaxButtonEntered(); - // } - // else - // { - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); - // // _titlebar.MaxButtonExited(); - // } + // TODO! We no longer show tooltips for the caption buttons when they're + // hovered. That's not good. break; case WM_NCMOUSELEAVE: case WM_MOUSELEAVE: - // _titlebar.MaxButtonExited(); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); + // When the mouse leaves the drag rect, make sure to dismiss any hover. + _titlebar.ReleaseButtons(); _trackingMouse = false; break; - // NB: *Shouldn't be forwarding these* when they're not over the caption because they can inadvertently take action using the system's default metrics instead of our own. + // NB: *Shouldn't be forwarding these* when they're not over the caption + // because they can inadvertently take action using the system's default + // metrics instead of our own. case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDBLCLK: + // Manual handling for mouse clicks in the drag bar. If it's in a + // caption button, then tell the titlebar to "press" the button, which + // should change its visual state. + // + // If it's not in a caption button, then just forward the message along + // to the root HWND. switch (wparam) { case HTCAPTION: { // Pass caption-related nonclient messages to the parent window. - // The buttons won't work as you'd expect; we need to handle those ourselves. auto parentWindow{ GetHandle() }; return SendMessage(parentWindow, message, wparam, lparam); } + // The buttons won't work as you'd expect; we need to handle those + // ourselves. case HTMINBUTTON: _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Minimize); break; @@ -217,8 +234,13 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR break; } return 0; - // TODO!: I think we only want WM_NCLBUTTONUP + case WM_NCLBUTTONUP: + // Manual handling for mouse RELEASES in the drag bar. If it's in a + // caption button, then manually handle what we'd expect for that button. + // + // If it's not in a caption button, then just forward the message along + // to the root HWND. switch (wparam) { case HTCAPTION: @@ -233,20 +255,23 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR // Forward along to the button state machine. // As a proof of concept just locally handle the maximize button. case HTMINBUTTON: - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Minimize); - ShowWindow(GetHandle(), SW_MINIMIZE); + _titlebar.ClickButton(winrt::TerminalApp::CaptionButton::Minimize); + _titlebar.ReleaseButtons(); + // ShowWindow(GetHandle(), SW_MINIMIZE); break; case HTMAXBUTTON: - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + _titlebar.ClickButton(winrt::TerminalApp::CaptionButton::Maximize); + _titlebar.ReleaseButtons(); // If we're maximized, restore down. Otherwise, maximize - ShowWindow(GetHandle(), IsZoomed(GetHandle()) ? SW_RESTORE : SW_MAXIMIZE); + // ShowWindow(GetHandle(), IsZoomed(GetHandle()) ? SW_RESTORE : SW_MAXIMIZE); break; case HTCLOSE: // TODO! this seems to crash unreasonably frequently - _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); - Close(); + _titlebar.ClickButton(winrt::TerminalApp::CaptionButton::Close); + _titlebar.ReleaseButtons(); + // Close(); break; } return 0; From 1915a06f6e6a15faef045d0508c21dc124f40c79 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 12:47:57 -0500 Subject: [PATCH 09/26] fixes #8587 --- src/cascadia/TerminalApp/TitlebarControl.cpp | 33 +++++++++++++------- src/cascadia/TerminalApp/TitlebarControl.h | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index d786c7f47..a4e5264ea 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -102,19 +102,30 @@ namespace winrt::TerminalApp::implementation { MinMaxCloseControl().PressButton(button); } - void TitlebarControl::ClickButton(CaptionButton button) + winrt::fire_and_forget TitlebarControl::ClickButton(CaptionButton button) { - switch (button) + // GH#8587: Handle this on the _next_ pass of the UI thread. If we + // handle this immediately, then we'll accidentally leave the button in + // the "Hovered" state when we minimize. This will leave the button + // visibly hovered in the taskbar preview for our window. + auto weakThis{ get_weak() }; + co_await MinMaxCloseControl().Dispatcher(); + if (auto self{ weakThis.get() }) { - case CaptionButton::Minimize: - Minimize_Click(nullptr, nullptr); - break; - case CaptionButton::Maximize: - Maximize_Click(nullptr, nullptr); - break; - case CaptionButton::Close: - Close_Click(nullptr, nullptr); - break; + // Just handle this in the same way we would if the button were + // clicked normally. + switch (button) + { + case CaptionButton::Minimize: + Minimize_Click(nullptr, nullptr); + break; + case CaptionButton::Maximize: + Maximize_Click(nullptr, nullptr); + break; + case CaptionButton::Close: + Close_Click(nullptr, nullptr); + break; + } } } void TitlebarControl::ReleaseButtons() diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index 23795a4d3..1956b528d 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -16,7 +16,7 @@ namespace winrt::TerminalApp::implementation void HoverButton(CaptionButton button); void PressButton(CaptionButton button); - void ClickButton(CaptionButton button); + winrt::fire_and_forget ClickButton(CaptionButton button); void ReleaseButtons(); IInspectable Content(); From 94d6bfbf2dbc6f54c56636bbb32a34aa9762889f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 12:48:07 -0500 Subject: [PATCH 10/26] cleanup everywhere --- src/cascadia/TerminalApp/TitlebarControl.cpp | 7 ++- src/cascadia/TerminalApp/TitlebarControl.h | 3 -- src/cascadia/TerminalApp/TitlebarControl.idl | 2 + .../WindowsTerminal/NonClientIslandWindow.cpp | 46 ++++++------------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index a4e5264ea..0d5596c03 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -1,7 +1,6 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -// TitlebarControl.xaml.cpp // Implementation of the TitlebarControl class // @@ -94,6 +93,10 @@ namespace winrt::TerminalApp::implementation MinMaxCloseControl().SetWindowVisualState(visualState); } + // GH#9443: HoverButton, PressButton, ClickButton and ReleaseButtons are all + // used to manually interact with the buttons, in the same way that XAML + // would normally send events. + void TitlebarControl::HoverButton(CaptionButton button) { MinMaxCloseControl().HoverButton(button); diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index 1956b528d..31dc4d7d2 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -1,8 +1,5 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -// -// Declaration of the MainUserControl class. -// #pragma once diff --git a/src/cascadia/TerminalApp/TitlebarControl.idl b/src/cascadia/TerminalApp/TitlebarControl.idl index 21e82eb87..a781a2eba 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.idl +++ b/src/cascadia/TerminalApp/TitlebarControl.idl @@ -10,6 +10,8 @@ namespace TerminalApp WindowVisualStateIconified }; + // For simplicity, make sure that these are the same values as the ones used + // by messages like WM_NCHITTEST enum CaptionButton { Minimize = 8, // HTMINBUTTON Maximize = 9, // HTMAXBUTTON diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 35091a675..1b41e703e 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -93,8 +93,6 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) // Consider the entire caption control area (rough estimate) to be the maximize button // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, // I just didn't duplicate it here. - // TODO! this 130 shouldn't be hardcoded - // TODO! other buttons too // TODO! Account for DPI scaling // TODO! ask the titlebar for caption button size? if ((rcParent.right - pointer.x()) < 46) @@ -159,13 +157,9 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR switch (wparam) { case HTMINBUTTON: - _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Minimize); - break; case HTMAXBUTTON: - _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); - break; case HTCLOSE: - _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Close); + _titlebar.HoverButton(static_cast(wparam)); break; default: _titlebar.ReleaseButtons(); @@ -224,13 +218,9 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR // The buttons won't work as you'd expect; we need to handle those // ourselves. case HTMINBUTTON: - _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Minimize); - break; case HTMAXBUTTON: - _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Maximize); - break; case HTCLOSE: - _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Close); + _titlebar.PressButton(static_cast(wparam)); break; } return 0; @@ -252,26 +242,13 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR } break; - // Forward along to the button state machine. - // As a proof of concept just locally handle the maximize button. + // If we do find a button, then tell the titlebar to raise the same + // event that would be raised if it were "tapped" case HTMINBUTTON: - _titlebar.ClickButton(winrt::TerminalApp::CaptionButton::Minimize); - _titlebar.ReleaseButtons(); - // ShowWindow(GetHandle(), SW_MINIMIZE); - break; - case HTMAXBUTTON: - _titlebar.ClickButton(winrt::TerminalApp::CaptionButton::Maximize); - _titlebar.ReleaseButtons(); - // If we're maximized, restore down. Otherwise, maximize - // ShowWindow(GetHandle(), IsZoomed(GetHandle()) ? SW_RESTORE : SW_MAXIMIZE); - break; - case HTCLOSE: - // TODO! this seems to crash unreasonably frequently - _titlebar.ClickButton(winrt::TerminalApp::CaptionButton::Close); _titlebar.ReleaseButtons(); - // Close(); + _titlebar.ClickButton(static_cast(wparam)); break; } return 0; @@ -295,7 +272,7 @@ void NonClientIslandWindow::_ResizeDragBarWindow() noexcept rect.width(), rect.height(), SWP_NOACTIVATE | SWP_SHOWWINDOW); - SetLayeredWindowAttributes(_dragBarWindow.get(), 0 /*RGB(100, 20, 20)*/, 255, LWA_ALPHA); + SetLayeredWindowAttributes(_dragBarWindow.get(), 0, 255, LWA_ALPHA); } else { @@ -422,17 +399,24 @@ RECT NonClientIslandWindow::_GetDragAreaRect() const noexcept { const auto scale = GetCurrentDpiScale(); const auto transform = _dragBar.TransformToVisual(_rootGrid); + + // GH#9443: Previously, we'd only extend the drag bar from the left of + // the tabs to the right of the caption buttons. Now, we're extending it + // all the way to the right side of the window, covering the caption + // buttons. We'll manually handle input to those buttons, to make it + // seem like they're still getting XAML input. We do this so we can get + // snap layout support for the maximize button. const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{ 0.0f, 0.0f, - static_cast(/*_dragBar*/ _rootGrid.ActualWidth()), + static_cast(_rootGrid.ActualWidth()), static_cast(_dragBar.ActualHeight()) }; const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect); RECT dragBarRect = { static_cast(clientDragBarRect.X * scale), static_cast(clientDragBarRect.Y * scale), - static_cast((clientDragBarRect.Width + clientDragBarRect.X + 300) * scale), + static_cast((clientDragBarRect.Width + clientDragBarRect.X) * scale), static_cast((clientDragBarRect.Height + clientDragBarRect.Y) * scale), }; return dragBarRect; From a00e9edecc8cb655c9e89a61c427f99b921b754d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 13:05:06 -0500 Subject: [PATCH 11/26] remaining TODO!s other than the one tooltip one --- src/cascadia/TerminalApp/TitlebarControl.cpp | 6 ++++ src/cascadia/TerminalApp/TitlebarControl.h | 1 + src/cascadia/TerminalApp/TitlebarControl.idl | 1 + .../WindowsTerminal/NonClientIslandWindow.cpp | 33 ++++++++++--------- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index 0d5596c03..2f4c1ccb9 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -23,6 +23,12 @@ namespace winrt::TerminalApp::implementation MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click }); } + double TitlebarControl::CaptionButtonWidth() + { + static double width{ MinMaxCloseControl().ActualWidth() / 3.0 }; + return width; + } + IInspectable TitlebarControl::Content() { return ContentRoot().Content(); diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index 31dc4d7d2..02c1c37a9 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -15,6 +15,7 @@ namespace winrt::TerminalApp::implementation void PressButton(CaptionButton button); winrt::fire_and_forget ClickButton(CaptionButton button); void ReleaseButtons(); + double CaptionButtonWidth(); IInspectable Content(); void Content(IInspectable content); diff --git a/src/cascadia/TerminalApp/TitlebarControl.idl b/src/cascadia/TerminalApp/TitlebarControl.idl index a781a2eba..53e4be947 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.idl +++ b/src/cascadia/TerminalApp/TitlebarControl.idl @@ -27,6 +27,7 @@ namespace TerminalApp void PressButton(CaptionButton button); void ClickButton(CaptionButton button); void ReleaseButtons(); + Double CaptionButtonWidth { get; }; IInspectable Content; Windows.UI.Xaml.Controls.Border DragBar { get; }; diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 1b41e703e..3fcf13310 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -90,20 +90,27 @@ void NonClientIslandWindow::MakeWindow() noexcept LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) { RECT rcParent = GetWindowRect(); - // Consider the entire caption control area (rough estimate) to be the maximize button - // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, - // I just didn't duplicate it here. - // TODO! Account for DPI scaling - // TODO! ask the titlebar for caption button size? - if ((rcParent.right - pointer.x()) < 46) + // The size of the buttons doesn't change over the life of the application. + static const auto buttonWidthInDips{ _titlebar.CaptionButtonWidth() }; + + // However, the dPI scaling might, so get the updated size of the buttons in pixels + const auto buttonWidthInPixels{ buttonWidthInDips * GetCurrentDpiScale() }; + + // From the right to the left, + // * are we in the close button? + // * the maximize button? + // * the minimize button? + // If we're not, then we're in either the top resize border, or just + // generally in the titlebar. + if ((rcParent.right - pointer.x()) < (buttonWidthInPixels)) { return HTCLOSE; } - else if ((rcParent.right - pointer.x()) < (46 * 2)) + else if ((rcParent.right - pointer.x()) < (buttonWidthInPixels * 2)) { return HTMAXBUTTON; } - else if ((rcParent.right - pointer.x()) < (46 * 3)) + else if ((rcParent.right - pointer.x()) < (buttonWidthInPixels * 3)) { return HTMINBUTTON; } @@ -134,7 +141,9 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) // and pressing them when needed. This gives the impression that they're // getting input as they normally would, even if they're not _really_ getting // input via XAML. -LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept +LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { switch (message) { @@ -678,8 +687,6 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept LPARAM lParam = MAKELONG(ptMouse.x, ptMouse.y); const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam); - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); - if (originalRet != HTCLIENT) { // If we're the quake window, suppress resizing on any side except the @@ -890,10 +897,6 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept return _OnNcHitTest({ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }); case WM_PAINT: return _OnPaint(); - // case WM_NCMOUSELEAVE: - // case WM_MOUSELEAVE: - // _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Close); - // break; case WM_NCRBUTTONUP: // The `DefWindowProc` function doesn't open the system menu for some // reason so we have to do it ourselves. From 953620669d3325599dbe869fd2b7bb2cff31120e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 15:13:06 -0500 Subject: [PATCH 12/26] Prototype: get some tooltips back --- .../TerminalApp/MinMaxCloseControl.cpp | 30 +++++++++++++++++++ src/cascadia/TerminalApp/MinMaxCloseControl.h | 3 ++ .../TerminalApp/MinMaxCloseControl.idl | 5 +++- .../TerminalApp/MinMaxCloseControl.xaml | 16 ++++++++-- .../Resources/en-US/Resources.resw | 6 ++++ 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index e1a315ad1..e4976fb6c 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -20,6 +20,7 @@ namespace winrt::TerminalApp::implementation MinMaxCloseControl::MinMaxCloseControl() { InitializeComponent(); + _MinimizeToolTip = RS_(L"WindowMinimizeButtonToolTipText"); } // These event handlers simply forward each buttons click events up to the @@ -104,16 +105,45 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); + if (auto tt{ Controls::ToolTipService::GetToolTip(MinimizeButton()) }) + { + if (auto tooltip{ tt.try_as() }) + { + tooltip.IsOpen(true); + } + } + break; case CaptionButton::Maximize: VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); + if (auto tt{ Controls::ToolTipService::GetToolTip(MaximizeButton()) }) + { + if (auto tooltip{ tt.try_as() }) + { + tooltip.IsOpen(true); + } + } break; case CaptionButton::Close: VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); + if (auto tt{ Controls::ToolTipService::GetToolTip(CloseButton()) }) + { + if (auto tooltip{ tt.try_as() }) + { + tooltip.IsOpen(true); + } + else if (auto s{winrt::unbox_value(tt)}; !s.empty()) + { + s; + int a = 0; + a++; + a; + } + } break; } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index e69616038..9bcd81def 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -31,6 +31,9 @@ namespace winrt::TerminalApp::implementation void _CloseClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); + WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); + WINRT_OBSERVABLE_PROPERTY(winrt::hstring, MinimizeToolTip, _PropertyChangedHandlers); + TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.idl b/src/cascadia/TerminalApp/MinMaxCloseControl.idl index 61600fe27..06b481e4a 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.idl +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.idl @@ -5,7 +5,8 @@ import "TitlebarControl.idl"; namespace TerminalApp { - [default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel + [default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel, + Windows.UI.Xaml.Data.INotifyPropertyChanged { MinMaxCloseControl(); @@ -15,6 +16,8 @@ namespace TerminalApp void PressButton(CaptionButton button); void ReleaseButtons(); + String MinimizeToolTip { get; }; + event Windows.Foundation.TypedEventHandler MinimizeClick; event Windows.Foundation.TypedEventHandler MaximizeClick; event Windows.Foundation.TypedEventHandler CloseClick; diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.xaml b/src/cascadia/TerminalApp/MinMaxCloseControl.xaml index 105de2226..684831586 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.xaml +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.xaml @@ -220,7 +220,7 @@ diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 56bc3ed17..a2da0841e 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -411,6 +411,9 @@ Close + + Close + Maximize @@ -420,6 +423,9 @@ Minimize + + Minimize + About From 0fa10cd3ef71ce63c6095302e97e5fd0629ed6bf Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 15:15:43 -0500 Subject: [PATCH 13/26] Only one tooltip at a time please --- .../TerminalApp/MinMaxCloseControl.cpp | 55 +++++++++---------- src/cascadia/TerminalApp/MinMaxCloseControl.h | 3 - .../TerminalApp/MinMaxCloseControl.idl | 5 +- .../Resources/en-US/Resources.resw | 2 +- 4 files changed, 27 insertions(+), 38 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index e4976fb6c..73f7b1d76 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -20,7 +20,6 @@ namespace winrt::TerminalApp::implementation MinMaxCloseControl::MinMaxCloseControl() { InitializeComponent(); - _MinimizeToolTip = RS_(L"WindowMinimizeButtonToolTipText"); } // These event handlers simply forward each buttons click events up to the @@ -97,6 +96,17 @@ namespace winrt::TerminalApp::implementation } } + void _openToolTipForButton(const Controls::Button& button, const bool isOpen) + { + if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) + { + if (auto tooltip{ tt.try_as() }) + { + tooltip.IsOpen(isOpen); + } + } + } + void MinMaxCloseControl::HoverButton(CaptionButton button) { switch (button) @@ -105,48 +115,29 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - if (auto tt{ Controls::ToolTipService::GetToolTip(MinimizeButton()) }) - { - if (auto tooltip{ tt.try_as() }) - { - tooltip.IsOpen(true); - } - } - + _openToolTipForButton(MinimizeButton(), true); + _openToolTipForButton(MaximizeButton(), false); + _openToolTipForButton(CloseButton(), false); break; case CaptionButton::Maximize: VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - if (auto tt{ Controls::ToolTipService::GetToolTip(MaximizeButton()) }) - { - if (auto tooltip{ tt.try_as() }) - { - tooltip.IsOpen(true); - } - } + _openToolTipForButton(MinimizeButton(), false); + _openToolTipForButton(MaximizeButton(), true); + _openToolTipForButton(CloseButton(), false); break; case CaptionButton::Close: VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); - if (auto tt{ Controls::ToolTipService::GetToolTip(CloseButton()) }) - { - if (auto tooltip{ tt.try_as() }) - { - tooltip.IsOpen(true); - } - else if (auto s{winrt::unbox_value(tt)}; !s.empty()) - { - s; - int a = 0; - a++; - a; - } - } + _openToolTipForButton(MinimizeButton(), false); + _openToolTipForButton(MaximizeButton(), false); + _openToolTipForButton(CloseButton(), true); break; } } + void MinMaxCloseControl::PressButton(CaptionButton button) { switch (button) @@ -168,10 +159,14 @@ namespace winrt::TerminalApp::implementation break; } } + void MinMaxCloseControl::ReleaseButtons() { VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); + _openToolTipForButton(MinimizeButton(), false); + _openToolTipForButton(MaximizeButton(), false); + _openToolTipForButton(CloseButton(), false); } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index 9bcd81def..e69616038 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -31,9 +31,6 @@ namespace winrt::TerminalApp::implementation void _CloseClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); - WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); - WINRT_OBSERVABLE_PROPERTY(winrt::hstring, MinimizeToolTip, _PropertyChangedHandlers); - TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.idl b/src/cascadia/TerminalApp/MinMaxCloseControl.idl index 06b481e4a..61600fe27 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.idl +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.idl @@ -5,8 +5,7 @@ import "TitlebarControl.idl"; namespace TerminalApp { - [default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel, - Windows.UI.Xaml.Data.INotifyPropertyChanged + [default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel { MinMaxCloseControl(); @@ -16,8 +15,6 @@ namespace TerminalApp void PressButton(CaptionButton button); void ReleaseButtons(); - String MinimizeToolTip { get; }; - event Windows.Foundation.TypedEventHandler MinimizeClick; event Windows.Foundation.TypedEventHandler MaximizeClick; event Windows.Foundation.TypedEventHandler CloseClick; diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index a2da0841e..294ffce58 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -423,7 +423,7 @@ Minimize - + Minimize From 21ba58ca29ffab4db1dfab13ed3ec187f4ba2465 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 15:34:31 -0500 Subject: [PATCH 14/26] Sorta adds a delay. A little janky --- .../TerminalApp/MinMaxCloseControl.cpp | 46 ++++++++++++++----- src/cascadia/TerminalApp/MinMaxCloseControl.h | 6 +-- src/cascadia/WinRTUtils/inc/ThrottledFunc.h | 9 ++++ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 73f7b1d76..6573a57b3 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -15,11 +15,40 @@ using namespace winrt::Windows::UI::Xaml; +// TODO! this should be a system constant +constexpr const auto ToolTipInterval = std::chrono::milliseconds(400); + namespace winrt::TerminalApp::implementation { + void _openToolTipForButton(const Controls::Button& button, const bool isOpen) + { + if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) + { + if (auto tooltip{ tt.try_as() }) + { + tooltip.IsOpen(isOpen); + } + } + } + MinMaxCloseControl::MinMaxCloseControl() { + // Get our dispatcher. This will get us the same dispatcher as + // Dispatcher(), but it's a DispatcherQueue, so we can use it with + // ThrottledFunc + auto dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); + InitializeComponent(); + + _displayMinimizeTooltip = std::make_shared>( + dispatcher, + ToolTipInterval, + [weakThis = get_weak()]() { + if (auto self{ weakThis.get() }) + { + _openToolTipForButton(self->MinimizeButton(), true); + } + }); } // These event handlers simply forward each buttons click events up to the @@ -96,17 +125,6 @@ namespace winrt::TerminalApp::implementation } } - void _openToolTipForButton(const Controls::Button& button, const bool isOpen) - { - if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) - { - if (auto tooltip{ tt.try_as() }) - { - tooltip.IsOpen(isOpen); - } - } - } - void MinMaxCloseControl::HoverButton(CaptionButton button) { switch (button) @@ -115,7 +133,8 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - _openToolTipForButton(MinimizeButton(), true); + // _openToolTipForButton(MinimizeButton(), true); + _displayMinimizeTooltip->Run(); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), false); break; @@ -124,6 +143,7 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); _openToolTipForButton(MinimizeButton(), false); + _displayMinimizeTooltip->Dismiss(); _openToolTipForButton(MaximizeButton(), true); _openToolTipForButton(CloseButton(), false); break; @@ -132,6 +152,7 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); _openToolTipForButton(MinimizeButton(), false); + _displayMinimizeTooltip->Dismiss(); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), true); break; @@ -166,6 +187,7 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); _openToolTipForButton(MinimizeButton(), false); + _displayMinimizeTooltip->Dismiss(); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), false); } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index e69616038..6dee1f624 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -6,11 +6,9 @@ #pragma once -#include "winrt/Windows.UI.Xaml.h" -#include "winrt/Windows.UI.Xaml.Markup.h" -#include "winrt/Windows.UI.Xaml.Interop.h" #include "MinMaxCloseControl.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" +#include namespace winrt::TerminalApp::implementation { @@ -34,6 +32,8 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); + + std::shared_ptr> _displayMinimizeTooltip{ nullptr }; }; } diff --git a/src/cascadia/WinRTUtils/inc/ThrottledFunc.h b/src/cascadia/WinRTUtils/inc/ThrottledFunc.h index 40482faf1..824d3a2bf 100644 --- a/src/cascadia/WinRTUtils/inc/ThrottledFunc.h +++ b/src/cascadia/WinRTUtils/inc/ThrottledFunc.h @@ -71,6 +71,15 @@ public: _storage.modify_pending(func); } + // This only really works for Trailing throttled funcs. + // + // Dismiss the currently pending callback, so it won't be called at the end + // of the timeout. + void Dismiss() + { + _storage.reset(); + } + private: static void __stdcall _timer_callback(PTP_CALLBACK_INSTANCE /*instance*/, PVOID context, PTP_TIMER /*timer*/) noexcept { From 01aa26c5220d3292933e4d5d84168fdac50de9c6 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 15:49:46 -0500 Subject: [PATCH 15/26] notes --- .../TerminalApp/MinMaxCloseControl.cpp | 26 ++++++++++++------- src/cascadia/WinRTUtils/inc/ThrottledFunc.h | 9 ------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 6573a57b3..0b7acc4ff 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -39,16 +39,22 @@ namespace winrt::TerminalApp::implementation auto dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); InitializeComponent(); - + auto createOpenToolTipFn = [weakThis = get_weak()](const Controls::Button& button) { + return [weakThis, button]() { + if (auto self{ weakThis.get() }) + { + _openToolTipForButton(button, true); + } + }; + }; _displayMinimizeTooltip = std::make_shared>( dispatcher, ToolTipInterval, - [weakThis = get_weak()]() { - if (auto self{ weakThis.get() }) - { - _openToolTipForButton(self->MinimizeButton(), true); - } - }); + createOpenToolTipFn(MinimizeButton())); + // TODO! I need to add a sentinel arg to this ThrottledFunc. With two + // values: Open, and Ignore. Open will open the tt, and Ignore will do + // nothing. WHere I'm dismissing below, instead, modifyPending(Ignore), + // so it does nothing on the next run. } // These event handlers simply forward each buttons click events up to the @@ -142,8 +148,8 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - _openToolTipForButton(MinimizeButton(), false); _displayMinimizeTooltip->Dismiss(); + _openToolTipForButton(MinimizeButton(), false); _openToolTipForButton(MaximizeButton(), true); _openToolTipForButton(CloseButton(), false); break; @@ -151,8 +157,8 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); - _openToolTipForButton(MinimizeButton(), false); _displayMinimizeTooltip->Dismiss(); + _openToolTipForButton(MinimizeButton(), false); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), true); break; @@ -183,11 +189,11 @@ namespace winrt::TerminalApp::implementation void MinMaxCloseControl::ReleaseButtons() { + _displayMinimizeTooltip->Dismiss(); VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); _openToolTipForButton(MinimizeButton(), false); - _displayMinimizeTooltip->Dismiss(); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), false); } diff --git a/src/cascadia/WinRTUtils/inc/ThrottledFunc.h b/src/cascadia/WinRTUtils/inc/ThrottledFunc.h index 824d3a2bf..40482faf1 100644 --- a/src/cascadia/WinRTUtils/inc/ThrottledFunc.h +++ b/src/cascadia/WinRTUtils/inc/ThrottledFunc.h @@ -71,15 +71,6 @@ public: _storage.modify_pending(func); } - // This only really works for Trailing throttled funcs. - // - // Dismiss the currently pending callback, so it won't be called at the end - // of the timeout. - void Dismiss() - { - _storage.reset(); - } - private: static void __stdcall _timer_callback(PTP_CALLBACK_INSTANCE /*instance*/, PVOID context, PTP_TIMER /*timer*/) noexcept { From 1167e20b0f42e4b950c678d20f352bb841c58cc2 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 4 Nov 2021 08:49:57 -0500 Subject: [PATCH 16/26] Yea, this works the way we want --- .../TerminalApp/MinMaxCloseControl.cpp | 26 ++++++++++++++----- src/cascadia/TerminalApp/MinMaxCloseControl.h | 2 +- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 0b7acc4ff..258222a55 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -47,10 +47,22 @@ namespace winrt::TerminalApp::implementation } }; }; - _displayMinimizeTooltip = std::make_shared>( + + _displayMinimizeTooltip = std::make_shared>( dispatcher, ToolTipInterval, - createOpenToolTipFn(MinimizeButton())); + [weakThis = get_weak()](Controls::Button button) { + if (button) + { + if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) + { + if (auto tooltip{ tt.try_as() }) + { + tooltip.IsOpen(true); + } + } + } + }); // TODO! I need to add a sentinel arg to this ThrottledFunc. With two // values: Open, and Ignore. Open will open the tt, and Ignore will do // nothing. WHere I'm dismissing below, instead, modifyPending(Ignore), @@ -140,7 +152,9 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); // _openToolTipForButton(MinimizeButton(), true); - _displayMinimizeTooltip->Run(); + + // _displayMinimizeTooltip->ModifyPending(MinimizeButton()); + _displayMinimizeTooltip->Run(MinimizeButton()); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), false); break; @@ -148,7 +162,7 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - _displayMinimizeTooltip->Dismiss(); + _displayMinimizeTooltip->Run(nullptr); _openToolTipForButton(MinimizeButton(), false); _openToolTipForButton(MaximizeButton(), true); _openToolTipForButton(CloseButton(), false); @@ -157,7 +171,7 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); - _displayMinimizeTooltip->Dismiss(); + _displayMinimizeTooltip->Run(nullptr); _openToolTipForButton(MinimizeButton(), false); _openToolTipForButton(MaximizeButton(), false); _openToolTipForButton(CloseButton(), true); @@ -189,7 +203,7 @@ namespace winrt::TerminalApp::implementation void MinMaxCloseControl::ReleaseButtons() { - _displayMinimizeTooltip->Dismiss(); + _displayMinimizeTooltip->Run(nullptr); VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index 6dee1f624..aaed86715 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); - std::shared_ptr> _displayMinimizeTooltip{ nullptr }; + std::shared_ptr> _displayMinimizeTooltip{ nullptr }; }; } From 6e2150ba5bf804c3854b85f7f7775c8bcaf0c046 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 4 Nov 2021 11:14:05 -0500 Subject: [PATCH 17/26] cleanup for the tooltips --- .../TerminalApp/MinMaxCloseControl.cpp | 96 +++++++++++-------- src/cascadia/TerminalApp/MinMaxCloseControl.h | 2 +- .../WindowsTerminal/NonClientIslandWindow.cpp | 2 - 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 258222a55..233c1dae5 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -1,32 +1,23 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -// -// MinMaxCloseControl.xaml.cpp -// Implementation of the MinMaxCloseControl class -// #include "pch.h" #include "MinMaxCloseControl.h" - #include "MinMaxCloseControl.g.cpp" - #include using namespace winrt::Windows::UI::Xaml; -// TODO! this should be a system constant -constexpr const auto ToolTipInterval = std::chrono::milliseconds(400); - namespace winrt::TerminalApp::implementation { - void _openToolTipForButton(const Controls::Button& button, const bool isOpen) + void _closeToolTipForButton(const Controls::Button& button) { if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) { if (auto tooltip{ tt.try_as() }) { - tooltip.IsOpen(isOpen); + tooltip.IsOpen(false); } } } @@ -39,19 +30,27 @@ namespace winrt::TerminalApp::implementation auto dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); InitializeComponent(); - auto createOpenToolTipFn = [weakThis = get_weak()](const Controls::Button& button) { - return [weakThis, button]() { - if (auto self{ weakThis.get() }) - { - _openToolTipForButton(button, true); - } - }; - }; - _displayMinimizeTooltip = std::make_shared>( + // Get the tooltip hover time from the system, or default to 400ms + // (which should be the default, see: + // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-trackmouseevent#remarks) + unsigned int hoverTimeoutMillis{ 400 }; + LOG_IF_WIN32_BOOL_FALSE(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0)); + const auto toolTipInterval = std::chrono::milliseconds(hoverTimeoutMillis); + + // Create a ThrottledFunc for opening the tooltip after the hover + // timeout. If we hover another button, we should make sure to call + // Run() with the new button. Calling `_displayToolTip.Run(nullptr)`, + // which will cause us to not display a tooltip, which is used when we + // leave the control entirely. + _displayToolTip = std::make_shared>( dispatcher, - ToolTipInterval, + toolTipInterval, [weakThis = get_weak()](Controls::Button button) { + // If we provide a button, then open the tooltip on that button. + // We can "dismiss" this throttled func by calling it with null, + // which will cause us to do nothing at the end of the timeout + // instead. if (button) { if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) @@ -63,10 +62,6 @@ namespace winrt::TerminalApp::implementation } } }); - // TODO! I need to add a sentinel arg to this ThrottledFunc. With two - // values: Open, and Ignore. Open will open the tt, and Ignore will do - // nothing. WHere I'm dismissing below, instead, modifyPending(Ignore), - // so it does nothing on the next run. } // These event handlers simply forward each buttons click events up to the @@ -143,6 +138,14 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - Called when the mouse hovers a button. + // - Transition that button to `PointerOver` + // - run the throttled func with this button, to display the tooltip after + // a timeout + // - dismiss any open tooltips on other buttons. + // Arguments: + // - button: the button that was hovered void MinMaxCloseControl::HoverButton(CaptionButton button) { switch (button) @@ -151,34 +154,39 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - // _openToolTipForButton(MinimizeButton(), true); - // _displayMinimizeTooltip->ModifyPending(MinimizeButton()); - _displayMinimizeTooltip->Run(MinimizeButton()); - _openToolTipForButton(MaximizeButton(), false); - _openToolTipForButton(CloseButton(), false); + _displayToolTip->Run(MinimizeButton()); + _closeToolTipForButton(MaximizeButton()); + _closeToolTipForButton(CloseButton()); break; case CaptionButton::Maximize: VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - _displayMinimizeTooltip->Run(nullptr); - _openToolTipForButton(MinimizeButton(), false); - _openToolTipForButton(MaximizeButton(), true); - _openToolTipForButton(CloseButton(), false); + + _closeToolTipForButton(MinimizeButton()); + _displayToolTip->Run(MaximizeButton()); + _closeToolTipForButton(CloseButton()); break; case CaptionButton::Close: VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); - _displayMinimizeTooltip->Run(nullptr); - _openToolTipForButton(MinimizeButton(), false); - _openToolTipForButton(MaximizeButton(), false); - _openToolTipForButton(CloseButton(), true); + + _closeToolTipForButton(MinimizeButton()); + _closeToolTipForButton(MaximizeButton()); + _displayToolTip->Run(CloseButton()); break; } } + // Method Description: + // - Called when the mouse presses down on a button. NOT when it is + // released. That's handled one level above, in + // TitleBarControl::ReleaseButtons + // - Transition that button to `Pressed` + // Arguments: + // - button: the button that was pressed void MinMaxCloseControl::PressButton(CaptionButton button) { switch (button) @@ -201,14 +209,18 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - Called when buttons are no longer hovered or pressed. Return them all + // to the normal state, and dismiss the tooltips. void MinMaxCloseControl::ReleaseButtons() { - _displayMinimizeTooltip->Run(nullptr); + _displayToolTip->Run(nullptr); VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); VisualStateManager::GoToState(CloseButton(), L"Normal", false); - _openToolTipForButton(MinimizeButton(), false); - _openToolTipForButton(MaximizeButton(), false); - _openToolTipForButton(CloseButton(), false); + + _closeToolTipForButton(MinimizeButton()); + _closeToolTipForButton(MaximizeButton()); + _closeToolTipForButton(CloseButton()); } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index aaed86715..c4da0f86a 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); - std::shared_ptr> _displayMinimizeTooltip{ nullptr }; + std::shared_ptr> _displayToolTip{ nullptr }; }; } diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 3fcf13310..83ab2e119 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -194,8 +194,6 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, LOG_IF_WIN32_BOOL_FALSE(TrackMouseEvent(&ev)); _trackingMouse = true; } - // TODO! We no longer show tooltips for the caption buttons when they're - // hovered. That's not good. break; case WM_NCMOUSELEAVE: From eebd1a078a951e18d633e9a2732c1052b241ccbb Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 4 Nov 2021 11:16:15 -0500 Subject: [PATCH 18/26] new APIs too --- .github/actions/spelling/allow/apis.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt index 19f5fb487..faf1afaad 100644 --- a/.github/actions/spelling/allow/apis.txt +++ b/.github/actions/spelling/allow/apis.txt @@ -44,6 +44,7 @@ HIGHCONTRASTW hotkeys href hrgn +HTCLOSE IActivation IApp IAppearance @@ -87,11 +88,14 @@ MENUDATA MENUINFO memicmp mptt +MOUSELEAVE mov msappx MULTIPLEUSE NCHITTEST NCLBUTTONDBLCLK +NCMOUSELEAVE +NCMOUSEMOVE NCRBUTTONDBLCLK NIF NIN @@ -153,9 +157,11 @@ TASKBARCREATED TBPF THEMECHANGED tlg +TME tmp tolower toupper +TRACKMOUSEEVENT TTask TVal UChar From 5acbad512efadfa0821622b949f20fbf60d6462e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 4 Nov 2021 11:22:12 -0500 Subject: [PATCH 19/26] an API that I missed --- .github/actions/spelling/allow/apis.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt index faf1afaad..67aeeac4d 100644 --- a/.github/actions/spelling/allow/apis.txt +++ b/.github/actions/spelling/allow/apis.txt @@ -38,6 +38,7 @@ fullkbd futex GETDESKWALLPAPER GETHIGHCONTRAST +GETMOUSEHOVERTIME Hashtable HIGHCONTRASTON HIGHCONTRASTW From 37c4cbee74d1dc5025eec68178191783c6b2bc51 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 11:39:23 -0600 Subject: [PATCH 20/26] Account for window frame on button hittesting --- .../WindowsTerminal/NonClientIslandWindow.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 1c6d2856a..7f6228287 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -91,26 +91,29 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) { RECT rcParent = GetWindowRect(); // The size of the buttons doesn't change over the life of the application. - static const auto buttonWidthInDips{ _titlebar.CaptionButtonWidth() }; + const auto buttonWidthInDips{ _titlebar.CaptionButtonWidth() }; - // However, the dPI scaling might, so get the updated size of the buttons in pixels + // However, the DPI scaling might, so get the updated size of the buttons in pixels const auto buttonWidthInPixels{ buttonWidthInDips * GetCurrentDpiScale() }; + // make sure to account for the width of the window frame! + const til::rectangle nonClientFrame{ GetNonClientFrame(_currentDpi) }; + const auto rightBorder{ rcParent.right - nonClientFrame.right() }; // From the right to the left, // * are we in the close button? // * the maximize button? // * the minimize button? // If we're not, then we're in either the top resize border, or just // generally in the titlebar. - if ((rcParent.right - pointer.x()) < (buttonWidthInPixels)) + if ((rightBorder - pointer.x()) < (buttonWidthInPixels)) { return HTCLOSE; } - else if ((rcParent.right - pointer.x()) < (buttonWidthInPixels * 2)) + else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 2)) { return HTMAXBUTTON; } - else if ((rcParent.right - pointer.x()) < (buttonWidthInPixels * 3)) + else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 3)) { return HTMINBUTTON; } From aa9577bfc721531ad28aa839592f9397bdabaa1b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 12:49:23 -0600 Subject: [PATCH 21/26] fix the pressing/hovering/tooltip interaction --- src/cascadia/TerminalApp/MinMaxCloseControl.cpp | 12 ++++++++++++ src/cascadia/TerminalApp/MinMaxCloseControl.h | 1 + src/cascadia/TerminalApp/TitlebarControl.cpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 233c1dae5..03b4f4113 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -148,6 +148,15 @@ namespace winrt::TerminalApp::implementation // - button: the button that was hovered void MinMaxCloseControl::HoverButton(CaptionButton button) { + // Keep track of the button that's been pressed. we get a mouse move + // message when we open the tooltip. If we move the mouse on top of this + // button, that we've already pressed, then no need to move to the + // "hovered" state, we should stay in the pressed state. + if (_lastPressedButton && _lastPressedButton.value() == button) + { + return; + } + switch (button) { case CaptionButton::Minimize: @@ -207,6 +216,7 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(CloseButton(), L"Pressed", false); break; } + _lastPressedButton = button; } // Method Description: @@ -222,5 +232,7 @@ namespace winrt::TerminalApp::implementation _closeToolTipForButton(MinimizeButton()); _closeToolTipForButton(MaximizeButton()); _closeToolTipForButton(CloseButton()); + + _lastPressedButton = std::nullopt; } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index c4da0f86a..0c336f256 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -34,6 +34,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs); std::shared_ptr> _displayToolTip{ nullptr }; + std::optional _lastPressedButton{ std::nullopt }; }; } diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index 2f4c1ccb9..4f3da96b5 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -25,6 +25,8 @@ namespace winrt::TerminalApp::implementation double TitlebarControl::CaptionButtonWidth() { + // Divide by three, since we know there are only three buttons. When + // Windows 12 comes along and adds another, we can update this /s static double width{ MinMaxCloseControl().ActualWidth() / 3.0 }; return width; } From 15ab87f5d4f42b336b30bcf42ea8d3f475452531 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 12:55:42 -0600 Subject: [PATCH 22/26] repair the top border resizing --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 7f6228287..28e9c0977 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -168,6 +168,13 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, // - If we're over _anything else_, stop hovering the buttons. switch (wparam) { + case HTTOP: + case HTCAPTION: + { + // Pass caption-related nonclient messages to the parent window. + auto parentWindow{ GetHandle() }; + return SendMessage(parentWindow, message, wparam, lparam); + } case HTMINBUTTON: case HTMAXBUTTON: case HTCLOSE: @@ -219,6 +226,7 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, // to the root HWND. switch (wparam) { + case HTTOP: case HTCAPTION: { // Pass caption-related nonclient messages to the parent window. @@ -243,6 +251,7 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, // to the root HWND. switch (wparam) { + case HTTOP: case HTCAPTION: { // Pass caption-related nonclient messages to the parent window. From fd2f5840190baf1fbecc0e81a65fa33fa9ef99c0 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 13:10:32 -0600 Subject: [PATCH 23/26] fix the system menu too --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 28e9c0977..c4025cbf4 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -271,6 +271,14 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, break; } return 0; + + // Make sure to pass along right-clicks in this region to our parent window + // - we don't need to handle these. + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONUP: + auto parentWindow{ GetHandle() }; + return SendMessage(parentWindow, message, wparam, lparam); } return DefWindowProc(_dragBarWindow.get(), message, wparam, lparam); From e24f4d5638316da133d3129642b9f703cff2174c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 13:10:46 -0600 Subject: [PATCH 24/26] a comment too --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index c4025cbf4..6a2b3fcbd 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -172,6 +172,8 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, case HTCAPTION: { // Pass caption-related nonclient messages to the parent window. + // Make sure to do this for the HTTOP, which is the top resize + // border, so we can resize the window on the top. auto parentWindow{ GetHandle() }; return SendMessage(parentWindow, message, wparam, lparam); } @@ -223,7 +225,8 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, // should change its visual state. // // If it's not in a caption button, then just forward the message along - // to the root HWND. + // to the root HWND. Make sure to do this for the HTTOP, which is the + // top resize border. switch (wparam) { case HTTOP: From 174e413f8ec30ef1104e645e9efad9dbdb6a724a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 13:16:04 -0600 Subject: [PATCH 25/26] color transitions too --- .../TerminalApp/MinMaxCloseControl.cpp | 44 ++++++++++--------- .../WindowsTerminal/NonClientIslandWindow.cpp | 2 + 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 03b4f4113..fe4b4058e 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -159,28 +159,30 @@ namespace winrt::TerminalApp::implementation switch (button) { + // Make sure to use true for the useTransitions parameter, to + // animate the fade in/out transition between colors. case CaptionButton::Minimize: - VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); - VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); - VisualStateManager::GoToState(CloseButton(), L"Normal", false); + VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", true); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); + VisualStateManager::GoToState(CloseButton(), L"Normal", true); _displayToolTip->Run(MinimizeButton()); _closeToolTipForButton(MaximizeButton()); _closeToolTipForButton(CloseButton()); break; case CaptionButton::Maximize: - VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); - VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); - VisualStateManager::GoToState(CloseButton(), L"Normal", false); + VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); + VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", true); + VisualStateManager::GoToState(CloseButton(), L"Normal", true); _closeToolTipForButton(MinimizeButton()); _displayToolTip->Run(MaximizeButton()); _closeToolTipForButton(CloseButton()); break; case CaptionButton::Close: - VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); - VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); - VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); + VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); + VisualStateManager::GoToState(CloseButton(), L"PointerOver", true); _closeToolTipForButton(MinimizeButton()); _closeToolTipForButton(MaximizeButton()); @@ -201,19 +203,19 @@ namespace winrt::TerminalApp::implementation switch (button) { case CaptionButton::Minimize: - VisualStateManager::GoToState(MinimizeButton(), L"Pressed", false); - VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); - VisualStateManager::GoToState(CloseButton(), L"Normal", false); + VisualStateManager::GoToState(MinimizeButton(), L"Pressed", true); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); + VisualStateManager::GoToState(CloseButton(), L"Normal", true); break; case CaptionButton::Maximize: - VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); - VisualStateManager::GoToState(MaximizeButton(), L"Pressed", false); - VisualStateManager::GoToState(CloseButton(), L"Normal", false); + VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); + VisualStateManager::GoToState(MaximizeButton(), L"Pressed", true); + VisualStateManager::GoToState(CloseButton(), L"Normal", true); break; case CaptionButton::Close: - VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); - VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); - VisualStateManager::GoToState(CloseButton(), L"Pressed", false); + VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); + VisualStateManager::GoToState(CloseButton(), L"Pressed", true); break; } _lastPressedButton = button; @@ -225,9 +227,9 @@ namespace winrt::TerminalApp::implementation void MinMaxCloseControl::ReleaseButtons() { _displayToolTip->Run(nullptr); - VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); - VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); - VisualStateManager::GoToState(CloseButton(), L"Normal", false); + VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); + VisualStateManager::GoToState(CloseButton(), L"Normal", true); _closeToolTipForButton(MinimizeButton()); _closeToolTipForButton(MaximizeButton()); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 6a2b3fcbd..50c68fd86 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -171,6 +171,8 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, case HTTOP: case HTCAPTION: { + _titlebar.ReleaseButtons(); + // Pass caption-related nonclient messages to the parent window. // Make sure to do this for the HTTOP, which is the top resize // border, so we can resize the window on the top. From 6939ff77cfaed833dc720e0f076841f99b5d5a97 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Nov 2021 13:18:22 -0600 Subject: [PATCH 26/26] this can be static --- .../TerminalApp/MinMaxCloseControl.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index fe4b4058e..24a47b0f8 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -11,7 +11,7 @@ using namespace winrt::Windows::UI::Xaml; namespace winrt::TerminalApp::implementation { - void _closeToolTipForButton(const Controls::Button& button) + static void closeToolTipForButton(const Controls::Button& button) { if (auto tt{ Controls::ToolTipService::GetToolTip(button) }) { @@ -167,25 +167,25 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(CloseButton(), L"Normal", true); _displayToolTip->Run(MinimizeButton()); - _closeToolTipForButton(MaximizeButton()); - _closeToolTipForButton(CloseButton()); + closeToolTipForButton(MaximizeButton()); + closeToolTipForButton(CloseButton()); break; case CaptionButton::Maximize: VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", true); VisualStateManager::GoToState(CloseButton(), L"Normal", true); - _closeToolTipForButton(MinimizeButton()); + closeToolTipForButton(MinimizeButton()); _displayToolTip->Run(MaximizeButton()); - _closeToolTipForButton(CloseButton()); + closeToolTipForButton(CloseButton()); break; case CaptionButton::Close: VisualStateManager::GoToState(MinimizeButton(), L"Normal", true); VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); VisualStateManager::GoToState(CloseButton(), L"PointerOver", true); - _closeToolTipForButton(MinimizeButton()); - _closeToolTipForButton(MaximizeButton()); + closeToolTipForButton(MinimizeButton()); + closeToolTipForButton(MaximizeButton()); _displayToolTip->Run(CloseButton()); break; } @@ -231,9 +231,9 @@ namespace winrt::TerminalApp::implementation VisualStateManager::GoToState(MaximizeButton(), L"Normal", true); VisualStateManager::GoToState(CloseButton(), L"Normal", true); - _closeToolTipForButton(MinimizeButton()); - _closeToolTipForButton(MaximizeButton()); - _closeToolTipForButton(CloseButton()); + closeToolTipForButton(MinimizeButton()); + closeToolTipForButton(MaximizeButton()); + closeToolTipForButton(CloseButton()); _lastPressedButton = std::nullopt; }