Win32: Add support for Per-Monitor V2 awareness

This adds basic support for the Per-Monitor V2 level of DPI awareness
in Windows 10, which allows for automatic DPI scaling of window
decorations.

This commit does not include resizing the window content area to match
the new window content scale.

Related to #1115.
Fixes #1294.
This commit is contained in:
Camilla Löwy
2018-06-07 19:01:07 +02:00
parent b3efdcb38a
commit 5294439595
4 changed files with 259 additions and 48 deletions
+153 -19
View File
@@ -186,14 +186,20 @@ static HICON createIcon(const GLFWimage* image,
return handle;
}
// Translate client window size to full window size according to styles
// Translate client window size to full window size according to styles and DPI
//
static void getFullWindowSize(DWORD style, DWORD exStyle,
int clientWidth, int clientHeight,
int* fullWidth, int* fullHeight)
int* fullWidth, int* fullHeight,
UINT dpi)
{
RECT rect = { 0, 0, clientWidth, clientHeight };
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
else
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
*fullWidth = rect.right - rect.left;
*fullHeight = rect.bottom - rect.top;
}
@@ -206,7 +212,8 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
const float ratio = (float) window->numer / (float) window->denom;
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff);
0, 0, &xoff, &yoff,
GetDpiForWindow(window->win32.handle));
if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT ||
edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
@@ -337,7 +344,16 @@ static void updateWindowStyles(const _GLFWwindow* window)
style |= getWindowStyle(window);
GetClientRect(window->win32.handle, &rect);
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, style, FALSE,
getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
SetWindowLongW(window->win32.handle, GWL_STYLE, style);
@@ -557,9 +573,18 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
if (!window)
{
// This is the message handling for the hidden helper window
// and for a regular window during its initial creation
switch (uMsg)
{
case WM_NCCREATE:
{
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
EnableNonClientDpiScaling(hWnd);
break;
}
case WM_DISPLAYCHANGE:
_glfwPollMonitorsWin32();
break;
@@ -982,7 +1007,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
break;
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff);
0, 0, &xoff, &yoff,
GetDpiForWindow(window->win32.handle));
if (window->minwidth != GLFW_DONT_CARE &&
window->minheight != GLFW_DONT_CARE)
@@ -1035,10 +1061,49 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
return 0;
}
case WM_GETDPISCALEDSIZE:
{
// Adjust the window size to keep the client area size constant
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
{
RECT source = {0}, target = {0};
SIZE* size = (SIZE*) lParam;
AdjustWindowRectExForDpi(&source, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
AdjustWindowRectExForDpi(&target, getWindowStyle(window),
FALSE, getWindowExStyle(window),
LOWORD(wParam));
size->cx += (target.right - target.left) -
(source.right - source.left);
size->cy += (target.bottom - target.top) -
(source.bottom - source.top);
return TRUE;
}
break;
}
case WM_DPICHANGED:
{
const float xscale = HIWORD(wParam) / 96.f;
const float yscale = LOWORD(wParam) / 96.f;
const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
// Only apply the suggested size if the OS is new enough to have
// sent a WM_GETDPISCALEDSIZE before this
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
{
RECT* suggested = (RECT*) lParam;
SetWindowPos(window->win32.handle, HWND_TOP,
suggested->left,
suggested->top,
suggested->right - suggested->left,
suggested->bottom - suggested->top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
_glfwInputWindowContentScale(window, xscale, yscale);
break;
}
@@ -1125,7 +1190,8 @@ static int createNativeWindow(_GLFWwindow* window,
getFullWindowSize(style, exStyle,
wndconfig->width, wndconfig->height,
&fullWidth, &fullHeight);
&fullWidth, &fullHeight,
USER_DEFAULT_SCREEN_DPI);
}
wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
@@ -1164,6 +1230,21 @@ static int createNativeWindow(_GLFWwindow* window,
WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
}
// Adjust window size to account for the DPI scaled window frame
// This cannot be done until we know what monitor it was placed on
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32() && !window->monitor)
{
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
GetDpiForWindow(window->win32.handle));
SetWindowPos(window->win32.handle, NULL,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
DragAcceptFiles(window->win32.handle, TRUE);
if (fbconfig->transparent)
@@ -1360,8 +1441,19 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{
RECT rect = { xpos, ypos, xpos, ypos };
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
}
@@ -1390,8 +1482,19 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
else
{
RECT rect = { 0, 0, width, height };
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, HWND_TOP,
0, 0, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
@@ -1446,8 +1549,18 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
_glfwPlatformGetWindowSize(window, &width, &height);
SetRect(&rect, 0, 0, width, height);
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
if (left)
*left = -rect.left;
@@ -1523,8 +1636,19 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else
{
RECT rect = { xpos, ypos, xpos + width, ypos + height };
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, HWND_TOP,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
@@ -1584,8 +1708,18 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else
after = HWND_NOTOPMOST;
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
GetDpiForWindow(window->win32.handle));
}
else
{
AdjustWindowRectEx(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window));
}
SetWindowPos(window->win32.handle, after,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,