Skip to content

Commit 4030a98

Browse files
committed
Fix high-DPI SDL window state handling
1 parent 3f24192 commit 4030a98

2 files changed

Lines changed: 33 additions & 23 deletions

File tree

Nu/Nu/Sdl/SdlDeps.fs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,24 @@ module SdlDeps =
164164
| Some window ->
165165

166166
// get a snapshot of whether screen was full
167-
let mutable (windowWidth, windowHeight) = (0, 0)
168-
SDL3.SDL_GetWindowSizeInPixels (window, &&windowWidth, &&windowHeight) |> ignore<SDLBool>
169-
let displayMode = getDisplayModeInternal window
170-
let wasFullScreen = windowWidth = displayMode.w || windowHeight = displayMode.h
167+
let flags = SDL3.SDL_GetWindowFlags window
168+
let wasFullScreen =
169+
flags &&& SDL_WindowFlags.SDL_WINDOW_FULLSCREEN <> LanguagePrimitives.EnumOfValue 0UL
171170

172171
// change full screen status via flags
173-
SDL3.SDL_SetWindowFullscreen (window, fullScreen) |> ignore<SDLBool>
172+
let fullScreenChanged = SDL3.SDL_SetWindowFullscreen (window, fullScreen) |> SDLBool.op_Implicit
174173

175174
// when changing from full screen, set window to windowed size and make sure its title bar is visible
176-
if wasFullScreen && not fullScreen then
177-
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
178-
let sizeWindowed = Constants.Render.DisplayVirtualResolution * 2
179-
SDL3.SDL_RestoreWindow window |> ignore<SDLBool>
180-
SDL3.SDL_SetWindowSize (window, int (single sizeWindowed.X / pixelDensity), int (single sizeWindowed.Y / pixelDensity)) |> ignore
181-
SDL3.SDL_SetWindowPosition (window, 100, 100) |> ignore<SDLBool> // NOTE: pretty arbitrary numbers here...
175+
if fullScreenChanged && wasFullScreen && not fullScreen then
176+
if SDL3.SDL_SyncWindow window |> SDLBool.op_Implicit then
177+
let windowSizeWindowed = Constants.Render.DisplayVirtualResolution * 2
178+
if SDL3.SDL_RestoreWindow window |> SDLBool.op_Implicit then
179+
if SDL3.SDL_SyncWindow window |> SDLBool.op_Implicit then
180+
// Restoration can change the window's display, and therefore its pixel density.
181+
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
182+
SDL3.SDL_SetWindowSize (window, int (single windowSizeWindowed.X / pixelDensity), int (single windowSizeWindowed.Y / pixelDensity)) |> ignore<SDLBool>
183+
if SDL3.SDL_SyncWindow window |> SDLBool.op_Implicit then
184+
SDL3.SDL_SetWindowPosition (window, 100, 100) |> ignore<SDLBool> // NOTE: pretty arbitrary numbers here...
182185

183186
| None -> ()
184187
sdlDeps
@@ -281,18 +284,24 @@ module SdlDeps =
281284
let windowConfig = sdlConfig.WindowConfig
282285
let windowOpt = SDL3.SDL_CreateWindow (windowConfig.WindowTitle, windowSize.X, windowSize.Y, windowConfig.WindowFlags)
283286
if NativePtr.notNullPtr windowOpt then
284-
285287
// set window position
286288
let window = windowOpt
287289
SDL3.SDL_SetWindowPosition (window, windowConfig.WindowX, windowConfig.WindowY) |> ignore<SDLBool>
288-
290+
// Wait for the move so pixel density reflects the display now containing the window.
291+
SDL3.SDL_SyncWindow window |> ignore<SDLBool>
292+
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
293+
SDL3.SDL_SetWindowSize (window, int (single windowSize.X / pixelDensity), int (single windowSize.Y / pixelDensity)) |> ignore<SDLBool>
294+
// Wait for the resize because the pre-splash immediately queries pixel dimensions and the window surface.
295+
SDL3.SDL_SyncWindow window |> ignore<SDLBool>
289296
// start text input except on platforms that would obscure the game with a virtual keyboard
290297
if not (SDL3.SDL_HasScreenKeyboardSupport ()) then
291298
SDL3.SDL_StartTextInput window |> ignore<SDLBool>
292299

293300
// set to full screen when window taking up entire screen and unaccompanied
294-
let mutable displayMode = getDisplayModeInternal window
295-
if (windowSize.X = displayMode.w || windowSize.Y = displayMode.h) && not accompanied then
301+
let displayMode = getDisplayModeInternal window
302+
if (windowSize.X = int (single displayMode.w * pixelDensity) ||
303+
windowSize.Y = int (single displayMode.h * pixelDensity)) &&
304+
not accompanied then
296305
SDL3.SDL_SetWindowFullscreen (window, true) |> ignore<SDLBool>
297306

298307
// attempt to show splash screen (software surface; will be overwritten by Vulkan)
@@ -302,7 +311,9 @@ module SdlDeps =
302311
windowOpt)
303312

304313
(fun window -> SDL3.SDL_DestroyWindow window; destroy ()) with
305-
| Left error -> Left error
314+
| Left error ->
315+
destroy ()
316+
Left error
306317
| Right (window, destroy) ->
307318
match tryMakeSdlGlobalResource SDL3_ttf.TTF_Init (fun () -> SDL3_ttf.TTF_Quit (); destroy window) with
308319
| Left error -> Left error

Nu/Nu/World/WorldPrelude.fs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -669,11 +669,9 @@ module internal AmbientState =
669669

670670
let internal tryGetWindowFullScreen state =
671671
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
672-
| Some window ->
673-
let mutable width, height = 0, 0
674-
SDL3.SDL_GetWindowSizeInPixels (window, &&width, &&height) |> ignore
675-
let displayMode = SdlDeps.getDisplayModeInternal window
676-
Some (width = displayMode.w || height = displayMode.h)
672+
| Some window ->
673+
let flags = SDL3.SDL_GetWindowFlags window
674+
Some (flags &&& SDL_WindowFlags.SDL_WINDOW_FULLSCREEN <> LanguagePrimitives.EnumOfValue 0UL)
677675
| _ -> None
678676

679677
let internal trySetWindowFullScreen fullScreen state =
@@ -698,7 +696,7 @@ module internal AmbientState =
698696
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
699697
| Some window ->
700698
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
701-
SDL3.SDL_SetWindowPosition (window, int (single position.X * pixelDensity), int (single position.Y * pixelDensity)) |> ignore<SDLBool>
699+
SDL3.SDL_SetWindowPosition (window, int (single position.X / pixelDensity), int (single position.Y / pixelDensity)) |> ignore<SDLBool>
702700
| None -> ()
703701

704702
let internal tryGetWindowSize state =
@@ -713,7 +711,8 @@ module internal AmbientState =
713711
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
714712
| Some window ->
715713
let pixelDensity = SDL3.SDL_GetWindowPixelDensity window
716-
SDL3.SDL_SetWindowSize (window, int (single size.X / pixelDensity), int (single size.Y / pixelDensity)) |> ignore
714+
SDL3.SDL_SetWindowSize (window, int (single size.X / pixelDensity), int (single size.Y / pixelDensity)) |> ignore<SDLBool>
715+
SDL3.SDL_SyncWindow window |> ignore<SDLBool>
717716
| None -> ()
718717

719718
let internal tryGetWindowProperties state =

0 commit comments

Comments
 (0)