From dab50b3ef3a1bad7f68320538223b6b41d1c6012 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:05:24 +0100 Subject: core: Optimize window/layer rule application and scanning (#8735) Optimizes window and layer rule parsing and later usage. --- src/config/ConfigManager.cpp | 275 +++++++++++-------------- src/config/ConfigManager.hpp | 10 +- src/desktop/LayerRule.cpp | 37 ++++ src/desktop/LayerRule.hpp | 28 +++ src/desktop/LayerSurface.cpp | 82 +++++--- src/desktop/LayerSurface.hpp | 6 +- src/desktop/Window.cpp | 307 ++++++++++++++------------- src/desktop/Window.hpp | 25 +-- src/desktop/WindowRule.cpp | 100 +++++++++ src/desktop/WindowRule.hpp | 65 ++++++ src/events/Windows.cpp | 480 +++++++++++++++++++++++-------------------- src/layout/IHyprLayout.cpp | 38 ++-- 12 files changed, 855 insertions(+), 598 deletions(-) create mode 100644 src/desktop/LayerRule.cpp create mode 100644 src/desktop/LayerRule.hpp create mode 100644 src/desktop/WindowRule.cpp create mode 100644 src/desktop/WindowRule.hpp 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 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 CConfigManager::getMatchingRules(PHLWINDOW pWindow, bool dynamic, bool shadowExec) { +std::vector> CConfigManager::getMatchingRules(PHLWINDOW pWindow, bool dynamic, bool shadowExec) { if (!valid(pWindow)) - return std::vector(); + return std::vector>(); // if the window is unmapped, don't process exec rules yet. shadowExec = shadowExec || !pWindow->m_bIsMapped; - std::vector returns; + std::vector> 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 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 internalMode, clientMode; @@ -1358,46 +1324,77 @@ std::vector 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 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 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(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 CConfigManager::getMatchingRules(PHLLS pLS) { - std::vector returns; +std::vector> CConfigManager::getMatchingRules(PHLLS pLS) { + std::vector> 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(pLS->layerSurface->layerNamespace, "blur")); return returns; } @@ -2306,29 +2302,6 @@ std::optional CConfigManager::handleUnbind(const std::string& comma return {}; } -bool windowRuleValid(const std::string& RULE) { - static const auto rules = std::unordered_set{ - "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", - }; - static const auto rulesPrefix = std::vector{ - "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{"noanim", "blur", "blurpopups", "dimaround"}; - static const auto rulesPrefix = std::vector{"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 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 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(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 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(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 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(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 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& getAllWorkspaceRules(); - std::vector getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); - std::vector getMatchingRules(PHLLS); + std::vector> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); + std::vector> getMatchingRules(PHLLS); const std::vector& getAllDescriptions(); @@ -291,8 +291,8 @@ class CConfigManager { std::vector m_vMonitorRules; std::vector m_vWorkspaceRules; - std::vector m_vWindowRules; - std::vector m_vLayerRules; + std::vector> m_vWindowRules; + std::vector> m_vLayerRules; std::vector 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 +#include +#include "../debug/Log.hpp" + +static const auto RULES = std::unordered_set{"noanim", "blur", "blurpopups", "dimaround"}; +static const auto RULES_PREFIX = std::unordered_set{"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 +#include + +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& 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 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 m_vMatchedRules; + std::vector> 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& 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 +#include +#include "../config/ConfigManager.hpp" + +static const auto RULES = std::unordered_set{ + "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", +}; +static const auto RULES_PREFIX = std::unordered_set{ + "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(&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 +#include + +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; } } -- cgit v1.2.3