fix(window): resize the borderless HWND directly so DPI-move sizes are exact
The hardware [WINLOG] trace showed the DPI-transition target computed correctly (min height 720) but the window stuck ~5% larger (759), with every deferred retry failing to shrink it. Root cause: the DX11 window is a borderless native HWND (WS_CAPTION/WS_THICKFRAME, for native move/resize) wrapped by SDL. SDL_SetWindowSize converts the requested CLIENT size to a window rect via AdjustWindowRectEx (adding the caption+border frame), but our WM_NCCALCSIZE handler folds that whole frame back into the client area — so every SDL resize inflates the window by ~one frame (~39px height, ~16px width) and the 720 minimum becomes an unreachable 759. That, not the earlier min-ordering/settle logic, is why the height wouldn't stay at min. resizeWindowExact() resizes the native HWND directly via SetWindowPos on the DX11 path (window rect == client for a borderless window → exact requested size); other platforms keep SDL_SetWindowSize. Used for the DPI-transition resize and the deferred retry, so the window now lands on the true minimum in both directions. Keeps the [WINLOG] native-rect + min-track tracing so the next capture confirms the fix (or surfaces any remaining gap). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
23
src/main.cpp
23
src/main.cpp
@@ -578,6 +578,25 @@ static void winlogState(SDL_Window* w, const char* tag)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Resize the window to an EXACT client size. On the DX11 borderless native HWND, SDL_SetWindowSize
|
||||
// inflates the result by a phantom caption+border frame: SDL runs AdjustWindowRectEx to turn the
|
||||
// requested client size into a window rect (adding the WS_CAPTION/WS_THICKFRAME frame), but our
|
||||
// WM_NCCALCSIZE handler folds that entire window rect back into the client area — so the client ends
|
||||
// up ~frame bigger than asked (e.g. a 720 min becomes 759, unreachable). Resize the HWND directly:
|
||||
// for a borderless window the window rect equals the client, so SetWindowPos gives the exact size.
|
||||
static void resizeWindowExact(SDL_Window* window, int w, int h)
|
||||
{
|
||||
#if defined(_WIN32) && defined(DRAGONX_USE_DX11)
|
||||
HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window),
|
||||
SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
|
||||
if (hwnd) {
|
||||
SetWindowPos(hwnd, nullptr, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SDL_SetWindowSize(window, w, h);
|
||||
}
|
||||
|
||||
// Handle SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: save the old-scale size,
|
||||
// compute + clamp the new physical size, arm the deferred resize retry,
|
||||
// and rebuild fonts / reset ImGui style at the new DPI scale. newScale
|
||||
@@ -662,7 +681,7 @@ static void handleDisplayScaleChange(SDL_Window* window, float newScale,
|
||||
// makes the shrink land on the new min immediately, without relying on the deferred retry.
|
||||
SDL_SetWindowMinimumSize(window, minW, minH);
|
||||
dpiResizePending = true;
|
||||
SDL_SetWindowSize(window, newW, newH);
|
||||
resizeWindowExact(window, newW, newH);
|
||||
lastKnownW = newW;
|
||||
lastKnownH = newH;
|
||||
// Arm deferred retry (SetWindowSize may not stick mid-drag) and suppress resize-recording
|
||||
@@ -1374,7 +1393,7 @@ int main(int argc, char* argv[])
|
||||
SDL_GetWindowSize(window, &curW, &curH);
|
||||
if (curW != dpiTargetW || curH != dpiTargetH) {
|
||||
dpiResizePending = true;
|
||||
SDL_SetWindowSize(window, dpiTargetW, dpiTargetH);
|
||||
resizeWindowExact(window, dpiTargetW, dpiTargetH);
|
||||
DEBUG_LOGF(" Deferred resize retry %d: %dx%d -> %dx%d\n",
|
||||
dpiResizeRetries, curW, curH, dpiTargetW, dpiTargetH);
|
||||
winlog("RETRY %d: cur %dx%d != target %dx%d -> SetWindowSize(target)",
|
||||
|
||||
Reference in New Issue
Block a user