windowrules: rewrite completely (#12269)

Reworks the window rule syntax completely

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
Vaxry 2025-11-17 18:34:02 +00:00 committed by GitHub
parent 95ee08b340
commit c2670e9ab9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 3574 additions and 2255 deletions

View file

@ -24,6 +24,7 @@
#include "../protocols/FractionalScale.hpp"
#include "../xwayland/XWayland.hpp"
#include "../helpers/Color.hpp"
#include "../helpers/math/Expression.hpp"
#include "../events/Events.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../render/Renderer.hpp"
@ -41,8 +42,9 @@ using enum NContentType::eContentType;
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
pWindow->m_self = pWindow;
pWindow->m_isX11 = true;
pWindow->m_self = pWindow;
pWindow->m_isX11 = true;
pWindow->m_ruleApplicator = makeUnique<Desktop::Rule::CWindowRuleApplicator>(pWindow);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_realPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_realSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
@ -67,6 +69,7 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
pWindow->m_self = pWindow;
resource->m_toplevel->m_window = pWindow;
pWindow->m_ruleApplicator = makeUnique<Desktop::Rule::CWindowRuleApplicator>(pWindow);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_realPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_realSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
@ -138,7 +141,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
const int BORDERSIZE = getRealBorderSize();
if (m_windowData.dimAround.valueOrDefault()) {
if (m_ruleApplicator->dimAround().valueOrDefault()) {
if (const auto PMONITOR = m_monitor.lock(); PMONITOR)
return {.topLeft = {m_realPosition->value().x - PMONITOR->m_position.x, m_realPosition->value().y - PMONITOR->m_position.y},
.bottomRight = {PMONITOR->m_size.x - (m_realPosition->value().x - PMONITOR->m_position.x),
@ -191,7 +194,7 @@ SBoxExtents CWindow::getFullWindowExtents() {
}
CBox CWindow::getFullWindowBoundingBox() {
if (m_windowData.dimAround.valueOrDefault()) {
if (m_ruleApplicator->dimAround().valueOrDefault()) {
if (const auto PMONITOR = m_monitor.lock(); PMONITOR)
return {PMONITOR->m_position.x, PMONITOR->m_position.y, PMONITOR->m_size.x, PMONITOR->m_size.y};
}
@ -251,7 +254,7 @@ SBoxExtents CWindow::getWindowExtentsUnified(uint64_t properties) {
}
CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_windowData.dimAround.valueOrDefault()) {
if (m_ruleApplicator->dimAround().valueOrDefault()) {
const auto PMONITOR = m_monitor.lock();
if (PMONITOR)
return {PMONITOR->m_position.x, PMONITOR->m_position.y, PMONITOR->m_size.x, PMONITOR->m_size.y};
@ -636,222 +639,6 @@ bool CWindow::isHidden() {
return m_hidden;
}
void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
const eOverridePriority priority = r->m_execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
static auto PCLAMP_TILED = CConfigValue<Hyprlang::INT>("misc:size_limits_tiled");
switch (r->m_ruleType) {
case CWindowRule::RULE_TAG: {
CVarList vars{r->m_rule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r->m_rule);
break;
}
case CWindowRule::RULE_OPACITY: {
try {
CVarList vars(r->m_rule, 0, ' ');
int opacityIDX = 0;
for (auto const& r : vars) {
if (r == "opacity")
continue;
if (r == "override") {
if (opacityIDX == 1)
m_windowData.alpha = CWindowOverridableVar(SAlphaValue{.alpha = m_windowData.alpha.value().alpha, .overridden = true}, priority);
else if (opacityIDX == 2)
m_windowData.alphaInactive = CWindowOverridableVar(SAlphaValue{.alpha = m_windowData.alphaInactive.value().alpha, .overridden = true}, priority);
else if (opacityIDX == 3)
m_windowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{.alpha = m_windowData.alphaFullscreen.value().alpha, .overridden = true}, priority);
} else {
if (opacityIDX == 0) {
m_windowData.alpha = CWindowOverridableVar(SAlphaValue{.alpha = std::stof(r), .overridden = false}, priority);
} else if (opacityIDX == 1) {
m_windowData.alphaInactive = CWindowOverridableVar(SAlphaValue{.alpha = std::stof(r), .overridden = false}, priority);
} else if (opacityIDX == 2) {
m_windowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{.alpha = std::stof(r), .overridden = false}, priority);
} else {
throw std::runtime_error("more than 3 alpha values");
}
opacityIDX++;
}
}
if (opacityIDX == 1) {
m_windowData.alphaInactive = m_windowData.alpha;
m_windowData.alphaFullscreen = m_windowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r->m_rule, e.what()); }
break;
}
case CWindowRule::RULE_ANIMATION: {
auto STYLE = r->m_rule.substr(r->m_rule.find_first_of(' ') + 1);
m_windowData.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->m_rule.substr(r->m_rule.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_windowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
m_windowData.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_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", r->m_rule);
else if (activeBorderGradient.m_colors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r->m_rule);
else if (inactiveBorderGradient.m_colors.empty())
m_windowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_windowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_windowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r->m_rule, e.what()); }
break;
}
case CWindowRule::RULE_IDLEINHIBIT: {
auto IDLERULE = r->m_rule.substr(r->m_rule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_idleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_idleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_idleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_idleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
break;
}
case CWindowRule::RULE_MAXSIZE: {
try {
if (!m_isFloating && !sc<bool>(*PCLAMP_TILED))
return;
const auto VEC = configStringToVector2D(r->m_rule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_windowData.maxSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(std::nullopt, m_windowData.maxSize.value());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r->m_rule, e.what()); }
break;
}
case CWindowRule::RULE_MINSIZE: {
try {
if (!m_isFloating && !sc<bool>(*PCLAMP_TILED))
return;
const auto VEC = configStringToVector2D(r->m_rule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_windowData.minSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(m_windowData.minSize.value(), std::nullopt);
if (m_groupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r->m_rule, e.what()); }
break;
}
case CWindowRule::RULE_RENDERUNFOCUSED: {
m_windowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_self.lock());
break;
}
case CWindowRule::RULE_PROP: {
const CVarList VARS(r->m_rule, 0, ' ');
if (auto search = NWindowProperties::intWindowProperties.find(VARS[1]); search != NWindowProperties::intWindowProperties.end()) {
try {
*(search->second(m_self.lock())) = CWindowOverridableVar(sc<Hyprlang::INT>(std::stoi(VARS[2])), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->m_rule, e.what()); }
} else if (auto search = NWindowProperties::floatWindowProperties.find(VARS[1]); search != NWindowProperties::floatWindowProperties.end()) {
try {
*(search->second(m_self.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->m_rule, e.what()); }
} else if (auto search = NWindowProperties::boolWindowProperties.find(VARS[1]); search != NWindowProperties::boolWindowProperties.end()) {
try {
*(search->second(m_self.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : sc<bool>(std::stoi(VARS[2])), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->m_rule, e.what()); }
}
break;
}
case CWindowRule::RULE_PERSISTENTSIZE: {
m_windowData.persistentSize = CWindowOverridableVar(true, PRIORITY_WINDOW_RULE);
break;
}
case CWindowRule::RULE_NOVRR: {
m_windowData.noVRR = CWindowOverridableVar(true, priority);
break;
}
default: break;
}
}
void CWindow::updateDynamicRules() {
m_windowData.alpha.unset(PRIORITY_WINDOW_RULE);
m_windowData.alphaInactive.unset(PRIORITY_WINDOW_RULE);
m_windowData.alphaFullscreen.unset(PRIORITY_WINDOW_RULE);
unsetWindowData(PRIORITY_WINDOW_RULE);
m_windowData.animationStyle.unset(PRIORITY_WINDOW_RULE);
m_windowData.maxSize.unset(PRIORITY_WINDOW_RULE);
m_windowData.minSize.unset(PRIORITY_WINDOW_RULE);
m_windowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE);
m_windowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE);
m_windowData.renderUnfocused.unset(PRIORITY_WINDOW_RULE);
m_windowData.noVRR.unset(PRIORITY_WINDOW_RULE);
m_idleInhibitMode = IDLEINHIBIT_NONE;
m_tags.removeDynamicTags();
m_matchedRules = g_pConfigManager->getMatchingRules(m_self.lock());
for (const auto& r : m_matchedRules) {
applyDynamicRule(r);
}
EMIT_HOOK_EVENT("windowUpdateRules", m_self.lock());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
}
// check if the point is "hidden" under a rounded corner of the window
// it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize)
// otherwise behaviour is undefined
@ -924,6 +711,8 @@ void CWindow::createGroup() {
g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("1,{:x}", rc<uintptr_t>(this))});
}
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
}
void CWindow::destroyGroup() {
@ -943,6 +732,7 @@ void CWindow::destroyGroup() {
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("0,{:x}", rc<uintptr_t>(this))});
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
return;
}
@ -969,6 +759,7 @@ void CWindow::destroyGroup() {
g_pKeybindManager->m_groupsLocked = true;
for (auto const& w : members) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
w->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
w->updateWindowDecos();
}
g_pKeybindManager->m_groupsLocked = GROUPSLOCKEDPREV;
@ -982,6 +773,8 @@ void CWindow::destroyGroup() {
if (!addresses.empty())
addresses.pop_back();
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("0,{}", addresses)});
}
@ -1217,16 +1010,16 @@ float CWindow::rounding() {
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
static auto PROUNDINGPOWER = CConfigValue<Hyprlang::FLOAT>("decoration:rounding_power");
float roundingPower = m_windowData.roundingPower.valueOr(*PROUNDINGPOWER);
float rounding = m_windowData.rounding.valueOr(*PROUNDING) * (roundingPower / 2.0); /* Make perceived roundness consistent. */
float roundingPower = m_ruleApplicator->roundingPower().valueOr(*PROUNDINGPOWER);
float rounding = m_ruleApplicator->rounding().valueOr(*PROUNDING) * (roundingPower / 2.0); /* Make perceived roundness consistent. */
return m_windowData.noRounding.valueOrDefault() ? 0 : rounding;
return rounding;
}
float CWindow::roundingPower() {
static auto PROUNDINGPOWER = CConfigValue<Hyprlang::FLOAT>("decoration:rounding_power");
return m_windowData.roundingPower.valueOr(std::clamp(*PROUNDINGPOWER, 1.F, 10.F));
return m_ruleApplicator->roundingPower().valueOr(std::clamp(*PROUNDINGPOWER, 1.F, 10.F));
}
void CWindow::updateWindowData() {
@ -1236,50 +1029,43 @@ void CWindow::updateWindowData() {
}
void CWindow::updateWindowData(const SWorkspaceRule& workspaceRule) {
static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating");
if (*PNOBORDERONFLOATING)
m_windowData.noBorder = CWindowOverridableVar(m_isFloating, PRIORITY_LAYOUT);
else
m_windowData.noBorder.unset(PRIORITY_LAYOUT);
m_windowData.borderSize.matchOptional(workspaceRule.borderSize, PRIORITY_WORKSPACE_RULE);
m_windowData.decorate.matchOptional(workspaceRule.decorate, PRIORITY_WORKSPACE_RULE);
m_windowData.noBorder.matchOptional(workspaceRule.noBorder, PRIORITY_WORKSPACE_RULE);
m_windowData.noRounding.matchOptional(workspaceRule.noRounding, PRIORITY_WORKSPACE_RULE);
m_windowData.noShadow.matchOptional(workspaceRule.noShadow, PRIORITY_WORKSPACE_RULE);
m_ruleApplicator->borderSize().matchOptional(workspaceRule.borderSize, Desktop::Types::PRIORITY_WORKSPACE_RULE);
m_ruleApplicator->decorate().matchOptional(workspaceRule.decorate, Desktop::Types::PRIORITY_WORKSPACE_RULE);
m_ruleApplicator->borderSize().matchOptional(workspaceRule.noBorder ? std::optional<Hyprlang::INT>(0) : std::nullopt, Desktop::Types::PRIORITY_WORKSPACE_RULE);
m_ruleApplicator->rounding().matchOptional(workspaceRule.noRounding.value_or(false) ? std::optional<Hyprlang::INT>(0) : std::nullopt, Desktop::Types::PRIORITY_WORKSPACE_RULE);
m_ruleApplicator->noShadow().matchOptional(workspaceRule.noShadow, Desktop::Types::PRIORITY_WORKSPACE_RULE);
}
int CWindow::getRealBorderSize() {
if (m_windowData.noBorder.valueOrDefault() || (m_workspace && isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) || !m_windowData.decorate.valueOrDefault())
if ((m_workspace && isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) || !m_ruleApplicator->decorate().valueOrDefault())
return 0;
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
return m_windowData.borderSize.valueOr(*PBORDERSIZE);
return m_ruleApplicator->borderSize().valueOr(*PBORDERSIZE);
}
float CWindow::getScrollMouse() {
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
return m_windowData.scrollMouse.valueOr(*PINPUTSCROLLFACTOR);
return m_ruleApplicator->scrollMouse().valueOr(*PINPUTSCROLLFACTOR);
}
float CWindow::getScrollTouchpad() {
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
return m_windowData.scrollTouchpad.valueOr(*PTOUCHPADSCROLLFACTOR);
return m_ruleApplicator->scrollTouchpad().valueOr(*PTOUCHPADSCROLLFACTOR);
}
bool CWindow::isScrollMouseOverridden() {
return m_windowData.scrollMouse.hasValue();
return m_ruleApplicator->scrollMouse().hasValue();
}
bool CWindow::isScrollTouchpadOverridden() {
return m_windowData.scrollTouchpad.hasValue();
return m_ruleApplicator->scrollTouchpad().hasValue();
}
bool CWindow::canBeTorn() {
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
return m_windowData.tearing.valueOr(m_tearingHint) && *PTEARING;
return m_ruleApplicator->tearing().valueOr(m_tearingHint) && *PTEARING;
}
void CWindow::setSuspended(bool suspend) {
@ -1454,7 +1240,8 @@ void CWindow::activate(bool force) {
g_pEventManager->postEvent(SHyprIPCEvent{.event = "urgent", .data = std::format("{:x}", rc<uintptr_t>(this))});
EMIT_HOOK_EVENT("urgent", m_self.lock());
if (!force && (!m_windowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_suppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_suppressedEvents & SUPPRESS_ACTIVATE)))
if (!force &&
(!m_ruleApplicator->focusOnActivate().valueOr(*PFOCUSONACTIVATE) || (m_suppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_suppressedEvents & SUPPRESS_ACTIVATE)))
return;
if (!m_isMapped) {
@ -1539,8 +1326,7 @@ void CWindow::onUpdateMeta() {
}
if (doUpdate) {
updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(m_self.lock());
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_TITLE | Desktop::Rule::RULE_PROP_CLASS);
updateToplevel();
}
}
@ -1718,18 +1504,6 @@ PHLWINDOW CWindow::getSwallower() {
return candidates[0];
}
void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : NWindowProperties::boolWindowProperties) {
element.second(m_self.lock())->unset(priority);
}
for (auto const& element : NWindowProperties::intWindowProperties) {
element.second(m_self.lock())->unset(priority);
}
for (auto const& element : NWindowProperties::floatWindowProperties) {
element.second(m_self.lock())->unset(priority);
}
}
bool CWindow::isX11OverrideRedirect() {
return m_xwaylandSurface && m_xwaylandSurface->m_overrideRedirect;
}
@ -1753,7 +1527,7 @@ Vector2D CWindow::requestedMinSize() {
Vector2D CWindow::requestedMaxSize() {
constexpr int NO_MAX_SIZE_LIMIT = 99999;
if (((m_isX11 && !m_xwaylandSurface->m_sizeHints) || (!m_isX11 && (!m_xdgSurface || !m_xdgSurface->m_toplevel)) || m_windowData.noMaxSize.valueOrDefault()))
if (((m_isX11 && !m_xwaylandSurface->m_sizeHints) || (!m_isX11 && (!m_xdgSurface || !m_xdgSurface->m_toplevel)) || m_ruleApplicator->noMaxSize().valueOrDefault()))
return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT);
Vector2D maxSize = m_isX11 ? Vector2D(m_xwaylandSurface->m_sizeHints->max_width, m_xwaylandSurface->m_sizeHints->max_height) : m_xdgSurface->m_toplevel->layoutMaxSize();
@ -1951,3 +1725,127 @@ Vector2D CWindow::getReportedSize() {
return m_wlSurface->resource()->m_current.ackedSize;
return m_reportedSize;
}
void CWindow::updateDecorationValues() {
static auto PACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.active_border");
static auto PINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.inactive_border");
static auto PNOGROUPACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.nogroup_border_active");
static auto PNOGROUPINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.nogroup_border");
static auto PGROUPACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_active");
static auto PGROUPINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_inactive");
static auto PGROUPACTIVELOCKEDCOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_locked_active");
static auto PGROUPINACTIVELOCKEDCOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_locked_inactive");
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
static auto PFULLSCREENALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:fullscreen_opacity");
static auto PSHADOWCOL = CConfigValue<Hyprlang::INT>("decoration:shadow:color");
static auto PSHADOWCOLINACTIVE = CConfigValue<Hyprlang::INT>("decoration:shadow:color_inactive");
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PDIMENABLED = CConfigValue<Hyprlang::INT>("decoration:dim_inactive");
static auto PDIMMODAL = CConfigValue<Hyprlang::INT>("decoration:dim_modal");
auto* const ACTIVECOL = sc<CGradientValueData*>((PACTIVECOL.ptr())->getData());
auto* const INACTIVECOL = sc<CGradientValueData*>((PINACTIVECOL.ptr())->getData());
auto* const NOGROUPACTIVECOL = sc<CGradientValueData*>((PNOGROUPACTIVECOL.ptr())->getData());
auto* const NOGROUPINACTIVECOL = sc<CGradientValueData*>((PNOGROUPINACTIVECOL.ptr())->getData());
auto* const GROUPACTIVECOL = sc<CGradientValueData*>((PGROUPACTIVECOL.ptr())->getData());
auto* const GROUPINACTIVECOL = sc<CGradientValueData*>((PGROUPINACTIVECOL.ptr())->getData());
auto* const GROUPACTIVELOCKEDCOL = sc<CGradientValueData*>((PGROUPACTIVELOCKEDCOL.ptr())->getData());
auto* const GROUPINACTIVELOCKEDCOL = sc<CGradientValueData*>((PGROUPINACTIVELOCKEDCOL.ptr())->getData());
auto setBorderColor = [&](CGradientValueData grad) -> void {
if (grad == m_realBorderColor)
return;
m_realBorderColorPrevious = m_realBorderColor;
m_realBorderColor = grad;
m_borderFadeAnimationProgress->setValueAndWarp(0.f);
*m_borderFadeAnimationProgress = 1.f;
};
const bool IS_SHADOWED_BY_MODAL = m_xdgSurface && m_xdgSurface->m_toplevel && m_xdgSurface->m_toplevel->anyChildModal();
// border
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(m_self.lock());
if (RENDERDATA.isBorderGradient)
setBorderColor(*RENDERDATA.borderGradient);
else {
const bool GROUPLOCKED = m_groupData.pNextWindow.lock() ? getGroupHead()->m_groupData.locked : false;
if (m_self == g_pCompositor->m_lastWindow) {
const auto* const ACTIVECOLOR =
!m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
setBorderColor(m_ruleApplicator->activeBorderColor().valueOr(*ACTIVECOLOR));
} else {
const auto* const INACTIVECOLOR =
!m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
setBorderColor(m_ruleApplicator->inactiveBorderColor().valueOr(*INACTIVECOLOR));
}
}
// opacity
const auto PWORKSPACE = m_workspace;
if (isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) {
*m_activeInactiveAlpha = m_ruleApplicator->alphaFullscreen().valueOrDefault().applyAlpha(*PFULLSCREENALPHA);
} else {
if (m_self == g_pCompositor->m_lastWindow)
*m_activeInactiveAlpha = m_ruleApplicator->alpha().valueOrDefault().applyAlpha(*PACTIVEALPHA);
else
*m_activeInactiveAlpha = m_ruleApplicator->alphaInactive().valueOrDefault().applyAlpha(*PINACTIVEALPHA);
}
// dim
float goalDim = 1.F;
if (m_self == g_pCompositor->m_lastWindow.lock() || m_ruleApplicator->noDim().valueOrDefault() || !*PDIMENABLED)
goalDim = 0;
else
goalDim = *PDIMSTRENGTH;
if (IS_SHADOWED_BY_MODAL && *PDIMMODAL)
goalDim += (1.F - goalDim) / 2.F;
*m_dimPercent = goalDim;
// shadow
if (!isX11OverrideRedirect() && !m_X11DoesntWantBorders) {
if (m_self == g_pCompositor->m_lastWindow)
*m_realShadowColor = CHyprColor(*PSHADOWCOL);
else
*m_realShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != -1 ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
} else
m_realShadowColor->setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow
updateWindowDecos();
}
std::optional<double> CWindow::calculateSingleExpr(const std::string& s) {
const auto PMONITOR = m_monitor ? m_monitor : g_pCompositor->m_lastMonitor;
const auto CURSOR_LOCAL = g_pInputManager->getMouseCoordsInternal() - (PMONITOR ? PMONITOR->m_position : Vector2D{});
Math::CExpression expr;
expr.addVariable("window_w", m_realSize->goal().x);
expr.addVariable("window_h", m_realSize->goal().y);
expr.addVariable("window_x", m_realPosition->goal().x - (PMONITOR ? PMONITOR->m_position.x : 0));
expr.addVariable("window_y", m_realPosition->goal().y - (PMONITOR ? PMONITOR->m_position.y : 0));
expr.addVariable("monitor_w", PMONITOR ? PMONITOR->m_size.x : 1920);
expr.addVariable("monitor_h", PMONITOR ? PMONITOR->m_size.y : 1080);
expr.addVariable("cursor_x", CURSOR_LOCAL.x);
expr.addVariable("cursor_y", CURSOR_LOCAL.y);
return expr.compute(s);
}
std::optional<Vector2D> CWindow::calculateExpression(const std::string& s) {
auto spacePos = s.find(' ');
if (spacePos == std::string::npos)
return std::nullopt;
const auto LHS = calculateSingleExpr(s.substr(0, spacePos));
const auto RHS = calculateSingleExpr(s.substr(spacePos + 1));
if (!LHS || !RHS)
return std::nullopt;
return Vector2D{*LHS, *RHS};
}