mirror of
				https://github.com/Ryujinx/SDL.git
				synced 2025-11-04 12:55:06 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							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.
 | 
			
		||||
                 */
 | 
			
		||||
                BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
 | 
			
		||||
                UINT dpi;
 | 
			
		||||
                
 | 
			
		||||
                dpi = 96;
 | 
			
		||||
                size.top = 0;
 | 
			
		||||
                size.left = 0;
 | 
			
		||||
                size.bottom = h;
 | 
			
		||||
                size.right = w;
 | 
			
		||||
 | 
			
		||||
                if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
 | 
			
		||||
                    UINT dpi = data->videodata->GetDpiForWindow(hwnd);
 | 
			
		||||
                    dpi = data->videodata->GetDpiForWindow(hwnd);
 | 
			
		||||
                    data->videodata->AdjustWindowRectExForDpi(&size, style, menu, 0, dpi);
 | 
			
		||||
                } else {
 | 
			
		||||
                    AdjustWindowRectEx(&size, style, menu, 0);
 | 
			
		||||
                }
 | 
			
		||||
                w = size.right - size.left;
 | 
			
		||||
                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 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1422,7 +1428,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
 | 
			
		||||
    case WM_GETDPISCALEDSIZE:
 | 
			
		||||
        /* 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) {
 | 
			
		||||
            /* Windows expects applications to scale their window rects linearly
 | 
			
		||||
               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);
 | 
			
		||||
            RECT* const suggestedRect = (RECT*)lParam;
 | 
			
		||||
            SDL_bool setExpectedResize = SDL_FALSE;
 | 
			
		||||
            int w, h;
 | 
			
		||||
 | 
			
		||||
#ifdef HIGHDPI_DEBUG
 | 
			
		||||
| 
						 | 
				
			
			@ -1497,11 +1507,27 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
                suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            /* DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 means that
 | 
			
		||||
               WM_GETDPISCALEDSIZE will have been called, so we can use suggestedRect. */
 | 
			
		||||
            if (data->expected_resize) {
 | 
			
		||||
                /* 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())) {
 | 
			
		||||
                /* WM_GETDPISCALEDSIZE should have been called prior, so we can trust the given
 | 
			
		||||
                   suggestedRect. */
 | 
			
		||||
                w = suggestedRect->right - suggestedRect->left;
 | 
			
		||||
                h = suggestedRect->bottom - suggestedRect->top;
 | 
			
		||||
 | 
			
		||||
#ifdef HIGHDPI_DEBUG
 | 
			
		||||
                SDL_Log("WM_DPICHANGED: using suggestedRect");
 | 
			
		||||
#endif
 | 
			
		||||
            } else {               
 | 
			
		||||
                RECT rect = { 0, 0, data->window->w, data->window->h };
 | 
			
		||||
                const DWORD style = GetWindowLong(hwnd, GWL_STYLE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1521,7 +1547,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
                suggestedRect->left, suggestedRect->top, w, h);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            if (!data->expected_resize) {
 | 
			
		||||
                setExpectedResize = SDL_TRUE;
 | 
			
		||||
                data->expected_resize = SDL_TRUE;
 | 
			
		||||
            }            
 | 
			
		||||
            SetWindowPos(hwnd,
 | 
			
		||||
                NULL,
 | 
			
		||||
                suggestedRect->left,
 | 
			
		||||
| 
						 | 
				
			
			@ -1529,7 +1558,13 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
                w,
 | 
			
		||||
                h,
 | 
			
		||||
                SWP_NOZORDER | SWP_NOACTIVATE);
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,8 @@
 | 
			
		|||
#define SWP_NOCOPYBITS 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* #define HIGHDPI_DEBUG */
 | 
			
		||||
 | 
			
		||||
/* Fake window to help with DirectInput events. */
 | 
			
		||||
HWND SDL_HelperWindow = NULL;
 | 
			
		||||
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
 | 
			
		||||
| 
						 | 
				
			
			@ -114,13 +116,14 @@ GetWindowStyle(SDL_Window * window)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
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)
 | 
			
		||||
WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
 | 
			
		||||
{
 | 
			
		||||
    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
 | 
			
		||||
    SDL_VideoData* videodata = SDL_GetVideoDevice() ? SDL_GetVideoDevice()->driverdata : NULL;
 | 
			
		||||
    RECT rect;
 | 
			
		||||
    UINT dpi;
 | 
			
		||||
 | 
			
		||||
    dpi = 96;
 | 
			
		||||
    rect.left = 0;
 | 
			
		||||
    rect.top = 0;
 | 
			
		||||
    rect.right = (use_current ? window->w : window->windowed.w);
 | 
			
		||||
| 
						 | 
				
			
			@ -133,18 +136,7 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
 | 
			
		|||
        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 
 | 
			
		||||
               AdjustWindowRectEx. */
 | 
			
		||||
            UINT dpi;
 | 
			
		||||
            
 | 
			
		||||
            if (data && !force_ignore_window_dpi) {
 | 
			
		||||
                /* The usual case - we have a HWND, so we can look up the DPI to use. */
 | 
			
		||||
                dpi = videodata->GetDpiForWindow(data->hwnd);
 | 
			
		||||
            } else {
 | 
			
		||||
                /* 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +152,6 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
 | 
			
		|||
            if (videodata->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &dpi, &unused) != S_OK) {
 | 
			
		||||
                dpi = 96;
 | 
			
		||||
            }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, dpi);
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    *width = (rect.right - rect.left);
 | 
			
		||||
    *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
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +184,7 @@ WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height
 | 
			
		|||
 | 
			
		||||
    style = GetWindowLong(hwnd, GWL_STYLE);
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +279,9 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
 | 
			
		|||
                int x, y;
 | 
			
		||||
                /* Figure out what the window area will be */
 | 
			
		||||
                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);
 | 
			
		||||
                data->expected_resize = SDL_FALSE;
 | 
			
		||||
            } else {
 | 
			
		||||
                window->w = w;
 | 
			
		||||
                window->h = h;
 | 
			
		||||
| 
						 | 
				
			
			@ -395,7 +397,7 @@ WIN_CreateWindow(_THIS, SDL_Window * window)
 | 
			
		|||
    style |= GetWindowStyle(window);
 | 
			
		||||
 | 
			
		||||
    /* 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 =
 | 
			
		||||
        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
 | 
			
		||||
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
 | 
			
		||||
| 
						 | 
				
			
			@ -820,13 +825,7 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
 | 
			
		||||
        /* HighDPI bug workaround - when leaving exclusive fullscreen, the window DPI reported
 | 
			
		||||
           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);
 | 
			
		||||
        WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
    SetWindowLong(hwnd, GWL_STYLE, style);
 | 
			
		||||
    data->expected_resize = SDL_TRUE;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -762,7 +762,7 @@ const char *wmtab[] = {
 | 
			
		|||
    "UNKNOWN (737)",
 | 
			
		||||
    "UNKNOWN (738)",
 | 
			
		||||
    "UNKNOWN (739)",
 | 
			
		||||
    "UNKNOWN (740)",
 | 
			
		||||
    "WM_GETDPISCALEDSIZE",
 | 
			
		||||
    "UNKNOWN (741)",
 | 
			
		||||
    "UNKNOWN (742)",
 | 
			
		||||
    "UNKNOWN (743)",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue