|
|
|
@ -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)
|
|
|
|
@ -78,11 +85,94 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto scale = GetCurrentDpiScale();
|
|
|
|
|
const auto dpi = ::GetDpiForWindow(_window.get());
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
_UpdateInternalMetrics();
|
|
|
|
|
|
|
|
|
|
const auto windowsWidth = RECT_WIDTH(&_clientArea);
|
|
|
|
|
const auto windowsHeight = RECT_HEIGHT(&_clientArea);
|
|
|
|
|
if (_rootGrid)
|
|
|
|
|
{
|
|
|
|
|
const auto scale = GetCurrentDpiScale();
|
|
|
|
|
|
|
|
|
|
winrt::Windows::Foundation::Size size{ (windowsWidth / scale) + 0.5f, (windowsHeight / scale) + 0.5f };
|
|
|
|
|
_rootGrid.Height(size.Height);
|
|
|
|
|
_rootGrid.Width(size.Width);
|
|
|
|
|
_rootGrid.Measure(size);
|
|
|
|
|
winrt::Windows::Foundation::Rect finalRect{};
|
|
|
|
|
_rootGrid.Arrange(finalRect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
winrt::check_bool(SetWindowPos(_interopWindowHandle, HWND_TOP, _clientArea.left, _clientArea.top, 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)
|
|
|
|
|
{
|
|
|
|
|
const auto dragBarRect = GetDragAreaRect();
|
|
|
|
|
const auto nonClientHeight = dragBarRect.bottom - dragBarRect.top;
|
|
|
|
|
const auto windowsWidth = RECT_WIDTH(&_clientArea);
|
|
|
|
|
const auto windowsHeight = RECT_HEIGHT(&_clientArea);
|
|
|
|
|
|
|
|
|
|
auto nonClientRegion = wil::unique_hrgn(CreateRectRgn(0, 0, 0, 0));
|
|
|
|
|
auto nonClientLeftRegion = wil::unique_hrgn(CreateRectRgn(0, 0, dragBarRect.left, nonClientHeight));
|
|
|
|
|
auto nonClientRightRegion = wil::unique_hrgn(CreateRectRgn(dragBarRect.right, 0, windowsWidth, nonClientHeight));
|
|
|
|
|
winrt::check_bool(CombineRgn(nonClientRegion.get(), nonClientLeftRegion.get(), nonClientRightRegion.get(), RGN_OR));
|
|
|
|
|
|
|
|
|
|
_dragBarRegion = wil::unique_hrgn(CreateRectRgn(0, 0, 0, 0));
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NonClientIslandWindow::_UpdateInternalMetrics()
|
|
|
|
|
{
|
|
|
|
|
// TODO:GH#1897 This is largely duplicated from OnSize, and we should do
|
|
|
|
|
// better than that.
|
|
|
|
|
_windowRect = GetWindowRect();
|
|
|
|
|
const auto width = _windowRect.right - _windowRect.left;
|
|
|
|
|
const auto height = _windowRect.bottom - _windowRect.top;
|
|
|
|
|
|
|
|
|
|
// const auto scale = GetCurrentDpiScale();
|
|
|
|
|
const auto dpi = _currentDpi; // ::GetDpiForWindow(_window.get());
|
|
|
|
|
|
|
|
|
|
const auto dragY = ::GetSystemMetricsForDpi(SM_CYDRAG, dpi);
|
|
|
|
|
const auto dragX = ::GetSystemMetricsForDpi(SM_CXDRAG, dpi);
|
|
|
|
|
_dragSize = { dragX, dragY };
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
@ -95,41 +185,21 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
|
|
|
|
|
const auto bordersHeight = _isMaximized ?
|
|
|
|
|
(_maximizedMargins.cyBottomHeight + _maximizedMargins.cyTopHeight) :
|
|
|
|
|
(dragY * 2);
|
|
|
|
|
_borderSize = { bordersWidth, bordersHeight };
|
|
|
|
|
|
|
|
|
|
const auto windowsWidth = width - bordersWidth;
|
|
|
|
|
const auto windowsHeight = height - bordersHeight;
|
|
|
|
|
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 };
|
|
|
|
|
_rootGrid.Height(size.Height);
|
|
|
|
|
_rootGrid.Width(size.Width);
|
|
|
|
|
_rootGrid.Measure(size);
|
|
|
|
|
winrt::Windows::Foundation::Rect finalRect{};
|
|
|
|
|
_rootGrid.Arrange(finalRect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_dragBar)
|
|
|
|
|
{
|
|
|
|
|
const auto dragBarRect = GetDragAreaRect();
|
|
|
|
|
const auto nonClientHeight = dragBarRect.bottom - dragBarRect.top;
|
|
|
|
|
|
|
|
|
|
auto nonClientRegion = wil::unique_hrgn(CreateRectRgn(0, 0, 0, 0));
|
|
|
|
|
auto nonClientLeftRegion = wil::unique_hrgn(CreateRectRgn(0, 0, dragBarRect.left, nonClientHeight));
|
|
|
|
|
auto nonClientRightRegion = wil::unique_hrgn(CreateRectRgn(dragBarRect.right, 0, windowsWidth, nonClientHeight));
|
|
|
|
|
winrt::check_bool(CombineRgn(nonClientRegion.get(), nonClientLeftRegion.get(), nonClientRightRegion.get(), RGN_OR));
|
|
|
|
|
|
|
|
|
|
_dragBarRegion = wil::unique_hrgn(CreateRectRgn(0, 0, 0, 0));
|
|
|
|
|
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_hresult(_UpdateFrameMargins());
|
|
|
|
|
// TODO
|
|
|
|
|
// Wait this isn't the client area. This is just the area inside the
|
|
|
|
|
// borders. (which yea is all our client area but still)
|
|
|
|
|
// I think I want to keep this structure, but maybe rename it
|
|
|
|
|
_clientArea.left = xPos;
|
|
|
|
|
_clientArea.top = yPos;
|
|
|
|
|
_clientArea.right = xPos + windowsWidth;
|
|
|
|
|
_clientArea.bottom = yPos + windowsHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
@ -229,10 +299,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 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.
|
|
|
|
|
return DwmExtendFrameIntoClientArea(_window.get(), &margins);
|
|
|
|
|
}
|
|
|
|
@ -386,61 +459,82 @@ RECT NonClientIslandWindow::GetMaxWindowRectInPixels(const RECT* const prcSugges
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case WM_EXITSIZEMOVE:
|
|
|
|
|
{
|
|
|
|
|
ForceResize();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case WM_NCACTIVATE:
|
|
|
|
|
case WM_NCPAINT:
|
|
|
|
|
|
|
|
|
|
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())
|
|
|
|
|
{
|
|
|
|
|
// Todo this shit can get pulled too
|
|
|
|
|
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();
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
// This would paint the _entire_ window area, but I think we want to
|
|
|
|
|
// be more precise about it (in case we want different titlebar and
|
|
|
|
|
// border colors)
|
|
|
|
|
dragBarRect.left = 0;
|
|
|
|
|
dragBarRect.top = 0;
|
|
|
|
|
dragBarRect.right = RECT_WIDTH(&_windowRect);
|
|
|
|
|
dragBarRect.bottom = RECT_HEIGHT(&_windowRect);
|
|
|
|
|
|
|
|
|
|
::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;
|
|
|
|
|
|
|
|
|
|
RECT clientRect = { 0, 0, cx, yPos };
|
|
|
|
|
::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
|
|
|
|
|
// // Draw the top window border
|
|
|
|
|
// RECT clientRect = { 0, 0, cx, yPos };
|
|
|
|
|
// ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
|
|
|
|
|
|
|
|
|
|
clientRect = { 0, 0, xPos, cy };
|
|
|
|
|
::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
|
|
|
|
|
// // Draw the left window border
|
|
|
|
|
// 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 bottom window border
|
|
|
|
|
// clientRect = { 0, cy - yPos, cx, cy };
|
|
|
|
|
// ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
// // Draw the right window border
|
|
|
|
|
// clientRect = { cx - xPos, 0, cx, cy };
|
|
|
|
|
// ::FillRect(hdc.get(), &clientRect, _backgroundBrush.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
{
|
|
|
|
|
POINT point1 = {};
|
|
|
|
|