From d584edf5469301f5625fbe85262c27a9c88eb93d Mon Sep 17 00:00:00 2001 From: WerWolv Date: Tue, 30 Jan 2024 11:21:34 +0100 Subject: [PATCH] impr: Improve situation where ImHex crashes on exit when resources aren't cleared properly --- .../include/hex/api/workspace_manager.hpp | 7 +- .../include/hex/helpers/auto_reset.hpp | 64 +++++++++ .../source/api/achievement_manager.cpp | 34 ++--- lib/libimhex/source/api/content_registry.cpp | 121 +++++++++------- lib/libimhex/source/api/imhex_api.cpp | 107 +++++++------- lib/libimhex/source/api/layout_manager.cpp | 24 ++-- .../source/api/localization_manager.cpp | 20 +-- lib/libimhex/source/api/plugin_manager.cpp | 5 +- .../source/api/project_file_manager.cpp | 20 ++- lib/libimhex/source/api/shortcut_manager.cpp | 17 +-- lib/libimhex/source/api/task_manager.cpp | 21 ++- lib/libimhex/source/api/theme_manager.cpp | 58 ++++---- lib/libimhex/source/api/tutorial_manager.cpp | 40 +++--- lib/libimhex/source/api/workspace_manager.cpp | 26 ++-- lib/libimhex/source/helpers/fs.cpp | 33 ++--- lib/libimhex/source/helpers/utils_macos.m | 6 + lib/libimhex/source/ui/popup.cpp | 3 +- lib/libimhex/source/ui/toast.cpp | 3 +- main/gui/source/init/tasks.cpp | 130 ++++-------------- 19 files changed, 376 insertions(+), 363 deletions(-) create mode 100644 lib/libimhex/include/hex/helpers/auto_reset.hpp diff --git a/lib/libimhex/include/hex/api/workspace_manager.hpp b/lib/libimhex/include/hex/api/workspace_manager.hpp index 4f9cd42e5..a255e1eac 100644 --- a/lib/libimhex/include/hex/api/workspace_manager.hpp +++ b/lib/libimhex/include/hex/api/workspace_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -20,7 +21,7 @@ namespace hex { static void importFromFile(const std::fs::path &path); static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {}); - static const auto& getWorkspaces() { return s_workspaces; } + static const auto& getWorkspaces() { return *s_workspaces; } static const auto& getCurrentWorkspace() { return s_currentWorkspace; } static void reset(); @@ -30,8 +31,8 @@ namespace hex { private: WorkspaceManager() = default; - static std::map s_workspaces; - static decltype(s_workspaces)::iterator s_currentWorkspace, s_previousWorkspace; + static AutoReset> s_workspaces; + static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace; }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/helpers/auto_reset.hpp b/lib/libimhex/include/hex/helpers/auto_reset.hpp new file mode 100644 index 000000000..2981ccc8b --- /dev/null +++ b/lib/libimhex/include/hex/helpers/auto_reset.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include + +namespace hex { + + template + class AutoReset { + public: + using Type = T; + + AutoReset() { + EventImHexClosing::subscribe(this, [this] { + this->reset(); + }); + } + + ~AutoReset() { + EventImHexClosing::unsubscribe(this); + } + + T* operator->() { + return &m_value; + } + + const T* operator->() const { + return &m_value; + } + + T& operator*() { + return m_value; + } + + const T& operator*() const { + return m_value; + } + + operator T&() { + return m_value; + } + + operator const T&() const { + return m_value; + } + + T& operator=(const T &value) { + m_value = value; + return m_value; + } + + T& operator=(T &&value) noexcept { + m_value = std::move(value); + return m_value; + } + + void reset() { + m_value = T(); + } + + private: + T m_value; + }; + +} \ No newline at end of file diff --git a/lib/libimhex/source/api/achievement_manager.cpp b/lib/libimhex/source/api/achievement_manager.cpp index 47232f0a3..464fc8c9d 100644 --- a/lib/libimhex/source/api/achievement_manager.cpp +++ b/lib/libimhex/source/api/achievement_manager.cpp @@ -1,27 +1,29 @@ #include #include +#include + #include namespace hex { std::unordered_map>> &AchievementManager::getAchievements() { - static std::unordered_map>> achievements; + static AutoReset>>> achievements; return achievements; } std::unordered_map>& AchievementManager::getAchievementNodes(bool rebuild) { - static std::unordered_map> nodeCategoryStorage; + static AutoReset>> nodeCategoryStorage; - if (!nodeCategoryStorage.empty() || !rebuild) + if (!nodeCategoryStorage->empty() || !rebuild) return nodeCategoryStorage; - nodeCategoryStorage.clear(); + nodeCategoryStorage->clear(); // Add all achievements to the node storage for (auto &[categoryName, achievements] : getAchievements()) { - auto &nodes = nodeCategoryStorage[categoryName]; + auto &nodes = (*nodeCategoryStorage)[categoryName]; for (auto &[achievementName, achievement] : achievements) { nodes.emplace_back(achievement.get()); @@ -32,21 +34,21 @@ namespace hex { } std::unordered_map>& AchievementManager::getAchievementStartNodes(bool rebuild) { - static std::unordered_map> startNodes; + static AutoReset>> startNodes; - if (!startNodes.empty() || !rebuild) + if (!startNodes->empty() || !rebuild) return startNodes; auto &nodeCategoryStorage = getAchievementNodes(); - startNodes.clear(); + startNodes->clear(); // Add all parents and children to the nodes for (auto &[categoryName, achievements] : nodeCategoryStorage) { for (auto &achievementNode : achievements) { for (auto &requirement : achievementNode.achievement->getRequirements()) { for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) { - auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) { + auto iter = std::ranges::find_if(requirementAchievements, [&requirement](auto &node) { return node.achievement->getUnlocalizedName() == requirement; }); @@ -59,7 +61,7 @@ namespace hex { for (auto &requirement : achievementNode.achievement->getVisibilityRequirements()) { for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) { - auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) { + auto iter = std::ranges::find_if(requirementAchievements, [&requirement](auto &node) { return node.achievement->getUnlocalizedName() == requirement; }); @@ -74,12 +76,12 @@ namespace hex { for (auto &[categoryName, achievements] : nodeCategoryStorage) { for (auto &achievementNode : achievements) { if (!achievementNode.hasParents()) { - startNodes[categoryName].emplace_back(&achievementNode); + (*startNodes)[categoryName].emplace_back(&achievementNode); } for (const auto &parent : achievementNode.parents) { if (parent->achievement->getUnlocalizedCategory() != achievementNode.achievement->getUnlocalizedCategory()) - startNodes[categoryName].emplace_back(&achievementNode); + (*startNodes)[categoryName].emplace_back(&achievementNode); } } } @@ -97,14 +99,12 @@ namespace hex { auto &[categoryName, achievements] = *categoryIter; - auto achievementIter = achievements.find(unlocalizedName); - + const auto achievementIter = achievements.find(unlocalizedName); if (achievementIter == achievements.end()) { return; } - auto &nodes = getAchievementNodes()[categoryName]; - + const auto &nodes = getAchievementNodes()[categoryName]; for (const auto &node : nodes) { auto &achievement = node.achievement; @@ -238,7 +238,7 @@ namespace hex { } } - auto result = json.dump(4); + const auto result = json.dump(4); file.setSize(0); file.writeString(result); break; diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index e9025997a..847d36979 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -40,7 +41,7 @@ namespace hex { } nlohmann::json &getSettingsData() { - static nlohmann::json settings; + static AutoReset settings; return settings; } @@ -89,19 +90,21 @@ namespace hex { } void store() { - auto settingsData = getSettingsData(); + const auto &settingsData = getSettingsData(); // During a crash settings can be empty, causing them to be overwritten. if (settingsData.empty()) { return; } + const auto result = settingsData.dump(4); + if (result.empty()) { + return; + } for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) { wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Write); if (file.isValid()) { - auto result = settingsData.dump(4); - file.setSize(0); file.writeString(result); break; @@ -137,7 +140,7 @@ namespace hex { } std::vector &getSettings() { - static std::vector categories; + static AutoReset> categories; return categories; } @@ -245,7 +248,7 @@ namespace hex { void ColorPicker::load(const nlohmann::json &data) { if (data.is_number()) { - ImColor color(data.get()); + const ImColor color(data.get()); m_value = { color.Value.x, color.Value.y, color.Value.z, color.Value.w }; } else { log::warn("Invalid data type loaded from settings for color picker!"); @@ -264,7 +267,7 @@ namespace hex { bool DropDown::draw(const std::string &name) { - const char *preview = ""; + auto preview = ""; if (static_cast(m_value) < m_items.size()) preview = m_items[m_value].c_str(); @@ -408,13 +411,13 @@ namespace hex { namespace impl { std::vector &getEntries() { - static std::vector commands; + static AutoReset> commands; return commands; } std::vector &getHandlers() { - static std::vector commands; + static AutoReset> commands; return commands; } @@ -521,25 +524,25 @@ namespace hex { namespace impl { std::map &getVisualizers() { - static std::map visualizers; + static AutoReset> visualizers; return visualizers; } std::map &getInlineVisualizers() { - static std::map visualizers; + static AutoReset> visualizers; return visualizers; } std::map &getPragmas() { - static std::map pragmas; + static AutoReset> pragmas; return pragmas; } std::vector &getFunctions() { - static std::vector functions; + static AutoReset> functions; return functions; } @@ -555,7 +558,7 @@ namespace hex { namespace impl { std::map> &getEntries() { - static std::map> views; + static AutoReset>> views; return views; } @@ -590,7 +593,7 @@ namespace hex { namespace impl { std::vector &getEntries() { - static std::vector tools; + static AutoReset> tools; return tools; } @@ -616,7 +619,7 @@ namespace hex { namespace impl { std::vector &getEntries() { - static std::vector entries; + static AutoReset> entries; return entries; } @@ -641,7 +644,7 @@ namespace hex { namespace impl { std::vector &getEntries() { - static std::vector nodes; + static AutoReset> nodes; return nodes; } @@ -696,13 +699,13 @@ namespace hex { namespace impl { std::map &getLanguages() { - static std::map languages; + static AutoReset> languages; return languages; } std::map> &getLanguageDefinitions() { - static std::map> definitions; + static AutoReset>> definitions; return definitions; } @@ -784,7 +787,7 @@ namespace hex { } void addMenuItemToToolbar(const UnlocalizedString& unlocalizedName, ImGuiCustomCol color) { - auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) { + const auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) { return a.second.toolbarIndex < b.second.toolbarIndex; })->second.toolbarIndex; @@ -809,38 +812,38 @@ namespace hex { namespace impl { std::multimap &getMainMenuItems() { - static std::multimap items; + static AutoReset> items; return items; } std::multimap &getMenuItems() { - static std::multimap items; + static AutoReset> items; return items; } std::vector &getWelcomeScreenEntries() { - static std::vector entries; + static AutoReset> entries; return entries; } std::vector &getFooterItems() { - static std::vector items; + static AutoReset> items; return items; } std::vector &getToolbarItems() { - static std::vector items; + static AutoReset> items; return items; } std::vector &getSidebarItems() { - static std::vector items; + static AutoReset> items; return items; } std::vector &getTitleBarButtons() { - static std::vector buttons; + static AutoReset> buttons; return buttons; } @@ -867,7 +870,7 @@ namespace hex { } std::vector &getEntries() { - static std::vector providerNames; + static AutoReset> providerNames; return providerNames; } @@ -894,7 +897,7 @@ namespace hex { namespace impl { std::vector &getEntries() { - static std::vector entries; + static AutoReset> entries; return entries; } @@ -915,7 +918,7 @@ namespace hex { namespace impl { std::vector &getEntries() { - static std::vector entries; + static AutoReset> entries; return entries; } @@ -996,13 +999,13 @@ namespace hex { } std::vector> &getVisualizers() { - static std::vector> visualizers; + static AutoReset>> visualizers; return visualizers; } std::vector> &getMiniMapVisualizers() { - static std::vector> visualizers; + static AutoReset>> visualizers; return visualizers; } @@ -1029,7 +1032,7 @@ namespace hex { namespace impl { std::vector>& getAlgorithms() { - static std::vector> algorithms; + static AutoReset>> algorithms; return algorithms; } @@ -1047,7 +1050,7 @@ namespace hex { namespace impl { std::vector> &getHashes() { - static std::vector> hashes; + static AutoReset>> hashes; return hashes; } @@ -1064,29 +1067,41 @@ namespace hex { namespace impl { - struct Service { - std::string name; - std::jthread thread; + class Service { + public: + Service(std::string name, std::jthread thread) : m_name(std::move(name)), m_thread(std::move(thread)) { } + Service(const Service&) = delete; + Service(Service &&) = default; + ~Service() { + m_thread.request_stop(); + if (m_thread.joinable()) + m_thread.join(); + } + + Service& operator=(const Service&) = delete; + Service& operator=(Service &&) = default; + + [[nodiscard]] const std::string &getName() const { + return m_name; + } + + [[nodiscard]] const std::jthread &getThread() const { + return m_thread; + } + + private: + std::string m_name; + std::jthread m_thread; }; std::vector &getServices() { - static std::vector services; + static AutoReset> services; return services; } void stopServices() { auto &services = getServices(); - - for (auto &service : services) { - service.thread.request_stop(); - } - - for (auto &service : services) { - if (service.thread.joinable()) - service.thread.join(); - } - services.clear(); } @@ -1095,7 +1110,7 @@ namespace hex { void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) { log::debug("Registered new background service: {}", unlocalizedName.get()); - impl::getServices().push_back(impl::Service { + impl::getServices().emplace_back( unlocalizedName, std::jthread([callback = auto(callback)](const std::stop_token &stopToken){ while (!stopToken.stop_requested()) { @@ -1103,7 +1118,7 @@ namespace hex { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } }) - }); + ); } } @@ -1113,7 +1128,7 @@ namespace hex { namespace impl { std::map &getNetworkEndpoints() { - static std::map endpoints; + static AutoReset> endpoints; return endpoints; } @@ -1133,7 +1148,7 @@ namespace hex { namespace impl { std::map &getExperiments() { - static std::map experiments; + static AutoReset> experiments; return experiments; } @@ -1184,7 +1199,7 @@ namespace hex { namespace impl { std::vector &getGenerators() { - static std::vector generators; + static AutoReset> generators; return generators; } diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index c1cac1925..6e8d2dcf7 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -5,11 +5,11 @@ #include #include #include +#include #include #include -#include #include #include @@ -19,6 +19,7 @@ #include #else #include + #include #endif namespace hex { @@ -36,39 +37,39 @@ namespace hex { namespace impl { - static std::map s_backgroundHighlights; std::map &getBackgroundHighlights() { - return s_backgroundHighlights; + static AutoReset> backgroundHighlights; + return backgroundHighlights; } - static std::map s_backgroundHighlightingFunctions; std::map &getBackgroundHighlightingFunctions() { - return s_backgroundHighlightingFunctions; + static AutoReset> backgroundHighlightingFunctions; + return backgroundHighlightingFunctions; } - static std::map s_foregroundHighlights; std::map &getForegroundHighlights() { - return s_foregroundHighlights; + static AutoReset> foregroundHighlights; + return foregroundHighlights; } - static std::map s_foregroundHighlightingFunctions; std::map &getForegroundHighlightingFunctions() { - return s_foregroundHighlightingFunctions; + static AutoReset> foregroundHighlightingFunctions; + return foregroundHighlightingFunctions; } - static std::map s_tooltips; std::map &getTooltips() { - return s_tooltips; + static AutoReset> tooltips; + return tooltips; } - static std::map s_tooltipFunctions; std::map &getTooltipFunctions() { - return s_tooltipFunctions; + static AutoReset> tooltipFunctions; + return tooltipFunctions; } - static std::optional s_currentSelection; + static AutoReset> s_currentSelection; void setCurrentSelection(const std::optional ®ion) { - s_currentSelection = region; + *s_currentSelection = region; } } @@ -226,7 +227,7 @@ namespace hex { namespace ImHexApi::Provider { static i64 s_currentProvider = -1; - static std::vector s_providers; + static AutoReset> s_providers; namespace impl { @@ -245,7 +246,7 @@ namespace hex { if (!ImHexApi::Provider::isValid()) return nullptr; - return s_providers[s_currentProvider]; + return (*s_providers)[s_currentProvider]; } const std::vector &getProviders() { @@ -256,7 +257,7 @@ namespace hex { if (TaskManager::getRunningTaskCount() > 0) return; - if (index < s_providers.size() && s_currentProvider != index) { + if (index < s_providers->size() && s_currentProvider != index) { auto oldProvider = get(); s_currentProvider = index; EventProviderChanged::post(oldProvider, get()); @@ -268,7 +269,7 @@ namespace hex { } bool isValid() { - return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size()); + return !s_providers->empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers->size()); } void markDirty() { @@ -276,12 +277,12 @@ namespace hex { } void resetDirty() { - for (auto &provider : s_providers) + for (const auto &provider : *s_providers) provider->markDirty(false); } bool isDirty() { - return std::ranges::any_of(s_providers, [](const auto &provider) { + return std::ranges::any_of(*s_providers, [](const auto &provider) { return provider->isDirty(); }); } @@ -293,11 +294,11 @@ namespace hex { if (skipLoadInterface) provider->skipLoadInterface(); - s_providers.push_back(provider); + s_providers->push_back(provider); EventProviderCreated::post(provider); - if (select || s_providers.size() == 1) - setCurrentProvider(s_providers.size() - 1); + if (select || s_providers->size() == 1) + setCurrentProvider(s_providers->size() - 1); } void remove(prv::Provider *provider, bool noQuestions) { @@ -316,29 +317,29 @@ namespace hex { return; } - auto it = std::find(s_providers.begin(), s_providers.end(), provider); - if (it == s_providers.end()) + const auto it = std::ranges::find(*s_providers, provider); + if (it == s_providers->end()) return; - if (!s_providers.empty()) { - if (it == s_providers.begin()) { + if (!s_providers->empty()) { + if (it == s_providers->begin()) { // If the first provider is being closed, select the one that's the first one now setCurrentProvider(0); - if (s_providers.size() > 1) - EventProviderChanged::post(s_providers[0], s_providers[1]); + if (s_providers->size() > 1) + EventProviderChanged::post(s_providers->at(0), s_providers->at(1)); } - else if (std::distance(s_providers.begin(), it) == s_currentProvider) { + else if (std::distance(s_providers->begin(), it) == s_currentProvider) { // If the current provider is being closed, select the one that's before it setCurrentProvider(s_currentProvider - 1); } else { // If any other provider is being closed, find the current provider in the list again and select it again - auto currentProvider = get(); - auto currentIt = std::find(s_providers.begin(), s_providers.end(), currentProvider); + const auto currentProvider = get(); + const auto currentIt = std::ranges::find(*s_providers, currentProvider); - if (currentIt != s_providers.end()) { - auto newIndex = std::distance(s_providers.begin(), currentIt); + if (currentIt != s_providers->end()) { + auto newIndex = std::distance(s_providers->begin(), currentIt); if (s_currentProvider == newIndex) newIndex -= 1; @@ -351,11 +352,11 @@ namespace hex { } } - s_providers.erase(it); - if (s_currentProvider >= i64(s_providers.size())) + s_providers->erase(it); + if (s_currentProvider >= i64(s_providers->size())) setCurrentProvider(0); - if (s_providers.empty()) + if (s_providers->empty()) EventProviderChanged::post(provider, nullptr); provider->close(); @@ -391,11 +392,11 @@ namespace hex { static ImVec2 s_mainWindowPos; static ImVec2 s_mainWindowSize; void setMainWindowPosition(i32 x, i32 y) { - s_mainWindowPos = ImVec2(x, y); + s_mainWindowPos = ImVec2(float(x), float(y)); } void setMainWindowSize(u32 width, u32 height) { - s_mainWindowSize = ImVec2(width, height); + s_mainWindowSize = ImVec2(float(width), float(height)); } static ImGuiID s_mainDockSpaceId; @@ -436,7 +437,7 @@ namespace hex { } - static std::string s_gpuVendor; + static AutoReset s_gpuVendor; void setGPUVendor(const std::string &vendor) { s_gpuVendor = vendor; } @@ -536,7 +537,7 @@ namespace hex { } std::map &getInitArguments() { - static std::map initArgs; + static AutoReset> initArgs; return initArgs; } @@ -556,7 +557,7 @@ namespace hex { std::vector &getAdditionalFolderPaths() { - static std::vector additionalFolderPaths; + static AutoReset> additionalFolderPaths; return additionalFolderPaths; } @@ -595,7 +596,7 @@ namespace hex { return hex::format("{}.{}.{}", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber); #elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB) - struct utsname details; + struct utsname details = { }; if (uname(&details) != 0) { return "Unknown"; @@ -627,13 +628,13 @@ namespace hex { return "Unknown"; } #elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB) - struct utsname details; + struct utsname details = { }; if (uname(&details) != 0) { return "Unknown"; } - return std::string(details.machine); + return { details.machine }; #else return "Unknown"; #endif @@ -732,7 +733,7 @@ namespace hex { } void setWindowResizable(bool resizable) { - glfwSetWindowAttrib(impl::s_mainWindowHandle, GLFW_RESIZABLE, resizable); + glfwSetWindowAttrib(impl::s_mainWindowHandle, GLFW_RESIZABLE, int(resizable)); impl::s_windowResizable = resizable; } @@ -745,14 +746,14 @@ namespace hex { namespace impl { std::map &getHandlers() { - static std::map handlers; + static AutoReset> handlers; return handlers; } void runHandler(const std::string &eventName, const std::vector &args) { const auto& handlers = impl::getHandlers(); - auto matchHandler = handlers.find(eventName); + const auto matchHandler = handlers.find(eventName); if (matchHandler == handlers.end()) { log::error("Forward event handler {} not found", eventName); @@ -777,12 +778,12 @@ namespace hex { namespace impl { std::vector& getFonts() { - static std::vector fonts; + static AutoReset> fonts; return fonts; } - static std::fs::path s_customFontPath; + static AutoReset s_customFontPath; void setCustomFontPath(const std::fs::path &path) { s_customFontPath = path; } @@ -792,7 +793,7 @@ namespace hex { s_fontSize = size; } - static std::unique_ptr s_fontAtlas; + static AutoReset> s_fontAtlas; void setFontAtlas(ImFontAtlas* fontAtlas) { s_fontAtlas = std::unique_ptr(fontAtlas); } @@ -875,7 +876,7 @@ namespace hex { } ImFontAtlas* getFontAtlas() { - return impl::s_fontAtlas.get(); + return impl::s_fontAtlas->get(); } ImFont* Bold() { diff --git a/lib/libimhex/source/api/layout_manager.cpp b/lib/libimhex/source/api/layout_manager.cpp index d48473065..6f6747c9c 100644 --- a/lib/libimhex/source/api/layout_manager.cpp +++ b/lib/libimhex/source/api/layout_manager.cpp @@ -6,16 +6,16 @@ #include #include -#include #include +#include namespace hex { namespace { - std::optional s_layoutPathToLoad; - std::optional s_layoutStringToLoad; - std::vector s_layouts; + AutoReset> s_layoutPathToLoad; + AutoReset> s_layoutStringToLoad; + AutoReset> s_layouts; bool s_layoutLocked = false; @@ -33,7 +33,7 @@ namespace hex { void LayoutManager::save(const std::string &name) { auto fileName = name; fileName = wolv::util::replaceStrings(fileName, " ", "_"); - std::transform(fileName.begin(), fileName.end(), fileName.begin(), tolower); + std::ranges::transform(fileName, fileName.begin(), tolower); fileName += ".hexlyt"; std::fs::path layoutPath; @@ -71,8 +71,8 @@ namespace hex { } void LayoutManager::process() { - if (s_layoutPathToLoad.has_value()) { - const auto pathString = wolv::util::toUTF8String(*s_layoutPathToLoad); + if (s_layoutPathToLoad->has_value()) { + const auto pathString = wolv::util::toUTF8String(**s_layoutPathToLoad); LayoutManager::closeAllViews(); ImGui::LoadIniSettingsFromDisk(pathString.c_str()); @@ -81,9 +81,9 @@ namespace hex { log::info("Loaded layout from {}", pathString); } - if (s_layoutStringToLoad.has_value()) { + if (s_layoutStringToLoad->has_value()) { LayoutManager::closeAllViews(); - ImGui::LoadIniSettingsFromMemory(s_layoutStringToLoad->c_str()); + ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str()); s_layoutStringToLoad = std::nullopt; log::info("Loaded layout from string"); @@ -91,7 +91,7 @@ namespace hex { } void LayoutManager::reload() { - s_layouts.clear(); + s_layouts->clear(); for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) { for (const auto &entry : std::fs::directory_iterator(directory)) { @@ -107,7 +107,7 @@ namespace hex { name[i] = char(std::toupper(name[i])); } - s_layouts.push_back({ + s_layouts->push_back({ name, path }); @@ -118,7 +118,7 @@ namespace hex { void LayoutManager::reset() { s_layoutPathToLoad.reset(); s_layoutStringToLoad.reset(); - s_layouts.clear(); + s_layouts->clear(); } bool LayoutManager::isLayoutLocked() { diff --git a/lib/libimhex/source/api/localization_manager.cpp b/lib/libimhex/source/api/localization_manager.cpp index 49670ef2b..421803adb 100644 --- a/lib/libimhex/source/api/localization_manager.cpp +++ b/lib/libimhex/source/api/localization_manager.cpp @@ -7,17 +7,17 @@ namespace hex { namespace { - std::string s_fallbackLanguage; - std::string s_selectedLanguage; - std::map s_currStrings; + AutoReset s_fallbackLanguage; + AutoReset s_selectedLanguage; + AutoReset> s_currStrings; } namespace impl { void resetLanguageStrings() { - s_currStrings.clear(); - s_selectedLanguage.clear(); + s_currStrings->clear(); + s_selectedLanguage->clear(); } void setFallbackLanguage(const std::string &language) { @@ -41,7 +41,7 @@ namespace hex { } void loadLanguage(const std::string &language) { - s_currStrings.clear(); + s_currStrings->clear(); auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions(); @@ -49,12 +49,12 @@ namespace hex { return; for (auto &definition : definitions[language]) - s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end()); + s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end()); const auto& fallbackLanguage = getFallbackLanguage(); if (language != fallbackLanguage) { for (auto &definition : definitions[fallbackLanguage]) - s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end()); + s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end()); } s_selectedLanguage = language; @@ -122,8 +122,8 @@ namespace hex { const std::string &Lang::get() const { auto &lang = LocalizationManager::s_currStrings; - if (lang.contains(m_unlocalizedString)) - return lang[m_unlocalizedString]; + if (lang->contains(m_unlocalizedString)) + return lang->at(m_unlocalizedString); else return m_unlocalizedString; } diff --git a/lib/libimhex/source/api/plugin_manager.cpp b/lib/libimhex/source/api/plugin_manager.cpp index bb476ca21..b14f7ec42 100644 --- a/lib/libimhex/source/api/plugin_manager.cpp +++ b/lib/libimhex/source/api/plugin_manager.cpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -303,13 +302,13 @@ namespace hex { } std::vector &PluginManager::getPluginPaths() { - static std::vector pluginPaths; + static AutoReset> pluginPaths; return pluginPaths; } std::vector &PluginManager::getPluginLoadPaths() { - static std::vector pluginPaths; + static AutoReset> pluginPaths; return pluginPaths; } diff --git a/lib/libimhex/source/api/project_file_manager.cpp b/lib/libimhex/source/api/project_file_manager.cpp index fe6f98c1a..0093aeaa5 100644 --- a/lib/libimhex/source/api/project_file_manager.cpp +++ b/lib/libimhex/source/api/project_file_manager.cpp @@ -1,20 +1,18 @@ #include -#include - #include namespace hex { namespace { - std::vector s_handlers; - std::vector s_providerHandlers; + AutoReset> s_handlers; + AutoReset> s_providerHandlers; - std::fs::path s_currProjectPath; + AutoReset s_currProjectPath; - std::function s_loadProjectFunction; - std::function, bool)> s_storeProjectFunction; + AutoReset> s_loadProjectFunction; + AutoReset, bool)>> s_storeProjectFunction; } @@ -28,19 +26,19 @@ namespace hex { } bool ProjectFile::load(const std::fs::path &filePath) { - return s_loadProjectFunction(filePath); + return (*s_loadProjectFunction)(filePath); } bool ProjectFile::store(std::optional filePath, bool updateLocation) { - return s_storeProjectFunction(std::move(filePath), updateLocation); + return (*s_storeProjectFunction)(std::move(filePath), updateLocation); } bool ProjectFile::hasPath() { - return !s_currProjectPath.empty(); + return !s_currProjectPath->empty(); } void ProjectFile::clearPath() { - s_currProjectPath.clear(); + s_currProjectPath->clear(); } std::fs::path ProjectFile::getPath() { diff --git a/lib/libimhex/source/api/shortcut_manager.cpp b/lib/libimhex/source/api/shortcut_manager.cpp index 04ac2908e..c70bba9e0 100644 --- a/lib/libimhex/source/api/shortcut_manager.cpp +++ b/lib/libimhex/source/api/shortcut_manager.cpp @@ -8,7 +8,7 @@ namespace hex { namespace { - std::map s_globalShortcuts; + AutoReset> s_globalShortcuts; std::atomic s_paused; std::optional s_prevShortcut; @@ -16,7 +16,7 @@ namespace hex { void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function &callback) { - s_globalShortcuts.insert({ shortcut, { shortcut, unlocalizedName, callback } }); + s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } }); } void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function &callback) { @@ -57,7 +57,7 @@ namespace hex { } void ShortcutManager::process(const std::unique_ptr ¤tView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) { - Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode); + const Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode); if (keyCode != 0) s_prevShortcut = Shortcut(pressedShortcut.getKeys()); @@ -65,7 +65,7 @@ namespace hex { } void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) { - Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode); + const Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode); if (keyCode != 0) s_prevShortcut = Shortcut(pressedShortcut.getKeys()); @@ -73,7 +73,7 @@ namespace hex { } void ShortcutManager::clearShortcuts() { - s_globalShortcuts.clear(); + s_globalShortcuts->clear(); } void ShortcutManager::resumeShortcuts() { @@ -90,17 +90,18 @@ namespace hex { } std::vector ShortcutManager::getGlobalShortcuts() { - std::vector result; + std::vector result; - for (auto &[shortcut, entry] : s_globalShortcuts) + for (auto &[shortcut, entry] : *s_globalShortcuts) result.push_back(entry); return result; } std::vector ShortcutManager::getViewShortcuts(const View *view) { - std::vector result; + std::vector result; + result.reserve(view->m_shortcuts.size()); for (auto &[shortcut, entry] : view->m_shortcuts) result.push_back(entry); diff --git a/lib/libimhex/source/api/task_manager.cpp b/lib/libimhex/source/api/task_manager.cpp index 5de452b5c..138d8afb1 100644 --- a/lib/libimhex/source/api/task_manager.cpp +++ b/lib/libimhex/source/api/task_manager.cpp @@ -7,7 +7,6 @@ #include #include -#include #if defined(OS_WINDOWS) #include @@ -149,7 +148,7 @@ namespace hex { bool TaskHolder::isRunning() const { - auto task = m_task.lock(); + const auto &task = m_task.lock(); if (!task) return false; @@ -157,7 +156,7 @@ namespace hex { } bool TaskHolder::hadException() const { - auto task = m_task.lock(); + const auto &task = m_task.lock(); if (!task) return false; @@ -165,7 +164,7 @@ namespace hex { } bool TaskHolder::shouldInterrupt() const { - auto task = m_task.lock(); + const auto &task = m_task.lock(); if (!task) return false; @@ -173,7 +172,7 @@ namespace hex { } bool TaskHolder::wasInterrupted() const { - auto task = m_task.lock(); + const auto &task = m_task.lock(); if (!task) return false; @@ -181,7 +180,7 @@ namespace hex { } void TaskHolder::interrupt() const { - auto task = m_task.lock(); + const auto &task = m_task.lock(); if (!task) return; @@ -189,9 +188,9 @@ namespace hex { } u32 TaskHolder::getProgress() const { - auto task = m_task.lock(); + const auto &task = m_task.lock(); if (!task) - return false; + return 0; // If the max value is 0, the task has no progress if (task->getMaxValue() == 0) @@ -265,7 +264,7 @@ namespace hex { void TaskManager::exit() { // Interrupt all tasks - for (auto &task : s_tasks) { + for (const auto &task : s_tasks) { task->interrupt(); } @@ -342,7 +341,7 @@ namespace hex { size_t TaskManager::getRunningTaskCount() { std::scoped_lock lock(s_queueMutex); - return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){ + return std::ranges::count_if(s_tasks, [](const auto &task){ return !task->isBackgroundTask(); }); } @@ -350,7 +349,7 @@ namespace hex { size_t TaskManager::getRunningBackgroundTaskCount() { std::scoped_lock lock(s_queueMutex); - return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){ + return std::ranges::count_if(s_tasks, [](const auto &task){ return task->isBackgroundTask(); }); } diff --git a/lib/libimhex/source/api/theme_manager.cpp b/lib/libimhex/source/api/theme_manager.cpp index c1a4d82fb..8eccb7531 100644 --- a/lib/libimhex/source/api/theme_manager.cpp +++ b/lib/libimhex/source/api/theme_manager.cpp @@ -10,21 +10,21 @@ namespace hex { namespace { - std::map s_themes; - std::map s_themeHandlers; - std::map s_styleHandlers; - std::string s_imageTheme; - std::string s_currTheme; + AutoReset> s_themes; + AutoReset> s_themeHandlers; + AutoReset> s_styleHandlers; + AutoReset s_imageTheme; + AutoReset s_currTheme; } void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function &getFunction, const std::function &setFunction) { - s_themeHandlers[name] = { colorMap, getFunction, setFunction }; + (*s_themeHandlers)[name] = { colorMap, getFunction, setFunction }; } void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) { - s_styleHandlers[name] = { styleMap }; + (*s_styleHandlers)[name] = { styleMap }; } void ThemeManager::addTheme(const std::string &content) { @@ -32,7 +32,7 @@ namespace hex { auto theme = nlohmann::json::parse(content); if (theme.contains("name") && theme.contains("colors")) { - s_themes[theme["name"].get()] = theme; + (*s_themes)[theme["name"].get()] = theme; } else { hex::log::error("Invalid theme file"); } @@ -77,7 +77,7 @@ namespace hex { { "base", s_currTheme } }; - for (const auto &[type, handler] : s_themeHandlers) { + for (const auto &[type, handler] : *s_themeHandlers) { theme["colors"][type] = {}; for (const auto &[key, value] : handler.colorMap) { @@ -86,7 +86,7 @@ namespace hex { } } - for (const auto &[type, handler] : s_styleHandlers) { + for (const auto &[type, handler] : *s_styleHandlers) { theme["styles"][type] = {}; for (const auto &[key, style] : handler.styleMap) { @@ -105,17 +105,17 @@ namespace hex { } void ThemeManager::changeTheme(std::string name) { - if (!s_themes.contains(name)) { - if (s_themes.empty()) { + if (!s_themes->contains(name)) { + if (s_themes->empty()) { return; } else { - const std::string &defaultTheme = s_themes.begin()->first; + const std::string &defaultTheme = s_themes->begin()->first; hex::log::error("Theme '{}' does not exist, using default theme '{}' instead!", name, defaultTheme); name = defaultTheme; } } - const auto &theme = s_themes[name]; + const auto &theme = (*s_themes)[name]; if (theme.contains("base")) { if (theme["base"].is_string()) { @@ -126,14 +126,14 @@ namespace hex { } } - if (theme.contains("colors") && !s_themeHandlers.empty()) { + if (theme.contains("colors") && !s_themeHandlers->empty()) { for (const auto&[type, content] : theme["colors"].items()) { - if (!s_themeHandlers.contains(type)) { + if (!s_themeHandlers->contains(type)) { log::warn("No theme handler found for '{}'", type); continue; } - const auto &handler = s_themeHandlers[type]; + const auto &handler = (*s_themeHandlers)[type]; for (const auto &[key, value] : content.items()) { if (!handler.colorMap.contains(key)) { log::warn("No color found for '{}.{}'", type, key); @@ -146,19 +146,19 @@ namespace hex { continue; } - s_themeHandlers[type].setFunction(s_themeHandlers[type].colorMap.at(key), color.value()); + (*s_themeHandlers)[type].setFunction((*s_themeHandlers)[type].colorMap.at(key), color.value()); } } } - if (theme.contains("styles") && !s_styleHandlers.empty()) { + if (theme.contains("styles") && !s_styleHandlers->empty()) { for (const auto&[type, content] : theme["styles"].items()) { - if (!s_styleHandlers.contains(type)) { + if (!s_styleHandlers->contains(type)) { log::warn("No style handler found for '{}'", type); continue; } - auto &handler = s_styleHandlers[type]; + auto &handler = (*s_styleHandlers)[type]; for (const auto &[key, value] : content.items()) { if (!handler.styleMap.contains(key)) continue; @@ -167,12 +167,12 @@ namespace hex { const float scale = style.needsScaling ? 1_scaled : 1.0F; if (value.is_number_float()) { - if (auto newValue = std::get_if(&style.value); newValue != nullptr) + if (const auto newValue = std::get_if(&style.value); newValue != nullptr) **newValue = value.get() * scale; else log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name); } else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) { - if (auto newValue = std::get_if(&style.value); newValue != nullptr) + if (const auto newValue = std::get_if(&style.value); newValue != nullptr) **newValue = ImVec2(value[0].get() * scale, value[1].get() * scale); else log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name); @@ -203,18 +203,18 @@ namespace hex { std::vector ThemeManager::getThemeNames() { std::vector themeNames; - for (const auto &[name, theme] : s_themes) + for (const auto &[name, theme] : *s_themes) themeNames.push_back(name); return themeNames; } void ThemeManager::reset() { - s_themes.clear(); - s_styleHandlers.clear(); - s_themeHandlers.clear(); - s_imageTheme.clear(); - s_currTheme.clear(); + s_themes->clear(); + s_styleHandlers->clear(); + s_themeHandlers->clear(); + s_imageTheme->clear(); + s_currTheme->clear(); } diff --git a/lib/libimhex/source/api/tutorial_manager.cpp b/lib/libimhex/source/api/tutorial_manager.cpp index 7a5ae66cd..b779035c0 100644 --- a/lib/libimhex/source/api/tutorial_manager.cpp +++ b/lib/libimhex/source/api/tutorial_manager.cpp @@ -13,11 +13,11 @@ namespace hex { namespace { - std::map s_tutorials; - decltype(s_tutorials)::iterator s_currentTutorial = s_tutorials.end(); + AutoReset> s_tutorials; + auto s_currentTutorial = s_tutorials->end(); - std::map s_highlights; - std::vector> s_highlightDisplays; + AutoReset> s_highlights; + AutoReset>> s_highlightDisplays; class IDStack { @@ -67,19 +67,19 @@ namespace hex { TutorialManager::Tutorial& TutorialManager::createTutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) { - return s_tutorials.try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second; + return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second; } void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) { - s_currentTutorial = s_tutorials.find(unlocalizedName); - if (s_currentTutorial == s_tutorials.end()) + s_currentTutorial = s_tutorials->find(unlocalizedName); + if (s_currentTutorial == s_tutorials->end()) return; s_currentTutorial->second.start(); } void TutorialManager::drawHighlights() { - for (const auto &[rect, unlocalizedText] : s_highlightDisplays) { + for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) { const auto drawList = ImGui::GetForegroundDrawList(); drawList->PushClipRectFullScreen(); @@ -122,7 +122,7 @@ namespace hex { drawList->PopClipRect(); } - s_highlightDisplays.clear(); + s_highlightDisplays->clear(); } void TutorialManager::drawMessageBox(std::optional message) { @@ -196,7 +196,7 @@ namespace hex { void TutorialManager::drawTutorial() { drawHighlights(); - if (s_currentTutorial == s_tutorials.end()) + if (s_currentTutorial == s_tutorials->end()) return; const auto ¤tStep = s_currentTutorial->second.m_currentStep; @@ -210,11 +210,11 @@ namespace hex { void TutorialManager::reset() { - s_tutorials.clear(); - s_currentTutorial = s_tutorials.end(); + s_tutorials->clear(); + s_currentTutorial = s_tutorials->end(); - s_highlights.clear(); - s_highlightDisplays.clear(); + s_highlights->clear(); + s_highlightDisplays->clear(); } TutorialManager::Tutorial::Step& TutorialManager::Tutorial::addStep() { @@ -252,7 +252,7 @@ namespace hex { }, id); } - s_highlights.emplace(idStack.get(), text); + s_highlights->emplace(idStack.get(), text); } } @@ -271,7 +271,7 @@ namespace hex { }, id); } - s_highlights.erase(idStack.get()); + s_highlights->erase(idStack.get()); } } @@ -285,7 +285,7 @@ namespace hex { if (m_parent->m_currentStep != m_parent->m_steps.end()) m_parent->m_currentStep->addHighlights(); else - s_currentTutorial = s_tutorials.end(); + s_currentTutorial = s_tutorials->end(); } @@ -369,9 +369,9 @@ namespace hex { } void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) { - const auto element = hex::s_highlights.find(id); - if (element != hex::s_highlights.end()) { - hex::s_highlightDisplays.emplace_back(bb, element->second); + const auto element = hex::s_highlights->find(id); + if (element != hex::s_highlights->end()) { + hex::s_highlightDisplays->emplace_back(bb, element->second); } } diff --git a/lib/libimhex/source/api/workspace_manager.cpp b/lib/libimhex/source/api/workspace_manager.cpp index fc0b5c87b..9c4271dd1 100644 --- a/lib/libimhex/source/api/workspace_manager.cpp +++ b/lib/libimhex/source/api/workspace_manager.cpp @@ -11,12 +11,12 @@ namespace hex { - std::map WorkspaceManager::s_workspaces; - decltype(WorkspaceManager::s_workspaces)::iterator WorkspaceManager::s_currentWorkspace = s_workspaces.end(); - decltype(WorkspaceManager::s_workspaces)::iterator WorkspaceManager::s_previousWorkspace = s_workspaces.end(); + AutoReset> WorkspaceManager::s_workspaces; + decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_currentWorkspace = s_workspaces->end(); + decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_previousWorkspace = s_workspaces->end(); void WorkspaceManager::createWorkspace(const std::string& name, const std::string &layout) { - s_currentWorkspace = s_workspaces.insert_or_assign(name, Workspace { + s_currentWorkspace = s_workspaces->insert_or_assign(name, Workspace { .layout = layout.empty() ? LayoutManager::saveToString() : layout, .path = {} }).first; @@ -28,8 +28,8 @@ namespace hex { } void WorkspaceManager::switchWorkspace(const std::string& name) { - const auto newWorkspace = s_workspaces.find(name); - if (newWorkspace != s_workspaces.end()) { + const auto newWorkspace = s_workspaces->find(name); + if (newWorkspace != s_workspaces->end()) { s_currentWorkspace = newWorkspace; log::info("Switching to workspace '{}'", name); } @@ -46,10 +46,10 @@ namespace hex { try { auto json = nlohmann::json::parse(content.begin(), content.end()); - std::string name = json["name"]; + const std::string name = json["name"]; std::string layout = json["layout"]; - s_workspaces[name] = Workspace { + (*s_workspaces)[name] = Workspace { .layout = std::move(layout), .path = path }; @@ -60,7 +60,7 @@ namespace hex { bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName) { if (path.empty()) { - if (s_currentWorkspace == s_workspaces.end()) + if (s_currentWorkspace == s_workspaces->end()) return false; path = s_currentWorkspace->second.path; @@ -86,7 +86,7 @@ namespace hex { void WorkspaceManager::process() { if (s_previousWorkspace != s_currentWorkspace) { - if (s_previousWorkspace != s_workspaces.end()) + if (s_previousWorkspace != s_workspaces->end()) exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first); LayoutManager::closeAllViews(); @@ -98,9 +98,9 @@ namespace hex { void WorkspaceManager::reset() { - s_workspaces.clear(); - s_currentWorkspace = s_workspaces.end(); - s_previousWorkspace = s_workspaces.end(); + s_workspaces->clear(); + s_currentWorkspace = s_workspaces->end(); + s_previousWorkspace = s_workspaces->end(); } diff --git a/lib/libimhex/source/helpers/fs.cpp b/lib/libimhex/source/helpers/fs.cpp index 056c94f90..38ee67988 100644 --- a/lib/libimhex/source/helpers/fs.cpp +++ b/lib/libimhex/source/helpers/fs.cpp @@ -5,8 +5,7 @@ #include #include #include - -#include +#include #if defined(OS_WINDOWS) #include @@ -23,7 +22,6 @@ #include #endif -#include #include #include @@ -32,7 +30,7 @@ namespace hex::fs { - static std::function s_fileBrowserErrorCallback; + static AutoReset> s_fileBrowserErrorCallback; void setFileBrowserErrorCallback(const std::function &callback) { s_fileBrowserErrorCallback = callback; } @@ -40,8 +38,9 @@ namespace hex::fs { // With help from https://github.com/owncloud/client/blob/cba22aa34b3677406e0499aadd126ce1d94637a2/src/gui/openfilemanager.cpp void openFileExternal(const std::fs::path &filePath) { // Make sure the file exists before trying to open it - if (!wolv::io::fs::exists(filePath)) + if (!wolv::io::fs::exists(filePath)) { return; + } #if defined(OS_WINDOWS) hex::unused( @@ -58,8 +57,9 @@ namespace hex::fs { void openFolderExternal(const std::fs::path &dirPath) { // Make sure the folder exists before trying to open it - if (!wolv::io::fs::exists(dirPath)) + if (!wolv::io::fs::exists(dirPath)) { return; + } #if defined(OS_WINDOWS) hex::unused(system( @@ -76,8 +76,9 @@ namespace hex::fs { void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath) { // Make sure the file exists before trying to open it - if (!wolv::io::fs::exists(selectedFilePath)) + if (!wolv::io::fs::exists(selectedFilePath)) { return; + } #if defined(OS_WINDOWS) hex::unused(system( @@ -203,7 +204,7 @@ namespace hex::fs { bool openFileBrowser(DialogMode mode, const std::vector &validExtensions, const std::function &callback, const std::string &defaultPath, bool multiple) { // Turn the content of the ItemFilter objects into something NFD understands - std::vector validExtensionsNfd; + std::vector validExtensionsNfd(validExtensions.size()); for (const auto &extension : validExtensions) { validExtensionsNfd.emplace_back(nfdfilteritem_t{ extension.name.c_str(), extension.spec.c_str() }); } @@ -215,9 +216,9 @@ namespace hex::fs { if (NFD::Init() != NFD_OKAY) { // Handle errors if initialization failed log::error("NFD init returned an error: {}", NFD::GetError()); - if (s_fileBrowserErrorCallback != nullptr) { - auto error = NFD::GetError(); - s_fileBrowserErrorCallback(error != nullptr ? error : "No details"); + if (*s_fileBrowserErrorCallback != nullptr) { + const auto error = NFD::GetError(); + (*s_fileBrowserErrorCallback)(error != nullptr ? error : "No details"); } return false; @@ -267,9 +268,9 @@ namespace hex::fs { log::error("Requested file dialog returned an error: {}", NFD::GetError()); - if (s_fileBrowserErrorCallback != nullptr) { - auto error = NFD::GetError(); - s_fileBrowserErrorCallback(error != nullptr ? error : "No details"); + if (*s_fileBrowserErrorCallback != nullptr) { + const auto error = NFD::GetError(); + (*s_fileBrowserErrorCallback)(error != nullptr ? error : "No details"); } } @@ -326,7 +327,7 @@ namespace hex::fs { // Add additional data directories to the path auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths(); - std::copy(additionalDirs.begin(), additionalDirs.end(), std::back_inserter(paths)); + std::ranges::copy(additionalDirs, std::back_inserter(paths)); // Add the project file directory to the path, if one is loaded if (ProjectFile::hasPath()) { @@ -457,7 +458,7 @@ namespace hex::fs { // Try to create a new file in the given path // If that fails, or the file cannot be deleted anymore afterward; the path is not writable wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Create); - bool result = file.isValid(); + const bool result = file.isValid(); if (!file.remove()) return false; diff --git a/lib/libimhex/source/helpers/utils_macos.m b/lib/libimhex/source/helpers/utils_macos.m index f49aa6796..997b0cf2e 100644 --- a/lib/libimhex/source/helpers/utils_macos.m +++ b/lib/libimhex/source/helpers/utils_macos.m @@ -47,6 +47,12 @@ void setupMacosWindowStyle(GLFWwindow *window) { NSWindow* cocoaWindow = glfwGetCocoaWindow(window); cocoaWindow.titleVisibility = NSWindowTitleHidden; + + NSVisualEffectView *visualEffectView = [[NSVisualEffectView alloc] init]; + [visualEffectView setMaterial:NSVisualEffectMaterialAppearanceBased]; + [visualEffectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; + + [cocoaWindow.contentView addSubview:visualEffectView positioned:NSWindowBelow relativeTo:nil]; } @interface HexDocument : NSDocument diff --git a/lib/libimhex/source/ui/popup.cpp b/lib/libimhex/source/ui/popup.cpp index a3f28eb0f..6066b7fcb 100644 --- a/lib/libimhex/source/ui/popup.cpp +++ b/lib/libimhex/source/ui/popup.cpp @@ -1,10 +1,11 @@ #include +#include namespace hex::impl { [[nodiscard]] std::vector> &PopupBase::getOpenPopups() { - static std::vector> openPopups; + static AutoReset>> openPopups; return openPopups; } diff --git a/lib/libimhex/source/ui/toast.cpp b/lib/libimhex/source/ui/toast.cpp index 55560a857..5a5f193f9 100644 --- a/lib/libimhex/source/ui/toast.cpp +++ b/lib/libimhex/source/ui/toast.cpp @@ -1,9 +1,10 @@ #include +#include namespace hex::impl { [[nodiscard]] std::list> &ToastBase::getQueuedToasts() { - static std::list> queuedToasts; + static AutoReset>> queuedToasts; return queuedToasts; } diff --git a/main/gui/source/init/tasks.cpp b/main/gui/source/init/tasks.cpp index a6567286b..ffaf6c5e1 100644 --- a/main/gui/source/init/tasks.cpp +++ b/main/gui/source/init/tasks.cpp @@ -9,17 +9,11 @@ #include #include -#include -#include #include -#include #include -#include -#include #include #include -#include #include @@ -59,108 +53,41 @@ namespace hex::init { return result; } - bool deleteSharedData() { - // This function is called when ImHex is closed. It deletes all shared data that was created by plugins - // This is a bit of a hack but necessary because when ImHex gets closed, all plugins are unloaded in order for - // destructors to be called correctly. To prevent crashes when ImHex exits, we need to delete all shared data - - EventImHexClosing::post(); - EventManager::clear(); - - while (ImHexApi::Provider::isValid()) - ImHexApi::Provider::remove(ImHexApi::Provider::get()); - + bool prepareExit() { // Terminate all asynchronous tasks TaskManager::exit(); - ContentRegistry::Provider::impl::getEntries().clear(); - - ImHexApi::System::getInitArguments().clear(); - ImHexApi::HexEditor::impl::getBackgroundHighlights().clear(); - ImHexApi::HexEditor::impl::getForegroundHighlights().clear(); - ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear(); - ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions().clear(); - ImHexApi::HexEditor::impl::getTooltips().clear(); - ImHexApi::HexEditor::impl::getTooltipFunctions().clear(); - ImHexApi::System::getAdditionalFolderPaths().clear(); - ImHexApi::Messaging::impl::getHandlers().clear(); - ImHexApi::Fonts::getCustomFontPath().clear(); - ImHexApi::Fonts::impl::getFonts().clear(); - - ContentRegistry::Settings::impl::getSettings().clear(); - ContentRegistry::Settings::impl::getSettingsData().clear(); - - ContentRegistry::CommandPaletteCommands::impl::getEntries().clear(); - ContentRegistry::CommandPaletteCommands::impl::getHandlers().clear(); - - ContentRegistry::PatternLanguage::impl::getFunctions().clear(); - ContentRegistry::PatternLanguage::impl::getPragmas().clear(); - ContentRegistry::PatternLanguage::impl::getVisualizers().clear(); - ContentRegistry::PatternLanguage::impl::getInlineVisualizers().clear(); - - ContentRegistry::Views::impl::getEntries().clear(); - impl::PopupBase::getOpenPopups().clear(); - impl::ToastBase::getQueuedToasts().clear(); - - - ContentRegistry::Tools::impl::getEntries().clear(); - ContentRegistry::DataInspector::impl::getEntries().clear(); - - ContentRegistry::Language::impl::getLanguages().clear(); - ContentRegistry::Language::impl::getLanguageDefinitions().clear(); - LocalizationManager::impl::resetLanguageStrings(); - - ContentRegistry::Interface::impl::getWelcomeScreenEntries().clear(); - ContentRegistry::Interface::impl::getFooterItems().clear(); - ContentRegistry::Interface::impl::getToolbarItems().clear(); - ContentRegistry::Interface::impl::getMainMenuItems().clear(); - ContentRegistry::Interface::impl::getMenuItems().clear(); - ContentRegistry::Interface::impl::getSidebarItems().clear(); - ContentRegistry::Interface::impl::getTitleBarButtons().clear(); - - ShortcutManager::clearShortcuts(); - - ContentRegistry::DataProcessorNode::impl::getEntries().clear(); - - ContentRegistry::DataFormatter::impl::getEntries().clear(); - ContentRegistry::FileHandler::impl::getEntries().clear(); - ContentRegistry::Hashes::impl::getHashes().clear(); - ContentRegistry::HexEditor::impl::getVisualizers().clear(); - ContentRegistry::HexEditor::impl::getMiniMapVisualizers().clear(); - - ContentRegistry::BackgroundServices::impl::stopServices(); - - ContentRegistry::CommunicationInterface::impl::getNetworkEndpoints().clear(); - - ContentRegistry::Experiments::impl::getExperiments().clear(); - ContentRegistry::Reports::impl::getGenerators().clear(); - - ContentRegistry::Diffing::impl::getAlgorithms().clear(); - - WorkspaceManager::reset(); - LayoutManager::reset(); - - ThemeManager::reset(); - - AchievementManager::getAchievements().clear(); - TutorialManager::reset(); - - ProjectFile::getHandlers().clear(); - ProjectFile::getProviderHandlers().clear(); - ProjectFile::setProjectFunctions(nullptr, nullptr); - - fs::setFileBrowserErrorCallback(nullptr); - // Unlock font atlas so it can be deleted in case of a crash if (ImGui::GetCurrentContext() != nullptr) ImGui::GetIO().Fonts->Locked = false; + // Print a nice message if a crash happened while cleaning up resources + // To the person fixing this: + // ALWAYS wrap static heap allocated objects inside libimhex such as std::vector, std::string, std::function, etc. in a AutoReset + // e.g `AutoReset> m_structs;` + // + // The reason this is necessary is because each plugin / dynamic library gets its own instance of `std::allocator` + // which will try to free the allocated memory when the object is destroyed. However since the storage is static, this + // will happen only when libimhex is unloaded after main() returns. At this point all plugins have been unloaded already so + // the std::allocator will try to free memory in a heap that does not exist anymore which will cause a crash. + // By wrapping the object in a AutoReset, the `EventImHexClosing` event will automatically handle clearing the object + // while the heap is still valid. + // The heap stays valid right up to the point where `PluginManager::unload()` is called. + EventAbnormalTermination::post([] { + log::fatal("A crash happened while cleaning up resources during exit!"); + log::fatal("This is most certainly because WerWolv again forgot to mark a heap allocated object as 'AutoReset'."); + log::fatal("Please report this issue on the ImHex GitHub page!"); + log::fatal("To the person fixing this, read the comment above this message for more information."); + }); + + EventImHexClosing::post(); + EventManager::clear(); + return true; } bool loadPlugins() { // Load all plugins - bool hasExtraPluginFolders = !PluginManager::getPluginLoadPaths().empty(); #if !defined(IMHEX_STATIC_LINK_PLUGINS) for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) { PluginManager::addLoadPath(dir); @@ -170,7 +97,7 @@ namespace hex::init { #endif // Get loaded plugins - auto &plugins = PluginManager::getPlugins(); + const auto &plugins = PluginManager::getPlugins(); // If no plugins were loaded, ImHex wasn't installed properly. This will trigger an error popup later on if (plugins.empty()) { @@ -180,7 +107,7 @@ namespace hex::init { return false; } - const auto shouldLoadPlugin = [hasExtraPluginFolders, executablePath = wolv::io::fs::getExecutablePath()](const Plugin &plugin) { + const auto shouldLoadPlugin = [executablePath = wolv::io::fs::getExecutablePath()](const Plugin &plugin) { // In debug builds, ignore all plugins that are not part of the executable directory #if !defined(DEBUG) return true; @@ -189,7 +116,7 @@ namespace hex::init { if (!executablePath.has_value()) return true; - if (hasExtraPluginFolders) + if (!PluginManager::getPluginLoadPaths().empty()) return true; // Check if the plugin is somewhere in the same directory tree as the executable @@ -283,7 +210,6 @@ namespace hex::init { bool unloadPlugins() { PluginManager::unload(); - PluginManager::getPluginLoadPaths().clear(); return true; } @@ -320,7 +246,7 @@ namespace hex::init { // Run all exit tasks, and print to console void runExitTasks() { for (const auto &[name, task, async] : init::getExitTasks()) { - bool result = task(); + const bool result = task(); log::info("Exit task '{0}' finished {1}", name, result ? "successfully" : "unsuccessfully"); } } @@ -337,7 +263,7 @@ namespace hex::init { std::vector getExitTasks() { return { { "Saving settings", storeSettings, false }, - { "Cleaning up shared data", deleteSharedData, false }, + { "Prepare exit", prepareExit, false }, { "Unloading plugins", unloadPlugins, false }, { "Deleting old files", deleteOldFiles, false }, };