diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index 8e3ee64c2..faac3c1f9 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -171,6 +171,8 @@ namespace hex { void setGPUVendor(const std::string &vendor); void setPortableVersion(bool enabled); + + void addInitArgument(const std::string &key, const std::string &value = { }); } struct ProgramArguments { diff --git a/lib/libimhex/include/hex/helpers/logger.hpp b/lib/libimhex/include/hex/helpers/logger.hpp index 8f1af3eb3..62f95c1f9 100644 --- a/lib/libimhex/include/hex/helpers/logger.hpp +++ b/lib/libimhex/include/hex/helpers/logger.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -30,6 +31,9 @@ namespace hex::log { template [[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) { + static std::mutex logMutex; + std::scoped_lock lock(logMutex); + auto dest = getDestination(); printPrefix(dest, ts, level); diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index bc61db540..0515cb644 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -385,6 +385,13 @@ namespace hex { s_portableVersion = enabled; } + void addInitArgument(const std::string &key, const std::string &value) { + static std::mutex initArgumentsMutex; + std::scoped_lock lock(initArgumentsMutex); + + getInitArguments()[key] = value; + } + } diff --git a/main/include/init/splash_window.hpp b/main/include/init/splash_window.hpp index 416af1ffa..ec03ed074 100644 --- a/main/include/init/splash_window.hpp +++ b/main/include/init/splash_window.hpp @@ -19,8 +19,8 @@ namespace hex::init { bool loop(); - void addStartupTask(const std::string &taskName, const TaskFunction &task) { - this->m_tasks.emplace_back(taskName, task); + void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) { + this->m_tasks.emplace_back(taskName, task, async); } private: @@ -37,7 +37,7 @@ namespace hex::init { std::future processTasksAsync(); - std::vector> m_tasks; + std::vector> m_tasks; std::string m_gpuVendor; }; diff --git a/main/include/init/tasks.hpp b/main/include/init/tasks.hpp index c464f2245..172b7909e 100644 --- a/main/include/init/tasks.hpp +++ b/main/include/init/tasks.hpp @@ -9,6 +9,7 @@ namespace hex::init { struct Task { std::string name; std::function function; + bool async; }; std::vector getInitTasks(); diff --git a/main/source/init/splash_window.cpp b/main/source/init/splash_window.cpp index 5c7a911e0..e92e0012d 100644 --- a/main/source/init/splash_window.cpp +++ b/main/source/init/splash_window.cpp @@ -43,15 +43,27 @@ namespace hex::init { return std::async(std::launch::async, [this] { bool status = true; - for (const auto &[name, task] : this->m_tasks) { - { + u32 tasksCompleted = 0; + for (const auto &[name, task, async] : this->m_tasks) { + if (!async) { std::lock_guard guard(this->m_progressMutex); this->m_currTaskName = name; } - try { + auto runTask = [&, task = task] { if (!task()) status = false; + + tasksCompleted++; + }; + + try { + if (async) { + std::thread(runTask).detach(); + } else { + runTask(); + } + } catch (std::exception &e) { log::error("Init task '{}' threw an exception: {}", name, e.what()); status = false; @@ -63,6 +75,9 @@ namespace hex::init { } } + while (tasksCompleted < this->m_tasks.size()) + std::this_thread::sleep_for(100ms); + // Small extra delay so the last progress step is visible std::this_thread::sleep_for(200ms); diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index 487bec218..1603c20e3 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -40,7 +40,7 @@ namespace hex::init { auto latestVersion = releases.body["tag_name"].get(); if (latestVersion != currVersion) - ImHexApi::System::getInitArguments().insert({ "update-available", latestVersion.data() }); + ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data()); return true; } @@ -52,7 +52,7 @@ namespace hex::init { if (tip.code != 200) return false; - ImHexApi::System::getInitArguments().insert({ "tip-of-the-day", tip.body }); + ImHexApi::System::impl::addInitArgument("tip-of-the-day", tip.body); return true; } @@ -99,7 +99,7 @@ namespace hex::init { } if (!result) - ImHexApi::System::getInitArguments().insert({ "folder-creation-error", {} }); + ImHexApi::System::impl::addInitArgument("folder-creation-error"); return result; } @@ -246,7 +246,7 @@ namespace hex::init { if (plugins.empty()) { log::error("No plugins found!"); - ImHexApi::System::getInitArguments().insert({ "no-plugins", {} }); + ImHexApi::System::impl::addInitArgument("no-plugins"); return false; } @@ -274,17 +274,17 @@ namespace hex::init { if (loadErrors == plugins.size()) { log::error("No plugins loaded successfully!"); - ImHexApi::System::getInitArguments().insert({ "no-plugins", {} }); + ImHexApi::System::impl::addInitArgument("no-plugins"); return false; } if (builtinPlugins == 0) { log::error("Built-in plugin not found!"); - ImHexApi::System::getInitArguments().insert({ "no-builtin-plugin", {} }); + ImHexApi::System::impl::addInitArgument("no-builtin-plugin"); return false; } else if (builtinPlugins > 1) { log::error("Found more than one built-in plugin!"); - ImHexApi::System::getInitArguments().insert({ "multiple-builtin-plugins", {} }); + ImHexApi::System::impl::addInitArgument("multiple-builtin-plugins"); return false; } @@ -324,20 +324,20 @@ namespace hex::init { std::vector getInitTasks() { return { - {"Checking for updates...", checkForUpdates }, - { "Downloading information...", downloadInformation}, - { "Creating directories...", createDirectories }, - { "Loading settings...", loadSettings }, - { "Loading plugins...", loadPlugins }, - { "Loading fonts...", loadFonts }, + { "Checking for updates...", checkForUpdates, false }, + { "Downloading information...", downloadInformation, true }, + { "Loading fonts...", loadFonts, true }, + { "Creating directories...", createDirectories, false }, + { "Loading settings...", loadSettings, false }, + { "Loading plugins...", loadPlugins, false }, }; } std::vector getExitTasks() { return { - {"Saving settings...", storeSettings }, - { "Cleaning up shared data...", deleteSharedData}, - { "Unloading plugins...", unloadPlugins }, + { "Saving settings...", storeSettings, false }, + { "Cleaning up shared data...", deleteSharedData, false }, + { "Unloading plugins...", unloadPlugins, false }, }; } diff --git a/main/source/main.cpp b/main/source/main.cpp index 8b0a17081..8fb69f927 100644 --- a/main/source/main.cpp +++ b/main/source/main.cpp @@ -33,8 +33,8 @@ int main(int argc, char **argv, char **envp) { init::WindowSplash splashWindow; - for (const auto &[name, task] : init::getInitTasks()) - splashWindow.addStartupTask(name, task); + for (const auto &[name, task, async] : init::getInitTasks()) + splashWindow.addStartupTask(name, task, async); if (!splashWindow.loop()) ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} }); @@ -42,7 +42,7 @@ int main(int argc, char **argv, char **envp) { // Clean up ON_SCOPE_EXIT { - for (const auto &[name, task] : init::getExitTasks()) + for (const auto &[name, task, async] : init::getExitTasks()) task(); };