fix(window): defer caption-button window ops out of the ImGui frame
The custom minimize / maximize / restore buttons are drawn from inside app.render(), while an ImGui frame is open. Calling SDL to change the window state there pushes resize events synchronously, which re-enters the resize watcher and can nest a new frame inside the open one. - A click now records the requested op instead of acting on it, and the window state change is applied once the frame has closed, after the pacing block so the follow-up redraw is not dropped. Windows-only; it rides the borderless caption controls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+19
-5
@@ -334,6 +334,11 @@ static LRESULT CALLBACK BorderlessWndProc(HWND hwnd, UINT msg,
|
||||
return CallWindowProcW(g_sdlWndProc, hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Caption-button window ops are deferred out of the open ImGui frame and run
|
||||
// after the frame closes (SDL pushes resize events synchronously). (C146)
|
||||
enum class CaptionOp { None, Minimize, Maximize, Restore };
|
||||
static CaptionOp g_pendingCaptionOp = CaptionOp::None;
|
||||
|
||||
// Draw custom window-control buttons (minimize / maximize-restore / close)
|
||||
// on the foreground draw list, and handle title-bar dragging.
|
||||
static void renderBorderlessControls(SDL_Window* window, HWND /*hwnd*/,
|
||||
@@ -380,7 +385,7 @@ static void renderBorderlessControls(SDL_Window* window, HWND /*hwnd*/,
|
||||
float cy = oy + btnH * 0.5f, lx = minX + btnW * 0.5f - iconHalf;
|
||||
fg->AddLine(ImVec2(lx, cy), ImVec2(lx + iconHalf * 2.0f, cy),
|
||||
wcIcon, lineThk);
|
||||
if (hov && click) SDL_MinimizeWindow(window);
|
||||
if (hov && click) g_pendingCaptionOp = CaptionOp::Minimize;
|
||||
}
|
||||
|
||||
// --- Maximize / Restore button ---
|
||||
@@ -402,10 +407,7 @@ static void renderBorderlessControls(SDL_Window* window, HWND /*hwnd*/,
|
||||
ImVec2(cx + iconHalf, cy + iconHalf - dp),
|
||||
wcIcon, 0, 0, lineThk);
|
||||
}
|
||||
if (hov && click) {
|
||||
if (maximized) SDL_RestoreWindow(window);
|
||||
else SDL_MaximizeWindow(window);
|
||||
}
|
||||
if (hov && click) g_pendingCaptionOp = maximized ? CaptionOp::Restore : CaptionOp::Maximize;
|
||||
}
|
||||
|
||||
// --- Close button ---
|
||||
@@ -2374,6 +2376,18 @@ int main(int argc, char* argv[])
|
||||
nextAmbientFrameMs = lastFrameStartNs / 1000000 + interval;
|
||||
}
|
||||
}
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
if (g_pendingCaptionOp != CaptionOp::None) {
|
||||
switch (g_pendingCaptionOp) {
|
||||
case CaptionOp::Minimize: SDL_MinimizeWindow(window); break;
|
||||
case CaptionOp::Maximize: SDL_MaximizeWindow(window); break;
|
||||
case CaptionOp::Restore: SDL_RestoreWindow(window); break;
|
||||
default: break;
|
||||
}
|
||||
g_pendingCaptionOp = CaptionOp::None;
|
||||
needsRedraw = true; // after the pacing block, so it is not overwritten
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Remove resize event watcher
|
||||
|
||||
Reference in New Issue
Block a user