diff --git a/src/Compositor.cpp b/src/Compositor.cpp index cc9d4244..20656243 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1194,24 +1194,33 @@ void CCompositor::sanityCheckWorkspaces() { continue; } - const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace((*it)->m_iID); + const auto& WORKSPACE = *it; + const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace(WORKSPACE->m_iID); - if ((WINDOWSONWORKSPACE == 0 && !isWorkspaceVisible((*it)->m_iID))) { + if (WINDOWSONWORKSPACE == 0) { + if (!isWorkspaceVisible(WORKSPACE->m_iID)) { - if ((*it)->m_bIsSpecialWorkspace) { - if ((*it)->m_fAlpha.fl() > 0.f /* don't abruptly end the fadeout */) { - ++it; - continue; + if (WORKSPACE->m_bIsSpecialWorkspace) { + if (WORKSPACE->m_fAlpha.fl() > 0.f /* don't abruptly end the fadeout */) { + ++it; + continue; + } + + const auto PMONITOR = getMonitorFromID(WORKSPACE->m_iMonitorID); + + if (PMONITOR && PMONITOR->specialWorkspaceID == WORKSPACE->m_iID) + PMONITOR->setSpecialWorkspace(nullptr); } - const auto PMONITOR = getMonitorFromID((*it)->m_iMonitorID); - - if (PMONITOR && PMONITOR->specialWorkspaceID == (*it)->m_iID) - PMONITOR->setSpecialWorkspace(nullptr); + it = m_vWorkspaces.erase(it); + continue; } + if (!WORKSPACE->m_bOnCreatedEmptyExecuted) { + if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) + g_pKeybindManager->spawn(*cmd); - it = m_vWorkspaces.erase(it); - continue; + WORKSPACE->m_bOnCreatedEmptyExecuted = true; + } } ++it; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f0961aa0..2ecac5c9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2,6 +2,7 @@ #include "../managers/KeybindManager.hpp" #include +#include #include #include #include @@ -1176,7 +1177,10 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std: rules = value.substr(WORKSPACE_DELIM + 1); } - auto assignRule = [&](std::string rule) { + const static std::string ruleOnCreatedEmtpy = "on-created-empty:"; + const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length(); + + auto assignRule = [&](std::string rule) { size_t delim = std::string::npos; if ((delim = rule.find("gapsin:")) != std::string::npos) wsRule.gapsIn = std::stoi(rule.substr(delim + 7)); @@ -1198,6 +1202,8 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std: wsRule.isDefault = configStringToInt(rule.substr(delim + 8)); else if ((delim = rule.find("persistent:")) != std::string::npos) wsRule.isPersistent = configStringToInt(rule.substr(delim + 11)); + else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos) + wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen)); }; size_t pos = 0; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index e637979d..c6c726bf 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -36,19 +36,20 @@ struct SConfigValue { }; struct SWorkspaceRule { - std::string monitor = ""; - std::string workspaceString = ""; - std::string workspaceName = ""; - int workspaceId = -1; - bool isDefault = false; - bool isPersistent = false; - std::optional gapsIn; - std::optional gapsOut; - std::optional borderSize; - std::optional border; - std::optional rounding; - std::optional decorate; - std::optional shadow; + std::string monitor = ""; + std::string workspaceString = ""; + std::string workspaceName = ""; + int workspaceId = -1; + bool isDefault = false; + bool isPersistent = false; + std::optional gapsIn; + std::optional gapsOut; + std::optional borderSize; + std::optional border; + std::optional rounding; + std::optional decorate; + std::optional shadow; + std::optional onCreatedEmptyRunCmd; }; struct SMonitorAdditionalReservedArea { diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index b3236725..3cce73d2 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -2,6 +2,7 @@ #include "../defines.hpp" #include #include "../Compositor.hpp" +#include #include #include #include @@ -503,6 +504,43 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { return result; } +std::optional cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) { + + std::string cmd = removeBeginEndSpacesTabs(dirtyCmd); + + if (!cmd.empty()) { + std::string rules; + const std::string workspaceRule = "workspace " + inWorkspaceName; + + if (cmd[0] == '[') { + const int closingBracketIdx = cmd.find_last_of(']'); + auto tmpRules = cmd.substr(1, closingBracketIdx - 1); + cmd = cmd.substr(closingBracketIdx + 1); + + auto rulesList = CVarList(tmpRules, 0, ';'); + + bool hadWorkspaceRule = false; + rulesList.map([&](std::string& rule) { + if (rule.find("workspace") == 0) { + rule = workspaceRule; + hadWorkspaceRule = true; + } + }); + + if (!hadWorkspaceRule) + rulesList.append(workspaceRule); + + rules = "[" + rulesList.join(";") + "]"; + } else { + rules = "[" + workspaceRule + "]"; + } + + return std::optional(rules + " " + cmd); + } + + return std::nullopt; +} + float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) { const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x}); const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y}); @@ -594,8 +632,8 @@ int64_t getPPIDof(int64_t pid) { return 0; #else - std::string dir = "/proc/" + std::to_string(pid) + "/status"; - FILE* infile; + std::string dir = "/proc/" + std::to_string(pid) + "/status"; + FILE* infile; infile = fopen(dir.c_str(), "r"); if (!infile) diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 429f381f..d489a0cd 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -20,6 +21,7 @@ std::string removeBeginEndSpacesTabs(std::string); bool isNumber(const std::string&, bool allowfloat = false); bool isDirection(const std::string&); int getWorkspaceIDFromString(const std::string&, std::string&); +std::optional cleanCmdForWorkspace(const std::string&, std::string); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); void logSystemInfo(); std::string execAndGet(const char*); diff --git a/src/helpers/VarList.hpp b/src/helpers/VarList.hpp index 60e9a551..8f33f166 100644 --- a/src/helpers/VarList.hpp +++ b/src/helpers/VarList.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include "../macros.hpp" @@ -20,6 +21,15 @@ class CVarList { std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const; + void map(std::function func) { + for (auto& s : m_vArgs) + func(s); + } + + void append(const std::string arg) { + m_vArgs.emplace_back(arg); + } + std::string operator[](const size_t& idx) const { if (idx >= m_vArgs.size()) return ""; diff --git a/src/helpers/Workspace.hpp b/src/helpers/Workspace.hpp index cbdbc07a..a0bbb815 100644 --- a/src/helpers/Workspace.hpp +++ b/src/helpers/Workspace.hpp @@ -4,8 +4,7 @@ #include #include "../defines.hpp" -enum eFullscreenMode : int8_t -{ +enum eFullscreenMode : int8_t { FULLSCREEN_INVALID = -1, FULLSCREEN_FULL = 0, FULLSCREEN_MAXIMIZED @@ -53,6 +52,9 @@ class CWorkspace { // last monitor (used on reconnect) std::string m_szLastMonitor = ""; + // Whether the user configured command for on-created-empty has been executed, if any + bool m_bOnCreatedEmptyExecuted = false; + void startAnim(bool in, bool left, bool instant = false); void setActive(bool on); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 321409cc..72e7f24e 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1,5 +1,7 @@ #include "KeybindManager.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" +#include "debug/Log.hpp" +#include "helpers/VarList.hpp" #include