HighDPI: remove SWP_NOSIZE in WIN_SetWindowPosition
If the move results in a DPI change, we need to allow the window to resize (e.g. AdjustWindowRectExForDpi frame sizes are different). - WM_DPICHANGED: Don't assume WM_GETDPISCALEDSIZE is always called for PMv2 awareness - it's only called during interactive dragging. - WIN_AdjustWindowRectWithStyle: always calculate final window size including frame based on the destination rect, not based on the current window DPI. - Update wmmsg.h to include WM_GETDPISCALEDSIZE (for WMMSG_DEBUG) - WIN_AdjustWindowRectWithStyle: add optional logging - WM_GETMINMAXINFO: add optional HIGHDPI_DEBUG logging - WM_DPICHANGED: fix potentially clobbering data->expected_resize Together these changes fix the following scenario: - launch testwm2 with the SDL_WINDOWS_DPI_AWARENESS=permonitorv2 environment variable - Windows 10 21H2 (OS Build 19044.1706) - Left (primary) monitor: 3840x2160, 125% scaling - Right (secondary) monitor: 2560x1440, 100% scaling - Alt+Enter, Alt+Enter (to enter + leave desktop fullscreen), Alt+Right (to move window to right monitor). Ensure the window client area stays 640x480. Drag the window back to the 125% monitor, ensure client area stays 640x480.main
parent
51ebefeeee
commit
d3b970d4d5
|
@ -1088,19 +1088,25 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
inside their function, so I have to do it here.
|
inside their function, so I have to do it here.
|
||||||
*/
|
*/
|
||||||
BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||||
|
UINT dpi;
|
||||||
|
|
||||||
|
dpi = 96;
|
||||||
size.top = 0;
|
size.top = 0;
|
||||||
size.left = 0;
|
size.left = 0;
|
||||||
size.bottom = h;
|
size.bottom = h;
|
||||||
size.right = w;
|
size.right = w;
|
||||||
|
|
||||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||||
UINT dpi = data->videodata->GetDpiForWindow(hwnd);
|
dpi = data->videodata->GetDpiForWindow(hwnd);
|
||||||
data->videodata->AdjustWindowRectExForDpi(&size, style, menu, 0, dpi);
|
data->videodata->AdjustWindowRectExForDpi(&size, style, menu, 0, dpi);
|
||||||
} else {
|
} else {
|
||||||
AdjustWindowRectEx(&size, style, menu, 0);
|
AdjustWindowRectEx(&size, style, menu, 0);
|
||||||
}
|
}
|
||||||
w = size.right - size.left;
|
w = size.right - size.left;
|
||||||
h = size.bottom - size.top;
|
h = size.bottom - size.top;
|
||||||
|
#ifdef HIGHDPI_DEBUG
|
||||||
|
SDL_Log("WM_GETMINMAXINFO: max window size: %dx%d using dpi: %u", w, h, dpi);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix our size to the current size */
|
/* Fix our size to the current size */
|
||||||
|
@ -1422,7 +1428,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
case WM_GETDPISCALEDSIZE:
|
case WM_GETDPISCALEDSIZE:
|
||||||
/* Windows 10 Creators Update+ */
|
/* Windows 10 Creators Update+ */
|
||||||
/* Documented as only being sent to windows that are per-monitor V2 DPI aware. */
|
/* Documented as only being sent to windows that are per-monitor V2 DPI aware.
|
||||||
|
|
||||||
|
Experimentation shows it's only sent during interactive dragging, not in response to
|
||||||
|
SetWindowPos. */
|
||||||
if (data->videodata->GetDpiForWindow && data->videodata->AdjustWindowRectExForDpi) {
|
if (data->videodata->GetDpiForWindow && data->videodata->AdjustWindowRectExForDpi) {
|
||||||
/* Windows expects applications to scale their window rects linearly
|
/* Windows expects applications to scale their window rects linearly
|
||||||
when dragging between monitors with different DPI's.
|
when dragging between monitors with different DPI's.
|
||||||
|
@ -1490,6 +1499,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
const int newDPI = HIWORD(wParam);
|
const int newDPI = HIWORD(wParam);
|
||||||
RECT* const suggestedRect = (RECT*)lParam;
|
RECT* const suggestedRect = (RECT*)lParam;
|
||||||
|
SDL_bool setExpectedResize = SDL_FALSE;
|
||||||
int w, h;
|
int w, h;
|
||||||
|
|
||||||
#ifdef HIGHDPI_DEBUG
|
#ifdef HIGHDPI_DEBUG
|
||||||
|
@ -1497,12 +1507,28 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
|
suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 means that
|
if (data->expected_resize) {
|
||||||
WM_GETDPISCALEDSIZE will have been called, so we can use suggestedRect. */
|
/* This DPI change is coming from an explicit SetWindowPos call within SDL.
|
||||||
|
Assume all call sites are calculating the DPI-aware frame correctly, so
|
||||||
|
we don't need to do any further adjustment. */
|
||||||
|
#ifdef HIGHDPI_DEBUG
|
||||||
|
SDL_Log("WM_DPICHANGED: Doing nothing, assuming window is already sized correctly");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive user-initiated resizing/movement */
|
||||||
|
|
||||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||||
|
/* WM_GETDPISCALEDSIZE should have been called prior, so we can trust the given
|
||||||
|
suggestedRect. */
|
||||||
w = suggestedRect->right - suggestedRect->left;
|
w = suggestedRect->right - suggestedRect->left;
|
||||||
h = suggestedRect->bottom - suggestedRect->top;
|
h = suggestedRect->bottom - suggestedRect->top;
|
||||||
} else {
|
|
||||||
|
#ifdef HIGHDPI_DEBUG
|
||||||
|
SDL_Log("WM_DPICHANGED: using suggestedRect");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
RECT rect = { 0, 0, data->window->w, data->window->h };
|
RECT rect = { 0, 0, data->window->w, data->window->h };
|
||||||
const DWORD style = GetWindowLong(hwnd, GWL_STYLE);
|
const DWORD style = GetWindowLong(hwnd, GWL_STYLE);
|
||||||
const BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
const BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||||
|
@ -1521,7 +1547,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
suggestedRect->left, suggestedRect->top, w, h);
|
suggestedRect->left, suggestedRect->top, w, h);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
data->expected_resize = SDL_TRUE;
|
if (!data->expected_resize) {
|
||||||
|
setExpectedResize = SDL_TRUE;
|
||||||
|
data->expected_resize = SDL_TRUE;
|
||||||
|
}
|
||||||
SetWindowPos(hwnd,
|
SetWindowPos(hwnd,
|
||||||
NULL,
|
NULL,
|
||||||
suggestedRect->left,
|
suggestedRect->left,
|
||||||
|
@ -1529,7 +1558,13 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
data->expected_resize = SDL_FALSE;
|
if (setExpectedResize) {
|
||||||
|
/* Only unset data->expected_resize if we set it above.
|
||||||
|
WM_DPICHANGED can happen inside a block of code that sets data->expected_resize,
|
||||||
|
e.g. WIN_SetWindowPositionInternal.
|
||||||
|
*/
|
||||||
|
data->expected_resize = SDL_FALSE;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#define SWP_NOCOPYBITS 0
|
#define SWP_NOCOPYBITS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* #define HIGHDPI_DEBUG */
|
||||||
|
|
||||||
/* Fake window to help with DirectInput events. */
|
/* Fake window to help with DirectInput events. */
|
||||||
HWND SDL_HelperWindow = NULL;
|
HWND SDL_HelperWindow = NULL;
|
||||||
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
|
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
|
||||||
|
@ -114,13 +116,14 @@ GetWindowStyle(SDL_Window * window)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current,
|
WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
|
||||||
SDL_bool force_ignore_window_dpi)
|
|
||||||
{
|
{
|
||||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||||
SDL_VideoData* videodata = SDL_GetVideoDevice() ? SDL_GetVideoDevice()->driverdata : NULL;
|
SDL_VideoData* videodata = SDL_GetVideoDevice() ? SDL_GetVideoDevice()->driverdata : NULL;
|
||||||
RECT rect;
|
RECT rect;
|
||||||
|
UINT dpi;
|
||||||
|
|
||||||
|
dpi = 96;
|
||||||
rect.left = 0;
|
rect.left = 0;
|
||||||
rect.top = 0;
|
rect.top = 0;
|
||||||
rect.right = (use_current ? window->w : window->windowed.w);
|
rect.right = (use_current ? window->w : window->windowed.w);
|
||||||
|
@ -133,33 +136,21 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
|
||||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||||
/* With per-monitor v2, the window border/titlebar size depend on the DPI, so we need to call AdjustWindowRectExForDpi instead of
|
/* With per-monitor v2, the window border/titlebar size depend on the DPI, so we need to call AdjustWindowRectExForDpi instead of
|
||||||
AdjustWindowRectEx. */
|
AdjustWindowRectEx. */
|
||||||
UINT dpi;
|
|
||||||
|
UINT unused;
|
||||||
|
RECT screen_rect;
|
||||||
|
HMONITOR mon;
|
||||||
|
|
||||||
if (data && !force_ignore_window_dpi) {
|
screen_rect.left = (use_current ? window->x : window->windowed.x);
|
||||||
/* The usual case - we have a HWND, so we can look up the DPI to use. */
|
screen_rect.top = (use_current ? window->y : window->windowed.y);
|
||||||
dpi = videodata->GetDpiForWindow(data->hwnd);
|
screen_rect.right = screen_rect.left + (use_current ? window->w : window->windowed.w);
|
||||||
} else {
|
screen_rect.bottom = screen_rect.top + (use_current ? window->h : window->windowed.h);
|
||||||
/* In this case we guess the window DPI based on its rectangle on the screen.
|
|
||||||
|
|
||||||
This happens at creation time of an SDL window, before we have a HWND,
|
|
||||||
and also in a bug workaround (when force_ignore_window_dpi is SDL_TRUE
|
|
||||||
- see WIN_SetWindowFullscreen).
|
|
||||||
*/
|
|
||||||
UINT unused;
|
|
||||||
RECT screen_rect;
|
|
||||||
HMONITOR mon;
|
|
||||||
|
|
||||||
screen_rect.left = (use_current ? window->x : window->windowed.x);
|
mon = MonitorFromRect(&screen_rect, MONITOR_DEFAULTTONEAREST);
|
||||||
screen_rect.top = (use_current ? window->y : window->windowed.y);
|
|
||||||
screen_rect.right = screen_rect.left + (use_current ? window->w : window->windowed.w);
|
|
||||||
screen_rect.bottom = screen_rect.top + (use_current ? window->h : window->windowed.h);
|
|
||||||
|
|
||||||
mon = MonitorFromRect(&screen_rect, MONITOR_DEFAULTTONEAREST);
|
/* GetDpiForMonitor docs promise to return the same hdpi / vdpi */
|
||||||
|
if (videodata->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &dpi, &unused) != S_OK) {
|
||||||
/* GetDpiForMonitor docs promise to return the same hdpi / vdpi */
|
dpi = 96;
|
||||||
if (videodata->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &dpi, &unused) != S_OK) {
|
|
||||||
dpi = 96;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, dpi);
|
videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, dpi);
|
||||||
|
@ -172,6 +163,15 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
|
||||||
*y = (use_current ? window->y : window->windowed.y) + rect.top;
|
*y = (use_current ? window->y : window->windowed.y) + rect.top;
|
||||||
*width = (rect.right - rect.left);
|
*width = (rect.right - rect.left);
|
||||||
*height = (rect.bottom - rect.top);
|
*height = (rect.bottom - rect.top);
|
||||||
|
|
||||||
|
#ifdef HIGHDPI_DEBUG
|
||||||
|
SDL_Log("WIN_AdjustWindowRectWithStyle: in: %d, %d, %dx%d, returning: %d, %d, %dx%d, used dpi %d for frame calculation",
|
||||||
|
(use_current ? window->x : window->windowed.x),
|
||||||
|
(use_current ? window->y : window->windowed.y),
|
||||||
|
(use_current ? window->w : window->windowed.w),
|
||||||
|
(use_current ? window->h : window->windowed.h),
|
||||||
|
*x, *y, *width, *height, dpi);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -184,7 +184,7 @@ WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height
|
||||||
|
|
||||||
style = GetWindowLong(hwnd, GWL_STYLE);
|
style = GetWindowLong(hwnd, GWL_STYLE);
|
||||||
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||||
WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current, SDL_FALSE);
|
WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -279,7 +279,9 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
||||||
int x, y;
|
int x, y;
|
||||||
/* Figure out what the window area will be */
|
/* Figure out what the window area will be */
|
||||||
WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
|
WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
|
||||||
|
data->expected_resize = SDL_TRUE;
|
||||||
SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
|
SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
|
data->expected_resize = SDL_FALSE;
|
||||||
} else {
|
} else {
|
||||||
window->w = w;
|
window->w = w;
|
||||||
window->h = h;
|
window->h = h;
|
||||||
|
@ -395,7 +397,7 @@ WIN_CreateWindow(_THIS, SDL_Window * window)
|
||||||
style |= GetWindowStyle(window);
|
style |= GetWindowStyle(window);
|
||||||
|
|
||||||
/* Figure out what the window area will be */
|
/* Figure out what the window area will be */
|
||||||
WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE, SDL_FALSE);
|
WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE);
|
||||||
|
|
||||||
hwnd =
|
hwnd =
|
||||||
CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, parent, NULL,
|
CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, parent, NULL,
|
||||||
|
@ -580,7 +582,10 @@ WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
|
||||||
void
|
void
|
||||||
WIN_SetWindowPosition(_THIS, SDL_Window * window)
|
WIN_SetWindowPosition(_THIS, SDL_Window * window)
|
||||||
{
|
{
|
||||||
WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
|
/* HighDPI support: removed SWP_NOSIZE. If the move results in a DPI change, we need to allow
|
||||||
|
* the window to resize (e.g. AdjustWindowRectExForDpi frame sizes are different).
|
||||||
|
*/
|
||||||
|
WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOACTIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -820,13 +825,7 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
|
||||||
}
|
}
|
||||||
|
|
||||||
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
|
||||||
/* HighDPI bug workaround - when leaving exclusive fullscreen, the window DPI reported
|
WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
|
||||||
by GetDpiForWindow will be wrong. Pass SDL_TRUE for `force_ignore_window_dpi`
|
|
||||||
makes us recompute the DPI based on the monitor we are restoring onto.
|
|
||||||
Fixes windows shrinking slightly when going from exclusive fullscreen to windowed
|
|
||||||
on a HighDPI monitor with scaling.
|
|
||||||
*/
|
|
||||||
WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE, SDL_TRUE);
|
|
||||||
}
|
}
|
||||||
SetWindowLong(hwnd, GWL_STYLE, style);
|
SetWindowLong(hwnd, GWL_STYLE, style);
|
||||||
data->expected_resize = SDL_TRUE;
|
data->expected_resize = SDL_TRUE;
|
||||||
|
|
|
@ -762,7 +762,7 @@ const char *wmtab[] = {
|
||||||
"UNKNOWN (737)",
|
"UNKNOWN (737)",
|
||||||
"UNKNOWN (738)",
|
"UNKNOWN (738)",
|
||||||
"UNKNOWN (739)",
|
"UNKNOWN (739)",
|
||||||
"UNKNOWN (740)",
|
"WM_GETDPISCALEDSIZE",
|
||||||
"UNKNOWN (741)",
|
"UNKNOWN (741)",
|
||||||
"UNKNOWN (742)",
|
"UNKNOWN (742)",
|
||||||
"UNKNOWN (743)",
|
"UNKNOWN (743)",
|
||||||
|
|
Loading…
Reference in New Issue