From a5c14370c11287cbf520c8f427179c665ac9c891 Mon Sep 17 00:00:00 2001 From: Pollux Date: Sun, 5 Jan 2025 12:38:49 -0600 Subject: [PATCH 01/24] renderer: Add supercircular window corners (#8943) renderer: Add supercircular shadows and borders config: Add rounding_power to default and example configs rule: add `roundingpower` window rule --- example/hyprland.conf | 1 + src/config/ConfigDescriptions.hpp | 6 + src/config/ConfigManager.cpp | 1 + src/config/ConfigManager.hpp | 1 + src/config/defaultConfig.hpp | 1 + src/desktop/Window.cpp | 23 ++-- src/desktop/Window.hpp | 2 + src/desktop/WindowRule.cpp | 6 +- src/render/OpenGL.cpp | 106 +++++++++------- src/render/OpenGL.hpp | 119 +++++++++--------- src/render/Renderer.cpp | 11 +- src/render/Shader.hpp | 1 + .../decorations/CHyprBorderDecoration.cpp | 16 +-- .../decorations/CHyprDropShadowDecoration.cpp | 14 ++- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- src/render/pass/BorderPassElement.cpp | 6 +- src/render/pass/BorderPassElement.hpp | 1 + src/render/pass/RectPassElement.cpp | 4 +- src/render/pass/RectPassElement.hpp | 5 +- src/render/pass/SurfacePassElement.cpp | 17 +-- src/render/pass/SurfacePassElement.hpp | 5 +- src/render/pass/TexPassElement.cpp | 3 +- src/render/pass/TexPassElement.hpp | 7 +- src/render/shaders/Border.hpp | 7 +- src/render/shaders/Shadow.hpp | 13 +- src/render/shaders/Textures.hpp | 23 ++-- 26 files changed, 228 insertions(+), 173 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index fe1a831a..c2b1a071 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -81,6 +81,7 @@ general { # https://wiki.hyprland.org/Configuring/Variables/#decoration decoration { rounding = 10 + rounding_power = 2 # Change transparency of focused and unfocused windows active_opacity = 1.0 diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 17657983..46f91a21 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -139,6 +139,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{0, 0, 20}, }, + SConfigOptionDescription{ + .value = "decoration:rounding_power", + .description = "rouding power of corners (2 is a circle)", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{2, 2, 10}, + }, SConfigOptionDescription{ .value = "decoration:active_opacity", .description = "opacity of active windows. [0.0 - 1.0]", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index bdce573f..732d12e5 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -427,6 +427,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("debug:colored_stdout_logs", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:rounding", Hyprlang::INT{0}); + m_pConfig->addConfigValue("decoration:rounding_power", {2.F}); m_pConfig->addConfigValue("decoration:blur:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:blur:size", Hyprlang::INT{8}); m_pConfig->addConfigValue("decoration:blur:passes", Hyprlang::INT{1}); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 0cd0a0a4..436362ae 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -259,6 +259,7 @@ class CConfigManager { }; std::unordered_map*(PHLWINDOW)>> mfWindowProperties = { + {"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; }}}; diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index c4eb3385..851e11f2 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -94,6 +94,7 @@ general { # https://wiki.hyprland.org/Configuring/Variables/#decoration decoration { rounding = 10 + rounding_power = 2 # Change transparency of focused and unfocused windows active_opacity = 1.0 diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 4104c737..60914198 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -824,7 +824,8 @@ void CWindow::updateDynamicRules() { // it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize) // otherwise behaviour is undefined bool CWindow::isInCurvedCorner(double x, double y) { - const int ROUNDING = rounding(); + const int ROUNDING = rounding(); + const int ROUNDINGPOWER = roundingPower(); if (getRealBorderSize() >= ROUNDING) return false; @@ -835,16 +836,16 @@ bool CWindow::isInCurvedCorner(double x, double y) { double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING; if (x < x0 && y < y0) { - return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } if (x > x1 && y < y0) { - return Vector2D{x1, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } if (x < x0 && y > y1) { - return Vector2D{x0, y1}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } if (x > x1 && y > y1) { - return Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } return false; @@ -1164,13 +1165,21 @@ bool CWindow::opaque() { } float CWindow::rounding() { - static auto PROUNDING = CConfigValue("decoration:rounding"); + static auto PROUNDING = CConfigValue("decoration:rounding"); + static auto PROUNDINGPOWER = CConfigValue("decoration:rounding_power"); - float rounding = m_sWindowData.rounding.valueOr(*PROUNDING); + float roundingPower = m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER); + float rounding = m_sWindowData.rounding.valueOr(*PROUNDING) * (roundingPower / 2.0); /* Make perceived roundness consistent. */ return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding; } +float CWindow::roundingPower() { + static auto PROUNDINGPOWER = CConfigValue("decoration:rounding_power"); + + return m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER); +} + void CWindow::updateWindowData() { const auto PWORKSPACE = m_pWorkspace; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 6ed9a525..3ceaf594 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -183,6 +183,7 @@ struct SWindowData { CWindowOverridableVar renderUnfocused = false; CWindowOverridableVar rounding; + CWindowOverridableVar roundingPower; CWindowOverridableVar borderSize; CWindowOverridableVar scrollMouse; @@ -414,6 +415,7 @@ class CWindow { Vector2D middle(); bool opaque(); float rounding(); + float roundingPower(); bool canBeTorn(); void setSuspended(bool suspend); bool visibleOnMonitor(PHLMONITOR pMonitor); diff --git a/src/desktop/WindowRule.cpp b/src/desktop/WindowRule.cpp index 7db6c3db..306a25ce 100644 --- a/src/desktop/WindowRule.cpp +++ b/src/desktop/WindowRule.cpp @@ -8,8 +8,8 @@ static const auto RULES = std::unordered_set{ "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", }; static const auto RULES_PREFIX = std::unordered_set{ - "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", - "plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray", + "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", + "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray", }; CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) { @@ -88,4 +88,4 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool ruleType = RULE_INVALID; } } -} \ No newline at end of file +} diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 1b51acbf..94b70acf 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -971,14 +971,15 @@ void CHyprOpenGLImpl::setDamage(const CRegion& damage_, std::optional f } void CHyprOpenGLImpl::initShaders() { - GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); - m_RenderData.pCurrentMonData->m_shQUAD.program = prog; - m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); - m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); + GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); + m_RenderData.pCurrentMonData->m_shQUAD.program = prog; + m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); + m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); + m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); + m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower"); prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA); m_RenderData.pCurrentMonData->m_shRGBA.program = prog; @@ -995,6 +996,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shRGBA.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shRGBA.tint = glGetUniformLocation(prog, "tint"); m_RenderData.pCurrentMonData->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); @@ -1037,6 +1039,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shRGBX.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shRGBX.tint = glGetUniformLocation(prog, "tint"); @@ -1053,6 +1056,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shEXT.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shEXT.tint = glGetUniformLocation(prog, "tint"); @@ -1097,18 +1101,19 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness"); m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise"); - prog = createProgram(QUADVERTSRC, FRAGSHADOW); - m_RenderData.pCurrentMonData->m_shSHADOW.program = prog; - m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); - m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range"); - m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); - m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color"); + prog = createProgram(QUADVERTSRC, FRAGSHADOW); + m_RenderData.pCurrentMonData->m_shSHADOW.program = prog; + m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft"); + m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); + m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize"); + m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shSHADOW.roundingPower = glGetUniformLocation(prog, "roundingPower"); + m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range"); + m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); + m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color"); prog = createProgram(QUADVERTSRC, FRAGBORDER1); m_RenderData.pCurrentMonData->m_shBORDER1.program = prog; @@ -1122,6 +1127,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed"); m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter"); + m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient2 = glGetUniformLocation(prog, "gradient2"); m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength"); @@ -1244,12 +1250,12 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h scissor(&box, transform); } -void CHyprOpenGLImpl::renderRect(CBox* box, const CHyprColor& col, int round) { +void CHyprOpenGLImpl::renderRect(CBox* box, const CHyprColor& col, int round, float roundingPower) { if (!m_RenderData.damage.empty()) - renderRectWithDamage(box, col, m_RenderData.damage, round); + renderRectWithDamage(box, col, m_RenderData.damage, round, roundingPower); } -void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float blurA, bool xray) { +void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float roundingPower, float blurA, bool xray) { if (m_RenderData.damage.empty()) return; @@ -1271,7 +1277,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - renderRect(box, CHyprColor(0, 0, 0, 0), round); + renderRect(box, CHyprColor(0, 0, 0, 0), round, roundingPower); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); @@ -1282,7 +1288,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r m_bEndFrame = true; // fix transformed const auto SAVEDRENDERMODIF = m_RenderData.renderModif; m_RenderData.renderModif = {}; // fix shit - renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, blurA, damage, 0, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, blurA, damage, 0, 2.0f, false, false, false); m_bEndFrame = false; m_RenderData.renderModif = SAVEDRENDERMODIF; @@ -1293,10 +1299,10 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); - renderRectWithDamage(box, col, m_RenderData.damage, round); + renderRectWithDamage(box, col, m_RenderData.damage, round, roundingPower); } -void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, const CRegion& damage, int round) { +void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, const CRegion& damage, int round, float roundingPower) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -1334,6 +1340,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, con glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round); + glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.roundingPower, roundingPower); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1361,25 +1368,25 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, con scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.damage, round, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.damage, round, roundingPower, discardActive, false, allowCustomUV, true); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, const CRegion& damage, float alpha, int round, bool discardActive, bool allowCustomUV, - SP waitTimeline, uint64_t waitPoint) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, const CRegion& damage, float alpha, int round, float roundingPower, bool discardActive, + bool allowCustomUV, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, roundingPower, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, const CRegion& damage, int round, bool discardActive, bool noAA, - bool allowCustomUV, bool allowDim, SP waitTimeline, uint64_t waitPoint) { +void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, + bool noAA, bool allowCustomUV, bool allowDim, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw nullptr texture!"); @@ -1506,6 +1513,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y); glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y); glUniform1f(shader->radius, round); + glUniform1f(shader->roundingPower, roundingPower); if (allowDim && m_RenderData.currentWindow) { glUniform1i(shader->applyTint, 1); @@ -1997,7 +2005,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { clear(CHyprColor(0, 0, 0, 0)); m_bEndFrame = true; // fix transformed - renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, fakeDamage, 0, false, true, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, fakeDamage, 0, 2.0f, false, true, false); m_bEndFrame = false; m_RenderData.currentFB->bind(); @@ -2045,8 +2053,8 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, bool blockBlurOptimization, float blurA, - float overallA) { +void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, float roundingPower, bool blockBlurOptimization, + float blurA, float overallA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto PNOBLUROVERSIZED = CConfigValue("decoration:no_blur_on_oversized"); @@ -2063,7 +2071,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float m_RenderData.renderModif.applyToRegion(texDamage); if (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { - renderTexture(tex, pBox, a, round, false, true); + renderTexture(tex, pBox, a, round, roundingPower, false, true); return; } @@ -2076,7 +2084,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale); if (inverseOpaque.empty()) { - renderTexture(tex, pBox, a, round, false, true); + renderTexture(tex, pBox, a, round, roundingPower, false, true); return; } } else { @@ -2112,9 +2120,9 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); if (USENEWOPTIMIZE && !(m_RenderData.discardMode & DISCARD_ALPHA)) - renderRect(pBox, CHyprColor(0, 0, 0, 0), round); + renderRect(pBox, CHyprColor(0, 0, 0, 0), round, roundingPower); else - renderTexture(tex, pBox, a, round, true, true); // discard opaque + renderTexture(tex, pBox, a, round, roundingPower, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); @@ -2127,7 +2135,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float setMonitorTransformEnabled(true); if (!USENEWOPTIMIZE) setRenderModifEnabled(false); - renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, 0, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, 0, 2.0f, false, false, false); if (!USENEWOPTIMIZE) setRenderModifEnabled(true); setMonitorTransformEnabled(false); @@ -2138,14 +2146,14 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float // draw window glDisable(GL_STENCIL_TEST); - renderTextureInternalWithDamage(tex, pBox, a * overallA, texDamage, round, false, false, true, true); + renderTextureInternalWithDamage(tex, pBox, a * overallA, texDamage, round, roundingPower, false, false, true, true); glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, int round, int borderSize, float a, int outerRound) { +void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, int round, float roundingPower, int borderSize, float a, int outerRound) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -2207,6 +2215,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -2238,7 +2247,8 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in blend(BLEND); } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, int borderSize, float a, int outerRound) { +void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, float roundingPower, int borderSize, float a, + int outerRound) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -2304,6 +2314,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -2335,7 +2346,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c blend(BLEND); } -void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CHyprColor& color, float a) { +void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, float roundingPower, int range, const CHyprColor& color, float a) { RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!"); RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); RASSERT(m_RenderData.currentWindow, "Tried to render shadow without a window!"); @@ -2381,6 +2392,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.radius, range + round); + glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.roundingPower, roundingPower); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.range, range); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower, SHADOWPOWER); @@ -2421,7 +2433,7 @@ void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) { blend(false); - renderTexture(m_RenderData.currentFB->getTexture(), box, 1.f, 0, false, false); + renderTexture(m_RenderData.currentFB->getTexture(), box, 1.f, 0, 2.0f, false, false); blend(true); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 713816bc..3f117a5a 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -166,83 +166,84 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); ~CHyprOpenGLImpl(); - void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); - void end(); + void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); + void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); + void end(); - void renderRect(CBox*, const CHyprColor&, int round = 0); - void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CHyprColor&, const CRegion& damage, int round = 0); - void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(SP, CBox*, const CRegion& damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, - SP waitTimeline = nullptr, uint64_t waitPoint = 0); - void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f, - float overallA = 1.f); - void renderRoundedShadow(CBox*, int round, int range, const CHyprColor& color, float a = 1.0); - void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); + void renderRect(CBox*, const CHyprColor&, int round = 0, float roundingPower = 2.0f); + void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float roundingPower = 2.0f, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(CBox*, const CHyprColor&, const CRegion& damage, int round = 0, float roundingPower = 2.0f); + void renderTexture(SP, CBox*, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, CBox*, const CRegion& damage, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, + bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); + void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, float roundingPower = 2.0f, bool blockBlurOptimization = false, + float blurA = 1.f, float overallA = 1.f); + void renderRoundedShadow(CBox*, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); + void renderBorder(CBox*, const CGradientValueData&, int round, float roundingPower, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, float roundingPower, int borderSize, float a = 1.0, + int outerRound = -1 /* use round */); + void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); - void setMonitorTransformEnabled(bool enabled); - void setRenderModifEnabled(bool enabled); + void setMonitorTransformEnabled(bool enabled); + void setRenderModifEnabled(bool enabled); - void saveMatrix(); - void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); - void restoreMatrix(); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); - void blend(bool enabled); + void blend(bool enabled); - bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - void clear(const CHyprColor&); - void clearWithTex(); - void scissor(const CBox*, bool transform = true); - void scissor(const pixman_box32*, bool transform = true); - void scissor(const int x, const int y, const int w, const int h, bool transform = true); + void clear(const CHyprColor&); + void clearWithTex(); + void scissor(const CBox*, bool transform = true); + void scissor(const pixman_box32*, bool transform = true); + void scissor(const int x, const int y, const int w, const int h, bool transform = true); - void destroyMonitorResources(PHLMONITOR); + void destroyMonitorResources(PHLMONITOR); - void markBlurDirtyForMonitor(PHLMONITOR); + void markBlurDirtyForMonitor(PHLMONITOR); - void preWindowPass(); - bool preBlurQueued(); - void preRender(PHLMONITOR); + void preWindowPass(); + bool preBlurQueued(); + void preRender(PHLMONITOR); - void saveBufferForMirror(CBox*); - void renderMirrored(); + void saveBufferForMirror(CBox*); + void renderMirrored(); - void applyScreenShader(const std::string& path); + void applyScreenShader(const std::string& path); - void bindOffMain(); - void renderOffToMain(CFramebuffer* off); - void bindBackOnMain(); + void bindOffMain(); + void renderOffToMain(CFramebuffer* off); + void bindBackOnMain(); - SP loadAsset(const std::string& file); - SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); + SP loadAsset(const std::string& file); + SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); - void setDamage(const CRegion& damage, std::optional finalDamage = {}); + void setDamage(const CRegion& damage, std::optional finalDamage = {}); - uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); - std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; - uint failedAssetsNo = 0; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; + uint failedAssetsNo = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - std::map m_mWindowFramebuffers; - std::map m_mLayerFramebuffers; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; std::map m_mMonitorRenderResources; std::map m_mMonitorBGFBs; @@ -311,8 +312,8 @@ class CHyprOpenGLImpl { // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - void renderTextureInternalWithDamage(SP, CBox* pBox, float a, const CRegion& damage, int round = 0, bool discardOpaque = false, bool noAA = false, - bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); + void renderTextureInternalWithDamage(SP, CBox* pBox, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, + bool noAA = false, bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); void renderTexturePrimitive(SP tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 35150ce2..d154e64a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -460,11 +460,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha.value()) * (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha.value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha.value(); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); - renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.blur = !ignoreAllGeometry && *PBLUR && !DONT_BLUR; - renderdata.pWindow = pWindow; + renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); + renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; + renderdata.roundingPower = ignoreAllGeometry || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); + renderdata.blur = !ignoreAllGeometry && *PBLUR && !DONT_BLUR; + renderdata.pWindow = pWindow; if (ignoreAllGeometry) { renderdata.alpha = 1.f; diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index eaf9da96..666ee9d4 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -26,6 +26,7 @@ class CShader { GLint fullSizeUntransformed = -1; GLint radius = -1; GLint radiusOuter = -1; + GLfloat roundingPower = -1; GLint thick = -1; diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 4a793eab..2bc894ef 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -67,15 +67,17 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); } - int borderSize = m_pWindow->getRealBorderSize(); - const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; + int borderSize = m_pWindow->getRealBorderSize(); + const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; + const auto ROUNDINGPOWER = m_pWindow->roundingPower(); CBorderPassElement::SBorderData data; - data.box = windowBox; - data.grad1 = grad; - data.round = ROUNDING; - data.a = a; - data.borderSize = borderSize; + data.box = windowBox; + data.grad1 = grad; + data.round = ROUNDING; + data.roundingPower = ROUNDINGPOWER; + data.a = a; + data.borderSize = borderSize; if (ANIMATED) { data.hasGrad2 = true; diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 21242b57..07dbb436 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -55,6 +55,7 @@ void CHyprDropShadowDecoration::damageEntire() { static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); const auto ROUNDING = PWINDOW->rounding(); + const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1; CRegion shadowRegion(shadowBox); @@ -119,6 +120,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { return; // disabled const auto ROUNDINGBASE = PWINDOW->rounding(); + const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDING = ROUNDINGBASE > 0 ? ROUNDINGBASE + PWINDOW->getRealBorderSize() : 0; const auto PWORKSPACE = PWINDOW->m_pWorkspace; const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); @@ -192,10 +194,10 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); // render black window box ("clip") - g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale); + g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale, ROUNDINGPOWER); alphaSwapFB.bind(); @@ -214,7 +216,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->m_RenderData.damage = saveDamage; } else - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); if (m_seExtents != m_seReportedExtents) g_pDecorationPositioner->repositionDeco(this); @@ -226,7 +228,7 @@ eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() { return DECORATION_LAYER_BOTTOM; } -void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a) { +void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, float roundingPower, int range, CHyprColor color, float a) { static auto PSHADOWSHARP = CConfigValue("decoration:shadow:sharp"); g_pHyprOpenGL->blend(true); @@ -234,7 +236,7 @@ void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int ran color.a *= a; if (*PSHADOWSHARP) - g_pHyprOpenGL->renderRect(box, color, round); + g_pHyprOpenGL->renderRect(box, color, round, roundingPower); else - g_pHyprOpenGL->renderRoundedShadow(box, round, range, color, 1.F); + g_pHyprOpenGL->renderRoundedShadow(box, round, roundingPower, range, color, 1.F); } diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index fe0f8952..93fa3d1a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -36,7 +36,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { Vector2D m_vLastWindowPos; Vector2D m_vLastWindowSize; - void drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a); + void drawShadowInternal(CBox* box, int round, float roundingPower, int range, CHyprColor color, float a); CBox m_bLastWindowBox = {0}; CBox m_bLastWindowBoxWithDecos = {0}; diff --git a/src/render/pass/BorderPassElement.cpp b/src/render/pass/BorderPassElement.cpp index 635533d0..ceeec6f3 100644 --- a/src/render/pass/BorderPassElement.cpp +++ b/src/render/pass/BorderPassElement.cpp @@ -7,9 +7,9 @@ CBorderPassElement::CBorderPassElement(const CBorderPassElement::SBorderData& da void CBorderPassElement::draw(const CRegion& damage) { if (data.hasGrad2) - g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.grad2, data.lerp, data.round, data.borderSize, data.a, data.outerRound); + g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.grad2, data.lerp, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); else - g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.round, data.borderSize, data.a, data.outerRound); + g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); } bool CBorderPassElement::needsLiveBlur() { @@ -18,4 +18,4 @@ bool CBorderPassElement::needsLiveBlur() { bool CBorderPassElement::needsPrecomputeBlur() { return false; -} \ No newline at end of file +} diff --git a/src/render/pass/BorderPassElement.hpp b/src/render/pass/BorderPassElement.hpp index 3a529640..785653ab 100644 --- a/src/render/pass/BorderPassElement.hpp +++ b/src/render/pass/BorderPassElement.hpp @@ -12,6 +12,7 @@ class CBorderPassElement : public IPassElement { bool hasGrad2 = false; float lerp = 0.F, a = 1.F; int round = 0, borderSize = 1, outerRound = -1; + float roundingPower = 2.F; }; CBorderPassElement(const SBorderData& data_); diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index 25a550b3..a57c959e 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -10,9 +10,9 @@ void CRectPassElement::draw(const CRegion& damage) { return; if (data.color.a == 1.F || !data.blur) - g_pHyprOpenGL->renderRectWithDamage(&data.box, data.color, damage, data.round); + g_pHyprOpenGL->renderRectWithDamage(&data.box, data.color, damage, data.round, data.roundingPower); else - g_pHyprOpenGL->renderRectWithBlur(&data.box, data.color, data.round, data.blurA, data.xray); + g_pHyprOpenGL->renderRectWithBlur(&data.box, data.color, data.round, data.roundingPower, data.blurA, data.xray); } bool CRectPassElement::needsLiveBlur() { diff --git a/src/render/pass/RectPassElement.hpp b/src/render/pass/RectPassElement.hpp index 32111a43..d27abdcc 100644 --- a/src/render/pass/RectPassElement.hpp +++ b/src/render/pass/RectPassElement.hpp @@ -6,7 +6,8 @@ class CRectPassElement : public IPassElement { struct SRectData { CBox box; CHyprColor color; - int round = 0; + int round = 0; + float roundingPower = 2.0f; bool blur = false, xray = false; float blurA = 1.F; }; @@ -26,4 +27,4 @@ class CRectPassElement : public IPassElement { private: SRectData data; -}; \ No newline at end of file +}; diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index bdb21338..13e9e741 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -88,12 +88,15 @@ void CSurfacePassElement::draw(const CRegion& damage) { if (MISALIGNEDFSV1) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - float rounding = data.rounding; + float rounding = data.rounding; + float roundingPower = data.roundingPower; rounding -= 1; // to fix a border issue - if (data.dontRound) - rounding = 0; + if (data.dontRound) { + rounding = 0; + roundingPower = 2.0f; + } const bool WINDOWOPAQUE = data.pWindow && data.pWindow->m_pWLSurface->resource() == data.surface ? data.pWindow->opaque() : false; const bool CANDISABLEBLEND = ALPHA >= 1.f && OVERALL_ALPHA >= 1.f && rounding == 0 && WINDOWOPAQUE; @@ -108,14 +111,14 @@ void CSurfacePassElement::draw(const CRegion& damage) { // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) if (data.surfaceCounter == 0 && !data.popup) { if (BLUR) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, data.blockBlurOptimization, data.fadeAlpha, OVERALL_ALPHA); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, roundingPower, data.blockBlurOptimization, data.fadeAlpha, OVERALL_ALPHA); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, false, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); } else { if (BLUR && data.popup) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, true, data.fadeAlpha, OVERALL_ALPHA); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, roundingPower, true, data.fadeAlpha, OVERALL_ALPHA); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, false, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp index 746c5a64..14d8ef14 100644 --- a/src/render/pass/SurfacePassElement.hpp +++ b/src/render/pass/SurfacePassElement.hpp @@ -35,6 +35,9 @@ class CSurfacePassElement : public IPassElement { // for custom round values int rounding = -1; // -1 means not set + // for custom rounding powers + float roundingPower = 2.0f; + // for blurring bool blur = false; bool blockBlurOptimization = false; @@ -79,4 +82,4 @@ class CSurfacePassElement : public IPassElement { SRenderData data; CBox getTexBox(); -}; \ No newline at end of file +}; diff --git a/src/render/pass/TexPassElement.cpp b/src/render/pass/TexPassElement.cpp index 05f756dc..0624a786 100644 --- a/src/render/pass/TexPassElement.cpp +++ b/src/render/pass/TexPassElement.cpp @@ -18,7 +18,8 @@ void CTexPassElement::draw(const CRegion& damage) { if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = *data.replaceProjection; - g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, &data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.syncTimeline, data.syncPoint); + g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, &data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline, + data.syncPoint); if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = g_pHyprOpenGL->m_RenderData.pMonitor->projMatrix; } diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp index bf896951..036b89fe 100644 --- a/src/render/pass/TexPassElement.hpp +++ b/src/render/pass/TexPassElement.hpp @@ -13,8 +13,9 @@ class CTexPassElement : public IPassElement { CBox box; float a = 1.F; CRegion damage; - int round = 0; - bool flipEndFrame = false; + int round = 0; + float roundingPower = 2.0f; + bool flipEndFrame = false; SP syncTimeline; int64_t syncPoint = 0; std::optional replaceProjection; @@ -36,4 +37,4 @@ class CTexPassElement : public IPassElement { private: SRenderData data; -}; \ No newline at end of file +}; diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp index acd3f3ff..3b9a91f0 100644 --- a/src/render/shaders/Border.hpp +++ b/src/render/shaders/Border.hpp @@ -15,6 +15,7 @@ uniform vec2 fullSize; uniform vec2 fullSizeUntransformed; uniform float radius; uniform float radiusOuter; +uniform float roundingPower; uniform float thick; // Gradients are in OkLabA!!!! {l, a, b, alpha} @@ -138,9 +139,9 @@ void main() { const float SMOOTHING_CONSTANT = )#" + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - float dist = length(pixCoord); - float distOuter = length(pixCoordOuter); - float h = (thick / 2.0); + float dist = pow(pow(pixCoord.x,roundingPower)+pow(pixCoord.y,roundingPower),1.0/roundingPower); + float distOuter = pow(pow(pixCoordOuter.x,roundingPower)+pow(pixCoordOuter.y,roundingPower),1.0/roundingPower); + float h = (thick / 2.0); if (dist < radius - h) { // lower diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp index 0acab6b7..c04d4bf3 100644 --- a/src/render/shaders/Shadow.hpp +++ b/src/render/shaders/Shadow.hpp @@ -11,6 +11,7 @@ uniform vec2 topLeft; uniform vec2 bottomRight; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform float range; uniform float shadowPower; @@ -26,6 +27,10 @@ float pixAlphaRoundedDistance(float distanceToCorner) { return 1.0; } +float modifiedLength(vec2 a) { + return pow(pow(abs(a.x),roundingPower)+pow(abs(a.y),roundingPower),1.0/roundingPower); +} + void main() { vec4 pixColor = v_color; @@ -40,21 +45,21 @@ void main() { if (pixCoord[0] < topLeft[0]) { if (pixCoord[1] < topLeft[1]) { // top left - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topLeft)); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft)); done = true; } else if (pixCoord[1] > bottomRight[1]) { // bottom left - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(topLeft[0], bottomRight[1]))); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1]))); done = true; } } else if (pixCoord[0] > bottomRight[0]) { if (pixCoord[1] < topLeft[1]) { // top right - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(bottomRight[0], topLeft[1]))); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1]))); done = true; } else if (pixCoord[1] > bottomRight[1]) { // bottom right - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomRight)); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight)); done = true; } } diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index b203ad04..49d27b4c 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -19,23 +19,18 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar const float SMOOTHING_CONSTANT = )#" + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - if (pixCoord.x + pixCoord.y > radius) { + //if (pixCoord.x + pixCoord.y > radius) { - float dist = length(pixCoord); + float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); - if (dist > radius + SMOOTHING_CONSTANT * 2.0) - discard; + if (dist > radius + SMOOTHING_CONSTANT) + discard; - if (dist > radius - SMOOTHING_CONSTANT * 2.0) { - float dist = length(pixCoord); + float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); - float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); - - )#" + + )#" + colorVarName + R"#( = )#" + colorVarName + R"#( * normalized; - } - - } + //} )#"; }; @@ -63,6 +58,7 @@ varying vec4 v_color; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; void main() { @@ -107,6 +103,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform int discardOpaque; uniform int discardAlpha; @@ -167,6 +164,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform int discardOpaque; uniform int discardAlpha; @@ -440,6 +438,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform int discardOpaque; uniform int discardAlpha; From 391ff29110e3fb9711b98e92cee44182dda2e2ba Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 5 Jan 2025 19:49:27 +0100 Subject: [PATCH 02/24] pass: improve pass debug mode --- src/render/pass/Pass.cpp | 42 +++++++++++++++++++++++++++++++++++----- src/render/pass/Pass.hpp | 6 +++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 3e1282f0..0489e985 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -88,7 +88,7 @@ void CRenderPass::simplify() { } newDamage.subtract(opaque); if (*PDEBUGPASS) - occludedRegion.add(opaque); + occludedRegions.emplace_back(opaque); } } @@ -114,9 +114,11 @@ CRegion CRenderPass::render(const CRegion& damage_) { const auto WILLBLUR = std::ranges::any_of(m_vPassElements, [](const auto& el) { return el->element->needsLiveBlur(); }); - damage = *PDEBUGPASS ? CRegion{CBox{{}, {INT32_MAX, INT32_MAX}}} : damage_.copy(); - occludedRegion = CRegion{}; - totalLiveBlurRegion = CRegion{}; + damage = *PDEBUGPASS ? CRegion{CBox{{}, {INT32_MAX, INT32_MAX}}} : damage_.copy(); + if (*PDEBUGPASS) { + occludedRegions.clear(); + totalLiveBlurRegion = CRegion{}; + } if (damage.empty()) { g_pHyprOpenGL->m_RenderData.damage = damage; @@ -198,7 +200,9 @@ CRegion CRenderPass::render(const CRegion& damage_) { void CRenderPass::renderDebugData() { CBox box = {{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize}; - g_pHyprOpenGL->renderRectWithDamage(&box, Colors::RED.modifyA(0.1F), occludedRegion); + for (const auto& rg : occludedRegions) { + g_pHyprOpenGL->renderRectWithDamage(&box, Colors::RED.modifyA(0.1F), rg); + } g_pHyprOpenGL->renderRectWithDamage(&box, Colors::GREEN.modifyA(0.1F), totalLiveBlurRegion); std::unordered_map offsets; @@ -239,6 +243,34 @@ void CRenderPass::renderDebugData() { renderHLSurface(debugData.pointerFocusText, g_pSeatManager->state.pointerFocus.lock(), Colors::ORANGE.modifyA(0.1F)); if (g_pCompositor->m_pLastWindow) renderHLSurface(debugData.lastWindowText, g_pCompositor->m_pLastWindow->m_pWLSurface->resource(), Colors::LIGHT_BLUE.modifyA(0.1F)); + + const auto DISCARDED_ELEMENTS = std::count_if(m_vPassElements.begin(), m_vPassElements.end(), [](const auto& e) { return e->discard; }); + auto tex = g_pHyprOpenGL->renderText(std::format("occlusion layers: {}\npass elements: {} ({} discarded)\nviewport: {:X0}", occludedRegions.size(), m_vPassElements.size(), + DISCARDED_ELEMENTS, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize), + Colors::WHITE, 12); + + if (tex) { + box = CBox{{0.F, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y - tex->m_vSize.y}, tex->m_vSize}.scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale); + g_pHyprOpenGL->renderTexture(tex, &box, 1.F); + } + + std::string passStructure; + auto yn = [](const bool val) -> const char* { return val ? "yes" : "no"; }; + auto tick = [](const bool val) -> const char* { return val ? "✔" : "✖"; }; + for (const auto& el : m_vPassElements | std::views::reverse) { + passStructure += std::format("{} {} (bb: {} op: {})\n", tick(!el->discard), el->element->passName(), yn(el->element->boundingBox().has_value()), + yn(!el->element->opaqueRegion().empty())); + } + + if (!passStructure.empty()) + passStructure.pop_back(); + + tex = g_pHyprOpenGL->renderText(passStructure, Colors::WHITE, 12); + if (tex) { + box = CBox{{g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.x - tex->m_vSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y - tex->m_vSize.y}, tex->m_vSize}.scale( + g_pHyprOpenGL->m_RenderData.pMonitor->scale); + g_pHyprOpenGL->renderTexture(tex, &box, 1.F); + } } float CRenderPass::oneBlurRadius() { diff --git a/src/render/pass/Pass.hpp b/src/render/pass/Pass.hpp index 5fa25fc3..a0810155 100644 --- a/src/render/pass/Pass.hpp +++ b/src/render/pass/Pass.hpp @@ -19,9 +19,9 @@ class CRenderPass { CRegion render(const CRegion& damage_); private: - CRegion damage; - CRegion occludedRegion; - CRegion totalLiveBlurRegion; + CRegion damage; + std::vector occludedRegions; + CRegion totalLiveBlurRegion; struct SPassElementData { CRegion elementDamage; From 1b06d222cf5abfc9802f7787315a8190f011d43e Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 5 Jan 2025 20:35:24 +0100 Subject: [PATCH 03/24] pass/surface: fixup invalid expansion by old -1 rounding param fixes #8889 --- src/render/pass/SurfacePassElement.hpp | 36 +++++++------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp index 14d8ef14..12387367 100644 --- a/src/render/pass/SurfacePassElement.hpp +++ b/src/render/pass/SurfacePassElement.hpp @@ -9,38 +9,22 @@ class CSyncTimeline; class CSurfacePassElement : public IPassElement { public: struct SRenderData { - PHLMONITORREF pMonitor; - timespec* when = nullptr; - Vector2D pos, localPos; + PHLMONITORREF pMonitor; + timespec* when = nullptr; + Vector2D pos, localPos; - // for iters void* data = nullptr; SP surface = nullptr; SP texture = nullptr; bool mainSurface = true; double w = 0, h = 0; - - // for rounding - bool dontRound = true; - - // for fade - float fadeAlpha = 1.f; - - // for alpha settings - float alpha = 1.f; - - // for decorations (border) - bool decorate = false; - - // for custom round values - int rounding = -1; // -1 means not set - - // for custom rounding powers - float roundingPower = 2.0f; - - // for blurring - bool blur = false; - bool blockBlurOptimization = false; + int rounding = 0; + bool dontRound = true; + float roundingPower = 2.0F; + bool decorate = false; + float alpha = 1.F, fadeAlpha = 1.F; + bool blur = false; + bool blockBlurOptimization = false; // only for windows, not popups bool squishOversized = true; From f390f48a07d117e24acec59dcf6791bcb3a81110 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 5 Jan 2025 23:19:13 +0100 Subject: [PATCH 04/24] pass: fixup debug mode rendering of input boxes --- src/render/pass/Pass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 0489e985..b72248c2 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -226,12 +226,13 @@ void CRenderPass::renderDebugData() { if (box.intersection(CBox{{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize}).empty()) return; + g_pHyprOpenGL->renderRectWithDamage(&box, color, CRegion{0, 0, INT32_MAX, INT32_MAX}); + if (offsets.contains(surface.get())) box.translate(Vector2D{0.F, offsets[surface.get()]}); else offsets[surface.get()] = 0; - g_pHyprOpenGL->renderRectWithDamage(&box, Colors::PURPLE.modifyA(0.1F), CRegion{0, 0, INT32_MAX, INT32_MAX}); box = {box.pos(), texture->m_vSize}; g_pHyprOpenGL->renderRectWithDamage(&box, CHyprColor{0.F, 0.F, 0.F, 0.2F}, CRegion{0, 0, INT32_MAX, INT32_MAX}, std::min(5.0, box.size().y)); g_pHyprOpenGL->renderTexture(texture, &box, 1.F); From f1a7a7497e9b058092e915acd5164dcc162a8260 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 6 Jan 2025 15:27:57 +0100 Subject: [PATCH 05/24] datadevice: guard XWayland server against crashes The server might be dead or restarting, and we'd deref null ref #7822 --- src/protocols/core/DataDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 6ad17d7b..722eb9fd 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -417,7 +417,7 @@ void CWLDataDeviceProtocol::destroyResource(CWLDataOfferResource* resource) { SP CWLDataDeviceProtocol::dataDeviceForClient(wl_client* c) { #ifndef NO_XWAYLAND - if (c == g_pXWayland->pServer->xwaylandClient) + if (g_pXWayland->pServer && c == g_pXWayland->pServer->xwaylandClient) return g_pXWayland->pWM->getDataDevice(); #endif From 780e3dd542c9706dd37b715f95eb1134b14e6624 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 6 Jan 2025 14:29:29 +0000 Subject: [PATCH 06/24] [gha] Nix: update inputs --- flake.lock | 73 +++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/flake.lock b/flake.lock index 76d371bc..f16ecaa7 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1734906446, - "narHash": "sha256-6OWluVE2A8xi+8V3jN9KA72RCgJjYdyyuLBUjxZ2q2U=", + "lastModified": 1736102453, + "narHash": "sha256-5qb4kb7Xbt8jJFL/oDqOor9Z2+E+A+ql3PiyDvsfWZ0=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "eecb74dc79bb6752a2a507e6edee3042390a6091", + "rev": "4846091641f3be0ad7542086d52769bb7932bde6", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1734906236, - "narHash": "sha256-vH/ysV2ONGQgYZPtcJKwc8jJivzyVxru2aaOxC20ZOE=", + "lastModified": 1736115290, + "narHash": "sha256-Jcn6yAzfUMcxy3tN/iZRbi/QgrYm7XLyVRl9g/nbUl4=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "6dea3fba08fd704dd624b6d4b261638fb4003c9c", + "rev": "52202272d89da32a9f866c0d10305a5e3d954c50", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1735734474, - "narHash": "sha256-9OV4lOqrEJVLdOrpNN/9msNwAhI6FQTu4N7fufilG08=", + "lastModified": 1735774328, + "narHash": "sha256-vIRwLS9w+N99EU1aJ+XNOU6mJTxrUBa31i1r82l0V7s=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "271df559dd30e4bc5ec6af02d017ac0aaabd63a7", + "rev": "e3b6af97ddcfaafbda8e2828c719a5af84f662cb", "type": "github" }, "original": { @@ -154,11 +154,11 @@ ] }, "locked": { - "lastModified": 1734906472, - "narHash": "sha256-pWPRv/GA/X/iAwoE6gMNUqn/ZeJX1IeLPRpZI0tTPK0=", + "lastModified": 1736114838, + "narHash": "sha256-FxbuGQExtN37ToWYnGmO6weOYN6WPHN/RAqbr7gNPek=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "c77109d7e1ddbcdb87cafd32ce411f76328ae152", + "rev": "6997fe382dcf396704227d2b98ffdd5066da6959", "type": "github" }, "original": { @@ -180,11 +180,11 @@ ] }, "locked": { - "lastModified": 1734906259, - "narHash": "sha256-P79t/7HbACO4/PuJBroGpTptvCWJtXTv+gWsF+sM6MI=", + "lastModified": 1735393019, + "narHash": "sha256-NPpqA8rtmDLsEmZOmz+qR67zsB6Y503Jnv+nSFLKJZ8=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "0404833ea18d543df44df935ebf1b497310eb046", + "rev": "55608efdaa387af7bfdc0eddb404c409958efa43", "type": "github" }, "original": { @@ -203,11 +203,11 @@ ] }, "locked": { - "lastModified": 1735316583, - "narHash": "sha256-AiiUwHWHfEdpFzXy7l1x3zInCUa1xcRMrbZ1XRSkzwU=", + "lastModified": 1736164519, + "narHash": "sha256-1LimBKvDpBbeX+qW7T240WEyw+DBVpDotZB4JYm8Aps=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "8f15d45b120b33712f6db477fe5ffb18034d0ea8", + "rev": "3c895da64b0eb19870142196fa48c07090b441c4", "type": "github" }, "original": { @@ -226,11 +226,11 @@ ] }, "locked": { - "lastModified": 1734793513, - "narHash": "sha256-rrrHcXapXJvGFqX+L/Bb0182L25jofAZ0fm1FInvrTQ=", + "lastModified": 1735493474, + "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "4d7367b6eee87397e2dbca2e78078dd0a4ef4c61", + "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", "type": "github" }, "original": { @@ -241,11 +241,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1735291276, - "narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=", + "lastModified": 1736012469, + "narHash": "sha256-/qlNWm/IEVVH7GfgAIyP6EsVZI6zjAx1cV5zNyrs+rI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "634fd46801442d760e09493a794c4f15db2d0cbb", + "rev": "8f3e1f807051e32d8c95cd12b9b421623850a34d", "type": "github" }, "original": { @@ -255,37 +255,20 @@ "type": "github" } }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1730741070, - "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", "gitignore": "gitignore", "nixpkgs": [ "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" + ] }, "locked": { - "lastModified": 1734797603, - "narHash": "sha256-ulZN7ps8nBV31SE+dwkDvKIzvN6hroRY8sYOT0w+E28=", + "lastModified": 1735882644, + "narHash": "sha256-3FZAG+pGt3OElQjesCAWeMkQ7C/nB1oTHLRQ8ceP110=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "f0f0dc4920a903c3e08f5bdb9246bb572fcae498", + "rev": "a5a961387e75ae44cc20f0a57ae463da5e959656", "type": "github" }, "original": { From 602d6b73563e56fe003bbf3d25b45a53c51bad24 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 6 Jan 2025 11:37:13 -0500 Subject: [PATCH 07/24] snap: don't snap to any windows if workspace has a fullscreen window (#8870) --- src/layout/IHyprLayout.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index e90ab0f0..f875b99c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -421,11 +421,13 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA SRange sourceY = {sourcePos.y, sourcePos.y + sourceSize.y}; if (*SNAPWINDOWGAP) { - const double GAPSIZE = *SNAPWINDOWGAP; - const auto WSID = DRAGGINGWINDOW->workspaceID(); + const double GAPSIZE = *SNAPWINDOWGAP; + const auto WSID = DRAGGINGWINDOW->workspaceID(); + const bool HASFULLSCREEN = DRAGGINGWINDOW->m_pWorkspace && DRAGGINGWINDOW->m_pWorkspace->m_bHasFullscreenWindow; for (auto& other : g_pCompositor->m_vWindows) { - if (other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) + if ((HASFULLSCREEN && !other->m_bCreatedOverFullscreen) || other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || + other->isX11OverrideRedirect()) continue; const int OTHERBORDERSIZE = other->getRealBorderSize(); From 6a90b505456cc708ec2779e0943eb9764e7630a5 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:52:35 +0300 Subject: [PATCH 08/24] core/compositor: fix too early buffer release (#8966) --- src/protocols/core/Compositor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index ee1e6224..6213f987 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -428,6 +428,7 @@ void CWLSurfaceResource::commitPendingState() { pending.damage.clear(); pending.bufferDamage.clear(); pending.newBuffer = false; + dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore events.roleCommit.emit(); @@ -448,10 +449,9 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->buffer->isSynchronous()) { - dropCurrentBuffer(); - dropPendingBuffer(); // pending atm is just a copied ref of the current, drop it too to send a release - } + // Some clients aren't ready to receive a release this early. Should be fine to release it on the next commitPendingState. + // if (current.buffer->buffer->isSynchronous()) + // dropCurrentBuffer(); } // TODO: we should _accumulate_ and not replace above if sync From 1bf4937b0292dc156e2530185c231608280be27f Mon Sep 17 00:00:00 2001 From: Byso Date: Mon, 6 Jan 2025 17:52:59 +0100 Subject: [PATCH 09/24] hyprctl: fix hyprctl --batch not working with exec rules (#8952) --- src/debug/HyprCtl.cpp | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index b946da6e..8724d2c7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1150,34 +1150,26 @@ static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string req } static std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) { - // split by ; - - request = request.substr(9); - std::string curitem = ""; - std::string reply = ""; - - auto nextItem = [&]() { - auto idx = request.find_first_of(';'); - - if (idx != std::string::npos) { - curitem = request.substr(0, idx); - request = request.substr(idx + 1); - } else { - curitem = request; - request = ""; - } - - curitem = trim(curitem); - }; - - nextItem(); + // split by ; ignores ; inside [] and adds ; on last command + request = request.substr(9); + std::string reply = ""; const std::string DELIMITER = "\n\n\n"; + int bracket = 0; + size_t idx = 0; - while (curitem != "" || request != "") { - reply += g_pHyprCtl->getReply(curitem) + DELIMITER; - - nextItem(); + for (size_t i = 0; i <= request.size(); ++i) { + char ch = (i < request.size()) ? request[i] : ';'; + if (ch == '[') + ++bracket; + else if (ch == ']') + --bracket; + else if (ch == ';' && bracket == 0) { + if (idx < i) + reply += g_pHyprCtl->getReply(trim(request.substr(idx, i - idx))).append(DELIMITER); + idx = i + 1; + continue; + } } return reply.substr(0, std::max(static_cast(reply.size() - DELIMITER.size()), 0)); From b9f110ef8726fcba2b4ee69856027731e73003a5 Mon Sep 17 00:00:00 2001 From: Pollux Date: Mon, 6 Jan 2025 13:30:57 -0600 Subject: [PATCH 10/24] shaders: fix blank windows when using corner rounding (#8969) (#8971) --- src/render/shaders/Textures.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index 49d27b4c..78845322 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -19,7 +19,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar const float SMOOTHING_CONSTANT = )#" + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - //if (pixCoord.x + pixCoord.y > radius) { + if (pixCoord.x + pixCoord.y > radius) { float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); @@ -30,7 +30,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar )#" + colorVarName + R"#( = )#" + colorVarName + R"#( * normalized; - //} + } )#"; }; From c7086f936a06abebcc863c35f634760ca1ee90c0 Mon Sep 17 00:00:00 2001 From: Zetta1 Reid0 <79805086+Zetta1Reid0@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:50:34 +0200 Subject: [PATCH 11/24] master: add option to show slaves on left in center orientation (#8940) Co-authored-by: Zetta1_Reid0 <11255-Zetta1_Reid0@users.noreply.gitlab.xfce.org> --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/layout/MasterLayout.cpp | 20 +++++++++++++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 46f91a21..8c35a3b1 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1632,6 +1632,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE? }, + SConfigOptionDescription{ + .value = "master:center_master_slaves_on_right", + .description = "set if the slaves should appear on right of master when slave_count_for_center_master > 2", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "master:center_ignores_reserved", .description = "centers the master window on monitor ignoring reserved areas", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 732d12e5..927cee9f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -479,6 +479,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:mfact", {0.55f}); m_pConfig->addConfigValue("master:new_status", {"slave"}); m_pConfig->addConfigValue("master:slave_count_for_center_master", Hyprlang::INT{2}); + m_pConfig->addConfigValue("master:center_master_slaves_on_right", Hyprlang::INT{1}); m_pConfig->addConfigValue("master:center_ignores_reserved", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index fb7df84f..225246f0 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -328,6 +328,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { eOrientation orientation = getDynamicOrientation(pWorkspace); bool centerMasterWindow = false; static auto SLAVECOUNTFORCENTER = CConfigValue("master:slave_count_for_center_master"); + static auto CMSLAVESONRIGHT = CConfigValue("master:center_master_slaves_on_right"); static auto PIGNORERESERVED = CConfigValue("master:center_ignores_reserved"); static auto PSMARTRESIZING = CConfigValue("master:smart_resizing"); @@ -341,7 +342,10 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { if (STACKWINDOWS >= *SLAVECOUNTFORCENTER) { centerMasterWindow = true; } else { - orientation = ORIENTATION_LEFT; + if (*CMSLAVESONRIGHT) + orientation = ORIENTATION_LEFT; + else + orientation = ORIENTATION_RIGHT; } } @@ -515,15 +519,20 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { float nextY = 0; float nextYL = 0; float nextYR = 0; - bool onRight = true; + bool onRight = *CMSLAVESONRIGHT; + int slavesLeftL = 1 + (slavesLeft - 1) / 2; + int slavesLeftR = slavesLeft - slavesLeftL; - int slavesLeftR = 1 + (slavesLeft - 1) / 2; - int slavesLeftL = slavesLeft - slavesLeftR; + if (*CMSLAVESONRIGHT) { + slavesLeftR = 1 + (slavesLeft - 1) / 2; + slavesLeftL = slavesLeft - slavesLeftR; + } const float slaveAverageHeightL = WSSIZE.y / slavesLeftL; const float slaveAverageHeightR = WSSIZE.y / slavesLeftR; float slaveAccumulatedHeightL = 0; float slaveAccumulatedHeightR = 0; + if (*PSMARTRESIZING) { for (auto const& nd : m_lMasterNodesData) { if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster) @@ -536,7 +545,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { } onRight = !onRight; } - onRight = true; + + onRight = *CMSLAVESONRIGHT; } for (auto& nd : m_lMasterNodesData) { From 5642ed331df56375c55cd8d56a14054af8bdf8f2 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:55:14 +0000 Subject: [PATCH 12/24] core: move parts of the animation system to hyprutils (#8868) * core: change animation manager to use Hyprutils::Animation * config: move animation config to hyprutils animation tree * use g_pAnimationManager->createAnimation and the new PHLANIMVAR template * core: use CGenericAnimatedVariabled::{enabled,setConfig,getStyle} and adapt callbacks * core: adapt animated variable usage (dereference the shared pointer) * misc: bump CMakeLists to hyprutils 0.3.3 --- CMakeLists.txt | 2 +- src/Compositor.cpp | 78 +-- src/config/ConfigManager.cpp | 156 ++--- src/config/ConfigManager.hpp | 87 ++- src/debug/HyprCtl.cpp | 23 +- src/desktop/LayerSurface.cpp | 88 ++- src/desktop/LayerSurface.hpp | 18 +- src/desktop/Popup.cpp | 4 +- src/desktop/Subsurface.cpp | 2 +- src/desktop/WLSurface.cpp | 2 +- src/desktop/Window.cpp | 198 +++--- src/desktop/Window.hpp | 42 +- src/desktop/Workspace.cpp | 99 ++- src/desktop/Workspace.hpp | 6 +- src/events/Windows.cpp | 100 +-- src/helpers/AnimatedVariable.cpp | 87 --- src/helpers/AnimatedVariable.hpp | 275 +-------- src/helpers/BezierCurve.cpp | 90 --- src/helpers/BezierCurve.hpp | 28 - src/helpers/Monitor.cpp | 8 +- src/helpers/WLClasses.hpp | 1 - src/hyprerror/HyprError.cpp | 30 +- src/hyprerror/HyprError.hpp | 20 +- src/layout/DwindleLayout.cpp | 38 +- src/layout/IHyprLayout.cpp | 100 +-- src/layout/MasterLayout.cpp | 36 +- src/managers/AnimationManager.cpp | 584 +++++++----------- src/managers/AnimationManager.hpp | 75 ++- src/managers/KeybindManager.cpp | 64 +- src/managers/XWaylandManager.cpp | 6 +- src/managers/input/InputManager.cpp | 12 +- src/managers/input/Swipe.cpp | 120 ++-- src/managers/input/Tablets.cpp | 2 +- src/managers/input/Touch.cpp | 16 +- src/protocols/CTMControl.cpp | 14 +- src/protocols/CTMControl.hpp | 4 +- src/protocols/ToplevelExport.cpp | 8 +- src/render/OpenGL.cpp | 8 +- src/render/Renderer.cpp | 94 +-- .../decorations/CHyprBorderDecoration.cpp | 14 +- .../decorations/CHyprDropShadowDecoration.cpp | 28 +- .../decorations/CHyprGroupBarDecoration.cpp | 10 +- .../decorations/DecorationPositioner.cpp | 6 +- src/render/pass/SurfacePassElement.cpp | 12 +- 44 files changed, 1031 insertions(+), 1664 deletions(-) delete mode 100644 src/helpers/AnimatedVariable.cpp delete mode 100644 src/helpers/BezierCurve.cpp delete mode 100644 src/helpers/BezierCurve.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d5c58b7..aa746d2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.3.3) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c80f05e6..5805eff9 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -569,7 +569,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pKeybindManager = std::make_unique(); Debug::log(LOG, "Creating the AnimationManager!"); - g_pAnimationManager = std::make_unique(); + g_pAnimationManager = std::make_unique(); Debug::log(LOG, "Creating the ConfigManager!"); g_pConfigManager = std::make_unique(); @@ -964,11 +964,11 @@ SP CCompositor::vectorWindowToSurface(const Vector2D& pos, P if (PPOPUP) { const auto OFF = PPOPUP->coordsRelativeToParent(); - sl = pos - pWindow->m_vRealPosition.goal() - OFF; + sl = pos - pWindow->m_vRealPosition->goal() - OFF; return PPOPUP->m_pWLSurface->resource(); } - auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition.goal(), true); + auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition->goal(), true); if (surf) { sl = local; return surf; @@ -982,7 +982,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo return {}; if (pWindow->m_bIsX11) - return vec - pWindow->m_vRealPosition.goal(); + return vec - pWindow->m_vRealPosition->goal(); const auto PPOPUP = pWindow->m_pPopupHead->at(vec); if (PPOPUP) @@ -1001,9 +1001,9 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo CBox geom = pWindow->m_pXDGSurface->current.geometry; if (std::get<1>(iterData) == Vector2D{-1337, -1337}) - return vec - pWindow->m_vRealPosition.goal(); + return vec - pWindow->m_vRealPosition->goal(); - return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; + return vec - pWindow->m_vRealPosition->goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } PHLMONITOR CCompositor::getMonitorFromOutput(SP out) { @@ -1211,7 +1211,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) + if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) continue; auto SURFACEAT = ls->popupHead->at(pos, true); @@ -1229,7 +1229,7 @@ SP CCompositor::vectorToLayerPopupSurface(const Vector2D& po SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& ls : *layerSurfaces | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) + if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) continue; auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); @@ -1378,7 +1378,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { if (w->monitorID() != monid && w->m_pMonitor) continue; - if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { + if (!w->m_bFadingOut || w->m_fAlpha->value() == 0.f) { w->m_bFadingOut = false; @@ -1831,8 +1831,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->m_cRealBorderColorPrevious = pWindow->m_cRealBorderColor; pWindow->m_cRealBorderColor = grad; - pWindow->m_fBorderFadeAnimationProgress.setValueAndWarp(0.f); - pWindow->m_fBorderFadeAnimationProgress = 1.f; + pWindow->m_fBorderFadeAnimationProgress->setValueAndWarp(0.f); + *pWindow->m_fBorderFadeAnimationProgress = 1.f; }; const bool IS_SHADOWED_BY_MODAL = pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel && pWindow->m_pXDGSurface->toplevel->anyChildModal(); @@ -1855,18 +1855,18 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // tick angle if it's not running (aka dead) - if (!pWindow->m_fBorderAngleAnimationProgress.isBeingAnimated()) - pWindow->m_fBorderAngleAnimationProgress.setValueAndWarp(0.f); + if (!pWindow->m_fBorderAngleAnimationProgress->isBeingAnimated()) + pWindow->m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); // opacity const auto PWORKSPACE = pWindow->m_pWorkspace; if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) { - pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); + *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); } else { if (pWindow == m_pLastWindow) - pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA); + *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA); else - pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA); + *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA); } // dim @@ -1879,16 +1879,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { if (IS_SHADOWED_BY_MODAL) goalDim += (1.F - goalDim) / 2.F; - pWindow->m_fDimPercent = goalDim; + *pWindow->m_fDimPercent = goalDim; // shadow if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { if (pWindow == m_pLastWindow) - pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL); + *pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL); else - pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); + *pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); } else { - pWindow->m_cRealShadowColor.setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow + pWindow->m_cRealShadowColor->setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow } pWindow->updateWindowDecos(); @@ -1932,11 +1932,11 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor // additionally, move floating and fs windows manually if (w->m_bIsFloating) - w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition; + *w->m_vRealPosition = w->m_vRealPosition->goal() - pMonitorA->vecPosition + pMonitorB->vecPosition; if (w->isFullscreen()) { - w->m_vRealPosition = pMonitorB->vecPosition; - w->m_vRealSize = pMonitorB->vecSize; + *w->m_vRealPosition = pMonitorB->vecPosition; + *w->m_vRealSize = pMonitorB->vecSize; } w->updateToplevel(); @@ -1957,11 +1957,11 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor // additionally, move floating and fs windows manually if (w->m_bIsFloating) - w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition; + *w->m_vRealPosition = w->m_vRealPosition->goal() - pMonitorB->vecPosition + pMonitorA->vecPosition; if (w->isFullscreen()) { - w->m_vRealPosition = pMonitorA->vecPosition; - w->m_vRealSize = pMonitorA->vecSize; + *w->m_vRealPosition = pMonitorA->vecPosition; + *w->m_vRealSize = pMonitorA->vecSize; } w->updateToplevel(); @@ -2135,14 +2135,14 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo if (w->m_bIsMapped && !w->isHidden()) { if (POLDMON) { if (w->m_bIsFloating) - w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition; + *w->m_vRealPosition = w->m_vRealPosition->goal() - POLDMON->vecPosition + pMonitor->vecPosition; if (w->isFullscreen()) { - w->m_vRealPosition = pMonitor->vecPosition; - w->m_vRealSize = pMonitor->vecSize; + *w->m_vRealPosition = pMonitor->vecPosition; + *w->m_vRealSize = pMonitor->vecSize; } } else { - w->m_vRealPosition = Vector2D{(int)w->m_vRealPosition.goal().x % (int)pMonitor->vecSize.x, (int)w->m_vRealPosition.goal().y % (int)pMonitor->vecSize.y}; + *w->m_vRealPosition = Vector2D{(int)w->m_vRealPosition->goal().x % (int)pMonitor->vecSize.x, (int)w->m_vRealPosition->goal().y % (int)pMonitor->vecSize.y}; } } @@ -2216,9 +2216,9 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { continue; if (!FULLSCREEN) - w->m_fAlpha = 1.f; + *w->m_fAlpha = 1.f; else if (!w->isFullscreen()) - w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f; + *w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f; } } @@ -2227,7 +2227,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (!ls->fadingOut) - ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; + *ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } } @@ -2317,7 +2317,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS updateFullscreenFadeOnWorkspace(PWORKSPACE); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); PWORKSPACE->forceReportSizesToWindows(); @@ -2573,7 +2573,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, getMonitorFromID(monID), NAME, SPECIAL, isEmpty)); - PWORKSPACE->m_fAlpha.setValueAndWarp(0); + PWORKSPACE->m_fAlpha->setValueAndWarp(0); return PWORKSPACE; } @@ -2659,7 +2659,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor const PHLWINDOW pFirstWindowOnWorkspace = pWorkspace->getFirstWindow(); const int visibleWindowsOnWorkspace = pWorkspace->getWindows(std::nullopt, true); const auto PWINDOWMONITOR = pWindow->m_pMonitor.lock(); - const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; + const auto POSTOMON = pWindow->m_vRealPosition->goal() - PWINDOWMONITOR->vecPosition; const auto PWORKSPACEMONITOR = pWorkspace->m_pMonitor.lock(); if (!pWindow->m_bIsFloating) @@ -2696,7 +2696,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow); if (pWindow->m_bIsFloating) - pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; + *pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; } pWindow->updateToplevel(); @@ -2721,8 +2721,8 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pCompositor->updateSuspendedStates(); if (!WASVISIBLE && pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible()) { - pWindow->m_fMovingFromWorkspaceAlpha.setValueAndWarp(0.F); - pWindow->m_fMovingFromWorkspaceAlpha = 1.F; + pWindow->m_fMovingFromWorkspaceAlpha->setValueAndWarp(0.F); + *pWindow->m_fMovingFromWorkspaceAlpha = 1.F; } } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 927cee9f..1ab29b1f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -11,6 +11,7 @@ #include "../protocols/LayerShell.hpp" #include "../xwayland/XWayland.hpp" #include "../protocols/OutputManagement.hpp" +#include "managers/AnimationManager.hpp" #include #include @@ -32,6 +33,7 @@ #include #include using namespace Hyprutils::String; +using namespace Hyprutils::Animation; //NOLINTNEXTLINE extern "C" char** environ; @@ -681,7 +683,6 @@ CConfigManager::CConfigManager() { m_pConfig->commence(); - setDefaultAnimationVars(); resetHLConfig(); Debug::log(INFO, @@ -780,76 +781,46 @@ void CConfigManager::reload() { } void CConfigManager::setDefaultAnimationVars() { - if (isFirstLaunch) { - INITANIMCFG("__internal_fadeCTM"); + m_AnimationTree.createNode("__internal_fadeCTM"); + m_AnimationTree.createNode("global"); - INITANIMCFG("global"); - INITANIMCFG("windows"); - INITANIMCFG("layers"); - INITANIMCFG("fade"); - INITANIMCFG("border"); - INITANIMCFG("borderangle"); + // global + m_AnimationTree.createNode("windows", "global"); + m_AnimationTree.createNode("layers", "global"); + m_AnimationTree.createNode("fade", "global"); + m_AnimationTree.createNode("border", "global"); + m_AnimationTree.createNode("borderangle", "global"); + m_AnimationTree.createNode("workspaces", "global"); - // windows - INITANIMCFG("windowsIn"); - INITANIMCFG("windowsOut"); - INITANIMCFG("windowsMove"); + // layer + m_AnimationTree.createNode("layersIn", "layers"); + m_AnimationTree.createNode("layersOut", "layers"); - // layers - INITANIMCFG("layersIn"); - INITANIMCFG("layersOut"); + // windows + m_AnimationTree.createNode("windowsIn", "windows"); + m_AnimationTree.createNode("windowsOut", "windows"); + m_AnimationTree.createNode("windowsMove", "windows"); - // fade - INITANIMCFG("fadeIn"); - INITANIMCFG("fadeOut"); - INITANIMCFG("fadeSwitch"); - INITANIMCFG("fadeShadow"); - INITANIMCFG("fadeDim"); + // fade + m_AnimationTree.createNode("fadeIn", "fade"); + m_AnimationTree.createNode("fadeOut", "fade"); + m_AnimationTree.createNode("fadeSwitch", "fade"); + m_AnimationTree.createNode("fadeShadow", "fade"); + m_AnimationTree.createNode("fadeDim", "fade"); + m_AnimationTree.createNode("fadeLayers", "fade"); + m_AnimationTree.createNode("fadeLayersIn", "fadeLayers"); + m_AnimationTree.createNode("fadeLayersOut", "fadeLayers"); - // border + // workspaces + m_AnimationTree.createNode("workspacesIn", "workspaces"); + m_AnimationTree.createNode("workspacesOut", "workspaces"); + m_AnimationTree.createNode("specialWorkspace", "workspaces"); + m_AnimationTree.createNode("specialWorkspaceIn", "specialWorkspace"); + m_AnimationTree.createNode("specialWorkspaceOut", "specialWorkspace"); - // workspaces - INITANIMCFG("workspaces"); - INITANIMCFG("workspacesIn"); - INITANIMCFG("workspacesOut"); - INITANIMCFG("specialWorkspace"); - INITANIMCFG("specialWorkspaceIn"); - INITANIMCFG("specialWorkspaceOut"); - } - - // init the values - animationConfig["global"] = {false, "default", "", 8.f, 1, &animationConfig["general"], nullptr}; - - animationConfig["__internal_fadeCTM"] = {false, "linear", "", 5.F, 1, &animationConfig["__internal_fadeCTM"], nullptr}; - - CREATEANIMCFG("windows", "global"); - CREATEANIMCFG("layers", "global"); - CREATEANIMCFG("fade", "global"); - CREATEANIMCFG("border", "global"); - CREATEANIMCFG("borderangle", "global"); - CREATEANIMCFG("workspaces", "global"); - - CREATEANIMCFG("layersIn", "layers"); - CREATEANIMCFG("layersOut", "layers"); - - CREATEANIMCFG("windowsIn", "windows"); - CREATEANIMCFG("windowsOut", "windows"); - CREATEANIMCFG("windowsMove", "windows"); - - CREATEANIMCFG("fadeIn", "fade"); - CREATEANIMCFG("fadeOut", "fade"); - CREATEANIMCFG("fadeSwitch", "fade"); - CREATEANIMCFG("fadeShadow", "fade"); - CREATEANIMCFG("fadeDim", "fade"); - CREATEANIMCFG("fadeLayers", "fade"); - CREATEANIMCFG("fadeLayersIn", "fadeLayers"); - CREATEANIMCFG("fadeLayersOut", "fadeLayers"); - - CREATEANIMCFG("workspacesIn", "workspaces"); - CREATEANIMCFG("workspacesOut", "workspaces"); - CREATEANIMCFG("specialWorkspace", "workspaces"); - CREATEANIMCFG("specialWorkspaceIn", "specialWorkspace"); - CREATEANIMCFG("specialWorkspaceOut", "specialWorkspace"); + // init the root nodes + m_AnimationTree.setConfigForNode("global", 1, 8.f, "", "default"); + m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "", "linear"); } std::optional CConfigManager::resetHLConfig() { @@ -857,6 +828,8 @@ std::optional CConfigManager::resetHLConfig() { m_vWindowRules.clear(); g_pKeybindManager->clearKeybinds(); g_pAnimationManager->removeAllBeziers(); + g_pAnimationManager->addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)); + m_mAdditionalReservedAreas.clear(); m_dBlurLSNamespaces.clear(); m_vWorkspaceRules.clear(); @@ -1647,8 +1620,8 @@ void CConfigManager::ensureVRR(PHLMONITOR pMonitor) { } } -SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) { - return &animationConfig[name]; +SP CConfigManager::getAnimationPropertyConfig(const std::string& name) { + return m_AnimationTree.getConfig(name); } void CConfigManager::addParseError(const std::string& err) { @@ -1711,8 +1684,8 @@ ICustomConfigValueData::~ICustomConfigValueData() { ; // empty } -std::unordered_map CConfigManager::getAnimationConfig() { - return animationConfig; +const std::unordered_map>& CConfigManager::getAnimationConfig() { + return m_AnimationTree.getFullConfig(); } void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value) { @@ -2058,17 +2031,6 @@ std::optional CConfigManager::handleBezier(const std::string& comma return {}; } -void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) { - for (auto& [name, anim] : animationConfig) { - if (anim.pParentAnimation == ANIM && !anim.overridden) { - // if a child isnt overridden, set the values of the parent - anim.pValues = ANIM->pValues; - - setAnimForChildren(&anim); - } - } -}; - std::optional CConfigManager::handleAnimation(const std::string& command, const std::string& args) { const auto ARGS = CVarList(args); @@ -2077,14 +2039,9 @@ std::optional CConfigManager::handleAnimation(const std::string& co // anim name const auto ANIMNAME = ARGS[0]; - const auto PANIM = animationConfig.find(ANIMNAME); - - if (PANIM == animationConfig.end()) + if (!m_AnimationTree.nodeExists(ANIMNAME)) return "no such animation"; - PANIM->second.overridden = true; - PANIM->second.pValues = &PANIM->second; - // This helper casts strings like "1", "true", "off", "yes"... to int. int64_t enabledInt = configStringToInt(ARGS[1]).value_or(0) == 1; @@ -2092,33 +2049,31 @@ std::optional CConfigManager::handleAnimation(const std::string& co if (enabledInt != 0 && enabledInt != 1) return "invalid animation on/off state"; - PANIM->second.internalEnabled = configStringToInt(ARGS[1]).value_or(0) == 1; + if (enabledInt) { + int64_t speed = -1; - if (PANIM->second.internalEnabled) { // speed if (isNumber(ARGS[2], true)) { - PANIM->second.internalSpeed = std::stof(ARGS[2]); + speed = std::stof(ARGS[2]); - if (PANIM->second.internalSpeed <= 0) { - PANIM->second.internalSpeed = 1.f; + if (speed <= 0) { + speed = 1.f; return "invalid speed"; } } else { - PANIM->second.internalSpeed = 10.f; + speed = 10.f; return "invalid speed"; } - // curve - PANIM->second.internalBezier = ARGS[3]; + std::string bezierName = ARGS[3]; + m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, speed, ARGS[3], ARGS[4]); - if (!g_pAnimationManager->bezierExists(ARGS[3])) { - PANIM->second.internalBezier = "default"; + if (!g_pAnimationManager->bezierExists(bezierName)) { + const auto PANIMNODE = m_AnimationTree.getConfig(ANIMNAME); + PANIMNODE->internalBezier = "default"; return "no such bezier"; } - // style - PANIM->second.internalStyle = ARGS[4]; - if (ARGS[4] != "") { auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); @@ -2127,9 +2082,6 @@ std::optional CConfigManager::handleAnimation(const std::string& co } } - // now, check for children, recursively - setAnimForChildren(&PANIM->second); - return {}; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 436362ae..53772401 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -1,5 +1,6 @@ #pragma once +#include #define CONFIG_MANAGER_H #include @@ -23,9 +24,6 @@ #include -#define INITANIMCFG(name) animationConfig[name] = {} -#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]} - #define HANDLE void* struct SWorkspaceRule { @@ -54,18 +52,6 @@ struct SMonitorAdditionalReservedArea { int right = 0; }; -struct SAnimationPropertyConfig { - bool overridden = true; - - std::string internalBezier = ""; - std::string internalStyle = ""; - float internalSpeed = 0.f; - int internalEnabled = -1; - - SAnimationPropertyConfig* pValues = nullptr; - SAnimationPropertyConfig* pParentAnimation = nullptr; -}; - struct SPluginKeyword { HANDLE handle = nullptr; std::string name = ""; @@ -181,32 +167,32 @@ class CConfigManager { std::unordered_map m_mAdditionalReservedAreas; - std::unordered_map getAnimationConfig(); + const std::unordered_map>& getAnimationConfig(); - void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value); + void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value); void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {}); void removePluginConfig(HANDLE handle); // no-op when done. - void dispatchExecOnce(); - void dispatchExecShutdown(); + void dispatchExecOnce(); + void dispatchExecShutdown(); - void performMonitorReload(); - void ensureMonitorStatus(); - void ensureVRR(PHLMONITOR pMonitor = nullptr); + void performMonitorReload(); + void ensureMonitorStatus(); + void ensureVRR(PHLMONITOR pMonitor = nullptr); - bool shouldUseSoftwareCursors(); + bool shouldUseSoftwareCursors(); - std::string parseKeyword(const std::string&, const std::string&); + std::string parseKeyword(const std::string&, const std::string&); - void addParseError(const std::string&); + void addParseError(const std::string&); - SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&); + SP getAnimationPropertyConfig(const std::string&); - void addExecRule(const SExecRequestedRule&); + void addExecRule(const SExecRequestedRule&); - void handlePluginLoads(); - std::string getErrors(); + void handlePluginLoads(); + std::string getErrors(); // keywords std::optional handleRawExec(const std::string&, const std::string&); @@ -269,39 +255,38 @@ class CConfigManager { bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking private: - std::unique_ptr m_pConfig; + std::unique_ptr m_pConfig; - std::vector configPaths; // stores all the config paths - std::unordered_map configModifyTimes; // stores modify times + std::vector configPaths; // stores all the config paths + std::unordered_map configModifyTimes; // stores modify times - std::unordered_map animationConfig; // stores all the animations with their set values + Hyprutils::Animation::CAnimationConfigTree m_AnimationTree; - std::string m_szCurrentSubmap = ""; // For storing the current keybind submap + std::string m_szCurrentSubmap = ""; // For storing the current keybind submap - std::vector execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty + std::vector execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty - std::vector m_vDeclaredPlugins; - std::vector pluginKeywords; - std::vector pluginVariables; + std::vector m_vDeclaredPlugins; + std::vector pluginKeywords; + std::vector pluginVariables; - bool isFirstLaunch = true; // For exec-once + bool isFirstLaunch = true; // For exec-once - std::vector m_vMonitorRules; - std::vector m_vWorkspaceRules; - std::vector> m_vWindowRules; - std::vector> m_vLayerRules; - std::vector m_dBlurLSNamespaces; + std::vector m_vMonitorRules; + std::vector m_vWorkspaceRules; + std::vector> m_vWindowRules; + std::vector> m_vLayerRules; + std::vector m_dBlurLSNamespaces; - bool firstExecDispatched = false; - bool m_bManualCrashInitiated = false; - std::vector firstExecRequests; - std::vector finalExecRequests; + bool firstExecDispatched = false; + bool m_bManualCrashInitiated = false; + std::vector firstExecRequests; + std::vector finalExecRequests; - std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins - std::string m_szConfigErrors = ""; + std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins + std::string m_szConfigErrors = ""; // internal methods - void setAnimForChildren(SAnimationPropertyConfig* const); void updateBlurredLS(const std::string&, const bool); void setDefaultAnimationVars(); std::optional resetHLConfig(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 8724d2c7..7edace21 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -248,8 +248,8 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "focusHistoryID": {}, "inhibitingIdle": {} }},)#", - (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, - (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, + (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition->goal().x, (int)w->m_vRealPosition->goal().y, + (int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), (int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), @@ -261,11 +261,12 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\txwayland: {}\n\tpinned: " "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\n", - (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, - (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), - (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), - (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), - (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false)); + (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition->goal().x, (int)w->m_vRealPosition->goal().y, + (int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, + (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, + w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, + (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), + (int)g_pInputManager->isWindowInhibiting(w, false)); } } @@ -732,8 +733,8 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re ret += "animations:\n"; for (auto const& ac : g_pConfigManager->getAnimationConfig()) { - ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second.overridden, - ac.second.internalBezier, ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle); + ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second->overridden, + ac.second->internalBezier, ac.second->internalEnabled, ac.second->internalSpeed, ac.second->internalStyle); } ret += "beziers:\n"; @@ -755,8 +756,8 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re "speed": {:.2f}, "style": "{}" }},)#", - ac.first, ac.second.overridden ? "true" : "false", escapeJSONStrings(ac.second.internalBezier), ac.second.internalEnabled ? "true" : "false", - ac.second.internalSpeed, escapeJSONStrings(ac.second.internalStyle)); + ac.first, ac.second->overridden ? "true" : "false", escapeJSONStrings(ac.second->internalBezier), ac.second->internalEnabled ? "true" : "false", + ac.second->internalSpeed, escapeJSONStrings(ac.second->internalStyle)); } ret[ret.length() - 1] = ']'; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 05ea4473..fe11f3f3 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -4,6 +4,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/AnimationManager.hpp" PHLLS CLayerSurface::create(SP resource) { PHLLS pLS = SP(new CLayerSurface(resource)); @@ -31,16 +32,13 @@ PHLLS CLayerSurface::create(SP resource) { pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); - pLS->alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); - pLS->realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); - pLS->realSize.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); - pLS->alpha.registerVar(); - pLS->realPosition.registerVar(); - pLS->realSize.registerVar(); + g_pAnimationManager->createAnimation(0.f, pLS->alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realSize, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); pLS->registerCallbacks(); - pLS->alpha.setValueAndWarp(0.f); + pLS->alpha->setValueAndWarp(0.f); Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); @@ -48,7 +46,7 @@ PHLLS CLayerSurface::create(SP resource) { } void CLayerSurface::registerCallbacks() { - alpha.setUpdateCallback([this](void*) { + alpha->setUpdateCallback([this](auto) { if (dimAround) g_pHyprRenderer->damageMonitor(monitor.lock()); }); @@ -93,7 +91,7 @@ void CLayerSurface::onDestroy() { onUnmap(); } else { Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); - alpha.setValueAndWarp(0.f); + alpha->setValueAndWarp(0.f); fadingOut = true; g_pCompositor->addToFadingOutSafe(self.lock()); } @@ -307,17 +305,17 @@ void CLayerSurface::onCommit() { } } - if (realPosition.goal() != geometry.pos()) { - if (realPosition.isBeingAnimated()) - realPosition = geometry.pos(); + if (realPosition->goal() != geometry.pos()) { + if (realPosition->isBeingAnimated()) + *realPosition = geometry.pos(); else - realPosition.setValueAndWarp(geometry.pos()); + realPosition->setValueAndWarp(geometry.pos()); } - if (realSize.goal() != geometry.size()) { - if (realSize.isBeingAnimated()) - realSize = geometry.size(); + if (realSize->goal() != geometry.size()) { + if (realSize->isBeingAnimated()) + *realSize = geometry.size(); else - realSize.setValueAndWarp(geometry.size()); + realSize->setValueAndWarp(geometry.size()); } if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { @@ -434,17 +432,17 @@ void CLayerSurface::applyRules() { } void CLayerSurface::startAnimation(bool in, bool instant) { - const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle); if (in) { - realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn"); - realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn"); - alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"); + realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); + realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); + alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn")); } else { - realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut"); - realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut"); - alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut"); + realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); + realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); + alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut")); } + const auto ANIMSTYLE = animationStyle.value_or(realPosition->getStyle()); if (ANIMSTYLE.starts_with("slide")) { // get closest edge const auto MIDDLE = geometry.middle(); @@ -485,9 +483,9 @@ void CLayerSurface::startAnimation(bool in, bool instant) { } } - realSize.setValueAndWarp(geometry.size()); - alpha.setValueAndWarp(in ? 0.f : 1.f); - alpha = in ? 1.f : 0.f; + realSize->setValueAndWarp(geometry.size()); + alpha->setValueAndWarp(in ? 0.f : 1.f); + *alpha = in ? 1.f : 0.f; Vector2D prePos; @@ -512,11 +510,11 @@ void CLayerSurface::startAnimation(bool in, bool instant) { } if (in) { - realPosition.setValueAndWarp(prePos); - realPosition = geometry.pos(); + realPosition->setValueAndWarp(prePos); + *realPosition = geometry.pos(); } else { - realPosition.setValueAndWarp(geometry.pos()); - realPosition = prePos; + realPosition->setValueAndWarp(geometry.pos()); + *realPosition = prePos; } } else if (ANIMSTYLE.starts_with("popin")) { @@ -535,25 +533,25 @@ void CLayerSurface::startAnimation(bool in, bool instant) { const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5}); const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f; - alpha.setValueAndWarp(in ? 0.f : 1.f); - alpha = in ? 1.f : 0.f; + alpha->setValueAndWarp(in ? 0.f : 1.f); + *alpha = in ? 1.f : 0.f; if (in) { - realSize.setValueAndWarp(GOALSIZE); - realPosition.setValueAndWarp(GOALPOS); - realSize = geometry.size(); - realPosition = geometry.pos(); + realSize->setValueAndWarp(GOALSIZE); + realPosition->setValueAndWarp(GOALPOS); + *realSize = geometry.size(); + *realPosition = geometry.pos(); } else { - realSize.setValueAndWarp(geometry.size()); - realPosition.setValueAndWarp(geometry.pos()); - realSize = GOALSIZE; - realPosition = GOALPOS; + realSize->setValueAndWarp(geometry.size()); + realPosition->setValueAndWarp(geometry.pos()); + *realSize = GOALSIZE; + *realPosition = GOALPOS; } } else { // fade - realPosition.setValueAndWarp(geometry.pos()); - realSize.setValueAndWarp(geometry.size()); - alpha = in ? 1.f : 0.f; + realPosition->setValueAndWarp(geometry.pos()); + realSize->setValueAndWarp(geometry.size()); + *alpha = in ? 1.f : 0.f; } if (!in) @@ -564,7 +562,7 @@ bool CLayerSurface::isFadedOut() { if (!fadingOut) return false; - return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated(); + return !realPosition->isBeingAnimated() && !realSize->isBeingAnimated() && !alpha->isBeingAnimated(); } int CLayerSurface::popupsCount() { diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index e906fc6f..3a03e57e 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -18,17 +18,17 @@ class CLayerSurface { public: ~CLayerSurface(); - void applyRules(); - void startAnimation(bool in, bool instant = false); - bool isFadedOut(); - int popupsCount(); + void applyRules(); + void startAnimation(bool in, bool instant = false); + bool isFadedOut(); + int popupsCount(); - CAnimatedVariable realPosition; - CAnimatedVariable realSize; - CAnimatedVariable alpha; + PHLANIMVAR realPosition; + PHLANIMVAR realSize; + PHLANIMVAR alpha; - WP layerSurface; - wl_list link; + WP layerSurface; + wl_list link; // the header providing the enum type cannot be imported here int interactivity = 0; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 692a75e3..ce286b28 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -243,9 +243,9 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) { Vector2D CPopup::t1ParentCoords() { if (!m_pWindowOwner.expired()) - return m_pWindowOwner->m_vRealPosition.value(); + return m_pWindowOwner->m_vRealPosition->value(); if (!m_pLayerOwner.expired()) - return m_pLayerOwner->realPosition.value(); + return m_pLayerOwner->realPosition->value(); ASSERT(false); return {}; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 893411bd..62854f80 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -169,7 +169,7 @@ Vector2D CSubsurface::coordsGlobal() { Vector2D coords = coordsRelativeToParent(); if (!m_pWindowParent.expired()) - coords += m_pWindowParent->m_vRealPosition.value(); + coords += m_pWindowParent->m_vRealPosition->value(); else if (m_pPopupParent) coords += m_pPopupParent->coordsGlobal(); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 5e88f507..9ed8ec49 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -72,7 +72,7 @@ Vector2D CWLSurface::correctSmallVec() const { const auto SIZE = getViewporterCorrectedSize(); const auto O = m_pWindowOwner.lock(); - return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize); + return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize->value() / O->m_vReportedSize); } Vector2D CWLSurface::correctSmallVecBuf() const { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 60914198..8175fc57 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -11,12 +12,16 @@ #include "../render/decorations/CHyprBorderDecoration.hpp" #include "../config/ConfigValue.hpp" #include "../managers/TokenManager.hpp" +#include "../managers/AnimationManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" +#include "../helpers/Color.hpp" #include + using namespace Hyprutils::String; +using namespace Hyprutils::Animation; PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -24,16 +29,16 @@ PHLWINDOW CWindow::create(SP surface) { pWindow->m_pSelf = pWindow; pWindow->m_bIsX11 = true; - pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); - pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingFromWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -47,16 +52,16 @@ PHLWINDOW CWindow::create(SP resource) { pWindow->m_pSelf = pWindow; resource->toplevel->window = pWindow; - pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); - pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingFromWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -118,8 +123,8 @@ SBoxExtents CWindow::getFullWindowExtents() { if (m_sWindowData.dimAround.valueOrDefault()) { if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) - return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, - {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; + return {{m_vRealPosition->value().x - PMONITOR->vecPosition.x, m_vRealPosition->value().y - PMONITOR->vecPosition.y}, + {PMONITOR->vecSize.x - (m_vRealPosition->value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition->value().y - PMONITOR->vecPosition.y)}}; } SBoxExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; @@ -183,8 +188,8 @@ CBox CWindow::getFullWindowBoundingBox() { auto maxExtents = getFullWindowExtents(); - CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().y - maxExtents.topLeft.y, - m_vRealSize.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y}; + CBox finalBox = {m_vRealPosition->value().x - maxExtents.topLeft.x, m_vRealPosition->value().y - maxExtents.topLeft.y, + m_vRealSize->value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize->value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y}; return finalBox; } @@ -238,7 +243,7 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) { if (properties & FULL_EXTENTS) EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock(), false)); - CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; + CBox box = {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; box.addExtents(EXTENTS); return box; @@ -409,9 +414,9 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; - m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); - m_fMovingToWorkspaceAlpha = 0.F; - m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); + m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); + m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); + *m_fMovingToWorkspaceAlpha = 0.F; m_pWorkspace = pWorkspace; @@ -439,7 +444,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } // update xwayland coords - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->value()); if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) @@ -475,10 +480,6 @@ PHLWINDOW CWindow::x11TransientFor() { return nullptr; } -static void unregisterVar(void* ptr) { - ((CBaseAnimatedVariable*)ptr)->unregister(); -} - void CWindow::onUnmap() { static auto PCLOSEONLASTSPECIAL = CConfigValue("misc:close_special_on_empty"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); @@ -497,19 +498,6 @@ void CWindow::onUnmap() { m_iLastWorkspace = m_pWorkspace->m_iID; - m_vRealPosition.setCallbackOnEnd(unregisterVar); - m_vRealSize.setCallbackOnEnd(unregisterVar); - m_fBorderFadeAnimationProgress.setCallbackOnEnd(unregisterVar); - m_fBorderAngleAnimationProgress.setCallbackOnEnd(unregisterVar); - m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar); - m_fAlpha.setCallbackOnEnd(unregisterVar); - m_cRealShadowColor.setCallbackOnEnd(unregisterVar); - m_fDimPercent.setCallbackOnEnd(unregisterVar); - m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar); - m_fMovingFromWorkspaceAlpha.setCallbackOnEnd(unregisterVar); - - m_vRealSize.setCallbackOnBegin(nullptr); - std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) { @@ -541,34 +529,24 @@ void CWindow::onUnmap() { void CWindow::onMap() { // JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped) - m_vRealPosition.resetAllCallbacks(); - m_vRealSize.resetAllCallbacks(); - m_fBorderFadeAnimationProgress.resetAllCallbacks(); - m_fBorderAngleAnimationProgress.resetAllCallbacks(); - m_fActiveInactiveAlpha.resetAllCallbacks(); - m_fAlpha.resetAllCallbacks(); - m_cRealShadowColor.resetAllCallbacks(); - m_fDimPercent.resetAllCallbacks(); - m_fMovingToWorkspaceAlpha.resetAllCallbacks(); - m_fMovingFromWorkspaceAlpha.resetAllCallbacks(); + m_vRealPosition->resetAllCallbacks(); + m_vRealSize->resetAllCallbacks(); + m_fBorderFadeAnimationProgress->resetAllCallbacks(); + m_fBorderAngleAnimationProgress->resetAllCallbacks(); + m_fActiveInactiveAlpha->resetAllCallbacks(); + m_fAlpha->resetAllCallbacks(); + m_cRealShadowColor->resetAllCallbacks(); + m_fDimPercent->resetAllCallbacks(); + m_fMovingToWorkspaceAlpha->resetAllCallbacks(); + m_fMovingFromWorkspaceAlpha->resetAllCallbacks(); - m_vRealPosition.registerVar(); - m_vRealSize.registerVar(); - m_fBorderFadeAnimationProgress.registerVar(); - m_fBorderAngleAnimationProgress.registerVar(); - m_fActiveInactiveAlpha.registerVar(); - m_fAlpha.registerVar(); - m_cRealShadowColor.registerVar(); - m_fDimPercent.registerVar(); - m_fMovingToWorkspaceAlpha.registerVar(); - m_fMovingFromWorkspaceAlpha.registerVar(); + m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); + m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); - m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); + m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); + *m_fBorderAngleAnimationProgress = 1.f; - m_fBorderAngleAnimationProgress.setValueAndWarp(0.f); - m_fBorderAngleAnimationProgress = 1.f; - - m_fMovingFromWorkspaceAlpha.setValueAndWarp(1.F); + m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); @@ -584,20 +562,22 @@ void CWindow::onMap() { m_pPopupHead = std::make_unique(m_pSelf.lock()); } -void CWindow::onBorderAngleAnimEnd(void* ptr) { - const auto PANIMVAR = (CAnimatedVariable*)ptr; - - const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle; - - if (STYLE != "loop" || !PANIMVAR->getConfig()->pValues->internalEnabled) +void CWindow::onBorderAngleAnimEnd(WP pav) { + const auto PAV = pav.lock(); + if (!PAV) return; + if (PAV->getStyle() != "loop" || !PAV->enabled()) + return; + + const auto PANIMVAR = dynamic_cast*>(PAV.get()); + PANIMVAR->setCallbackOnEnd(nullptr); // we remove the callback here because otherwise setvalueandwarp will recurse this PANIMVAR->setValueAndWarp(0); *PANIMVAR = 1.f; - PANIMVAR->setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); + PANIMVAR->setCallbackOnEnd([&](WP pav) { onBorderAngleAnimEnd(pav); }, false); } void CWindow::setHidden(bool hidden) { @@ -830,10 +810,10 @@ bool CWindow::isInCurvedCorner(double x, double y) { return false; // (x0, y0), (x0, y1), ... are the center point of rounding at each corner - double x0 = m_vRealPosition.value().x + ROUNDING; - double y0 = m_vRealPosition.value().y + ROUNDING; - double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING; - double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING; + double x0 = m_vRealPosition->value().x + ROUNDING; + double y0 = m_vRealPosition->value().y + ROUNDING; + double x1 = m_vRealPosition->value().x + m_vRealSize->value().x - ROUNDING; + double y1 = m_vRealPosition->value().y + m_vRealSize->value().y - ROUNDING; if (x < x0 && y < y0) { return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); @@ -1032,8 +1012,8 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { if (FULLSCREEN) g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE); - const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); - const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); + const auto PWINDOWSIZE = PCURRENT->m_vRealSize->goal(); + const auto PWINDOWPOS = PCURRENT->m_vRealPosition->goal(); PCURRENT->setHidden(true); pWindow->setHidden(false); // can remove m_pLastWindow @@ -1041,8 +1021,8 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow); if (PCURRENT->m_bIsFloating) { - pWindow->m_vRealPosition.setValueAndWarp(PWINDOWPOS); - pWindow->m_vRealSize.setValueAndWarp(PWINDOWSIZE); + pWindow->m_vRealPosition->setValueAndWarp(PWINDOWPOS); + pWindow->m_vRealSize->setValueAndWarp(PWINDOWSIZE); } g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -1124,22 +1104,22 @@ void CWindow::updateGroupOutputs() { curr->m_pMonitor = m_pMonitor; curr->moveToWorkspace(WS); - curr->m_vRealPosition = m_vRealPosition.goal(); - curr->m_vRealSize = m_vRealSize.goal(); + *curr->m_vRealPosition = m_vRealPosition->goal(); + *curr->m_vRealSize = m_vRealSize->goal(); curr = curr->m_sGroupData.pNextWindow.lock(); } } Vector2D CWindow::middle() { - return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f; + return m_vRealPosition->goal() + m_vRealSize->goal() / 2.f; } bool CWindow::opaque() { - if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f) + if (m_fAlpha->value() != 1.f || m_fActiveInactiveAlpha->value() != 1.f) return false; - if (m_vRealSize.goal().floor() != m_vReportedSize) + if (m_vRealSize->goal().floor() != m_vReportedSize) return false; const auto PWORKSPACE = m_pWorkspace; @@ -1147,7 +1127,7 @@ bool CWindow::opaque() { if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall) return false; - if (PWORKSPACE->m_fAlpha.value() != 1.f) + if (PWORKSPACE->m_fAlpha->value() != 1.f) return false; if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture) @@ -1237,15 +1217,13 @@ void CWindow::setSuspended(bool suspend) { } bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) { - CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; + CBox wbox = {m_vRealPosition->value(), m_vRealSize->value()}; return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); } void CWindow::setAnimationsToMove() { - auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); - m_vRealPosition.setConfig(PANIMCFG); - m_vRealSize.setConfig(PANIMCFG); + m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); m_bAnimatingIn = false; } @@ -1266,16 +1244,16 @@ void CWindow::onWorkspaceAnimUpdate() { return; const auto WINBB = getFullWindowBoundingBox(); - if (PWORKSPACE->m_vRenderOffset.value().x != 0) { - const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x; + if (PWORKSPACE->m_vRenderOffset->value().x != 0) { + const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().x / PWSMON->vecSize.x; if (WINBB.x < PWSMON->vecPosition.x) offset.x += (PWSMON->vecPosition.x - WINBB.x) * PROGRESS; if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) offset.x += (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS; - } else if (PWORKSPACE->m_vRenderOffset.value().y != 0) { - const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y; + } else if (PWORKSPACE->m_vRenderOffset->value().y != 0) { + const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().y / PWSMON->vecSize.y; if (WINBB.y < PWSMON->vecPosition.y) offset.y += (PWSMON->vecPosition.y - WINBB.y) * PROGRESS; @@ -1306,12 +1284,12 @@ int CWindow::surfacesCount() { } void CWindow::clampWindowSize(const std::optional minSize, const std::optional maxSize) { - const Vector2D REALSIZE = m_vRealSize.goal(); + const Vector2D REALSIZE = m_vRealSize->goal(); const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); const Vector2D DELTA = REALSIZE - NEWSIZE; - m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0; - m_vRealSize = NEWSIZE; + *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; + *m_vRealSize = NEWSIZE; g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE); } @@ -1525,7 +1503,7 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->goal(), true); g_pInputManager->refocus(); g_pHyprRenderer->damageWindow(m_pSelf.lock()); return; @@ -1538,19 +1516,19 @@ void CWindow::onX11Configure(CBox box) { const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos()); - m_vRealPosition.setValueAndWarp(LOGICALPOS); - m_vRealSize.setValueAndWarp(box.size()); + m_vRealPosition->setValueAndWarp(LOGICALPOS); + m_vRealSize->setValueAndWarp(box.size()); static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { - m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); + m_vRealSize->setValueAndWarp(m_vRealSize->goal() / PMONITOR->scale); m_fX11SurfaceScaledBy = PMONITOR->scale; } } - m_vPosition = m_vRealPosition.value(); - m_vSize = m_vRealSize.value(); + m_vPosition = m_vRealPosition->value(); + m_vSize = m_vRealSize->value(); m_pXWaylandSurface->configure(box); @@ -1562,7 +1540,7 @@ void CWindow::onX11Configure(CBox box) { if (!m_pWorkspace || !m_pWorkspace->isVisible()) return; // further things are only for visible windows - m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace; + m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition->value() + m_vRealSize->value() / 2.f)->activeWorkspace; g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 3ceaf594..37189a00 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -233,8 +233,8 @@ class CWindow { Vector2D m_vSize = Vector2D(0, 0); // this is the real position and size used to draw the thing - CAnimatedVariable m_vRealPosition; - CAnimatedVariable m_vRealSize; + PHLANIMVAR m_vRealPosition; + PHLANIMVAR m_vRealSize; // for not spamming the protocols Vector2D m_vReportedPosition; @@ -298,19 +298,19 @@ class CWindow { std::unique_ptr m_pPopupHead; // Animated border - CGradientValueData m_cRealBorderColor = {0}; - CGradientValueData m_cRealBorderColorPrevious = {0}; - CAnimatedVariable m_fBorderFadeAnimationProgress; - CAnimatedVariable m_fBorderAngleAnimationProgress; + CGradientValueData m_cRealBorderColor = {0}; + CGradientValueData m_cRealBorderColorPrevious = {0}; + PHLANIMVAR m_fBorderFadeAnimationProgress; + PHLANIMVAR m_fBorderAngleAnimationProgress; // Fade in-out - CAnimatedVariable m_fAlpha; - bool m_bFadingOut = false; - bool m_bReadyToDelete = false; - Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in - Vector2D m_vOriginalClosedSize; // drawing the closing animations - SBoxExtents m_eOriginalClosedExtents; - bool m_bAnimatingIn = false; + PHLANIMVAR m_fAlpha; + bool m_bFadingOut = false; + bool m_bReadyToDelete = false; + Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in + Vector2D m_vOriginalClosedSize; // drawing the closing animations + SBoxExtents m_eOriginalClosedExtents; + bool m_bAnimatingIn = false; // For pinned (sticky) windows bool m_bPinned = false; @@ -336,18 +336,18 @@ class CWindow { std::vector> m_vTransformers; // for alpha - CAnimatedVariable m_fActiveInactiveAlpha; - CAnimatedVariable m_fMovingFromWorkspaceAlpha; + PHLANIMVAR m_fActiveInactiveAlpha; + PHLANIMVAR m_fMovingFromWorkspaceAlpha; // animated shadow color - CAnimatedVariable m_cRealShadowColor; + PHLANIMVAR m_cRealShadowColor; // animated tint - CAnimatedVariable m_fDimPercent; + PHLANIMVAR m_fDimPercent; // animate moving to an invisible workspace - int m_iMonitorMovedFrom = -1; // -1 means not moving - CAnimatedVariable m_fMovingToWorkspaceAlpha; + int m_iMonitorMovedFrom = -1; // -1 means not moving + PHLANIMVAR m_fMovingToWorkspaceAlpha; // swallowing PHLWINDOWREF m_pSwallowed; @@ -432,7 +432,7 @@ class CWindow { float getScrollTouchpad(); void updateWindowData(); void updateWindowData(const struct SWorkspaceRule&); - void onBorderAngleAnimEnd(void* ptr); + void onBorderAngleAnimEnd(WP pav); bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); int popupsCount(); @@ -467,7 +467,7 @@ class CWindow { Vector2D requestedMaxSize(); CBox getWindowMainSurfaceBox() const { - return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; + return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; } // listeners diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 0930ef00..cab19254 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -1,7 +1,10 @@ #include "Workspace.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "config/ConfigManager.hpp" +#include "managers/AnimationManager.hpp" +#include #include using namespace Hyprutils::String; @@ -19,16 +22,10 @@ CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, boo void CWorkspace::init(PHLWORKSPACE self) { m_pSelf = self; - m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : - g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), - self, AVARDAMAGE_ENTIRE); - m_fAlpha.create(AVARTYPE_FLOAT, - m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, - AVARDAMAGE_ENTIRE); - m_fAlpha.setValueAndWarp(1.f); - - m_vRenderOffset.registerVar(); - m_fAlpha.registerVar(); + g_pAnimationManager->createAnimation(Vector2D(0, 0), m_vRenderOffset, + g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(1.f, m_fAlpha, g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, + AVARDAMAGE_ENTIRE); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self); if (RULEFORTHIS.defaultName.has_value()) @@ -63,8 +60,6 @@ SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const { } CWorkspace::~CWorkspace() { - m_vRenderOffset.unregister(); - Debug::log(LOG, "Destroying workspace ID {}", m_iID); // check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing. @@ -82,15 +77,15 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { if (!instant) { const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); - m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); - m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); + m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); + m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); } - const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; + const auto ANIMSTYLE = m_fAlpha->getStyle(); static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); // set floating windows offset callbacks - m_vRenderOffset.setUpdateCallback([&](void*) { + m_vRenderOffset->setUpdateCallback([&](auto) { for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->workspaceID() != m_iID) continue; @@ -110,84 +105,84 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } } - m_fAlpha.setValueAndWarp(1.f); - m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); + m_fAlpha->setValueAndWarp(1.f); + m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); if (ANIMSTYLE.starts_with("slidefadevert")) { if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); - m_fAlpha = 1.f; - m_vRenderOffset = Vector2D(0, 0); + m_fAlpha->setValueAndWarp(0.f); + m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); + *m_fAlpha = 1.f; + *m_vRenderOffset = Vector2D(0, 0); } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; - m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; + *m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); } } else { if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); - m_fAlpha = 1.f; - m_vRenderOffset = Vector2D(0, 0); + m_fAlpha->setValueAndWarp(0.f); + m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); + *m_fAlpha = 1.f; + *m_vRenderOffset = Vector2D(0, 0); } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; - m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; + *m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); } } } else if (ANIMSTYLE == "fade") { - m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. + m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_fAlpha = 1.f; + m_fAlpha->setValueAndWarp(0.f); + *m_fAlpha = 1.f; } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; } } else if (ANIMSTYLE == "slidevert") { // fallback is slide const auto PMONITOR = m_pMonitor.lock(); const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP; - m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. + m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. if (in) { - m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); - m_vRenderOffset = Vector2D(0, 0); + m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); + *m_vRenderOffset = Vector2D(0, 0); } else { - m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); + *m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); } } else { // fallback is slide const auto PMONITOR = m_pMonitor.lock(); const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP; - m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. + m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. if (in) { - m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); - m_vRenderOffset = Vector2D(0, 0); + m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); + *m_vRenderOffset = Vector2D(0, 0); } else { - m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); + *m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); } } if (m_bIsSpecialWorkspace) { // required for open/close animations if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_fAlpha = 1.f; + m_fAlpha->setValueAndWarp(0.f); + *m_fAlpha = 1.f; } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; } } if (instant) { - m_vRenderOffset.warp(); - m_fAlpha.warp(); + m_vRenderOffset->warp(); + m_fAlpha->warp(); } } @@ -633,7 +628,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); + g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->value(), true); } } diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 606485a2..f86dd656 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -37,9 +37,9 @@ class CWorkspace { wl_array m_wlrCoordinateArr; // for animations - CAnimatedVariable m_vRenderOffset; - CAnimatedVariable m_fAlpha; - bool m_bForceRendering = false; + PHLANIMVAR m_vRenderOffset; + PHLANIMVAR m_fAlpha; + bool m_bForceRendering = false; // allows damage to propagate. bool m_bVisible = false; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a20cbcad..8082cdc9 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -12,10 +12,12 @@ #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" #include "../xwayland/XSurface.hpp" +#include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" #include using namespace Hyprutils::String; +using namespace Hyprutils::Animation; // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // @@ -27,15 +29,17 @@ using namespace Hyprutils::String; // // // ------------------------------------------------------------ // -static void setAnimToMove(void* data) { - auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); +static void setVector2DAnimToMove(WP pav) { + const auto PAV = pav.lock(); + if (!PAV) + return; - CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data; + CAnimatedVariable* animvar = dynamic_cast*>(PAV.get()); + animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); - animvar->setConfig(PANIMCFG); - - if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated()) - animvar->getWindow()->m_bAnimatingIn = false; + const auto PHLWINDOW = animvar->m_Context.pWindow.lock(); + if (PHLWINDOW && PHLWINDOW->m_vRealPosition->isBeingAnimated() && PHLWINDOW->m_vRealSize->isBeingAnimated()) + PHLWINDOW->m_bAnimatingIn = false; } void Events::listener_mapWindow(void* owner, void* data) { @@ -378,10 +382,10 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto MAXSIZE = PWINDOW->requestedMaxSize(); const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : - stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); + stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize->goal().x, PMONITOR->vecSize.x); const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : - stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y); + stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize->goal().y, PMONITOR->vecSize.y); Debug::log(LOG, "Rule size, applying to {}", PWINDOW); @@ -418,7 +422,7 @@ void Events::listener_mapWindow(void* owner, void* data) { (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x); if (subtractWindow) - posX -= PWINDOW->m_vRealSize.goal().x; + posX -= PWINDOW->m_vRealSize->goal().x; if (CURSOR) Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!"); @@ -430,7 +434,7 @@ void Events::listener_mapWindow(void* owner, void* data) { posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x; } else { posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x + - (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x); + (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize->goal().x); } } @@ -441,7 +445,7 @@ void Events::listener_mapWindow(void* owner, void* data) { (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y); if (subtractWindow) - posY -= PWINDOW->m_vRealSize.goal().y; + posY -= PWINDOW->m_vRealSize->goal().y; if (CURSOR) Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!"); @@ -453,7 +457,7 @@ void Events::listener_mapWindow(void* owner, void* data) { posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y; } else { posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y + - (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y); + (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize->goal().y); } } @@ -461,15 +465,15 @@ void Events::listener_mapWindow(void* owner, void* data) { int borderSize = PWINDOW->getRealBorderSize(); posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize), - (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize)); + (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize->goal().x - borderSize)); posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize), - (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize)); + (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize->goal().y - borderSize)); } Debug::log(LOG, "Rule move, applying to {}", PWINDOW); - PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition; + *PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition; PWINDOW->setHidden(false); } catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); } @@ -481,7 +485,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (ARGS[1] == "1") RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f; - PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; + *PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize->goal() / 2.f + RESERVEDOFFSET; break; } @@ -491,7 +495,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // set the pseudo size to the GOAL of our current size // because the windows are animated on RealSize - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal(); + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal(); g_pCompositor->changeWindowZOrder(PWINDOW, true); } else { @@ -524,7 +528,7 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (!setPseudo) - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10); + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal() - Vector2D(10, 10); } const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); @@ -554,11 +558,11 @@ void Events::listener_mapWindow(void* owner, void* data) { (!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); - PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); - PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH); + PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PACTIVEALPHA); + PWINDOW->m_fDimPercent->setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH); } else { - PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); - PWINDOW->m_fDimPercent.setValueAndWarp(0); + PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PINACTIVEALPHA); + PWINDOW->m_fDimPercent->setValueAndWarp(0); } if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) @@ -571,8 +575,8 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE); - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); if (requestedFSState.has_value()) { PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE); g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value()); @@ -607,7 +611,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bFirstMap = false; - Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal()); + Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition->goal(), PWINDOW->m_vRealSize->goal()); auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName; g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)}); @@ -620,17 +624,17 @@ void Events::listener_mapWindow(void* owner, void* data) { // do animations g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false); - PWINDOW->m_fAlpha.setValueAndWarp(0.f); - PWINDOW->m_fAlpha = 1.f; + PWINDOW->m_fAlpha->setValueAndWarp(0.f); + *PWINDOW->m_fAlpha = 1.f; - PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove); - PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove); + PWINDOW->m_vRealPosition->setCallbackOnEnd(setVector2DAnimToMove); + PWINDOW->m_vRealSize->setCallbackOnEnd(setVector2DAnimToMove); // recalc the values for this window g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); // avoid this window being visible if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating) - PWINDOW->m_fAlpha.setValueAndWarp(0.f); + PWINDOW->m_fAlpha->setValueAndWarp(0.f); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform); @@ -666,8 +670,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { const auto PMONITOR = PWINDOW->m_pMonitor.lock(); if (PMONITOR) { - PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition; - PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value(); + PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition->value() - PMONITOR->vecPosition; + PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize->value(); PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents(); } @@ -757,12 +761,12 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pCompositor->addToFadingOutSafe(PWINDOW); - if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it + if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. + *PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition->value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it // anims g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true); - PWINDOW->m_fAlpha = 0.f; + *PWINDOW->m_fAlpha = 0.f; // recheck idle inhibitors g_pInputManager->recheckIdleInhibitorStatus(); @@ -812,7 +816,7 @@ void Events::listener_commitWindow(void* owner, void* data) { g_pSeatManager->isPointerFrameSkipped = false; g_pSeatManager->isPointerFrameCommit = false; } else - g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, + g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition->goal().x, PWINDOW->m_vRealPosition->goal().y, PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); if (g_pSeatManager->isPointerFrameSkipped) { @@ -903,8 +907,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect) return; - const auto POS = PWINDOW->m_vRealPosition.goal(); - const auto SIZ = PWINDOW->m_vRealSize.goal(); + const auto POS = PWINDOW->m_vRealPosition->goal(); + const auto SIZ = PWINDOW->m_vRealSize->goal(); if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1}) PWINDOW->setHidden(false); @@ -912,7 +916,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->setHidden(true); if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); g_pHyprRenderer->damageWindow(PWINDOW); return; } @@ -926,27 +930,27 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size()); g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); + PWINDOW->m_vRealPosition->setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2) - PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); + PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = PWINDOW->m_pMonitor.lock(); PMONITOR) { - PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); + PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_vRealSize->goal() / PMONITOR->scale); } } - PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); - PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal(); + PWINDOW->m_vPosition = PWINDOW->m_vRealPosition->goal(); + PWINDOW->m_vSize = PWINDOW->m_vRealSize->goal(); - PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace; + PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition->value() + PWINDOW->m_vRealSize->value() / 2.f)->activeWorkspace; g_pCompositor->changeWindowZOrder(PWINDOW, true); PWINDOW->updateWindowDecos(); g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goal(); - PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal(); + PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition->goal(); + PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize->goal(); } } diff --git a/src/helpers/AnimatedVariable.cpp b/src/helpers/AnimatedVariable.cpp deleted file mode 100644 index ab5643a6..00000000 --- a/src/helpers/AnimatedVariable.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "AnimatedVariable.hpp" -#include "../managers/AnimationManager.hpp" -#include "../config/ConfigManager.hpp" - -CBaseAnimatedVariable::CBaseAnimatedVariable(eAnimatedVarType type) : m_Type(type) { - ; // dummy var -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - m_pWindow = pWindow; - - m_bDummy = false; -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - m_pLayer = pLayer; - - m_bDummy = false; -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - m_pWorkspace = pWorkspace; - - m_bDummy = false; -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - - m_bDummy = false; -} - -CBaseAnimatedVariable::~CBaseAnimatedVariable() { - unregister(); -} - -void CBaseAnimatedVariable::unregister() { - if (!g_pAnimationManager) - return; - std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; }); - m_bIsRegistered = false; - disconnectFromActive(); -} - -void CBaseAnimatedVariable::registerVar() { - if (!m_bIsRegistered) - g_pAnimationManager->m_vAnimatedVariables.push_back(this); - m_bIsRegistered = true; -} - -float CBaseAnimatedVariable::getPercent() { - const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::steady_clock::now() - animationBegin).count(); - return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f); -} - -float CBaseAnimatedVariable::getCurveValue() { - if (!m_bIsBeingAnimated) - return 1.f; - - const auto SPENT = getPercent(); - - if (SPENT >= 1.f) - return 1.f; - - return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT); -} - -void CBaseAnimatedVariable::connectToActive() { - g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up - - if (!m_bIsConnectedToActive) - g_pAnimationManager->m_vActiveAnimatedVariables.push_back(this); - - m_bIsConnectedToActive = true; -} - -void CBaseAnimatedVariable::disconnectFromActive() { - std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; }); - m_bIsConnectedToActive = false; -} diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index a1da00da..e7d5fd8c 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -1,15 +1,18 @@ #pragma once -#include -#include -#include -#include -#include "math/Math.hpp" +#include + #include "Color.hpp" #include "../defines.hpp" -#include "../debug/Log.hpp" #include "../desktop/DesktopTypes.hpp" +enum eAVarDamagePolicy : int8_t { + AVARDAMAGE_NONE = -1, + AVARDAMAGE_ENTIRE = 0, + AVARDAMAGE_BORDER, + AVARDAMAGE_SHADOW +}; + enum eAnimatedVarType : int8_t { AVARTYPE_INVALID = -1, AVARTYPE_FLOAT, @@ -42,20 +45,6 @@ struct STypeToAnimatedVarType_t { template inline constexpr eAnimatedVarType typeToeAnimatedVarType = STypeToAnimatedVarType_t::value; -enum eAVarDamagePolicy : int8_t { - AVARDAMAGE_NONE = -1, - AVARDAMAGE_ENTIRE = 0, - AVARDAMAGE_BORDER, - AVARDAMAGE_SHADOW -}; - -class CAnimationManager; -struct SAnimationPropertyConfig; -class CHyprRenderer; -class CWindow; -class CWorkspace; -class CLayerSurface; - // Utility to define a concept as a list of possible type template concept OneOf = (... or std::same_as); @@ -66,245 +55,19 @@ concept OneOf = (... or std::same_as); template concept Animable = OneOf; -class CBaseAnimatedVariable { - public: - CBaseAnimatedVariable(eAnimatedVarType type); - void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy); - void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy); - void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy); - void create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy); +struct SAnimationContext { + PHLWINDOWREF pWindow; + PHLWORKSPACEREF pWorkspace; + PHLLSREF pLayer; - CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete; - CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete; - CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete; - CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete; - - virtual ~CBaseAnimatedVariable(); - - void unregister(); - void registerVar(); - - virtual void warp(bool endCallback = true) = 0; - - // - void setConfig(SAnimationPropertyConfig* pConfig) { - m_pConfig = pConfig; - } - - SAnimationPropertyConfig* getConfig() { - return m_pConfig; - } - - /* returns the spent (completion) % */ - float getPercent(); - - /* returns the current curve value */ - float getCurveValue(); - - // checks if an animation is in progress - bool isBeingAnimated() const { - return m_bIsBeingAnimated; - } - - /* sets a function to be ran when the animation finishes. - if an animation is not running, runs instantly. - if "remove" is set to true, will remove the callback when ran. */ - void setCallbackOnEnd(std::function func, bool remove = true) { - m_fEndCallback = std::move(func); - m_bRemoveEndAfterRan = remove; - - if (!isBeingAnimated()) - onAnimationEnd(); - } - - /* sets a function to be ran when an animation is started. - if "remove" is set to true, will remove the callback when ran. */ - void setCallbackOnBegin(std::function func, bool remove = true) { - m_fBeginCallback = std::move(func); - m_bRemoveBeginAfterRan = remove; - } - - /* Sets the update callback, called every time the value is animated and a step is done - Warning: calling unregisterVar/registerVar in this handler will cause UB */ - void setUpdateCallback(std::function func) { - m_fUpdateCallback = std::move(func); - } - - /* resets all callbacks. Does not call any. */ - void resetAllCallbacks() { - m_fBeginCallback = nullptr; - m_fEndCallback = nullptr; - m_fUpdateCallback = nullptr; - m_bRemoveBeginAfterRan = false; - m_bRemoveEndAfterRan = false; - } - - PHLWINDOW getWindow() { - return m_pWindow.lock(); - } - - protected: - PHLWINDOWREF m_pWindow; - PHLWORKSPACEREF m_pWorkspace; - PHLLSREF m_pLayer; - - SAnimationPropertyConfig* m_pConfig = nullptr; - - bool m_bDummy = true; - bool m_bIsRegistered = false; - bool m_bIsBeingAnimated = false; - - std::chrono::steady_clock::time_point animationBegin; - - eAVarDamagePolicy m_eDamagePolicy = AVARDAMAGE_NONE; - eAnimatedVarType m_Type; - - bool m_bRemoveEndAfterRan = true; - bool m_bRemoveBeginAfterRan = true; - std::function m_fEndCallback; - std::function m_fBeginCallback; - std::function m_fUpdateCallback; - - bool m_bIsConnectedToActive = false; - - void connectToActive(); - - void disconnectFromActive(); - - // methods - void onAnimationEnd() { - m_bIsBeingAnimated = false; - disconnectFromActive(); - - if (m_fEndCallback) { - // loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false. - auto removeEndCallback = m_bRemoveEndAfterRan; - m_fEndCallback(this); - if (removeEndCallback) - m_fEndCallback = nullptr; // reset - } - } - - void onAnimationBegin() { - m_bIsBeingAnimated = true; - connectToActive(); - - if (m_fBeginCallback) { - m_fBeginCallback(this); - if (m_bRemoveBeginAfterRan) - m_fBeginCallback = nullptr; // reset - } - } - - friend class CAnimationManager; - friend class CWorkspace; - friend class CLayerSurface; - friend class CHyprRenderer; + eAVarDamagePolicy eDamagePolicy = AVARDAMAGE_NONE; }; template -class CAnimatedVariable : public CBaseAnimatedVariable { - public: - CAnimatedVariable() : CBaseAnimatedVariable(typeToeAnimatedVarType) { - ; - } // dummy var +using CAnimatedVariable = Hyprutils::Animation::CGenericAnimatedVariable; - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { - create(pAnimConfig, pWindow, policy); - m_Value = value; - m_Goal = value; - } - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) { - create(pAnimConfig, pLayer, policy); - m_Value = value; - m_Goal = value; - } - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { - create(pAnimConfig, pWorkspace, policy); - m_Value = value; - m_Goal = value; - } - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) { - create(pAnimConfig, policy); - m_Value = value; - m_Goal = value; - } +template +using PHLANIMVAR = SP>; - using CBaseAnimatedVariable::create; - - CAnimatedVariable(const CAnimatedVariable&) = delete; - CAnimatedVariable(CAnimatedVariable&&) = delete; - CAnimatedVariable& operator=(const CAnimatedVariable&) = delete; - CAnimatedVariable& operator=(CAnimatedVariable&&) = delete; - - ~CAnimatedVariable() = default; - - // gets the current vector value (real time) - const VarType& value() const { - return m_Value; - } - - // gets the goal vector value - const VarType& goal() const { - return m_Goal; - } - - CAnimatedVariable& operator=(const VarType& v) { - if (v == m_Goal) - return *this; - - m_Goal = v; - animationBegin = std::chrono::steady_clock::now(); - m_Begun = m_Value; - - onAnimationBegin(); - - return *this; - } - - // Sets the actual stored value, without affecting the goal, but resets the timer - void setValue(const VarType& v) { - if (v == m_Value) - return; - - m_Value = v; - animationBegin = std::chrono::steady_clock::now(); - m_Begun = m_Value; - - onAnimationBegin(); - } - - // Sets the actual value and goal - void setValueAndWarp(const VarType& v) { - m_Goal = v; - m_bIsBeingAnimated = true; - warp(); - } - - void warp(bool endCallback = true) override { - if (!m_bIsBeingAnimated) - return; - - m_Value = m_Goal; - - m_bIsBeingAnimated = false; - - if (m_fUpdateCallback) - m_fUpdateCallback(this); - - if (endCallback) - onAnimationEnd(); - } - - private: - VarType m_Value{}; - VarType m_Goal{}; - VarType m_Begun{}; - - // owners - - friend class CAnimationManager; - friend class CWorkspace; - friend class CLayerSurface; - friend class CHyprRenderer; -}; +template +using PHLANIMVARREF = WP>; diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp deleted file mode 100644 index a0610fc9..00000000 --- a/src/helpers/BezierCurve.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "BezierCurve.hpp" -#include "../debug/Log.hpp" -#include "../macros.hpp" - -#include -#include - -void CBezierCurve::setup(std::vector* pVec) { - const auto BEGIN = std::chrono::high_resolution_clock::now(); - - // Avoid reallocations by reserving enough memory upfront - m_vPoints.resize(pVec->size() + 2); - m_vPoints[0] = Vector2D(0, 0); // Start point - size_t index = 1; // Start after the first element - for (const auto& vec : *pVec) { - if (index < m_vPoints.size() - 1) { // Bounds check to ensure safety - m_vPoints[index] = vec; - ++index; - } - } - m_vPoints.back() = Vector2D(1, 1); // End point - - RASSERT(m_vPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_vPoints.size()); - - // bake BAKEDPOINTS points for faster lookups - // T -> X ( / BAKEDPOINTS ) - for (int i = 0; i < BAKEDPOINTS; ++i) { - float const t = (i + 1) / (float)BAKEDPOINTS; - m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t)); - } - - const auto ELAPSEDUS = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f; - const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f; - - const auto BEGINCALC = std::chrono::high_resolution_clock::now(); - for (int j = 1; j < 10; ++j) { - float i = j / 10.0f; - getYForPoint(i); - } - const auto ELAPSEDCALCAVG = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f; - - Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE, - ELAPSEDUS, ELAPSEDCALCAVG); -} - -float CBezierCurve::getXForT(float const& t) const { - float t2 = t * t; - float t3 = t2 * t; - - return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].x + 3 * t2 * (1 - t) * m_vPoints[2].x + t3 * m_vPoints[3].x; -} - -float CBezierCurve::getYForT(float const& t) const { - float t2 = t * t; - float t3 = t2 * t; - - return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].y + 3 * t2 * (1 - t) * m_vPoints[2].y + t3 * m_vPoints[3].y; -} - -// Todo: this probably can be done better and faster -float CBezierCurve::getYForPoint(float const& x) const { - if (x >= 1.f) - return 1.f; - if (x <= 0.f) - return 0.f; - - int index = 0; - bool below = true; - for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) { - if (below) - index += step; - else - index -= step; - - below = m_aPointsBaked[index].x < x; - } - - int lowerIndex = index - (!below || index == BAKEDPOINTS - 1); - - // in the name of performance i shall make a hack - const auto LOWERPOINT = &m_aPointsBaked[lowerIndex]; - const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1]; - - const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x); - - if (std::isnan(PERCINDELTA) || std::isinf(PERCINDELTA)) // can sometimes happen for VERY small x - return 0.f; - - return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA; -} diff --git a/src/helpers/BezierCurve.hpp b/src/helpers/BezierCurve.hpp deleted file mode 100644 index e643fb41..00000000 --- a/src/helpers/BezierCurve.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include -#include "math/Math.hpp" - -constexpr int BAKEDPOINTS = 255; -constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS; - -// an implementation of a cubic bezier curve -// might do better later -class CBezierCurve { - public: - // sets up the bezier curve. - // this EXCLUDES the 0,0 and 1,1 points, - void setup(std::vector* points); - - float getYForT(float const& t) const; - float getXForT(float const& t) const; - float getYForPoint(float const& x) const; - - private: - // this INCLUDES the 0,0 and 1,1 points. - std::vector m_vPoints; - - std::array m_aPointsBaked; -}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 76df00b3..e833e661 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1127,16 +1127,16 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && !w->isX11OverrideRedirect()) { // if it's floating and the middle isnt on the current mon, move it to the center const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE); - Vector2D pos = w->m_vRealPosition.goal(); + Vector2D pos = w->m_vRealPosition->goal(); if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x, PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) { // not on any monitor, center - pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f; + pos = middle() / 2.f - w->m_vRealSize->goal() / 2.f; } else pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition; - w->m_vRealPosition = pos; - w->m_vPosition = pos; + *w->m_vRealPosition = pos; + w->m_vPosition = pos; } } } diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 0a6ef55d..b6e3ac12 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -5,7 +5,6 @@ #include "../desktop/Window.hpp" #include "../desktop/Subsurface.hpp" #include "../desktop/Popup.hpp" -#include "AnimatedVariable.hpp" #include "../desktop/WLSurface.hpp" #include "signal/Signal.hpp" #include "math/Math.hpp" diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index d3cd8273..5e0dcf5e 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -3,13 +3,13 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../render/pass/TexPassElement.hpp" +#include "../managers/AnimationManager.hpp" #include -using namespace Hyprutils::Utils; +using namespace Hyprutils::Animation; CHyprError::CHyprError() { - m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); - m_fFadeOpacity.registerVar(); + g_pAnimationManager->createAnimation(0.f, m_fFadeOpacity, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { if (!m_bIsCreated) @@ -23,16 +23,14 @@ CHyprError::CHyprError() { if (!m_bIsCreated) return; - if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged) + if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged) g_pHyprRenderer->damageBox(&m_bDamageBox); }); m_pTexture = makeShared(); } -CHyprError::~CHyprError() { - m_fFadeOpacity.unregister(); -} +CHyprError::~CHyprError() = default; void CHyprError::queueCreate(std::string message, const CHyprColor& color) { m_szQueued = message; @@ -43,10 +41,10 @@ void CHyprError::createQueued() { if (m_bIsCreated) m_pTexture->destroyTexture(); - m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); + m_fFadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); - m_fFadeOpacity.setValueAndWarp(0.f); - m_fFadeOpacity = 1.f; + m_fFadeOpacity->setValueAndWarp(0.f); + *m_fFadeOpacity = 1.f; const auto PMONITOR = g_pCompositor->m_vMonitors.front(); @@ -176,8 +174,8 @@ void CHyprError::draw() { } if (m_bQueuedDestroy) { - if (!m_fFadeOpacity.isBeingAnimated()) { - if (m_fFadeOpacity.value() == 0.f) { + if (!m_fFadeOpacity->isBeingAnimated()) { + if (m_fFadeOpacity->value() == 0.f) { m_bQueuedDestroy = false; m_pTexture->destroyTexture(); m_bIsCreated = false; @@ -189,8 +187,8 @@ void CHyprError::draw() { return; } else { - m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); - m_fFadeOpacity = 0.f; + m_fFadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); + *m_fFadeOpacity = 0.f; } } } @@ -202,7 +200,7 @@ void CHyprError::draw() { m_bDamageBox.x = (int)PMONITOR->vecPosition.x; m_bDamageBox.y = (int)PMONITOR->vecPosition.y; - if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged) + if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged) g_pHyprRenderer->damageBox(&m_bDamageBox); m_bMonitorChanged = false; @@ -210,7 +208,7 @@ void CHyprError::draw() { CTexPassElement::SRenderData data; data.tex = m_pTexture; data.box = monbox; - data.a = m_fFadeOpacity.value(); + data.a = m_fFadeOpacity->value(); g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 042dccd0..9a662423 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -19,17 +19,17 @@ class CHyprError { float height(); // logical private: - void createQueued(); - std::string m_szQueued = ""; - CHyprColor m_cQueued; - bool m_bQueuedDestroy = false; - bool m_bIsCreated = false; - SP m_pTexture; - CAnimatedVariable m_fFadeOpacity; - CBox m_bDamageBox = {0, 0, 0, 0}; - float m_fLastHeight = 0.F; + void createQueued(); + std::string m_szQueued = ""; + CHyprColor m_cQueued; + bool m_bQueuedDestroy = false; + bool m_bIsCreated = false; + SP m_pTexture; + PHLANIMVAR m_fFadeOpacity; + CBox m_bDamageBox = {0, 0, 0, 0}; + float m_fLastHeight = 0.F; - bool m_bMonitorChanged = false; + bool m_bMonitorChanged = false; }; inline std::unique_ptr g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time. diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index dc6e37dd..2ee41eba 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -192,16 +192,16 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealPosition = wb.pos(); - PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealSize = wb.size(); - PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } @@ -209,8 +209,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for if (force) { g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); g_pHyprRenderer->damageWindow(PWINDOW); } @@ -508,8 +508,8 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) { const auto PFULLWINDOW = pWorkspace->getFullscreenWindow(); if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { - PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; - PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; + *PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; + *PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) { SDwindleNodeData fakeNode; fakeNode.pWindow = PFULLWINDOW; @@ -554,8 +554,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn const auto PNODE = getNodeFromWindow(PWINDOW); if (!PNODE) { - PWINDOW->m_vRealSize = - (PWINDOW->m_vRealSize.goal() + pixResize) + *PWINDOW->m_vRealSize = + (PWINDOW->m_vRealSize->goal() + pixResize) .clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); PWINDOW->updateWindowDecos(); return; @@ -575,7 +575,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn if (!m_PseudoDragFlags.started) { m_PseudoDragFlags.started = true; - const auto pseudoSize = PWINDOW->m_vRealSize.goal(); + const auto pseudoSize = PWINDOW->m_vRealSize->goal(); const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2))); if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) { @@ -743,10 +743,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu // save position and size if floating if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { - pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); - pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vSize = pWindow->m_vRealSize.goal(); + pWindow->m_vLastFloatingSize = pWindow->m_vRealSize->goal(); + pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vSize = pWindow->m_vRealSize->goal(); } if (EFFECTIVE_MODE == FSMODE_NONE) { @@ -756,8 +756,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu applyNodeDataToWindow(PNODE); else { // get back its' dimensions from position and size - pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; - pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; + *pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; + *pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); @@ -765,8 +765,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu } else { // apply new pos and size being monitors' box if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { - pWindow->m_vRealPosition = PMONITOR->vecPosition; - pWindow->m_vRealSize = PMONITOR->vecSize; + *pWindow->m_vRealPosition = PMONITOR->vecPosition; + *pWindow->m_vRealSize = PMONITOR->vecSize; } else { // This is a massive hack. // We make a fake "only" node and apply diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f875b99c..eeebd815 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -106,7 +106,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { const auto PWINDOWSURFACE = pWindow->m_pWLSurface->resource(); - pWindow->m_vRealSize = PWINDOWSURFACE->current.size; + *pWindow->m_vRealSize = PWINDOWSURFACE->current.size; if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect()) { // XDG windows should be fine. TODO: check for weird atoms? @@ -115,23 +115,23 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } // reject any windows with size <= 5x5 - if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5) - pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; + if (pWindow->m_vRealSize->goal().x <= 5 || pWindow->m_vRealSize->goal().y <= 5) + *pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; if (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect()) { if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0) - pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); + *pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); else - pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f, - PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f); + *pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize->goal().x) / 2.f, + PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize->goal().y) / 2.f); } else { - pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f, - PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f); + *pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize->goal().x) / 2.f, + PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize->goal().y) / 2.f); } } else { // we respect the size. - pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + *pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height); // check if it's on the correct monitor! Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f; @@ -150,35 +150,35 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_bIsX11) { // if the pos isn't set, fall back to the center placement if it's not a child, otherwise middle of parent if available if (!pWindow->m_bIsX11 && pWindow->m_pXDGSurface->toplevel->parent && validMapped(pWindow->m_pXDGSurface->toplevel->parent->window)) - pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition.goal() + - pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize.goal() / 2.F - desiredGeometry.size() / 2.F; + *pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition->goal() + + pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize->goal() / 2.F - desiredGeometry.size() / 2.F; else - pWindow->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.F - desiredGeometry.size() / 2.F; + *pWindow->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.F - desiredGeometry.size() / 2.F; } else { // if it is, we respect where it wants to put itself, but apply monitor offset if outside // most of these are popups if (const auto POPENMON = g_pCompositor->getMonitorFromVector(middlePoint); POPENMON->ID != PMONITOR->ID) - pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->vecPosition + PMONITOR->vecPosition; + *pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->vecPosition + PMONITOR->vecPosition; else - pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); + *pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); } } if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) - pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale; + *pWindow->m_vRealSize = pWindow->m_vRealSize->goal() / PMONITOR->scale; if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect())) { - pWindow->m_vRealPosition.warp(); - pWindow->m_vRealSize.warp(); + pWindow->m_vRealPosition->warp(); + pWindow->m_vRealSize->warp(); } if (!pWindow->isX11OverrideRedirect()) { - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal()); + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize->goal()); g_pCompositor->changeWindowZOrder(pWindow, true); } else { - pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goal(); + pWindow->m_vPendingReportedSize = pWindow->m_vRealSize->goal(); pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; } } @@ -250,18 +250,18 @@ void IHyprLayout::onBeginDragWindow() { if (!DRAGGINGWINDOW->m_bIsFloating) { if (g_pInputManager->dragMode == MBIND_MOVE) { - DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize.goal() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor(); + DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize->goal() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor(); changeWindowFloatingMode(DRAGGINGWINDOW); DRAGGINGWINDOW->m_bIsFloating = true; DRAGGINGWINDOW->m_bDraggingTiled = true; - DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goal() / 2.f; + *DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize->goal() / 2.f; } } m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); - m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goal(); - m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goal(); + m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition->goal(); + m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize->goal(); m_vLastDragXY = m_vBeginDragXY; // get the grab corner @@ -348,10 +348,10 @@ void IHyprLayout::onEndDragWindow() { if (DRAGGINGWINDOW->m_sGroupData.pNextWindow) { PHLWINDOW next = DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock(); while (next != DRAGGINGWINDOW) { - next->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members - next->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members - next->m_vRealPosition = pWindow->m_vRealPosition.goal(); // match the position of group members - next = next->m_sGroupData.pNextWindow.lock(); + next->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members + *next->m_vRealSize = pWindow->m_vRealSize->goal(); // match the size of group members + *next->m_vRealPosition = pWindow->m_vRealPosition->goal(); // match the position of group members + next = next->m_sGroupData.pNextWindow.lock(); } } @@ -360,7 +360,7 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->m_bDraggingTiled = false; if (pWindow->m_bIsFloating) - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize.goal()); // match the size of the window + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize->goal()); // match the size of the window static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); @@ -593,7 +593,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (g_pInputManager->dragMode == MBIND_MOVE) { Vector2D newPos = m_vBeginDragPositionXY + DELTA; - Vector2D newSize = DRAGGINGWINDOW->m_vRealSize.goal(); + Vector2D newSize = DRAGGINGWINDOW->m_vRealSize->goal(); if (*SNAPENABLED && !DRAGGINGWINDOW->m_bDraggingTiled) performSnap(newPos, newSize, DRAGGINGWINDOW, MBIND_MOVE, -1, m_vBeginDragSizeXY); @@ -602,11 +602,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { wb.round(); if (*PANIMATEMOUSE) - DRAGGINGWINDOW->m_vRealPosition = wb.pos(); + *DRAGGINGWINDOW->m_vRealPosition = wb.pos(); else - DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal()); + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize->goal()); } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { @@ -671,21 +671,21 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { wb.round(); if (*PANIMATE) { - DRAGGINGWINDOW->m_vRealSize = wb.size(); - DRAGGINGWINDOW->m_vRealPosition = wb.pos(); + *DRAGGINGWINDOW->m_vRealSize = wb.size(); + *DRAGGINGWINDOW->m_vRealPosition = wb.pos(); } else { - DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(wb.size()); - DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->m_vRealSize->setValueAndWarp(wb.size()); + DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); } - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal()); + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize->goal()); } else { resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); } } // get middle point - Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.value() + DRAGGINGWINDOW->m_vRealSize.value() / 2.f; + Vector2D middle = DRAGGINGWINDOW->m_vRealPosition->value() + DRAGGINGWINDOW->m_vRealSize->value() / 2.f; // and check its monitor const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); @@ -719,7 +719,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { EMIT_HOOK_EVENT("changeFloatingMode", pWindow); if (!TILED) { - const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f); + const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition->value() + pWindow->m_vRealSize->value() / 2.f); pWindow->m_pMonitor = PNEWMON; pWindow->moveToWorkspace(PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace); pWindow->updateGroupOutputs(); @@ -730,12 +730,12 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE); // save real pos cuz the func applies the default 5,5 mid - const auto PSAVEDPOS = pWindow->m_vRealPosition.goal(); - const auto PSAVEDSIZE = pWindow->m_vRealSize.goal(); + const auto PSAVEDPOS = pWindow->m_vRealPosition->goal(); + const auto PSAVEDSIZE = pWindow->m_vRealSize->goal(); // if the window is pseudo, update its size if (!pWindow->m_bDraggingTiled) - pWindow->m_vPseudoSize = pWindow->m_vRealSize.goal(); + pWindow->m_vPseudoSize = pWindow->m_vRealSize->goal(); pWindow->m_vLastFloatingSize = PSAVEDSIZE; @@ -744,8 +744,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { onWindowCreatedTiling(pWindow); - pWindow->m_vRealPosition.setValue(PSAVEDPOS); - pWindow->m_vRealSize.setValue(PSAVEDSIZE); + pWindow->m_vRealPosition->setValue(PSAVEDPOS); + pWindow->m_vRealSize->setValue(PSAVEDSIZE); // fix pseudo leaving artifacts g_pHyprRenderer->damageMonitor(pWindow->m_pMonitor.lock()); @@ -757,16 +757,16 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->changeWindowZOrder(pWindow, true); - CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; + CBox wb = {pWindow->m_vRealPosition->goal() + (pWindow->m_vRealSize->goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; wb.round(); - if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && - DELTALESSTHAN(pWindow->m_vRealSize.value().y, pWindow->m_vLastFloatingSize.y, 10)) { + if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize->value().x, pWindow->m_vLastFloatingSize.x, 10) && + DELTALESSTHAN(pWindow->m_vRealSize->value().y, pWindow->m_vLastFloatingSize.y, 10)) { wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}}; } - pWindow->m_vRealPosition = wb.pos(); - pWindow->m_vRealSize = wb.size(); + *pWindow->m_vRealPosition = wb.pos(); + *pWindow->m_vRealSize = wb.size(); pWindow->m_vSize = wb.pos(); pWindow->m_vPosition = wb.size(); @@ -798,7 +798,7 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, PHLWINDOW pWindow) { PWINDOW->setAnimationsToMove(); - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta; + *PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition->goal() + delta; g_pHyprRenderer->damageWindow(PWINDOW); } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 225246f0..e6e22326 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -301,8 +301,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { const auto PFULLWINDOW = pWorkspace->getFullscreenWindow(); if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { - PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; - PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; + *PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; + *PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) { SMasterNodeData fakeNode; fakeNode.pWindow = PFULLWINDOW; @@ -672,16 +672,16 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealPosition = wb.pos(); - PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealPosition = wb.pos(); - PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } @@ -689,8 +689,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { if (m_bForceWarps && !*PANIMATE) { g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); g_pHyprRenderer->damageWindow(PWINDOW); } @@ -711,8 +711,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne const auto PNODE = getNodeFromWindow(PWINDOW); if (!PNODE) { - PWINDOW->m_vRealSize = - (PWINDOW->m_vRealSize.goal() + pixResize) + *PWINDOW->m_vRealSize = + (PWINDOW->m_vRealSize->goal() + pixResize) .clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); PWINDOW->updateWindowDecos(); return; @@ -852,10 +852,10 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul // save position and size if floating if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { - pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); - pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vSize = pWindow->m_vRealSize.goal(); + pWindow->m_vLastFloatingSize = pWindow->m_vRealSize->goal(); + pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vSize = pWindow->m_vRealSize->goal(); } if (EFFECTIVE_MODE == FSMODE_NONE) { @@ -865,8 +865,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul applyNodeDataToWindow(PNODE); else { // get back its' dimensions from position and size - pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; - pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; + *pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; + *pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); @@ -874,8 +874,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul } else { // apply new pos and size being monitors' box if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { - pWindow->m_vRealPosition = PMONITOR->vecPosition; - pWindow->m_vRealSize = PMONITOR->vecSize; + *pWindow->m_vRealPosition = PMONITOR->vecPosition; + *pWindow->m_vRealSize = PMONITOR->vecSize; } else { // This is a massive hack. // We make a fake "only" node and apply diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index cff438b1..6bfeed83 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -1,6 +1,9 @@ #include "AnimationManager.hpp" #include "../Compositor.hpp" #include "HookSystemManager.hpp" +#include "config/ConfigManager.hpp" +#include "desktop/DesktopTypes.hpp" +#include "helpers/AnimatedVariable.hpp" #include "macros.hpp" #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" @@ -9,6 +12,8 @@ #include "../helpers/varlist/VarList.hpp" #include +#include +#include static int wlTick(SP self, void* data) { if (g_pAnimationManager) @@ -26,324 +31,245 @@ static int wlTick(SP self, void* data) { return 0; } -CAnimationManager::CAnimationManager() { - std::vector points = {Vector2D(0.0, 0.75), Vector2D(0.15, 1.0)}; - m_mBezierCurves["default"].setup(&points); - - points = {Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)}; - m_mBezierCurves["linear"].setup(&points); - +CHyprAnimationManager::CHyprAnimationManager() { m_pAnimationTimer = SP(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr)); g_pEventLoopManager->addTimer(m_pAnimationTimer); + + addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)); } -void CAnimationManager::removeAllBeziers() { - m_mBezierCurves.clear(); +template +void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { + if (POINTY >= 1.f || warp || av.value() == av.goal()) { + av.warp(); + return; + } - // add the default one - std::vector points = {Vector2D(0.0, 0.75), Vector2D(0.15, 1.0)}; - m_mBezierCurves["default"].setup(&points); - - points = {Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)}; - m_mBezierCurves["linear"].setup(&points); + const auto DELTA = av.goal() - av.begun(); + av.value() = av.begun() + DELTA * POINTY; } -void CAnimationManager::addBezierWithName(std::string name, const Vector2D& p1, const Vector2D& p2) { - std::vector points = {p1, p2}; - m_mBezierCurves[name].setup(&points); +void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { + if (POINTY >= 1.f || warp || av.value() == av.goal()) { + av.warp(); + return; + } + + // convert both to OkLab, then lerp that, and convert back. + // This is not as fast as just lerping rgb, but it's WAY more precise... + // Use the CHyprColor cache for OkLab + + const auto& L1 = av.begun().asOkLab(); + const auto& L2 = av.goal().asOkLab(); + + static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; + + const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{ + .l = lerp(L1.l, L2.l, POINTY), + .a = lerp(L1.a, L2.a, POINTY), + .b = lerp(L1.b, L2.b, POINTY), + }; + + av.value() = {lerped, lerp(av.begun().a, av.goal().a, POINTY)}; } -void CAnimationManager::onTicked() { - m_bTickScheduled = false; +template +static void handleUpdate(CAnimatedVariable& av, bool warp) { + PHLWINDOW PWINDOW = av.m_Context.pWindow.lock(); + PHLWORKSPACE PWORKSPACE = av.m_Context.pWorkspace.lock(); + PHLLS PLAYER = av.m_Context.pLayer.lock(); + PHLMONITOR PMONITOR = nullptr; + bool animationsDisabled = warp; + + if (PWINDOW) { + if (av.m_Context.eDamagePolicy == AVARDAMAGE_ENTIRE) + g_pHyprRenderer->damageWindow(PWINDOW); + else if (av.m_Context.eDamagePolicy == AVARDAMAGE_BORDER) { + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); + PDECO->damageEntire(); + } else if (av.m_Context.eDamagePolicy == AVARDAMAGE_SHADOW) { + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); + PDECO->damageEntire(); + } + + PMONITOR = PWINDOW->m_pMonitor.lock(); + if (!PMONITOR) + return; + + animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); + } else if (PWORKSPACE) { + PMONITOR = PWORKSPACE->m_pMonitor.lock(); + if (!PMONITOR) + return; + + // dont damage the whole monitor on workspace change, unless it's a special workspace, because dim/blur etc + if (PWORKSPACE->m_bIsSpecialWorkspace) + g_pHyprRenderer->damageMonitor(PMONITOR); + + // TODO: just make this into a damn callback already vax... + for (auto const& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE) + continue; + + if (w->m_bIsFloating && !w->m_bPinned) { + // still doing the full damage hack for floating because sometimes when the window + // goes through multiple monitors the last rendered frame is missing damage somehow?? + const CBox windowBoxNoOffset = w->getFullWindowBoundingBox(); + const CBox monitorBox = {PMONITOR->vecPosition, PMONITOR->vecSize}; + if (windowBoxNoOffset.intersection(monitorBox) != windowBoxNoOffset) // on edges between multiple monitors + g_pHyprRenderer->damageWindow(w, true); + } + + if (PWORKSPACE->m_bIsSpecialWorkspace) + g_pHyprRenderer->damageWindow(w, true); // hack for special too because it can cross multiple monitors + } + + // damage any workspace window that is on any monitor + for (auto const& w : g_pCompositor->m_vWindows) { + if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned) + continue; + + g_pHyprRenderer->damageWindow(w); + } + } else if (PLAYER) { + // "some fucking layers miss 1 pixel???" -- vaxry + CBox expandBox = CBox{PLAYER->realPosition->value(), PLAYER->realSize->value()}; + expandBox.expand(5); + g_pHyprRenderer->damageBox(&expandBox); + + PMONITOR = g_pCompositor->getMonitorFromVector(PLAYER->realPosition->goal() + PLAYER->realSize->goal() / 2.F); + if (!PMONITOR) + return; + animationsDisabled = animationsDisabled || PLAYER->noAnimations; + } + + const auto SPENT = av.getPercent(); + const auto PBEZIER = g_pAnimationManager->getBezier(av.getBezierName()); + const auto POINTY = PBEZIER->getYForPoint(SPENT); + + if constexpr (std::same_as) { + updateColorVariable(av, POINTY, animationsDisabled); + } else { + updateVariable(av, POINTY, animationsDisabled); + } + + av.onUpdate(); + + switch (av.m_Context.eDamagePolicy) { + case AVARDAMAGE_ENTIRE: { + if (PWINDOW) { + PWINDOW->updateWindowDecos(); + g_pHyprRenderer->damageWindow(PWINDOW); + } else if (PWORKSPACE) { + for (auto const& w : g_pCompositor->m_vWindows) { + if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE) + continue; + + w->updateWindowDecos(); + + // damage any workspace window that is on any monitor + if (!w->m_bPinned) + g_pHyprRenderer->damageWindow(w); + } + } else if (PLAYER) { + if (PLAYER->layer <= 1) + g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); + + // some fucking layers miss 1 pixel??? + CBox expandBox = CBox{PLAYER->realPosition->value(), PLAYER->realSize->value()}; + expandBox.expand(5); + g_pHyprRenderer->damageBox(&expandBox); + } + break; + } + case AVARDAMAGE_BORDER: { + RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); + + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); + PDECO->damageEntire(); + + break; + } + case AVARDAMAGE_SHADOW: { + RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); + + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); + + PDECO->damageEntire(); + + break; + } + default: { + break; + } + } + + // manually schedule a frame + if (PMONITOR) + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION); } -void CAnimationManager::tick() { +void CHyprAnimationManager::tick() { static std::chrono::time_point lastTick = std::chrono::high_resolution_clock::now(); m_fLastTickTime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - lastTick).count() / 1000.0; lastTick = std::chrono::high_resolution_clock::now(); - if (m_vActiveAnimatedVariables.empty()) - return; - - bool animGlobalDisabled = false; - static auto PANIMENABLED = CConfigValue("animations:enabled"); - - if (!*PANIMENABLED) - animGlobalDisabled = true; - - static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:shadow:enabled"); - - const auto DEFAULTBEZIER = m_mBezierCurves.find("default"); - - std::vector animationEndedVars; - - for (auto const& av : m_vActiveAnimatedVariables) { - - if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) { - av->warp(false); - animationEndedVars.push_back(av); + for (auto const& pav : m_vActiveAnimatedVariables) { + const auto PAV = pav.lock(); + if (!PAV) continue; - } - // get the spent % (0 - 1) - const float SPENT = av->getPercent(); + // for disabled anims just warp + bool warp = !*PANIMENABLED || !PAV->enabled(); - // window stuff - PHLWINDOW PWINDOW = av->m_pWindow.lock(); - PHLWORKSPACE PWORKSPACE = av->m_pWorkspace.lock(); - PHLLS PLAYER = av->m_pLayer.lock(); - PHLMONITOR PMONITOR = nullptr; - bool animationsDisabled = animGlobalDisabled; - - if (PWINDOW) { - if (av->m_eDamagePolicy == AVARDAMAGE_ENTIRE) { - g_pHyprRenderer->damageWindow(PWINDOW); - } else if (av->m_eDamagePolicy == AVARDAMAGE_BORDER) { - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); - PDECO->damageEntire(); - } else if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW) { - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); - PDECO->damageEntire(); - } - - PMONITOR = PWINDOW->m_pMonitor.lock(); - if (!PMONITOR) - continue; - animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); - } else if (PWORKSPACE) { - PMONITOR = PWORKSPACE->m_pMonitor.lock(); - if (!PMONITOR) - continue; - - // dont damage the whole monitor on workspace change, unless it's a special workspace, because dim/blur etc - if (PWORKSPACE->m_bIsSpecialWorkspace) - g_pHyprRenderer->damageMonitor(PMONITOR); - - // TODO: just make this into a damn callback already vax... - for (auto const& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE) - continue; - - if (w->m_bIsFloating && !w->m_bPinned) { - // still doing the full damage hack for floating because sometimes when the window - // goes through multiple monitors the last rendered frame is missing damage somehow?? - const CBox windowBoxNoOffset = w->getFullWindowBoundingBox(); - const CBox monitorBox = {PMONITOR->vecPosition, PMONITOR->vecSize}; - if (windowBoxNoOffset.intersection(monitorBox) != windowBoxNoOffset) // on edges between multiple monitors - g_pHyprRenderer->damageWindow(w, true); - } - - if (PWORKSPACE->m_bIsSpecialWorkspace) - g_pHyprRenderer->damageWindow(w, true); // hack for special too because it can cross multiple monitors - } - - // damage any workspace window that is on any monitor - for (auto const& w : g_pCompositor->m_vWindows) { - if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned) - continue; - - g_pHyprRenderer->damageWindow(w); - } - } else if (PLAYER) { - // "some fucking layers miss 1 pixel???" -- vaxry - CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; - expandBox.expand(5); - g_pHyprRenderer->damageBox(&expandBox); - - PMONITOR = g_pCompositor->getMonitorFromVector(PLAYER->realPosition.goal() + PLAYER->realSize.goal() / 2.F); - if (!PMONITOR) - continue; - animationsDisabled = animationsDisabled || PLAYER->noAnimations; - } - - const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? PWINDOW->m_pWorkspace->isVisible() : true; - - // beziers are with a switch unforto - // TODO: maybe do something cleaner - - static const auto updateVariable = [this](CAnimatedVariable& av, const float SPENT, const CBezierCurve& DEFAULTBEZIER, const bool DISABLED) { - // for disabled anims just warp - if (av.m_pConfig->pValues->internalEnabled == 0 || DISABLED) { - av.warp(false); - return; - } - - if (SPENT >= 1.f || av.m_Begun == av.m_Goal) { - av.warp(false); - return; - } - - const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier); - const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER.getYForPoint(SPENT); - - const auto DELTA = av.m_Goal - av.m_Begun; - - if (BEZIER != m_mBezierCurves.end()) - av.m_Value = av.m_Begun + DELTA * POINTY; - else - av.m_Value = av.m_Begun + DELTA * POINTY; - }; - - static const auto updateColorVariable = [this](CAnimatedVariable& av, const float SPENT, const CBezierCurve& DEFAULTBEZIER, const bool DISABLED) { - // for disabled anims just warp - if (av.m_pConfig->pValues->internalEnabled == 0 || DISABLED) { - av.warp(false); - return; - } - - if (SPENT >= 1.f || av.m_Begun == av.m_Goal) { - av.warp(false); - return; - } - - const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier); - const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER.getYForPoint(SPENT); - - // convert both to OkLab, then lerp that, and convert back. - // This is not as fast as just lerping rgb, but it's WAY more precise... - // Use the CHyprColor cache for OkLab - - const auto& L1 = av.m_Begun.asOkLab(); - const auto& L2 = av.m_Goal.asOkLab(); - - static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; - - const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{ - .l = lerp(L1.l, L2.l, POINTY), - .a = lerp(L1.a, L2.a, POINTY), - .b = lerp(L1.b, L2.b, POINTY), - }; - - av.m_Value = {lerped, lerp(av.m_Begun.a, av.m_Goal.a, POINTY)}; - - return; - }; - - switch (av->m_Type) { + switch (PAV->m_Type) { case AVARTYPE_FLOAT: { - auto typedAv = dynamic_cast*>(av); - updateVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled); - break; - } + auto pTypedAV = dynamic_cast*>(PAV.get()); + RASSERT(pTypedAV, "Failed to upcast animated float"); + handleUpdate(*pTypedAV, warp); + } break; case AVARTYPE_VECTOR: { - auto typedAv = dynamic_cast*>(av); - updateVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled); - break; - } + auto pTypedAV = dynamic_cast*>(PAV.get()); + RASSERT(pTypedAV, "Failed to upcast animated Vector2D"); + handleUpdate(*pTypedAV, warp); + } break; case AVARTYPE_COLOR: { - auto typedAv = dynamic_cast*>(av); - updateColorVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled); - break; - } + auto pTypedAV = dynamic_cast*>(PAV.get()); + RASSERT(pTypedAV, "Failed to upcast animated CHyprColor"); + handleUpdate(*pTypedAV, warp); + } break; default: UNREACHABLE(); } - // set size and pos if valid, but only if damage policy entire (dont if border for example) - if (validMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && !PWINDOW->isX11OverrideRedirect()) - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - - // check if we did not finish animating. If so, trigger onAnimationEnd. - if (!av->isBeingAnimated()) - animationEndedVars.push_back(av); - - // lastly, handle damage, but only if whatever we are animating is visible. - if (!VISIBLE) - continue; - - if (av->m_fUpdateCallback) - av->m_fUpdateCallback(av); - - switch (av->m_eDamagePolicy) { - case AVARDAMAGE_ENTIRE: { - if (PWINDOW) { - PWINDOW->updateWindowDecos(); - g_pHyprRenderer->damageWindow(PWINDOW); - } else if (PWORKSPACE) { - for (auto const& w : g_pCompositor->m_vWindows) { - if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE) - continue; - - w->updateWindowDecos(); - - // damage any workspace window that is on any monitor - if (!w->m_bPinned) - g_pHyprRenderer->damageWindow(w); - } - } else if (PLAYER) { - if (PLAYER->layer <= 1) - g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); - - // some fucking layers miss 1 pixel??? - CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; - expandBox.expand(5); - g_pHyprRenderer->damageBox(&expandBox); - } - break; - } - case AVARDAMAGE_BORDER: { - RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); - - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); - PDECO->damageEntire(); - - break; - } - case AVARDAMAGE_SHADOW: { - RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); - - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); - - PDECO->damageEntire(); - - break; - } - default: { - break; - } - } - - // manually schedule a frame - if (PMONITOR) - g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION); } - // do it here, because if this alters the animation vars vec we would be in trouble above. - for (auto const& ave : animationEndedVars) { - ave->onAnimationEnd(); - } + tickDone(); } -bool CAnimationManager::deltaSmallToFlip(const Vector2D& a, const Vector2D& b) { - return std::abs(a.x - b.x) < 0.5f && std::abs(a.y - b.y) < 0.5f; -} +void CHyprAnimationManager::scheduleTick() { + if (m_bTickScheduled) + return; -bool CAnimationManager::deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b) { - return std::abs(a.r - b.r) < 0.5f && std::abs(a.g - b.g) < 0.5f && std::abs(a.b - b.b) < 0.5f && std::abs(a.a - b.a) < 0.5f; -} + m_bTickScheduled = true; -bool CAnimationManager::deltaSmallToFlip(const float& a, const float& b) { - return std::abs(a - b) < 0.5f; -} + const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor; -bool CAnimationManager::deltazero(const Vector2D& a, const Vector2D& b) { - return a.x == b.x && a.y == b.y; -} - -bool CAnimationManager::deltazero(const float& a, const float& b) { - return a == b; -} - -bool CAnimationManager::deltazero(const CHyprColor& a, const CHyprColor& b) { - return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; -} - -bool CAnimationManager::bezierExists(const std::string& bezier) { - for (auto const& [bc, bz] : m_mBezierCurves) { - if (bc == bezier) - return true; + if (!PMOSTHZ) { + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16)); + return; } - return false; + float refreshDelayMs = std::floor(1000.f / PMOSTHZ->refreshRate); + + const float SINCEPRES = std::chrono::duration_cast(std::chrono::steady_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f; + + const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it + + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds((int)std::floor(TOPRES))); +} + +void CHyprAnimationManager::onTicked() { + m_bTickScheduled = false; } // @@ -351,24 +277,24 @@ bool CAnimationManager::bezierExists(const std::string& bezier) { // // -void CAnimationManager::animationPopin(PHLWINDOW pWindow, bool close, float minPerc) { - const auto GOALPOS = pWindow->m_vRealPosition.goal(); - const auto GOALSIZE = pWindow->m_vRealSize.goal(); +void CHyprAnimationManager::animationPopin(PHLWINDOW pWindow, bool close, float minPerc) { + const auto GOALPOS = pWindow->m_vRealPosition->goal(); + const auto GOALSIZE = pWindow->m_vRealSize->goal(); if (!close) { - pWindow->m_vRealSize.setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y})); - pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_Value / 2.f); + pWindow->m_vRealSize->setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y})); + pWindow->m_vRealPosition->setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize->value() / 2.f); } else { - pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}); - pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_Goal / 2.f; + *pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}); + *pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize->goal() / 2.f; } } -void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, bool close) { - pWindow->m_vRealSize.warp(false); // size we preserve in slide +void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, bool close) { + pWindow->m_vRealSize->warp(false); // size we preserve in slide - const auto GOALPOS = pWindow->m_vRealPosition.goal(); - const auto GOALSIZE = pWindow->m_vRealSize.goal(); + const auto GOALPOS = pWindow->m_vRealPosition->goal(); + const auto GOALSIZE = pWindow->m_vRealSize->goal(); const auto PMONITOR = pWindow->m_pMonitor.lock(); @@ -388,9 +314,9 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo posOffset = Vector2D(GOALPOS.x, PMONITOR->vecPosition.y - GOALSIZE.y); if (!close) - pWindow->m_vRealPosition.setValue(posOffset); + pWindow->m_vRealPosition->setValue(posOffset); else - pWindow->m_vRealPosition = posOffset; + *pWindow->m_vRealPosition = posOffset; return; } @@ -423,33 +349,33 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo } if (!close) - pWindow->m_vRealPosition.setValue(posOffset); + pWindow->m_vRealPosition->setValue(posOffset); else - pWindow->m_vRealPosition = posOffset; + *pWindow->m_vRealPosition = posOffset; } -void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { +void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (!close) { - pWindow->m_vRealPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsIn"); - pWindow->m_vRealSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsIn"); - pWindow->m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeIn"); + pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); + pWindow->m_vRealSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); + pWindow->m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); } else { - pWindow->m_vRealPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsOut"); - pWindow->m_vRealSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsOut"); - pWindow->m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeOut"); + pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); + pWindow->m_vRealSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); + pWindow->m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); } - auto ANIMSTYLE = pWindow->m_vRealPosition.m_pConfig->pValues->internalStyle; + std::string ANIMSTYLE = pWindow->m_vRealPosition->getStyle(); transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower); CVarList animList(ANIMSTYLE, 0, 's'); // if the window is not being animated, that means the layout set a fixed size for it, don't animate. - if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated()) + if (!pWindow->m_vRealPosition->isBeingAnimated() && !pWindow->m_vRealSize->isBeingAnimated()) return; // if the animation is disabled and we are leaving, ignore the anim to prevent the snapshot being fucked - if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled) + if (!pWindow->m_vRealPosition->enabled()) return; if (pWindow->m_sWindowData.animationStyle.hasValue()) { @@ -494,7 +420,7 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { } } -std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { +std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { if (style.starts_with("slide")) return ""; @@ -568,39 +494,3 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config, return ""; } - -CBezierCurve* CAnimationManager::getBezier(const std::string& name) { - const auto BEZIER = std::find_if(m_mBezierCurves.begin(), m_mBezierCurves.end(), [&](const auto& other) { return other.first == name; }); - - return BEZIER == m_mBezierCurves.end() ? &m_mBezierCurves["default"] : &BEZIER->second; -} - -std::unordered_map CAnimationManager::getAllBeziers() { - return m_mBezierCurves; -} - -bool CAnimationManager::shouldTickForNext() { - return !m_vActiveAnimatedVariables.empty(); -} - -void CAnimationManager::scheduleTick() { - if (m_bTickScheduled) - return; - - m_bTickScheduled = true; - - const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor; - - if (!PMOSTHZ) { - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16)); - return; - } - - float refreshDelayMs = std::floor(1000.f / PMOSTHZ->refreshRate); - - const float SINCEPRES = std::chrono::duration_cast(std::chrono::steady_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f; - - const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it - - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds((int)std::floor(TOPRES))); -} diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 3960f261..7bf73f97 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -1,57 +1,64 @@ #pragma once +#include +#include + #include "../defines.hpp" -#include -#include #include "../helpers/AnimatedVariable.hpp" -#include "../helpers/BezierCurve.hpp" -#include "../helpers/Timer.hpp" +#include "desktop/DesktopTypes.hpp" #include "eventLoop/EventLoopTimer.hpp" -class CWindow; - -class CAnimationManager { +class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { public: - CAnimationManager(); + CHyprAnimationManager(); - void tick(); - bool shouldTickForNext(); - void onTicked(); - void scheduleTick(); - void addBezierWithName(std::string, const Vector2D&, const Vector2D&); - void removeAllBeziers(); + void tick(); + virtual void scheduleTick(); + virtual void onTicked(); - void onWindowPostCreateClose(PHLWINDOW, bool close = false); + using SAnimationPropertyConfig = Hyprutils::Animation::SAnimationPropertyConfig; + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, eAVarDamagePolicy policy) { + constexpr const eAnimatedVarType EAVTYPE = typeToeAnimatedVarType; + const auto PAV = makeShared>(); - bool bezierExists(const std::string&); - CBezierCurve* getBezier(const std::string&); + PAV->create(EAVTYPE, static_cast(this), PAV, v); + PAV->setConfig(pConfig); + PAV->m_Context.eDamagePolicy = policy; - std::string styleValidInConfigVar(const std::string&, const std::string&); + pav = std::move(PAV); + } - std::unordered_map getAllBeziers(); + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { + createAnimation(v, pav, pConfig, policy); + pav->m_Context.pWindow = pWindow; + } + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { + createAnimation(v, pav, pConfig, policy); + pav->m_Context.pWorkspace = pWorkspace; + } + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, PHLLS pLayer, eAVarDamagePolicy policy) { + createAnimation(v, pav, pConfig, policy); + pav->m_Context.pLayer = pLayer; + } - std::vector m_vAnimatedVariables; - std::vector m_vActiveAnimatedVariables; + void onWindowPostCreateClose(PHLWINDOW, bool close = false); - SP m_pAnimationTimer; + std::string styleValidInConfigVar(const std::string&, const std::string&); - float m_fLastTickTime; // in ms + SP m_pAnimationTimer; + + float m_fLastTickTime; // in ms private: - bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b); - bool deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b); - bool deltaSmallToFlip(const float& a, const float& b); - bool deltazero(const Vector2D& a, const Vector2D& b); - bool deltazero(const CHyprColor& a, const CHyprColor& b); - bool deltazero(const float& a, const float& b); - - std::unordered_map m_mBezierCurves; - - bool m_bTickScheduled = false; + bool m_bTickScheduled = false; // Anim stuff void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f); void animationSlide(PHLWINDOW, std::string force = "", bool close = false); }; -inline std::unique_ptr g_pAnimationManager; +inline std::unique_ptr g_pAnimationManager; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d368d14c..fd4992eb 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -377,8 +377,8 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); // warp the position + size animation, otherwise it looks weird. - PWINDOWTOCHANGETO->m_vRealPosition.warp(); - PWINDOWTOCHANGETO->m_vRealSize.warp(); + PWINDOWTOCHANGETO->m_vRealPosition->warp(); + PWINDOWTOCHANGETO->m_vRealSize->warp(); } else { updateRelativeCursorCoords(); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); @@ -1070,8 +1070,8 @@ SDispatchResult CKeybindManager::centerWindow(std::string args) { if (args == "1") RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f; - PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; - PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); + *PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize->goal() / 2.f + RESERVEDOFFSET; + PWINDOW->m_vPosition = PWINDOW->m_vRealPosition->goal(); return {}; } @@ -1557,14 +1557,14 @@ SDispatchResult CKeybindManager::moveActiveTo(std::string args) { switch (arg) { case 'l': vPosx = PMONITOR->vecReservedTopLeft.x + BORDERSIZE + PMONITOR->vecPosition.x; break; - case 'r': vPosx = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break; + case 'r': vPosx = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize->goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break; case 't': case 'u': vPosy = PMONITOR->vecReservedTopLeft.y + BORDERSIZE + PMONITOR->vecPosition.y; break; case 'b': - case 'd': vPosy = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break; + case 'd': vPosy = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize->goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break; } - PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition.goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition.goal().y)); + *PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition->goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition->goal().y)); return {}; } @@ -1735,20 +1735,20 @@ SDispatchResult CKeybindManager::moveCursorToCorner(std::string arg) { switch (CORNER) { case 0: // bottom left - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, true); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition->value().x, PWINDOW->m_vRealPosition->value().y + PWINDOW->m_vRealSize->value().y}, true); break; case 1: // bottom right - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, - true); + g_pCompositor->warpCursorTo( + {PWINDOW->m_vRealPosition->value().x + PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealPosition->value().y + PWINDOW->m_vRealSize->value().y}, true); break; case 2: // top right - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y}, true); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition->value().x + PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealPosition->value().y}, true); break; case 3: // top left - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition->value().x, PWINDOW->m_vRealPosition->value().y}, true); break; } @@ -1817,18 +1817,18 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { continue; if (!w->m_bRequestsFloat && w->m_bIsFloating != PWORKSPACE->m_bDefaultFloating) { - const auto SAVEDPOS = w->m_vRealPosition.value(); - const auto SAVEDSIZE = w->m_vRealSize.value(); + const auto SAVEDPOS = w->m_vRealPosition->value(); + const auto SAVEDSIZE = w->m_vRealSize->value(); w->m_bIsFloating = PWORKSPACE->m_bDefaultFloating; g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(w); if (PWORKSPACE->m_bDefaultFloating) { - w->m_vRealPosition.setValueAndWarp(SAVEDPOS); - w->m_vRealSize.setValueAndWarp(SAVEDSIZE); + w->m_vRealPosition->setValueAndWarp(SAVEDPOS); + w->m_vRealSize->setValueAndWarp(SAVEDSIZE); g_pXWaylandManager->setWindowSize(w, SAVEDSIZE); - w->m_vRealSize = w->m_vRealSize.value() + Vector2D(4, 4); - w->m_vRealPosition = w->m_vRealPosition.value() - Vector2D(2, 2); + *w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4); + *w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2); } } } @@ -2043,14 +2043,14 @@ SDispatchResult CKeybindManager::resizeActive(std::string args) { if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return {}; - const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal()); + const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) return {}; - g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize.goal()); + g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize->goal()); - if (PLASTWINDOW->m_vRealSize.goal().x > 1 && PLASTWINDOW->m_vRealSize.goal().y > 1) + if (PLASTWINDOW->m_vRealSize->goal().x > 1 && PLASTWINDOW->m_vRealSize->goal().y > 1) PLASTWINDOW->setHidden(false); return {}; @@ -2062,9 +2062,9 @@ SDispatchResult CKeybindManager::moveActive(std::string args) { if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return {}; - const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal()); + const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition->goal()); - g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PLASTWINDOW->m_vRealPosition.goal()); + g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PLASTWINDOW->m_vRealPosition->goal()); return {}; } @@ -2084,9 +2084,9 @@ SDispatchResult CKeybindManager::moveWindow(std::string args) { if (PWINDOW->isFullscreen()) return {}; - const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal()); + const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition->goal()); - g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goal(), PWINDOW); + g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition->goal(), PWINDOW); return {}; } @@ -2106,14 +2106,14 @@ SDispatchResult CKeybindManager::resizeWindow(std::string args) { if (PWINDOW->isFullscreen()) return {}; - const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal()); + const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) return {}; - g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goal(), CORNER_NONE, PWINDOW); + g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize->goal(), CORNER_NONE, PWINDOW); - if (PWINDOW->m_vRealSize.goal().x > 1 && PWINDOW->m_vRealSize.goal().y > 1) + if (PWINDOW->m_vRealSize->goal().x > 1 && PWINDOW->m_vRealSize->goal().y > 1) PWINDOW->setHidden(false); return {}; @@ -2192,8 +2192,8 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { g_pCompositor->setWindowFullscreenClient(PWINDOW, FSMODE); // warp the position + size animation, otherwise it looks weird. - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); } } else g_pCompositor->focusWindow(PWINDOW); @@ -2311,7 +2311,7 @@ SDispatchResult CKeybindManager::pass(std::string regexp) { } } - const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + const auto SL = PWINDOW->m_vRealPosition->goal() - g_pInputManager->getMouseCoordsInternal(); if (g_pKeybindManager->m_uLastCode != 0) g_pSeatManager->setKeyboardFocus(LASTKBSURF); @@ -2466,7 +2466,7 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) { } } - const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + const auto SL = PWINDOW->m_vRealPosition->goal() - g_pInputManager->getMouseCoordsInternal(); if (!isMouse) g_pSeatManager->setKeyboardFocus(LASTSURFACE); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index ca31752d..bc988f39 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos + setWindowSize(pWindow, pWindow->m_vRealSize->value()); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) @@ -123,7 +123,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool // calculate pos // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = pWindow->m_vRealPosition.value(); + Vector2D windowPos = pWindow->m_vRealPosition->value(); if (pWindow->m_bIsX11 && PMONITOR) { windowPos -= PMONITOR->vecPosition; // normalize to monitor @@ -273,4 +273,4 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { result += pMonitor->vecPosition; return result; -} \ No newline at end of file +} diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index cccaa43e..8a50a7bf 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -137,7 +137,7 @@ void CInputManager::sendMotionEventsToFocused() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - const auto LOCAL = getMouseCoordsInternal() - (PWINDOW ? PWINDOW->m_vRealPosition.goal() : (PLS ? Vector2D{PLS->geometry.x, PLS->geometry.y} : Vector2D{})); + const auto LOCAL = getMouseCoordsInternal() - (PWINDOW ? PWINDOW->m_vRealPosition->goal() : (PLS ? Vector2D{PLS->geometry.x, PLS->geometry.y} : Vector2D{})); m_bEmptyFocusCursorSet = false; @@ -243,7 +243,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (forcedFocus) { pFoundWindow = forcedFocus; - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); foundSurface = pFoundWindow->m_pWLSurface->resource(); } @@ -320,7 +320,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { surfacePos = Vector2D(-1337, -1337); } else { foundSurface = pFoundWindow->m_pWLSurface->resource(); - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); } } @@ -362,11 +362,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); if (!foundSurface) { foundSurface = pFoundWindow->m_pWLSurface->resource(); - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); } } else { foundSurface = pFoundWindow->m_pWLSurface->resource(); - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); } } } @@ -689,7 +689,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // TODO detect click on LS properly if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || !w->isX11OverrideRedirect())) { if (w && !w->isFullscreen()) { - const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; + const CBox real = {w->m_vRealPosition->value().x, w->m_vRealPosition->value().y, w->m_vRealSize->value().x, w->m_vRealSize->value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; if ((grab.containsPoint(mouseCoords) && (!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y))) && !w->hasPopupAt(mouseCoords)) { diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 6cfe5a24..3e03c4c7 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -38,7 +38,7 @@ void CInputManager::beginWorkspaceSwipe() { if (PWORKSPACE->m_bHasFullscreenWindow) { for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { - ls->alpha = 1.f; + *ls->alpha = 1.f; } } } @@ -58,8 +58,8 @@ void CInputManager::endWorkspaceSwipe() { static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); static auto PSWIPEUSER = CConfigValue("gestures:workspace_swipe_use_r"); static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); // commit auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; @@ -86,7 +86,7 @@ void CInputManager::endWorkspaceSwipe() { auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER - const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.value(); + const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->value(); const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; @@ -97,35 +97,35 @@ void CInputManager::endWorkspaceSwipe() { // revert if (abs(m_sActiveSwipe.delta) < 2) { if (PWORKSPACEL) - PWORKSPACEL->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); + PWORKSPACEL->m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); if (PWORKSPACER) - PWORKSPACER->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); + PWORKSPACER->m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); } else { if (m_sActiveSwipe.delta < 0) { // to left if (PWORKSPACEL) { if (VERTANIMS) - PWORKSPACEL->m_vRenderOffset = Vector2D{0.0, -YDISTANCE}; + *PWORKSPACEL->m_vRenderOffset = Vector2D{0.0, -YDISTANCE}; else - PWORKSPACEL->m_vRenderOffset = Vector2D{-XDISTANCE, 0.0}; + *PWORKSPACEL->m_vRenderOffset = Vector2D{-XDISTANCE, 0.0}; } } else if (PWORKSPACER) { // to right if (VERTANIMS) - PWORKSPACER->m_vRenderOffset = Vector2D{0.0, YDISTANCE}; + *PWORKSPACER->m_vRenderOffset = Vector2D{0.0, YDISTANCE}; else - PWORKSPACER->m_vRenderOffset = Vector2D{XDISTANCE, 0.0}; + *PWORKSPACER->m_vRenderOffset = Vector2D{XDISTANCE, 0.0}; } - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); } pSwitchedTo = m_sActiveSwipe.pWorkspaceBegin; } else if (m_sActiveSwipe.delta < 0) { // switch to left - const auto RENDEROFFSET = PWORKSPACEL ? PWORKSPACEL->m_vRenderOffset.value() : Vector2D(); + const auto RENDEROFFSET = PWORKSPACEL ? PWORKSPACEL->m_vRenderOffset->value() : Vector2D(); if (PWORKSPACEL) m_sActiveSwipe.pMonitor->changeWorkspace(workspaceIDLeft); @@ -134,15 +134,15 @@ void CInputManager::endWorkspaceSwipe() { PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); } - PWORKSPACEL->m_vRenderOffset.setValue(RENDEROFFSET); - PWORKSPACEL->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACEL->m_vRenderOffset->setValue(RENDEROFFSET); + PWORKSPACEL->m_fAlpha->setValueAndWarp(1.f); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValue(RENDEROFFSETMIDDLE); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, YDISTANCE); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, YDISTANCE); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0.0); - m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0.0); + m_sActiveSwipe.pWorkspaceBegin->m_fAlpha->setValueAndWarp(1.f); g_pInputManager->unconstrainMouse(); @@ -151,7 +151,7 @@ void CInputManager::endWorkspaceSwipe() { pSwitchedTo = PWORKSPACEL; } else { // switch to right - const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_vRenderOffset.value() : Vector2D(); + const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_vRenderOffset->value() : Vector2D(); if (PWORKSPACER) m_sActiveSwipe.pMonitor->changeWorkspace(workspaceIDRight); @@ -160,15 +160,15 @@ void CInputManager::endWorkspaceSwipe() { PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); } - PWORKSPACER->m_vRenderOffset.setValue(RENDEROFFSET); - PWORKSPACER->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACER->m_vRenderOffset->setValue(RENDEROFFSET); + PWORKSPACER->m_fAlpha->setValueAndWarp(1.f); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValue(RENDEROFFSETMIDDLE); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, -YDISTANCE); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, -YDISTANCE); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0.0); - m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0.0); + m_sActiveSwipe.pWorkspaceBegin->m_fAlpha->setValueAndWarp(1.f); g_pInputManager->unconstrainMouse(); @@ -193,7 +193,7 @@ void CInputManager::endWorkspaceSwipe() { // apply alpha for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { - ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; + *ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } @@ -202,30 +202,30 @@ void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) { if (!m_sActiveSwipe.pWorkspaceBegin) return; - static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e.delta.y : e.delta.y) : (*PSWIPEINVR ? -e.delta.x : e.delta.x)); updateWorkspaceSwipe(delta); } void CInputManager::updateWorkspaceSwipe(double delta) { - static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); - static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); - static auto PSWIPEDIRLOCK = CConfigValue("gestures:workspace_swipe_direction_lock"); - static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue("gestures:workspace_swipe_direction_lock_threshold"); - static auto PSWIPEFOREVER = CConfigValue("gestures:workspace_swipe_forever"); - static auto PSWIPEUSER = CConfigValue("gestures:workspace_swipe_use_r"); - static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); + static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); + static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); + static auto PSWIPEDIRLOCK = CConfigValue("gestures:workspace_swipe_direction_lock"); + static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue("gestures:workspace_swipe_direction_lock_threshold"); + static auto PSWIPEFOREVER = CConfigValue("gestures:workspace_swipe_forever"); + static auto PSWIPEUSER = CConfigValue("gestures:workspace_swipe_use_r"); + static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); - const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); - const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; - const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - const double d = m_sActiveSwipe.delta - delta; - m_sActiveSwipe.delta = delta; + const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); + const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; + const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); + const double d = m_sActiveSwipe.delta - delta; + m_sActiveSwipe.delta = delta; m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(d)) / (m_sActiveSwipe.speedPoints + 1); m_sActiveSwipe.speedPoints++; @@ -265,9 +265,9 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); return; @@ -277,23 +277,23 @@ void CInputManager::updateWorkspaceSwipe(double delta) { } PWORKSPACE->m_bForceRendering = true; - PWORKSPACE->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACE->m_fAlpha->setValueAndWarp(1.f); if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_sActiveSwipe.pWorkspaceBegin->m_iID) { const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); if (PWORKSPACER) { PWORKSPACER->m_bForceRendering = false; - PWORKSPACER->m_fAlpha.setValueAndWarp(0.f); + PWORKSPACER->m_fAlpha->setValueAndWarp(0.f); } } if (VERTANIMS) { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); } else { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } PWORKSPACE->updateWindowDecos(); @@ -305,9 +305,9 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); return; @@ -317,23 +317,23 @@ void CInputManager::updateWorkspaceSwipe(double delta) { } PWORKSPACE->m_bForceRendering = true; - PWORKSPACE->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACE->m_fAlpha->setValueAndWarp(1.f); if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_sActiveSwipe.pWorkspaceBegin->m_iID) { const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); if (PWORKSPACEL) { PWORKSPACEL->m_bForceRendering = false; - PWORKSPACEL->m_fAlpha.setValueAndWarp(0.f); + PWORKSPACEL->m_fAlpha->setValueAndWarp(0.f); } } if (VERTANIMS) { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); } else { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } PWORKSPACE->updateWindowDecos(); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index aba54387..d7ebfe87 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -69,7 +69,7 @@ static void refocusTablet(SP tab, SP tool, bool motion = f // yes, this technically ignores any regions set by the app. Too bad! if (LASTHLSURFACE->getWindow()) - local = tool->absolutePos * LASTHLSURFACE->getWindow()->m_vRealSize.goal(); + local = tool->absolutePos * LASTHLSURFACE->getWindow()->m_vRealSize->goal(); else local = tool->absolutePos * BOX->size(); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 4e3980aa..7212ba61 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -3,6 +3,7 @@ #include "../../config/ConfigValue.hpp" #include "../../devices/ITouch.hpp" #include "../SeatManager.hpp" +#include "managers/AnimationManager.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { m_bLastInputTouch = true; @@ -36,9 +37,9 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { return; // TODO: Don't swipe if you touched a floating window. } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= 1)) { - const auto PWORKSPACE = PMONITOR->activeWorkspace; - const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + const auto PWORKSPACE = PMONITOR->activeWorkspace; + const auto STYLE = PWORKSPACE->m_vRenderOffset->getStyle(); + const bool VERTANIMS = STYLE == "slidevert" || STYLE.starts_with("slidefadevert"); const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x); const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x)); const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); @@ -62,8 +63,8 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { if (!m_sTouchData.touchFocusWindow.expired()) { if (m_sTouchData.touchFocusWindow->m_bIsX11) { - local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goal()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; - m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition.goal(); + local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition->goal()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; + m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition->goal(); } else { g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow.lock(), local); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; @@ -101,8 +102,9 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { // Do nothing if this is using a different finger. if (e.touchID != m_sActiveSwipe.touch_id) return; - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_touch_invert"); static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index 250c6326..fd7cdcd6 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -3,6 +3,7 @@ #include "../render/Renderer.hpp" #include "core/Output.hpp" #include "../config/ConfigValue.hpp" +#include "managers/AnimationManager.hpp" CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP resource_) : resource(resource_) { if (!good()) @@ -92,8 +93,7 @@ bool CHyprlandCTMControlProtocol::isCTMAnimationEnabled() { } CHyprlandCTMControlProtocol::SCTMData::SCTMData() { - progress.create(g_pConfigManager->getAnimationPropertyConfig("__internal_fadeCTM"), AVARDAMAGE_NONE); - progress.setValueAndWarp(0.F); + g_pAnimationManager->createAnimation(0.f, progress, g_pConfigManager->getAnimationPropertyConfig("__internal_fadeCTM"), AVARDAMAGE_NONE); } void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) { @@ -112,18 +112,18 @@ void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) data->ctmFrom = data->ctmTo; data->ctmTo = ctm; - data->progress.setValueAndWarp(0.F); - data->progress = 1.F; + data->progress->setValueAndWarp(0.F); + *data->progress = 1.F; monitor->setCTM(data->ctmFrom); - data->progress.setUpdateCallback([monitor = PHLMONITORREF{monitor}, this](void* self) { + data->progress->setUpdateCallback([monitor = PHLMONITORREF{monitor}, this](auto) { if (!monitor || !m_mCTMDatas.contains(monitor)) return; auto& data = m_mCTMDatas.at(monitor); const auto from = data->ctmFrom.getMatrix(); const auto to = data->ctmTo.getMatrix(); - const auto PROGRESS = data->progress.getPercent(); + const auto PROGRESS = data->progress->getPercent(); static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; @@ -135,7 +135,7 @@ void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) monitor->setCTM(mtx); }); - data->progress.setCallbackOnEnd([monitor = PHLMONITORREF{monitor}, this](void* self) { + data->progress->setCallbackOnEnd([monitor = PHLMONITORREF{monitor}, this](auto) { if (!monitor || !m_mCTMDatas.contains(monitor)) { monitor->setCTM(Mat3x3::identity()); return; diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp index dea2c258..2639d176 100644 --- a/src/protocols/CTMControl.hpp +++ b/src/protocols/CTMControl.hpp @@ -42,8 +42,8 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { // struct SCTMData { SCTMData(); - Mat3x3 ctmFrom = Mat3x3::identity(), ctmTo = Mat3x3::identity(); - CAnimatedVariable progress; + Mat3x3 ctmFrom = Mat3x3::identity(), ctmTo = Mat3x3::identity(); + PHLANIMVAR progress; }; std::map> m_mCTMDatas; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index f5fbaa0c..2c934b40 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -119,7 +119,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re dmabufFormat = PMONITOR->output->state->state().drmFormat; - box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; + box = {0, 0, (int)(pWindow->m_vRealSize->value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize->value().y * PMONITOR->scale)}; box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); @@ -263,7 +263,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (overlayCursor) - g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition->value()); const auto PFORMAT = NFormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { @@ -315,7 +315,7 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) { g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (overlayCursor) - g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition->value()); g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); @@ -386,7 +386,7 @@ void CToplevelExportProtocol::onOutputCommit(PHLMONITOR pMonitor) { if (pMonitor != PWINDOW->m_pMonitor.lock()) continue; - CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; + CBox geometry = {PWINDOW->m_vRealPosition->value().x, PWINDOW->m_vRealPosition->value().y, PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealSize->value().y}; if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty()) continue; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 94b70acf..93ab5fdf 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -713,7 +713,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(PHLMONITOR pMonitor) { if (!ws->m_bIsSpecialWorkspace || ws->m_pMonitor != pMonitor) continue; - if (ws->m_fAlpha.value() == 0) + if (ws->m_fAlpha->value() == 0) continue; return true; @@ -1517,7 +1517,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB if (allowDim && m_RenderData.currentWindow) { glUniform1i(shader->applyTint, 1); - const auto DIM = m_RenderData.currentWindow->m_fDimPercent.value(); + const auto DIM = m_RenderData.currentWindow->m_fDimPercent->value(); glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); } else { glUniform1i(shader->applyTint, 0); @@ -1931,7 +1931,7 @@ void CHyprOpenGLImpl::preRender(PHLMONITOR pMonitor) { const auto PSURFACE = pWindow->m_pWLSurface->resource(); const auto PWORKSPACE = pWindow->m_pWorkspace; - const float A = pWindow->m_fAlpha.value() * pWindow->m_fActiveInactiveAlpha.value() * PWORKSPACE->m_fAlpha.value(); + const float A = pWindow->m_fAlpha->value() * pWindow->m_fActiveInactiveAlpha->value() * PWORKSPACE->m_fAlpha->value(); if (A >= 1.f) { // if (PSURFACE->opaque) @@ -1969,7 +1969,7 @@ void CHyprOpenGLImpl::preRender(PHLMONITOR pMonitor) { if (!ls->layerSurface || ls->xray != 1) continue; - // if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) + // if (ls->layerSurface->surface->opaque && ls->alpha->value() >= 1.f) // continue; hasWindows = true; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d154e64a..4d93d92f 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -172,21 +172,21 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; // if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it. - if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha.isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha.value() > 0.F && pWindow->m_pWorkspace && + if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha->isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha->value() > 0.F && pWindow->m_pWorkspace && !pWindow->m_pWorkspace->isVisible()) return true; const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_pMonitor == pMonitor) { - if (PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) + if (PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha->isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) return true; // if hidden behind fullscreen if (PWINDOWWORKSPACE->m_bHasFullscreenWindow && !pWindow->isFullscreen() && (!pWindow->m_bIsFloating || !pWindow->m_bCreatedOverFullscreen) && - pWindow->m_fAlpha.value() == 0) + pWindow->m_fAlpha->value() == 0) return false; - if (!PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() && !PWINDOWWORKSPACE->isVisible()) + if (!PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() && !PWINDOWWORKSPACE->m_fAlpha->isBeingAnimated() && !PWINDOWWORKSPACE->isVisible()) return false; } @@ -204,17 +204,17 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; // if window is tiled and it's flying in, don't render on other mons (for slide) - if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition.isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_pMonitor != pMonitor) + if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition->isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_pMonitor != pMonitor) return false; - if (pWindow->m_vRealPosition.isBeingAnimated()) { - if (PWINDOWWORKSPACE && !PWINDOWWORKSPACE->m_bIsSpecialWorkspace && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated()) + if (pWindow->m_vRealPosition->isBeingAnimated()) { + if (PWINDOWWORKSPACE && !PWINDOWWORKSPACE->m_bIsSpecialWorkspace && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated()) return false; // render window if window and monitor intersect // (when moving out of or through a monitor) CBox windowBox = pWindow->getFullWindowBoundingBox(); - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated()) - windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated()) + windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset->value()); windowBox.translate(pWindow->m_vFloatingOffset); const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize}; @@ -242,7 +242,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { return true; for (auto const& m : g_pCompositor->m_vMonitors) { - if (PWORKSPACE && PWORKSPACE->m_pMonitor == m && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) + if (PWORKSPACE && PWORKSPACE->m_pMonitor == m && (PWORKSPACE->m_vRenderOffset->isBeingAnimated() || PWORKSPACE->m_fAlpha->isBeingAnimated())) return true; if (m->activeSpecialWorkspace && pWindow->onSpecialWorkspace()) @@ -262,7 +262,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (!shouldRenderWindow(w, pMonitor)) continue; - if (w->m_fAlpha.value() == 0.f) + if (w->m_fAlpha->value() == 0.f) continue; if (w->isFullscreen() || w->m_bIsFloating) @@ -279,7 +279,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (!shouldRenderWindow(w, pMonitor)) continue; - if (w->m_fAlpha.value() == 0.f) + if (w->m_fAlpha->value() == 0.f) continue; if (w->isFullscreen() || !w->m_bIsFloating) @@ -299,7 +299,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR const auto PWORKSPACE = w->m_pWorkspace; if (w->m_pWorkspace != pWorkspace || !w->isFullscreen()) { - if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering))) + if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset->isBeingAnimated() || PWORKSPACE->m_fAlpha->isBeingAnimated() || PWORKSPACE->m_bForceRendering))) continue; if (w->m_pMonitor != pMonitor) @@ -432,12 +432,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe TRACY_GPU_ZONE("RenderWindow"); const auto PWORKSPACE = pWindow->m_pWorkspace; - const auto REALPOS = pWindow->m_vRealPosition.value() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.value()); + const auto REALPOS = pWindow->m_vRealPosition->value() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset->value()); static auto PDIMAROUND = CConfigValue("decoration:dim_around"); static auto PBLUR = CConfigValue("decoration:blur:enabled"); CSurfacePassElement::SRenderData renderdata = {pMonitor, time}; - CBox textureBox = {REALPOS.x, REALPOS.y, std::max(pWindow->m_vRealSize.value().x, 5.0), std::max(pWindow->m_vRealSize.value().y, 5.0)}; + CBox textureBox = {REALPOS.x, REALPOS.y, std::max(pWindow->m_vRealSize->value().x, 5.0), std::max(pWindow->m_vRealSize->value().y, 5.0)}; renderdata.pos.x = textureBox.x; renderdata.pos.y = textureBox.y; @@ -458,9 +458,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); - renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha.value()) * - (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha.value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha.value(); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); + renderdata.fadeAlpha = pWindow->m_fAlpha->value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha->value()) * + (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha->value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha->value(); + renderdata.alpha = pWindow->m_fActiveInactiveAlpha->value(); renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; renderdata.roundingPower = ignoreAllGeometry || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); @@ -492,9 +492,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.pos.y += pWindow->m_vFloatingOffset.y; // if window is floating and we have a slide animation, clip it to its full bb - if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->isFullscreen() && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) { + if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->isFullscreen() && PWORKSPACE->m_vRenderOffset->isBeingAnimated() && !pWindow->m_bPinned) { CRegion rg = - pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.value() + pWindow->m_vFloatingOffset).scale(pMonitor->scale); + pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset->value() + pWindow->m_vFloatingOffset).scale(pMonitor->scale); renderdata.clipBox = rg.getExtents(); } @@ -657,7 +657,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim if (*PDIMAROUND && pLayer->dimAround && !m_bRenderingSnapshot && !popups) { CRectPassElement::SRectData data; data.box = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y}; - data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->alpha.value()); + data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->alpha->value()); m_sRenderPass.add(makeShared(data)); } @@ -671,11 +671,11 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim TRACY_GPU_ZONE("RenderLayer"); - const auto REALPOS = pLayer->realPosition.value(); - const auto REALSIZ = pLayer->realSize.value(); + const auto REALPOS = pLayer->realPosition->value(); + const auto REALSIZ = pLayer->realSize->value(); CSurfacePassElement::SRenderData renderdata = {pMonitor, time, REALPOS}; - renderdata.fadeAlpha = pLayer->alpha.value(); + renderdata.fadeAlpha = pLayer->alpha->value(); renderdata.blur = pLayer->forceBlur && *PBLUR; renderdata.surface = pLayer->surface->resource(); renderdata.decorate = false; @@ -866,8 +866,8 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // and then special for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_pMonitor == pMonitor && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { - const auto SPECIALANIMPROGRS = ws->m_vRenderOffset.isBeingAnimated() ? ws->m_vRenderOffset.getCurveValue() : ws->m_fAlpha.getCurveValue(); + if (ws->m_pMonitor == pMonitor && ws->m_fAlpha->value() > 0.f && ws->m_bIsSpecialWorkspace) { + const auto SPECIALANIMPROGRS = ws->m_vRenderOffset->isBeingAnimated() ? ws->m_vRenderOffset->getCurveValue() : ws->m_fAlpha->getCurveValue(); const bool ANIMOUT = !pMonitor->activeSpecialWorkspace; if (*PDIMSPECIAL != 0.f) { @@ -894,7 +894,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // special for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { + if (ws->m_fAlpha->value() > 0.f && ws->m_bIsSpecialWorkspace) { if (ws->m_bHasFullscreenWindow) renderWorkspaceWindowsFullscreen(pMonitor, ws, time); else @@ -1617,8 +1617,8 @@ void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vectorlayerSurface->configure(box.size()); - ls->realPosition = box.pos(); - ls->realSize = box.size(); + *ls->realPosition = box.pos(); + *ls->realSize = box.size(); } } @@ -1727,8 +1727,8 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { CBox windowBox = pWindow->getFullWindowBoundingBox(); const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) - windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() && !pWindow->m_bPinned) + windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset->value()); windowBox.translate(pWindow->m_vFloatingOffset); for (auto const& m : g_pCompositor->m_vMonitors) { @@ -1977,8 +1977,8 @@ void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { const auto PWORKSPACE = pMonitor->activeWorkspace; - if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || PROTO::data->dndActive() || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha.value() != 1.f || - PWORKSPACE->m_vRenderOffset.value() != Vector2D{}) + if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || PROTO::data->dndActive() || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha->value() != 1.f || + PWORKSPACE->m_vRenderOffset->value() != Vector2D{}) return; const auto PCANDIDATE = PWORKSPACE->getFullscreenWindow(); @@ -1989,15 +1989,15 @@ void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { if (!PCANDIDATE->opaque()) return; - if (PCANDIDATE->m_vRealSize.value() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.value() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() || - PCANDIDATE->m_vRealSize.isBeingAnimated()) + if (PCANDIDATE->m_vRealSize->value() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition->value() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition->isBeingAnimated() || + PCANDIDATE->m_vRealSize->isBeingAnimated()) return; if (!pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty()) return; for (auto const& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - if (topls->alpha.value() != 0.f) + if (topls->alpha->value() != 0.f) return; } @@ -2410,13 +2410,13 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { CBox windowBox; // some mafs to figure out the correct box // the originalClosedPos is relative to the monitor's pos - Vector2D scaleXY = Vector2D((PMONITOR->scale * pWindow->m_vRealSize.value().x / (pWindow->m_vOriginalClosedSize.x * PMONITOR->scale)), - (PMONITOR->scale * pWindow->m_vRealSize.value().y / (pWindow->m_vOriginalClosedSize.y * PMONITOR->scale))); + Vector2D scaleXY = Vector2D((PMONITOR->scale * pWindow->m_vRealSize->value().x / (pWindow->m_vOriginalClosedSize.x * PMONITOR->scale)), + (PMONITOR->scale * pWindow->m_vRealSize->value().y / (pWindow->m_vOriginalClosedSize.y * PMONITOR->scale))); windowBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x; windowBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y; - windowBox.x = ((pWindow->m_vRealPosition.value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x); - windowBox.y = ((pWindow->m_vRealPosition.value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y); + windowBox.x = ((pWindow->m_vRealPosition->value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x); + windowBox.y = ((pWindow->m_vRealPosition->value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y); CRegion fakeDamage{0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; @@ -2425,7 +2425,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { CRectPassElement::SRectData data; data.box = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y}; - data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value()); + data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha->value()); m_sRenderPass.add(makeShared(data)); damageMonitor(PMONITOR); @@ -2435,7 +2435,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { data.flipEndFrame = true; data.tex = FBDATA->getTexture(); data.box = windowBox; - data.a = pWindow->m_fAlpha.value(); + data.a = pWindow->m_fAlpha->value(); data.damage = fakeDamage; m_sRenderPass.add(makeShared(data)); @@ -2455,13 +2455,13 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) { CBox layerBox; // some mafs to figure out the correct box // the originalClosedPos is relative to the monitor's pos - Vector2D scaleXY = Vector2D((PMONITOR->scale * pLayer->realSize.value().x / (pLayer->geometry.w * PMONITOR->scale)), - (PMONITOR->scale * pLayer->realSize.value().y / (pLayer->geometry.h * PMONITOR->scale))); + Vector2D scaleXY = Vector2D((PMONITOR->scale * pLayer->realSize->value().x / (pLayer->geometry.w * PMONITOR->scale)), + (PMONITOR->scale * pLayer->realSize->value().y / (pLayer->geometry.h * PMONITOR->scale))); layerBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x; layerBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y; - layerBox.x = ((pLayer->realPosition.value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - (((pLayer->geometry.x - PMONITOR->vecPosition.x) * PMONITOR->scale) * scaleXY.x); - layerBox.y = ((pLayer->realPosition.value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - (((pLayer->geometry.y - PMONITOR->vecPosition.y) * PMONITOR->scale) * scaleXY.y); + layerBox.x = ((pLayer->realPosition->value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - (((pLayer->geometry.x - PMONITOR->vecPosition.x) * PMONITOR->scale) * scaleXY.x); + layerBox.y = ((pLayer->realPosition->value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - (((pLayer->geometry.y - PMONITOR->vecPosition.y) * PMONITOR->scale) * scaleXY.y); CRegion fakeDamage{0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; @@ -2469,7 +2469,7 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) { data.flipEndFrame = true; data.tex = FBDATA->getTexture(); data.box = layerBox; - data.a = pLayer->alpha.value(); + data.a = pLayer->alpha->value(); data.damage = fakeDamage; m_sRenderPass.add(makeShared(data)); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 2bc894ef..7261431f 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -43,7 +43,7 @@ CBox CHyprBorderDecoration::assignedBoxGlobal() { if (!PWORKSPACE) return box; - const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); + const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); return box.translate(WORKSPACEOFFSET); } @@ -60,10 +60,10 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { return; auto grad = m_pWindow->m_cRealBorderColor; - const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress.isBeingAnimated(); + const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress->isBeingAnimated(); - if (m_pWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) { - grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress.value() * M_PI * 2; + if (m_pWindow->m_fBorderAngleAnimationProgress->enabled()) { + grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress->value() * M_PI * 2; grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); } @@ -83,7 +83,7 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { data.hasGrad2 = true; data.grad1 = m_pWindow->m_cRealBorderColorPrevious; data.grad2 = grad; - data.lerp = m_pWindow->m_fBorderFadeAnimationProgress.value(); + data.lerp = m_pWindow->m_fBorderFadeAnimationProgress->value(); } g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); @@ -117,8 +117,8 @@ void CHyprBorderDecoration::damageEntire() { const auto BORDERSIZE = m_pWindow->getRealBorderSize() + 1; const auto PWINDOWWORKSPACE = m_pWindow->m_pWorkspace; - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) - surfaceBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() && !m_pWindow->m_bPinned) + surfaceBox.translate(PWINDOWWORKSPACE->m_vRenderOffset->value()); surfaceBox.translate(m_pWindow->m_vFloatingOffset); CBox surfaceBoxExpandedBorder = surfaceBox; diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 07dbb436..ddd5198d 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -44,13 +44,13 @@ void CHyprDropShadowDecoration::damageEntire() { const auto PWINDOW = m_pWindow.lock(); - CBox shadowBox = {PWINDOW->m_vRealPosition.value().x - m_seExtents.topLeft.x, PWINDOW->m_vRealPosition.value().y - m_seExtents.topLeft.y, - PWINDOW->m_vRealSize.value().x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, - PWINDOW->m_vRealSize.value().y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; + CBox shadowBox = {PWINDOW->m_vRealPosition->value().x - m_seExtents.topLeft.x, PWINDOW->m_vRealPosition->value().y - m_seExtents.topLeft.y, + PWINDOW->m_vRealSize->value().x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, + PWINDOW->m_vRealSize->value().y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; const auto PWORKSPACE = PWINDOW->m_pWorkspace; - if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOW->m_bPinned) - shadowBox.translate(PWORKSPACE->m_vRenderOffset.value()); + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset->isBeingAnimated() && !PWINDOW->m_bPinned) + shadowBox.translate(PWORKSPACE->m_vRenderOffset->value()); shadowBox.translate(PWINDOW->m_vFloatingOffset); static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); @@ -61,8 +61,8 @@ void CHyprDropShadowDecoration::damageEntire() { CRegion shadowRegion(shadowBox); if (*PSHADOWIGNOREWINDOW) { CBox surfaceBox = PWINDOW->getWindowMainSurfaceBox(); - if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOW->m_bPinned) - surfaceBox.translate(PWORKSPACE->m_vRenderOffset.value()); + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset->isBeingAnimated() && !PWINDOW->m_bPinned) + surfaceBox.translate(PWORKSPACE->m_vRenderOffset->value()); surfaceBox.translate(PWINDOW->m_vFloatingOffset); surfaceBox.expand(-ROUNDINGSIZE); shadowRegion.subtract(CRegion(surfaceBox)); @@ -81,8 +81,8 @@ void CHyprDropShadowDecoration::damageEntire() { void CHyprDropShadowDecoration::updateWindow(PHLWINDOW pWindow) { const auto PWINDOW = m_pWindow.lock(); - m_vLastWindowPos = PWINDOW->m_vRealPosition.value(); - m_vLastWindowSize = PWINDOW->m_vRealSize.value(); + m_vLastWindowPos = PWINDOW->m_vRealPosition->value(); + m_vLastWindowSize = PWINDOW->m_vRealSize->value(); m_bLastWindowBox = {m_vLastWindowPos.x, m_vLastWindowPos.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; m_bLastWindowBoxWithDecos = g_pDecorationPositioner->getBoxWithIncludedDecos(pWindow); @@ -101,7 +101,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { if (!validMapped(PWINDOW)) return; - if (PWINDOW->m_cRealShadowColor.value() == CHyprColor(0, 0, 0, 0)) + if (PWINDOW->m_cRealShadowColor->value() == CHyprColor(0, 0, 0, 0)) return; // don't draw invisible shadows if (!PWINDOW->m_sWindowData.decorate.valueOrDefault()) @@ -123,7 +123,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDING = ROUNDINGBASE > 0 ? ROUNDINGBASE + PWINDOW->getRealBorderSize() : 0; const auto PWORKSPACE = PWINDOW->m_pWorkspace; - const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); + const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); // draw the shadow CBox fullBox = m_bLastWindowBoxWithDecos; @@ -194,7 +194,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor->value().a), a); // render black window box ("clip") g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale, ROUNDINGPOWER); @@ -202,7 +202,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { alphaSwapFB.bind(); // alpha swap just has the shadow color. It will be the "texture" to render. - g_pHyprOpenGL->renderRect(&fullBox, PWINDOW->m_cRealShadowColor.value().stripA(), 0); + g_pHyprOpenGL->renderRect(&fullBox, PWINDOW->m_cRealShadowColor->value().stripA(), 0); LASTFB->bind(); @@ -216,7 +216,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->m_RenderData.damage = saveDamage; } else - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor->value(), a); if (m_seExtents != m_seReportedExtents) g_pDecorationPositioner->repositionDeco(this); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index c6dc5779..970273d7 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -390,9 +390,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND // restores the group for (auto it = members.begin(); it != members.end(); ++it) { - (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members - (*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize.goal(); // match the size of group members - (*it)->m_vRealPosition = pWindowInsertAfter->m_vRealPosition.goal(); // match the position of group members + (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members + *(*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize->goal(); // match the size of group members + *(*it)->m_vRealPosition = pWindowInsertAfter->m_vRealPosition->goal(); // match the position of group members if (std::next(it) != members.end()) (*it)->m_sGroupData.pNextWindow = *std::next(it); else @@ -406,7 +406,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window if (pWindowInsertAfter->m_bIsFloating) - g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize.goal()); // match the size of the window + g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize->goal()); // match the size of the window pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); @@ -515,7 +515,7 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() { const auto PWORKSPACE = m_pWindow->m_pWorkspace; if (PWORKSPACE && !m_pWindow->m_bPinned) - box.translate(PWORKSPACE->m_vRenderOffset.value()); + box.translate(PWORKSPACE->m_vRenderOffset->value()); return box; } diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 6a41cbdc..abfa19ec 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -124,7 +124,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { datas.push_back(getDataFor(wd.get(), pWindow)); } - if (WINDOWDATA->lastWindowSize == pWindow->m_vRealSize.value() /* position not changed */ + if (WINDOWDATA->lastWindowSize == pWindow->m_vRealSize->value() /* position not changed */ && std::all_of(m_vWindowPositioningDatas.begin(), m_vWindowPositioningDatas.end(), [pWindow](const auto& data) { return pWindow != data->pWindow.lock() || !data->needsReposition; }) /* all window datas are either not for this window or don't need a reposition */ @@ -132,9 +132,9 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { ) return; - WINDOWDATA->lastWindowSize = pWindow->m_vRealSize.value(); + WINDOWDATA->lastWindowSize = pWindow->m_vRealSize->value(); WINDOWDATA->needsRecalc = false; - const bool EPHEMERAL = pWindow->m_vRealSize.isBeingAnimated(); + const bool EPHEMERAL = pWindow->m_vRealSize->isBeingAnimated(); std::sort(datas.begin(), datas.end(), [](const auto& a, const auto& b) { return a->positioningInfo.priority > b->positioningInfo.priority; }); diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index 13e9e741..f2f2627a 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -77,7 +77,7 @@ void CSurfacePassElement::draw(const CRegion& damage) { const bool MISALIGNEDFSV1 = std::floor(data.pMonitor->scale) != data.pMonitor->scale /* Fractional */ && data.surface->current.scale == 1 /* fs protocol */ && windowBox.size() != data.surface->current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, data.surface->current.bufferSize.x, 3) && DELTALESSTHAN(windowBox.height, data.surface->current.bufferSize.y, 3) /* off by one-or-two */ && - (!data.pWindow || (!data.pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; + (!data.pWindow || (!data.pWindow->m_vRealSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); @@ -148,8 +148,8 @@ CBox CSurfacePassElement::getTexBox() { if (!INTERACTIVERESIZEINPROGRESS) { windowBox.translate(CORRECT); - windowBox.width = SIZE.x * (PWINDOW->m_vRealSize.value().x / PWINDOW->m_vReportedSize.x); - windowBox.height = SIZE.y * (PWINDOW->m_vRealSize.value().y / PWINDOW->m_vReportedSize.y); + windowBox.width = SIZE.x * (PWINDOW->m_vRealSize->value().x / PWINDOW->m_vReportedSize.x); + windowBox.height = SIZE.y * (PWINDOW->m_vRealSize->value().y / PWINDOW->m_vReportedSize.y); } else { windowBox.width = SIZE.x; windowBox.height = SIZE.y; @@ -159,10 +159,10 @@ CBox CSurfacePassElement::getTexBox() { } else { // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + data.pos.x + data.localPos.x, (int)outputY + data.pos.y + data.localPos.y, std::max((float)data.surface->current.size.x, 2.F), std::max((float)data.surface->current.size.y, 2.F)}; - if (data.pWindow && data.pWindow->m_vRealSize.isBeingAnimated() && data.surface && !data.mainSurface && data.squishOversized /* subsurface */) { + if (data.pWindow && data.pWindow->m_vRealSize->isBeingAnimated() && data.surface && !data.mainSurface && data.squishOversized /* subsurface */) { // adjust subsurfaces to the window - windowBox.width = (windowBox.width / data.pWindow->m_vReportedSize.x) * data.pWindow->m_vRealSize.value().x; - windowBox.height = (windowBox.height / data.pWindow->m_vReportedSize.y) * data.pWindow->m_vRealSize.value().y; + windowBox.width = (windowBox.width / data.pWindow->m_vReportedSize.x) * data.pWindow->m_vRealSize->value().x; + windowBox.height = (windowBox.height / data.pWindow->m_vReportedSize.y) * data.pWindow->m_vRealSize->value().y; } } From 95542e44884d2131a742f92013826a0b5f341b33 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 19:13:35 +0100 Subject: [PATCH 13/24] animationmgr: fix invalid include --- src/managers/AnimationManager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 7bf73f97..10eeef05 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -5,7 +5,7 @@ #include "../defines.hpp" #include "../helpers/AnimatedVariable.hpp" -#include "desktop/DesktopTypes.hpp" +#include "../desktop/DesktopTypes.hpp" #include "eventLoop/EventLoopTimer.hpp" class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { From 830350a1f7a5ad653f33f2c62dd1694249a2f1e2 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Tue, 7 Jan 2025 21:32:50 +0300 Subject: [PATCH 14/24] core: Add support for HDR and color management protocols (#8715) --- CMakeLists.txt | 2 + protocols/frog-color-management-v1.xml | 366 ++++++ protocols/meson.build | 2 + protocols/xx-color-management-v4.xml | 1457 +++++++++++++++++++++++ src/Compositor.cpp | 19 + src/Compositor.hpp | 4 + src/config/ConfigDescriptions.hpp | 18 + src/config/ConfigManager.cpp | 4 + src/desktop/WLSurface.hpp | 1 + src/managers/ProtocolManager.cpp | 11 + src/protocols/ColorManagement.cpp | 571 +++++++++ src/protocols/ColorManagement.hpp | 182 +++ src/protocols/FrogColorManagement.cpp | 159 +++ src/protocols/FrogColorManagement.hpp | 55 + src/protocols/core/Compositor.hpp | 3 + src/protocols/types/ColorManagement.hpp | 47 + src/render/Renderer.cpp | 97 ++ src/render/pass/SurfacePassElement.cpp | 2 + 18 files changed, 3000 insertions(+) create mode 100644 protocols/frog-color-management-v1.xml create mode 100644 protocols/xx-color-management-v4.xml create mode 100644 src/protocols/ColorManagement.cpp create mode 100644 src/protocols/ColorManagement.hpp create mode 100644 src/protocols/FrogColorManagement.cpp create mode 100644 src/protocols/FrogColorManagement.hpp create mode 100644 src/protocols/types/ColorManagement.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa746d2e..c1ecb14c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,6 +316,8 @@ protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolnew("protocols" "xx-color-management-v4" true) +protocolnew("protocols" "frog-color-management-v1" true) protocolnew("protocols" "wayland-drm" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true) diff --git a/protocols/frog-color-management-v1.xml b/protocols/frog-color-management-v1.xml new file mode 100644 index 00000000..aab235a7 --- /dev/null +++ b/protocols/frog-color-management-v1.xml @@ -0,0 +1,366 @@ + + + + + Copyright © 2023 Joshua Ashton for Valve Software + Copyright © 2023 Xaver Hugl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + The aim of this color management extension is to get HDR games working quickly, + and have an easy way to test implementations in the wild before the upstream + protocol is ready to be merged. + For that purpose it's intentionally limited and cut down and does not serve + all uses cases. + + + + + The color management factory singleton creates color managed surface objects. + + + + + + + + + + + + + + + + Interface for changing surface color management and HDR state. + + An implementation must: support every part of the version + of the frog_color_managed_surface interface it exposes. + Including all known enums associated with a given version. + + + + + Destroying the color managed surface resets all known color + state for the surface back to 'undefined' implementation-specific + values. + + + + + + Extended information on the transfer functions described + here can be found in the Khronos Data Format specification: + https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extended information on render intents described + here can be found in ICC.1:2022: + + https://www.color.org/specification/ICC.1-2022-05.pdf + + + + + + + NOTE: On a surface with "perceptual" (default) render intent, handling of the container's + color volume + is implementation-specific, and may differ between different transfer functions it is paired + with: + ie. sRGB + 709 rendering may have it's primaries widened to more of the available display's + gamut + to be be more pleasing for the viewer. + Compared to scRGB Linear + 709 being treated faithfully as 709 + (including utilizing negatives out of the 709 gamut triangle) + + + + + + + Forwards HDR metadata from the client to the compositor. + + HDR Metadata Infoframe as per CTA 861.G spec. + + Usage of this HDR metadata is implementation specific and + outside of the scope of this protocol. + + + + Mastering Red Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Red Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Green Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Green Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Blue Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Blue Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering White Point X Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering White Point Y Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Max Mastering Display Luminance. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Min Mastering Display Luminance. + This value is coded as an unsigned 16-bit value in units of + 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + represents 6.5535 cd/m2. + + + + + Max Content Light Level. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Max Frame Average Light Level. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + + + Current preferred metadata for a surface. + The application should use this information to tone-map its buffers + to this target before committing. + + This metadata does not necessarily correspond to any physical output, but + rather what the compositor thinks would be best for a given surface. + + + + Specifies a known transfer function that corresponds to the + output the surface is targeting. + + + + + Output Red Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Red Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Green Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Green Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Blue Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Blue Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output White Point X Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output White Point Y Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Max Output Luminance + The max luminance in nits that the output is capable of rendering in small areas. + Content should: not exceed this value to avoid clipping. + + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Min Output Luminance + The min luminance that the output is capable of rendering. + Content should: not exceed this value to avoid clipping. + + This value is coded as an unsigned 16-bit value in units of + 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + represents 6.5535 cd/m2. + + + + + Max Full Frame Luminance + The max luminance in nits that the output is capable of rendering for the + full frame sustained. + + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + \ No newline at end of file diff --git a/protocols/meson.build b/protocols/meson.build index a39602b7..fdbbf181 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -33,6 +33,8 @@ protocols = [ 'wayland-drm.xml', 'wlr-data-control-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml', + 'xx-color-management-v4.xml', + 'frog-color-management-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', diff --git a/protocols/xx-color-management-v4.xml b/protocols/xx-color-management-v4.xml new file mode 100644 index 00000000..23ff716e --- /dev/null +++ b/protocols/xx-color-management-v4.xml @@ -0,0 +1,1457 @@ + + + + Copyright 2019 Sebastian Wick + Copyright 2019 Erwin Burema + Copyright 2020 AMD + Copyright 2020-2024 Collabora, Ltd. + Copyright 2024 Xaver Hugl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + The aim of the color management extension is to allow clients to know + the color properties of outputs, and to tell the compositor about the color + properties of their content on surfaces. Doing this enables a compositor + to perform automatic color management of content for different outputs + according to how content is intended to look like. + + The color properties are represented as an image description object which + is immutable after it has been created. A wl_output always has an + associated image description that clients can observe. A wl_surface + always has an associated preferred image description as a hint chosen by + the compositor that clients can also observe. Clients can set an image + description on a wl_surface to denote the color characteristics of the + surface contents. + + An image description includes SDR and HDR colorimetry and encoding, HDR + metadata, and viewing environment parameters. An image description does + not include the properties set through color-representation extension. + It is expected that the color-representation extension is used in + conjunction with the color management extension when necessary, + particularly with the YUV family of pixel formats. + + Recommendation ITU-T H.273 + "Coding-independent code points for video signal type identification" + shall be referred to as simply H.273 here. + + The color-and-hdr repository + (https://gitlab.freedesktop.org/pq/color-and-hdr) contains + background information on the protocol design and legacy color management. + It also contains a glossary, learning resources for digital color, tools, + samples and more. + + The terminology used in this protocol is based on common color science and + color encoding terminology where possible. The glossary in the color-and-hdr + repository shall be the authority on the definition of terms in this + protocol. + + + + + A global interface used for getting color management extensions for + wl_surface and wl_output objects, and for creating client defined image + description objects. The extension interfaces allow + getting the image description of outputs and setting the image + description of surfaces. + + + + + Destroy the xx_color_manager_v4 object. This does not affect any other + objects in any way. + + + + + + + + + + + See the ICC.1:2022 specification from the International Color Consortium + for more details about rendering intents. + + The principles of ICC defined rendering intents apply with all types of + image descriptions, not only those with ICC file profiles. + + Compositors must support the perceptual rendering intent. Other + rendering intents are optional. + + + + + + + + + + + + + + + + + + + + The compositor supports set_mastering_display_primaries request with a + target color volume fully contained inside the primary color volume. + + + + + The compositor additionally supports target color volumes that + extend outside of the primary color volume. + + This can only be advertised if feature set_mastering_display_primaries + is supported as well. + + + + + + + Named color primaries used to encode well-known sets of primaries. H.273 + is the authority, when it comes to the exact values of primaries and + authoritative specifications, where an equivalent code point exists. + + Descriptions do list the specifications for convenience. + + + + + Color primaries as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended + colour gamut system (historical) + - IEC 61966-2-1 sRGB or sYCC + - IEC 61966-2-4 + - Society of Motion Picture and Television Engineers (SMPTE) RP 177 + (1993) Annex B + Equivalent to H.273 ColourPrimaries code point 1. + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a)(20) + Equivalent to H.273 ColourPrimaries code point 4. + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + - Rec. ITU-R BT.601-7 625 + - Rec. ITU-R BT.1358-0 625 (historical) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + Equivalent to H.273 ColourPrimaries code point 5. + + + + + Color primaries as defined by + - Rec. ITU-R BT.601-7 525 + - Rec. ITU-R BT.1358-1 525 or 625 (historical) + - Rec. ITU-R BT.1700-0 NTSC + - SMPTE 170M (2004) + - SMPTE 240M (1999) (historical) + Equivalent to H.273 ColourPrimaries code point 6 and 7. + + + + + Color primaries as defined by H.273 for generic film. + Equivalent to H.273 ColourPrimaries code point 8. + + + + + Color primaries as defined by + - Rec. ITU-R BT.2020-2 + - Rec. ITU-R BT.2100-0 + Equivalent to H.273 ColourPrimaries code point 9. + + + + + Color primaries as defined as the maximum of the CIE 1931 XYZ color + space by + - SMPTE ST 428-1 + - (CIE 1931 XYZ as in ISO 11664-1) + Equivalent to H.273 ColourPrimaries code point 10. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE RP 431-2 (2011). Equivalent to H.273 ColourPrimaries code point + 11. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE EG 432-1 (2010). + Equivalent to H.273 ColourPrimaries code point 12. + + + + + Color primaries as defined by Adobe as "Adobe RGB" and later published + by ISO 12640-4 (2011). + + + + + + + Named transfer functions used to encode well-known transfer + characteristics. H.273 is the authority, when it comes to the exact + formulas and authoritative specifications, where an equivalent code + point exists. + + Descriptions do list the specifications for convenience. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system (historical) + Equivalent to H.273 TransferCharacteristics code point 1, 6, 14, 15. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a) (20) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + Equivalent to H.273 TransferCharacteristics code point 4. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + Equivalent to H.273 TransferCharacteristics code point 5. + + + + + Transfer characteristics as defined by + - SMPTE ST 240 (1999) + Equivalent to H.273 TransferCharacteristics code point 7. + + + + + Linear transfer characteristics. + Equivalent to H.273 TransferCharacteristics code point 8. + + + + + Logarithmic transfer characteristic (100:1 range). + Equivalent to H.273 TransferCharacteristics code point 9. + + + + + Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + Equivalent to H.273 TransferCharacteristics code point 10. + + + + + Transfer characteristics as defined by + - IEC 61966-2-4 + Equivalent to H.273 TransferCharacteristics code point 11. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.1361-0 extended colour gamut system (historical) + Equivalent to H.273 TransferCharacteristics code point 12. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sRGB + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to 0. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sYCC + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to anything but 0. + + + + + Transfer characteristics as defined by + - SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems + - Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system + Equivalent to H.273 TransferCharacteristics code point 16. + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 10000 cd/m² + - reference white: 203 cd/m² + + + + + Transfer characteristics as defined by + - SMPTE ST 428-1 (2019) + Equivalent to H.273 TransferCharacteristics code point 17. + + + + + Transfer characteristics as defined by + - ARIB STD-B67 (2015) + - Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + Equivalent to H.273 TransferCharacteristics code point 18. + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 1000 cd/m² + - reference white: 203 cd/m² + Note: HLG is a scene referred signal. All absolute luminance values + used here for HLG assume a 1000 cd/m² display. + + + + + + + This creates a new xx_color_management_output_v4 object for the + given wl_output. + + See the xx_color_management_output_v4 interface for more details. + + + + + + + + + If a xx_color_management_surface_v4 object already exists for the given + wl_surface, the protocol error surface_exists is raised. + + This creates a new color xx_color_management_surface_v4 object for the + given wl_surface. + + See the xx_color_management_surface_v4 interface for more details. + + + + + + + + + This creates a new color xx_color_management_feedback_surface_v4 object + for the given wl_surface. + + See the xx_color_management_feedback_surface_v4 interface for more + details. + + + + + + + + + Makes a new ICC-based image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a xx_image_description_v4 object. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.icc_v2_v4. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + Makes a new parametric image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a xx_image_description_v4 object. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.parametric. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + When this object is created, it shall immediately send this event once + for each rendering intent the compositor supports. + + + + + + + + When this object is created, it shall immediately send this event once + for each compositor supported feature listed in the enumeration. + + + + + + + + When this object is created, it shall immediately send this event once + for each named transfer function the compositor supports with the + parametric image description creator. + + + + + + + + When this object is created, it shall immediately send this event once + for each named set of primaries the compositor supports with the + parametric image description creator. + + + + + + + + + A xx_color_management_output_v4 describes the color properties of an + output. + + The xx_color_management_output_v4 is associated with the wl_output global + underlying the wl_output object. Therefore the client destroying the + wl_output object has no impact, but the compositor removing the output + global makes the xx_color_management_output_v4 object inert. + + + + + Destroy the color xx_color_management_output_v4 object. This does not + affect any remaining protocol objects. + + + + + + This event is sent whenever the image description of the output changed, + followed by one wl_output.done event common to output events across all + extensions. + + If the client wants to use the updated image description, it needs to do + get_image_description again, because image description objects are + immutable. + + + + + + This creates a new xx_image_description_v4 object for the current image + description of the output. There always is exactly one image description + active for an output so the client should destroy the image description + created by earlier invocations of this request. This request is usually + sent as a reaction to the image_description_changed event or when + creating a xx_color_management_output_v4 object. + + The image description of an output represents the color encoding the + output expects. There might be performance and power advantages, as well + as improved color reproduction, if a content update matches the image + description of the output it is being shown on. If a content update is + shown on any other output than the one it matches the image description + of, then the color reproduction on those outputs might be considerably + worse. + + The created xx_image_description_v4 object preserves the image + description of the output from the time the object was created. + + The resulting image description object allows get_information request. + + If this protocol object is inert, the resulting image description object + shall immediately deliver the xx_image_description_v4.failed event with + the no_output cause. + + If the interface version is inadequate for the output's image + description, meaning that the client does not support all the events + needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + xx_image_description_v4.failed event with the low_version cause. + + Otherwise the object shall immediately deliver the ready event. + + + + + + + + + A xx_color_management_surface_v4 allows the client to set the color + space and HDR properties of a surface. + + If the wl_surface associated with the xx_color_management_surface_v4 is + destroyed, the xx_color_management_surface_v4 object becomes inert. + + + + + Destroy the xx_color_management_surface_v4 object and do the same as + unset_image_description. + + + + + + + + + + + + Set the image description of the underlying surface. The image + description and rendering intent are double-buffered state, see + wl_surface.commit. + + It is the client's responsibility to understand the image description + it sets on a surface, and to provide content that matches that image + description. Compositors might convert images to match their own or any + other image descriptions. + + Image description whose creation gracefully failed (received + xx_image_description_v4.failed) are forbidden in this request, and in + such case the protocol error image_description is raised. + + All image descriptions whose creation succeeded (received + xx_image_description_v4.ready) are allowed and must always be accepted + by the compositor. + + A rendering intent provides the client's preference on how content + colors should be mapped to each output. The render_intent value must + be one advertised by the compositor with + xx_color_manager_v4.render_intent event, otherwise the protocol error + render_intent is raised. + + By default, a surface does not have an associated image description + nor a rendering intent. The handling of color on such surfaces is + compositor implementation defined. Compositors should handle such + surfaces as sRGB but may handle them differently if they have specific + requirements. + + + + + + + + + This request removes any image description from the surface. See + set_image_description for how a compositor handles a surface without + an image description. This is double-buffered state, see + wl_surface.commit. + + + + + + + A xx_color_management_feedback_surface_v4 allows the client to get the + preferred color description of a surface. + + If the wl_surface associated with this object is destroyed, the + xx_color_management_feedback_surface_v4 object becomes inert. + + + + + Destroy the xx_color_management_feedback_surface_v4 object. + + + + + + + + + + + The preferred image description is the one which likely has the most + performance and/or quality benefits for the compositor if used by the + client for its wl_surface contents. This event is sent whenever the + compositor changes the wl_surface's preferred image description. + + This event is merely a notification. When the client wants to know + what the preferred image description is, it shall use the get_preferred + request. + + The preferred image description is not automatically used for anything. + It is only a hint, and clients may set any valid image description with + set_image_description but there might be performance and color accuracy + improvements by providing the wl_surface contents in the preferred + image description. Therefore clients that can, should render according + to the preferred image description + + + + + + If this protocol object is inert, the protocol error inert is raised. + + The preferred image description represents the compositor's preferred + color encoding for this wl_surface at the current time. There might be + performance and power advantages, as well as improved color + reproduction, if the image description of a content update matches the + preferred image description. + + This creates a new xx_image_description_v4 object for the currently + preferred image description for the wl_surface. The client should + stop using and destroy the image descriptions created by earlier + invocations of this request for the associated wl_surface. + This request is usually sent as a reaction to the preferred_changed + event or when creating a xx_color_management_feedback_surface_v4 object + if the client is capable of adapting to image descriptions. + + The created xx_image_description_v4 object preserves the preferred image + description of the wl_surface from the time the object was created. + + The resulting image description object allows get_information request. + + If the interface version is inadequate for the preferred image + description, meaning that the client does not support all the + events needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + xx_image_description_v4.failed event with the low_version cause, + otherwise the object shall immediately deliver the ready event. + + + + + + + + + This type of object is used for collecting all the information required + to create a xx_image_description_v4 object from an ICC file. A complete + set of required parameters consists of these properties: + - ICC file + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + + + + + + + + + + + + + + Create an image description object based on the ICC information + previously set on this object. A compositor must parse the ICC data in + some undefined but finite amount of time. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + If the particular combination of the information is not supported + by the compositor, the resulting image description object shall + immediately deliver the xx_image_description_v4.failed event with the + 'unsupported' cause. If a valid image description was created from the + information, the xx_image_description_v4.ready event will eventually + be sent instead. + + This request destroys the xx_image_description_creator_icc_v4 object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the ICC profile file to be used as the basis of the image + description. + + The data shall be found through the given fd at the given offset, having + the given length. The fd must seekable and readable. Violating these + requirements raises the bad_fd protocol error. + + If reading the data fails due to an error independent of the client, the + compositor shall send the xx_image_description_v4.failed event on the + created xx_image_description_v4 with the 'operating_system' cause. + + The maximum size of the ICC profile is 4 MB. If length is greater than + that or zero, the protocol error bad_size is raised. If offset + length + exceeds the file size, the protocol error out_of_file is raised. + + A compositor may read the file at any time starting from this request + and only until whichever happens first: + - If create request was issued, the xx_image_description_v4 object + delivers either failed or ready event; or + - if create request was not issued, this + xx_image_description_creator_icc_v4 object is destroyed. + + A compositor shall not modify the contents of the file, and the fd may + be sealed for writes and size changes. The client must ensure to its + best ability that the data does not change while the compositor is + reading it. + + The data must represent a valid ICC profile. The ICC profile version + must be 2 or 4, it must be a 3 channel profile and the class must be + Display or ColorSpace. Violating these requirements will not result in a + protocol error but will eventually send the + xx_image_description_v4.failed event on the created + xx_image_description_v4 with the 'unsupported' cause. + + See the International Color Consortium specification ICC.1:2022 for more + details about ICC profiles. + + If ICC file has already been set on this object, the protocol error + already_set is raised. + + + + + + + + + + + This type of object is used for collecting all the parameters required + to create a xx_image_description_v4 object. A complete set of required + parameters consists of these properties: + - transfer characteristic function (tf) + - chromaticities of primaries and white point (primary color volume) + + The following properties are optional and have a well-defined default + if not explicitly set: + - primary color volume luminance range + - reference white luminance level + - mastering display primaries and white point (target color volume) + - mastering luminance range + - maximum content light level + - maximum frame-average light level + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + + + + + + + + + + + + + + + + + Create an image description object based on the parameters previously + set on this object. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + Also, the combination of the parameter set is verified. If the set is + not consistent, the protocol error inconsistent_set is raised. + + If the particular combination of the parameter set is not supported + by the compositor, the resulting image description object shall + immediately deliver the xx_image_description_v4.failed event with the + 'unsupported' cause. If a valid image description was created from the + parameter set, the xx_image_description_v4.ready event will eventually + be sent instead. + + This request destroys the xx_image_description_creator_params_v4 + object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the transfer characteristic using explicitly enumerated named + functions. + + When the resulting image description is attached to an image, the + content should be encoded and decoded according to the industry standard + practices for the transfer characteristic. + + Only names advertised with xx_color_manager_v4 event supported_tf_named + are allowed. Other values shall raise the protocol error invalid_tf. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + + + + + + + Sets the color component transfer characteristic to a power curve with + the given exponent. This curve represents the conversion from electrical + to optical pixel or color values. + + When the resulting image description is attached to an image, the + content should be encoded with the inverse of the power curve. + + The curve exponent shall be multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + The curve exponent must be at least 1.0 and at most 10.0. Otherwise the + protocol error invalid_tf is raised. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.set_tf_power. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + Sets the color primaries and white point using explicitly named sets. + This describes the primary color volume which is the basis for color + value encoding. + + Only names advertised with xx_color_manager_v4 event + supported_primaries_named are allowed. Other values shall raise the + protocol error invalid_primaries. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + + + + + + + Sets the color primaries and white point using CIE 1931 xy chromaticity + coordinates. This describes the primary color volume which is the basis + for color value encoding. + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + xx_color_manager_v4.feature.set_primaries. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + + + + + + + + Sets the primary color volume luminance range and the reference white + luminance level. + + The default luminances are + - primary color volume minimum: 0.2 cd/m² + - primary color volume maximum: 80 cd/m² + - reference white: 80 cd/m² + + Setting a named transfer characteristic can imply other default + luminances. + + The default luminances get overwritten when this request is used. + + 'min_lum' and 'max_lum' specify the minimum and maximum luminances of + the primary color volume as reproduced by the targeted display. + + 'reference_lum' specifies the luminance of the reference white as + reproduced by the targeted display, and reflects the targeted viewing + environment. + + Compositors should make sure that all content is anchored, meaning that + an input signal level of 'reference_lum' on one image description and + another input signal level of 'reference_lum' on another image + description should produce the same output level, even though the + 'reference_lum' on both image representations can be different. + + If 'max_lum' is less than the 'reference_lum', or 'reference_lum' is + less than or equal to 'min_lum', the protocol error invalid_luminance is + raised. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + If the primary color volume luminance range and the reference white + luminance level have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + xx_color_manager_v4.feature.set_luminances. Otherwise this request + raises the protocol error unsupported_feature. + + + + + + + + + + Provides the color primaries and white point of the mastering display + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata. + + The mastering display primaries define the target color volume. + + If mastering display primaries are not explicitly set, the target color + volume is assumed to be equal to the primary color volume. + + The target color volume is defined by all tristimulus values between 0.0 + and 1.0 (inclusive) of the color space defined by the given mastering + display primaries and white point. The colorimetry is identical between + the container color space and the mastering display color space, + including that no chromatic adaptation is applied even if the white + points differ. + + The target color volume can exceed the primary color volume to allow for + a greater color volume with an existing color space definition (for + example scRGB). It can be smaller than the primary color volume to + minimize gamut and tone mapping distances for big color spaces (HDR + metadata). + + To make use of the entire target color volume a suitable pixel format + has to be chosen (e.g. floating point to exceed the primary color + volume, or abusing limited quantization range as with xvYCC). + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + If mastering display primaries have already been set on this object, the + protocol error already_set is raised. + + This request can be used if the compositor advertises + xx_color_manager_v4.feature.set_mastering_display_primaries. Otherwise + this request raises the protocol error unsupported_feature. The + advertisement implies support only for target color volumes fully + contained within the primary color volume. + + If a compositor additionally supports target color volume exceeding the + primary color volume, it must advertise + xx_color_manager_v4.feature.extended_target_volume. If a client uses + target color volume exceeding the primary color volume and the + compositor does not support it, the result is implementation defined. + Compositors are recommended to detect this case and fail the image + description gracefully, but it may as well result in color artifacts. + + + + + + + + + + + + + + + Sets the luminance range that was used during the content mastering + process as the minimum and maximum absolute luminance L. This is + compatible with the SMPTE ST 2086 definition of HDR static metadata. + + The mastering luminance range is undefined by default. + + If max L is less than or equal to min L, the protocol error + invalid_luminance is raised. + + Min L value is multiplied by 10000 to get the argument min_lum value + and carry precision of 4 decimals. Max L value is unscaled for max_lum. + + + + + + + + + Sets the maximum content light level (max_cll) as defined by CTA-861-H. + + This can only be set when set_tf_cicp is used to set the transfer + characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system. + Otherwise, 'create' request shall raise inconsistent_set protocol + error. + + max_cll is undefined by default. + + + + + + + + Sets the maximum frame-average light level (max_fall) as defined by + CTA-861-H. + + This can only be set when set_tf_cicp is used to set the transfer + characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system. + Otherwise, 'create' request shall raise inconsistent_set protocol error. + + max_fall is undefined by default. + + + + + + + + + An image description carries information about the color encoding used on + a surface when attached to a wl_surface via + xx_color_management_surface_v4.set_image_description. A compositor can use + this information to decode pixel values into colorimetrically meaningful + quantities. + + Note, that the xx_image_description_v4 object is not ready to be used + immediately after creation. The object eventually delivers either the + 'ready' or the 'failed' event, specified in all requests creating it. The + object is deemed "ready" after receiving the 'ready' event. + + An object which is not ready is illegal to use, it can only be destroyed. + Any other request in this interface shall result in the 'not_ready' + protocol error. Attempts to use an object which is not ready through other + interfaces shall raise protocol errors defined there. + + Once created and regardless of how it was created, a + xx_image_description_v4 object always refers to one fixed image + description. It cannot change after creation. + + + + + Destroy this object. It is safe to destroy an object which is not ready. + + Destroying a xx_image_description_v4 object has no side-effects, not + even if a xx_color_management_surface_v4.set_image_description has not + yet been followed by a wl_surface.commit. + + + + + + + + + + + + + + + + + + + + + + If creating a xx_image_description_v4 object fails for a reason that is + not defined as a protocol error, this event is sent. + + The requests that create image description objects define whether and + when this can occur. Only such creation requests can trigger this event. + This event cannot be triggered after the image description was + successfully formed. + + Once this event has been sent, the xx_image_description_v4 object will + never become ready and it can only be destroyed. + + + + + + + + + Once this event has been sent, the xx_image_description_v4 object is + deemed "ready". Ready objects can be used to send requests and can be + used through other interfaces. + + Every ready xx_image_description_v4 protocol object refers to an + underlying image description record in the compositor. Multiple protocol + objects may end up referring to the same record. Clients may identify + these "copies" by comparing their id numbers: if the numbers from two + protocol objects are identical, the protocol objects refer to the same + image description record. Two different image description records + cannot have the same id number simultaneously. The id number does not + change during the lifetime of the image description record. + + The id number is valid only as long as the protocol object is alive. If + all protocol objects referring to the same image description record are + destroyed, the id number may be recycled for a different image + description record. + + Image description id number is not a protocol object id. Zero is + reserved as an invalid id number. It shall not be possible for a client + to refer to an image description by its id number in protocol. The id + numbers might not be portable between Wayland connections. + + This identity allows clients to de-duplicate image description records + and avoid get_information request if they already have the image + description information. + + + + + + + + Creates a xx_image_description_info_v4 object which delivers the + information that makes up the image description. + + Not all image description protocol objects allow get_information + request. Whether it is allowed or not is defined by the request that + created the object. If get_information is not allowed, the protocol + error no_information is raised. + + + + + + + + + Sends all matching events describing an image description object exactly + once and finally sends the 'done' event. + + Once a xx_image_description_info_v4 object has delivered a 'done' event it + is automatically destroyed. + + Every xx_image_description_info_v4 created from the same + xx_image_description_v4 shall always return the exact same data. + + + + + Signals the end of information events and destroys the object. + + + + + + The icc argument provides a file descriptor to the client which may be + memory-mapped to provide the ICC profile matching the image description. + The fd is read-only, and if mapped then it must be mapped with + MAP_PRIVATE by the client. + + The ICC profile version and other details are determined by the + compositor. There is no provision for a client to ask for a specific + kind of a profile. + + + + + + + + + + Delivers the primary color volume primaries and white point using CIE + 1931 xy chromaticity coordinates. + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + + + + + + + + + + + + + + Delivers the primary color volume primaries and white point using an + explicitly enumerated named set. + + + + + + + + The color component transfer characteristic of this image description is + a pure power curve. This event provides the exponent of the power + function. This curve represents the conversion from electrical to + optical pixel or color values. + + The curve exponent has been multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + + + + + + + Delivers the transfer characteristic using an explicitly enumerated + named function. + + + + + + + + Delivers the primary color volume luminance range and the reference + white luminance level. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + + + + + + + + + Provides the color primaries and white point of the target color volume + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata for mastering displays. + + While primary color volume is about how color is encoded, the target + color volume is the actually displayable color volume. If target color + volume is equal to the primary color volume, then this event is not + sent. + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + + + + + + + + + + + + + + Provides the luminance range that the image description is targeting as + the minimum and maximum absolute luminance L. This is compatible with + the SMPTE ST 2086 definition of HDR static metadata. + + This luminance range is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + Min L value is multiplied by 10000 to get the argument min_lum value and + carry precision of 4 decimals. Max L value is unscaled for max_lum. + + + + + + + + + Provides the targeted max_cll of the image description. max_cll is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + + + Provides the targeted max_fall of the image description. max_fall is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + \ No newline at end of file diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5805eff9..3d159042 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -31,6 +31,7 @@ #include "protocols/XDGShell.hpp" #include "protocols/XDGOutput.hpp" #include "protocols/SecurityContext.hpp" +#include "protocols/ColorManagement.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -2985,4 +2986,22 @@ void CCompositor::onNewMonitor(SP output) { g_pHyprRenderer->damageMonitor(PNEWMONITOR); PNEWMONITOR->onMonitorFrame(); + + if (PROTO::colorManagement && shouldChangePreferredImageDescription()) + PROTO::colorManagement->onImagePreferredChanged(); +} + +SImageDescription CCompositor::getPreferredImageDescription() { + if (!PROTO::colorManagement) { + Debug::log(ERR, "FIXME: color management protocol is not enabled, returning empty image description"); + return SImageDescription{}; + } + Debug::log(WARN, "FIXME: color management protocol is enabled, determine correct preferred image description"); + // should determine some common settings to avoid unnecessary transformations while keeping maximum displayable precision + return SImageDescription{.primaries = NColorPrimaries::BT709}; +} + +bool CCompositor::shouldChangePreferredImageDescription() { + Debug::log(WARN, "FIXME: color management protocol is enabled and outputs changed, check preferred image description changes"); + return false; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 4c428fca..629b71bc 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -23,6 +23,7 @@ #include "helpers/Monitor.hpp" #include "desktop/Workspace.hpp" #include "desktop/Window.hpp" +#include "protocols/types/ColorManagement.hpp" #include "render/Renderer.hpp" #include "render/OpenGL.hpp" #include "hyprerror/HyprError.hpp" @@ -169,6 +170,9 @@ class CCompositor { void updateSuspendedStates(); void onNewMonitor(SP output); + SImageDescription getPreferredImageDescription(); + bool shouldChangePreferredImageDescription(); + std::string explicitConfigPath; private: diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 8c35a3b1..686b996a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1658,4 +1658,22 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "experimental:wide_color_gamut", + .description = "force wide color gamut for all supported outputs", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "experimental:hdr", + .description = "force static hdr for all supported outputs", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "experimental:xx_color_management_v4", + .description = "enable color management protocol", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1ab29b1f..bbb3e68f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -622,6 +622,10 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("ecosystem:no_update_news", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:wide_color_gamut", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:hdr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:xx_color_management_v4", Hyprlang::INT{0}); + // devices m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 07af13df..057a6f90 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -119,4 +119,5 @@ class CWLSurface { } listeners; friend class CPointerConstraint; + friend class CXxColorManagerV4; }; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 0e1c21f5..b7d61f67 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -55,6 +55,8 @@ #include "../protocols/core/Subcompositor.hpp" #include "../protocols/core/Output.hpp" #include "../protocols/core/Shm.hpp" +#include "../protocols/ColorManagement.hpp" +#include "../protocols/FrogColorManagement.hpp" #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" @@ -77,11 +79,15 @@ void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { PROTO::outputs.erase(pMonitor->szName); PROTO::outputs.emplace(pMonitor->szName, makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); } + + if (PROTO::colorManagement && g_pCompositor->shouldChangePreferredImageDescription()) + PROTO::colorManagement->onImagePreferredChanged(); } CProtocolManager::CProtocolManager() { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static const auto PENABLEXXCM = CConfigValue("experimental:xx_color_management_v4"); // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { @@ -162,6 +168,11 @@ CProtocolManager::CProtocolManager() { PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); PROTO::hyprlandSurface = std::make_unique(&hyprland_surface_manager_v1_interface, 1, "HyprlandSurface"); + if (*PENABLEXXCM) { + PROTO::colorManagement = std::make_unique(&xx_color_manager_v4_interface, 1, "ColorManagement"); + PROTO::frogColorManagement = std::make_unique(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); + } + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp new file mode 100644 index 00000000..7ff4db4f --- /dev/null +++ b/src/protocols/ColorManagement.cpp @@ -0,0 +1,571 @@ +#include "ColorManagement.hpp" +#include "Compositor.hpp" + +CColorManager::CColorManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_EXTENDED_TARGET_VOLUME); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES); + + resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_NTSC); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM); + resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB); + + // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22); + resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB); + resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ); + // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR); + + resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_ABSOLUTE); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE_BPC); + + resource->setDestroy([](CXxColorManagerV4* r) { LOGM(TRACE, "Destroy xx_color_manager at {:x} (generated default)", (uintptr_t)r); }); + resource->setGetOutput([](CXxColorManagerV4* r, uint32_t id, wl_resource* output) { + LOGM(TRACE, "Get output for id={}, output={}", id, (uintptr_t)output); + const auto RESOURCE = + PROTO::colorManagement->m_vOutputs.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vOutputs.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + resource->setGetSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->colorManagement) { + r->error(XX_COLOR_MANAGER_V4_ERROR_SURFACE_EXISTS, "CM Surface already exists"); + return; + } + + const auto RESOURCE = + PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), SURF)); + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + SURF->colorManagement = RESOURCE; + }); + resource->setGetFeedbackSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get feedback surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_vFeedbackSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), SURF)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vFeedbackSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + resource->setNewIccCreator([](CXxColorManagerV4* r, uint32_t id) { + LOGM(WARN, "New ICC creator for id={} (unsupported)", id); + r->error(XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported"); + }); + resource->setNewParametricCreator([](CXxColorManagerV4* r, uint32_t id) { + LOGM(TRACE, "New parametric creator for id={}", id); + + const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vParametricCreators.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + + resource->setOnDestroy([this](CXxColorManagerV4* r) { PROTO::colorManagement->destroyResource(this); }); +} + +bool CColorManager::good() { + return resource->resource(); +} + +CColorManagementOutput::CColorManagementOutput(SP resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); + resource->setOnDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); + + resource->setGetImageDescription([this](CXxColorManagementOutputV4* r, uint32_t id) { + LOGM(TRACE, "Get image description for output={}, id={}", (uintptr_t)r, id); + if (imageDescription.valid()) + PROTO::colorManagement->destroyResource(imageDescription.get()); + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); +} + +bool CColorManagementOutput::good() { + return resource->resource(); +} + +wl_client* CColorManagementOutput::client() { + return pClient; +} + +CColorManagementSurface::CColorManagementSurface(SP surface_) : surface(surface_) { + // only for frog cm untill wayland cm is adopted +} + +CColorManagementSurface::CColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); + }); + resource->setOnDestroy([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); + }); + + resource->setSetImageDescription([this](CXxColorManagementSurfaceV4* r, wl_resource* image_description, uint32_t render_intent) { + LOGM(TRACE, "Set image description for surface={}, desc={}, intent={}", (uintptr_t)r, (uintptr_t)image_description, render_intent); + + const auto PO = (CXxImageDescriptionV4*)wl_resource_get_user_data(image_description); + if (!PO) { // FIXME check validity + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description creation failed"); + return; + } + if (render_intent != XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL) { + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_RENDER_INTENT, "Unsupported render intent"); + return; + } + + const auto imageDescription = std::find_if(PROTO::colorManagement->m_vImageDescriptions.begin(), PROTO::colorManagement->m_vImageDescriptions.end(), + [&](const auto& other) { return other->resource()->resource() == image_description; }); + if (imageDescription == PROTO::colorManagement->m_vImageDescriptions.end()) { + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description not found"); + return; + } + + m_hasImageDescription = true; + m_imageDescription = imageDescription->get()->settings; + }); + resource->setUnsetImageDescription([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r); + m_imageDescription = SImageDescription{}; + m_hasImageDescription = false; + }); +} + +bool CColorManagementSurface::good() { + return resource && resource->resource(); +} + +wl_client* CColorManagementSurface::client() { + return pClient; +} + +const SImageDescription& CColorManagementSurface::imageDescription() { + if (!hasImageDescription()) + LOGM(WARN, "Reading imageDescription while none set. Returns default or empty values"); + return m_imageDescription; +} + +bool CColorManagementSurface::hasImageDescription() { + return m_hasImageDescription; +} + +CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP resource_, SP surface_) : + surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + PROTO::colorManagement->destroyResource(this); + }); + resource->setOnDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + PROTO::colorManagement->destroyResource(this); + }); + + resource->setGetPreferred([this](CXxColorManagementFeedbackSurfaceV4* r, uint32_t id) { + LOGM(TRACE, "Get preferred for id {}", id); + + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), true)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + m_currentPreferred = RESOURCE; + + m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription(); + + RESOURCE->resource()->sendReady(id); + }); +} + +bool CColorManagementFeedbackSurface::good() { + return resource->resource(); +} + +wl_client* CColorManagementFeedbackSurface::client() { + return pClient; +} + +CColorManagementParametricCreator::CColorManagementParametricCreator(SP resource_) : resource(resource_) { + if (!good()) + return; + // + pClient = resource->client(); + + resource->setOnDestroy([this](CXxImageDescriptionCreatorParamsV4* r) { PROTO::colorManagement->destroyResource(this); }); + + resource->setCreate([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t id) { + LOGM(TRACE, "Create image description from params for id {}", id); + + // FIXME actually check completeness + if (!valuesSet) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET, "Missing required settings"); + return; + } + + // FIXME actually check consistency + if (!valuesSet) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCONSISTENT_SET, "Set is not consistent"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + // FIXME actually check support + if (!valuesSet) { + RESOURCE->resource()->sendFailed(XX_IMAGE_DESCRIPTION_V4_CAUSE_UNSUPPORTED, "unsupported"); + return; + } + + RESOURCE->self = RESOURCE; + RESOURCE->settings = settings; + RESOURCE->resource()->sendReady(id); + + PROTO::colorManagement->destroyResource(this); + }); + resource->setSetTfNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t tf) { + LOGM(TRACE, "Set image description transfer function to {}", tf); + if (valuesSet & PC_TF) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function already set"); + return; + } + + switch (tf) { + case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB: break; + case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: break; + default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return; + } + + settings.transferFunction = (xxColorManagerV4TransferFunction)tf; + valuesSet |= PC_TF; + }); + resource->setSetTfPower([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t eexp) { + LOGM(TRACE, "Set image description tf power to {}", eexp); + if (valuesSet & PC_TF_POWER) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function power already set"); + return; + } + settings.transferFunctionPower = eexp / 10000.0f; + valuesSet |= PC_TF_POWER; + }); + resource->setSetPrimariesNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t primaries) { + LOGM(TRACE, "Set image description primaries by name {}", primaries); + if (valuesSet & PC_PRIMARIES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); + return; + } + + switch (primaries) { + case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: + settings.primariesNameSet = true; + settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + settings.primaries = NColorPrimaries::BT709; + valuesSet |= PC_PRIMARIES; + break; + case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: + settings.primariesNameSet = true; + settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_BT2020; + settings.primaries = NColorPrimaries::BT2020; + valuesSet |= PC_PRIMARIES; + break; + default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries"); + } + }); + resource->setSetPrimaries( + [this](CXxImageDescriptionCreatorParamsV4* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { + LOGM(TRACE, "Set image description primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); + if (valuesSet & PC_PRIMARIES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); + return; + } + settings.primariesNameSet = false; + settings.primaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + valuesSet |= PC_PRIMARIES; + }); + resource->setSetLuminances([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) { + auto min = min_lum / 10000.0f; + LOGM(TRACE, "Set image description luminances to {} - {} ({})", min, max_lum, reference_lum); + if (valuesSet & PC_LUMINANCES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Luminances already set"); + return; + } + if (max_lum < reference_lum || reference_lum <= min) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); + return; + } + settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; + valuesSet |= PC_LUMINANCES; + }); + resource->setSetMasteringDisplayPrimaries( + [this](CXxImageDescriptionCreatorParamsV4* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { + LOGM(TRACE, "Set image description mastering primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); + // if (valuesSet & PC_MASTERING_PRIMARIES) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering primaries already set"); + // return; + // } + settings.masteringPrimaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + valuesSet |= PC_MASTERING_PRIMARIES; + }); + resource->setSetMasteringLuminance([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum) { + auto min = min_lum / 10000.0f; + LOGM(TRACE, "Set image description mastering luminances to {} - {}", min, max_lum); + // if (valuesSet & PC_MASTERING_LUMINANCES) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering luminances already set"); + // return; + // } + if (min > 0 && max_lum > 0 && max_lum <= min) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); + return; + } + settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; + valuesSet |= PC_MASTERING_LUMINANCES; + }); + resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) { + LOGM(TRACE, "Set image description max content light level to {}", max_cll); + // if (valuesSet & PC_CLL) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max CLL already set"); + // return; + // } + settings.maxCLL = max_cll; + valuesSet |= PC_CLL; + }); + resource->setSetMaxFall([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_fall) { + LOGM(TRACE, "Set image description max frame-average light level to {}", max_fall); + // if (valuesSet & PC_FALL) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max FALL already set"); + // return; + // } + settings.maxFALL = max_fall; + valuesSet |= PC_FALL; + }); +} + +bool CColorManagementParametricCreator::good() { + return resource->resource(); +} + +wl_client* CColorManagementParametricCreator::client() { + return pClient; +} + +CColorManagementImageDescription::CColorManagementImageDescription(SP resource_, bool allowGetInformation) : + m_resource(resource_), m_allowGetInformation(allowGetInformation) { + if (!good()) + return; + + pClient = m_resource->client(); + + m_resource->setDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); + m_resource->setOnDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); + + m_resource->setGetInformation([this](CXxImageDescriptionV4* r, uint32_t id) { + LOGM(TRACE, "Get image information for image={}, id={}", (uintptr_t)r, id); + if (!m_allowGetInformation) { + r->error(XX_IMAGE_DESCRIPTION_V4_ERROR_NO_INFORMATION, "Image descriptions doesn't allow get_information request"); + return; + } + + auto RESOURCE = makeShared(makeShared(r->client(), r->version(), id), settings); + + if (!RESOURCE->good()) + r->noMemory(); + + // CColorManagementImageDescriptionInfo should send everything in the constructor and be ready for destroying at this point + RESOURCE.reset(); + }); +} + +bool CColorManagementImageDescription::good() { + return m_resource->resource(); +} + +wl_client* CColorManagementImageDescription::client() { + return pClient; +} + +SP CColorManagementImageDescription::resource() { + return m_resource; +} + +CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_) : + m_resource(resource_), settings(settings_) { + if (!good()) + return; + + pClient = m_resource->client(); + + const auto toProto = [](float value) { return int32_t(std::round(value * 10000)); }; + + if (settings.iccFd >= 0) + m_resource->sendIccFile(settings.iccFd, settings.iccSize); + + // send preferred client paramateres + m_resource->sendPrimaries(toProto(settings.primaries.red.x), toProto(settings.primaries.red.y), toProto(settings.primaries.green.x), toProto(settings.primaries.green.y), + toProto(settings.primaries.blue.x), toProto(settings.primaries.blue.y), toProto(settings.primaries.white.x), toProto(settings.primaries.white.y)); + if (settings.primariesNameSet) + m_resource->sendPrimariesNamed(settings.primariesNamed); + m_resource->sendTfPower(std::round(settings.transferFunctionPower * 10000)); + m_resource->sendTfNamed(settings.transferFunction); + m_resource->sendLuminances(std::round(settings.luminances.min * 10000), settings.luminances.max, settings.luminances.reference); + + // send expexted display paramateres + m_resource->sendTargetPrimaries(toProto(settings.masteringPrimaries.red.x), toProto(settings.masteringPrimaries.red.y), toProto(settings.masteringPrimaries.green.x), + toProto(settings.masteringPrimaries.green.y), toProto(settings.masteringPrimaries.blue.x), toProto(settings.masteringPrimaries.blue.y), + toProto(settings.masteringPrimaries.white.x), toProto(settings.masteringPrimaries.white.y)); + m_resource->sendTargetLuminance(std::round(settings.masteringLuminances.min * 10000), settings.masteringLuminances.max); + m_resource->sendTargetMaxCll(settings.maxCLL); + m_resource->sendTargetMaxFall(settings.maxFALL); + + m_resource->sendDone(); +} + +bool CColorManagementImageDescriptionInfo::good() { + return m_resource->resource(); +} + +wl_client* CColorManagementImageDescriptionInfo::client() { + return pClient; +} + +CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(TRACE, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CColorManagementProtocol::onImagePreferredChanged() { + for (auto const& feedback : m_vFeedbackSurfaces) { + feedback->resource->sendPreferredChanged(); + } +} + +void CColorManagementProtocol::destroyResource(CColorManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementOutput* resource) { + std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementSurface* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementFeedbackSurface* resource) { + std::erase_if(m_vFeedbackSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementParametricCreator* resource) { + std::erase_if(m_vParametricCreators, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementImageDescription* resource) { + std::erase_if(m_vImageDescriptions, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp new file mode 100644 index 00000000..573abf69 --- /dev/null +++ b/src/protocols/ColorManagement.hpp @@ -0,0 +1,182 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "protocols/core/Compositor.hpp" +#include "xx-color-management-v4.hpp" +#include "types/ColorManagement.hpp" + +class CColorManager; +class CColorManagementOutput; +class CColorManagementImageDescription; +class CColorManagementProtocol; + +class CColorManager { + public: + CColorManager(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CColorManagementOutput { + public: + CColorManagementOutput(SP resource_); + + bool good(); + wl_client* client(); + + WP self; + WP imageDescription; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CColorManagementProtocol; + friend class CColorManagementImageDescription; +}; + +class CColorManagementSurface { + public: + CColorManagementSurface(SP surface_); // temporary interface for frog CM + CColorManagementSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + const SImageDescription& imageDescription(); + bool hasImageDescription(); + + private: + SP resource; + wl_client* pClient = nullptr; + SImageDescription m_imageDescription; + bool m_hasImageDescription = false; + + friend class CFrogColorManagementSurface; +}; + +class CColorManagementFeedbackSurface { + public: + CColorManagementFeedbackSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + private: + SP resource; + wl_client* pClient = nullptr; + + WP m_currentPreferred; + + friend class CColorManagementProtocol; +}; + +class CColorManagementParametricCreator { + public: + CColorManagementParametricCreator(SP resource_); + + bool good(); + wl_client* client(); + + WP self; + + SImageDescription settings; + + private: + enum eValuesSet : uint32_t { // NOLINT + PC_TF = (1 << 0), + PC_TF_POWER = (1 << 1), + PC_PRIMARIES = (1 << 2), + PC_LUMINANCES = (1 << 3), + PC_MASTERING_PRIMARIES = (1 << 4), + PC_MASTERING_LUMINANCES = (1 << 5), + PC_CLL = (1 << 6), + PC_FALL = (1 << 7), + }; + + SP resource; + wl_client* pClient = nullptr; + uint32_t valuesSet = 0; // enum eValuesSet +}; + +class CColorManagementImageDescription { + public: + CColorManagementImageDescription(SP resource_, bool allowGetInformation = false); + + bool good(); + wl_client* client(); + SP resource(); + + WP self; + + SImageDescription settings; + + private: + SP m_resource; + wl_client* pClient = nullptr; + bool m_allowGetInformation = false; + + friend class CColorManagementOutput; +}; + +class CColorManagementImageDescriptionInfo { + public: + CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_); + + bool good(); + wl_client* client(); + + private: + SP m_resource; + wl_client* pClient = nullptr; + SImageDescription settings; +}; + +class CColorManagementProtocol : public IWaylandProtocol { + public: + CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + void onImagePreferredChanged(); + + private: + void destroyResource(CColorManager* resource); + void destroyResource(CColorManagementOutput* resource); + void destroyResource(CColorManagementSurface* resource); + void destroyResource(CColorManagementFeedbackSurface* resource); + void destroyResource(CColorManagementParametricCreator* resource); + void destroyResource(CColorManagementImageDescription* resource); + + std::vector> m_vManagers; + std::vector> m_vOutputs; + std::vector> m_vSurfaces; + std::vector> m_vFeedbackSurfaces; + std::vector> m_vParametricCreators; + std::vector> m_vImageDescriptions; + + friend class CColorManager; + friend class CColorManagementOutput; + friend class CColorManagementSurface; + friend class CColorManagementFeedbackSurface; + friend class CColorManagementParametricCreator; + friend class CColorManagementImageDescription; + + friend class CFrogColorManagementSurface; +}; + +namespace PROTO { + inline UP colorManagement; +}; diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp new file mode 100644 index 00000000..3ea20405 --- /dev/null +++ b/src/protocols/FrogColorManagement.cpp @@ -0,0 +1,159 @@ +#include "FrogColorManagement.hpp" +#include "protocols/ColorManagement.hpp" +#include "protocols/core/Subcompositor.hpp" + +CFrogColorManager::CFrogColorManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([](CFrogColorManagementFactoryV1* r) { LOGM(TRACE, "Destroy frog_color_management at {:x} (generated default)", (uintptr_t)r); }); + resource->setOnDestroy([this](CFrogColorManagementFactoryV1* r) { PROTO::frogColorManagement->destroyResource(this); }); + + resource->setGetColorManagedSurface([](CFrogColorManagementFactoryV1* r, wl_resource* surface, uint32_t id) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->role->role() == SURFACE_ROLE_SUBSURFACE) + SURF = ((CSubsurfaceRole*)SURF->role.get())->subsurface->t1Parent(); + + const auto RESOURCE = PROTO::frogColorManagement->m_vSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), SURF)); + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::frogColorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); +} + +bool CFrogColorManager::good() { + return resource->resource(); +} + +CFrogColorManagementSurface::CFrogColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + if (!surface->colorManagement.valid()) { + const auto RESOURCE = PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(surface_)); + if (!RESOURCE) { + resource->noMemory(); + PROTO::colorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + surface->colorManagement = RESOURCE; + + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm and xx cm for surface {}", (uintptr_t)surface); + if (surface.valid()) + PROTO::colorManagement->destroyResource(surface->colorManagement.get()); + PROTO::frogColorManagement->destroyResource(this); + }); + } else + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + + resource->setDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + + resource->setSetKnownTransferFunction([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceTransferFunction tf) { + LOGM(TRACE, "Set frog cm transfer function {} for {}", (uint32_t)tf, surface->id()); + switch (tf) { + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + break; + ; + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: + if (pqIntentSent) { + LOGM(TRACE, + "FIXME: assuming broken enum value 2 (FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22) referring to eotf value 2 (TRANSFER_FUNCTION_ST2084_PQ)"); + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + break; + }; // intended fall through + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, std::format("FIXME: add tf support for {}", (uint32_t)tf)); // intended fall through + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + + surface->colorManagement->m_hasImageDescription = true; + } + }); + resource->setSetKnownContainerColorVolume([this](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { + LOGM(TRACE, "Set frog cm primaries {}", (uint32_t)primariesName); + switch (primariesName) { + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: surface->colorManagement->m_imageDescription.primaries = NColorPrimaries::BT709; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: surface->colorManagement->m_imageDescription.primaries = NColorPrimaries::BT2020; break; + } + + surface->colorManagement->m_hasImageDescription = true; + }); + resource->setSetRenderIntent([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { + LOGM(TRACE, "Set frog cm intent {}", (uint32_t)intent); + pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + surface->colorManagement->m_hasImageDescription = true; + }); + resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, + uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { + LOGM(TRACE, "Set frog primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, fall); + surface->colorManagement->m_imageDescription.masteringPrimaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, + .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, + .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, + .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; + surface->colorManagement->m_imageDescription.masteringLuminances.min = min_lum / 10000.0f; + surface->colorManagement->m_imageDescription.masteringLuminances.max = max_lum; + surface->colorManagement->m_imageDescription.maxCLL = cll; + surface->colorManagement->m_imageDescription.maxFALL = fall; + + surface->colorManagement->m_hasImageDescription = true; + }); +} + +bool CFrogColorManagementSurface::good() { + return resource->resource(); +} + +wl_client* CFrogColorManagementSurface::client() { + return pClient; +} + +CFrogColorManagementProtocol::CFrogColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CFrogColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(TRACE, "New frog_color_management at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CFrogColorManagementProtocol::destroyResource(CFrogColorManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CFrogColorManagementProtocol::destroyResource(CFrogColorManagementSurface* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/FrogColorManagement.hpp b/src/protocols/FrogColorManagement.hpp new file mode 100644 index 00000000..6c00e38d --- /dev/null +++ b/src/protocols/FrogColorManagement.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "protocols/core/Compositor.hpp" +#include "frog-color-management-v1.hpp" + +class CFrogColorManager { + public: + CFrogColorManager(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CFrogColorManagementSurface { + public: + CFrogColorManagementSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + bool pqIntentSent = false; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CFrogColorManagementProtocol : public IWaylandProtocol { + public: + CFrogColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CFrogColorManager* resource); + void destroyResource(CFrogColorManagementSurface* resource); + + std::vector> m_vManagers; + std::vector> m_vSurfaces; + + friend class CFrogColorManager; + friend class CFrogColorManagementSurface; +}; + +namespace PROTO { + inline UP frogColorManagement; +}; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 2a6f96f6..b347eb64 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -25,6 +25,8 @@ class CWLSurfaceResource; class CWLSubsurfaceResource; class CViewportResource; class CDRMSyncobjSurfaceResource; +class CColorManagementSurface; +class CFrogColorManagementSurface; class CWLCallbackResource { public: @@ -121,6 +123,7 @@ class CWLSurfaceResource { SP role; WP viewportResource; WP syncobj; // may not be present + WP colorManagement; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); diff --git a/src/protocols/types/ColorManagement.hpp b/src/protocols/types/ColorManagement.hpp new file mode 100644 index 00000000..e18f0b84 --- /dev/null +++ b/src/protocols/types/ColorManagement.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "xx-color-management-v4.hpp" + +struct SImageDescription { + int iccFd = -1; + uint32_t iccSize = 0; + + xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + float transferFunctionPower = 1.0f; + + bool primariesNameSet = false; + xxColorManagerV4Primaries primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + // primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0) + // wayland protocol expects int32_t values multiplied by 10000 + // drm expects uint16_t values multiplied by 50000 + // frog protocol expects drm values + struct SPCPRimaries { + struct { + float x = 0; + float y = 0; + } red, green, blue, white; + } primaries, masteringPrimaries; + + // luminances in cd/m² + // protos and drm expect min * 10000 + struct SPCLuminances { + float min = 0.2; // 0.2 cd/m² + uint32_t max = 80; // 80 cd/m² + uint32_t reference = 80; // 80 cd/m² + } luminances; + struct SPCMasteringLuminances { + float min = 0; + uint32_t max = 0; + } masteringLuminances; + + uint32_t maxCLL = 0; + uint32_t maxFALL = 0; +}; + +namespace NColorPrimaries { + static const auto BT709 = + SImageDescription::SPCPRimaries{.red = {.x = 0.64, .y = 0.33}, .green = {.x = 0.30, .y = 0.60}, .blue = {.x = 0.15, .y = 0.06}, .white = {.x = 0.3127, .y = 0.3290}}; + + static const auto BT2020 = + SImageDescription::SPCPRimaries{.red = {.x = 0.708, .y = 0.292}, .green = {.x = 0.170, .y = 0.797}, .blue = {.x = 0.131, .y = 0.046}, .white = {.x = 0.3127, .y = 0.3290}}; +} \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4d93d92f..978384d5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -25,6 +25,7 @@ #include "pass/RendererHintsPassElement.hpp" #include "pass/SurfacePassElement.hpp" #include "debug/Log.hpp" +#include "protocols/ColorManagement.hpp" #include using namespace Hyprutils::Utils; @@ -1374,6 +1375,82 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { } } +static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{ + .red = Aquamarine::IOutput::xy{.x = 0.64, .y = 0.33}, + .green = Aquamarine::IOutput::xy{.x = 0.30, .y = 0.60}, + .blue = Aquamarine::IOutput::xy{.x = 0.15, .y = 0.06}, + .white = Aquamarine::IOutput::xy{.x = 0.3127, .y = 0.3290}, +}; + +static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid) { + if (eotf == 0) + return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR + + const auto toNits = [](float value) { return uint16_t(std::round(value)); }; + const auto to16Bit = [](float value) { return uint16_t(std::round(value * 50000)); }; + const auto colorimetry = edid.chromaticityCoords.value_or(BT709); + + Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, + colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "ColorManagement max avg {}, min {}, max {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, + edid.hdrMetadata->desiredContentMaxLuminance); + return hdr_output_metadata{ + .metadata_type = 0, + .hdmi_metadata_type1 = + hdr_metadata_infoframe{ + .eotf = eotf, + .metadata_type = 0, + .display_primaries = + { + {.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)}, + {.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)}, + {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, + }, + .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, + .max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + .min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000), + .max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + .max_fall = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + }, + }; +} + +static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamarine::IOutput::SParsedEDID edid) { + if (settings.transferFunction != XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ) + return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR + + const auto toNits = [](uint32_t value) { return uint16_t(std::round(value)); }; + const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); }; + + auto colorimetry = settings.primaries; + auto luminances = settings.masteringLuminances.max > 0 ? + settings.masteringLuminances : + SImageDescription::SPCMasteringLuminances{.min = edid.hdrMetadata->desiredContentMinLuminance, .max = edid.hdrMetadata->desiredContentMaxLuminance}; + + Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, + colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", luminances.min, luminances.max, settings.maxCLL, settings.maxFALL); + return hdr_output_metadata{ + .metadata_type = 0, + .hdmi_metadata_type1 = + hdr_metadata_infoframe{ + .eotf = 2, + .metadata_type = 0, + .display_primaries = + { + {.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)}, + {.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)}, + {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, + }, + .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, + .max_display_mastering_luminance = toNits(luminances.max), + .min_display_mastering_luminance = toNits(luminances.min * 10000), + .max_cll = toNits(settings.maxCLL), + .max_fall = toNits(settings.maxFALL), + }, + }; +} + bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it @@ -1382,6 +1459,26 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); + static auto PWIDE = CConfigValue("experimental:wide_color_gamut"); + if (pMonitor->output->state->state().wideColorGamut != *PWIDE) + Debug::log(TRACE, "Setting wide color gamut {}", *PWIDE ? "on" : "off"); + pMonitor->output->state->setWideColorGamut(*PWIDE); + + static auto PHDR = CConfigValue("experimental:hdr"); + + Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, pMonitor->output->parsedEDID.hdrMetadata->supportsPQ); + if (pMonitor->output->parsedEDID.supportsBT2020 && pMonitor->output->parsedEDID.hdrMetadata->supportsPQ) { + if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { + const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); + const auto SURF = WINDOW->m_pWLSurface->resource(); + if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) + pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); + else + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + } else + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + } + if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; pMonitor->output->state->setCTM(pMonitor->ctm); diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index f2f2627a..71aa26be 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -79,6 +79,8 @@ void CSurfacePassElement::draw(const CRegion& damage) { DELTALESSTHAN(windowBox.height, data.surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!data.pWindow || (!data.pWindow->m_vRealSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; + if (data.surface->colorManagement.valid()) + Debug::log(TRACE, "FIXME: rendering surface with color management enabled, should apply necessary transformations"); g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size From c14390785745972903865c824fd324aa708f296a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 20:27:07 +0100 Subject: [PATCH 15/24] config: update animation even if disabled --- src/config/ConfigManager.cpp | 44 +++++++++++++++++------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index bbb3e68f..5839204f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2053,37 +2053,35 @@ std::optional CConfigManager::handleAnimation(const std::string& co if (enabledInt != 0 && enabledInt != 1) return "invalid animation on/off state"; - if (enabledInt) { - int64_t speed = -1; + int64_t speed = -1; - // speed - if (isNumber(ARGS[2], true)) { - speed = std::stof(ARGS[2]); + // speed + if (isNumber(ARGS[2], true)) { + speed = std::stof(ARGS[2]); - if (speed <= 0) { - speed = 1.f; - return "invalid speed"; - } - } else { - speed = 10.f; + if (speed <= 0) { + speed = 1.f; return "invalid speed"; } + } else { + speed = 10.f; + return "invalid speed"; + } - std::string bezierName = ARGS[3]; - m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, speed, ARGS[3], ARGS[4]); + std::string bezierName = ARGS[3]; + m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, speed, ARGS[3], ARGS[4]); - if (!g_pAnimationManager->bezierExists(bezierName)) { - const auto PANIMNODE = m_AnimationTree.getConfig(ANIMNAME); - PANIMNODE->internalBezier = "default"; - return "no such bezier"; - } + if (!g_pAnimationManager->bezierExists(bezierName)) { + const auto PANIMNODE = m_AnimationTree.getConfig(ANIMNAME); + PANIMNODE->internalBezier = "default"; + return "no such bezier"; + } - if (ARGS[4] != "") { - auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); + if (ARGS[4] != "") { + auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); - if (ERR != "") - return ERR; - } + if (ERR != "") + return ERR; } return {}; From 308b1f3afbb150fa008e3147faeee5d3ba7e6876 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 20:30:44 +0100 Subject: [PATCH 16/24] core: minor fixes for animation rewrite --- src/desktop/Workspace.cpp | 2 +- src/managers/AnimationManager.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index cab19254..376288ed 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -628,7 +628,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->value(), true); + g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->goal(), true); } } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 6bfeed83..c1ea1d27 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -147,11 +147,10 @@ static void handleUpdate(CAnimatedVariable& av, bool warp) { const auto PBEZIER = g_pAnimationManager->getBezier(av.getBezierName()); const auto POINTY = PBEZIER->getYForPoint(SPENT); - if constexpr (std::same_as) { + if constexpr (std::same_as) updateColorVariable(av, POINTY, animationsDisabled); - } else { + else updateVariable(av, POINTY, animationsDisabled); - } av.onUpdate(); From 67e1e46f9b6285ea260bc88844f85dec6b7d7d02 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 20:58:49 +0100 Subject: [PATCH 17/24] window: fixup fade out animation on silent moves --- src/desktop/Window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 8175fc57..2bd82ad3 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -413,10 +413,10 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; - m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; - m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); *m_fMovingToWorkspaceAlpha = 0.F; + m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; m_pWorkspace = pWorkspace; @@ -541,9 +541,9 @@ void CWindow::onMap() { m_fMovingFromWorkspaceAlpha->resetAllCallbacks(); m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); - m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); + m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); *m_fBorderAngleAnimationProgress = 1.f; m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); From 75727e7c17f31d97d518df8fdb11ec9d802ca5f3 Mon Sep 17 00:00:00 2001 From: staz Date: Wed, 8 Jan 2025 15:28:47 +0500 Subject: [PATCH 18/24] protocols: fix compilation error (#8988) --- src/protocols/FrogColorManagement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index 3ea20405..6a921981 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -88,7 +88,7 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPcolorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; From 5fa2594659f9f4ad19a1afe456ee34bd1c1907b7 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:28:55 +0000 Subject: [PATCH 19/24] renderer: don't access hdrMetadata optional if it has no value (#8987) --- src/render/Renderer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 978384d5..cf25d477 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1466,8 +1466,9 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { static auto PHDR = CConfigValue("experimental:hdr"); - Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, pMonitor->output->parsedEDID.hdrMetadata->supportsPQ); - if (pMonitor->output->parsedEDID.supportsBT2020 && pMonitor->output->parsedEDID.hdrMetadata->supportsPQ) { + const bool SUPPORTSPQ = pMonitor->output->parsedEDID.hdrMetadata.has_value() ? pMonitor->output->parsedEDID.hdrMetadata->supportsPQ : false; + Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, SUPPORTSPQ); + if (pMonitor->output->parsedEDID.supportsBT2020 && SUPPORTSPQ) { if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); const auto SURF = WINDOW->m_pWLSurface->resource(); From ad64726f5df0fa3cabcd6af9f872d5e8e1f65dbc Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 8 Jan 2025 11:33:41 +0100 Subject: [PATCH 20/24] opengl: only allocate offMainFB on demand These are not used by hyprland, only potentially plugins. No need to keep the VRAM allocated all the time --- src/render/OpenGL.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 93ab5fdf..819791e8 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -843,7 +843,6 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); - m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->offloadFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); m_RenderData.pCurrentMonData->mirrorFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); @@ -954,6 +953,12 @@ void CHyprOpenGLImpl::end() { m_RenderData.mainFB = nullptr; m_RenderData.outFB = nullptr; + // if we dropped to offMain, release it now. + // if there is a plugin constantly using it, this might be a bit slow, + // but I havent seen a single plugin yet use these, so it's better to drop a bit of vram. + if (m_RenderData.pCurrentMonData->offMainFB.isAllocated()) + m_RenderData.pCurrentMonData->offMainFB.release(); + // check for gl errors const GLenum ERR = glGetError(); @@ -2881,6 +2886,9 @@ void CHyprOpenGLImpl::restoreMatrix() { } void CHyprOpenGLImpl::bindOffMain() { + if (!m_RenderData.pCurrentMonData->offMainFB.isAllocated()) + m_RenderData.pCurrentMonData->offMainFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, + m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->offMainFB.bind(); clear(CHyprColor(0, 0, 0, 0)); m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offMainFB; From b320bc2dc6e308360936ce4396010359b74558bf Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 8 Jan 2025 12:29:24 +0100 Subject: [PATCH 21/24] core: use cpu-buffer hw cursors on nvidia by default --- src/config/ConfigManager.cpp | 6 +++--- src/managers/PointerManager.cpp | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5839204f..def15f26 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -578,7 +578,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{1}); // TODO: remove this. I don't think it does us any good to disable intro. - m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{2}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); @@ -593,7 +593,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); - m_pConfig->addConfigValue("cursor:use_cpu_buffer", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:use_cpu_buffer", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:warp_back_after_non_mouse_input", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); @@ -2741,7 +2741,7 @@ bool CConfigManager::shouldUseSoftwareCursors() { switch (*PNOHW) { case 0: return false; case 1: return true; - default: return g_pHyprRenderer->isNvidia(); + default: break; } return true; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index bc166825..85e1c601 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -376,7 +376,9 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->output->cursorPlaneSize(); auto const& cursorSize = currentCursorImage.size; - static auto PDUMB = CConfigValue("cursor:use_cpu_buffer"); + static auto PCPUBUFFER = CConfigValue("cursor:use_cpu_buffer"); + + const bool shouldUseCpuBuffer = *PCPUBUFFER == 1 || (*PCPUBUFFER != 0 && g_pHyprRenderer->isNvidia()); if (maxSize == Vector2D{}) return nullptr; @@ -390,12 +392,12 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size || - *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { + shouldUseCpuBuffer != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { - if (!state->monitor->cursorSwapchain || *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { + if (!state->monitor->cursorSwapchain || shouldUseCpuBuffer != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { auto allocator = state->monitor->output->getBackend()->preferredAllocator(); - if (*PDUMB) { + if (shouldUseCpuBuffer) { for (const auto& a : state->monitor->output->getBackend()->getAllocators()) { if (a->type() == Aquamarine::AQ_ALLOCATOR_TYPE_DRM_DUMB) { allocator = a; @@ -415,7 +417,7 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; // We do not set the format (unless shm). If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, // but if it's set, we don't wanna change it. - if (*PDUMB) + if (shouldUseCpuBuffer) options.format = DRM_FORMAT_ARGB8888; if (!state->monitor->cursorSwapchain->reconfigure(options)) { @@ -438,7 +440,7 @@ SP CPointerManager::renderHWCursorBuffer(SPdataCopy(); if (texData.empty()) { From 983bc067dac2e737bc724721c79d87cd81f27501 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 8 Jan 2025 12:34:43 +0100 Subject: [PATCH 22/24] opengl: fix crash on null fb stencil op --- src/render/OpenGL.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 819791e8..3a4781e7 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -847,7 +847,6 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb m_RenderData.pCurrentMonData->offloadFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); m_RenderData.pCurrentMonData->mirrorFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); m_RenderData.pCurrentMonData->mirrorSwapFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); - m_RenderData.pCurrentMonData->offMainFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); } if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) @@ -2886,9 +2885,13 @@ void CHyprOpenGLImpl::restoreMatrix() { } void CHyprOpenGLImpl::bindOffMain() { - if (!m_RenderData.pCurrentMonData->offMainFB.isAllocated()) + if (!m_RenderData.pCurrentMonData->offMainFB.isAllocated()) { m_RenderData.pCurrentMonData->offMainFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->output->state->state().drmFormat); + + m_RenderData.pCurrentMonData->offMainFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); + } + m_RenderData.pCurrentMonData->offMainFB.bind(); clear(CHyprColor(0, 0, 0, 0)); m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offMainFB; From c9822b08f914da2997e8ef47c8bef8016e5ff313 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Thu, 9 Jan 2025 05:16:34 +0800 Subject: [PATCH 23/24] keybinds: add new window destruction dispatchers (#8962) --- src/managers/KeybindManager.cpp | 84 +++++++++++++++++++++++++++++++-- src/managers/KeybindManager.hpp | 6 ++- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index fd4992eb..09f6f928 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -12,6 +12,7 @@ #include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" +#include "../helpers/signal/Signal.hpp" #include #include @@ -63,8 +64,12 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["exec"] = spawn; m_mDispatchers["execr"] = spawnRaw; - m_mDispatchers["killactive"] = killActive; - m_mDispatchers["closewindow"] = kill; + m_mDispatchers["killactive"] = closeActive; + m_mDispatchers["forcekillactive"] = killActive; + m_mDispatchers["closewindow"] = closeWindow; + m_mDispatchers["killwindow"] = killWindow; + m_mDispatchers["signal"] = signalActive; + m_mDispatchers["signalwindow"] = signalWindow; m_mDispatchers["togglefloating"] = toggleActiveFloating; m_mDispatchers["setfloating"] = setActiveFloating; m_mDispatchers["settiled"] = setActiveTiled; @@ -978,17 +983,23 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo } SDispatchResult CKeybindManager::killActive(std::string args) { + kill(g_pCompositor->m_pLastWindow.lock()->getPID(), SIGKILL); + + return {}; +} + +SDispatchResult CKeybindManager::closeActive(std::string args) { g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow.lock()); return {}; } -SDispatchResult CKeybindManager::kill(std::string args) { +SDispatchResult CKeybindManager::closeWindow(std::string args) { const auto PWINDOW = g_pCompositor->getWindowByRegex(args); if (!PWINDOW) { - Debug::log(ERR, "kill: no window found"); - return {.success = false, .error = "kill: no window found"}; + Debug::log(ERR, "closeWindow: no window found"); + return {.success = false, .error = "closeWindow: no window found"}; } g_pCompositor->closeWindow(PWINDOW); @@ -996,6 +1007,69 @@ SDispatchResult CKeybindManager::kill(std::string args) { return {}; } +SDispatchResult CKeybindManager::killWindow(std::string args) { + const auto PWINDOW = g_pCompositor->getWindowByRegex(args); + + if (!PWINDOW) { + Debug::log(ERR, "killWindow: no window found"); + return {.success = false, .error = "killWindow: no window found"}; + } + + kill(PWINDOW->getPID(), SIGKILL); + + return {}; +} + +SDispatchResult CKeybindManager::signalActive(std::string args) { + if (!std::all_of(args.begin(), args.end(), ::isdigit)) + return {.success = false, .error = "signalActive: signal has to be int"}; + + try { + const auto SIGNALNUM = std::stoi(args); + if (SIGNALNUM < 1 || SIGNALNUM > 31) { + Debug::log(ERR, "signalActive: invalid signal number {}", SIGNALNUM); + return {.success = false, .error = std::format("signalActive: invalid signal number {}", SIGNALNUM)}; + } + kill(g_pCompositor->m_pLastWindow.lock()->getPID(), SIGNALNUM); + } catch (const std::exception& e) { + Debug::log(ERR, "signalActive: invalid signal format \"{}\"", args); + return {.success = false, .error = std::format("signalActive: invalid signal format \"{}\"", args)}; + } + + kill(g_pCompositor->m_pLastWindow.lock()->getPID(), std::stoi(args)); + + return {}; +} + +SDispatchResult CKeybindManager::signalWindow(std::string args) { + const auto WINDOWREGEX = args.substr(0, args.find_first_of(',')); + const auto SIGNAL = args.substr(args.find_first_of(',') + 1); + + const auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX); + + if (!PWINDOW) { + Debug::log(ERR, "signalWindow: no window"); + return {.success = false, .error = "signalWindow: no window"}; + } + + if (!std::all_of(SIGNAL.begin(), SIGNAL.end(), ::isdigit)) + return {.success = false, .error = "signalWindow: signal has to be int"}; + + try { + const auto SIGNALNUM = std::stoi(SIGNAL); + if (SIGNALNUM < 1 || SIGNALNUM > 31) { + Debug::log(ERR, "signalWindow: invalid signal number {}", SIGNALNUM); + return {.success = false, .error = std::format("signalWindow: invalid signal number {}", SIGNALNUM)}; + } + kill(PWINDOW->getPID(), SIGNALNUM); + } catch (const std::exception& e) { + Debug::log(ERR, "signalWindow: invalid signal format \"{}\"", SIGNAL); + return {.success = false, .error = std::format("signalWindow: invalid signal format \"{}\"", SIGNAL)}; + } + + return {}; +} + void CKeybindManager::clearKeybinds() { m_vKeybinds.clear(); } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 02a39df9..76c72187 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -152,8 +152,12 @@ class CKeybindManager { static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); // -------------- Dispatchers -------------- // + static SDispatchResult closeActive(std::string); static SDispatchResult killActive(std::string); - static SDispatchResult kill(std::string); + static SDispatchResult closeWindow(std::string); + static SDispatchResult killWindow(std::string); + static SDispatchResult signalActive(std::string); + static SDispatchResult signalWindow(std::string); static SDispatchResult spawn(std::string); static SDispatchResult spawnRaw(std::string); static SDispatchResult toggleActiveFloating(std::string); From e66eab7b6a90514251439f661454c536afa3e5c8 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:13:47 +0000 Subject: [PATCH 24/24] animationmgr: don't warp based on POINTY value (#9000) --- src/managers/AnimationManager.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index c1ea1d27..f0f6a980 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -40,7 +40,7 @@ CHyprAnimationManager::CHyprAnimationManager() { template void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { - if (POINTY >= 1.f || warp || av.value() == av.goal()) { + if (warp || av.value() == av.goal()) { av.warp(); return; } @@ -50,7 +50,7 @@ void updateVariable(CAnimatedVariable& av, const float POINTY, bool war } void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { - if (POINTY >= 1.f || warp || av.value() == av.goal()) { + if (warp || av.value() == av.goal()) { av.warp(); return; } @@ -146,11 +146,12 @@ static void handleUpdate(CAnimatedVariable& av, bool warp) { const auto SPENT = av.getPercent(); const auto PBEZIER = g_pAnimationManager->getBezier(av.getBezierName()); const auto POINTY = PBEZIER->getYForPoint(SPENT); + const bool WARP = animationsDisabled || SPENT >= 1.f; if constexpr (std::same_as) - updateColorVariable(av, POINTY, animationsDisabled); + updateColorVariable(av, POINTY, WARP); else - updateVariable(av, POINTY, animationsDisabled); + updateVariable(av, POINTY, WARP); av.onUpdate();