From 15a1f482548db10cf49a0702b6e8b912241596e8 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2019 09:11:25 -0500 Subject: [PATCH 1/7] This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. --- src/cascadia/WindowsTerminal/IslandWindow.cpp | 2 +- .../WindowsTerminal/NonClientIslandWindow.cpp | 117 +++++++++++++++--- 2 files changed, 100 insertions(+), 19 deletions(-) diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index e937f5fcd53..80d5eef18f2 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -53,7 +53,7 @@ void IslandWindow::MakeWindow() noexcept // WM_CREATE will be handled synchronously, before CreateWindow returns. WINRT_VERIFY(CreateWindow(wc.lpszClassName, L"Windows Terminal", - WS_OVERLAPPEDWINDOW, + WS_CAPTION | WS_POPUP, // WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 368961817c4..1c3a4daa2cb 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -232,7 +232,10 @@ MARGINS NonClientIslandWindow::GetFrameMargins() const noexcept // Get the size of the borders we want to use. The sides and bottom will // just be big enough for resizing, but the top will be as big as we need // for the non-client content. - MARGINS margins = GetFrameMargins(); + // MARGINS margins = GetFrameMargins(); + + MARGINS margins = { 0, 0, 0, 1 }; + // Extend the frame into the client area. return DwmExtendFrameIntoClientArea(_window.get(), &margins); } @@ -337,7 +340,8 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges // First call DwmDefWindowProc. This might handle things like the // min/max/close buttons for us. - const bool dwmHandledMessage = DwmDefWindowProc(_window.get(), message, wParam, lParam, &lRet); + // const bool dwmHandledMessage = DwmDefWindowProc(_window.get(), message, wParam, lParam, &lRet); + const bool dwmHandledMessage = false; switch (message) { @@ -391,19 +395,22 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges ForceResize(); break; } - case WM_NCACTIVATE: - case WM_NCPAINT: + case WM_PAINT: { if (!_dragBar) { return 0; } + HWND hwnd = _window.get(); + + PAINTSTRUCT ps{ 0 }; + HDC hdc = BeginPaint(hwnd, &ps); - const auto hdc = wil::GetDC(_window.get()); - if (hdc.get()) + if (hdc) { const auto scale = GetCurrentDpiScale(); const auto dpi = ::GetDpiForWindow(_window.get()); + // Get the dimensions of the drag borders for the sides of the window. const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi); const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi); const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX; @@ -415,31 +422,105 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges const auto color = RGB(backgroundColor.R, backgroundColor.G, backgroundColor.B); _backgroundBrush = wil::unique_hbrush(CreateSolidBrush(color)); + RECT dragBarRect = GetDragAreaRect(); + dragBarRect.left += xPos; + dragBarRect.right += xPos; + dragBarRect.bottom += yPos; + dragBarRect.top += yPos; + // ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); + ::FillRect(hdc, &dragBarRect, _backgroundBrush.get()); + RECT windowRect = {}; ::GetWindowRect(_window.get(), &windowRect); const auto cx = windowRect.right - windowRect.left; const auto cy = windowRect.bottom - windowRect.top; RECT clientRect = { 0, 0, cx, yPos }; - ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + ::FillRect(hdc, &clientRect, _backgroundBrush.get()); clientRect = { 0, 0, xPos, cy }; - ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + ::FillRect(hdc, &clientRect, _backgroundBrush.get()); clientRect = { 0, cy - yPos, cx, cy }; - ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + ::FillRect(hdc, &clientRect, _backgroundBrush.get()); + // Draw the right window border clientRect = { cx - xPos, 0, cx, cy }; - ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); - - RECT dragBarRect = GetDragAreaRect(); - dragBarRect.left += xPos; - dragBarRect.right += xPos; - dragBarRect.bottom += yPos; - dragBarRect.top += yPos; - ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); + ::FillRect(hdc, &clientRect, _backgroundBrush.get()); } - return 0; + + EndPaint(hwnd, &ps); + return TRUE; + } + // We need to update our NC area on WM_NCACTIVATE as well, otherwise it will + // update the NC area with the aero-style titlebar/border on focus gain/loss + case WM_NCACTIVATE: + case WM_NCPAINT: + { + // if (!_dragBar) + // { + // return 0; + // } + + // // const auto hdc = wil::GetDC(_window.get()); + // //////////////////////////////////////////////////////////////////////// + // HRGN hrgn = (HRGN)wParam; + // HWND hwnd = _window.get(); + // HDC hdcEx = ::GetDCEx(hwnd, hrgn, DCX_CACHE | DCX_WINDOW | DCX_INTERSECTRGN); + // if (hdcEx == nullptr) + // { + // auto gle = ::GetLastError(); + // gle; + // auto a = 0; + // a++; + // } + // const auto hdc = wil::unique_hdc_window(wil::window_dc(hdcEx)); + // //////////////////////////////////////////////////////////////////////// + // // Seems to do nothing different than just GetDC + // // const auto hdc = wil::GetWindowDC(_window.get()); + + // if (hdc.get()) + // // if (hdcEx) + // { + // const auto scale = GetCurrentDpiScale(); + // const auto dpi = ::GetDpiForWindow(_window.get()); + // const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi); + // const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi); + // const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX; + // const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY; + + // const auto backgroundBrush = _dragBar.Background(); + // const auto backgroundSolidBrush = backgroundBrush.as(); + // const auto backgroundColor = backgroundSolidBrush.Color(); + // const auto color = RGB(backgroundColor.R, backgroundColor.G, backgroundColor.B); + // _backgroundBrush = wil::unique_hbrush(CreateSolidBrush(color)); + + // RECT windowRect = {}; + // ::GetWindowRect(_window.get(), &windowRect); + // const auto cx = windowRect.right - windowRect.left; + // const auto cy = windowRect.bottom - windowRect.top; + + // RECT clientRect = { 0, 0, cx, yPos }; + // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + + // clientRect = { 0, 0, xPos, cy }; + // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + + // clientRect = { 0, cy - yPos, cx, cy }; + // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + + // // Draw the right window border + // clientRect = { cx - xPos, 0, cx, cy }; + // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + + // RECT dragBarRect = GetDragAreaRect(); + // dragBarRect.left += xPos; + // dragBarRect.right += xPos; + // dragBarRect.bottom += yPos; + // dragBarRect.top += yPos; + // ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); + // } + // return 0; } case WM_LBUTTONDOWN: { From 0bc9969361c3d583cf0ab34d2f7e95d4aafbf347 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2019 09:16:32 -0500 Subject: [PATCH 2/7] The window style was _not_ important --- src/cascadia/WindowsTerminal/IslandWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index 80d5eef18f2..e937f5fcd53 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -53,7 +53,7 @@ void IslandWindow::MakeWindow() noexcept // WM_CREATE will be handled synchronously, before CreateWindow returns. WINRT_VERIFY(CreateWindow(wc.lpszClassName, L"Windows Terminal", - WS_CAPTION | WS_POPUP, // WS_OVERLAPPEDWINDOW, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, From bf239b6de055fa2719367529590264443bc9a0b4 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2019 14:04:24 -0500 Subject: [PATCH 3/7] Still getting a black xaml islands area (the HRGN) when we switch to high DPI --- src/cascadia/WindowsTerminal/BaseWindow.h | 1 + .../WindowsTerminal/NonClientIslandWindow.cpp | 112 ++++-------------- 2 files changed, 24 insertions(+), 89 deletions(-) diff --git a/src/cascadia/WindowsTerminal/BaseWindow.h b/src/cascadia/WindowsTerminal/BaseWindow.h index 4e8b31ed932..227c738db10 100644 --- a/src/cascadia/WindowsTerminal/BaseWindow.h +++ b/src/cascadia/WindowsTerminal/BaseWindow.h @@ -89,6 +89,7 @@ class BaseWindow // do nothing. break; } + break; } case CM_UPDATE_TITLE: { diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 1c3a4daa2cb..bad946f92d4 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -229,11 +229,11 @@ MARGINS NonClientIslandWindow::GetFrameMargins() const noexcept // - the HRESULT returned by DwmExtendFrameIntoClientArea. [[nodiscard]] HRESULT NonClientIslandWindow::_UpdateFrameMargins() const noexcept { - // Get the size of the borders we want to use. The sides and bottom will - // just be big enough for resizing, but the top will be as big as we need - // for the non-client content. - // MARGINS margins = GetFrameMargins(); - + // Set frame margines with just a single pixel on the bottom. We don't + // really want a window frame at all - we're drawing all of it. We + // especially don't want a top margin - that's where the caption buttons + // are, and we're drawing those. So just set a single pixel on the bottom, + // because the method won't work with {0}. MARGINS margins = { 0, 0, 0, 1 }; // Extend the frame into the client area. @@ -340,8 +340,8 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges // First call DwmDefWindowProc. This might handle things like the // min/max/close buttons for us. - // const bool dwmHandledMessage = DwmDefWindowProc(_window.get(), message, wParam, lParam, &lRet); - const bool dwmHandledMessage = false; + const bool dwmHandledMessage = DwmDefWindowProc(_window.get(), message, wParam, lParam, &lRet); + // const bool dwmHandledMessage = false; switch (message) { @@ -390,23 +390,23 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges } break; } + case WM_EXITSIZEMOVE: { ForceResize(); break; } + case WM_PAINT: { if (!_dragBar) { return 0; } - HWND hwnd = _window.get(); PAINTSTRUCT ps{ 0 }; - HDC hdc = BeginPaint(hwnd, &ps); - - if (hdc) + const auto hdc = wil::BeginPaint(_window.get(), &ps); + if (hdc.get()) { const auto scale = GetCurrentDpiScale(); const auto dpi = ::GetDpiForWindow(_window.get()); @@ -416,112 +416,46 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX; const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY; + // Create brush for borders, titlebar color. const auto backgroundBrush = _dragBar.Background(); const auto backgroundSolidBrush = backgroundBrush.as(); const auto backgroundColor = backgroundSolidBrush.Color(); const auto color = RGB(backgroundColor.R, backgroundColor.G, backgroundColor.B); _backgroundBrush = wil::unique_hbrush(CreateSolidBrush(color)); + // Fill in the area between the non-client content and the caption buttons. RECT dragBarRect = GetDragAreaRect(); dragBarRect.left += xPos; dragBarRect.right += xPos; dragBarRect.bottom += yPos; dragBarRect.top += yPos; - // ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); - ::FillRect(hdc, &dragBarRect, _backgroundBrush.get()); + ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); RECT windowRect = {}; ::GetWindowRect(_window.get(), &windowRect); const auto cx = windowRect.right - windowRect.left; const auto cy = windowRect.bottom - windowRect.top; + // Draw the top window border RECT clientRect = { 0, 0, cx, yPos }; - ::FillRect(hdc, &clientRect, _backgroundBrush.get()); + ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + // Draw the left window border clientRect = { 0, 0, xPos, cy }; - ::FillRect(hdc, &clientRect, _backgroundBrush.get()); + ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); + // Draw the bottom window border clientRect = { 0, cy - yPos, cx, cy }; - ::FillRect(hdc, &clientRect, _backgroundBrush.get()); + ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); // Draw the right window border clientRect = { cx - xPos, 0, cx, cy }; - ::FillRect(hdc, &clientRect, _backgroundBrush.get()); + ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); } - EndPaint(hwnd, &ps); - return TRUE; - } - // We need to update our NC area on WM_NCACTIVATE as well, otherwise it will - // update the NC area with the aero-style titlebar/border on focus gain/loss - case WM_NCACTIVATE: - case WM_NCPAINT: - { - // if (!_dragBar) - // { - // return 0; - // } - - // // const auto hdc = wil::GetDC(_window.get()); - // //////////////////////////////////////////////////////////////////////// - // HRGN hrgn = (HRGN)wParam; - // HWND hwnd = _window.get(); - // HDC hdcEx = ::GetDCEx(hwnd, hrgn, DCX_CACHE | DCX_WINDOW | DCX_INTERSECTRGN); - // if (hdcEx == nullptr) - // { - // auto gle = ::GetLastError(); - // gle; - // auto a = 0; - // a++; - // } - // const auto hdc = wil::unique_hdc_window(wil::window_dc(hdcEx)); - // //////////////////////////////////////////////////////////////////////// - // // Seems to do nothing different than just GetDC - // // const auto hdc = wil::GetWindowDC(_window.get()); - - // if (hdc.get()) - // // if (hdcEx) - // { - // const auto scale = GetCurrentDpiScale(); - // const auto dpi = ::GetDpiForWindow(_window.get()); - // const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi); - // const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi); - // const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX; - // const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY; - - // const auto backgroundBrush = _dragBar.Background(); - // const auto backgroundSolidBrush = backgroundBrush.as(); - // const auto backgroundColor = backgroundSolidBrush.Color(); - // const auto color = RGB(backgroundColor.R, backgroundColor.G, backgroundColor.B); - // _backgroundBrush = wil::unique_hbrush(CreateSolidBrush(color)); - - // RECT windowRect = {}; - // ::GetWindowRect(_window.get(), &windowRect); - // const auto cx = windowRect.right - windowRect.left; - // const auto cy = windowRect.bottom - windowRect.top; - - // RECT clientRect = { 0, 0, cx, yPos }; - // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); - - // clientRect = { 0, 0, xPos, cy }; - // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); - - // clientRect = { 0, cy - yPos, cx, cy }; - // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); - - // // Draw the right window border - // clientRect = { cx - xPos, 0, cx, cy }; - // ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get()); - - // RECT dragBarRect = GetDragAreaRect(); - // dragBarRect.left += xPos; - // dragBarRect.right += xPos; - // dragBarRect.bottom += yPos; - // dragBarRect.top += yPos; - // ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); - // } - // return 0; + return 0; } + case WM_LBUTTONDOWN: { POINT point1 = {}; From 22e102386b29c537acff8f95d8606255dd7d1288 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2019 14:04:45 -0500 Subject: [PATCH 4/7] I don't know if this affects anything. --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index bad946f92d4..8cc61c00042 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -657,7 +657,7 @@ bool NonClientIslandWindow::_HandleWindowPosChanging(WINDOWPOS* const windowPos) // you do this here, then a small gap will appear between the titlebar // and the content, until the window is moved. However, we do need to // keep this here _in general_ for dragging across DPI boundaries. - if (!_isMaximized) + if (_isMaximized) { THROW_IF_FAILED(_UpdateFrameMargins()); } From aad9f56d83cf2a25fcea680016797a6f982d6cc5 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2019 15:18:03 -0500 Subject: [PATCH 5/7] heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. --- .../WindowsTerminal/NonClientIslandWindow.cpp | 48 ++++++++++++++++--- .../WindowsTerminal/NonClientIslandWindow.h | 1 + 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 8cc61c00042..d7a995a51be 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -36,8 +36,9 @@ NonClientIslandWindow::~NonClientIslandWindow() void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs) { - InvalidateRect(NULL, NULL, TRUE); - ForceResize(); + // InvalidateRect(NULL, NULL, TRUE); + // ForceResize(); + _UpdateDragRegion(); } void NonClientIslandWindow::OnAppInitialized(winrt::TerminalApp::App app) @@ -101,8 +102,6 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height) const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX; const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY; - winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_BOTTOM, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW)); - if (_rootGrid) { winrt::Windows::Foundation::Size size{ (windowsWidth / scale) + 0.5f, (windowsHeight / scale) + 0.5f }; @@ -113,8 +112,40 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height) _rootGrid.Arrange(finalRect); } + winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_TOP, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW)); +} + +void NonClientIslandWindow::_UpdateDragRegion() +{ if (_dragBar) { + const auto windowRect = GetWindowRect(); + const auto width = windowRect.right - windowRect.left; + const auto height = windowRect.bottom - windowRect.top; + + const auto scale = GetCurrentDpiScale(); + const auto dpi = ::GetDpiForWindow(_window.get()); + + const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi); + const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi); + + // If we're maximized, we don't want to use the frame as our margins, + // instead we want to use the margins from the maximization. If we included + // the left&right sides of the frame in this calculation while maximized, + // you' have a few pixels of the window border on the sides while maximized, + // which most apps do not have. + const auto bordersWidth = _isMaximized ? + (_maximizedMargins.cxLeftWidth + _maximizedMargins.cxRightWidth) : + (dragX * 2); + const auto bordersHeight = _isMaximized ? + (_maximizedMargins.cyBottomHeight + _maximizedMargins.cyTopHeight) : + (dragY * 2); + + const auto windowsWidth = width - bordersWidth; + const auto windowsHeight = height - bordersHeight; + const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX; + const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY; + const auto dragBarRect = GetDragAreaRect(); const auto nonClientHeight = dragBarRect.bottom - dragBarRect.top; @@ -127,9 +158,8 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height) auto clientRegion = wil::unique_hrgn(CreateRectRgn(0, nonClientHeight, windowsWidth, windowsHeight)); winrt::check_bool(CombineRgn(_dragBarRegion.get(), nonClientRegion.get(), clientRegion.get(), RGN_OR)); winrt::check_bool(SetWindowRgn(_interopWindowHandle, _dragBarRegion.get(), true)); + // winrt::check_bool(InvalidateRgn(_interopWindowHandle, _dragBarRegion.get(), true)); } - - winrt::check_hresult(_UpdateFrameMargins()); } // Method Description: @@ -403,6 +433,12 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges { return 0; } + RECT updateRect{ 0 }; + const bool updateRectResult = ::GetUpdateRect(_window.get(), &updateRect, false); + if (updateRectResult == 0) + { + break; + } PAINTSTRUCT ps{ 0 }; const auto hdc = wil::BeginPaint(_window.get(), &ps); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index 0e0ebe0868b..a514c08773d 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -54,6 +54,7 @@ class NonClientIslandWindow : public IslandWindow void _HandleActivateWindow(); bool _HandleWindowPosChanging(WINDOWPOS* const windowPos); + void _UpdateDragRegion(); void OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs); From 5fd41919e94e3e9b14836c29eaab4751f9bffa03 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2019 15:49:05 -0500 Subject: [PATCH 6/7] Add more comments and cleanup --- .../WindowsTerminal/NonClientIslandWindow.cpp | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index d7a995a51be..ce180d270b9 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -34,10 +34,16 @@ NonClientIslandWindow::~NonClientIslandWindow() { } -void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs) +// Method Description: +// - Called when the app's size changes. When that happens, the size of the drag +// bar may have changed. If it has, we'll need to update the WindowRgn of the +// interop window. +// Arguments: +// - +// Return Value: +// - +void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/, winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/) { - // InvalidateRect(NULL, NULL, TRUE); - // ForceResize(); _UpdateDragRegion(); } @@ -115,10 +121,23 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height) winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_TOP, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW)); } +// Method Description: +// - Update the region of our window that is the draggable area. This happens in +// response to a OnDragBarSizeChanged event. We'll calculate the areas of the +// window that we want to display XAML content in, and set the window region +// of our child xaml-island window to that region. That way, the parent window +// will still get NCHITTEST'ed _outside_ the XAML content area, for things +// like dragging and resizing. +// Arguments: +// - +// Return Value: +// - void NonClientIslandWindow::_UpdateDragRegion() { if (_dragBar) { + // TODO:GH#1897 This is largely duplicated from OnSize, and we should do + // better than that. const auto windowRect = GetWindowRect(); const auto width = windowRect.right - windowRect.left; const auto height = windowRect.bottom - windowRect.top; @@ -158,7 +177,6 @@ void NonClientIslandWindow::_UpdateDragRegion() auto clientRegion = wil::unique_hrgn(CreateRectRgn(0, nonClientHeight, windowsWidth, windowsHeight)); winrt::check_bool(CombineRgn(_dragBarRegion.get(), nonClientRegion.get(), clientRegion.get(), RGN_OR)); winrt::check_bool(SetWindowRgn(_interopWindowHandle, _dragBarRegion.get(), true)); - // winrt::check_bool(InvalidateRgn(_interopWindowHandle, _dragBarRegion.get(), true)); } } @@ -371,7 +389,6 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges // First call DwmDefWindowProc. This might handle things like the // min/max/close buttons for us. const bool dwmHandledMessage = DwmDefWindowProc(_window.get(), message, wParam, lParam, &lRet); - // const bool dwmHandledMessage = false; switch (message) { @@ -433,13 +450,7 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges { return 0; } - RECT updateRect{ 0 }; - const bool updateRectResult = ::GetUpdateRect(_window.get(), &updateRect, false); - if (updateRectResult == 0) - { - break; - } - + PAINTSTRUCT ps{ 0 }; const auto hdc = wil::BeginPaint(_window.get(), &ps); if (hdc.get()) @@ -693,7 +704,7 @@ bool NonClientIslandWindow::_HandleWindowPosChanging(WINDOWPOS* const windowPos) // you do this here, then a small gap will appear between the titlebar // and the content, until the window is moved. However, we do need to // keep this here _in general_ for dragging across DPI boundaries. - if (_isMaximized) + if (!_isMaximized) { THROW_IF_FAILED(_UpdateFrameMargins()); } From 90409409116bde04e69b86c3e857fd38507856e9 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 12 Jul 2019 11:25:52 -0500 Subject: [PATCH 7/7] Some PR nits, fix the titlebar painting on maximize --- .../WindowsTerminal/NonClientIslandWindow.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index ce180d270b9..b2eac1cade5 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -118,7 +118,8 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height) _rootGrid.Arrange(finalRect); } - winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_TOP, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW)); + // I'm not sure that HWND_BOTTOM is any different than HWND_TOP for us. + winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_BOTTOM, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW)); } // Method Description: @@ -142,7 +143,6 @@ void NonClientIslandWindow::_UpdateDragRegion() const auto width = windowRect.right - windowRect.left; const auto height = windowRect.bottom - windowRect.top; - const auto scale = GetCurrentDpiScale(); const auto dpi = ::GetDpiForWindow(_window.get()); const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi); @@ -277,7 +277,7 @@ MARGINS NonClientIslandWindow::GetFrameMargins() const noexcept // - the HRESULT returned by DwmExtendFrameIntoClientArea. [[nodiscard]] HRESULT NonClientIslandWindow::_UpdateFrameMargins() const noexcept { - // Set frame margines with just a single pixel on the bottom. We don't + // Set frame margins with just a single pixel on the bottom. We don't // really want a window frame at all - we're drawing all of it. We // especially don't want a top margin - that's where the caption buttons // are, and we're drawing those. So just set a single pixel on the bottom, @@ -450,7 +450,7 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges { return 0; } - + PAINTSTRUCT ps{ 0 }; const auto hdc = wil::BeginPaint(_window.get(), &ps); if (hdc.get()) @@ -470,19 +470,19 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges const auto color = RGB(backgroundColor.R, backgroundColor.G, backgroundColor.B); _backgroundBrush = wil::unique_hbrush(CreateSolidBrush(color)); - // Fill in the area between the non-client content and the caption buttons. - RECT dragBarRect = GetDragAreaRect(); - dragBarRect.left += xPos; - dragBarRect.right += xPos; - dragBarRect.bottom += yPos; - dragBarRect.top += yPos; - ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); - RECT windowRect = {}; ::GetWindowRect(_window.get(), &windowRect); const auto cx = windowRect.right - windowRect.left; const auto cy = windowRect.bottom - windowRect.top; + // Fill in the _entire_ titlebar area. + RECT dragBarRect = {}; + dragBarRect.left = xPos; + dragBarRect.right = xPos + cx; + dragBarRect.top = yPos; + dragBarRect.bottom = yPos + cy; + ::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get()); + // Draw the top window border RECT clientRect = { 0, 0, cx, yPos }; ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());