windowrules: allow incrementing window props (#9566)

This commit is contained in:
MightyPlaza
2025-04-15 23:00:40 +00:00
committed by GitHub
parent 8b7b169043
commit ffd6cf65e4
21 changed files with 191 additions and 102 deletions

View File

@@ -0,0 +1,15 @@
#include "ConfigValue.hpp"
#include "ConfigManager.hpp"
#include "../macros.hpp"
void local__configValuePopulate(void* const** p, const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
*p = PVHYPRLANG->getDataStaticPtr();
}
std::type_index local__configValueTypeIdx(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
const auto ANY = PVHYPRLANG->getValue();
return std::type_index(ANY.type());
}

View File

@@ -4,21 +4,19 @@
#include <typeindex>
#include <hyprlang.hpp>
#include "../macros.hpp"
#include "ConfigManager.hpp"
// giga hack to avoid including configManager here
// NOLINTNEXTLINE
void local__configValuePopulate(void* const** p, const std::string& val);
std::type_index local__configValueTypeIdx(const std::string& val);
template <typename T>
class CConfigValue {
public:
CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
// NOLINTNEXTLINE
p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG
// verify type
const auto ANY = PVHYPRLANG->getValue();
const auto TYPE = std::type_index(ANY.type());
const auto TYPE = local__configValueTypeIdx(val);
// exceptions
const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING));
@@ -26,6 +24,8 @@ class CConfigValue {
RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name());
#endif
local__configValuePopulate(&p_, val);
}
T* ptr() const {

View File

@@ -11,6 +11,7 @@
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../render/decorations/CHyprBorderDecoration.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../managers/TokenManager.hpp"
#include "../managers/AnimationManager.hpp"
#include "../managers/ANRManager.hpp"
@@ -780,7 +781,7 @@ void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
const CVarList VARS(r->szRule, 0, ' ');
if (auto search = NWindowProperties::intWindowProperties.find(VARS[1]); search != NWindowProperties::intWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(Hyprlang::INT(std::stoi(VARS[2])), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = NWindowProperties::floatWindowProperties.find(VARS[1]); search != NWindowProperties::floatWindowProperties.end()) {
try {

View File

@@ -19,6 +19,7 @@
#include "WLSurface.hpp"
#include "Workspace.hpp"
#include "WindowRule.hpp"
#include "WindowOverridableVar.hpp"
#include "../protocols/types/ContentType.hpp"
class CXDGSurfaceResource;
@@ -77,88 +78,6 @@ struct SAlphaValue {
};
};
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value;
}
CWindowOverridableVar(T const& value) : defaultValue{value} {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
for (auto const& value : other.values) {
values[value.first] = value.second;
}
return *this;
}
void unset(eOverridePriority priority) {
values.erase(priority);
}
bool hasValue() {
return !values.empty();
}
T value() {
if (!values.empty())
return std::prev(values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
T valueOrDefault() {
return valueOr(defaultValue);
}
eOverridePriority getPriority() {
if (!values.empty())
return std::prev(values.end())->first;
else
throw std::bad_optional_access();
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool
};
struct SWindowData {
CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false};
CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false};
@@ -186,12 +105,12 @@ struct SWindowData {
CWindowOverridableVar<bool> xray = false;
CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<int> rounding;
CWindowOverridableVar<float> roundingPower;
CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<Hyprlang::INT> borderSize = {std::string("general:border_size"), Hyprlang::INT(0), std::nullopt};
CWindowOverridableVar<Hyprlang::INT> rounding = {std::string("decoration:rounding"), Hyprlang::INT(0), std::nullopt};
CWindowOverridableVar<float> scrollMouse;
CWindowOverridableVar<float> scrollTouchpad;
CWindowOverridableVar<Hyprlang::FLOAT> roundingPower = {std::string("decoration:rounding_power")};
CWindowOverridableVar<Hyprlang::FLOAT> scrollMouse = {std::string("input:scroll_factor")};
CWindowOverridableVar<Hyprlang::FLOAT> scrollTouchpad = {std::string("input:touchpad:scroll_factor")};
CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize;
@@ -567,12 +486,12 @@ namespace NWindowProperties {
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> intWindowProperties = {
const std::unordered_map<std::string, std::function<CWindowOverridableVar<Hyprlang::INT>*(const PHLWINDOW&)>> intWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
const std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> floatWindowProperties = {
const std::unordered_map<std::string, std::function<CWindowOverridableVar<Hyprlang::FLOAT>*(PHLWINDOW)>> floatWindowProperties = {
{"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.roundingPower; }},
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }},

View File

@@ -0,0 +1,132 @@
#pragma once
#include <cstdint>
#include <type_traits>
#include <any>
#include "../config/ConfigValue.hpp"
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T>
T clampOptional(T const& value, std::optional<T> const& min, std::optional<T> const& max) {
return std::clamp(value, min.value_or(std::numeric_limits<T>::min()), max.value_or(std::numeric_limits<T>::max()));
}
template <typename T, bool Extended = std::is_same_v<T, bool> || std::is_same_v<T, Hyprlang::INT> || std::is_same_v<T, Hyprlang::FLOAT>>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T const& value, eOverridePriority priority) {
m_values[priority] = value;
}
CWindowOverridableVar(T const& value) : m_defaultValue{value} {}
CWindowOverridableVar(T const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt) : m_defaultValue{value}, m_minValue{min}, m_maxValue{max} {}
CWindowOverridableVar(std::string const& value)
requires(Extended && !std::is_same_v<T, bool>)
: m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
CWindowOverridableVar(std::string const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt)
requires(Extended && !std::is_same_v<T, bool>)
: m_minValue(min), m_maxValue(max), m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
for (auto const& value : other.m_values) {
if constexpr (Extended && !std::is_same_v<T, bool>)
m_values[value.first] = clampOptional(value.second, m_minValue, m_maxValue);
else
m_values[value.first] = value.second;
}
return *this;
}
void unset(eOverridePriority priority) {
m_values.erase(priority);
}
bool hasValue() {
return !m_values.empty();
}
T value() {
if (!m_values.empty())
return std::prev(m_values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
T valueOrDefault()
requires(Extended && !std::is_same_v<T, bool>)
{
if (hasValue())
return value();
else if (m_defaultValue.has_value())
return m_defaultValue.value();
else
return **std::any_cast<SP<CConfigValue<T>>>(m_configValue);
}
T valueOrDefault()
requires(!Extended || std::is_same_v<T, bool>)
{
if (hasValue())
return value();
else if (!m_defaultValue.has_value())
throw std::bad_optional_access();
else
return m_defaultValue.value();
}
eOverridePriority getPriority() {
if (!m_values.empty())
return std::prev(m_values.end())->first;
else
throw std::bad_optional_access();
}
void increment(T const& other, eOverridePriority priority) {
if constexpr (std::is_same_v<T, bool>)
m_values[priority] = valueOr(false) ^ other;
else
m_values[priority] = clampOptional(valueOrDefault() + other, m_minValue, m_maxValue);
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
m_values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::map<eOverridePriority, T> m_values;
std::optional<T> m_defaultValue; // used for toggling, so required for bool
std::optional<T> m_minValue;
std::optional<T> m_maxValue;
std::any m_configValue; // only there for select variables
};

View File

@@ -7,6 +7,7 @@
#include "../managers/SeatManager.hpp"
#include "../render/Renderer.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"

View File

@@ -6,6 +6,7 @@
#include "sync/SyncReleaser.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../protocols/GammaControl.hpp"
#include "../devices/ITouch.hpp"
#include "../protocols/LayerShell.hpp"

View File

@@ -2,6 +2,7 @@
#include "HyprError.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../render/pass/TexPassElement.hpp"
#include "../managers/AnimationManager.hpp"
#include "../render/Renderer.hpp"

View File

@@ -1,6 +1,7 @@
#include "DwindleLayout.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp"

View File

@@ -3,6 +3,7 @@
#include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../desktop/Window.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"

View File

@@ -4,6 +4,7 @@
#include "config/ConfigDataValues.hpp"
#include <ranges>
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp"
#include "../managers/LayoutManager.hpp"

View File

@@ -4,6 +4,7 @@
#include "PointerManager.hpp"
#include "../xwayland/XWayland.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../helpers/Monitor.hpp"
static int cursorAnimTimer(SP<CEventLoopTimer> self, void* data) {
const auto cursorMgr = reinterpret_cast<CCursorManager*>(data);

View File

@@ -18,6 +18,7 @@
#include "../managers/EventManager.hpp"
#include "../render/Renderer.hpp"
#include "../hyprerror/HyprError.hpp"
#include "../config/ConfigManager.hpp"
#include <optional>
#include <iterator>
@@ -3221,7 +3222,7 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
} else if (auto search = NWindowProperties::boolWindowProperties.find(PROP); search != NWindowProperties::boolWindowProperties.end()) {
auto pWindowDataElement = search->second(PWINDOW);
if (VAL == "toggle")
*pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
pWindowDataElement->increment(true, PRIORITY_SET_PROP);
else if (VAL == "unset")
pWindowDataElement->unset(PRIORITY_SET_PROP);
else
@@ -3229,12 +3230,18 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
} else if (auto search = NWindowProperties::intWindowProperties.find(PROP); search != NWindowProperties::intWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else if (const auto V = configStringToInt(VAL); V)
*(search->second(PWINDOW)) = CWindowOverridableVar((int)*V, PRIORITY_SET_PROP);
else if (VAL.starts_with("relative")) {
const Hyprlang::INT V = std::stoi(VAL.substr(VAL.find(' ')));
search->second(PWINDOW)->increment(V, PRIORITY_SET_PROP);
} else if (const auto V = configStringToInt(VAL); V)
*(search->second(PWINDOW)) = CWindowOverridableVar((Hyprlang::INT)*V, PRIORITY_SET_PROP);
} else if (auto search = NWindowProperties::floatWindowProperties.find(PROP); search != NWindowProperties::floatWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else {
else if (VAL.starts_with("relative")) {
const auto V = std::stof(VAL.substr(VAL.find(' ')));
search->second(PWINDOW)->increment(V, PRIORITY_SET_PROP);
} else {
const auto V = std::stof(VAL);
*(search->second(PWINDOW)) = CWindowOverridableVar(V, PRIORITY_SET_PROP);
}

View File

@@ -1,6 +1,7 @@
#include "PointerManager.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../protocols/PointerGestures.hpp"
#include "../protocols/RelativePointer.hpp"
#include "../protocols/FractionalScale.hpp"

View File

@@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../events/Events.hpp"
#include "../config/ConfigValue.hpp"
#include "../helpers/Monitor.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../xwayland/XWayland.hpp"

View File

@@ -4,6 +4,7 @@
#include <cstdint>
#include <ranges>
#include "../../config/ConfigValue.hpp"
#include "../../config/ConfigManager.hpp"
#include "../../desktop/Window.hpp"
#include "../../desktop/LayerSurface.hpp"
#include "../../protocols/CursorShape.hpp"

View File

@@ -4,6 +4,7 @@
#include "../../Compositor.hpp"
#include "../../desktop/LayerSurface.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../helpers/Monitor.hpp"
#include "../../devices/ITouch.hpp"
#include "../SeatManager.hpp"
#include "managers/AnimationManager.hpp"

View File

@@ -3,6 +3,7 @@
#include "../render/Renderer.hpp"
#include "core/Output.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "managers/AnimationManager.hpp"
#include "../helpers/Monitor.hpp"

View File

@@ -1,5 +1,6 @@
#include "XDGOutput.hpp"
#include "../config/ConfigValue.hpp"
#include "../helpers/Monitor.hpp"
#include "../xwayland/XWayland.hpp"
#include "../managers/HookSystemManager.hpp"
#include "core/Output.hpp"

View File

@@ -7,6 +7,7 @@
#include "../Compositor.hpp"
#include "../helpers/MiscFunctions.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../desktop/LayerSurface.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"

View File

@@ -6,6 +6,7 @@
#include <aquamarine/output/Output.hpp>
#include <filesystem>
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../managers/CursorManager.hpp"
#include "../managers/PointerManager.hpp"
#include "../managers/input/InputManager.hpp"