mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 13:18:04 +02:00
desktop/windowRule: use variants for storage internally
Improves storage: less dynamic parsing, immediate config errors, faster.
This commit is contained in:
parent
98fbbafef7
commit
cbefb357a5
8 changed files with 482 additions and 229 deletions
|
|
@ -895,8 +895,11 @@ std::optional<std::string> CConfigManager::addRuleFromConfigKey(const std::strin
|
|||
|
||||
for (const auto& e : Desktop::Rule::windowEffects()->allEffectStrings()) {
|
||||
auto VAL = m_config->getSpecialConfigValuePtr("windowrule", e.c_str(), name.c_str());
|
||||
if (VAL && VAL->m_bSetByUser)
|
||||
rule->addEffect(Desktop::Rule::windowEffects()->get(e).value_or(Desktop::Rule::WINDOW_RULE_EFFECT_NONE), std::any_cast<Hyprlang::STRING>(VAL->getValue()));
|
||||
if (VAL && VAL->m_bSetByUser) {
|
||||
auto res = rule->addEffect(Desktop::Rule::windowEffects()->get(e).value_or(Desktop::Rule::WINDOW_RULE_EFFECT_NONE), std::any_cast<Hyprlang::STRING>(VAL->getValue()));
|
||||
if (!res)
|
||||
return res.error();
|
||||
}
|
||||
}
|
||||
|
||||
Desktop::Rule::ruleEngine()->registerRule(std::move(rule));
|
||||
|
|
@ -1981,7 +1984,9 @@ std::optional<std::string> CConfigManager::handleWindowrule(const std::string& c
|
|||
const auto EFFECT = Desktop::Rule::windowEffects()->get(FIRST);
|
||||
if (!EFFECT.has_value())
|
||||
return std::format("invalid effect {}", el);
|
||||
rule->addEffect(*EFFECT, std::string{el.substr(spacePos + 1)});
|
||||
auto res = rule->addEffect(*EFFECT, std::string{el.substr(spacePos + 1)});
|
||||
if (!res)
|
||||
return res.error();
|
||||
} else
|
||||
return std::format("invalid field type {}", FIRST);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1066,8 +1066,11 @@ static int hlWindowRule(lua_State* L) {
|
|||
auto val = Internal::ruleValueToString(L);
|
||||
if (!val)
|
||||
self->addError(std::format("{}: hl.window_rule: field '{}': {}", sourceInfo, key, val.error()));
|
||||
else
|
||||
rule->addEffect(*dynamicEffect, *val);
|
||||
else {
|
||||
auto res = rule->addEffect(*dynamicEffect, *val);
|
||||
if (!res)
|
||||
self->addError(std::format("{}: hl.window_rule: field '{}': {}", sourceInfo, key, res.error()));
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
|
|
@ -1077,12 +1080,17 @@ static int hlWindowRule(lua_State* L) {
|
|||
auto err = val->parse(L);
|
||||
if (err.errorCode != PARSE_ERROR_OK) {
|
||||
const bool allowLegacyString = (key == "max_size" || key == "min_size" || key == "border_color") && lua_isstring(L, -1);
|
||||
if (allowLegacyString)
|
||||
rule->addEffect(desc->effect, lua_tostring(L, -1));
|
||||
else
|
||||
if (allowLegacyString) {
|
||||
auto res = rule->addEffect(desc->effect, lua_tostring(L, -1));
|
||||
if (!res)
|
||||
self->addError(std::format("{}: hl.window_rule: field '{}': {}", sourceInfo, key, res.error()));
|
||||
} else
|
||||
self->addError(std::format("{}: hl.window_rule: field '{}': {}", sourceInfo, key, err.message));
|
||||
} else
|
||||
rule->addEffect(desc->effect, val->toString());
|
||||
} else {
|
||||
auto res = rule->addEffect(desc->effect, val->toString());
|
||||
if (!res)
|
||||
self->addError(std::format("{}: hl.window_rule: field '{}': {}", sourceInfo, key, res.error()));
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -527,7 +527,11 @@ std::expected<SP<Desktop::Rule::CWindowRule>, int> Internal::buildRuleFromTable(
|
|||
return std::unexpected(Internal::configError(L, "buildRuleFromTable: effect '{}': {}", key, val.error()));
|
||||
}
|
||||
|
||||
rule->addEffect(*dynamicEffect, *val);
|
||||
auto res = rule->addEffect(*dynamicEffect, *val);
|
||||
if (!res) {
|
||||
lua_pop(L, 1);
|
||||
return std::unexpected(Internal::configError(L, "buildRuleFromTable: effect '{}': {}", key, res.error()));
|
||||
}
|
||||
hasRuleEffects = true;
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
|
@ -538,14 +542,23 @@ std::expected<SP<Desktop::Rule::CWindowRule>, int> Internal::buildRuleFromTable(
|
|||
auto err = val->parse(L);
|
||||
if (err.errorCode != PARSE_ERROR_OK) {
|
||||
const bool allowLegacyString = (key == "max_size" || key == "min_size" || key == "border_color") && lua_isstring(L, -1);
|
||||
if (allowLegacyString)
|
||||
rule->addEffect(desc->effect, lua_tostring(L, -1));
|
||||
else {
|
||||
if (allowLegacyString) {
|
||||
auto res = rule->addEffect(desc->effect, lua_tostring(L, -1));
|
||||
if (!res) {
|
||||
lua_pop(L, 1);
|
||||
return std::unexpected(Internal::configError(L, "buildRuleFromTable: effect '{}': {}", key, res.error()));
|
||||
}
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
return std::unexpected(Internal::configError(L, "buildRuleFromTable: effect '{}': {}", key, err.message));
|
||||
}
|
||||
} else
|
||||
rule->addEffect(desc->effect, val->toString());
|
||||
} else {
|
||||
auto res = rule->addEffect(desc->effect, val->toString());
|
||||
if (!res) {
|
||||
lua_pop(L, 1);
|
||||
return std::unexpected(Internal::configError(L, "buildRuleFromTable: effect '{}': {}", key, res.error()));
|
||||
}
|
||||
}
|
||||
|
||||
hasRuleEffects = true;
|
||||
lua_pop(L, 1);
|
||||
|
|
|
|||
|
|
@ -123,7 +123,11 @@ std::optional<uint64_t> CExecutor::spawnWithRules(std::string args, PHLWORKSPACE
|
|||
std::string execToken = "";
|
||||
|
||||
if (!RULES.empty()) {
|
||||
auto rule = Desktop::Rule::CWindowRule::buildFromExecString(std::move(RULES));
|
||||
auto rule = Desktop::Rule::CWindowRule::buildFromExecString(std::move(RULES));
|
||||
if (!rule) {
|
||||
Log::logger->log(Log::ERR, "Failed to parse exec rule: {}", rule.error());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto TOKEN = g_pTokenManager->registerNewToken(nullptr, std::chrono::seconds(1));
|
||||
|
||||
|
|
@ -132,7 +136,7 @@ std::optional<uint64_t> CExecutor::spawnWithRules(std::string args, PHLWORKSPACE
|
|||
if (!PROC)
|
||||
return std::nullopt;
|
||||
|
||||
applyRuleToProc(rule, *PROC, TOKEN);
|
||||
applyRuleToProc(*rule, *PROC, TOKEN);
|
||||
|
||||
return PROC;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,298 @@
|
|||
#include "WindowRule.hpp"
|
||||
#include "../../view/Window.hpp"
|
||||
#include "../../../helpers/Monitor.hpp"
|
||||
#include "../../../helpers/MiscFunctions.hpp"
|
||||
#include "../../../Compositor.hpp"
|
||||
#include "../../../managers/TokenManager.hpp"
|
||||
#include "../../../desktop/state/FocusState.hpp"
|
||||
#include "../../../protocols/types/ContentType.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
#include <hyprutils/string/VarList2.hpp>
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::Rule;
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
static std::expected<int64_t, std::string> parseInt(std::string_view effectName, const std::string& raw) {
|
||||
try {
|
||||
return std::stoll(raw);
|
||||
} catch (std::exception& e) { return std::unexpected(std::format("{} rule \"{}\" failed with: {}", effectName, raw, e.what())); }
|
||||
}
|
||||
|
||||
static std::expected<float, std::string> parseFloat(std::string_view effectName, const std::string& raw) {
|
||||
try {
|
||||
return std::stof(raw);
|
||||
} catch (std::exception& e) { return std::unexpected(std::format("{} rule \"{}\" failed with: {}", effectName, raw, e.what())); }
|
||||
}
|
||||
|
||||
static std::expected<CHyprColor, std::string> parseBorderColorToken(const std::string& raw, const std::string& token) {
|
||||
auto parsed = configStringToInt(token);
|
||||
if (!parsed)
|
||||
return std::unexpected(std::format(R"(border_color rule "{}" has invalid color "{}": {})", raw, token, parsed.error()));
|
||||
|
||||
return CHyprColor(*parsed);
|
||||
}
|
||||
|
||||
static std::expected<SFullscreenStateRule, std::string> parseFullscreenState(const std::string& raw) {
|
||||
CVarList2 vars(std::string{raw}, 0, 's');
|
||||
|
||||
try {
|
||||
SFullscreenStateRule result;
|
||||
result.internal = std::stoi(std::string{vars[0]});
|
||||
if (!vars[1].empty())
|
||||
result.client = std::stoi(std::string{vars[1]});
|
||||
return result;
|
||||
} catch (std::exception& e) { return std::unexpected(std::format("fullscreen_state rule \"{}\" failed with: {}", raw, e.what())); }
|
||||
}
|
||||
|
||||
static std::expected<int64_t, std::string> parseIdleInhibitMode(const std::string& raw) {
|
||||
if (raw == "none")
|
||||
return IDLEINHIBIT_NONE;
|
||||
if (raw == "always")
|
||||
return IDLEINHIBIT_ALWAYS;
|
||||
if (raw == "focus")
|
||||
return IDLEINHIBIT_FOCUS;
|
||||
if (raw == "fullscreen")
|
||||
return IDLEINHIBIT_FULLSCREEN;
|
||||
|
||||
return std::unexpected(std::format("idle_inhibit rule has unknown mode \"{}\"", raw));
|
||||
}
|
||||
|
||||
static std::expected<SOpacityRule, std::string> parseOpacityRule(const std::string& raw) {
|
||||
try {
|
||||
CVarList2 vars(std::string{raw}, 0, ' ');
|
||||
|
||||
int opacityIDX = 0;
|
||||
SOpacityRule result;
|
||||
|
||||
for (const auto& r : vars) {
|
||||
if (r == "opacity")
|
||||
continue;
|
||||
|
||||
if (r == "override") {
|
||||
if (opacityIDX == 1)
|
||||
result.alpha.overridden = true;
|
||||
else if (opacityIDX == 2)
|
||||
result.alphaInactive.overridden = true;
|
||||
else if (opacityIDX == 3)
|
||||
result.alphaFullscreen.overridden = true;
|
||||
} else {
|
||||
if (opacityIDX == 0)
|
||||
result.alpha.alpha = std::stof(std::string{r});
|
||||
else if (opacityIDX == 1)
|
||||
result.alphaInactive.alpha = std::stof(std::string{r});
|
||||
else if (opacityIDX == 2)
|
||||
result.alphaFullscreen.alpha = std::stof(std::string{r});
|
||||
else
|
||||
throw std::runtime_error("more than 3 alpha values");
|
||||
|
||||
opacityIDX++;
|
||||
}
|
||||
}
|
||||
|
||||
if (opacityIDX == 1) {
|
||||
result.alphaInactive = result.alpha;
|
||||
result.alphaFullscreen = result.alpha;
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (std::exception& e) { return std::unexpected(std::format("opacity rule \"{}\" failed with: {}", raw, e.what())); }
|
||||
}
|
||||
|
||||
static std::expected<SBorderColorRule, std::string> parseBorderColorRule(const std::string& raw) {
|
||||
try {
|
||||
Config::CGradientValueData activeBorderGradient = {};
|
||||
Config::CGradientValueData inactiveBorderGradient = {};
|
||||
bool active = true;
|
||||
CVarList colorsAndAngles = CVarList(trim(raw), 0, 's', true);
|
||||
|
||||
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
|
||||
auto activeColor = parseBorderColorToken(raw, colorsAndAngles[0]);
|
||||
if (!activeColor)
|
||||
return std::unexpected(activeColor.error());
|
||||
|
||||
auto inactiveColor = parseBorderColorToken(raw, colorsAndAngles[1]);
|
||||
if (!inactiveColor)
|
||||
return std::unexpected(inactiveColor.error());
|
||||
|
||||
return SBorderColorRule{
|
||||
.active = Config::CGradientValueData(*activeColor),
|
||||
.inactive = Config::CGradientValueData(*inactiveColor),
|
||||
};
|
||||
}
|
||||
|
||||
for (auto const& token : colorsAndAngles) {
|
||||
if (active && token.contains("deg")) {
|
||||
activeBorderGradient.m_angle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
active = false;
|
||||
} else if (token.contains("deg"))
|
||||
inactiveBorderGradient.m_angle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
else {
|
||||
auto color = parseBorderColorToken(raw, token);
|
||||
if (!color)
|
||||
return std::unexpected(color.error());
|
||||
|
||||
if (active)
|
||||
activeBorderGradient.m_colors.emplace_back(*color);
|
||||
else
|
||||
inactiveBorderGradient.m_colors.emplace_back(*color);
|
||||
}
|
||||
}
|
||||
|
||||
activeBorderGradient.updateColorsOk();
|
||||
|
||||
if (activeBorderGradient.m_colors.size() > 10 || inactiveBorderGradient.m_colors.size() > 10)
|
||||
return std::unexpected(std::format("border_color rule \"{}\" has more than 10 colors in one gradient", raw));
|
||||
if (activeBorderGradient.m_colors.empty())
|
||||
return std::unexpected(std::format("border_color rule \"{}\" has no colors", raw));
|
||||
|
||||
SBorderColorRule result{.active = activeBorderGradient};
|
||||
if (!inactiveBorderGradient.m_colors.empty())
|
||||
result.inactive = inactiveBorderGradient;
|
||||
|
||||
return result;
|
||||
} catch (std::exception& e) { return std::unexpected(std::format("border_color rule \"{}\" failed with: {}", raw, e.what())); }
|
||||
}
|
||||
|
||||
static std::vector<std::string> parseStringList(const std::string& raw) {
|
||||
std::vector<std::string> result;
|
||||
CVarList2 varlist(std::string{raw}, 0, 's');
|
||||
|
||||
for (const auto& e : varlist) {
|
||||
result.emplace_back(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::expected<WindowRuleEffectValue, std::string> parseWindowRuleEffect(CWindowRuleEffectContainer::storageType e, const std::string& raw) {
|
||||
if (windowEffects()->isEffectDynamic(e))
|
||||
return std::string{raw};
|
||||
|
||||
const auto EFFECT_NAME = windowEffects()->get(e);
|
||||
|
||||
switch (e) {
|
||||
default: return std::unexpected(std::format("unknown window rule effect {}", e));
|
||||
|
||||
case WINDOW_RULE_EFFECT_NONE: return std::monostate{};
|
||||
|
||||
case WINDOW_RULE_EFFECT_FLOAT:
|
||||
case WINDOW_RULE_EFFECT_TILE:
|
||||
case WINDOW_RULE_EFFECT_FULLSCREEN:
|
||||
case WINDOW_RULE_EFFECT_MAXIMIZE:
|
||||
case WINDOW_RULE_EFFECT_CENTER:
|
||||
case WINDOW_RULE_EFFECT_PSEUDO:
|
||||
case WINDOW_RULE_EFFECT_NOINITIALFOCUS:
|
||||
case WINDOW_RULE_EFFECT_PIN:
|
||||
case WINDOW_RULE_EFFECT_PERSISTENT_SIZE:
|
||||
case WINDOW_RULE_EFFECT_ALLOWS_INPUT:
|
||||
case WINDOW_RULE_EFFECT_DIM_AROUND:
|
||||
case WINDOW_RULE_EFFECT_DECORATE:
|
||||
case WINDOW_RULE_EFFECT_FOCUS_ON_ACTIVATE:
|
||||
case WINDOW_RULE_EFFECT_KEEP_ASPECT_RATIO:
|
||||
case WINDOW_RULE_EFFECT_NEAREST_NEIGHBOR:
|
||||
case WINDOW_RULE_EFFECT_NO_ANIM:
|
||||
case WINDOW_RULE_EFFECT_NO_BLUR:
|
||||
case WINDOW_RULE_EFFECT_NO_DIM:
|
||||
case WINDOW_RULE_EFFECT_NO_FOCUS:
|
||||
case WINDOW_RULE_EFFECT_NO_FOLLOW_MOUSE:
|
||||
case WINDOW_RULE_EFFECT_NO_MAX_SIZE:
|
||||
case WINDOW_RULE_EFFECT_NO_SHADOW:
|
||||
case WINDOW_RULE_EFFECT_NO_SHORTCUTS_INHIBIT:
|
||||
case WINDOW_RULE_EFFECT_OPAQUE:
|
||||
case WINDOW_RULE_EFFECT_FORCE_RGBX:
|
||||
case WINDOW_RULE_EFFECT_SYNC_FULLSCREEN:
|
||||
case WINDOW_RULE_EFFECT_IMMEDIATE:
|
||||
case WINDOW_RULE_EFFECT_XRAY:
|
||||
case WINDOW_RULE_EFFECT_RENDER_UNFOCUSED:
|
||||
case WINDOW_RULE_EFFECT_NO_SCREEN_SHARE:
|
||||
case WINDOW_RULE_EFFECT_NO_VRR:
|
||||
case WINDOW_RULE_EFFECT_STAY_FOCUSED: return truthy(raw);
|
||||
|
||||
case WINDOW_RULE_EFFECT_FULLSCREENSTATE: {
|
||||
auto parsed = parseFullscreenState(raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return *parsed;
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_MOVE:
|
||||
case WINDOW_RULE_EFFECT_SIZE:
|
||||
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_SUPPRESSEVENT: return parseStringList(raw);
|
||||
|
||||
case WINDOW_RULE_EFFECT_CONTENT: return sc<int64_t>(NContentType::fromString(raw));
|
||||
|
||||
case WINDOW_RULE_EFFECT_NOCLOSEFOR:
|
||||
case WINDOW_RULE_EFFECT_BORDER_SIZE: {
|
||||
auto parsed = parseInt(EFFECT_NAME, raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return *parsed;
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_ROUNDING: {
|
||||
auto parsed = parseInt(EFFECT_NAME, raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
if (*parsed < 0)
|
||||
return std::unexpected(std::format("{} rule \"{}\" must be non-negative", EFFECT_NAME, raw));
|
||||
return *parsed;
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_SCROLLING_WIDTH: {
|
||||
auto parsed = parseFloat(EFFECT_NAME, raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return *parsed;
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_ROUNDING_POWER: {
|
||||
auto parsed = parseFloat(EFFECT_NAME, raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return std::clamp(*parsed, 1.F, 10.F);
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SCROLL_MOUSE:
|
||||
case WINDOW_RULE_EFFECT_SCROLL_TOUCHPAD: {
|
||||
auto parsed = parseFloat(EFFECT_NAME, raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return std::clamp(*parsed, 0.01F, 10.F);
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_BORDER_COLOR: {
|
||||
auto parsed = parseBorderColorRule(raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return *parsed;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_IDLE_INHIBIT: {
|
||||
auto parsed = parseIdleInhibitMode(raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return *parsed;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_OPACITY: {
|
||||
auto parsed = parseOpacityRule(raw);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
return *parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CWindowRule::CWindowRule(const std::string& name) : IRule(name) {
|
||||
;
|
||||
}
|
||||
|
|
@ -19,12 +301,18 @@ 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));
|
||||
std::expected<void, std::string> CWindowRule::addEffect(CWindowRule::storageType e, const std::string& result) {
|
||||
auto parsed = parseWindowRuleEffect(e, result);
|
||||
if (!parsed)
|
||||
return std::unexpected(parsed.error());
|
||||
|
||||
m_effects.emplace_back(SWindowRuleEffect{.key = e, .raw = result, .value = std::move(*parsed)});
|
||||
m_effectSet.emplace(e);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::vector<std::pair<CWindowRule::storageType, std::string>>& CWindowRule::effects() {
|
||||
const std::vector<SWindowRuleEffect>& CWindowRule::effects() {
|
||||
return m_effects;
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +419,7 @@ bool CWindowRule::matches(PHLWINDOW w, bool allowEnvLookup) {
|
|||
return true;
|
||||
}
|
||||
|
||||
SP<CWindowRule> CWindowRule::buildFromExecString(std::string&& s) {
|
||||
std::expected<SP<CWindowRule>, std::string> CWindowRule::buildFromExecString(std::string&& s) {
|
||||
CVarList2 varlist(std::move(s), 0, ';');
|
||||
SP<CWindowRule> wr = makeShared<CWindowRule>("__exec_rule");
|
||||
|
||||
|
|
@ -146,7 +434,9 @@ SP<CWindowRule> CWindowRule::buildFromExecString(std::string&& s) {
|
|||
if (!EFFECT.has_value() || *EFFECT == WINDOW_RULE_EFFECT_NONE)
|
||||
continue; // invalid...
|
||||
|
||||
wr->addEffect(*EFFECT, std::string{el.substr(spacePos + 1)});
|
||||
auto res = wr->addEffect(*EFFECT, std::string{el.substr(spacePos + 1)});
|
||||
if (!res)
|
||||
return std::unexpected(res.error());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +447,9 @@ SP<CWindowRule> CWindowRule::buildFromExecString(std::string&& s) {
|
|||
if (!EFFECT.has_value() || *EFFECT == WINDOW_RULE_EFFECT_NONE)
|
||||
continue; // invalid...
|
||||
|
||||
wr->addEffect(*EFFECT, std::string{"1"});
|
||||
auto res = wr->addEffect(*EFFECT, std::string{"1"});
|
||||
if (!res)
|
||||
return std::unexpected(res.error());
|
||||
}
|
||||
|
||||
return wr;
|
||||
|
|
|
|||
|
|
@ -2,14 +2,42 @@
|
|||
|
||||
#include "../Rule.hpp"
|
||||
#include "../../DesktopTypes.hpp"
|
||||
#include "../../types/OverridableVar.hpp"
|
||||
#include "WindowRuleEffectContainer.hpp"
|
||||
#include "../../../config/shared/complex/ComplexDataTypes.hpp"
|
||||
#include "../../../helpers/math/Math.hpp"
|
||||
|
||||
#include <expected>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
|
||||
namespace Desktop::Rule {
|
||||
constexpr const char* EXEC_RULE_ENV_NAME = "HL_EXEC_RULE_TOKEN";
|
||||
|
||||
struct SFullscreenStateRule {
|
||||
int internal = 0;
|
||||
std::optional<int> client;
|
||||
};
|
||||
|
||||
struct SOpacityRule {
|
||||
Types::SAlphaValue alpha;
|
||||
Types::SAlphaValue alphaInactive;
|
||||
Types::SAlphaValue alphaFullscreen;
|
||||
};
|
||||
|
||||
struct SBorderColorRule {
|
||||
Config::CGradientValueData active;
|
||||
std::optional<Config::CGradientValueData> inactive;
|
||||
};
|
||||
|
||||
using WindowRuleEffectValue = std::variant<std::monostate, bool, int64_t, float, std::string, std::vector<std::string>, SFullscreenStateRule, SOpacityRule, SBorderColorRule>;
|
||||
|
||||
struct SWindowRuleEffect {
|
||||
CWindowRuleEffectContainer::storageType key = WINDOW_RULE_EFFECT_NONE;
|
||||
std::string raw;
|
||||
WindowRuleEffectValue value;
|
||||
};
|
||||
|
||||
class CWindowRule : public IRule {
|
||||
private:
|
||||
using storageType = CWindowRuleEffectContainer::storageType;
|
||||
|
|
@ -22,22 +50,22 @@ namespace Desktop::Rule {
|
|||
CWindowRule(CWindowRule&) = default;
|
||||
CWindowRule(CWindowRule&&) = default;
|
||||
|
||||
static SP<CWindowRule> buildFromExecString(std::string&&);
|
||||
static std::expected<SP<CWindowRule>, std::string> buildFromExecString(std::string&&);
|
||||
|
||||
virtual eRuleType type();
|
||||
virtual eRuleType type();
|
||||
|
||||
void addEffect(storageType e, const std::string& result);
|
||||
const std::vector<std::pair<storageType, std::string>>& effects();
|
||||
const std::unordered_set<storageType>& effectsSet();
|
||||
std::expected<void, std::string> addEffect(storageType e, const std::string& result);
|
||||
const std::vector<SWindowRuleEffect>& effects();
|
||||
const std::unordered_set<storageType>& effectsSet();
|
||||
|
||||
void setEnabled(bool enable);
|
||||
bool isEnabled() const;
|
||||
void setEnabled(bool enable);
|
||||
bool isEnabled() const;
|
||||
|
||||
bool matches(PHLWINDOW w, bool allowEnvLookup = false);
|
||||
bool matches(PHLWINDOW w, bool allowEnvLookup = false);
|
||||
|
||||
private:
|
||||
std::vector<std::pair<storageType, std::string>> m_effects;
|
||||
std::unordered_set<storageType> m_effectSet;
|
||||
bool m_enabled = true;
|
||||
std::vector<SWindowRuleEffect> m_effects;
|
||||
std::unordered_set<storageType> m_effectSet;
|
||||
bool m_enabled = true;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,33 +6,26 @@
|
|||
#include "../../types/OverridableVar.hpp"
|
||||
#include "../../../event/EventBus.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
#include <hyprutils/string/VarList2.hpp>
|
||||
#include <tuple>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::Rule;
|
||||
|
||||
namespace {
|
||||
template <typename T, typename TEffect>
|
||||
void resetRuleProp(std::pair<Desktop::Types::COverridableVar<T>, std::underlying_type_t<Desktop::Rule::eRuleProperty>>& prop,
|
||||
std::underlying_type_t<Desktop::Rule::eRuleProperty> props, Desktop::Types::eOverridePriority prio,
|
||||
std::unordered_set<Desktop::Rule::CWindowRuleEffectContainer::storageType>& effectsNuked, TEffect&& effect) {
|
||||
auto& [value, propMask] = prop;
|
||||
template <typename T, typename TEffect>
|
||||
static void resetRuleProp(std::pair<Desktop::Types::COverridableVar<T>, std::underlying_type_t<Desktop::Rule::eRuleProperty>>& prop,
|
||||
std::underlying_type_t<Desktop::Rule::eRuleProperty> props, Desktop::Types::eOverridePriority prio,
|
||||
std::unordered_set<Desktop::Rule::CWindowRuleEffectContainer::storageType>& effectsNuked, TEffect&& effect) {
|
||||
auto& [value, propMask] = prop;
|
||||
|
||||
if (!(propMask & props))
|
||||
return;
|
||||
if (!(propMask & props))
|
||||
return;
|
||||
|
||||
if (prio == Desktop::Types::PRIORITY_WINDOW_RULE) {
|
||||
effectsNuked.emplace(effect());
|
||||
propMask &= ~props;
|
||||
}
|
||||
|
||||
value.unset(prio);
|
||||
if (prio == Desktop::Types::PRIORITY_WINDOW_RULE) {
|
||||
effectsNuked.emplace(effect());
|
||||
propMask &= ~props;
|
||||
}
|
||||
|
||||
value.unset(prio);
|
||||
}
|
||||
|
||||
CWindowRuleApplicator::CWindowRuleApplicator(PHLWINDOW w) : m_window(w) {
|
||||
|
|
@ -85,7 +78,11 @@ std::unordered_set<CWindowRuleEffectContainer::storageType> CWindowRuleApplicato
|
|||
CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const SP<CWindowRule>& rule) {
|
||||
SRuleResult result;
|
||||
|
||||
for (const auto& [key, effect] : rule->effects()) {
|
||||
for (const auto& effectData : rule->effects()) {
|
||||
const auto key = effectData.key;
|
||||
const auto& effect = effectData.raw;
|
||||
const auto& value = effectData.value;
|
||||
|
||||
switch (key) {
|
||||
default: {
|
||||
if (key <= WINDOW_RULE_EFFECT_LAST_STATIC) {
|
||||
|
|
@ -115,133 +112,44 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const
|
|||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ROUNDING: {
|
||||
try {
|
||||
m_rounding.first.set(std::stoull(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_rounding.second |= rule->getPropertiesMask();
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyDynamicRule: invalid rounding {}", effect); }
|
||||
m_rounding.first.set(std::get<int64_t>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_rounding.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ROUNDING_POWER: {
|
||||
try {
|
||||
m_roundingPower.first.set(std::clamp(std::stof(effect), 1.F, 10.F), Types::PRIORITY_WINDOW_RULE);
|
||||
m_roundingPower.second |= rule->getPropertiesMask();
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyDynamicRule: invalid rounding_power {}", effect); }
|
||||
m_roundingPower.first.set(std::get<float>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_roundingPower.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_PERSISTENT_SIZE: {
|
||||
m_persistentSize.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_persistentSize.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_persistentSize.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ANIMATION: {
|
||||
m_animationStyle.first.set(effect, Types::PRIORITY_WINDOW_RULE);
|
||||
m_animationStyle.first.set(std::get<std::string>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_animationStyle.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_BORDER_COLOR: {
|
||||
try {
|
||||
// Each vector will only get used if it has at least one color
|
||||
Config::CGradientValueData activeBorderGradient = {};
|
||||
Config::CGradientValueData inactiveBorderGradient = {};
|
||||
bool active = true;
|
||||
CVarList colorsAndAngles = CVarList(trim(effect), 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_activeBorderColor.first =
|
||||
Types::COverridableVar(Config::CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), Types::PRIORITY_WINDOW_RULE);
|
||||
m_inactiveBorderColor.first =
|
||||
Types::COverridableVar(Config::CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), Types::PRIORITY_WINDOW_RULE);
|
||||
m_activeBorderColor.second |= rule->getPropertiesMask();
|
||||
m_inactiveBorderColor.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto const& token : colorsAndAngles) {
|
||||
// The first angle, or an explicit "0deg", splits the two gradients
|
||||
if (active && token.contains("deg")) {
|
||||
activeBorderGradient.m_angle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
active = false;
|
||||
} else if (token.contains("deg"))
|
||||
inactiveBorderGradient.m_angle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
else if (active)
|
||||
activeBorderGradient.m_colors.emplace_back(configStringToInt(token).value_or(0));
|
||||
else
|
||||
inactiveBorderGradient.m_colors.emplace_back(configStringToInt(token).value_or(0));
|
||||
}
|
||||
|
||||
activeBorderGradient.updateColorsOk();
|
||||
|
||||
// Includes sanity checks for the number of colors in each gradient
|
||||
if (activeBorderGradient.m_colors.size() > 10 || inactiveBorderGradient.m_colors.size() > 10)
|
||||
Log::logger->log(Log::WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", effect);
|
||||
else if (activeBorderGradient.m_colors.empty())
|
||||
Log::logger->log(Log::WARN, "Bordercolor rule \"{}\" has no colors, ignoring", effect);
|
||||
else if (inactiveBorderGradient.m_colors.empty())
|
||||
m_activeBorderColor.first = Types::COverridableVar(activeBorderGradient, Types::PRIORITY_WINDOW_RULE);
|
||||
else {
|
||||
m_activeBorderColor.first = Types::COverridableVar(activeBorderGradient, Types::PRIORITY_WINDOW_RULE);
|
||||
m_inactiveBorderColor.first = Types::COverridableVar(inactiveBorderGradient, Types::PRIORITY_WINDOW_RULE);
|
||||
}
|
||||
} catch (std::exception& e) { Log::logger->log(Log::ERR, "BorderColor rule \"{}\" failed with: {}", effect, e.what()); }
|
||||
const auto& borderColor = std::get<SBorderColorRule>(value);
|
||||
m_activeBorderColor.first = Types::COverridableVar(borderColor.active, Types::PRIORITY_WINDOW_RULE);
|
||||
if (borderColor.inactive)
|
||||
m_inactiveBorderColor.first = Types::COverridableVar(*borderColor.inactive, Types::PRIORITY_WINDOW_RULE);
|
||||
m_activeBorderColor.second = rule->getPropertiesMask();
|
||||
m_inactiveBorderColor.second = rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_IDLE_INHIBIT: {
|
||||
if (effect == "none")
|
||||
m_idleInhibitMode.first.set(IDLEINHIBIT_NONE, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (effect == "always")
|
||||
m_idleInhibitMode.first.set(IDLEINHIBIT_ALWAYS, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (effect == "focus")
|
||||
m_idleInhibitMode.first.set(IDLEINHIBIT_FOCUS, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (effect == "fullscreen")
|
||||
m_idleInhibitMode.first.set(IDLEINHIBIT_FULLSCREEN, Types::PRIORITY_WINDOW_RULE);
|
||||
else
|
||||
Log::logger->log(Log::ERR, "Rule idleinhibit: unknown mode {}", effect);
|
||||
m_idleInhibitMode.first.set(std::get<int64_t>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_idleInhibitMode.second = rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_OPACITY: {
|
||||
try {
|
||||
CVarList2 vars(std::string{effect}, 0, ' ');
|
||||
|
||||
int opacityIDX = 0;
|
||||
|
||||
for (const auto& r : vars) {
|
||||
if (r == "opacity")
|
||||
continue;
|
||||
|
||||
if (r == "override") {
|
||||
if (opacityIDX == 1)
|
||||
m_alpha.first = Types::COverridableVar(Types::SAlphaValue{.alpha = m_alpha.first.value().alpha, .overridden = true}, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (opacityIDX == 2)
|
||||
m_alphaInactive.first =
|
||||
Types::COverridableVar(Types::SAlphaValue{.alpha = m_alphaInactive.first.value().alpha, .overridden = true}, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (opacityIDX == 3)
|
||||
m_alphaFullscreen.first =
|
||||
Types::COverridableVar(Types::SAlphaValue{.alpha = m_alphaFullscreen.first.value().alpha, .overridden = true}, Types::PRIORITY_WINDOW_RULE);
|
||||
} else {
|
||||
if (opacityIDX == 0)
|
||||
m_alpha.first = Types::COverridableVar(Types::SAlphaValue{.alpha = std::stof(std::string{r}), .overridden = false}, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (opacityIDX == 1)
|
||||
m_alphaInactive.first =
|
||||
Types::COverridableVar(Types::SAlphaValue{.alpha = std::stof(std::string{r}), .overridden = false}, Types::PRIORITY_WINDOW_RULE);
|
||||
else if (opacityIDX == 2)
|
||||
m_alphaFullscreen.first =
|
||||
Types::COverridableVar(Types::SAlphaValue{.alpha = std::stof(std::string{r}), .overridden = false}, Types::PRIORITY_WINDOW_RULE);
|
||||
else
|
||||
throw std::runtime_error("more than 3 alpha values");
|
||||
|
||||
opacityIDX++;
|
||||
}
|
||||
}
|
||||
|
||||
if (opacityIDX == 1) {
|
||||
m_alphaInactive.first = m_alpha.first;
|
||||
m_alphaFullscreen.first = m_alpha.first;
|
||||
}
|
||||
} catch (std::exception& e) { Log::logger->log(Log::ERR, "Opacity rule \"{}\" failed with: {}", effect, e.what()); }
|
||||
const auto& opacity = std::get<SOpacityRule>(value);
|
||||
m_alpha.first = Types::COverridableVar(opacity.alpha, Types::PRIORITY_WINDOW_RULE);
|
||||
m_alphaInactive.first = Types::COverridableVar(opacity.alphaInactive, Types::PRIORITY_WINDOW_RULE);
|
||||
m_alphaFullscreen.first = Types::COverridableVar(opacity.alphaFullscreen, Types::PRIORITY_WINDOW_RULE);
|
||||
m_alpha.second = rule->getPropertiesMask();
|
||||
m_alphaInactive.second = rule->getPropertiesMask();
|
||||
m_alphaFullscreen.second = rule->getPropertiesMask();
|
||||
|
|
@ -304,142 +212,136 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const
|
|||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_BORDER_SIZE: {
|
||||
try {
|
||||
auto oldBorderSize = m_borderSize.first.valueOrDefault();
|
||||
m_borderSize.first.set(std::stoi(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_borderSize.second |= rule->getPropertiesMask();
|
||||
if (oldBorderSize != m_borderSize.first.valueOrDefault())
|
||||
result.needsRelayout = true;
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyDynamicRule: invalid border_size {}", effect); }
|
||||
auto oldBorderSize = m_borderSize.first.valueOrDefault();
|
||||
m_borderSize.first.set(std::get<int64_t>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_borderSize.second |= rule->getPropertiesMask();
|
||||
if (oldBorderSize != m_borderSize.first.valueOrDefault())
|
||||
result.needsRelayout = true;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ALLOWS_INPUT: {
|
||||
m_allowsInput.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_allowsInput.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_allowsInput.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_DIM_AROUND: {
|
||||
m_dimAround.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_dimAround.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_dimAround.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_DECORATE: {
|
||||
m_decorate.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_decorate.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_decorate.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_FOCUS_ON_ACTIVATE: {
|
||||
m_focusOnActivate.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_focusOnActivate.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_focusOnActivate.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_KEEP_ASPECT_RATIO: {
|
||||
m_keepAspectRatio.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_keepAspectRatio.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_keepAspectRatio.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NEAREST_NEIGHBOR: {
|
||||
m_nearestNeighbor.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_nearestNeighbor.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_nearestNeighbor.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_ANIM: {
|
||||
m_noAnim.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noAnim.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noAnim.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_BLUR: {
|
||||
m_noBlur.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noBlur.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noBlur.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_DIM: {
|
||||
m_noDim.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noDim.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noDim.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_FOCUS: {
|
||||
m_noFocus.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noFocus.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noFocus.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_FOLLOW_MOUSE: {
|
||||
m_noFollowMouse.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noFollowMouse.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noFollowMouse.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_MAX_SIZE: {
|
||||
m_noMaxSize.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noMaxSize.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noMaxSize.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_SHADOW: {
|
||||
m_noShadow.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noShadow.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noShadow.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_SHORTCUTS_INHIBIT: {
|
||||
m_noShortcutsInhibit.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noShortcutsInhibit.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noShortcutsInhibit.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_OPAQUE: {
|
||||
m_opaque.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_opaque.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_opaque.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_FORCE_RGBX: {
|
||||
m_RGBX.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_RGBX.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_RGBX.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SYNC_FULLSCREEN: {
|
||||
m_syncFullscreen.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_syncFullscreen.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_syncFullscreen.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_IMMEDIATE: {
|
||||
m_tearing.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_tearing.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_tearing.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_XRAY: {
|
||||
m_xray.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_xray.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_xray.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_RENDER_UNFOCUSED: {
|
||||
m_renderUnfocused.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_renderUnfocused.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_renderUnfocused.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_SCREEN_SHARE: {
|
||||
m_noScreenShare.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noScreenShare.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noScreenShare.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_VRR: {
|
||||
m_noVRR.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noVRR.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_noVRR.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_STAY_FOCUSED: {
|
||||
m_stayFocused.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_stayFocused.first.set(std::get<bool>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_stayFocused.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SCROLL_MOUSE: {
|
||||
try {
|
||||
m_scrollMouse.first.set(std::clamp(std::stof(effect), 0.01F, 10.F), Types::PRIORITY_WINDOW_RULE);
|
||||
m_scrollMouse.second |= rule->getPropertiesMask();
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyDynamicRule: invalid scroll_mouse {}", effect); }
|
||||
m_scrollMouse.first.set(std::get<float>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_scrollMouse.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SCROLL_TOUCHPAD: {
|
||||
try {
|
||||
m_scrollTouchpad.first.set(std::clamp(std::stof(effect), 0.01F, 10.F), Types::PRIORITY_WINDOW_RULE);
|
||||
m_scrollTouchpad.second |= rule->getPropertiesMask();
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyDynamicRule: invalid scroll_touchpad {}", effect); }
|
||||
m_scrollTouchpad.first.set(std::get<float>(value), Types::PRIORITY_WINDOW_RULE);
|
||||
m_scrollTouchpad.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -448,7 +350,10 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const
|
|||
}
|
||||
|
||||
CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyStaticRule(const SP<CWindowRule>& rule) {
|
||||
for (const auto& [key, effect] : rule->effects()) {
|
||||
for (const auto& effectData : rule->effects()) {
|
||||
const auto key = effectData.key;
|
||||
const auto& value = effectData.value;
|
||||
|
||||
switch (key) {
|
||||
default: {
|
||||
Log::logger->log(Log::TRACE, "CWindowRuleApplicator::applyStaticRule: Skipping effect {}, not static", sc<std::underlying_type_t<eWindowRuleEffect>>(key));
|
||||
|
|
@ -456,89 +361,82 @@ CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyStaticRule(const
|
|||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_FLOAT: {
|
||||
static_.floating = truthy(effect);
|
||||
static_.floating = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_TILE: {
|
||||
static_.floating = !truthy(effect);
|
||||
static_.floating = !std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_FULLSCREEN: {
|
||||
static_.fullscreen = truthy(effect);
|
||||
static_.fullscreen = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MAXIMIZE: {
|
||||
static_.maximize = truthy(effect);
|
||||
static_.maximize = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_FULLSCREENSTATE: {
|
||||
CVarList2 vars(std::string{effect}, 0, 's');
|
||||
try {
|
||||
static_.fullscreenStateInternal = std::stoi(std::string{vars[0]});
|
||||
if (!vars[1].empty())
|
||||
static_.fullscreenStateClient = std::stoi(std::string{vars[1]});
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyStaticRule: invalid fullscreen state {}", effect); }
|
||||
const auto& fullscreenState = std::get<SFullscreenStateRule>(value);
|
||||
static_.fullscreenStateInternal = fullscreenState.internal;
|
||||
if (fullscreenState.client)
|
||||
static_.fullscreenStateClient = *fullscreenState.client;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MOVE: {
|
||||
static_.center = std::nullopt;
|
||||
static_.position = effect;
|
||||
static_.position = std::get<std::string>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SIZE: {
|
||||
static_.size = effect;
|
||||
static_.size = std::get<std::string>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_CENTER: {
|
||||
static_.position.clear();
|
||||
static_.center = truthy(effect);
|
||||
static_.center = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_PSEUDO: {
|
||||
static_.pseudo = truthy(effect);
|
||||
static_.pseudo = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MONITOR: {
|
||||
static_.monitor = effect;
|
||||
static_.monitor = std::get<std::string>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_WORKSPACE: {
|
||||
static_.workspace = effect;
|
||||
static_.workspace = std::get<std::string>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NOINITIALFOCUS: {
|
||||
static_.noInitialFocus = truthy(effect);
|
||||
static_.noInitialFocus = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_PIN: {
|
||||
static_.pin = truthy(effect);
|
||||
static_.pin = std::get<bool>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_GROUP: {
|
||||
static_.group = effect;
|
||||
static_.group = std::get<std::string>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SUPPRESSEVENT: {
|
||||
CVarList2 varlist(std::string{effect}, 0, 's');
|
||||
for (const auto& e : varlist) {
|
||||
for (const auto& e : std::get<std::vector<std::string>>(value)) {
|
||||
static_.suppressEvent.emplace_back(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_CONTENT: {
|
||||
static_.content = NContentType::fromString(effect);
|
||||
static_.content = std::get<int64_t>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NOCLOSEFOR: {
|
||||
try {
|
||||
static_.noCloseFor = std::stoi(effect);
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyStaticRule: invalid no close for {}", effect); }
|
||||
static_.noCloseFor = std::get<int64_t>(value);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SCROLLING_WIDTH: {
|
||||
try {
|
||||
static_.scrollingWidth = std::stof(effect);
|
||||
} catch (...) { Log::logger->log(Log::ERR, "CWindowRuleApplicator::applyStaticRule: invalid scrolling width {}", effect); }
|
||||
static_.scrollingWidth = std::get<float>(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,12 @@ SP<CAsyncDialogBox> CAsyncDialogBox::lockSelf() {
|
|||
}
|
||||
|
||||
void CAsyncDialogBox::setExecRule(std::string&& s) {
|
||||
auto rule = Desktop::Rule::CWindowRule::buildFromExecString(std::move(s));
|
||||
m_execRuleToken = rule->execToken();
|
||||
Desktop::Rule::ruleEngine()->registerRule(std::move(rule));
|
||||
auto rule = Desktop::Rule::CWindowRule::buildFromExecString(std::move(s));
|
||||
if (!rule) {
|
||||
Log::logger->log(Log::ERR, "CAsyncDialogBox: failed to parse exec rule: {}", rule.error());
|
||||
return;
|
||||
}
|
||||
|
||||
m_execRuleToken = (*rule)->execToken();
|
||||
Desktop::Rule::ruleEngine()->registerRule(std::move(*rule));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue