core: Optimize window/layer rule application and scanning (#8735)

Optimizes window and layer rule parsing and later usage.
This commit is contained in:
Vaxry 2024-12-16 19:05:24 +01:00 committed by GitHub
parent eaac5c7cbd
commit dab50b3ef3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 866 additions and 609 deletions

37
src/desktop/LayerRule.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "LayerRule.hpp"
#include <unordered_set>
#include <algorithm>
#include "../debug/Log.hpp"
static const auto RULES = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto RULES_PREFIX = std::unordered_set<std::string>{"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;
}
}

28
src/desktop/LayerRule.hpp Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <cstdint>
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;
};

View file

@ -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);
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"); }
} 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"); }
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;
}
}
}

View file

@ -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;

View file

@ -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};
void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
const eOverridePriority priority = r->execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
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, ' ');
switch (r->ruleType) {
case CWindowRule::RULE_TAG: {
CVarList vars{r->szRule, 0, 's', true};
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);
} else {
throw std::runtime_error("more than 3 alpha values");
}
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;
}
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 (...) {}
if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r->szRule);
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);
case CWindowRule::RULE_OPACITY: {
try {
CVarList vars(r->szRule, 0, ' ');
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;
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);
} else {
throw std::runtime_error("more than 3 alpha values");
}
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()); }
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));
}
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;
}
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());
} 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);
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()); }
}
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;
}
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());
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);
}

View file

@ -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<CGradientValueData> 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<SWindowRule> m_vMatchedRules;
std::vector<SP<CWindowRule>> 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<CWindowRule>& r);
void updateDynamicRules();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();

100
src/desktop/WindowRule.cpp Normal file
View file

@ -0,0 +1,100 @@
#include "WindowRule.hpp"
#include <unordered_set>
#include <algorithm>
#include "../config/ConfigManager.hpp"
static const auto RULES = std::unordered_set<std::string>{
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
};
static const auto RULES_PREFIX = std::unordered_set<std::string>{
"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<std::string*>(&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;
}
}
}

View file

@ -0,0 +1,65 @@
#pragma once
#include <string>
#include <cstdint>
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
};