#include "WindowRule.hpp" #include "../../Window.hpp" #include "../../../helpers/Monitor.hpp" #include "../../../Compositor.hpp" #include "../../../managers/TokenManager.hpp" #include "../../../desktop/state/FocusState.hpp" using namespace Desktop; using namespace Desktop::Rule; CWindowRule::CWindowRule(const std::string& name) : IRule(name) { ; } eRuleType CWindowRule::type() { return RULE_TYPE_WINDOW; } void CWindowRule::addEffect(CWindowRule::storageType e, const std::string& result) { m_effects.emplace_back(std::make_pair<>(e, result)); m_effectSet.emplace(e); } const std::vector>& CWindowRule::effects() { return m_effects; } bool CWindowRule::matches(PHLWINDOW w, bool allowEnvLookup) { if (m_matchEngines.empty()) return false; for (const auto& [prop, engine] : m_matchEngines) { switch (prop) { default: { Debug::log(TRACE, "CWindowRule::matches: skipping prop entry {}", sc>(prop)); break; } case RULE_PROP_TITLE: if (!engine->match(w->m_title)) return false; break; case RULE_PROP_INITIAL_TITLE: if (!engine->match(w->m_initialTitle)) return false; break; case RULE_PROP_CLASS: if (!engine->match(w->m_class)) return false; break; case RULE_PROP_INITIAL_CLASS: if (!engine->match(w->m_initialClass)) return false; break; case RULE_PROP_FLOATING: if (!engine->match(w->m_isFloating)) return false; break; case RULE_PROP_TAG: if (!engine->match(w->m_ruleApplicator->m_tagKeeper)) return false; break; case RULE_PROP_XWAYLAND: if (!engine->match(w->m_isX11)) return false; break; case RULE_PROP_FULLSCREEN: if (!engine->match(w->m_fullscreenState.internal != 0)) return false; break; case RULE_PROP_PINNED: if (!engine->match(w->m_pinned)) return false; break; case RULE_PROP_FOCUS: if (!engine->match(Desktop::focusState()->window() == w)) return false; break; case RULE_PROP_GROUP: if (!engine->match(w->m_groupData.pNextWindow)) return false; break; case RULE_PROP_MODAL: if (!engine->match(w->isModal())) return false; break; case RULE_PROP_FULLSCREENSTATE_INTERNAL: if (!engine->match(w->m_fullscreenState.internal)) return false; break; case RULE_PROP_FULLSCREENSTATE_CLIENT: if (!engine->match(w->m_fullscreenState.client)) return false; break; case RULE_PROP_ON_WORKSPACE: if (!engine->match(w->m_workspace)) return false; break; case RULE_PROP_CONTENT: if (!engine->match(NContentType::toString(w->getContentType()))) return false; break; case RULE_PROP_XDG_TAG: if (!w->xdgTag().has_value() || !engine->match(*w->xdgTag())) return false; break; case RULE_PROP_EXEC_TOKEN: // this is only allowed on static rules, we don't need it on dynamic plus it's expensive if (!allowEnvLookup) break; const auto ENV = w->getEnv(); if (ENV.contains(EXEC_RULE_ENV_NAME)) { const auto TKN = ENV.at(EXEC_RULE_ENV_NAME); if (!engine->match(TKN)) return false; break; } return false; } } return true; } SP CWindowRule::buildFromExecString(std::string&& s) { CVarList2 varlist(std::move(s), 0, ';'); SP wr = makeShared("__exec_rule"); for (const auto& el : varlist) { // split element by space, can't do better size_t spacePos = el.find(' '); if (spacePos != std::string::npos) { // great, split and try to parse auto LHS = el.substr(0, spacePos); const auto EFFECT = windowEffects()->get(LHS); if (!EFFECT.has_value() || *EFFECT == WINDOW_RULE_EFFECT_NONE) continue; // invalid... wr->addEffect(*EFFECT, std::string{el.substr(spacePos + 1)}); continue; } // assume 1 maybe... const auto EFFECT = windowEffects()->get(el); if (!EFFECT.has_value() || *EFFECT == WINDOW_RULE_EFFECT_NONE) continue; // invalid... wr->addEffect(*EFFECT, std::string{"1"}); } const auto TOKEN = g_pTokenManager->registerNewToken(nullptr, std::chrono::seconds(1)); wr->markAsExecRule(TOKEN, false /* TODO: could be nice. */); wr->registerMatch(RULE_PROP_EXEC_TOKEN, TOKEN); return wr; } const std::unordered_set& CWindowRule::effectsSet() { return m_effectSet; }