From 04145d4fe01492590045690d4c861bc869e387bc Mon Sep 17 00:00:00 2001 From: Chris Swan Date: Fri, 3 Sep 2021 10:29:54 -0700 Subject: [PATCH] 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;