diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 435915ff62..861395d6f7 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -2656,6 +2656,10 @@ ImDebugger::ImDebugger() { } ImDebugger::~ImDebugger() { + SaveConfig(); +} + +void ImDebugger::SaveConfig() { cfg_.SaveConfig(ConfigPath()); } diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index b79209b509..caf982a6b9 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -190,6 +190,7 @@ public: externalCommand_ = cmd; } void DeviceLost(); + void SaveConfig(); private: Path ConfigPath(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index bbbf6cf386..6c3f2a73cb 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -436,6 +436,7 @@ void runImDebugger(Draw::DrawContext *draw) { // Convert to drawlists. ImGui::Render(); + ImGui_ImplPlatform_SaveIni(false); wantTextInput = io.WantTextInput; } else { uiContext->SetOverrideScreenFrame(nullptr); @@ -1128,19 +1129,13 @@ void NativeShutdownGraphics(GraphicsContext *graphicsContext) { gpu->DeviceLost(); } + // The imgui context and the debugger outlive the graphics, so that their state survives Android + // switching away from the app. Save now anyway, since the app may be killed in the background. if (imguiInited_) { - if (imDebugger_) { - imDebugger_->DeviceLost(); - } + imDebugger_->DeviceLost(); + imDebugger_->SaveConfig(); + ImGui_ImplPlatform_SaveIni(true); ImGui_ImplThin3d_DestroyDeviceObjects(); - ImGui_ImplThin3d_Shutdown(); - // Destroy the debugger here, while the things it refers to are still alive. If left to - // static destruction, ~ImDisasmView runs after Core's globals are gone and its - // g_disassemblyManager.clear() walks a destroyed map (and locks a destroyed mutex). - imDebugger_.reset(); - ImGui::DestroyContext(ctx_); - ctx_ = nullptr; - imguiInited_ = false; } #if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) @@ -1979,6 +1974,19 @@ void NativeShutdown() { g_screenManager = nullptr; } + if (imguiInited_) { + ImGui_ImplPlatform_SaveIni(true); + // The device objects went with NativeShutdownGraphics. + ImGui_ImplThin3d_Shutdown(); + // Destroy the debugger here, while the things it refers to are still alive. If left to + // static destruction, ~ImDisasmView runs after Core's globals are gone and its + // g_disassemblyManager.clear() walks a destroyed map (and locks a destroyed mutex). + imDebugger_.reset(); + ImGui::DestroyContext(ctx_); + ctx_ = nullptr; + imguiInited_ = false; + } + System_Notify(SystemNotification::BEFORE_CONFIG_SAVE_ON_EXIT); g_Config.Save("NativeShutdown"); diff --git a/ext/imgui/imgui_impl_platform.cpp b/ext/imgui/imgui_impl_platform.cpp index eda6490851..dfaff32157 100644 --- a/ext/imgui/imgui_impl_platform.cpp +++ b/ext/imgui/imgui_impl_platform.cpp @@ -1,5 +1,6 @@ #include "ext/imgui/imgui.h" #include "Common/File/Path.h" +#include "Common/File/FileUtil.h" #include "Common/Input/KeyCodes.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/System/Display.h" @@ -10,6 +11,7 @@ #include "imgui_impl_platform.h" static ImGuiMouseCursor g_cursor = ImGuiMouseCursor_Arrow; +static Path g_iniPath; void ImGui_ImplPlatform_KeyEvent(const KeyInput &key) { ImGuiIO &io = ImGui::GetIO(); @@ -86,10 +88,28 @@ void ImGui_ImplPlatform_TouchEvent(const TouchInput &touch) { } void ImGui_ImplPlatform_Init(const Path &configPath) { - static char path[1024]; - truncate_cpy(path, configPath.ToString()); - ImGui::GetIO().IniFilename = path; + // imgui's own ini handling uses fopen, which can't reach a memstick behind an Android content URI. + g_iniPath = configPath; + ImGui::GetIO().IniFilename = nullptr; ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable; + + std::string data; + if (File::ReadTextFileToString(g_iniPath, &data)) { + ImGui::LoadIniSettingsFromMemory(data.data(), data.size()); + } +} + +void ImGui_ImplPlatform_SaveIni(bool force) { + ImGuiIO &io = ImGui::GetIO(); + if (!force && !io.WantSaveIniSettings) { + return; + } + size_t size = 0; + const char *data = ImGui::SaveIniSettingsToMemory(&size); + if (!File::WriteDataToFile(true, data, size, g_iniPath)) { + WARN_LOG(Log::System, "Failed to save imgui settings to '%s'", g_iniPath.c_str()); + } + io.WantSaveIniSettings = false; } void ImGui_ImplPlatform_AxisEvent(const AxisInput &axis) { diff --git a/ext/imgui/imgui_impl_platform.h b/ext/imgui/imgui_impl_platform.h index c6bec60101..4e6f0f8c3f 100644 --- a/ext/imgui/imgui_impl_platform.h +++ b/ext/imgui/imgui_impl_platform.h @@ -11,6 +11,8 @@ ImGuiKey KeyCodeToImGui(InputKeyCode keyCode); void ImGui_ImplPlatform_Init(const Path &configPath); void ImGui_ImplPlatform_NewFrame(); +// Writes the ini if imgui asked for it, or always if force is set. Call after ImGui::Render. +void ImGui_ImplPlatform_SaveIni(bool force); void ImGui_ImplPlatform_KeyEvent(const KeyInput &key); void ImGui_ImplPlatform_TouchEvent(const TouchInput &touch);