aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-12-16 19:05:24 +0100
committerGitHub <[email protected]>2024-12-16 19:05:24 +0100
commitdab50b3ef3a1bad7f68320538223b6b41d1c6012 (patch)
tree3b911a592b2bece2017bdfdcc7557cbc6a3d22b0
parenteaac5c7cbdd40a2211c75a770df56bd2153b77cb (diff)
downloadHyprland-dab50b3ef3a1bad7f68320538223b6b41d1c6012.tar.gz
Hyprland-dab50b3ef3a1bad7f68320538223b6b41d1c6012.zip
core: Optimize window/layer rule application and scanning (#8735)
Optimizes window and layer rule parsing and later usage.
-rw-r--r--src/config/ConfigManager.cpp275
-rw-r--r--src/config/ConfigManager.hpp10
-rw-r--r--src/desktop/LayerRule.cpp37
-rw-r--r--src/desktop/LayerRule.hpp28
-rw-r--r--src/desktop/LayerSurface.cpp82
-rw-r--r--src/desktop/LayerSurface.hpp6
-rw-r--r--src/desktop/Window.cpp307
-rw-r--r--src/desktop/Window.hpp25
-rw-r--r--src/desktop/WindowRule.cpp100
-rw-r--r--src/desktop/WindowRule.hpp65
-rw-r--r--src/events/Windows.cpp480
-rw-r--r--src/layout/IHyprLayout.cpp38
12 files changed, 855 insertions, 598 deletions
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index d81e3947..bcbfe7e7 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -736,7 +736,7 @@ std::optional<std::string> CConfigManager::verifyConfigExists() {
return {};
}
-const std::string CConfigManager::getConfigString() {
+std::string CConfigManager::getConfigString() {
std::string configString;
std::string currFileContent;
@@ -1231,19 +1231,16 @@ SWorkspaceRule CConfigManager::mergeWorkspaceRules(const SWorkspaceRule& rule1,
return mergedRule;
}
-std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, bool dynamic, bool shadowExec) {
+std::vector<SP<CWindowRule>> CConfigManager::getMatchingRules(PHLWINDOW pWindow, bool dynamic, bool shadowExec) {
if (!valid(pWindow))
- return std::vector<SWindowRule>();
+ return std::vector<SP<CWindowRule>>();
// if the window is unmapped, don't process exec rules yet.
shadowExec = shadowExec || !pWindow->m_bIsMapped;
- std::vector<SWindowRule> returns;
+ std::vector<SP<CWindowRule>> returns;
- std::string title = pWindow->m_szTitle;
- std::string appidclass = pWindow->m_szClass;
-
- Debug::log(LOG, "Searching for matching rules for {} (title: {})", appidclass, title);
+ Debug::log(LOG, "Searching for matching rules for {} (title: {})", pWindow->m_szClass, pWindow->m_szTitle);
// since some rules will be applied later, we need to store some flags
bool hasFloating = pWindow->m_bIsFloating;
@@ -1254,86 +1251,55 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
for (auto const& rule : m_vWindowRules) {
// check if we have a matching rule
- if (!rule.v2) {
+ if (!rule->v2) {
try {
- if (rule.szValue.starts_with("tag:") && !tags.isTagged(rule.szValue.substr(4)))
+ if (rule->szValue.starts_with("tag:") && !tags.isTagged(rule->szValue.substr(4)))
continue;
- if (rule.szValue.starts_with("title:")) {
- std::regex RULECHECK(rule.szValue.substr(6));
+ if (rule->szValue.starts_with("title:")) {
+ std::regex RULECHECK(rule->szValue.substr(6));
- if (!std::regex_search(title, RULECHECK))
+ if (!std::regex_search(pWindow->m_szTitle, RULECHECK))
continue;
} else {
- std::regex classCheck(rule.szValue);
+ std::regex classCheck(rule->szValue);
- if (!std::regex_search(appidclass, classCheck))
+ if (!std::regex_search(pWindow->m_szClass, classCheck))
continue;
}
} catch (...) {
- Debug::log(ERR, "Regex error at {}", rule.szValue);
+ Debug::log(ERR, "Regex error at {}", rule->szValue);
continue;
}
} else {
try {
- if (!rule.szTag.empty() && !tags.isTagged(rule.szTag))
- continue;
-
- if (!rule.szClass.empty()) {
- std::regex RULECHECK(rule.szClass);
-
- if (!std::regex_search(appidclass, RULECHECK))
- continue;
- }
-
- if (!rule.szTitle.empty()) {
- std::regex RULECHECK(rule.szTitle);
-
- if (!std::regex_search(title, RULECHECK))
- continue;
- }
-
- if (!rule.szInitialTitle.empty()) {
- std::regex RULECHECK(rule.szInitialTitle);
-
- if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
- continue;
- }
-
- if (!rule.szInitialClass.empty()) {
- std::regex RULECHECK(rule.szInitialClass);
-
- if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
- continue;
- }
-
- if (rule.bX11 != -1) {
- if (pWindow->m_bIsX11 != rule.bX11)
+ if (rule->bX11 != -1) {
+ if (pWindow->m_bIsX11 != rule->bX11)
continue;
}
- if (rule.bFloating != -1) {
- if (hasFloating != rule.bFloating)
+ if (rule->bFloating != -1) {
+ if (hasFloating != rule->bFloating)
continue;
}
- if (rule.bFullscreen != -1) {
- if (hasFullscreen != rule.bFullscreen)
+ if (rule->bFullscreen != -1) {
+ if (hasFullscreen != rule->bFullscreen)
continue;
}
- if (rule.bPinned != -1) {
- if (pWindow->m_bPinned != rule.bPinned)
+ if (rule->bPinned != -1) {
+ if (pWindow->m_bPinned != rule->bPinned)
continue;
}
- if (rule.bFocus != -1) {
- if (rule.bFocus != (g_pCompositor->m_pLastWindow.lock() == pWindow))
+ if (rule->bFocus != -1) {
+ if (rule->bFocus != (g_pCompositor->m_pLastWindow.lock() == pWindow))
continue;
}
- if (!rule.szFullscreenState.empty()) {
- const auto ARGS = CVarList(rule.szFullscreenState, 2, ' ');
+ if (!rule->szFullscreenState.empty()) {
+ const auto ARGS = CVarList(rule->szFullscreenState, 2, ' ');
//
std::optional<eFullscreenMode> internalMode, clientMode;
@@ -1358,46 +1324,77 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
continue;
}
- if (!rule.szOnWorkspace.empty()) {
+ if (!rule->szOnWorkspace.empty()) {
const auto PWORKSPACE = pWindow->m_pWorkspace;
- if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule.szOnWorkspace))
+ if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule->szOnWorkspace))
continue;
}
- if (!rule.szWorkspace.empty()) {
+ if (!rule->szWorkspace.empty()) {
const auto PWORKSPACE = pWindow->m_pWorkspace;
if (!PWORKSPACE)
continue;
- if (rule.szWorkspace.starts_with("name:")) {
- if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5))
+ if (rule->szWorkspace.starts_with("name:")) {
+ if (PWORKSPACE->m_szName != rule->szWorkspace.substr(5))
continue;
} else {
// number
- if (!isNumber(rule.szWorkspace))
+ if (!isNumber(rule->szWorkspace))
throw std::runtime_error("szWorkspace not name: or number");
- const int64_t ID = std::stoll(rule.szWorkspace);
+ const int64_t ID = std::stoll(rule->szWorkspace);
if (PWORKSPACE->m_iID != ID)
continue;
}
}
+
+ if (!rule->szTag.empty() && !tags.isTagged(rule->szTag))
+ continue;
+
+ if (!rule->szClass.empty()) {
+ std::regex RULECHECK(rule->szClass);
+
+ if (!std::regex_search(pWindow->m_szClass, RULECHECK))
+ continue;
+ }
+
+ if (!rule->szTitle.empty()) {
+ std::regex RULECHECK(rule->szTitle);
+
+ if (!std::regex_search(pWindow->m_szTitle, RULECHECK))
+ continue;
+ }
+
+ if (!rule->szInitialTitle.empty()) {
+ std::regex RULECHECK(rule->szInitialTitle);
+
+ if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
+ continue;
+ }
+
+ if (!rule->szInitialClass.empty()) {
+ std::regex RULECHECK(rule->szInitialClass);
+
+ if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
+ continue;
+ }
} catch (std::exception& e) {
- Debug::log(ERR, "Regex error at {} ({})", rule.szValue, e.what());
+ Debug::log(ERR, "Regex error at {} ({})", rule->szValue, e.what());
continue;
}
}
// applies. Read the rule and behave accordingly
- Debug::log(LOG, "Window rule {} -> {} matched {}", rule.szRule, rule.szValue, pWindow);
+ Debug::log(LOG, "Window rule {} -> {} matched {}", rule->szRule, rule->szValue, pWindow);
- returns.push_back(rule);
+ returns.emplace_back(rule);
// apply tag with local tags
- if (rule.szRule.starts_with("tag")) {
- CVarList vars{rule.szRule, 0, 's', true};
+ if (rule->ruleType == CWindowRule::RULE_TAG) {
+ CVarList vars{rule->szRule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag")
tags.applyTag(vars[1], true);
}
@@ -1405,9 +1402,9 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
if (dynamic)
continue;
- if (rule.szRule == "float")
+ if (rule->szRule == "float")
hasFloating = true;
- else if (rule.szRule == "fullscreen")
+ else if (rule->szRule == "fullscreen")
hasFullscreen = true;
}
@@ -1419,41 +1416,40 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
for (auto const& er : execRequestedRules) {
if (std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == er.iPid; })) {
- returns.push_back({er.szRule, "execRule"});
+ returns.emplace_back(makeShared<CWindowRule>(er.szRule, "", false, true));
anyExecFound = true;
}
}
if (anyExecFound && !shadowExec) // remove exec rules to unclog searches in the future, why have the garbage here.
- execRequestedRules.erase(std::remove_if(execRequestedRules.begin(), execRequestedRules.end(),
- [&](const SExecRequestedRule& other) { return std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == other.iPid; }); }));
+ std::erase_if(execRequestedRules, [&](const SExecRequestedRule& other) { return std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == other.iPid; }); });
return returns;
}
-std::vector<SLayerRule> CConfigManager::getMatchingRules(PHLLS pLS) {
- std::vector<SLayerRule> returns;
+std::vector<SP<CLayerRule>> CConfigManager::getMatchingRules(PHLLS pLS) {
+ std::vector<SP<CLayerRule>> returns;
if (!pLS->layerSurface || pLS->fadingOut)
return returns;
for (auto const& lr : m_vLayerRules) {
- if (lr.targetNamespace.starts_with("address:0x")) {
- if (std::format("address:0x{:x}", (uintptr_t)pLS.get()) != lr.targetNamespace)
+ if (lr->targetNamespace.starts_with("address:0x")) {
+ if (std::format("address:0x{:x}", (uintptr_t)pLS.get()) != lr->targetNamespace)
continue;
} else {
- std::regex NSCHECK(lr.targetNamespace);
+ std::regex NSCHECK(lr->targetNamespace);
if (!std::regex_search(pLS->layerSurface->layerNamespace, NSCHECK))
continue;
}
// hit
- returns.push_back(lr);
+ returns.emplace_back(lr);
}
if (shouldBlurLS(pLS->layerSurface->layerNamespace))
- returns.push_back({pLS->layerSurface->layerNamespace, "blur"});
+ returns.emplace_back(makeShared<CLayerRule>(pLS->layerSurface->layerNamespace, "blur"));
return returns;
}
@@ -2306,29 +2302,6 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
return {};
}
-bool windowRuleValid(const std::string& RULE) {
- static const auto rules = std::unordered_set<std::string>{
- "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
- };
- static const auto rulesPrefix = std::vector<std::string>{
- "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move",
- "opacity", "plugin:", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
- };
-
- const auto VALS = CVarList(RULE, 2, ' ');
- return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }) ||
- (g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
- (g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
- (g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
-}
-
-bool layerRuleValid(const std::string& RULE) {
- static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
- static const auto rulesPrefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order"};
-
- return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
-}
-
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
const auto RULE = trim(value.substr(0, value.find_first_of(',')));
const auto VALUE = trim(value.substr(value.find_first_of(',') + 1));
@@ -2338,20 +2311,22 @@ std::optional<std::string> CConfigManager::handleWindowRule(const std::string& c
return "empty rule?";
if (RULE == "unset") {
- std::erase_if(m_vWindowRules, [&](const SWindowRule& other) { return other.szValue == VALUE; });
+ std::erase_if(m_vWindowRules, [&](const auto& other) { return other->szValue == VALUE; });
return {};
}
+ auto newRule = makeShared<CWindowRule>(RULE, VALUE, false);
+
// verify we support a rule
- if (!windowRuleValid(RULE)) {
+ if (newRule->ruleType == CWindowRule::RULE_INVALID) {
Debug::log(ERR, "Invalid rule found: {}", RULE);
return "Invalid rule: " + RULE;
}
if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
- m_vWindowRules.insert(m_vWindowRules.begin(), {RULE, VALUE});
+ m_vWindowRules.insert(m_vWindowRules.begin(), newRule);
else
- m_vWindowRules.push_back({RULE, VALUE});
+ m_vWindowRules.emplace_back(newRule);
return {};
}
@@ -2365,16 +2340,18 @@ std::optional<std::string> CConfigManager::handleLayerRule(const std::string& co
return "empty rule?";
if (RULE == "unset") {
- std::erase_if(m_vLayerRules, [&](const SLayerRule& other) { return other.targetNamespace == VALUE; });
+ std::erase_if(m_vLayerRules, [&](const auto& other) { return other->targetNamespace == VALUE; });
return {};
}
- if (!layerRuleValid(RULE)) {
+ auto rule = makeShared<CLayerRule>(RULE, VALUE);
+
+ if (rule->ruleType == CLayerRule::RULE_INVALID) {
Debug::log(ERR, "Invalid rule found: {}", RULE);
return "Invalid rule found: " + RULE;
}
- m_vLayerRules.push_back({VALUE, RULE});
+ m_vLayerRules.emplace_back(rule);
for (auto const& m : g_pCompositor->m_vMonitors)
for (auto const& lsl : m->m_aLayerSurfaceLayers)
@@ -2388,17 +2365,14 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
const auto RULE = trim(value.substr(0, value.find_first_of(',')));
const auto VALUE = value.substr(value.find_first_of(',') + 1);
- if (!windowRuleValid(RULE) && RULE != "unset") {
+ auto rule = makeShared<CWindowRule>(RULE, VALUE, true);
+
+ if (rule->ruleType == CWindowRule::RULE_INVALID && RULE != "unset") {
Debug::log(ERR, "Invalid rulev2 found: {}", RULE);
return "Invalid rulev2 found: " + RULE;
}
// now we estract shit from the value
- SWindowRule rule;
- rule.v2 = true;
- rule.szRule = RULE;
- rule.szValue = VALUE;
-
const auto TAGPOS = VALUE.find("tag:");
const auto TITLEPOS = VALUE.find("title:");
const auto CLASSPOS = VALUE.find("class:");
@@ -2473,86 +2447,86 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
};
if (TAGPOS != std::string::npos)
- rule.szTag = extract(TAGPOS + 4);
+ rule->szTag = extract(TAGPOS + 4);
if (CLASSPOS != std::string::npos)
- rule.szClass = extract(CLASSPOS + 6);
+ rule->szClass = extract(CLASSPOS + 6);
if (TITLEPOS != std::string::npos)
- rule.szTitle = extract(TITLEPOS + 6);
+ rule->szTitle = extract(TITLEPOS + 6);
if (INITIALCLASSPOS != std::string::npos)
- rule.szInitialClass = extract(INITIALCLASSPOS + 13);
+ rule->szInitialClass = extract(INITIALCLASSPOS + 13);
if (INITIALTITLEPOS != std::string::npos)
- rule.szInitialTitle = extract(INITIALTITLEPOS + 13);
+ rule->szInitialTitle = extract(INITIALTITLEPOS + 13);
if (X11POS != std::string::npos)
- rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
+ rule->bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
if (FLOATPOS != std::string::npos)
- rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
+ rule->bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
if (FULLSCREENPOS != std::string::npos)
- rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
+ rule->bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
if (PINNEDPOS != std::string::npos)
- rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
+ rule->bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
if (FULLSCREENSTATEPOS != std::string::npos)
- rule.szFullscreenState = extract(FULLSCREENSTATEPOS + 16);
+ rule->szFullscreenState = extract(FULLSCREENSTATEPOS + 16);
if (WORKSPACEPOS != std::string::npos)
- rule.szWorkspace = extract(WORKSPACEPOS + 10);
+ rule->szWorkspace = extract(WORKSPACEPOS + 10);
if (FOCUSPOS != std::string::npos)
- rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
+ rule->bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
if (ONWORKSPACEPOS != std::string::npos)
- rule.szOnWorkspace = extract(ONWORKSPACEPOS + 12);
+ rule->szOnWorkspace = extract(ONWORKSPACEPOS + 12);
if (RULE == "unset") {
- std::erase_if(m_vWindowRules, [&](const SWindowRule& other) {
- if (!other.v2) {
- return other.szClass == rule.szClass && !rule.szClass.empty();
- } else {
- if (!rule.szTag.empty() && rule.szTag != other.szTag)
+ std::erase_if(m_vWindowRules, [&](const auto& other) {
+ if (!other->v2)
+ return other->szClass == rule->szClass && !rule->szClass.empty();
+ else {
+ if (!rule->szTag.empty() && rule->szTag != other->szTag)
return false;
- if (!rule.szClass.empty() && rule.szClass != other.szClass)
+ if (!rule->szClass.empty() && rule->szClass != other->szClass)
return false;
- if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
+ if (!rule->szTitle.empty() && rule->szTitle != other->szTitle)
return false;
- if (!rule.szInitialClass.empty() && rule.szInitialClass != other.szInitialClass)
+ if (!rule->szInitialClass.empty() && rule->szInitialClass != other->szInitialClass)
return false;
- if (!rule.szInitialTitle.empty() && rule.szInitialTitle != other.szInitialTitle)
+ if (!rule->szInitialTitle.empty() && rule->szInitialTitle != other->szInitialTitle)
return false;
- if (rule.bX11 != -1 && rule.bX11 != other.bX11)
+ if (rule->bX11 != -1 && rule->bX11 != other->bX11)
return false;
- if (rule.bFloating != -1 && rule.bFloating != other.bFloating)
+ if (rule->bFloating != -1 && rule->bFloating != other->bFloating)
return false;
- if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen)
+ if (rule->bFullscreen != -1 && rule->bFullscreen != other->bFullscreen)
return false;
- if (rule.bPinned != -1 && rule.bPinned != other.bPinned)
+ if (rule->bPinned != -1 && rule->bPinned != other->bPinned)
return false;
- if (!rule.szFullscreenState.empty() && rule.szFullscreenState != other.szFullscreenState)
+ if (!rule->szFullscreenState.empty() && rule->szFullscreenState != other->szFullscreenState)
return false;
- if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
+ if (!rule->szWorkspace.empty() && rule->szWorkspace != other->szWorkspace)
return false;
- if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
+ if (rule->bFocus != -1 && rule->bFocus != other->bFocus)
return false;
- if (!rule.szOnWorkspace.empty() && rule.szOnWorkspace != other.szOnWorkspace)
+ if (!rule->szOnWorkspace.empty() && rule->szOnWorkspace != other->szOnWorkspace)
return false;
return true;
@@ -2573,9 +2547,8 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl
const bool BYADDRESS = name.starts_with("address:");
std::string matchName = name;
- if (BYADDRESS) {
+ if (BYADDRESS)
matchName = matchName.substr(8);
- }
for (auto const& m : g_pCompositor->m_vMonitors) {
for (auto const& lsl : m->m_aLayerSurfaceLayers) {
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index 7802d1e4..1eca5ac3 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -166,7 +166,7 @@ class CConfigManager {
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getMainConfigPath();
- const std::string getConfigString();
+ std::string getConfigString();
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
@@ -176,8 +176,8 @@ class CConfigManager {
std::string getBoundMonitorStringForWS(const std::string&);
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
- std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
- std::vector<SLayerRule> getMatchingRules(PHLLS);
+ std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
+ std::vector<SP<CLayerRule>> getMatchingRules(PHLLS);
const std::vector<SConfigOptionDescription>& getAllDescriptions();
@@ -291,8 +291,8 @@ class CConfigManager {
std::vector<SMonitorRule> m_vMonitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules;
- std::vector<SWindowRule> m_vWindowRules;
- std::vector<SLayerRule> m_vLayerRules;
+ std::vector<SP<CWindowRule>> m_vWindowRules;
+ std::vector<SP<CLayerRule>> m_vLayerRules;
std::vector<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false;
diff --git a/src/desktop/LayerRule.cpp b/src/desktop/LayerRule.cpp
new file mode 100644
index 00000000..d82e4d30
--- /dev/null
+++ b/src/desktop/LayerRule.cpp
@@ -0,0 +1,37 @@
+#include "LayerRule.hpp"
+#include <unordered_set>
+#include <algorithm>
+#include "../debug/Log.hpp"
+
+static const auto RULES = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
+static const auto RULES_PREFIX = std::unordered_set<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order"};
+
+CLayerRule::CLayerRule(const std::string& rule_, const std::string& ns_) : targetNamespace(ns_), rule(rule_) {
+ const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule_](const auto& prefix) { return rule_.starts_with(prefix); });
+
+ if (!VALID)
+ return;
+
+ if (rule == "noanim")
+ ruleType = RULE_NOANIM;
+ else if (rule == "blur")
+ ruleType = RULE_BLUR;
+ else if (rule == "blurpopups")
+ ruleType = RULE_BLURPOPUPS;
+ else if (rule == "dimaround")
+ ruleType = RULE_DIMAROUND;
+ else if (rule.starts_with("ignorealpha"))
+ ruleType = RULE_IGNOREALPHA;
+ else if (rule.starts_with("ignorezero"))
+ ruleType = RULE_IGNOREZERO;
+ else if (rule.starts_with("xray"))
+ ruleType = RULE_XRAY;
+ else if (rule.starts_with("animation"))
+ ruleType = RULE_ANIMATION;
+ else if (rule.starts_with("order"))
+ ruleType = RULE_ORDER;
+ else {
+ Debug::log(ERR, "CLayerRule: didn't match a rule that was found valid?!");
+ ruleType = RULE_INVALID;
+ }
+} \ No newline at end of file
diff --git a/src/desktop/LayerRule.hpp b/src/desktop/LayerRule.hpp
new file mode 100644
index 00000000..7dca4621
--- /dev/null
+++ b/src/desktop/LayerRule.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <string>
+#include <cstdint>
+
+class CLayerRule {
+ public:
+ CLayerRule(const std::string& rule, const std::string& targetNS);
+
+ enum eRuleType : uint8_t {
+ RULE_INVALID = 0,
+ RULE_NOANIM,
+ RULE_BLUR,
+ RULE_BLURPOPUPS,
+ RULE_DIMAROUND,
+ RULE_IGNOREALPHA,
+ RULE_IGNOREZERO,
+ RULE_XRAY,
+ RULE_ANIMATION,
+ RULE_ORDER,
+ RULE_ZUMBA,
+ };
+
+ eRuleType ruleType = RULE_INVALID;
+
+ const std::string targetNamespace;
+ const std::string rule;
+}; \ No newline at end of file
diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp
index fa421b17..6c63c1ca 100644
--- a/src/desktop/LayerSurface.cpp
+++ b/src/desktop/LayerSurface.cpp
@@ -378,38 +378,56 @@ void CLayerSurface::applyRules() {
animationStyle.reset();
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) {
- if (rule.rule == "noanim")
- noAnimations = true;
- else if (rule.rule == "blur")
- forceBlur = true;
- else if (rule.rule == "blurpopups")
- forceBlurPopups = true;
- else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
- const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
- std::string alphaValue = "";
- if (FIRST_SPACE_POS != std::string::npos)
- alphaValue = rule.rule.substr(FIRST_SPACE_POS + 1);
-
- try {
- ignoreAlpha = true;
- if (!alphaValue.empty())
- ignoreAlphaValue = std::stof(alphaValue);
- } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
- } else if (rule.rule == "dimaround") {
- dimAround = true;
- } else if (rule.rule.starts_with("xray")) {
- CVarList vars{rule.rule, 0, ' '};
- try {
- xray = configStringToInt(vars[1]).value_or(false);
- } catch (...) {}
- } else if (rule.rule.starts_with("animation")) {
- CVarList vars{rule.rule, 2, 's'};
- animationStyle = vars[1];
- } else if (rule.rule.starts_with("order")) {
- CVarList vars{rule.rule, 2, 's'};
- try {
- order = std::stoi(vars[1]);
- } catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
+ switch (rule->ruleType) {
+ case CLayerRule::RULE_NOANIM: {
+ noAnimations = true;
+ break;
+ }
+ case CLayerRule::RULE_BLUR: {
+ forceBlur = true;
+ break;
+ }
+ case CLayerRule::RULE_BLURPOPUPS: {
+ forceBlurPopups = true;
+ break;
+ }
+ case CLayerRule::RULE_IGNOREALPHA: {
+ const auto FIRST_SPACE_POS = rule->rule.find_first_of(' ');
+ std::string alphaValue = "";
+ if (FIRST_SPACE_POS != std::string::npos)
+ alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1);
+
+ try {
+ ignoreAlpha = true;
+ if (!alphaValue.empty())
+ ignoreAlphaValue = std::stof(alphaValue);
+ } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
+ break;
+ }
+ case CLayerRule::RULE_DIMAROUND: {
+ dimAround = true;
+ break;
+ }
+ case CLayerRule::RULE_XRAY: {
+ CVarList vars{rule->rule, 0, ' '};
+ try {
+ xray = configStringToInt(vars[1]).value_or(false);
+ } catch (...) {}
+ break;
+ }
+ case CLayerRule::RULE_ANIMATION: {
+ CVarList vars{rule->rule, 2, 's'};
+ animationStyle = vars[1];
+ break;
+ }
+ case CLayerRule::RULE_ORDER: {
+ CVarList vars{rule->rule, 2, 's'};
+ try {
+ order = std::stoi(vars[1]);
+ } catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
+ break;
+ }
+ default: break;
}
}
}
diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp
index 6aa8eb81..e906fc6f 100644
--- a/src/desktop/LayerSurface.hpp
+++ b/src/desktop/LayerSurface.hpp
@@ -4,11 +4,7 @@
#include "../defines.hpp"
#include "WLSurface.hpp"
#include "../helpers/AnimatedVariable.hpp"
-
-struct SLayerRule {
- std::string targetNamespace = "";
- std::string rule = "";
-};
+#include "LayerRule.hpp"
class CLayerShellResource;
diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp
index e2106e4a..9d4b597b 100644
--- a/src/desktop/Window.cpp
+++ b/src/desktop/Window.cpp
@@ -614,160 +614,179 @@ bool CWindow::isHidden() {
return m_bHidden;
}
-void CWindow::applyDynamicRule(const SWindowRule& r) {
- const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
- const CVarList VARS(r.szRule, 0, ' ');
- if (r.szRule.starts_with("tag")) {
- CVarList vars{r.szRule, 0, 's', true};
-
- if (vars.size() == 2 && vars[0] == "tag")
- m_tags.applyTag(vars[1], true);
- else
- Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
- } else if (r.szRule.starts_with("opacity")) {
- try {
- CVarList vars(r.szRule, 0, ' ');
-
- int opacityIDX = 0;
-
- for (auto const& r : vars) {
- if (r == "opacity")
- continue;
-
- if (r == "override") {
- if (opacityIDX == 1)
- m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
- else if (opacityIDX == 2)
- m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
- else if (opacityIDX == 3)
- m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
- } else {
- if (opacityIDX == 0) {
- m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
- } else if (opacityIDX == 1) {
- m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
- } else if (opacityIDX == 2) {
- m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
+void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
+ const eOverridePriority priority = r->execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
+
+ switch (r->ruleType) {
+ case CWindowRule::RULE_TAG: {
+ CVarList vars{r->szRule, 0, 's', true};
+
+ if (vars.size() == 2 && vars[0] == "tag")
+ m_tags.applyTag(vars[1], true);
+ else
+ Debug::log(ERR, "Tag rule invalid: {}", r->szRule);
+ break;
+ }
+ case CWindowRule::RULE_OPACITY: {
+ try {
+ CVarList vars(r->szRule, 0, ' ');
+
+ int opacityIDX = 0;
+
+ for (auto const& r : vars) {
+ if (r == "opacity")
+ continue;
+
+ if (r == "override") {
+ if (opacityIDX == 1)
+ m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
+ else if (opacityIDX == 2)
+ m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
+ else if (opacityIDX == 3)
+ m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
} else {
- throw std::runtime_error("more than 3 alpha values");
+ if (opacityIDX == 0) {
+ m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
+ } else if (opacityIDX == 1) {
+ m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
+ } else if (opacityIDX == 2) {
+ m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
+ } else {
+ throw std::runtime_error("more than 3 alpha values");
+ }
+
+ opacityIDX++;
}
-
- opacityIDX++;
}
- }
- if (opacityIDX == 1) {
- m_sWindowData.alphaInactive = m_sWindowData.alpha;
- m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
- }
- } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
- } else if (r.szRule.starts_with("animation")) {
- auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
- m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
- } else if (r.szRule.starts_with("bordercolor")) {
- try {
- // Each vector will only get used if it has at least one color
- CGradientValueData activeBorderGradient = {};
- CGradientValueData inactiveBorderGradient = {};
- bool active = true;
- CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
-
- // Basic form has only two colors, everything else can be parsed as a gradient
- if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
- m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
- m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
- return;
- }
+ if (opacityIDX == 1) {
+ m_sWindowData.alphaInactive = m_sWindowData.alpha;
+ m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
+ }
+ } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ break;
+ }
+ case CWindowRule::RULE_ANIMATION: {
+ auto STYLE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
+ m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
+ break;
+ }
+ case CWindowRule::RULE_BORDERCOLOR: {
+ try {
+ // Each vector will only get used if it has at least one color
+ CGradientValueData activeBorderGradient = {};
+ CGradientValueData inactiveBorderGradient = {};
+ bool active = true;
+ CVarList colorsAndAngles = CVarList(trim(r->szRule.substr(r->szRule.find_first_of(' ') + 1)), 0, 's', true);
+
+ // Basic form has only two colors, everything else can be parsed as a gradient
+ if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
+ m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
+ m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
+ return;
+ }
- for (auto const& token : colorsAndAngles) {
- // The first angle, or an explicit "0deg", splits the two gradients
- if (active && token.contains("deg")) {
- activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
- active = false;
- } else if (token.contains("deg"))
- inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
- else if (active)
- activeBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
- else
- inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
- }
+ for (auto const& token : colorsAndAngles) {
+ // The first angle, or an explicit "0deg", splits the two gradients
+ if (active && token.contains("deg")) {
+ activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
+ active = false;
+ } else if (token.contains("deg"))
+ inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
+ else if (active)
+ activeBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
+ else
+ inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
+ }
- activeBorderGradient.updateColorsOk();
-
- // Includes sanity checks for the number of colors in each gradient
- if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
- Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
- else if (activeBorderGradient.m_vColors.empty())
- Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
- else if (inactiveBorderGradient.m_vColors.empty())
- m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
- else {
- m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
- m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
- }
- } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
- } else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
- if (VARS[1].empty()) {
- *(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
- } else {
- try {
- *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]).value_or(0), priority);
- } catch (...) {}
+ activeBorderGradient.updateColorsOk();
+
+ // Includes sanity checks for the number of colors in each gradient
+ if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
+ Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r->szRule);
+ else if (activeBorderGradient.m_vColors.empty())
+ Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r->szRule);
+ else if (inactiveBorderGradient.m_vColors.empty())
+ m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
+ else {
+ m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
+ m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
+ }
+ } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ break;
}
- } else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
- try {
- *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
- } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
- } else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[0]); search != g_pConfigManager->mfWindowProperties.end()) {
- try {
- *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[1]), priority);
- } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
- } else if (r.szRule.starts_with("idleinhibit")) {
- auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
-
- if (IDLERULE == "none")
- m_eIdleInhibitMode = IDLEINHIBIT_NONE;
- else if (IDLERULE == "always")
- m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
- else if (IDLERULE == "focus")
- m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
- else if (IDLERULE == "fullscreen")
- m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
- else
- Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
- } else if (r.szRule.starts_with("maxsize")) {
- try {
- if (!m_bIsFloating)
- return;
- const auto VEC = configStringToVector2D(r.szRule.substr(8));
- if (VEC.x < 1 || VEC.y < 1) {
- Debug::log(ERR, "Invalid size for maxsize");
- return;
- }
+ case CWindowRule::RULE_IDLEINHIBIT: {
+ auto IDLERULE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
+
+ if (IDLERULE == "none")
+ m_eIdleInhibitMode = IDLEINHIBIT_NONE;
+ else if (IDLERULE == "always")
+ m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
+ else if (IDLERULE == "focus")
+ m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
+ else if (IDLERULE == "fullscreen")
+ m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
+ else
+ Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
+ break;
+ }
+ case CWindowRule::RULE_MAXSIZE: {
+ try {
+ if (!m_bIsFloating)
+ return;
+ const auto VEC = configStringToVector2D(r->szRule.substr(8));
+ if (VEC.x < 1 || VEC.y < 1) {
+ Debug::log(ERR, "Invalid size for maxsize");
+ return;
+ }
- m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
- clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
+ m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
+ clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
- } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
- } else if (r.szRule.starts_with("minsize")) {
- try {
- if (!m_bIsFloating)
- return;
- const auto VEC = configStringToVector2D(r.szRule.substr(8));
- if (VEC.x < 1 || VEC.y < 1) {
- Debug::log(ERR, "Invalid size for minsize");
- return;
- }
+ } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ break;
+ }
+ case CWindowRule::RULE_MINSIZE: {
+ try {
+ if (!m_bIsFloating)
+ return;
+ const auto VEC = configStringToVector2D(r->szRule.substr(8));
+ if (VEC.x < 1 || VEC.y < 1) {
+ Debug::log(ERR, "Invalid size for minsize");
+ return;
+ }
- m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
- clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
+ m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
+ clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
- if (m_sGroupData.pNextWindow.expired())
- setHidden(false);
- } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
- } else if (r.szRule == "renderunfocused") {
- m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
- g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
+ if (m_sGroupData.pNextWindow.expired())
+ setHidden(false);
+ } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ break;
+ }
+ case CWindowRule::RULE_RENDERUNFOCUSED: {
+ m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
+ g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
+ break;
+ }
+ case CWindowRule::RULE_PROP: {
+ const CVarList VARS(r->szRule, 0, ' ');
+ if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
+ try {
+ *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
+ } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ } else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
+ try {
+ *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
+ } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ } else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
+ try {
+ *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)std::stoi(VARS[2]), priority);
+ } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
+ }
+ break;
+ }
+ default: break;
}
}
@@ -792,7 +811,7 @@ void CWindow::updateDynamicRules() {
m_tags.removeDynamicTags();
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
- for (auto const& r : m_vMatchedRules) {
+ for (const auto& r : m_vMatchedRules) {
applyDynamicRule(r);
}
diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp
index f57d6e60..c72f010e 100644
--- a/src/desktop/Window.hpp
+++ b/src/desktop/Window.hpp
@@ -17,6 +17,7 @@
#include "Subsurface.hpp"
#include "WLSurface.hpp"
#include "Workspace.hpp"
+#include "WindowRule.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
@@ -195,26 +196,6 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
};
-struct SWindowRule {
- std::string szRule;
- std::string szValue;
-
- bool v2 = false;
- std::string szTitle;
- std::string szClass;
- std::string szInitialTitle;
- std::string szInitialClass;
- std::string szTag;
- int bX11 = -1; // -1 means "ANY"
- int bFloating = -1;
- int bFullscreen = -1;
- int bPinned = -1;
- int bFocus = -1;
- std::string szFullscreenState = ""; // empty means any
- std::string szOnWorkspace = ""; // empty means any
- std::string szWorkspace = ""; // empty means any
-};
-
struct SInitialWorkspaceToken {
PHLWINDOWREF primaryOwner;
std::string workspace;
@@ -395,7 +376,7 @@ class CWindow {
bool m_bTearingHint = false;
// stores the currently matched window rules
- std::vector<SWindowRule> m_vMatchedRules;
+ std::vector<SP<CWindowRule>> m_vMatchedRules;
// window tags
CTagKeeper m_tags;
@@ -427,7 +408,7 @@ class CWindow {
void onMap();
void setHidden(bool hidden);
bool isHidden();
- void applyDynamicRule(const SWindowRule& r);
+ void applyDynamicRule(const SP<CWindowRule>& r);
void updateDynamicRules();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
diff --git a/src/desktop/WindowRule.cpp b/src/desktop/WindowRule.cpp
new file mode 100644
index 00000000..d721c4bd
--- /dev/null
+++ b/src/desktop/WindowRule.cpp
@@ -0,0 +1,100 @@
+#include "WindowRule.hpp"
+#include <unordered_set>
+#include <algorithm>
+#include "../config/ConfigManager.hpp"
+
+static const auto RULES = std::unordered_set<std::string>{
+ "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
+};
+static const auto RULES_PREFIX = std::unordered_set<std::string>{
+ "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity",
+ "plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
+};
+
+CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) {
+ const auto VALS = CVarList(rule, 2, ' ');
+ const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
+ (g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
+ (g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
+ (g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
+
+ if (!VALID)
+ return;
+
+ if (rule == "float")
+ ruleType = RULE_FLOAT;
+ else if (rule == "fullscreen")
+ ruleType = RULE_FULLSCREEN;
+ else if (rule == "maximize")
+ ruleType = RULE_MAXIMIZE;
+ else if (rule == "noinitialfocus")
+ ruleType = RULE_NOINITIALFOCUS;
+ else if (rule == "pin")
+ ruleType = RULE_PIN;
+ else if (rule == "stayfocused")
+ ruleType = RULE_STAYFOCUSED;
+ else if (rule == "tile")
+ ruleType = RULE_TILE;
+ else if (rule == "renderunfocused")
+ ruleType = RULE_RENDERUNFOCUSED;
+ else if (rule.starts_with("animation"))
+ ruleType = RULE_ANIMATION;
+ else if (rule.starts_with("bordercolor"))
+ ruleType = RULE_BORDERCOLOR;
+ else if (rule.starts_with("bordersize"))
+ ruleType = RULE_BORDERSIZE;
+ else if (rule.starts_with("center"))
+ ruleType = RULE_CENTER;
+ else if (rule.starts_with("fullscreenstate"))
+ ruleType = RULE_FULLSCREENSTATE;
+ else if (rule.starts_with("group"))
+ ruleType = RULE_GROUP;
+ else if (rule.starts_with("idleinhibit"))
+ ruleType = RULE_IDLEINHIBIT;
+ else if (rule.starts_with("maxsize"))
+ ruleType = RULE_MAXSIZE;
+ else if (rule.starts_with("minsize"))
+ ruleType = RULE_MINSIZE;
+ else if (rule.starts_with("monitor"))
+ ruleType = RULE_MONITOR;
+ else if (rule.starts_with("move"))
+ ruleType = RULE_MOVE;
+ else if (rule.starts_with("opacity"))
+ ruleType = RULE_OPACITY;
+ else if (rule.starts_with("plugin:"))
+ ruleType = RULE_PLUGIN;
+ else if (rule.starts_with("pseudo"))
+ ruleType = RULE_PSEUDO;
+ else if (rule.starts_with("rounding"))
+ ruleType = RULE_ROUNDING;
+ else if (rule.starts_with("scrollmouse"))
+ ruleType = RULE_SCROLLMOUSE;
+ else if (rule.starts_with("scrolltouchpad"))
+ ruleType = RULE_SCROLLTOUCHPAD;
+ else if (rule.starts_with("size"))
+ ruleType = RULE_SIZE;
+ else if (rule.starts_with("suppressevent"))
+ ruleType = RULE_SUPPRESSEVENT;
+ else if (rule.starts_with("tag"))
+ ruleType = RULE_TAG;
+ else if (rule.starts_with("workspace"))
+ ruleType = RULE_WORKSPACE;
+ else if (rule.starts_with("xray"))
+ ruleType = RULE_XRAY;
+ else if (rule.starts_with("prop"))
+ ruleType = RULE_PROP;
+ else {
+ // check if this is a prop.
+ const CVarList VARS(rule, 0, 's', true);
+ if (g_pConfigManager->miWindowProperties.find(VARS[0]) != g_pConfigManager->miWindowProperties.end() ||
+ g_pConfigManager->mbWindowProperties.find(VARS[0]) != g_pConfigManager->mbWindowProperties.end() ||
+ g_pConfigManager->mfWindowProperties.find(VARS[0]) != g_pConfigManager->mfWindowProperties.end()) {
+ *const_cast<std::string*>(&szRule) = "prop " + rule;
+ ruleType = RULE_PROP;
+ Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule);
+ } else {
+ Debug::log(ERR, "CWindowRule: didn't match a rule that was found valid?!");
+ ruleType = RULE_INVALID;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/desktop/WindowRule.hpp b/src/desktop/WindowRule.hpp
new file mode 100644
index 00000000..d1034cf6
--- /dev/null
+++ b/src/desktop/WindowRule.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <string>
+#include <cstdint>
+
+class CWindowRule {
+ public:
+ CWindowRule(const std::string& rule, const std::string& value, bool isV2 = false, bool isExecRule = false);
+
+ enum eRuleType : uint8_t {
+ RULE_INVALID = 0,
+ RULE_FLOAT,
+ RULE_FULLSCREEN,
+ RULE_MAXIMIZE,
+ RULE_NOINITIALFOCUS,
+ RULE_PIN,
+ RULE_STAYFOCUSED,
+ RULE_TILE,
+ RULE_RENDERUNFOCUSED,
+ RULE_ANIMATION,
+ RULE_BORDERCOLOR,
+ RULE_BORDERSIZE,
+ RULE_CENTER,
+ RULE_FULLSCREENSTATE,
+ RULE_GROUP,
+ RULE_IDLEINHIBIT,
+ RULE_MAXSIZE,
+ RULE_MINSIZE,
+ RULE_MONITOR,
+ RULE_MOVE,
+ RULE_OPACITY,
+ RULE_PLUGIN,
+ RULE_PSEUDO,
+ RULE_ROUNDING,
+ RULE_SCROLLMOUSE,
+ RULE_SCROLLTOUCHPAD,
+ RULE_SIZE,
+ RULE_SUPPRESSEVENT,
+ RULE_TAG,
+ RULE_WORKSPACE,
+ RULE_XRAY,
+ RULE_PROP,
+ };
+
+ eRuleType ruleType = RULE_INVALID;
+
+ const std::string szValue;
+ const std::string szRule;
+ const bool v2 = false;
+ const bool execRule = false;
+
+ std::string szTitle;
+ std::string szClass;
+ std::string szInitialTitle;
+ std::string szInitialClass;
+ std::string szTag;
+ int bX11 = -1; // -1 means "ANY"
+ int bFloating = -1;
+ int bFullscreen = -1;
+ int bPinned = -1;
+ int bFocus = -1;
+ std::string szFullscreenState = ""; // empty means any
+ std::string szOnWorkspace = ""; // empty means any
+ std::string szWorkspace = ""; // empty means any
+}; \ No newline at end of file
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index 7f258898..85eae934 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -139,144 +139,173 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestedClientFSMode = FSMODE_FULLSCREEN;
for (auto const& r : PWINDOW->m_vMatchedRules) {
- if (r.szRule.starts_with("monitor")) {
- try {
- const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' ')));
+ switch (r->ruleType) {
+ case CWindowRule::RULE_MONITOR: {
+ try {
+ const auto MONITORSTR = trim(r->szRule.substr(r->szRule.find(' ')));
- if (MONITORSTR == "unset") {
- PWINDOW->m_pMonitor = PMONITOR;
- } else {
- if (isNumber(MONITORSTR)) {
- const MONITORID MONITOR = std::stoi(MONITORSTR);
- if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
- PWINDOW->m_pMonitor = PM;
- else
- PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0);
+ if (MONITORSTR == "unset") {
+ PWINDOW->m_pMonitor = PMONITOR;
} else {
- const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
- if (PMONITOR)
- PWINDOW->m_pMonitor = PMONITOR;
- else {
- Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
- continue;
+ if (isNumber(MONITORSTR)) {
+ const MONITORID MONITOR = std::stoi(MONITORSTR);
+ if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
+ PWINDOW->m_pMonitor = PM;
+ else
+ PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0);
+ } else {
+ const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
+ if (PMONITOR)
+ PWINDOW->m_pMonitor = PMONITOR;
+ else {
+ Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
+ continue;
+ }
}
}
- }
-
- const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
- if (PWINDOW->m_pMonitor != PMONITOR) {
- g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
- PMONITOR = PMONITORFROMID;
- }
- PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
+ const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
- Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
- } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
- } else if (r.szRule.starts_with("workspace")) {
- // check if it isnt unset
- const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
+ if (PWINDOW->m_pMonitor != PMONITOR) {
+ g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
+ PMONITOR = PMONITORFROMID;
+ }
+ PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
- if (WORKSPACERQ == "unset") {
- requestedWorkspace = "";
- } else {
- requestedWorkspace = WORKSPACERQ;
+ Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
+ } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); }
+ break;
}
+ case CWindowRule::RULE_WORKSPACE: {
+ // check if it isnt unset
+ const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
- const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
+ if (WORKSPACERQ == "unset") {
+ requestedWorkspace = "";
+ } else {
+ requestedWorkspace = WORKSPACERQ;
+ }
- if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
- requestedWorkspace = "";
+ const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
- Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
- } else if (r.szRule.starts_with("float")) {
- PWINDOW->m_bIsFloating = true;
- } else if (r.szRule.starts_with("tile")) {
- PWINDOW->m_bIsFloating = false;
- } else if (r.szRule.starts_with("pseudo")) {
- PWINDOW->m_bIsPseudotiled = true;
- } else if (r.szRule.starts_with("noinitialfocus")) {
- PWINDOW->m_bNoInitialFocus = true;
- } else if (r.szRule.starts_with("fullscreenstate")) {
- const auto ARGS = CVarList(r.szRule.substr(r.szRule.find_first_of(' ') + 1), 2, ' ');
- int internalMode, clientMode;
- try {
- internalMode = std::stoi(ARGS[0]);
- } catch (std::exception& e) { internalMode = 0; }
- try {
- clientMode = std::stoi(ARGS[1]);
- } catch (std::exception& e) { clientMode = 0; }
- requestedFSState = SFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
- } else if (r.szRule.starts_with("suppressevent")) {
- CVarList vars(r.szRule, 0, 's', true);
- for (size_t i = 1; i < vars.size(); ++i) {
- if (vars[i] == "fullscreen")
- PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
- else if (vars[i] == "maximize")
- PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
- else if (vars[i] == "activate")
- PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
- else if (vars[i] == "activatefocus")
- PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
- else
- Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
- }
- } else if (r.szRule == "pin") {
- PWINDOW->m_bPinned = true;
- } else if (r.szRule == "fullscreen") {
- requestedInternalFSMode = FSMODE_FULLSCREEN;
- } else if (r.szRule == "maximize") {
- requestedInternalFSMode = FSMODE_MAXIMIZED;
- } else if (r.szRule == "stayfocused") {
- PWINDOW->m_bStayFocused = true;
- } else if (r.szRule.starts_with("group")) {
- if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
- continue;
+ if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
+ requestedWorkspace = "";
- // `group` is a shorthand of `group set`
- if (trim(r.szRule) == "group") {
- PWINDOW->m_eGroupRules |= GROUP_SET;
- continue;
+ Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue);
+ break;
}
-
- CVarList vars(r.szRule, 0, 's');
- std::string vPrev = "";
-
- for (auto const& v : vars) {
- if (v == "group")
+ case CWindowRule::RULE_FLOAT: {
+ PWINDOW->m_bIsFloating = true;
+ break;
+ }
+ case CWindowRule::RULE_TILE: {
+ PWINDOW->m_bIsFloating = false;
+ break;
+ }
+ case CWindowRule::RULE_PSEUDO: {
+ PWINDOW->m_bIsPseudotiled = true;
+ break;
+ }
+ case CWindowRule::RULE_NOINITIALFOCUS: {
+ PWINDOW->m_bNoInitialFocus = true;
+ break;
+ }
+ case CWindowRule::RULE_FULLSCREENSTATE: {
+ const auto ARGS = CVarList(r->szRule.substr(r->szRule.find_first_of(' ') + 1), 2, ' ');
+ int internalMode, clientMode;
+ try {
+ internalMode = std::stoi(ARGS[0]);
+ } catch (std::exception& e) { internalMode = 0; }
+ try {
+ clientMode = std::stoi(ARGS[1]);
+ } catch (std::exception& e) { clientMode = 0; }
+ requestedFSState = SFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
+ break;
+ }
+ case CWindowRule::RULE_SUPPRESSEVENT: {
+ CVarList vars(r->szRule, 0, 's', true);
+ for (size_t i = 1; i < vars.size(); ++i) {
+ if (vars[i] == "fullscreen")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
+ else if (vars[i] == "maximize")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
+ else if (vars[i] == "activate")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
+ else if (vars[i] == "activatefocus")
+ PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
+ else
+ Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
+ }
+ break;
+ }
+ case CWindowRule::RULE_PIN: {
+ PWINDOW->m_bPinned = true;
+ break;
+ }
+ case CWindowRule::RULE_FULLSCREEN: {
+ requestedInternalFSMode = FSMODE_FULLSCREEN;
+ break;
+ }
+ case CWindowRule::RULE_MAXIMIZE: {
+ requestedInternalFSMode = FSMODE_MAXIMIZED;
+ break;
+ }
+ case CWindowRule::RULE_STAYFOCUSED: {
+ PWINDOW->m_bStayFocused = true;
+ break;
+ }
+ case CWindowRule::RULE_GROUP: {
+ if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue;
- if (v == "set") {
+ // `group` is a shorthand of `group set`
+ if (trim(r->szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET;
- } else if (v == "new") {
- // shorthand for `group barred set`
- PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
- } else if (v == "lock") {
- PWINDOW->m_eGroupRules |= GROUP_LOCK;
- } else if (v == "invade") {
- PWINDOW->m_eGroupRules |= GROUP_INVADE;
- } else if (v == "barred") {
- PWINDOW->m_eGroupRules |= GROUP_BARRED;
- } else if (v == "deny") {
- PWINDOW->m_sGroupData.deny = true;
- } else if (v == "override") {
- // Clear existing rules
- PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
- } else if (v == "unset") {
- // Clear existing rules and stop processing
- PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
- break;
- } else if (v == "always") {
- if (vPrev == "set" || vPrev == "group")
- PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
- else if (vPrev == "lock")
- PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
- else
- Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
+ continue;
}
- vPrev = v;
+
+ CVarList vars(r->szRule, 0, 's');
+ std::string vPrev = "";
+
+ for (auto const& v : vars) {
+ if (v == "group")
+ continue;
+
+ if (v == "set") {
+ PWINDOW->m_eGroupRules |= GROUP_SET;
+ } else if (v == "new") {
+ // shorthand for `group barred set`
+ PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
+ } else if (v == "lock") {
+ PWINDOW->m_eGroupRules |= GROUP_LOCK;
+ } else if (v == "invade") {
+ PWINDOW->m_eGroupRules |= GROUP_INVADE;
+ } else if (v == "barred") {
+ PWINDOW->m_eGroupRules |= GROUP_BARRED;
+ } else if (v == "deny") {
+ PWINDOW->m_sGroupData.deny = true;
+ } else if (v == "override") {
+ // Clear existing rules
+ PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
+ } else if (v == "unset") {
+ // Clear existing rules and stop processing
+ PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
+ break;
+ } else if (v == "always") {
+ if (vPrev == "set" || vPrev == "group")
+ PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
+ else if (vPrev == "lock")
+ PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
+ else
+ Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
+ }
+ vPrev = v;
+ }
+ break;
}
+ default: break;
}
+
PWINDOW->applyDynamicRule(r);
}
@@ -330,125 +359,133 @@ void Events::listener_mapWindow(void* owner, void* data) {
// size and move rules
for (auto const& r : PWINDOW->m_vMatchedRules) {
- if (r.szRule.starts_with("size")) {
- try {
-
- auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
- if (VALUE.starts_with('<'))
- return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
- else if (VALUE.starts_with('>'))
- return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
+ switch (r->ruleType) {
+ case CWindowRule::RULE_SIZE: {
+ try {
+ auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
+ if (VALUE.starts_with('<'))
+ return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
+ else if (VALUE.starts_with('>'))
+ return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
- return stringToPercentage(VALUE, REL);
- };
+ return stringToPercentage(VALUE, REL);
+ };
- const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
- const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
- const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
+ const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
+ const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
+ const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
- const auto MAXSIZE = PWINDOW->requestedMaxSize();
+ const auto MAXSIZE = PWINDOW->requestedMaxSize();
- const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
- stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
+ const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
+ stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
- const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
- stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
+ const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
+ stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
- Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
+ Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
- PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
+ PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
- PWINDOW->setHidden(false);
- } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
- } else if (r.szRule.starts_with("move")) {
- try {
- auto value = r.szRule.substr(r.szRule.find(' ') + 1);
+ PWINDOW->setHidden(false);
+ } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
+ break;
+ }
+ case CWindowRule::RULE_MOVE: {
+ try {
+ auto value = r->szRule.substr(r->szRule.find(' ') + 1);
- const bool ONSCREEN = value.starts_with("onscreen");
+ const bool ONSCREEN = value.starts_with("onscreen");
- if (ONSCREEN)
- value = value.substr(value.find_first_of(' ') + 1);
+ if (ONSCREEN)
+ value = value.substr(value.find_first_of(' ') + 1);
- const bool CURSOR = value.starts_with("cursor");
+ const bool CURSOR = value.starts_with("cursor");
- if (CURSOR)
- value = value.substr(value.find_first_of(' ') + 1);
+ if (CURSOR)
+ value = value.substr(value.find_first_of(' ') + 1);
- const auto POSXSTR = value.substr(0, value.find(' '));
- const auto POSYSTR = value.substr(value.find(' ') + 1);
+ const auto POSXSTR = value.substr(0, value.find(' '));
+ const auto POSYSTR = value.substr(value.find(' ') + 1);
- int posX = 0;
- int posY = 0;
+ int posX = 0;
+ int posY = 0;
- if (POSXSTR.starts_with("100%-")) {
- const bool subtractWindow = POSXSTR.starts_with("100%-w-");
- const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : POSXSTR.substr(5);
- posX =
- PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
+ if (POSXSTR.starts_with("100%-")) {
+ const bool subtractWindow = POSXSTR.starts_with("100%-w-");
+ const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : POSXSTR.substr(5);
+ posX = PMONITOR->vecSize.x -
+ (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
- if (subtractWindow)
- posX -= PWINDOW->m_vRealSize.goal().x;
+ if (subtractWindow)
+ posX -= PWINDOW->m_vRealSize.goal().x;
- if (CURSOR)
- Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
- } else if (!CURSOR) {
- posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
- } else {
- // cursor
- if (POSXSTR == "cursor") {
- posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
+ if (CURSOR)
+ Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
+ } else if (!CURSOR) {
+ posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
} else {
- posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
- (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
+ // cursor
+ if (POSXSTR == "cursor") {
+ posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
+ } else {
+ posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
+ (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
+ }
}
- }
- if (POSYSTR.starts_with("100%-")) {
- const bool subtractWindow = POSYSTR.starts_with("100%-w-");
- const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : POSYSTR.substr(5);
- posY =
- PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
+ if (POSYSTR.starts_with("100%-")) {
+ const bool subtractWindow = POSYSTR.starts_with("100%-w-");
+ const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : POSYSTR.substr(5);
+ posY = PMONITOR->vecSize.y -
+ (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
- if (subtractWindow)
- posY -= PWINDOW->m_vRealSize.goal().y;
+ if (subtractWindow)
+ posY -= PWINDOW->m_vRealSize.goal().y;
- if (CURSOR)
- Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
- } else if (!CURSOR) {
- posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
- } else {
- // cursor
- if (POSYSTR == "cursor") {
- posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
+ if (CURSOR)
+ Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
+ } else if (!CURSOR) {
+ posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
} else {
- posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
- (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
+ // cursor
+ if (POSYSTR == "cursor") {
+ posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
+ } else {
+ posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
+ (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
+ }
}
- }
- if (ONSCREEN) {
- int borderSize = PWINDOW->getRealBorderSize();
+ if (ONSCREEN) {
+ int borderSize = PWINDOW->getRealBorderSize();
- posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
- (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
+ posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
+ (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
- posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
- (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
- }
+ posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
+ (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
+ }
- Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
+ Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
- PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
+ PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
+
+ PWINDOW->setHidden(false);
+ } catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); }
+ break;
+ }
+ case CWindowRule::RULE_CENTER: {
+ auto RESERVEDOFFSET = Vector2D();
+ const auto ARGS = CVarList(r->szRule, 2, ' ');
+ if (ARGS[1] == "1")
+ RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
- PWINDOW->setHidden(false);
- } catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
- } else if (r.szRule.starts_with("center")) {
- auto RESERVEDOFFSET = Vector2D();
- const auto ARGS = CVarList(r.szRule, 2, ' ');
- if (ARGS[1] == "1")
- RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
+ PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
+ break;
+ }
- PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
+ default: break;
}
}
@@ -463,26 +500,27 @@ void Events::listener_mapWindow(void* owner, void* data) {
bool setPseudo = false;
for (auto const& r : PWINDOW->m_vMatchedRules) {
- if (r.szRule.starts_with("size")) {
- try {
- const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
- const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
- const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
+ if (r->ruleType != CWindowRule::RULE_SIZE)
+ continue;
+
+ try {
+ const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
+ const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
+ const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
- const auto MAXSIZE = PWINDOW->requestedMaxSize();
+ const auto MAXSIZE = PWINDOW->requestedMaxSize();
- const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x);
+ const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x);
- const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y);
+ const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y);
- Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
+ Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
- setPseudo = true;
- PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
+ setPseudo = true;
+ PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
- PWINDOW->setHidden(false);
- } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
- }
+ PWINDOW->setHidden(false);
+ } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
}
if (!setPseudo)
diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp
index 857baacd..d9c2f6a1 100644
--- a/src/layout/IHyprLayout.cpp
+++ b/src/layout/IHyprLayout.cpp
@@ -887,25 +887,26 @@ Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // ge
Vector2D sizeOverride = {};
if (g_pCompositor->m_pLastMonitor) {
for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
- if (r.szRule.starts_with("size")) {
- try {
- const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
- const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
- const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
+ if (r->ruleType != CWindowRule::RULE_SIZE)
+ continue;
- const auto MAXSIZE = pWindow->requestedMaxSize();
+ try {
+ const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
+ const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
+ const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
- const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) :
- stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x);
+ const auto MAXSIZE = pWindow->requestedMaxSize();
- const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.y) :
- stringToPercentage(SIZEYSTR, g_pCompositor->m_pLastMonitor->vecSize.y);
+ const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) :
+ stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x);
- sizeOverride = {SIZEX, SIZEY};
+ const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.y) :
+ stringToPercentage(SIZEYSTR, g_pCompositor->m_pLastMonitor->vecSize.y);
- } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
- break;
- }
+ sizeOverride = {SIZEX, SIZEY};
+
+ } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
+ break;
}
}
@@ -917,10 +918,11 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
if (!shouldBeFloated) {
for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
- if (r.szRule.starts_with("float")) {
- shouldBeFloated = true;
- break;
- }
+ if (r->ruleType != CWindowRule::RULE_FLOAT)
+ continue;
+
+ shouldBeFloated = true;
+ break;
}
}