From 70add904c40924a761059e4009a8c0f1e43d76a3 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Sat, 7 Sep 2024 14:54:33 -0500 Subject: [PATCH] config: add exec-shutdown for running commands on shutdown (#7683) * config: add exec-shutdown for running commands on shutdown * compositor: delay stopping until after exec-shutdown --- src/Compositor.hpp | 1 + src/config/ConfigManager.cpp | 42 +++++++++++++++++++++++++++++++++ src/config/ConfigManager.hpp | 3 +++ src/managers/KeybindManager.cpp | 5 ++++ 4 files changed, 51 insertions(+) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index f17d86e5..a57450f1 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -91,6 +91,7 @@ class CCompositor { bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; + bool m_bFinalRequests = false; bool m_bDesktopEnvSet = false; bool m_bEnableXwayland = true; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b16b7747..852994a7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -141,6 +141,18 @@ static Hyprlang::CParseResult handleExecOnce(const char* c, const char* v) { return result; } +static Hyprlang::CParseResult handleExecShutdown(const char* c, const char* v) { + const std::string VALUE = v; + const std::string COMMAND = c; + + const auto RESULT = g_pConfigManager->handleExecShutdown(COMMAND, VALUE); + + Hyprlang::CParseResult result; + if (RESULT.has_value()) + result.setError(RESULT.value().c_str()); + return result; +} + static Hyprlang::CParseResult handleMonitor(const char* c, const char* v) { const std::string VALUE = v; const std::string COMMAND = c; @@ -609,6 +621,7 @@ CConfigManager::CConfigManager() { // keywords m_pConfig->registerHandler(&::handleRawExec, "exec", {false}); m_pConfig->registerHandler(&::handleExecOnce, "exec-once", {false}); + m_pConfig->registerHandler(&::handleExecShutdown, "exec-shutdown", {false}); m_pConfig->registerHandler(&::handleMonitor, "monitor", {false}); m_pConfig->registerHandler(&::handleBind, "bind", {true}); m_pConfig->registerHandler(&::handleUnbind, "unbind", {false}); @@ -801,6 +814,7 @@ std::optional CConfigManager::resetHLConfig() { m_vDeclaredPlugins.clear(); m_dLayerRules.clear(); m_vFailedPluginConfigValues.clear(); + finalExecRequests.clear(); // paths configPaths.clear(); @@ -1398,6 +1412,24 @@ void CConfigManager::dispatchExecOnce() { g_pCompositor->performUserChecks(); } +void CConfigManager::dispatchExecShutdown() { + if (finalExecRequests.empty()) { + g_pCompositor->m_bFinalRequests = false; + return; + } + + g_pCompositor->m_bFinalRequests = true; + + for (auto const& c : finalExecRequests) { + handleExecShutdown("", c); + } + + finalExecRequests.clear(); + + // Actually exit now + handleExecShutdown("", "hyprctl dispatch exit"); +} + void CConfigManager::appendMonitorRule(const SMonitorRule& r) { m_dMonitorRules.emplace_back(r); } @@ -1700,6 +1732,16 @@ std::optional CConfigManager::handleExecOnce(const std::string& com return {}; } +std::optional CConfigManager::handleExecShutdown(const std::string& command, const std::string& args) { + if (g_pCompositor->m_bFinalRequests) { + g_pKeybindManager->spawn(args); + return {}; + } + + finalExecRequests.push_back(args); + return {}; +} + static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { auto args = CVarList(modeline, 0, 's'); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 4d087753..da450e39 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -192,6 +192,7 @@ class CConfigManager { // no-op when done. void dispatchExecOnce(); + void dispatchExecShutdown(); void performMonitorReload(); void appendMonitorRule(const SMonitorRule&); @@ -213,6 +214,7 @@ class CConfigManager { // keywords std::optional handleRawExec(const std::string&, const std::string&); std::optional handleExecOnce(const std::string&, const std::string&); + std::optional handleExecShutdown(const std::string&, const std::string&); std::optional handleMonitor(const std::string&, const std::string&); std::optional handleBind(const std::string&, const std::string&); std::optional handleUnbind(const std::string&, const std::string&); @@ -289,6 +291,7 @@ class CConfigManager { bool firstExecDispatched = false; bool m_bManualCrashInitiated = false; std::deque firstExecRequests; + std::deque finalExecRequests; std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins std::string m_szConfigErrors = ""; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2db9f375..2f593d74 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1781,6 +1781,11 @@ SDispatchResult CKeybindManager::renameWorkspace(std::string args) { } SDispatchResult CKeybindManager::exitHyprland(std::string argz) { + g_pConfigManager->dispatchExecShutdown(); + + if (g_pCompositor->m_bFinalRequests) + return {}; // Exiting deferred until requests complete + g_pCompositor->stopCompositor(); return {}; }