Skip to content

Commit a3373d3

Browse files
zadjii-msftmcpiroman
authored andcommitted
Don't NCPAINT our window, PAINT our window (microsoft#1898)
* 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. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * 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. * Add more comments and cleanup * Some PR nits, fix the titlebar painting on maximize
1 parent fcf4576 commit a3373d3

File tree

3 files changed

+85
-21
lines changed

3 files changed

+85
-21
lines changed

src/cascadia/WindowsTerminal/BaseWindow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class BaseWindow
8989
// do nothing.
9090
break;
9191
}
92+
break;
9293
}
9394
case CM_UPDATE_TITLE:
9495
{

src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,17 @@ NonClientIslandWindow::~NonClientIslandWindow()
3434
{
3535
}
3636

37-
void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs)
37+
// Method Description:
38+
// - Called when the app's size changes. When that happens, the size of the drag
39+
// bar may have changed. If it has, we'll need to update the WindowRgn of the
40+
// interop window.
41+
// Arguments:
42+
// - <unused>
43+
// Return Value:
44+
// - <none>
45+
void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/, winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/)
3846
{
39-
InvalidateRect(NULL, NULL, TRUE);
40-
ForceResize();
47+
_UpdateDragRegion();
4148
}
4249

4350
void NonClientIslandWindow::OnAppInitialized(winrt::TerminalApp::App app)
@@ -101,8 +108,6 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
101108
const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX;
102109
const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY;
103110

104-
winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_BOTTOM, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW));
105-
106111
if (_rootGrid)
107112
{
108113
winrt::Windows::Foundation::Size size{ (windowsWidth / scale) + 0.5f, (windowsHeight / scale) + 0.5f };
@@ -113,8 +118,53 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
113118
_rootGrid.Arrange(finalRect);
114119
}
115120

121+
// I'm not sure that HWND_BOTTOM is any different than HWND_TOP for us.
122+
winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_BOTTOM, xPos, yPos, windowsWidth, windowsHeight, SWP_SHOWWINDOW));
123+
}
124+
125+
// Method Description:
126+
// - Update the region of our window that is the draggable area. This happens in
127+
// response to a OnDragBarSizeChanged event. We'll calculate the areas of the
128+
// window that we want to display XAML content in, and set the window region
129+
// of our child xaml-island window to that region. That way, the parent window
130+
// will still get NCHITTEST'ed _outside_ the XAML content area, for things
131+
// like dragging and resizing.
132+
// Arguments:
133+
// - <none>
134+
// Return Value:
135+
// - <none>
136+
void NonClientIslandWindow::_UpdateDragRegion()
137+
{
116138
if (_dragBar)
117139
{
140+
// TODO:GH#1897 This is largely duplicated from OnSize, and we should do
141+
// better than that.
142+
const auto windowRect = GetWindowRect();
143+
const auto width = windowRect.right - windowRect.left;
144+
const auto height = windowRect.bottom - windowRect.top;
145+
146+
const auto dpi = ::GetDpiForWindow(_window.get());
147+
148+
const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi);
149+
const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi);
150+
151+
// If we're maximized, we don't want to use the frame as our margins,
152+
// instead we want to use the margins from the maximization. If we included
153+
// the left&right sides of the frame in this calculation while maximized,
154+
// you' have a few pixels of the window border on the sides while maximized,
155+
// which most apps do not have.
156+
const auto bordersWidth = _isMaximized ?
157+
(_maximizedMargins.cxLeftWidth + _maximizedMargins.cxRightWidth) :
158+
(dragX * 2);
159+
const auto bordersHeight = _isMaximized ?
160+
(_maximizedMargins.cyBottomHeight + _maximizedMargins.cyTopHeight) :
161+
(dragY * 2);
162+
163+
const auto windowsWidth = width - bordersWidth;
164+
const auto windowsHeight = height - bordersHeight;
165+
const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX;
166+
const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY;
167+
118168
const auto dragBarRect = GetDragAreaRect();
119169
const auto nonClientHeight = dragBarRect.bottom - dragBarRect.top;
120170

@@ -128,8 +178,6 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
128178
winrt::check_bool(CombineRgn(_dragBarRegion.get(), nonClientRegion.get(), clientRegion.get(), RGN_OR));
129179
winrt::check_bool(SetWindowRgn(_interopWindowHandle, _dragBarRegion.get(), true));
130180
}
131-
132-
winrt::check_hresult(_UpdateFrameMargins());
133181
}
134182

