Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't NCPAINT our window, PAINT our window #1898

Merged
merged 7 commits into from
Jul 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/cascadia/WindowsTerminal/BaseWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class BaseWindow
// do nothing.
break;
}
break;
}
case CM_UPDATE_TITLE:
{
Expand Down
104 changes: 83 additions & 21 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,17 @@ 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:
// - <unused>
// Return Value:
// - <none>
void NonClientIslandWindow::OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/, winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/)
{
InvalidateRect(NULL, NULL, TRUE);
ForceResize();
_UpdateDragRegion();
}

void NonClientIslandWindow::OnAppInitialized(winrt::TerminalApp::App app)
Expand Down Expand Up @@ -101,8 +108,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 };
Expand All @@ -113,8 +118,53 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
_rootGrid.Arrange(finalRect);
}

// I'm not sure that HWND_BOTTOM is any different than HWND_TOP for us.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what this comment is supposed to mean.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh mainly just that both those values do the same thing, which doesn't really make sense, so there's not really a reason one was picked over the other

winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_BOTTOM, 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:
// - <none>
// Return Value:
// - <none>
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;

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;

Expand All @@ -128,8 +178,6 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
winrt::check_bool(CombineRgn(_dragBarRegion.get(), nonClientRegion.get(), clientRegion.get(), RGN_OR));
winrt::check_bool(SetWindowRgn(_interopWindowHandle, _dragBarRegion.get(), true));
}

winrt::check_hresult(_UpdateFrameMargins());
}

// Method Description:
Expand Down Expand Up @@ -229,10 +277,13 @@ 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 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,
// because the method won't work with {0}.
MARGINS margins = { 0, 0, 0, 1 };

// Extend the frame into the client area.
return DwmExtendFrameIntoClientArea(_window.get(), &margins);
}
Expand Down Expand Up @@ -386,29 +437,33 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
}
break;
}

case WM_EXITSIZEMOVE:
{
ForceResize();
break;
}
case WM_NCACTIVATE:
case WM_NCPAINT:
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved

case WM_PAINT:
{
if (!_dragBar)
{
return 0;
}

const auto hdc = wil::GetDC(_window.get());
PAINTSTRUCT ps{ 0 };
const auto hdc = wil::BeginPaint(_window.get(), &ps);
if (hdc.get())
{
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;
const auto yPos = _isMaximized ? _maximizedMargins.cyTopHeight : dragY;

// Create brush for borders, titlebar color.
const auto backgroundBrush = _dragBar.Background();
const auto backgroundSolidBrush = backgroundBrush.as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
const auto backgroundColor = backgroundSolidBrush.Color();
Expand All @@ -420,27 +475,34 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
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());

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

// Draw the bottom window border
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:
{
POINT point1 = {};
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down