mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Simplify DPI logic (#829)
* Simply DPI logic * Apply PR comments * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Dustin L. Howett (MSFT) <duhowett@microsoft.com> * Add comments * Update src/cascadia/WindowsTerminal/BaseWindow.h Co-Authored-By: Dustin L. Howett (MSFT) <duhowett@microsoft.com> * Apply PR feedback
This commit is contained in:
parent
9f4ad6d1ce
commit
37ea2dce48
@ -89,7 +89,6 @@ public:
|
||||
}
|
||||
case CM_UPDATE_TITLE:
|
||||
{
|
||||
|
||||
SetWindowTextW(_window, _title.c_str());
|
||||
break;
|
||||
}
|
||||
@ -115,30 +114,67 @@ public:
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
_currentDpi = uDpi;
|
||||
NewScale(uDpi);
|
||||
}
|
||||
_inDpiChange = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void NewScale(UINT dpi) = 0;
|
||||
|
||||
virtual void OnResize(const UINT width, const UINT height) = 0;
|
||||
virtual void OnMinimize() = 0;
|
||||
virtual void OnRestore() = 0;
|
||||
|
||||
RECT GetWindowRect() const
|
||||
RECT GetWindowRect() const noexcept
|
||||
{
|
||||
RECT rc = { 0 };
|
||||
::GetWindowRect(_window, &rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
HWND GetHandle() noexcept
|
||||
HWND GetHandle() const noexcept
|
||||
{
|
||||
return _window;
|
||||
};
|
||||
|
||||
float GetCurrentDpiScale() const noexcept
|
||||
{
|
||||
const auto dpi = ::GetDpiForWindow(_window);
|
||||
const auto scale = static_cast<float>(dpi) / static_cast<float>(USER_DEFAULT_SCREEN_DPI);
|
||||
return scale;
|
||||
}
|
||||
|
||||
//// Gets the physical size of the client area of the HWND in _window
|
||||
SIZE GetPhysicalSize() const noexcept
|
||||
{
|
||||
RECT rect = {};
|
||||
GetClientRect(_window, &rect);
|
||||
const auto windowsWidth = rect.right - rect.left;
|
||||
const auto windowsHeight = rect.bottom - rect.top;
|
||||
return SIZE{ windowsWidth, windowsHeight };
|
||||
}
|
||||
|
||||
//// Gets the logical (in DIPs) size of a physical size specified by the parameter physicalSize
|
||||
//// Remarks:
|
||||
//// XAML coordinate system is always in Display Indepenent Pixels (a.k.a DIPs or Logical). However Win32 GDI (because of legacy reasons)
|
||||
//// in DPI mode "Per-Monitor and Per-Monitor (V2) DPI Awareness" is always in physical pixels.
|
||||
//// The formula to transform is:
|
||||
//// logical = (physical / dpi) + 0.5 // 0.5 is to ensure that we pixel snap correctly at the edges, this is necessary with odd DPIs like 1.25, 1.5, 1, .75
|
||||
//// See also:
|
||||
//// https://docs.microsoft.com/en-us/windows/desktop/LearnWin32/dpi-and-device-independent-pixels
|
||||
//// https://docs.microsoft.com/en-us/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows#per-monitor-and-per-monitor-v2-dpi-awareness
|
||||
winrt::Windows::Foundation::Size GetLogicalSize(const SIZE physicalSize) const noexcept
|
||||
{
|
||||
const auto dpi = GetCurrentDpiScale();
|
||||
// 0.5 is to ensure that we pixel snap correctly at the edges, this is necessary with odd DPIs like 1.25, 1.5, 1, .75
|
||||
const auto logicalWidth = (physicalSize.cx / dpi) + 0.5f;
|
||||
const auto logicalHeigth = (physicalSize.cy / dpi) + 0.5f;
|
||||
return winrt::Windows::Foundation::Size(logicalWidth, logicalHeigth);
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Size GetLogicalSize() const noexcept
|
||||
{
|
||||
return GetLogicalSize(GetPhysicalSize());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sends a message to our message loop to update the title of the window.
|
||||
// Arguments:
|
||||
|
||||
@ -17,10 +17,7 @@ using namespace ::Microsoft::Console::Types;
|
||||
#define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS"
|
||||
|
||||
IslandWindow::IslandWindow() noexcept :
|
||||
_currentWidth{ 0 },
|
||||
_currentHeight{ 0 },
|
||||
_interopWindowHandle{ nullptr },
|
||||
_scale{ nullptr },
|
||||
_rootGrid{ nullptr },
|
||||
_source{ nullptr },
|
||||
_pfnCreateCallback{ nullptr }
|
||||
@ -126,40 +123,25 @@ void IslandWindow::Initialize()
|
||||
// stash the child interop handle so we can resize it when the main hwnd is resized
|
||||
interop->get_WindowHandle(&_interopWindowHandle);
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
_InitXamlContent();
|
||||
}
|
||||
|
||||
_rootGrid = winrt::Windows::UI::Xaml::Controls::Grid();
|
||||
_source.Content(_rootGrid);
|
||||
|
||||
// Do a quick resize to force the island to paint
|
||||
OnSize();
|
||||
}
|
||||
|
||||
void IslandWindow::_InitXamlContent()
|
||||
{
|
||||
// setup a root grid that will be used to apply DPI scaling
|
||||
winrt::Windows::UI::Xaml::Media::ScaleTransform dpiScaleTransform;
|
||||
winrt::Windows::UI::Xaml::Controls::Grid dpiAdjustmentGrid;
|
||||
|
||||
const auto dpi = GetDpiForWindow(_window);
|
||||
const double scale = double(dpi) / double(USER_DEFAULT_SCREEN_DPI);
|
||||
|
||||
_rootGrid = dpiAdjustmentGrid;
|
||||
_scale = dpiScaleTransform;
|
||||
|
||||
_scale.ScaleX(scale);
|
||||
_scale.ScaleY(scale);
|
||||
}
|
||||
|
||||
|
||||
void IslandWindow::OnSize()
|
||||
{
|
||||
const auto physicalSize = GetPhysicalSize();
|
||||
// update the interop window size
|
||||
SetWindowPos(_interopWindowHandle, 0, 0, 0, _currentWidth, _currentHeight, SWP_SHOWWINDOW);
|
||||
_rootGrid.Width(_currentWidth);
|
||||
_rootGrid.Height(_currentHeight);
|
||||
SetWindowPos(_interopWindowHandle, 0, 0, 0, physicalSize.cx, physicalSize.cy, SWP_SHOWWINDOW);
|
||||
|
||||
if (_rootGrid)
|
||||
{
|
||||
const auto size = GetLogicalSize();
|
||||
_rootGrid.Width(size.Width);
|
||||
_rootGrid.Height(size.Height);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT IslandWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
|
||||
@ -186,63 +168,6 @@ LRESULT IslandWindow::MessageHandler(UINT const message, WPARAM const wparam, LP
|
||||
return base_type::MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the DPI of this window changes. Updates the XAML content sizing to match the client area of our window.
|
||||
// Arguments:
|
||||
// - dpi: new DPI to use. The default is 96, as defined by USER_DEFAULT_SCREEN_DPI.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::NewScale(UINT dpi)
|
||||
{
|
||||
const double scaleFactor = static_cast<double>(dpi) / static_cast<double>(USER_DEFAULT_SCREEN_DPI);
|
||||
|
||||
if (_scale != nullptr)
|
||||
{
|
||||
_scale.ScaleX(scaleFactor);
|
||||
_scale.ScaleY(scaleFactor);
|
||||
}
|
||||
|
||||
ApplyCorrection(scaleFactor);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method updates the padding that exists off the edge of the window to
|
||||
// make sure to keep the XAML content size the same as the actual window size.
|
||||
// Arguments:
|
||||
// - scaleFactor: the DPI scaling multiplier to use. for a dpi of 96, this would
|
||||
// be 1, for 144, this would be 1.5.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::ApplyCorrection(double scaleFactor)
|
||||
{
|
||||
// Get the dimensions of the XAML content grid.
|
||||
const auto realWidth = _rootGrid.Width();
|
||||
const auto realHeight = _rootGrid.Height();
|
||||
|
||||
// Scale those dimensions by our dpi scaling. This is how big the XAML
|
||||
// content thinks it should be.
|
||||
const auto dpiAwareWidth = realWidth * scaleFactor;
|
||||
const auto dpiAwareHeight = realHeight * scaleFactor;
|
||||
|
||||
// Get the difference between what xaml thinks and the actual client area
|
||||
// of our window.
|
||||
const auto deltaX = dpiAwareWidth - realWidth;
|
||||
const auto deltaY = dpiAwareHeight - realHeight;
|
||||
|
||||
// correct for the scaling we applied above
|
||||
const auto dividedDeltaX = deltaX / scaleFactor;
|
||||
const auto dividedDeltaY = deltaY / scaleFactor;
|
||||
|
||||
const double rightCorrection = dividedDeltaX;
|
||||
const double bottomCorrection = dividedDeltaY;
|
||||
|
||||
// Apply padding to the root grid, so that it's content is the same size as
|
||||
// our actual window size.
|
||||
// Without this, XAML content will seem to spill off the side/bottom of the window
|
||||
_rootGrid.Padding(Xaml::ThicknessHelper::FromLengths(0, 0, rightCorrection, bottomCorrection));
|
||||
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the window has been resized (or maximized)
|
||||
// Arguments:
|
||||
@ -250,13 +175,7 @@ void IslandWindow::ApplyCorrection(double scaleFactor)
|
||||
// - height: the new height of the window _in pixels_
|
||||
void IslandWindow::OnResize(const UINT width, const UINT height)
|
||||
{
|
||||
_currentWidth = width;
|
||||
_currentHeight = height;
|
||||
if (nullptr != _rootGrid)
|
||||
{
|
||||
OnSize();
|
||||
ApplyCorrection(_scale.ScaleX());
|
||||
}
|
||||
OnSize();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -276,6 +195,5 @@ void IslandWindow::OnRestore()
|
||||
void IslandWindow::SetRootContent(winrt::Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
_rootGrid.Children().Clear();
|
||||
ApplyCorrection(_scale.ScaleX());
|
||||
_rootGrid.Children().Append(content);
|
||||
}
|
||||
|
||||
@ -17,8 +17,6 @@ public:
|
||||
virtual void OnSize();
|
||||
|
||||
virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
|
||||
void ApplyCorrection(double scaleFactor);
|
||||
void NewScale(UINT dpi) override;
|
||||
void OnResize(const UINT width, const UINT height) override;
|
||||
void OnMinimize() override;
|
||||
void OnRestore() override;
|
||||
@ -29,18 +27,13 @@ public:
|
||||
void SetCreateCallback(std::function<void(const HWND, const RECT)> pfn) noexcept;
|
||||
|
||||
protected:
|
||||
unsigned int _currentWidth;
|
||||
unsigned int _currentHeight;
|
||||
|
||||
HWND _interopWindowHandle;
|
||||
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _source;
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::ScaleTransform _scale;
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _rootGrid;
|
||||
|
||||
std::function<void(const HWND, const RECT)> _pfnCreateCallback;
|
||||
|
||||
void _InitXamlContent();
|
||||
void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept;
|
||||
};
|
||||
|
||||
@ -68,7 +68,6 @@ void NonClientIslandWindow::Initialize()
|
||||
void NonClientIslandWindow::SetNonClientContent(winrt::Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
_nonClientRootGrid.Children().Clear();
|
||||
ApplyCorrection(_scale.ScaleX());
|
||||
_nonClientRootGrid.Children().Append(content);
|
||||
}
|
||||
|
||||
@ -91,13 +90,15 @@ void NonClientIslandWindow::SetNonClientHeight(const int contentHeight) noexcept
|
||||
// content, in window coordinates.
|
||||
Viewport NonClientIslandWindow::GetTitlebarContentArea() const noexcept
|
||||
{
|
||||
const auto dpi = GetDpiForWindow(_window);
|
||||
const double scale = static_cast<double>(dpi) / static_cast<double>(USER_DEFAULT_SCREEN_DPI);
|
||||
const auto scale = GetCurrentDpiScale();
|
||||
|
||||
const auto titlebarContentHeight = _titlebarUnscaledContentHeight * scale;
|
||||
const auto titlebarMarginRight = _titlebarMarginRight;
|
||||
|
||||
auto titlebarWidth = _currentWidth - (_windowMarginSides + titlebarMarginRight);
|
||||
const auto physicalSize = GetPhysicalSize();
|
||||
const auto clientWidth = physicalSize.cx;
|
||||
|
||||
auto titlebarWidth = clientWidth - (_windowMarginSides + titlebarMarginRight);
|
||||
// Adjust for maximized margins
|
||||
titlebarWidth -= (_maximizedMargins.cxLeftWidth + _maximizedMargins.cxRightWidth);
|
||||
|
||||
@ -133,8 +134,9 @@ Viewport NonClientIslandWindow::GetClientContentArea() const noexcept
|
||||
COORD clientOrigin = { static_cast<short>(margins.cxLeftWidth),
|
||||
static_cast<short>(margins.cyTopHeight) };
|
||||
|
||||
auto clientWidth = _currentWidth;
|
||||
auto clientHeight = _currentHeight;
|
||||
const auto physicalSize = GetPhysicalSize();
|
||||
auto clientWidth = physicalSize.cx;
|
||||
auto clientHeight = physicalSize.cy;
|
||||
|
||||
// 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
|
||||
@ -177,8 +179,13 @@ void NonClientIslandWindow::OnSize()
|
||||
clientArea.Height(),
|
||||
SWP_SHOWWINDOW);
|
||||
|
||||
_rootGrid.Width(clientArea.Width());
|
||||
_rootGrid.Height(clientArea.Height());
|
||||
if (_rootGrid)
|
||||
{
|
||||
const SIZE physicalSize{ clientArea.Width(), clientArea.Height() };
|
||||
const auto logicalSize = GetLogicalSize(physicalSize);
|
||||
_rootGrid.Width(logicalSize.Width);
|
||||
_rootGrid.Height(logicalSize.Height);
|
||||
}
|
||||
|
||||
// update the interop window size
|
||||
SetWindowPos(_nonClientInteropWindowHandle, 0,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user