feat(input): Enhance window management capabilities#2608
Conversation
|
| Filename | Overview |
|---|---|
| GeneralsMD/Code/Main/WinMain.cpp | Core of this PR: adds Alt+Enter / F11 fullscreen toggle, live-resize pipeline, and performLiveResize; has a real defect where g_resizePending is cleared before the D3D reset, and a no-op SetWindowLong(WS_EX_TOPMOST) call. |
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp | Adds reflowWindowTree/reflowAllWindows and erases destroyed windows from g_windowLayoutRegistry; the earlier-flagged division-by-zero is guarded with createResX > 0 checks. |
| GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp | Rewrites recreateControlBar to look up by ControlBarParent, preserve hide/science-visible state, re-apply player scheme, and guard against a missing window; logic looks sound. |
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManagerScript.cpp | Defines g_windowLayoutRegistry and populates it via g_tempParsedRect whenever a window is created by script; safe because parsing is single-threaded. |
| GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp | Adds command-line priority logic for m_windowed in parseGameDataDefinition; correctly saves the pre-parse value and restores it when -win/-nowin was specified. |
| GeneralsMD/Code/GameEngineDevice/Source/Win32Device/Common/Win32GameEngine.cpp | Hooks checkAndApplyDeferredResize() into the game engine update loop via a function-body extern declaration; works but creates an opaque cross-file dependency. |
| Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | Refactors Set_Device_Resolution to forward all parameters through Set_Render_Device, removing the TODO about unsupported windowed/bit-depth changes; straightforward delegation. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant WndProc
participant toggleFullscreen
participant checkAndApplyDeferredResize
participant performLiveResize
participant TheDisplay
participant reflowAllWindows
participant InGameUI
User->>WndProc: Alt+Enter / F11 / SC_MAXIMIZE
WndProc->>toggleFullscreen: call
toggleFullscreen->>toggleFullscreen: flip m_windowed
toggleFullscreen->>WndProc: SetWindowPos (new size/style)
WndProc->>WndProc: "WM_SIZE → g_resizePending = true"
loop Every engine update
WndProc->>checkAndApplyDeferredResize: checkAndApplyDeferredResize()
checkAndApplyDeferredResize->>checkAndApplyDeferredResize: isResizeSafe()?
alt safe
checkAndApplyDeferredResize->>checkAndApplyDeferredResize: "g_resizePending = false"
checkAndApplyDeferredResize->>performLiveResize: call
performLiveResize->>TheDisplay: setDisplayMode(w, h, bpp, windowed)
alt D3D reset succeeds
TheDisplay-->>performLiveResize: true
performLiveResize->>reflowAllWindows: reflowAllWindows(w, h)
performLiveResize->>InGameUI: recreateControlBar()
performLiveResize->>performLiveResize: optionPref.write()
else D3D reset fails
TheDisplay-->>performLiveResize: false
Note over performLiveResize: window/D3D out of sync, no retry
end
else not safe
Note over checkAndApplyDeferredResize: g_resizePending stays true
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant WndProc
participant toggleFullscreen
participant checkAndApplyDeferredResize
participant performLiveResize
participant TheDisplay
participant reflowAllWindows
participant InGameUI
User->>WndProc: Alt+Enter / F11 / SC_MAXIMIZE
WndProc->>toggleFullscreen: call
toggleFullscreen->>toggleFullscreen: flip m_windowed
toggleFullscreen->>WndProc: SetWindowPos (new size/style)
WndProc->>WndProc: "WM_SIZE → g_resizePending = true"
loop Every engine update
WndProc->>checkAndApplyDeferredResize: checkAndApplyDeferredResize()
checkAndApplyDeferredResize->>checkAndApplyDeferredResize: isResizeSafe()?
alt safe
checkAndApplyDeferredResize->>checkAndApplyDeferredResize: "g_resizePending = false"
checkAndApplyDeferredResize->>performLiveResize: call
performLiveResize->>TheDisplay: setDisplayMode(w, h, bpp, windowed)
alt D3D reset succeeds
TheDisplay-->>performLiveResize: true
performLiveResize->>reflowAllWindows: reflowAllWindows(w, h)
performLiveResize->>InGameUI: recreateControlBar()
performLiveResize->>performLiveResize: optionPref.write()
else D3D reset fails
TheDisplay-->>performLiveResize: false
Note over performLiveResize: window/D3D out of sync, no retry
end
else not safe
Note over checkAndApplyDeferredResize: g_resizePending stays true
end
end
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
GeneralsMD/Code/Main/WinMain.cpp:411-418
**Deferred resize flag cleared before the attempt leaves resize unretried on D3D failure**
`g_resizePending` is set to `false` before `performLiveResize` is called. If `TheDisplay->setDisplayMode(...)` inside `performLiveResize` returns `false` (e.g., the D3D device is lost or a reset fails), the window has already been resized by `SetWindowPos` but the D3D surface stays at the previous dimensions. Because `g_resizePending` is now `false`, nothing re-triggers the resize — the mismatch persists until the user manually initiates another resize or toggle.
Consider clearing the flag only on a successful apply: have `performLiveResize` return a `bool` and conditionally reset `g_resizePending`.
Reviews (6): Last reviewed commit: "Fix windowed preference saving and preve..." | Re-trigger Greptile
|
Haven't read too closely but when the resolution is set to native display resolution, will alt+enter here switch between borderless and fullscreen? How is this typically implemented in games? |
|
Currently it switches between exclusive and windowed that covers the entire screen. Have a small regression there as the titel bars uncenters the borderless window. In modern games they don't let you set the fullscreen resolution anymore, the resolution setting only applies to windowed. The fullscreen resolution is always the desktop resolution. |
f4fca7f to
4d29ea6
Compare
…ve resize support
4d29ea6 to
76bd972
Compare
|
@greptile review |
| void checkAndApplyDeferredResize() | ||
| { | ||
| if (g_resizePending && isResizeSafe()) | ||
| { | ||
| g_resizePending = false; | ||
| performLiveResize(ApplicationHWnd); | ||
| } | ||
| } |
There was a problem hiding this comment.
Deferred resize flag cleared before the attempt leaves resize unretried on D3D failure
g_resizePending is set to false before performLiveResize is called. If TheDisplay->setDisplayMode(...) inside performLiveResize returns false (e.g., the D3D device is lost or a reset fails), the window has already been resized by SetWindowPos but the D3D surface stays at the previous dimensions. Because g_resizePending is now false, nothing re-triggers the resize — the mismatch persists until the user manually initiates another resize or toggle.
Consider clearing the flag only on a successful apply: have performLiveResize return a bool and conditionally reset g_resizePending.
Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/Main/WinMain.cpp
Line: 411-418
Comment:
**Deferred resize flag cleared before the attempt leaves resize unretried on D3D failure**
`g_resizePending` is set to `false` before `performLiveResize` is called. If `TheDisplay->setDisplayMode(...)` inside `performLiveResize` returns `false` (e.g., the D3D device is lost or a reset fails), the window has already been resized by `SetWindowPos` but the D3D surface stays at the previous dimensions. Because `g_resizePending` is now `false`, nothing re-triggers the resize — the mismatch persists until the user manually initiates another resize or toggle.
Consider clearing the flag only on a successful apply: have `performLiveResize` return a `bool` and conditionally reset `g_resizePending`.
How can I resolve this? If you propose a fix, please make it concise.
Alt+Enter Borderless Fullscreen & Live Resize Reflow Integration
Integrates Alt+Enter fullscreen / windowed toggling with live resizing during games.
Summary of Changes
options.ini.-win/-nowin) override persistent preferences.This change was generated with AI assistance. All generated code has been reviewed, tested, and verified for correctness.
todo, replicate to generals