diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9eda8e3b..4e31b015 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -402,6 +402,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the PluginSystem!"); g_pPluginSystem = std::make_unique(); + g_pConfigManager->handlePluginLoads(); } break; default: UNREACHABLE(); } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 4a56f27e..e274f89d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1105,6 +1105,15 @@ void CConfigManager::handleEnv(const std::string& command, const std::string& va } } +void CConfigManager::handlePlugin(const std::string& command, const std::string& path) { + if (std::find(m_vDeclaredPlugins.begin(), m_vDeclaredPlugins.end(), path) != m_vDeclaredPlugins.end()) { + parseError = "plugin '" + path + "' declared twice"; + return; + } + + m_vDeclaredPlugins.push_back(path); +} + std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE, bool dynamic) { if (dynamic) { parseError = ""; @@ -1151,6 +1160,8 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: handleBindWS(COMMAND, VALUE); else if (COMMAND.find("env") == 0) handleEnv(COMMAND, VALUE); + else if (COMMAND.find("plugin") == 0) + handlePlugin(COMMAND, VALUE); else { configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE); needsLayoutRecalc = 2; @@ -1303,6 +1314,7 @@ void CConfigManager::loadConfigLoadVars() { m_dBlurLSNamespaces.clear(); boundWorkspaces.clear(); setDefaultAnimationVars(); // reset anims + m_vDeclaredPlugins.clear(); // paths configPaths.clear(); @@ -1441,6 +1453,9 @@ void CConfigManager::loadConfigLoadVars() { // Reset no monitor reload m_bNoMonitorReload = false; + + // update plugins + handlePluginLoads(); } void CConfigManager::tick() { @@ -1954,6 +1969,31 @@ void CConfigManager::addExecRule(const SExecRequestedRule& rule) { execRequestedRules.push_back(rule); } +void CConfigManager::handlePluginLoads() { + if (g_pPluginSystem == nullptr) + return; + + bool pluginsChanged = false; + auto failedPlugins = g_pPluginSystem->updateConfigPlugins(m_vDeclaredPlugins, pluginsChanged); + + if (!failedPlugins.empty()) { + std::stringstream error; + error << "Failed to load the following plugins:"; + + for (auto path : failedPlugins) { + error << "\n" << path; + } + + g_pHyprError->queueCreate(error.str(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); + } + + if (pluginsChanged) { + g_pHyprError->destroy(); + m_bForceReload = true; + tick(); + } +} + ICustomConfigValueData::~ICustomConfigValueData() { ; // empty } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index cee6075e..0d4d6cd7 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -182,6 +182,8 @@ class CConfigManager { void addExecRule(const SExecRequestedRule&); + void handlePluginLoads(); + std::string configCurrentPath; private: @@ -203,6 +205,7 @@ class CConfigManager { std::vector execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty + std::vector m_vDeclaredPlugins; std::unordered_map>> pluginConfigs; // stores plugin configs bool isFirstLaunch = true; // For exec-once @@ -250,6 +253,7 @@ class CConfigManager { void handleBlurLS(const std::string&, const std::string&); void handleBindWS(const std::string&, const std::string&); void handleEnv(const std::string&, const std::string&); + void handlePlugin(const std::string&, const std::string&); }; inline std::unique_ptr g_pConfigManager; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index ca0776ea..b72f0589 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -33,7 +33,6 @@ void CHyprError::queueCreate(std::string message, const CColor& color) { void CHyprError::createQueued() { if (m_bIsCreated) { - m_bQueuedDestroy = false; m_tTexture.destroyTexture(); } @@ -171,4 +170,6 @@ void CHyprError::draw() { void CHyprError::destroy() { if (m_bIsCreated) m_bQueuedDestroy = true; + else + m_szQueued = ""; } diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index 73de9bf5..040cfcf1 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -119,6 +119,35 @@ void CPluginSystem::unloadAllPlugins() { unloadPlugin(p.get(), false); // Unload remaining plugins gracefully } +std::vector CPluginSystem::updateConfigPlugins(const std::vector& plugins, bool& changed) { + std::vector failures; + + // unload all plugins that are no longer present + for (auto& p : m_vLoadedPlugins | std::views::reverse) { + if (p->m_bLoadedWithConfig && std::find(plugins.begin(), plugins.end(), p->path) == plugins.end()) { + Debug::log(LOG, "Unloading plugin %s which is no longer present in config", p->path.c_str()); + unloadPlugin(p.get(), false); + changed = true; + } + } + + // load all new plugins + for (auto& path : plugins) { + if (std::find_if(m_vLoadedPlugins.begin(), m_vLoadedPlugins.end(), [&](const auto& other) { return other->path == path; }) == m_vLoadedPlugins.end()) { + Debug::log(LOG, "Loading plugin %s which is now present in config", path.c_str()); + const auto plugin = loadPlugin(path); + + if (plugin) { + plugin->m_bLoadedWithConfig = true; + changed = true; + } else + failures.push_back(path); + } + } + + return failures; +} + CPlugin* CPluginSystem::getPluginByPath(const std::string& path) { for (auto& p : m_vLoadedPlugins) { if (p->path == path) diff --git a/src/plugins/PluginSystem.hpp b/src/plugins/PluginSystem.hpp index 5d1a1532..0ef30bab 100644 --- a/src/plugins/PluginSystem.hpp +++ b/src/plugins/PluginSystem.hpp @@ -15,6 +15,8 @@ class CPlugin { std::string path = ""; + bool m_bLoadedWithConfig = false; + HANDLE m_pHandle = nullptr; std::vector registeredLayouts; @@ -27,14 +29,15 @@ class CPluginSystem { public: CPluginSystem(); - CPlugin* loadPlugin(const std::string& path); - void unloadPlugin(const CPlugin* plugin, bool eject = false); - void unloadAllPlugins(); - CPlugin* getPluginByPath(const std::string& path); - CPlugin* getPluginByHandle(HANDLE handle); - std::vector getAllPlugins(); + CPlugin* loadPlugin(const std::string& path); + void unloadPlugin(const CPlugin* plugin, bool eject = false); + void unloadAllPlugins(); + std::vector updateConfigPlugins(const std::vector& plugins, bool& changed); + CPlugin* getPluginByPath(const std::string& path); + CPlugin* getPluginByHandle(HANDLE handle); + std::vector getAllPlugins(); - bool m_bAllowConfigVars = false; + bool m_bAllowConfigVars = false; private: std::vector> m_vLoadedPlugins;