summaryrefslogtreecommitdiff
path: root/src/desktop/rule/layerRule/LayerRuleApplicator.cpp
blob: 8c157dae8337def58d9e7c97a64fb4a31c1fe498 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "LayerRuleApplicator.hpp"
#include "LayerRule.hpp"
#include "../Engine.hpp"
#include "../../view/LayerSurface.hpp"
#include "../../types/OverridableVar.hpp"
#include "../../../helpers/MiscFunctions.hpp"
#include "../../../event/EventBus.hpp"
#include <tuple>

using namespace Desktop;
using namespace Desktop::Rule;

namespace {
    template <typename T>
    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) {
        auto& [value, propMask] = prop;

        if (!(propMask & props))
            return;

        if (prio == Desktop::Types::PRIORITY_WINDOW_RULE)
            propMask &= ~props;

        value.unset(prio);
    }
}

CLayerRuleApplicator::CLayerRuleApplicator(PHLLS ls) : m_ls(ls) {
    ;
}

void CLayerRuleApplicator::resetProps(std::underlying_type_t<eRuleProperty> props, Types::eOverridePriority prio) {
    std::apply([&](auto&... prop) { (resetRuleProp(prop, props, prio), ...); },
               std::forward_as_tuple(m_noanim, m_blur, m_blurPopups, m_dimAround, m_xray, m_noScreenShare, m_order, m_aboveLock, m_ignoreAlpha, m_animationStyle));

    if (prio == Types::PRIORITY_WINDOW_RULE)
        std::erase_if(m_otherProps.props, [props](const auto& el) { return !el.second || el.second->propMask & props; });
}

void CLayerRuleApplicator::applyDynamicRule(const SP<CLayerRule>& rule) {
    for (const auto& [key, effect] : rule->effects()) {
        switch (key) {
            default: {
                if (key <= LAYER_RULE_EFFECT_LAST_STATIC) {
                    Log::logger->log(Log::TRACE, "CLayerRuleApplicator::applyDynamicRule: Skipping effect {}, not dynamic", sc<std::underlying_type_t<eLayerRuleEffect>>(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 LAYER_RULE_EFFECT_NONE: {
                Log::logger->log(Log::ERR, "CLayerRuleApplicator::applyDynamicRule: BUG THIS: LAYER_RULE_EFFECT_NONE??");
                break;
            }
            case LAYER_RULE_EFFECT_NO_ANIM: {
                m_noanim.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
                m_noanim.second |= rule->getPropertiesMask();
                break;
            }
            case LAYER_RULE_EFFECT_BLUR: {
                m_blur.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
                m_blur.second |= rule->getPropertiesMask();
                break;
            }
            case LAYER_RULE_EFFECT_BLUR_POPUPS: {
                m_blurPopups.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
                m_blurPopups.second |= rule->getPropertiesMask();
                break;
            }
            case LAYER_RULE_EFFECT_DIM_AROUND: {
                m_dimAround.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
                m_dimAround.second |= rule->getPropertiesMask();
                break;
            }
            case LAYER_RULE_EFFECT_XRAY: {
                m_xray.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
                m_xray.second |= rule->getPropertiesMask();
                break;
            }
            case LAYER_RULE_EFFECT_NO_SCREEN_SHARE: {
                m_noScreenShare.first.set(truthy(effect), Types::PRIORITY_WINDOW_RULE);
                m_noScreenShare.second |= rule->getPropertiesMask();
                break;
            }
            case LAYER_RULE_EFFECT_ORDER: {
                try {
                    m_order.first.set(std::stoi(effect), Types::PRIORITY_WINDOW_RULE);
                    m_order.second |= rule->getPropertiesMask();
                } catch (...) { Log::logger->log(Log::ERR, "CLayerRuleApplicator::applyDynamicRule: invalid order {}", effect); }
                break;
            }
            case LAYER_RULE_EFFECT_ABOVE_LOCK: {
                try {
                    m_aboveLock.first.set(std::clamp(std::stoull(effect), 0ULL, 2ULL), Types::PRIORITY_WINDOW_RULE);
                    m_aboveLock.second |= rule->getPropertiesMask();
                } catch (...) { Log::logger->log(Log::ERR, "CLayerRuleApplicator::applyDynamicRule: invalid order {}", effect); }
                break;
            }
            case LAYER_RULE_EFFECT_IGNORE_ALPHA: {
                try {
                    m_ignoreAlpha.first.set(std::clamp(std::stof(effect), 0.F, 1.F), Types::PRIORITY_WINDOW_RULE);
                    m_ignoreAlpha.second |= rule->getPropertiesMask();
                } catch (...) { Log::logger->log(Log::ERR, "CLayerRuleApplicator::applyDynamicRule: invalid order {}", effect); }
                break;
            }
            case LAYER_RULE_EFFECT_ANIMATION: {
                m_animationStyle.first.set(effect, Types::PRIORITY_WINDOW_RULE);
                m_animationStyle.second |= rule->getPropertiesMask();
                break;
            }
        }
    }
}

void CLayerRuleApplicator::propertiesChanged(std::underlying_type_t<eRuleProperty> props) {
    if (!m_ls)
        return;

    resetProps(props);

    // FIXME: this will not update properties correctly if we implement dynamic rules for
    // layers, due to effects overlapping on 0 prop intersection.
    // See WindowRule.cpp, and ::propertiesChanged there.

    for (const auto& r : ruleEngine()->rules()) {
        if (r->type() != RULE_TYPE_LAYER)
            continue;

        if (!(r->getPropertiesMask() & props))
            continue;

        auto wr = reinterpretPointerCast<CLayerRule>(r);

        if (!wr->matches(m_ls.lock()))
            continue;

        applyDynamicRule(wr);
    }

    // for plugins
    Event::bus()->m_events.layer.updateRules.emit(m_ls.lock());
}