windowrules: rewrite completely (#12269)
Reworks the window rule syntax completely --------- Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
parent
95ee08b340
commit
c2670e9ab9
93 changed files with 3574 additions and 2255 deletions
186
src/desktop/rule/windowRule/WindowRule.cpp
Normal file
186
src/desktop/rule/windowRule/WindowRule.cpp
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#include "WindowRule.hpp"
|
||||
#include "../../Window.hpp"
|
||||
#include "../../../helpers/Monitor.hpp"
|
||||
#include "../../../Compositor.hpp"
|
||||
#include "../../../managers/TokenManager.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::Rule;
|
||||
|
||||
std::optional<Vector2D> Rule::parseRelativeVector(PHLWINDOW w, const std::string& s) {
|
||||
try {
|
||||
const auto VALUE = s.substr(s.find(' ') + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
||||
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
|
||||
|
||||
const auto MAXSIZE = w->requestedMaxSize();
|
||||
|
||||
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_lastMonitor->m_size.x) :
|
||||
stringToPercentage(SIZEXSTR, g_pCompositor->m_lastMonitor->m_size.x);
|
||||
|
||||
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_lastMonitor->m_size.y) :
|
||||
stringToPercentage(SIZEYSTR, g_pCompositor->m_lastMonitor->m_size.y);
|
||||
|
||||
return Vector2D{SIZEX, SIZEY};
|
||||
|
||||
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {}", s); }
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CWindowRule::CWindowRule(const std::string& name) : IRule(name) {
|
||||
;
|
||||
}
|
||||
|
||||
eRuleType CWindowRule::type() {
|
||||
return RULE_TYPE_WINDOW;
|
||||
}
|
||||
|
||||
void CWindowRule::addEffect(CWindowRule::storageType e, const std::string& result) {
|
||||
m_effects.emplace_back(std::make_pair<>(e, result));
|
||||
m_effectSet.emplace(e);
|
||||
}
|
||||
|
||||
const std::vector<std::pair<CWindowRule::storageType, std::string>>& CWindowRule::effects() {
|
||||
return m_effects;
|
||||
}
|
||||
|
||||
bool CWindowRule::matches(PHLWINDOW w, bool allowEnvLookup) {
|
||||
if (m_matchEngines.empty())
|
||||
return false;
|
||||
|
||||
for (const auto& [prop, engine] : m_matchEngines) {
|
||||
switch (prop) {
|
||||
default: {
|
||||
Debug::log(TRACE, "CWindowRule::matches: skipping prop entry {}", sc<std::underlying_type_t<eRuleProperty>>(prop));
|
||||
break;
|
||||
}
|
||||
|
||||
case RULE_PROP_TITLE:
|
||||
if (!engine->match(w->m_title))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_INITIAL_TITLE:
|
||||
if (!engine->match(w->m_initialTitle))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_CLASS:
|
||||
if (!engine->match(w->m_class))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_INITIAL_CLASS:
|
||||
if (!engine->match(w->m_initialClass))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_FLOATING:
|
||||
if (!engine->match(w->m_isFloating))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_TAG:
|
||||
if (!engine->match(w->m_ruleApplicator->m_tagKeeper))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_XWAYLAND:
|
||||
if (!engine->match(w->m_isX11))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_FULLSCREEN:
|
||||
if (!engine->match(w->m_fullscreenState.internal != 0))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_PINNED:
|
||||
if (!engine->match(w->m_pinned))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_FOCUS:
|
||||
if (!engine->match(g_pCompositor->m_lastWindow == w))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_GROUP:
|
||||
if (!engine->match(w->m_groupData.pNextWindow))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_MODAL:
|
||||
if (!engine->match(w->isModal()))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_FULLSCREENSTATE_INTERNAL:
|
||||
if (!engine->match(w->m_fullscreenState.internal))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_FULLSCREENSTATE_CLIENT:
|
||||
if (!engine->match(w->m_fullscreenState.client))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_ON_WORKSPACE:
|
||||
if (!engine->match(w->m_workspace))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_CONTENT:
|
||||
if (!engine->match(NContentType::toString(w->getContentType())))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_XDG_TAG:
|
||||
if (w->xdgTag().has_value() && !engine->match(*w->xdgTag()))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_EXEC_TOKEN:
|
||||
// this is only allowed on static rules, we don't need it on dynamic plus it's expensive
|
||||
if (!allowEnvLookup)
|
||||
break;
|
||||
|
||||
const auto ENV = w->getEnv();
|
||||
if (ENV.contains(EXEC_RULE_ENV_NAME)) {
|
||||
const auto TKN = ENV.at(EXEC_RULE_ENV_NAME);
|
||||
if (!engine->match(TKN))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SP<CWindowRule> CWindowRule::buildFromExecString(std::string&& s) {
|
||||
CVarList2 varlist(std::move(s), 0, ';');
|
||||
SP<CWindowRule> wr = makeShared<CWindowRule>("__exec_rule");
|
||||
|
||||
for (const auto& el : varlist) {
|
||||
// split element by space, can't do better
|
||||
size_t spacePos = el.find(' ');
|
||||
if (spacePos != std::string::npos) {
|
||||
// great, split and try to parse
|
||||
auto LHS = el.substr(0, spacePos);
|
||||
const auto EFFECT = windowEffects()->get(LHS);
|
||||
|
||||
if (!EFFECT.has_value() || *EFFECT == WINDOW_RULE_EFFECT_NONE)
|
||||
continue; // invalid...
|
||||
|
||||
wr->addEffect(*EFFECT, std::string{el.substr(spacePos + 1)});
|
||||
continue;
|
||||
}
|
||||
|
||||
// assume 1 maybe...
|
||||
|
||||
const auto EFFECT = windowEffects()->get(el);
|
||||
|
||||
if (!EFFECT.has_value() || *EFFECT == WINDOW_RULE_EFFECT_NONE)
|
||||
continue; // invalid...
|
||||
|
||||
wr->addEffect(*EFFECT, std::string{"1"});
|
||||
}
|
||||
|
||||
const auto TOKEN = g_pTokenManager->registerNewToken(nullptr, std::chrono::seconds(1));
|
||||
|
||||
wr->markAsExecRule(TOKEN, false /* TODO: could be nice. */);
|
||||
wr->registerMatch(RULE_PROP_EXEC_TOKEN, TOKEN);
|
||||
|
||||
return wr;
|
||||
}
|
||||
|
||||
const std::unordered_set<CWindowRule::storageType>& CWindowRule::effectsSet() {
|
||||
return m_effectSet;
|
||||
}
|
||||
37
src/desktop/rule/windowRule/WindowRule.hpp
Normal file
37
src/desktop/rule/windowRule/WindowRule.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "../Rule.hpp"
|
||||
#include "../../DesktopTypes.hpp"
|
||||
#include "WindowRuleEffectContainer.hpp"
|
||||
#include "../../../helpers/math/Math.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Desktop::Rule {
|
||||
constexpr const char* EXEC_RULE_ENV_NAME = "HL_EXEC_RULE_TOKEN";
|
||||
|
||||
std::optional<Vector2D> parseRelativeVector(PHLWINDOW w, const std::string& s);
|
||||
|
||||
class CWindowRule : public IRule {
|
||||
private:
|
||||
using storageType = CWindowRuleEffectContainer::storageType;
|
||||
|
||||
public:
|
||||
CWindowRule(const std::string& name = "");
|
||||
virtual ~CWindowRule() = default;
|
||||
|
||||
static SP<CWindowRule> buildFromExecString(std::string&&);
|
||||
|
||||
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();
|
||||
|
||||
bool matches(PHLWINDOW w, bool allowEnvLookup = false);
|
||||
|
||||
private:
|
||||
std::vector<std::pair<storageType, std::string>> m_effects;
|
||||
std::unordered_set<storageType> m_effectSet;
|
||||
};
|
||||
};
|
||||
642
src/desktop/rule/windowRule/WindowRuleApplicator.cpp
Normal file
642
src/desktop/rule/windowRule/WindowRuleApplicator.cpp
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
#include "WindowRuleApplicator.hpp"
|
||||
#include "WindowRule.hpp"
|
||||
#include "../Engine.hpp"
|
||||
#include "../utils/SetUtils.hpp"
|
||||
#include "../../Window.hpp"
|
||||
#include "../../types/OverridableVar.hpp"
|
||||
#include "../../../managers/LayoutManager.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::Rule;
|
||||
|
||||
CWindowRuleApplicator::CWindowRuleApplicator(PHLWINDOW w) : m_window(w) {
|
||||
;
|
||||
}
|
||||
|
||||
void CWindowRuleApplicator::resetProps(std::underlying_type_t<eRuleProperty> props, Types::eOverridePriority prio) {
|
||||
// TODO: fucking kill me, is there a better way to do this?
|
||||
|
||||
#define UNSET(x) \
|
||||
if (m_##x.second & props) { \
|
||||
if (prio == Types::PRIORITY_WINDOW_RULE) \
|
||||
m_##x.second &= ~props; \
|
||||
m_##x.first.unset(prio); \
|
||||
}
|
||||
|
||||
UNSET(alpha)
|
||||
UNSET(alphaInactive)
|
||||
UNSET(alphaFullscreen)
|
||||
UNSET(allowsInput)
|
||||
UNSET(decorate)
|
||||
UNSET(focusOnActivate)
|
||||
UNSET(keepAspectRatio)
|
||||
UNSET(nearestNeighbor)
|
||||
UNSET(noAnim)
|
||||
UNSET(noBlur)
|
||||
UNSET(noDim)
|
||||
UNSET(noFocus)
|
||||
UNSET(noMaxSize)
|
||||
UNSET(noShadow)
|
||||
UNSET(noShortcutsInhibit)
|
||||
UNSET(opaque)
|
||||
UNSET(dimAround)
|
||||
UNSET(RGBX)
|
||||
UNSET(syncFullscreen)
|
||||
UNSET(tearing)
|
||||
UNSET(xray)
|
||||
UNSET(renderUnfocused)
|
||||
UNSET(noFollowMouse)
|
||||
UNSET(noScreenShare)
|
||||
UNSET(noVRR)
|
||||
UNSET(persistentSize)
|
||||
UNSET(stayFocused)
|
||||
UNSET(idleInhibitMode)
|
||||
UNSET(borderSize)
|
||||
UNSET(rounding)
|
||||
UNSET(roundingPower)
|
||||
UNSET(scrollMouse)
|
||||
UNSET(scrollTouchpad)
|
||||
UNSET(animationStyle)
|
||||
UNSET(maxSize)
|
||||
UNSET(minSize)
|
||||
UNSET(activeBorderColor)
|
||||
UNSET(inactiveBorderColor)
|
||||
|
||||
#undef UNSET
|
||||
|
||||
if (prio == Types::PRIORITY_WINDOW_RULE) {
|
||||
std::erase_if(m_dynamicTags, [props, this](const auto& el) {
|
||||
const bool REMOVE = el.second & props;
|
||||
|
||||
if (REMOVE)
|
||||
m_tagKeeper.removeDynamicTag(el.first);
|
||||
|
||||
return REMOVE;
|
||||
});
|
||||
|
||||
std::erase_if(m_otherProps.props, [props](const auto& el) { return !el.second || el.second->propMask & props; });
|
||||
}
|
||||
}
|
||||
|
||||
CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyDynamicRule(const SP<CWindowRule>& rule) {
|
||||
SRuleResult result;
|
||||
|
||||
for (const auto& [key, effect] : rule->effects()) {
|
||||
switch (key) {
|
||||
default: {
|
||||
if (key <= WINDOW_RULE_EFFECT_LAST_STATIC) {
|
||||
Debug::log(TRACE, "CWindowRuleApplicator::applyDynamicRule: Skipping effect {}, not dynamic", sc<std::underlying_type_t<eWindowRuleEffect>>(key));
|
||||
break;
|
||||
}
|
||||
|
||||
// custom type, add to our vec
|
||||
if (!m_otherProps.props.contains(key)) {
|
||||
m_otherProps.props.emplace(key,
|
||||
makeUnique<SCustomPropContainer>(SCustomPropContainer{
|
||||
.idx = key,
|
||||
.propMask = rule->getPropertiesMask(),
|
||||
.effect = effect,
|
||||
}));
|
||||
} else {
|
||||
auto& e = m_otherProps.props[key];
|
||||
e->propMask |= rule->getPropertiesMask();
|
||||
e->effect = effect;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_NONE: {
|
||||
Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: BUG THIS: WINDOW_RULE_EFFECT_NONE??");
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ROUNDING: {
|
||||
try {
|
||||
m_rounding.first.set(std::stoull(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_rounding.second |= rule->getPropertiesMask();
|
||||
} catch (...) { Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: invalid rounding {}", effect); }
|
||||
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 (...) { Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: invalid rounding_power {}", effect); }
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_PERSISTENT_SIZE: {
|
||||
try {
|
||||
m_persistentSize.first.set(std::stoi(effect), Types::PRIORITY_WINDOW_RULE);
|
||||
m_persistentSize.second |= rule->getPropertiesMask();
|
||||
} catch (...) { Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: invalid rounding_power {}", effect); }
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ANIMATION: {
|
||||
m_animationStyle.first.set(effect, 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
|
||||
CGradientValueData activeBorderGradient = {};
|
||||
CGradientValueData inactiveBorderGradient = {};
|
||||
bool active = true;
|
||||
CVarList colorsAndAngles = CVarList(trim(effect.substr(effect.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_activeBorderColor.first =
|
||||
Types::COverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), Types::PRIORITY_WINDOW_RULE);
|
||||
m_inactiveBorderColor.first =
|
||||
Types::COverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), Types::PRIORITY_WINDOW_RULE);
|
||||
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)
|
||||
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", effect);
|
||||
else if (activeBorderGradient.m_colors.empty())
|
||||
Debug::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) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", effect, e.what()); }
|
||||
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
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", effect);
|
||||
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) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", effect, e.what()); }
|
||||
m_alpha.second = rule->getPropertiesMask();
|
||||
m_alphaInactive.second = rule->getPropertiesMask();
|
||||
m_alphaFullscreen.second = rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_TAG: {
|
||||
m_dynamicTags.emplace_back(std::make_pair<>(effect, rule->getPropertiesMask()));
|
||||
m_tagKeeper.applyTag(effect, true);
|
||||
result.tagsChanged = true;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MAX_SIZE: {
|
||||
try {
|
||||
static auto PCLAMP_TILED = CConfigValue<Hyprlang::INT>("misc:size_limits_tiled");
|
||||
|
||||
if (!m_window)
|
||||
break;
|
||||
|
||||
if (!m_window->m_isFloating && !sc<bool>(*PCLAMP_TILED))
|
||||
break;
|
||||
|
||||
const auto VEC = configStringToVector2D(effect);
|
||||
if (VEC.x < 1 || VEC.y < 1) {
|
||||
Debug::log(ERR, "Invalid size for maxsize");
|
||||
break;
|
||||
}
|
||||
|
||||
m_maxSize.first = Types::COverridableVar(VEC, Types::PRIORITY_WINDOW_RULE);
|
||||
m_window->clampWindowSize(std::nullopt, m_maxSize.first.value());
|
||||
|
||||
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", effect, e.what()); }
|
||||
m_maxSize.second = rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MIN_SIZE: {
|
||||
try {
|
||||
static auto PCLAMP_TILED = CConfigValue<Hyprlang::INT>("misc:size_limits_tiled");
|
||||
|
||||
if (!m_window)
|
||||
break;
|
||||
|
||||
if (!m_window->m_isFloating && !sc<bool>(*PCLAMP_TILED))
|
||||
break;
|
||||
|
||||
const auto VEC = configStringToVector2D(effect);
|
||||
if (VEC.x < 1 || VEC.y < 1) {
|
||||
Debug::log(ERR, "Invalid size for maxsize");
|
||||
break;
|
||||
}
|
||||
|
||||
m_minSize.first = Types::COverridableVar(VEC, Types::PRIORITY_WINDOW_RULE);
|
||||
m_window->clampWindowSize(std::nullopt, m_minSize.first.value());
|
||||
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", effect, e.what()); }
|
||||
m_minSize.second = rule->getPropertiesMask();
|
||||
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 (...) { Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: invalid border_size {}", effect); }
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_ALLOWS_INPUT: {
|
||||
m_allowsInput.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_DECORATE: {
|
||||
m_decorate.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_KEEP_ASPECT_RATIO: {
|
||||
m_keepAspectRatio.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_ANIM: {
|
||||
m_noAnim.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_DIM: {
|
||||
m_noDim.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_FOLLOW_MOUSE: {
|
||||
m_noFollowMouse.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_SHADOW: {
|
||||
m_noShadow.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_OPAQUE: {
|
||||
m_opaque.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SYNC_FULLSCREEN: {
|
||||
m_syncFullscreen.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_XRAY: {
|
||||
m_xray.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NO_SCREEN_SHARE: {
|
||||
m_noScreenShare.first.set(truthy(effect), 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.second |= rule->getPropertiesMask();
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_STAY_FOCUSED: {
|
||||
m_stayFocused.first.set(truthy(effect), 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 (...) { Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: invalid scroll_mouse {}", effect); }
|
||||
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 (...) { Debug::log(ERR, "CWindowRuleApplicator::applyDynamicRule: invalid scroll_touchpad {}", effect); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CWindowRuleApplicator::SRuleResult CWindowRuleApplicator::applyStaticRule(const SP<CWindowRule>& rule) {
|
||||
for (const auto& [key, effect] : rule->effects()) {
|
||||
switch (key) {
|
||||
default: {
|
||||
Debug::log(TRACE, "CWindowRuleApplicator::applyStaticRule: Skipping effect {}, not static", sc<std::underlying_type_t<eWindowRuleEffect>>(key));
|
||||
break;
|
||||
}
|
||||
|
||||
case WINDOW_RULE_EFFECT_FLOAT: {
|
||||
static_.floating = truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_TILE: {
|
||||
static_.floating = !truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_FULLSCREEN: {
|
||||
static_.fullscreen = truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MAXIMIZE: {
|
||||
static_.maximize = truthy(effect);
|
||||
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 (...) { Debug::log(ERR, "CWindowRuleApplicator::applyStaticRule: invalid fullscreen state {}", effect); }
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MOVE: {
|
||||
static_.position = effect;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SIZE: {
|
||||
static_.size = effect;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_CENTER: {
|
||||
static_.center = truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_PSEUDO: {
|
||||
static_.pseudo = truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_MONITOR: {
|
||||
static_.monitor = effect;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_WORKSPACE: {
|
||||
static_.workspace = effect;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NOINITIALFOCUS: {
|
||||
static_.noInitialFocus = truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_PIN: {
|
||||
static_.pin = truthy(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_GROUP: {
|
||||
static_.group = effect;
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_SUPPRESSEVENT: {
|
||||
CVarList2 varlist(std::string{effect}, 0, 's');
|
||||
for (const auto& e : varlist) {
|
||||
static_.suppressEvent.emplace_back(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_CONTENT: {
|
||||
static_.content = NContentType::fromString(effect);
|
||||
break;
|
||||
}
|
||||
case WINDOW_RULE_EFFECT_NOCLOSEFOR: {
|
||||
try {
|
||||
static_.noCloseFor = std::stoi(effect);
|
||||
} catch (...) { Debug::log(ERR, "CWindowRuleApplicator::applyStaticRule: invalid no close for {}", effect); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SRuleResult{};
|
||||
}
|
||||
|
||||
void CWindowRuleApplicator::readStaticRules() {
|
||||
if (!m_window)
|
||||
return;
|
||||
|
||||
static_ = {};
|
||||
|
||||
std::vector<SP<IRule>> toRemove;
|
||||
bool tagsWereChanged = false;
|
||||
|
||||
for (const auto& r : ruleEngine()->rules()) {
|
||||
if (r->type() != RULE_TYPE_WINDOW)
|
||||
continue;
|
||||
|
||||
auto wr = reinterpretPointerCast<CWindowRule>(r);
|
||||
|
||||
if (!wr->matches(m_window.lock(), true))
|
||||
continue;
|
||||
|
||||
applyStaticRule(wr);
|
||||
const auto RES = applyDynamicRule(wr); // also apply dynamic, because we won't recheck it before layout gets data
|
||||
tagsWereChanged = tagsWereChanged || RES.tagsChanged;
|
||||
|
||||
if (wr->isExecRule())
|
||||
toRemove.emplace_back(wr);
|
||||
}
|
||||
|
||||
for (const auto& wr : toRemove) {
|
||||
ruleEngine()->unregisterRule(wr);
|
||||
}
|
||||
|
||||
// recheck some props people might wanna use for static rules.
|
||||
std::underlying_type_t<eRuleProperty> propsToRecheck = RULE_PROP_NONE;
|
||||
if (tagsWereChanged)
|
||||
propsToRecheck |= RULE_PROP_TAG;
|
||||
if (static_.content != NContentType::CONTENT_TYPE_NONE)
|
||||
propsToRecheck |= RULE_PROP_CONTENT;
|
||||
|
||||
if (propsToRecheck != RULE_PROP_NONE) {
|
||||
for (const auto& r : ruleEngine()->rules()) {
|
||||
if (r->type() != RULE_TYPE_WINDOW)
|
||||
continue;
|
||||
|
||||
if (!(r->getPropertiesMask() & propsToRecheck))
|
||||
continue;
|
||||
|
||||
auto wr = reinterpretPointerCast<CWindowRule>(r);
|
||||
|
||||
if (!wr->matches(m_window.lock(), true))
|
||||
continue;
|
||||
|
||||
applyStaticRule(wr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWindowRuleApplicator::propertiesChanged(std::underlying_type_t<eRuleProperty> props) {
|
||||
if (!m_window || !m_window->m_isMapped || m_window->isHidden())
|
||||
return;
|
||||
|
||||
resetProps(props);
|
||||
|
||||
bool needsRelayout = false;
|
||||
|
||||
std::unordered_set<CWindowRuleEffectContainer::storageType> effectsNeedingRecheck;
|
||||
std::unordered_set<SP<CWindowRule>> passedWrs;
|
||||
|
||||
for (const auto& r : ruleEngine()->rules()) {
|
||||
if (r->type() != RULE_TYPE_WINDOW)
|
||||
continue;
|
||||
|
||||
if (!(r->getPropertiesMask() & props))
|
||||
continue;
|
||||
|
||||
auto wr = reinterpretPointerCast<CWindowRule>(r);
|
||||
|
||||
if (!wr->matches(m_window.lock()))
|
||||
continue;
|
||||
|
||||
for (const auto& [type, eff] : wr->effects()) {
|
||||
effectsNeedingRecheck.emplace(type);
|
||||
}
|
||||
|
||||
passedWrs.emplace(std::move(wr));
|
||||
}
|
||||
|
||||
for (const auto& r : ruleEngine()->rules()) {
|
||||
if (r->type() != RULE_TYPE_WINDOW)
|
||||
continue;
|
||||
|
||||
const auto WR = reinterpretPointerCast<CWindowRule>(r);
|
||||
|
||||
if (!(WR->getPropertiesMask() & props) && !setsIntersect(WR->effectsSet(), effectsNeedingRecheck))
|
||||
continue;
|
||||
|
||||
if (!std::ranges::contains(passedWrs, WR) && !WR->matches(m_window.lock()))
|
||||
continue;
|
||||
|
||||
const auto RES = applyDynamicRule(WR);
|
||||
needsRelayout = needsRelayout || RES.needsRelayout;
|
||||
}
|
||||
|
||||
m_window->updateDecorationValues();
|
||||
|
||||
if (needsRelayout)
|
||||
g_pDecorationPositioner->forceRecalcFor(m_window.lock());
|
||||
}
|
||||
148
src/desktop/rule/windowRule/WindowRuleApplicator.hpp
Normal file
148
src/desktop/rule/windowRule/WindowRuleApplicator.hpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "WindowRuleEffectContainer.hpp"
|
||||
#include "../../DesktopTypes.hpp"
|
||||
#include "../Rule.hpp"
|
||||
#include "../../types/OverridableVar.hpp"
|
||||
#include "../../../helpers/math/Math.hpp"
|
||||
#include "../../../helpers/TagKeeper.hpp"
|
||||
#include "../../../config/ConfigDataValues.hpp"
|
||||
|
||||
namespace Desktop::Rule {
|
||||
class CWindowRule;
|
||||
|
||||
enum eIdleInhibitMode : uint8_t {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
IDLEINHIBIT_ALWAYS,
|
||||
IDLEINHIBIT_FULLSCREEN,
|
||||
IDLEINHIBIT_FOCUS
|
||||
};
|
||||
|
||||
class CWindowRuleApplicator {
|
||||
public:
|
||||
CWindowRuleApplicator(PHLWINDOW w);
|
||||
~CWindowRuleApplicator() = default;
|
||||
|
||||
CWindowRuleApplicator(const CWindowRuleApplicator&) = delete;
|
||||
CWindowRuleApplicator(CWindowRuleApplicator&) = delete;
|
||||
CWindowRuleApplicator(CWindowRuleApplicator&&) = delete;
|
||||
|
||||
void propertiesChanged(std::underlying_type_t<eRuleProperty> props);
|
||||
void resetProps(std::underlying_type_t<eRuleProperty> props, Types::eOverridePriority prio = Types::PRIORITY_WINDOW_RULE);
|
||||
void readStaticRules();
|
||||
void applyStaticRules();
|
||||
|
||||
// static props
|
||||
struct {
|
||||
std::string monitor, workspace, group;
|
||||
|
||||
std::optional<bool> floating;
|
||||
|
||||
bool fullscreen = false;
|
||||
bool maximize = false;
|
||||
bool pseudo = false;
|
||||
bool pin = false;
|
||||
bool noInitialFocus = false;
|
||||
|
||||
std::optional<int> fullscreenStateClient;
|
||||
std::optional<int> fullscreenStateInternal;
|
||||
std::optional<int> center;
|
||||
std::optional<int> content;
|
||||
std::optional<int> noCloseFor;
|
||||
|
||||
std::string size, position;
|
||||
|
||||
std::vector<std::string> suppressEvent;
|
||||
} static_;
|
||||
|
||||
struct SCustomPropContainer {
|
||||
CWindowRuleEffectContainer::storageType idx = WINDOW_RULE_EFFECT_NONE;
|
||||
std::underlying_type_t<eRuleProperty> propMask = RULE_PROP_NONE;
|
||||
std::string effect;
|
||||
};
|
||||
|
||||
// This struct holds props that were dynamically registered. Plugins may read this.
|
||||
struct {
|
||||
std::unordered_map<CWindowRuleEffectContainer::storageType, UP<SCustomPropContainer>> props;
|
||||
} m_otherProps;
|
||||
|
||||
#define COMMA ,
|
||||
#define DEFINE_PROP(type, name, def) \
|
||||
private: \
|
||||
std::pair<Types::COverridableVar<type>, std::underlying_type_t<eRuleProperty>> m_##name = {def, RULE_PROP_NONE}; \
|
||||
\
|
||||
public: \
|
||||
Types::COverridableVar<type>& name() { \
|
||||
return m_##name.first; \
|
||||
} \
|
||||
void name##Override(const Types::COverridableVar<type>& other) { \
|
||||
m_##name.first = other; \
|
||||
}
|
||||
|
||||
// dynamic props
|
||||
DEFINE_PROP(Types::SAlphaValue, alpha, Types::SAlphaValue{})
|
||||
DEFINE_PROP(Types::SAlphaValue, alphaInactive, Types::SAlphaValue{})
|
||||
DEFINE_PROP(Types::SAlphaValue, alphaFullscreen, Types::SAlphaValue{})
|
||||
|
||||
DEFINE_PROP(bool, allowsInput, false)
|
||||
DEFINE_PROP(bool, decorate, true)
|
||||
DEFINE_PROP(bool, focusOnActivate, false)
|
||||
DEFINE_PROP(bool, keepAspectRatio, false)
|
||||
DEFINE_PROP(bool, nearestNeighbor, false)
|
||||
DEFINE_PROP(bool, noAnim, false)
|
||||
DEFINE_PROP(bool, noBlur, false)
|
||||
DEFINE_PROP(bool, noDim, false)
|
||||
DEFINE_PROP(bool, noFocus, false)
|
||||
DEFINE_PROP(bool, noMaxSize, false)
|
||||
DEFINE_PROP(bool, noShadow, false)
|
||||
DEFINE_PROP(bool, noShortcutsInhibit, false)
|
||||
DEFINE_PROP(bool, opaque, false)
|
||||
DEFINE_PROP(bool, dimAround, false)
|
||||
DEFINE_PROP(bool, RGBX, false)
|
||||
DEFINE_PROP(bool, syncFullscreen, true)
|
||||
DEFINE_PROP(bool, tearing, false)
|
||||
DEFINE_PROP(bool, xray, false)
|
||||
DEFINE_PROP(bool, renderUnfocused, false)
|
||||
DEFINE_PROP(bool, noFollowMouse, false)
|
||||
DEFINE_PROP(bool, noScreenShare, false)
|
||||
DEFINE_PROP(bool, noVRR, false)
|
||||
DEFINE_PROP(bool, persistentSize, false)
|
||||
DEFINE_PROP(bool, stayFocused, false)
|
||||
|
||||
DEFINE_PROP(int, idleInhibitMode, false)
|
||||
|
||||
DEFINE_PROP(Hyprlang::INT, borderSize, {std::string("general:border_size") COMMA sc<Hyprlang::INT>(0) COMMA std::nullopt})
|
||||
DEFINE_PROP(Hyprlang::INT, rounding, {std::string("decoration:rounding") COMMA sc<Hyprlang::INT>(0) COMMA std::nullopt})
|
||||
|
||||
DEFINE_PROP(Hyprlang::FLOAT, roundingPower, {std::string("decoration:rounding_power")})
|
||||
DEFINE_PROP(Hyprlang::FLOAT, scrollMouse, {std::string("input:scroll_factor")})
|
||||
DEFINE_PROP(Hyprlang::FLOAT, scrollTouchpad, {std::string("input:touchpad:scroll_factor")})
|
||||
|
||||
DEFINE_PROP(std::string, animationStyle, std::string(""))
|
||||
|
||||
DEFINE_PROP(Vector2D, maxSize, Vector2D{})
|
||||
DEFINE_PROP(Vector2D, minSize, Vector2D{})
|
||||
|
||||
DEFINE_PROP(CGradientValueData, activeBorderColor, {})
|
||||
DEFINE_PROP(CGradientValueData, inactiveBorderColor, {})
|
||||
|
||||
std::vector<std::pair<std::string, std::underlying_type_t<eRuleProperty>>> m_dynamicTags;
|
||||
CTagKeeper m_tagKeeper;
|
||||
|
||||
#undef COMMA
|
||||
#undef DEFINE_PROP
|
||||
|
||||
private:
|
||||
PHLWINDOWREF m_window;
|
||||
|
||||
struct SRuleResult {
|
||||
bool needsRelayout = false;
|
||||
bool tagsChanged = false;
|
||||
};
|
||||
|
||||
SRuleResult applyDynamicRule(const SP<CWindowRule>& rule);
|
||||
SRuleResult applyStaticRule(const SP<CWindowRule>& rule);
|
||||
};
|
||||
};
|
||||
76
src/desktop/rule/windowRule/WindowRuleEffectContainer.cpp
Normal file
76
src/desktop/rule/windowRule/WindowRuleEffectContainer.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#include "WindowRuleEffectContainer.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::Rule;
|
||||
|
||||
//
|
||||
SP<CWindowRuleEffectContainer> Rule::windowEffects() {
|
||||
static SP<CWindowRuleEffectContainer> container = makeShared<CWindowRuleEffectContainer>();
|
||||
return container;
|
||||
}
|
||||
|
||||
static const std::vector<std::string> EFFECT_STRINGS = {
|
||||
"__internal_none", //
|
||||
"float", //
|
||||
"tile", //
|
||||
"fullscreen", //
|
||||
"maximize", //
|
||||
"fullscreen_state", //
|
||||
"move", //
|
||||
"size", //
|
||||
"center", //
|
||||
"pseudo", //
|
||||
"monitor", //
|
||||
"workspace", //
|
||||
"no_initial_focus", //
|
||||
"pin", //
|
||||
"group", //
|
||||
"suppress_event", //
|
||||
"content", //
|
||||
"no_close_for", //
|
||||
"rounding", //
|
||||
"rounding_power", //
|
||||
"persistent_size", //
|
||||
"animation", //
|
||||
"border_color", //
|
||||
"idle_inhibit", //
|
||||
"opacity", //
|
||||
"tag", //
|
||||
"max_size", //
|
||||
"min_size", //
|
||||
"border_size", //
|
||||
"allows_input", //
|
||||
"dim_around", //
|
||||
"decorate", //
|
||||
"focus_on_activate", //
|
||||
"keep_aspect_ratio", //
|
||||
"nearest_neighbor", //
|
||||
"no_anim", //
|
||||
"no_blur", //
|
||||
"no_dim", //
|
||||
"no_focus", //
|
||||
"no_follow_mouse", //
|
||||
"no_max_size", //
|
||||
"no_shadow", //
|
||||
"no_shortcuts_inhibit", //
|
||||
"opaque", //
|
||||
"force_rgbx", //
|
||||
"sync_fullscreen", //
|
||||
"immediate", //
|
||||
"xray", //
|
||||
"render_unfocused", //
|
||||
"no_screen_share", //
|
||||
"no_vrr", //
|
||||
"scroll_mouse", //
|
||||
"scroll_touchpad", //
|
||||
"stay_focused", //
|
||||
"__internal_last_static", //
|
||||
};
|
||||
|
||||
// This is here so that if we change the rules, we get reminded to update
|
||||
// the strings.
|
||||
static_assert(WINDOW_RULE_EFFECT_LAST_STATIC == 54);
|
||||
|
||||
CWindowRuleEffectContainer::CWindowRuleEffectContainer() : IEffectContainer<eWindowRuleEffect>(std::vector<std::string>{EFFECT_STRINGS}) {
|
||||
;
|
||||
}
|
||||
79
src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp
Normal file
79
src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include "../effect/EffectContainer.hpp"
|
||||
#include "../../../helpers/memory/Memory.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Desktop::Rule {
|
||||
enum eWindowRuleEffect : uint8_t {
|
||||
WINDOW_RULE_EFFECT_NONE = 0,
|
||||
|
||||
// static
|
||||
WINDOW_RULE_EFFECT_FLOAT,
|
||||
WINDOW_RULE_EFFECT_TILE,
|
||||
WINDOW_RULE_EFFECT_FULLSCREEN,
|
||||
WINDOW_RULE_EFFECT_MAXIMIZE,
|
||||
WINDOW_RULE_EFFECT_FULLSCREENSTATE,
|
||||
WINDOW_RULE_EFFECT_MOVE,
|
||||
WINDOW_RULE_EFFECT_SIZE,
|
||||
WINDOW_RULE_EFFECT_CENTER,
|
||||
WINDOW_RULE_EFFECT_PSEUDO,
|
||||
WINDOW_RULE_EFFECT_MONITOR,
|
||||
WINDOW_RULE_EFFECT_WORKSPACE,
|
||||
WINDOW_RULE_EFFECT_NOINITIALFOCUS,
|
||||
WINDOW_RULE_EFFECT_PIN,
|
||||
WINDOW_RULE_EFFECT_GROUP,
|
||||
WINDOW_RULE_EFFECT_SUPPRESSEVENT,
|
||||
WINDOW_RULE_EFFECT_CONTENT,
|
||||
WINDOW_RULE_EFFECT_NOCLOSEFOR,
|
||||
|
||||
// dynamic
|
||||
WINDOW_RULE_EFFECT_ROUNDING,
|
||||
WINDOW_RULE_EFFECT_ROUNDING_POWER,
|
||||
WINDOW_RULE_EFFECT_PERSISTENT_SIZE,
|
||||
WINDOW_RULE_EFFECT_ANIMATION,
|
||||
WINDOW_RULE_EFFECT_BORDER_COLOR,
|
||||
WINDOW_RULE_EFFECT_IDLE_INHIBIT,
|
||||
WINDOW_RULE_EFFECT_OPACITY,
|
||||
WINDOW_RULE_EFFECT_TAG,
|
||||
WINDOW_RULE_EFFECT_MAX_SIZE,
|
||||
WINDOW_RULE_EFFECT_MIN_SIZE,
|
||||
WINDOW_RULE_EFFECT_BORDER_SIZE,
|
||||
WINDOW_RULE_EFFECT_ALLOWS_INPUT,
|
||||
WINDOW_RULE_EFFECT_DIM_AROUND,
|
||||
WINDOW_RULE_EFFECT_DECORATE,
|
||||
WINDOW_RULE_EFFECT_FOCUS_ON_ACTIVATE,
|
||||
WINDOW_RULE_EFFECT_KEEP_ASPECT_RATIO,
|
||||
WINDOW_RULE_EFFECT_NEAREST_NEIGHBOR,
|
||||
WINDOW_RULE_EFFECT_NO_ANIM,
|
||||
WINDOW_RULE_EFFECT_NO_BLUR,
|
||||
WINDOW_RULE_EFFECT_NO_DIM,
|
||||
WINDOW_RULE_EFFECT_NO_FOCUS,
|
||||
WINDOW_RULE_EFFECT_NO_FOLLOW_MOUSE,
|
||||
WINDOW_RULE_EFFECT_NO_MAX_SIZE,
|
||||
WINDOW_RULE_EFFECT_NO_SHADOW,
|
||||
WINDOW_RULE_EFFECT_NO_SHORTCUTS_INHIBIT,
|
||||
WINDOW_RULE_EFFECT_OPAQUE,
|
||||
WINDOW_RULE_EFFECT_FORCE_RGBX,
|
||||
WINDOW_RULE_EFFECT_SYNC_FULLSCREEN,
|
||||
WINDOW_RULE_EFFECT_IMMEDIATE,
|
||||
WINDOW_RULE_EFFECT_XRAY,
|
||||
WINDOW_RULE_EFFECT_RENDER_UNFOCUSED,
|
||||
WINDOW_RULE_EFFECT_NO_SCREEN_SHARE,
|
||||
WINDOW_RULE_EFFECT_NO_VRR,
|
||||
WINDOW_RULE_EFFECT_SCROLL_MOUSE,
|
||||
WINDOW_RULE_EFFECT_SCROLL_TOUCHPAD,
|
||||
WINDOW_RULE_EFFECT_STAY_FOCUSED,
|
||||
|
||||
WINDOW_RULE_EFFECT_LAST_STATIC,
|
||||
};
|
||||
|
||||
class CWindowRuleEffectContainer : public IEffectContainer<eWindowRuleEffect> {
|
||||
public:
|
||||
CWindowRuleEffectContainer();
|
||||
virtual ~CWindowRuleEffectContainer() = default;
|
||||
};
|
||||
|
||||
SP<CWindowRuleEffectContainer> windowEffects();
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue