From 4bc669f9331bb66ab30bd705d09f1239bc3e83ed Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Feb 2024 15:00:34 +0000 Subject: [PATCH] layers: add fully featured animations Adds configs and layerrules to handle them alas fixes #981 I have cooked --- src/Compositor.cpp | 2 +- src/config/ConfigManager.cpp | 5 +- src/events/Layers.cpp | 18 +---- src/helpers/WLClasses.cpp | 123 +++++++++++++++++++++++++++++- src/helpers/WLClasses.hpp | 37 +++++---- src/managers/AnimationManager.cpp | 23 +++++- src/render/OpenGL.cpp | 15 +++- src/render/OpenGL.hpp | 2 +- src/render/Renderer.cpp | 14 +++- 9 files changed, 197 insertions(+), 42 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f0d7ca0f..48ac0e1c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1480,7 +1480,7 @@ void CCompositor::cleanupFadingOut(const int& monid) { if (ls->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || ls->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid)); - if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) { + if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) { for (auto& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](std::unique_ptr& other) { return other.get() == ls; }) != lsl.end()) { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5cb18e0f..151347ad 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -617,6 +617,7 @@ void CConfigManager::setDefaultAnimationVars() { if (isFirstLaunch) { INITANIMCFG("global"); INITANIMCFG("windows"); + INITANIMCFG("layers"); INITANIMCFG("fade"); INITANIMCFG("border"); INITANIMCFG("borderangle"); @@ -644,6 +645,7 @@ void CConfigManager::setDefaultAnimationVars() { animationConfig["global"] = {false, "default", "", 8.f, 1, &animationConfig["general"], nullptr}; CREATEANIMCFG("windows", "global"); + CREATEANIMCFG("layers", "global"); CREATEANIMCFG("fade", "global"); CREATEANIMCFG("border", "global"); CREATEANIMCFG("borderangle", "global"); @@ -658,6 +660,7 @@ void CConfigManager::setDefaultAnimationVars() { CREATEANIMCFG("fadeSwitch", "fade"); CREATEANIMCFG("fadeShadow", "fade"); CREATEANIMCFG("fadeDim", "fade"); + CREATEANIMCFG("fadeLayers", "fade"); CREATEANIMCFG("specialWorkspace", "workspaces"); } @@ -1840,7 +1843,7 @@ bool windowRuleValid(const std::string& RULE) { } bool layerRuleValid(const std::string& RULE) { - return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray"); + return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray") || RULE.starts_with("animation"); } std::optional CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index 9ef9b025..1b76c536 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -113,9 +113,6 @@ void Events::listener_mapLayerSurface(void* owner, void* data) { layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive; layersurface->surface = layersurface->layerSurface->surface; - // anim - layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); - // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output); @@ -166,8 +163,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) { const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; - layersurface->alpha.setValue(0); - layersurface->alpha = ((layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS) ? 0.f : 1.f); + layersurface->startAnimation(!(layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); layersurface->readyToDelete = false; layersurface->fadingOut = false; @@ -198,23 +194,17 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) { layersurface->mapped = false; - layersurface->fadingOut = true; - - layersurface->alpha.setValueAndWarp(0.f); + layersurface->startAnimation(false); return; } - // anim - layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); - // make a snapshot and start fade g_pHyprOpenGL->makeLayerSnapshot(layersurface); - layersurface->alpha = 0.f; + + layersurface->startAnimation(false); layersurface->mapped = false; - layersurface->fadingOut = true; - g_pCompositor->addToFadingOutSafe(layersurface); const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output); diff --git a/src/helpers/WLClasses.cpp b/src/helpers/WLClasses.cpp index 960145b9..3abcf0a5 100644 --- a/src/helpers/WLClasses.cpp +++ b/src/helpers/WLClasses.cpp @@ -3,9 +3,17 @@ #include "../Compositor.hpp" SLayerSurface::SLayerSurface() { - alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE); - alpha.m_pLayer = this; + alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeLayers"), nullptr, AVARDAMAGE_ENTIRE); + realPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE); + realSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE); + alpha.m_pLayer = this; + realPosition.m_pLayer = this; + realSize.m_pLayer = this; alpha.registerVar(); + realPosition.registerVar(); + realSize.registerVar(); + + alpha.setValueAndWarp(0.f); } SLayerSurface::~SLayerSurface() { @@ -22,6 +30,7 @@ void SLayerSurface::applyRules() { ignoreAlpha = false; ignoreAlphaValue = 0.f; xray = -1; + animationStyle.reset(); for (auto& rule : g_pConfigManager->getMatchingRules(this)) { if (rule.rule == "noanim") @@ -44,10 +53,120 @@ void SLayerSurface::applyRules() { try { xray = configStringToInt(vars[1]); } catch (...) {} + } else if (rule.rule.starts_with("animation")) { + CVarList vars{rule.rule, 0, 's'}; + animationStyle = vars[1]; } } } +void SLayerSurface::startAnimation(bool in, bool instant) { + const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle); + + if (ANIMSTYLE == "slide") { + // get closest edge + const auto MIDDLE = geometry.middle(); + + const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE); + + const std::array edgePoints = { + PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0}, + PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y}, + PMONITOR->vecPosition + Vector2D{0, PMONITOR->vecSize.y}, + PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, + }; + + float closest = std::numeric_limits::max(); + size_t leader = 0; + for (size_t i = 0; i < 4; ++i) { + float dist = MIDDLE.distance(edgePoints[i]); + if (dist < closest) { + leader = i; + closest = dist; + } + } + + realSize.setValueAndWarp(geometry.size()); + alpha.setValueAndWarp(1.f); + + Vector2D prePos; + + switch (leader) { + case 0: + // TOP + prePos = {geometry.x, PMONITOR->vecPosition.y - geometry.h}; + break; + case 1: + // BOTTOM + prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecPosition.y}; + break; + case 2: + // LEFT + prePos = {PMONITOR->vecPosition.x - geometry.w, geometry.y}; + break; + case 3: + // RIGHT + prePos = {PMONITOR->vecPosition.x + PMONITOR->vecSize.x, geometry.y}; + break; + default: UNREACHABLE(); + } + + if (in) { + realPosition.setValueAndWarp(prePos); + realPosition = geometry.pos(); + } else { + realPosition.setValueAndWarp(geometry.pos()); + realPosition = prePos; + } + + } else if (ANIMSTYLE.starts_with("popin")) { + float minPerc = 0.f; + if (ANIMSTYLE.find("%") != std::string::npos) { + try { + auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ')); + minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); + } catch (std::exception& e) { + ; // oops + } + } + + minPerc *= 0.01; + + 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; + + if (in) { + 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; + } + } else { + // fade + realPosition.setValueAndWarp(geometry.pos()); + realSize.setValueAndWarp(geometry.size()); + alpha = in ? 1.f : 0.f; + } + + if (!in) + fadingOut = true; +} + +bool SLayerSurface::isFadedOut() { + if (!fadingOut) + return false; + + return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated(); +} + CRegion SConstraint::getLogicCoordsRegion() { CRegion result; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 6cc9b5d5..b62a6489 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -19,6 +19,11 @@ struct SLayerSurface { ~SLayerSurface(); void applyRules(); + void startAnimation(bool in, bool instant = false); + bool isFadedOut(); + + CAnimatedVariable realPosition; + CAnimatedVariable realSize; wlr_layer_surface_v1* layerSurface; wl_list link; @@ -34,26 +39,28 @@ struct SLayerSurface { DYNLISTENER(commitLayerSurface); DYNLISTENER(newPopup); - CBox geometry = {0, 0, 0, 0}; - Vector2D position; - zwlr_layer_shell_v1_layer layer; + CBox geometry = {0, 0, 0, 0}; + Vector2D position; + zwlr_layer_shell_v1_layer layer; - bool mapped = false; + bool mapped = false; - int monitorID = -1; + int monitorID = -1; - std::string szNamespace = ""; + std::string szNamespace = ""; - CAnimatedVariable alpha; - bool fadingOut = false; - bool readyToDelete = false; - bool noProcess = false; - bool noAnimations = false; + CAnimatedVariable alpha; + bool fadingOut = false; + bool readyToDelete = false; + bool noProcess = false; + bool noAnimations = false; - bool forceBlur = false; - int xray = -1; - bool ignoreAlpha = false; - float ignoreAlphaValue = 0.f; + bool forceBlur = false; + int xray = -1; + bool ignoreAlpha = false; + float ignoreAlphaValue = 0.f; + + std::optional animationStyle; // For the list lookup bool operator==(const SLayerSurface& rhs) const { diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 23584827..859e3b03 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -101,7 +101,7 @@ void CAnimationManager::tick() { g_pHyprRenderer->damageWindow(w.get()); } } else if (PLAYER) { - WLRBOXPREV = PLAYER->geometry; + WLRBOXPREV = CBox{PLAYER->realPosition.vec(), PLAYER->realSize.vec()}; PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f); if (!PMONITOR) continue; @@ -513,6 +513,27 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config, if (style == "loop" || style == "once") return ""; return "unknown style"; + } else if (config.starts_with("layers")) { + if (style == "fade" || style == "" || style == "slide") + return ""; + else if (style.starts_with("popin")) { + // try parsing + float minPerc = 0.f; + if (style.find("%") != std::string::npos) { + try { + auto percstr = style.substr(style.find_last_of(' ')); + minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); + } catch (std::exception& e) { return "invalid minperc"; } + + return ""; + } + + minPerc; // fix warning + + return ""; + } + return ""; + return "unknown style"; } else { return "animation has no styles"; } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 1a53ec39..90e92e25 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1812,13 +1812,22 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) { const auto PMONITOR = g_pCompositor->getMonitorFromID(PLAYER->monitorID); - CBox monbox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; + 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.vec().x / (PLAYER->geometry.w * PMONITOR->scale)), + (PMONITOR->scale * PLAYER->realSize.vec().y / (PLAYER->geometry.h * PMONITOR->scale))); - CRegion fakeDamage{0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; + layerBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x; + layerBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y; + layerBox.x = ((PLAYER->realPosition.vec().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - (((PLAYER->geometry.x - PMONITOR->vecPosition.x) * PMONITOR->scale) * scaleXY.x); + layerBox.y = ((PLAYER->realPosition.vec().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}; m_bEndFrame = true; - renderTextureInternalWithDamage(it->second.m_cTex, &monbox, PLAYER->alpha.fl(), &fakeDamage, 0); + renderTextureInternalWithDamage(it->second.m_cTex, &layerBox, PLAYER->alpha.fl(), &fakeDamage, 0); m_bEndFrame = false; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1e43333b..f6dff805 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -112,7 +112,7 @@ struct SCurrentRenderData { Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); - CBox clipBox = {}; + CBox clipBox = {}; // scaled coordinates uint32_t discardMode = DISCARD_OPAQUE; float discardOpacity = 0.f; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 1c3aaab0..68803a4a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -606,15 +606,20 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times TRACY_GPU_ZONE("RenderLayer"); - SRenderData renderdata = {pMonitor, time, pLayer->geometry.x, pLayer->geometry.y}; + const auto REALPOS = pLayer->realPosition.vec(); + const auto REALSIZ = pLayer->realSize.vec(); + + SRenderData renderdata = {pMonitor, time, REALPOS.x, REALPOS.y}; renderdata.fadeAlpha = pLayer->alpha.fl(); renderdata.blur = pLayer->forceBlur; renderdata.surface = pLayer->layerSurface->surface; renderdata.decorate = false; - renderdata.w = pLayer->geometry.width; - renderdata.h = pLayer->geometry.height; + renderdata.w = REALSIZ.x; + renderdata.h = REALSIZ.y; renderdata.blockBlurOptimization = pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM || pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; + g_pHyprOpenGL->m_RenderData.clipBox = CBox{0, 0, pMonitor->vecSize.x, pMonitor->vecSize.y}.scale(pMonitor->scale); + g_pHyprOpenGL->m_pCurrentLayer = pLayer; if (pLayer->ignoreAlpha) { @@ -629,7 +634,8 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times renderdata.popup = true; wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata); - g_pHyprOpenGL->m_pCurrentLayer = nullptr; + g_pHyprOpenGL->m_pCurrentLayer = nullptr; + g_pHyprOpenGL->m_RenderData.clipBox = {}; } void CHyprRenderer::renderIMEPopup(SIMEPopup* pPopup, CMonitor* pMonitor, timespec* time) {