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) {