diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 9854767c3054e..721bae42ff888 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1146,6 +1146,24 @@ static bool DispatchModalLoopMessageHook(HWND *hwnd, UINT *msg, WPARAM *wParam, return false; } +static void WIN_OnDPIUpdateMinMaxSize(SDL_Window *window, int old_dpi, int new_dpi) +{ + float scale = (float)new_dpi / old_dpi; + + if (window->min_w || window->min_h) + { + int new_min_w = (int)SDL_ceilf(window->min_w * scale); + int new_min_h = (int)SDL_ceilf(window->min_h * scale); + SDL_SetWindowMinimumSize(window, new_min_w, new_min_h); + } + if (window->max_w || window->max_h) + { + int new_max_w = (int)SDL_ceilf(window->max_w * scale); + int new_max_h = (int)SDL_ceilf(window->max_h * scale); + SDL_SetWindowMaximumSize(window, new_max_w, new_max_h); + } +} + LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_WindowData *data; @@ -1669,7 +1687,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara 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); + // SDL_Log("WM_GETMINMAXINFO: max window size: %dx%d using dpi: %u", w, h, dpi); #endif } @@ -1706,7 +1724,11 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara #endif // WM_GETMINMAXINFO case WM_WINDOWPOSCHANGING: - + { +#ifdef WMMSG_DEBUG + const WINDOWPOS *windowpos = (WINDOWPOS *)lParam; + SDL_Log("WM_WINDOWPOSCHANGING: output size: (%dx%d)", windowpos->cx, windowpos->cy); +#endif // !WMMSG_DEBUG if (data->expected_resize) { returnCode = 0; } else if (data->in_modal_loop) { @@ -1726,6 +1748,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara returnCode = 0; } break; + } case WM_WINDOWPOSCHANGED: { @@ -1737,7 +1760,11 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara RECT rect; int x, y; int w, h; - +#ifdef WMMSG_DEBUG + GetClientRect(hwnd, &rect); + SDL_Log("WM_WINDOWPOSCHANGED: output size: WINDOWPOS(%dx%d), ClientRect(%d,%d)", windowpos->cx, windowpos->cy, + rect.right, rect.bottom); +#endif // !WMMSG_DEBUG if (windowpos->flags & SWP_SHOWWINDOW) { SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_SHOWN, 0, 0); } @@ -2291,70 +2318,6 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara } break; case WM_GETDPISCALEDSIZE: - // Windows 10 Creators Update+ - /* 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. - e.g. a 100x100 window dragged to a 200% scaled monitor - becomes 200x200. - - For SDL, we instead want the client size to scale linearly. - This is not the same as the window rect scaling linearly, - because Windows doesn't scale the non-client area (titlebar etc.) - linearly. So, we need to handle this message to request custom - scaling. */ - - const int nextDPI = (int)wParam; - const int prevDPI = (int)data->videodata->GetDpiForWindow(hwnd); - SIZE *sizeInOut = (SIZE *)lParam; - - int frame_w, frame_h; - int query_client_w_win, query_client_h_win; - -#ifdef HIGHDPI_DEBUG - SDL_Log("WM_GETDPISCALEDSIZE: current DPI: %d potential DPI: %d input size: (%dx%d)", - prevDPI, nextDPI, sizeInOut->cx, sizeInOut->cy); -#endif - - // Subtract the window frame size that would have been used at prevDPI - { - RECT rect = { 0 }; - - if (!(data->window->flags & SDL_WINDOW_BORDERLESS) && !SDL_WINDOW_IS_POPUP(data->window)) { - WIN_AdjustWindowRectForHWND(hwnd, &rect, prevDPI); - } - - frame_w = -rect.left + rect.right; - frame_h = -rect.top + rect.bottom; - - query_client_w_win = sizeInOut->cx - frame_w; - query_client_h_win = sizeInOut->cy - frame_h; - } - - // Add the window frame size that would be used at nextDPI - { - RECT rect = { 0 }; - rect.right = query_client_w_win; - rect.bottom = query_client_h_win; - - if (!(data->window->flags & SDL_WINDOW_BORDERLESS) && !SDL_WINDOW_IS_POPUP(data->window)) { - WIN_AdjustWindowRectForHWND(hwnd, &rect, nextDPI); - } - - // This is supposed to control the suggested rect param of WM_DPICHANGED - sizeInOut->cx = rect.right - rect.left; - sizeInOut->cy = rect.bottom - rect.top; - } - -#ifdef HIGHDPI_DEBUG - SDL_Log("WM_GETDPISCALEDSIZE: output size: (%dx%d)", sizeInOut->cx, sizeInOut->cy); -#endif - return TRUE; - } break; case WM_DPICHANGED: @@ -2363,7 +2326,6 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara const int newDPI = HIWORD(wParam); RECT *const suggestedRect = (RECT *)lParam; int w, h; - #ifdef HIGHDPI_DEBUG SDL_Log("WM_DPICHANGED: to %d\tsuggested rect: (%d, %d), (%dx%d)", newDPI, suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top); @@ -2378,11 +2340,15 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara #endif return 0; } + // Update minimum size and maximum size for new dpi + const int prevDPI = data->dpi; + WIN_OnDPIUpdateMinMaxSize(data->window, prevDPI, newDPI); // Interactive user-initiated resizing/movement { /* Calculate the new frame w/h such that the client area size is maintained. */ + RECT rect = { 0 }; rect.right = data->window->w; rect.bottom = data->window->h; @@ -2391,8 +2357,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara WIN_AdjustWindowRectForHWND(hwnd, &rect, newDPI); } - w = rect.right - rect.left; - h = rect.bottom - rect.top; + // w = rect.right - rect.left; + // h = rect.bottom - rect.top; + w = suggestedRect->right - suggestedRect->left; + h = suggestedRect->bottom - suggestedRect->top; } #ifdef HIGHDPI_DEBUG @@ -2410,6 +2378,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara h, SWP_NOZORDER | SWP_NOACTIVATE); data->expected_resize = false; + data->dpi = newDPI; return 0; } break; @@ -2446,6 +2415,13 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara } else if (returnCode >= 0) { return returnCode; } else { +#ifdef WMMSG_DEBUG + if (msg > MAX_WMMSG) { + SDL_Log("Forwarding UNKNOWN (%d) to DefWindowProc", msg); + } else { + SDL_Log("Forwarding %s to DefWindowProc", wmtab[msg]); + } +#endif // !WMMSG_DEBUG return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam); } } diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 02ed14018ce3f..9724ee87f1e30 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -392,6 +392,7 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, HWND hwn data->videodata = videodata; data->initializing = true; data->hint_erase_background_mode = GetEraseBackgroundModeHint(); + data->dpi = _this->internal->GetDpiForWindow(hwnd); // WIN_WarpCursor() jitters by +1, and remote desktop warp wobble is +/- 1 @@ -2296,4 +2297,9 @@ bool WIN_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal) return true; } +int WIN_GetWindowDpi(SDL_VideoDevice *_this, SDL_Window *window) +{ + return window->internal->dpi; +} + #endif // SDL_VIDEO_DRIVER_WINDOWS diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index 5d22b4fb9ea12..24218a1e31374 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -104,6 +104,7 @@ struct SDL_WindowData // Whether we retain the content of the window when changing state UINT copybits_flag; SDLDropTarget *drop_target; + int dpi; }; extern bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); @@ -144,6 +145,7 @@ extern bool WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, extern bool WIN_AdjustWindowRectForHWND(HWND hwnd, LPRECT lpRect, UINT frame_dpi); extern bool WIN_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent); extern bool WIN_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal); +extern int WIN_GetWindowDpi(SDL_VideoDevice *_this, SDL_Window *window); // Ends C function definitions when using C++ #ifdef __cplusplus