From 94b90a2cb0b4a0e13018cd5ebbf09394abf3b96b Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:10:25 +0100 Subject: config/lua: add ExpressionVec2, allow using a table for vec2 rules (#14197) --- src/desktop/rule/RuleWithEffects.hpp | 7 +++++ src/desktop/rule/windowRule/WindowRule.cpp | 24 +++++++++++++-- src/desktop/rule/windowRule/WindowRule.hpp | 8 ++++- .../rule/windowRule/WindowRuleApplicator.cpp | 34 ++++++++++++++++------ .../rule/windowRule/WindowRuleApplicator.hpp | 31 ++++++++++---------- src/desktop/view/Window.cpp | 18 +++++++----- src/desktop/view/Window.hpp | 1 + 7 files changed, 88 insertions(+), 35 deletions(-) (limited to 'src/desktop') diff --git a/src/desktop/rule/RuleWithEffects.hpp b/src/desktop/rule/RuleWithEffects.hpp index 17d755e8..17805e9b 100644 --- a/src/desktop/rule/RuleWithEffects.hpp +++ b/src/desktop/rule/RuleWithEffects.hpp @@ -44,6 +44,13 @@ namespace Desktop::Rule { virtual std::expected parseEffect(storageType e, const std::string& result) = 0; + std::expected addParsedEffect(storageType e, valueType value, std::string raw = {}) { + m_effects.emplace_back(TEffect{.key = e, .raw = std::move(raw), .value = std::move(value)}); + m_effectSet.emplace(e); + + return {}; + } + private: std::vector m_effects; std::unordered_set m_effectSet; diff --git a/src/desktop/rule/windowRule/WindowRule.cpp b/src/desktop/rule/windowRule/WindowRule.cpp index c2b520c0..10d39383 100644 --- a/src/desktop/rule/windowRule/WindowRule.cpp +++ b/src/desktop/rule/windowRule/WindowRule.cpp @@ -259,13 +259,19 @@ static std::expected parseWindowRuleEffect(C case WINDOW_RULE_EFFECT_MOVE: case WINDOW_RULE_EFFECT_SIZE: + case WINDOW_RULE_EFFECT_MAX_SIZE: + case WINDOW_RULE_EFFECT_MIN_SIZE: { + auto parsed = Math::parseExpressionVec2(raw); + if (!parsed) + return std::unexpected(std::format("{} rule \"{}\" failed with: {}", EFFECT_NAME, raw, parsed.error())); + return *parsed; + } + case WINDOW_RULE_EFFECT_MONITOR: case WINDOW_RULE_EFFECT_WORKSPACE: case WINDOW_RULE_EFFECT_GROUP: case WINDOW_RULE_EFFECT_ANIMATION: - case WINDOW_RULE_EFFECT_TAG: - case WINDOW_RULE_EFFECT_MAX_SIZE: - case WINDOW_RULE_EFFECT_MIN_SIZE: return std::string{raw}; + case WINDOW_RULE_EFFECT_TAG: return std::string{raw}; case WINDOW_RULE_EFFECT_SUPPRESSEVENT: return parseStringList(raw); @@ -334,6 +340,18 @@ CWindowRule::CWindowRule(const std::string& name) : CRuleWithEffects CWindowRule::addEffect(CWindowRule::storageType e, const Math::SExpressionVec2& expr) { + switch (e) { + case WINDOW_RULE_EFFECT_MOVE: + case WINDOW_RULE_EFFECT_SIZE: + case WINDOW_RULE_EFFECT_MAX_SIZE: + case WINDOW_RULE_EFFECT_MIN_SIZE: break; + default: return std::unexpected(std::format("{} is not an expression vec2 window rule effect", windowEffects()->get(e))); + } + + return addParsedEffect(e, expr, expr.toString()); +} + std::expected CWindowRule::parseEffect(CWindowRule::storageType e, const std::string& result) { return parseWindowRuleEffect(e, result); } diff --git a/src/desktop/rule/windowRule/WindowRule.hpp b/src/desktop/rule/windowRule/WindowRule.hpp index 61fc1520..3701ae35 100644 --- a/src/desktop/rule/windowRule/WindowRule.hpp +++ b/src/desktop/rule/windowRule/WindowRule.hpp @@ -5,6 +5,7 @@ #include "../../types/OverridableVar.hpp" #include "WindowRuleEffectContainer.hpp" #include "../../../config/shared/complex/ComplexDataTypes.hpp" +#include "../../../helpers/math/Expression.hpp" #include "../../../helpers/math/Math.hpp" #include @@ -30,7 +31,8 @@ namespace Desktop::Rule { std::optional inactive; }; - using WindowRuleEffectValue = std::variant, SFullscreenStateRule, SOpacityRule, SBorderColorRule>; + using WindowRuleEffectValue = + std::variant, SFullscreenStateRule, SOpacityRule, SBorderColorRule, Math::SExpressionVec2>; struct SWindowRuleEffect { using storageType = CWindowRuleEffectContainer::storageType; @@ -50,12 +52,16 @@ namespace Desktop::Rule { CWindowRule(const std::string& name = ""); virtual ~CWindowRule() = default; + using Base::addEffect; + CWindowRule(const CWindowRule&) = default; CWindowRule(CWindowRule&) = default; CWindowRule(CWindowRule&&) = default; static std::expected, std::string> buildFromExecString(std::string&&); + std::expected addEffect(storageType e, const Math::SExpressionVec2& expr); + bool matches(PHLWINDOW w, bool allowEnvLookup = false); private: diff --git a/src/desktop/rule/windowRule/WindowRuleApplicator.cpp b/src/desktop/rule/windowRule/WindowRuleApplicator.cpp index b51049e6..c19c6338 100644 --- a/src/desktop/rule/windowRule/WindowRuleApplicator.cpp +++ b/src/desktop/rule/windowRule/WindowRuleApplicator.cpp @@ -168,9 +168,13 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const if (!m_window) break; - const auto VEC = m_window->calculateExpression(effect); + const auto& expr = std::get(value); + if (expr.empty()) + break; + + const auto VEC = m_window->calculateExpression(expr); if (!VEC) { - Log::logger->log(Log::ERR, "failed to parse {} as an expression", effect); + Log::logger->log(Log::ERR, "failed to parse {} as an expression", expr.toString()); break; } if (VEC->x < 1 || VEC->y < 1) { @@ -182,7 +186,7 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const if (*PCLAMP_TILED || m_window->m_isFloating) m_window->clampWindowSize(std::nullopt, m_maxSize.first.value()); - } catch (std::exception& e) { Log::logger->log(Log::ERR, "maxsize rule \"{}\" failed with: {}", effect, e.what()); } + } catch (std::exception& e) { Log::logger->log(Log::ERR, "maxsize rule \"{}\" failed with: {}", std::get(value).toString(), e.what()); } m_maxSize.second = rule->getPropertiesMask(); break; } @@ -193,9 +197,13 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const if (!m_window) break; - const auto VEC = m_window->calculateExpression(effect); + const auto& expr = std::get(value); + if (expr.empty()) + break; + + const auto VEC = m_window->calculateExpression(expr); if (!VEC) { - Log::logger->log(Log::ERR, "failed to parse {} as an expression", effect); + Log::logger->log(Log::ERR, "failed to parse {} as an expression", expr.toString()); break; } @@ -207,7 +215,7 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const m_minSize.first = Types::COverridableVar(*VEC, Types::PRIORITY_WINDOW_RULE); if (*PCLAMP_TILED || m_window->m_isFloating) m_window->clampWindowSize(m_minSize.first.value(), std::nullopt); - } catch (std::exception& e) { Log::logger->log(Log::ERR, "minsize rule \"{}\" failed with: {}", effect, e.what()); } + } catch (std::exception& e) { Log::logger->log(Log::ERR, "minsize rule \"{}\" failed with: {}", std::get(value).toString(), e.what()); } m_minSize.second = rule->getPropertiesMask(); break; } @@ -385,15 +393,23 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyStaticRule(const } case WINDOW_RULE_EFFECT_MOVE: { static_.center = std::nullopt; - static_.position = std::get(value); + const auto& expr = std::get(value); + if (expr.empty()) + static_.position.reset(); + else + static_.position = expr; break; } case WINDOW_RULE_EFFECT_SIZE: { - static_.size = std::get(value); + const auto& expr = std::get(value); + if (expr.empty()) + static_.size.reset(); + else + static_.size = expr; break; } case WINDOW_RULE_EFFECT_CENTER: { - static_.position.clear(); + static_.position.reset(); static_.center = std::get(value); break; } diff --git a/src/desktop/rule/windowRule/WindowRuleApplicator.hpp b/src/desktop/rule/windowRule/WindowRuleApplicator.hpp index 1e52ed5c..f5e43609 100644 --- a/src/desktop/rule/windowRule/WindowRuleApplicator.hpp +++ b/src/desktop/rule/windowRule/WindowRuleApplicator.hpp @@ -8,6 +8,7 @@ #include "../Rule.hpp" #include "../../types/OverridableVar.hpp" #include "../../../helpers/math/Math.hpp" +#include "../../../helpers/math/Expression.hpp" #include "../../../helpers/TagKeeper.hpp" #include "../../../config/shared/complex/ComplexDataTypes.hpp" @@ -38,25 +39,25 @@ namespace Desktop::Rule { // static props struct { - std::string monitor, workspace, group; + std::string monitor, workspace, group; - std::optional floating; - std::optional fullscreen; - std::optional maximize; - std::optional pseudo; - std::optional pin; - std::optional noInitialFocus; - std::optional center; + std::optional floating; + std::optional fullscreen; + std::optional maximize; + std::optional pseudo; + std::optional pin; + std::optional noInitialFocus; + std::optional center; - std::optional fullscreenStateClient; - std::optional fullscreenStateInternal; - std::optional content; - std::optional noCloseFor; + std::optional fullscreenStateClient; + std::optional fullscreenStateInternal; + std::optional content; + std::optional noCloseFor; - std::string size, position; - std::optional scrollingWidth; + std::optional size, position; + std::optional scrollingWidth; - std::vector suppressEvent; + std::vector suppressEvent; } static_; struct SCustomPropContainer { diff --git a/src/desktop/view/Window.cpp b/src/desktop/view/Window.cpp index 53347722..e75c93a5 100644 --- a/src/desktop/view/Window.cpp +++ b/src/desktop/view/Window.cpp @@ -1645,12 +1645,16 @@ std::optional CWindow::calculateSingleExpr(const std::string& s) { } std::optional CWindow::calculateExpression(const std::string& s) { - auto spacePos = s.find(' '); - if (spacePos == std::string::npos) + const auto parsed = Math::parseExpressionVec2(s); + if (!parsed) return std::nullopt; - const auto LHS = calculateSingleExpr(s.substr(0, spacePos)); - const auto RHS = calculateSingleExpr(s.substr(spacePos + 1)); + return calculateExpression(*parsed); +} + +std::optional CWindow::calculateExpression(const Math::SExpressionVec2& expr) { + const auto LHS = calculateSingleExpr(expr.x); + const auto RHS = calculateSingleExpr(expr.y); if (!LHS || !RHS) return std::nullopt; @@ -2011,10 +2015,10 @@ void CWindow::mapWindow() { } else { bool setPseudo = false; - if (!m_ruleApplicator->static_.size.empty()) { - const auto COMPUTED = calculateExpression(m_ruleApplicator->static_.size); + if (m_ruleApplicator->static_.size) { + const auto COMPUTED = calculateExpression(*m_ruleApplicator->static_.size); if (!COMPUTED) - Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.size); + Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.size->toString()); else { setPseudo = true; m_target->setPseudoSize(*COMPUTED); diff --git a/src/desktop/view/Window.hpp b/src/desktop/view/Window.hpp index 35c08326..ff6fad96 100644 --- a/src/desktop/view/Window.hpp +++ b/src/desktop/view/Window.hpp @@ -356,6 +356,7 @@ namespace Desktop::View { SP getSolitaryResource(); Vector2D getReportedSize(); std::optional calculateExpression(const std::string& s); + std::optional calculateExpression(const Math::SExpressionVec2& expr); std::optional minSize(); std::optional maxSize(); SP layoutTarget(); -- cgit v1.2.3