summaryrefslogtreecommitdiff
path: root/src/desktop
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2026-04-28 18:10:25 +0100
committerGitHub <noreply@github.com>2026-04-28 18:10:25 +0100
commit94b90a2cb0b4a0e13018cd5ebbf09394abf3b96b (patch)
tree484d32baaab1acdaab7a817c86aa89f117a21059 /src/desktop
parentab75bbfbecdfb4a0355106f740944c87cb9edd4c (diff)
config/lua: add ExpressionVec2, allow using a table for vec2 rules (#14197)
Diffstat (limited to 'src/desktop')
-rw-r--r--src/desktop/rule/RuleWithEffects.hpp7
-rw-r--r--src/desktop/rule/windowRule/WindowRule.cpp24
-rw-r--r--src/desktop/rule/windowRule/WindowRule.hpp8
-rw-r--r--src/desktop/rule/windowRule/WindowRuleApplicator.cpp34
-rw-r--r--src/desktop/rule/windowRule/WindowRuleApplicator.hpp31
-rw-r--r--src/desktop/view/Window.cpp18
-rw-r--r--src/desktop/view/Window.hpp1
7 files changed, 88 insertions, 35 deletions
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<valueType, std::string> parseEffect(storageType e, const std::string& result) = 0;
+ std::expected<void, std::string> 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<TEffect> m_effects;
std::unordered_set<storageType> 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<WindowRuleEffectValue, std::string> 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<SWindowRule
;
}
+std::expected<void, std::string> 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<WindowRuleEffectValue, std::string> 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 <expected>
@@ -30,7 +31,8 @@ namespace Desktop::Rule {
std::optional<Config::CGradientValueData> inactive;
};
- using WindowRuleEffectValue = std::variant<std::monostate, bool, int64_t, float, std::string, std::vector<std::string>, SFullscreenStateRule, SOpacityRule, SBorderColorRule>;
+ using WindowRuleEffectValue =
+ std::variant<std::monostate, bool, int64_t, float, std::string, std::vector<std::string>, 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<SP<CWindowRule>, std::string> buildFromExecString(std::string&&);
+ std::expected<void, std::string> 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<Math::SExpressionVec2>(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<Math::SExpressionVec2>(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<Math::SExpressionVec2>(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<Math::SExpressionVec2>(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<std::string>(value);
+ const auto& expr = std::get<Math::SExpressionVec2>(value);
+ if (expr.empty())
+ static_.position.reset();
+ else
+ static_.position = expr;
break;
}
case WINDOW_RULE_EFFECT_SIZE: {
- static_.size = std::get<std::string>(value);
+ const auto& expr = std::get<Math::SExpressionVec2>(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<bool>(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<bool> floating;
- std::optional<bool> fullscreen;
- std::optional<bool> maximize;
- std::optional<bool> pseudo;
- std::optional<bool> pin;
- std::optional<bool> noInitialFocus;
- std::optional<bool> center;
+ std::optional<bool> floating;
+ std::optional<bool> fullscreen;
+ std::optional<bool> maximize;
+ std::optional<bool> pseudo;
+ std::optional<bool> pin;
+ std::optional<bool> noInitialFocus;
+ std::optional<bool> center;
- std::optional<int> fullscreenStateClient;
- std::optional<int> fullscreenStateInternal;
- std::optional<int> content;
- std::optional<int> noCloseFor;
+ std::optional<int> fullscreenStateClient;
+ std::optional<int> fullscreenStateInternal;
+ std::optional<int> content;
+ std::optional<int> noCloseFor;
- std::string size, position;
- std::optional<float> scrollingWidth;
+ std::optional<Math::SExpressionVec2> size, position;
+ std::optional<float> scrollingWidth;
- std::vector<std::string> suppressEvent;
+ std::vector<std::string> 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<double> CWindow::calculateSingleExpr(const std::string& s) {
}
std::optional<Vector2D> 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<Vector2D> 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<CWLSurfaceResource> getSolitaryResource();
Vector2D getReportedSize();
std::optional<Vector2D> calculateExpression(const std::string& s);
+ std::optional<Vector2D> calculateExpression(const Math::SExpressionVec2& expr);
std::optional<Vector2D> minSize();
std::optional<Vector2D> maxSize();
SP<Layout::ITarget> layoutTarget();