diff --git a/src/app.cpp b/src/app.cpp index fb4d03f..d935896 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -623,6 +623,10 @@ void App::applyVisualSettings() void App::preFrame() { + // Free textures retired during the previous frame (its draw data has been rendered by now). + for (ImTextureID t : pending_texture_destroy_) util::DestroyTexture(t); + pending_texture_destroy_.clear(); + ImGuiIO& io = ImGui::GetIO(); // Hot-reload unified UI schema @@ -3300,6 +3304,10 @@ void App::renderStatusBar() void App::reloadThemeImages(const std::string& bgPath, const std::string& logoPath) { + // Every branch below replaces gradient_tex_; the background draw list may already reference the + // old one this frame (skin switches happen mid-frame), so free it at the next preFrame(). + retireTexture(gradient_tex_); + // Reload background image from the path resolved by the skin system. // Each theme specifies its image via [theme] images.background_image in its .toml. if (!bgPath.empty()) { @@ -3337,14 +3345,15 @@ void App::reloadThemeImages(const std::string& bgPath, const std::string& logoPa } // Reset logo loaded flags — will reload on next render frame (ensureLogoTexture re-rasterizes the - // SVG for the new theme). Free the current texture first so a theme switch doesn't leak it. - if (logo_tex_) util::DestroyTexture(logo_tex_); + // SVG for the new theme). Retire the current texture (freed at the next preFrame(), after this + // frame's draw lists are rendered) so a theme switch doesn't leak it. + retireTexture(logo_tex_); logo_loaded_ = false; logo_tex_ = 0; logo_w_ = 0; logo_h_ = 0; coin_logo_loaded_ = false; - if (coin_logo_tex_) util::DestroyTexture(coin_logo_tex_); + retireTexture(coin_logo_tex_); coin_logo_tex_ = 0; coin_logo_w_ = 0; coin_logo_h_ = 0; diff --git a/src/app.h b/src/app.h index 8402d70..0c62dea 100644 --- a/src/app.h +++ b/src/app.h @@ -1619,6 +1619,10 @@ private: // Background gradient overlay ImTextureID gradient_tex_ = 0; + // Textures retired mid-frame (draw lists may still reference them); freed at the next preFrame(). + std::vector pending_texture_destroy_; + void retireTexture(ImTextureID& t) { if (t) { pending_texture_destroy_.push_back(t); t = 0; } } + // Logo texture (reload on skin change / dark↔light switch) ImTextureID logo_tex_ = 0; int logo_w_ = 0;