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.
This commit is contained in:
Camilla Löwy 2018-08-31 13:33:48 +02:00
parent 5294439595
commit 089ea9af22
12 changed files with 76 additions and 6 deletions

View File

@ -73,6 +73,10 @@ glfwGetWindowContentScale and @ref glfwGetMonitorContentScale.
Changes of the content scale of a window can be received with the window content Changes of the content scale of a window can be received with the window content
scale callback, set with @ref glfwSetWindowContentScaleCallback. 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 @see @ref window_scale

View File

@ -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 __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`. 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 @subsubsection window_hints_fb Framebuffer related hints
@anchor GLFW_RED_BITS @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_CENTER_CURSOR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_TRANSPARENT_FRAMEBUFFER | `GLFW_FALSE` | `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_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_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE`
GLFW_GREEN_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` 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 @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 @subsection window_sizelimits Window size limits

View File

@ -973,6 +973,10 @@ extern "C" {
* [attribute](@ref GLFW_CLIENT_API_attrib). * [attribute](@ref GLFW_CLIENT_API_attrib).
*/ */
#define GLFW_CONTEXT_CREATION_API 0x0002200B #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_RETINA_FRAMEBUFFER 0x00023001
#define GLFW_COCOA_FRAME_NAME 0x00023002 #define GLFW_COCOA_FRAME_NAME 0x00023002

View File

@ -268,6 +268,7 @@ struct _GLFWwndconfig
GLFWbool maximized; GLFWbool maximized;
GLFWbool centerCursor; GLFWbool centerCursor;
GLFWbool focusOnShow; GLFWbool focusOnShow;
GLFWbool scaleToMonitor;
struct { struct {
GLFWbool retina; GLFWbool retina;
char frameName[256]; char frameName[256];

View File

@ -306,6 +306,7 @@ typedef struct _GLFWwindowWin32
GLFWbool maximized; GLFWbool maximized;
// Whether to enable framebuffer transparency on DWM // Whether to enable framebuffer transparency on DWM
GLFWbool transparent; GLFWbool transparent;
GLFWbool scaleToMonitor;
// The last received cursor position, regardless of source // The last received cursor position, regardless of source
int lastCursorPosX, lastCursorPosY; int lastCursorPosX, lastCursorPosY;

View File

@ -1063,6 +1063,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_GETDPISCALEDSIZE: case WM_GETDPISCALEDSIZE:
{ {
if (window->win32.scaleToMonitor)
break;
// Adjust the window size to keep the client area size constant // Adjust the window size to keep the client area size constant
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
{ {
@ -1230,15 +1233,34 @@ static int createNativeWindow(_GLFWwindow* window,
WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); 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 // 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 }; 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.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right); 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, SetWindowPos(window->win32.handle, NULL,
rect.left, rect.top, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top, rect.right - rect.left, rect.bottom - rect.top,

View File

@ -369,6 +369,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_GRAPHICS_SWITCHING: case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
return; return;
case GLFW_SCALE_TO_MONITOR:
_glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_CENTER_CURSOR: case GLFW_CENTER_CURSOR:
_glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE;
return; return;

View File

@ -592,6 +592,15 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig, const _GLFWwndconfig* wndconfig,
Visual* visual, int depth) 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 // Create a colormap based on the visual used by the current context
window->x11.colormap = XCreateColormap(_glfw.x11.display, window->x11.colormap = XCreateColormap(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
@ -617,7 +626,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
window->x11.handle = XCreateWindow(_glfw.x11.display, window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
0, 0, 0, 0,
wndconfig->width, wndconfig->height, width, height,
0, // Border width 0, // Border width
depth, // Color depth depth, // Color depth
InputOutput, InputOutput,
@ -720,7 +729,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
XFree(hints); XFree(hints);
} }
updateNormalHints(window, wndconfig->width, wndconfig->height); updateNormalHints(window, width, height);
// Set ICCCM WM_CLASS property // Set ICCCM WM_CLASS property
{ {

View File

@ -99,6 +99,8 @@ int main(int argc, char** argv)
monitor = glfwGetPrimaryMonitor(); monitor = glfwGetPrimaryMonitor();
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
window = glfwCreateWindow(800, 400, "Gamma Test", NULL, NULL); window = glfwCreateWindow(800, 400, "Gamma Test", NULL, NULL);
if (!window) if (!window)
{ {

View File

@ -200,6 +200,8 @@ int main(int argc, char** argv)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
window = glfwCreateWindow(width, height, "Input lag test", monitor, NULL); window = glfwCreateWindow(width, height, "Input lag test", monitor, NULL);
if (!window) if (!window)
{ {

View File

@ -180,6 +180,8 @@ int main(void)
if (!glfwInit()) if (!glfwInit())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
window = glfwCreateWindow(800, 600, "Joystick Test", NULL, NULL); window = glfwCreateWindow(800, 600, "Joystick Test", NULL, NULL);
if (!window) if (!window)
{ {

View File

@ -57,6 +57,8 @@ int main(int argc, char** argv)
if (!glfwInit()) if (!glfwInit())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
window = glfwCreateWindow(400, 400, "Opacity", NULL, NULL); window = glfwCreateWindow(400, 400, "Opacity", NULL, NULL);
if (!window) if (!window)
{ {