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);
|
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)
|
// Draw custom window-control buttons (minimize / maximize-restore / close)
|
||||||
// on the foreground draw list, and handle title-bar dragging.
|
// on the foreground draw list, and handle title-bar dragging.
|
||||||
static void renderBorderlessControls(SDL_Window* window, HWND /*hwnd*/,
|
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;
|
float cy = oy + btnH * 0.5f, lx = minX + btnW * 0.5f - iconHalf;
|
||||||
fg->AddLine(ImVec2(lx, cy), ImVec2(lx + iconHalf * 2.0f, cy),
|
fg->AddLine(ImVec2(lx, cy), ImVec2(lx + iconHalf * 2.0f, cy),
|
||||||
wcIcon, lineThk);
|
wcIcon, lineThk);
|
||||||
if (hov && click) SDL_MinimizeWindow(window);
|
if (hov && click) g_pendingCaptionOp = CaptionOp::Minimize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Maximize / Restore button ---
|
// --- Maximize / Restore button ---
|
||||||
@@ -402,10 +407,7 @@ static void renderBorderlessControls(SDL_Window* window, HWND /*hwnd*/,
|
|||||||
ImVec2(cx + iconHalf, cy + iconHalf - dp),
|
ImVec2(cx + iconHalf, cy + iconHalf - dp),
|
||||||
wcIcon, 0, 0, lineThk);
|
wcIcon, 0, 0, lineThk);
|
||||||
}
|
}
|
||||||
if (hov && click) {
|
if (hov && click) g_pendingCaptionOp = maximized ? CaptionOp::Restore : CaptionOp::Maximize;
|
||||||
if (maximized) SDL_RestoreWindow(window);
|
|
||||||
else SDL_MaximizeWindow(window);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Close button ---
|
// --- Close button ---
|
||||||
@@ -2374,6 +2376,18 @@ int main(int argc, char* argv[])
|
|||||||
nextAmbientFrameMs = lastFrameStartNs / 1000000 + interval;
|
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
|
// Remove resize event watcher
|
||||||
|
|||||||
Reference in New Issue
Block a user