135183
// Method Description:
@@ -229,10 +277,13 @@ MARGINS NonClientIslandWindow::GetFrameMargins() const noexcept
229277
// - the HRESULT returned by DwmExtendFrameIntoClientArea.
230278
[[nodiscard]] HRESULT NonClientIslandWindow::_UpdateFrameMargins() const noexcept
231279
{
232-
// Get the size of the borders we want to use. The sides and bottom will
233-
// just be big enough for resizing, but the top will be as big as we need
234-
// for the non-client content.
235-
MARGINS margins = GetFrameMargins();
280+
// Set frame margins with just a single pixel on the bottom. We don't
281+
// really want a window frame at all - we're drawing all of it. We
282+
// especially don't want a top margin - that's where the caption buttons
283+
// are, and we're drawing those. So just set a single pixel on the bottom,
284+
// because the method won't work with {0}.
285+
MARGINS margins = { 0, 0, 0, 1 };
286+
236287
// Extend the frame into the client area.
237288
return DwmExtendFrameIntoClientArea(_window.get(), &margins);
238289
}
@@ -386,29 +437,33 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
386437
}
387438
break;
388439
}
440+
389441
case WM_EXITSIZEMOVE:
390442
{
391443
ForceResize();
392444
break;
393445
}
394-
case WM_NCACTIVATE:
395-
case WM_NCPAINT:
446+
447+
case WM_PAINT:
396448
{
397449
if (!_dragBar)
398450
{
399451
return 0;
400452
}
401453

402-
const auto hdc = wil::GetDC(_window.get());
454+
PAINTSTRUCT ps{ 0 };
455+
const auto hdc = wil::BeginPaint(_window.get(), &ps);
403456
if (hdc.get())
404457
{
405458
const auto scale = GetCurrentDpiScale();
406459
const auto dpi = ::GetDpiForWindow(_window.get());
460+
// Get the dimensions of the drag borders for the sides of the window.
407461
const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi);
408462
const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi);
409463
const auto xPos = _isMaximized ? _maximizedMargins.cxLeftWidth : dragX;
410464
const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY;
411465

466+
// Create brush for borders, titlebar color.
412467
const auto backgroundBrush = _dragBar.Background();
413468
const auto backgroundSolidBrush = backgroundBrush.as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
414469
const auto backgroundColor = backgroundSolidBrush.Color();
@@ -420,27 +475,34 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
420475
const auto cx = windowRect.right - windowRect.left;
421476
const auto cy = windowRect.bottom - windowRect.top;
422477

478+
// Fill in the _entire_ titlebar area.
479+
RECT dragBarRect = {};
480+
dragBarRect.left = xPos;
481+
dragBarRect.right = xPos + cx;
482+
dragBarRect.top = yPos;
483+
dragBarRect.bottom = yPos + cy;
484+
::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get());
485+
486+
// Draw the top window border
423487
RECT clientRect = { 0, 0, cx, yPos };
424488
::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
425489

490+
// Draw the left window border
426491
clientRect = { 0, 0, xPos, cy };
427492
::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
428493

494+
// Draw the bottom window border
429495
clientRect = { 0, cy - yPos, cx, cy };
430496
::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
431497

498+
// Draw the right window border
432499
clientRect = { cx - xPos, 0, cx, cy };
433500
::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
434-
435-
RECT dragBarRect = GetDragAreaRect();
436-
dragBarRect.left += xPos;
437-
dragBarRect.right += xPos;
438-
dragBarRect.bottom += yPos;
439-
dragBarRect.top += yPos;
440-
::FillRect(hdc.get(), &dragBarRect, _backgroundBrush.get());
441501
}
502+
442503
return 0;
443504
}
505+
444506
case WM_LBUTTONDOWN:
445507
{
446508
POINT point1 = {};

src/cascadia/WindowsTerminal/NonClientIslandWindow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class NonClientIslandWindow : public IslandWindow
5454

5555
void _HandleActivateWindow();
5656
bool _HandleWindowPosChanging(WINDOWPOS* const windowPos);
57+
void _UpdateDragRegion();
5758

5859
void OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs);
5960

0 commit comments

Comments
 (0)