diff --git a/src/app.cpp b/src/app.cpp index bc9af9f..50ba895 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -739,6 +739,10 @@ void App::update() { PERF_SCOPE("Update.Total"); ImGuiIO& io = ImGui::GetIO(); + // Clamp the frame delta: after a long pause (window minimized, or the machine slept) NewFrame reports + // a huge DeltaTime that would fire every refresh/animation timer at once. Every timer reads + // io.DeltaTime, so one clamp here bounds them all (also caps the real-clock delta fed while minimized). + if (io.DeltaTime > 0.25f) io.DeltaTime = 0.25f; // Full UI screenshot sweep: demo state is injected once and must stay frozen. Skip every live // op (refresh/connect/pumps) so a real daemon can't clobber it — on Windows a running node's diff --git a/src/main.cpp b/src/main.cpp index fbbc99b..7143d2d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1500,6 +1500,7 @@ int main(int argc, char* argv[]) // WINDOW_RESIZED events during the transition can't corrupt savedSizeForScale / lastKnownW/H. int dpiSettleFrames = 0; SDL_DisplayID lastLoggedDisplay = 0; // [WINLOG] throttle: log MOVED only when the display changes + Uint64 minimizedLastTickMs = 0; // real-clock tick for the minimized "keep syncing" update { float s = dragonx::ui::material::Typography::instance().getDpiScale(); int w = 0, h = 0; @@ -1734,13 +1735,28 @@ int main(int argc, char* argv[]) // Check if window is minimized if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { - // Still check shouldQuit while minimized to avoid hang - if (app.shouldQuit()) { - running = false; - } - SDL_Delay(10); + // Keep the wallet syncing while minimized: run the logic update (drains RPC results, ticks the + // refresh scheduler, keeps the daemon connection/reconnect + sync status live) but skip the + // ImGui frame + GPU present since nothing is visible. app.update() only reads + // GetIO()/GetTime()/IsAnyItemActive() — all valid outside a frame — so it's safe without a + // NewFrame; feed it a real-clock DeltaTime (NewFrame, which normally sets it, is skipped) and + // let app.update() clamp it. Throttled to ~5 Hz so CPU stays near-idle (refresh cadences are + // seconds-scale). shouldQuit is still checked so a quit request never hangs behind minimize. + Uint64 nowMs = SDL_GetTicks(); + float minDelta = (minimizedLastTickMs == 0) ? 0.001f + : (float)(nowMs - minimizedLastTickMs) / 1000.0f; + minimizedLastTickMs = nowMs; + ImGui::GetIO().DeltaTime = (minDelta > 0.0f) ? minDelta : 0.001f; + try { + app.update(); + } catch (const std::exception& e) { + DEBUG_LOGF("[Main] minimized app.update() threw: %s\n", e.what()); + } catch (...) {} + if (app.shouldQuit()) running = false; + SDL_Delay(200); continue; } + minimizedLastTickMs = 0; // visible again — reset the minimized clock // --- PerfLog: begin frame --- dragonx::util::PerfLog::instance().beginFrame();