From 089ea9af227fdffdf872348923e1c12682e63029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Fri, 31 Aug 2018 13:33:48 +0200 Subject: [PATCH] Add GLFW_SCALE_TO_MONITOR This adds the GLFW_SCALE_TO_MONITOR window hint for automatically resizing the content area of a window to the requested size times the monitor content scale each time it is placed on a new monitor. This only applies to windowed mode windows and includes the initial placement at window creation. This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11. Platforms like macOS instead change the resolution of the framebuffer independently of the window size. Related to #676. Related to #1115. --- docs/news.dox | 4 ++++ docs/window.dox | 18 ++++++++++++++++++ include/GLFW/glfw3.h | 4 ++++ src/internal.h | 1 + src/win32_platform.h | 1 + src/win32_window.c | 30 ++++++++++++++++++++++++++---- src/window.c | 3 +++ src/x11_window.c | 13 +++++++++++-- tests/gamma.c | 2 ++ tests/inputlag.c | 2 ++ tests/joysticks.c | 2 ++ tests/opacity.c | 2 ++ 12 files changed, 76 insertions(+), 6 deletions(-) diff --git a/docs/news.dox b/docs/news.dox index 34adf5be..9e75d7fd 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -73,6 +73,10 @@ glfwGetWindowContentScale and @ref glfwGetMonitorContentScale. Changes of the content scale of a window can be received with the window content scale callback, set with @ref glfwSetWindowContentScaleCallback. +The @ref GLFW_SCALE_TO_MONITOR window hint enables automatic resizing of a +window by the content scale of the monitor it is placed, on platforms like +Windows and X11 where this is necessary. + @see @ref window_scale diff --git a/docs/window.dox b/docs/window.dox index 386fb9c7..ca3f364f 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -238,6 +238,17 @@ does not affect window decorations. Possible values are `GLFW_TRUE` and __GLFW_FOCUS_ON_SHOW__ specifies whether the window will be given input focus when @ref glfwShowWindow is called. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. +@anchor GLFW_SCALE_TO_MONITOR +__GLFW_SCALE_TO_MONITOR__ specified whether the window content area should be +resized based on the [monitor content scale](@ref monitor_scale) of any monitor +it is placed on. This includes the initial placement when the window is +created. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. + +This hint only has an effect on platforms where screen coordinates and pixels +always map 1:1 such as Windows and X11. On platforms like macOS the resolution +of the framebuffer is changed independently of the window size. + + @subsubsection window_hints_fb Framebuffer related hints @anchor GLFW_RED_BITS @@ -493,6 +504,7 @@ GLFW_MAXIMIZED | `GLFW_FALSE` | `GLFW_TRUE` or `GL GLFW_CENTER_CURSOR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_TRANSPARENT_FRAMEBUFFER | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_FOCUS_ON_SHOW | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_SCALE_TO_MONITOR | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_GREEN_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_BLUE_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` @@ -716,6 +728,12 @@ void window_content_scale_callback(GLFWwindow* window, float xscale, float yscal } @endcode +On platforms where pixels and screen coordinates always map 1:1, the window +will need to be resized to appear the same size when it is moved to a monitor +with a different content scale. To have this done automatically both when the +window is created and when its content scale later changes, set the @ref +GLFW_SCALE_TO_MONITOR window hint. + @subsection window_sizelimits Window size limits diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index a4c64f48..1fc8fe55 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -973,6 +973,10 @@ extern "C" { * [attribute](@ref GLFW_CLIENT_API_attrib). */ #define GLFW_CONTEXT_CREATION_API 0x0002200B +/*! @brief Window content area scaling window + * [window hint](@ref GLFW_SCALE_TO_MONITOR). + */ +#define GLFW_SCALE_TO_MONITOR 0x0002200C #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 #define GLFW_COCOA_FRAME_NAME 0x00023002 diff --git a/src/internal.h b/src/internal.h index 9fc626dd..81cd9618 100644 --- a/src/internal.h +++ b/src/internal.h @@ -268,6 +268,7 @@ struct _GLFWwndconfig GLFWbool maximized; GLFWbool centerCursor; GLFWbool focusOnShow; + GLFWbool scaleToMonitor; struct { GLFWbool retina; char frameName[256]; diff --git a/src/win32_platform.h b/src/win32_platform.h index 8dddd218..829eba20 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -306,6 +306,7 @@ typedef struct _GLFWwindowWin32 GLFWbool maximized; // Whether to enable framebuffer transparency on DWM GLFWbool transparent; + GLFWbool scaleToMonitor; // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY; diff --git a/src/win32_window.c b/src/win32_window.c index c8ceabb4..858931bc 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1063,6 +1063,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_GETDPISCALEDSIZE: { + if (window->win32.scaleToMonitor) + break; + // Adjust the window size to keep the client area size constant if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) { @@ -1230,15 +1233,34 @@ static int createNativeWindow(_GLFWwindow* window, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } - // Adjust window size to account for the DPI scaled window frame + window->win32.scaleToMonitor = wndconfig->scaleToMonitor; + + // Adjust window size to account for DPI scaling of the window frame and + // optionally DPI scaling of the client area // This cannot be done until we know what monitor it was placed on - if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32() && !window->monitor) + if (!window->monitor) { RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; + + if (wndconfig->scaleToMonitor) + { + float xscale, yscale; + _glfwPlatformGetWindowContentScale(window, &xscale, &yscale); + rect.right = (int) (rect.right * xscale); + rect.bottom = (int) (rect.bottom * yscale); + } + ClientToScreen(window->win32.handle, (POINT*) &rect.left); ClientToScreen(window->win32.handle, (POINT*) &rect.right); - AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, - GetDpiForWindow(window->win32.handle)); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, + GetDpiForWindow(window->win32.handle)); + } + else + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, diff --git a/src/window.c b/src/window.c index 4ed415ca..4e365cb4 100644 --- a/src/window.c +++ b/src/window.c @@ -369,6 +369,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_COCOA_GRAPHICS_SWITCHING: _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; return; + case GLFW_SCALE_TO_MONITOR: + _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE; + return; case GLFW_CENTER_CURSOR: _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; return; diff --git a/src/x11_window.c b/src/x11_window.c index 40af37b2..c01cf17e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -592,6 +592,15 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, Visual* visual, int depth) { + int width = wndconfig->width; + int height = wndconfig->height; + + if (wndconfig->scaleToMonitor) + { + width *= _glfw.x11.contentScaleX; + height *= _glfw.x11.contentScaleY; + } + // Create a colormap based on the visual used by the current context window->x11.colormap = XCreateColormap(_glfw.x11.display, _glfw.x11.root, @@ -617,7 +626,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, window->x11.handle = XCreateWindow(_glfw.x11.display, _glfw.x11.root, 0, 0, - wndconfig->width, wndconfig->height, + width, height, 0, // Border width depth, // Color depth InputOutput, @@ -720,7 +729,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, XFree(hints); } - updateNormalHints(window, wndconfig->width, wndconfig->height); + updateNormalHints(window, width, height); // Set ICCCM WM_CLASS property { diff --git a/tests/gamma.c b/tests/gamma.c index 6fca690d..795a3054 100644 --- a/tests/gamma.c +++ b/tests/gamma.c @@ -99,6 +99,8 @@ int main(int argc, char** argv) monitor = glfwGetPrimaryMonitor(); + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); + window = glfwCreateWindow(800, 400, "Gamma Test", NULL, NULL); if (!window) { diff --git a/tests/inputlag.c b/tests/inputlag.c index eee4544c..79909a9f 100644 --- a/tests/inputlag.c +++ b/tests/inputlag.c @@ -200,6 +200,8 @@ int main(int argc, char** argv) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); + window = glfwCreateWindow(width, height, "Input lag test", monitor, NULL); if (!window) { diff --git a/tests/joysticks.c b/tests/joysticks.c index 1d299375..dc406dc9 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -180,6 +180,8 @@ int main(void) if (!glfwInit()) exit(EXIT_FAILURE); + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); + window = glfwCreateWindow(800, 600, "Joystick Test", NULL, NULL); if (!window) { diff --git a/tests/opacity.c b/tests/opacity.c index b8e9d753..8338d242 100644 --- a/tests/opacity.c +++ b/tests/opacity.c @@ -57,6 +57,8 @@ int main(int argc, char** argv) if (!glfwInit()) exit(EXIT_FAILURE); + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); + window = glfwCreateWindow(400, 400, "Opacity", NULL, NULL); if (!window) {