diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 50ce621a..4b6999c7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -513,7 +513,7 @@ CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) { wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list* layerSurfaces, Vector2D* sCoords) { for (auto& l : *layerSurfaces) { - if (!l->layerSurface->mapped) + if (l->fadingOut || (l->layerSurface && !l->layerSurface->mapped)) continue; const auto SURFACEAT = wlr_layer_surface_v1_surface_at(l->layerSurface, pos.x - l->geometry.x, pos.y - l->geometry.y, &sCoords->x, &sCoords->y); @@ -650,6 +650,24 @@ void CCompositor::cleanupWindows() { return; } } + + for (auto& ls : m_lSurfacesFadingOut) { + if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) { + for (auto& m : m_lMonitors) { + for (auto& lsl : m.m_aLayerSurfaceLists) { + lsl.remove(ls); + } + } + + g_pHyprOpenGL->m_mLayerFramebuffers[ls].release(); + g_pHyprOpenGL->m_mLayerFramebuffers.erase(ls); + + m_lSurfacesFadingOut.remove(ls); + delete ls; + + return; + } + } } CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { @@ -863,4 +881,4 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { return longestIntersectMonitor; return nullptr; -} \ No newline at end of file +} diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 4256dead..b072266a 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -67,6 +67,7 @@ public: std::list m_lWorkspaces; std::list m_lSubsurfaces; std::list m_lWindowsFadingOut; + std::list m_lSurfacesFadingOut; void startCompositor(); void cleanupExit(); diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index 12e9e93b..f9c98585 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -72,9 +72,6 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) { const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID); - // remove the layersurface as it's not used anymore - PMONITOR->m_aLayerSurfaceLists[layersurface->layer].remove(layersurface); - // rearrange to fix the reserved areas if (PMONITOR) { g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); @@ -85,7 +82,8 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) { g_pHyprRenderer->damageBox(&geomFixed); } - delete layersurface; + layersurface->readyToDelete = true; + layersurface->layerSurface = nullptr; } void Events::listener_mapLayerSurface(void* owner, void* data) { @@ -121,6 +119,11 @@ void Events::listener_mapLayerSurface(void* owner, void* data) { wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); + + layersurface->alpha.setValue(0); + layersurface->alpha = 255.f; + layersurface->readyToDelete = false; + layersurface->fadingOut = false; } void Events::listener_unmapLayerSurface(void* owner, void* data) { @@ -128,6 +131,14 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) { Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface); + // make a snapshot and start fade + g_pHyprOpenGL->makeLayerSnapshot(layersurface); + layersurface->alpha = 0.f; + + layersurface->fadingOut = true; + + g_pCompositor->m_lSurfacesFadingOut.push_back(layersurface); + if (layersurface->layerSurface->mapped) layersurface->layerSurface->mapped = false; diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index a484958b..0b31b5c5 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -18,6 +18,7 @@ enum AVARDAMAGEPOLICY { class CAnimationManager; class CWorkspace; +struct SLayerSurface; class CAnimatedVariable { public: @@ -183,8 +184,12 @@ private: float* m_pSpeed = nullptr; int64_t* m_pEnabled = nullptr; + + // owners void* m_pWindow = nullptr; void* m_pWorkspace = nullptr; + void* m_pLayer = nullptr; + std::string* m_pBezier = nullptr; bool m_bDummy = true; @@ -196,4 +201,5 @@ private: friend class CAnimationManager; friend class CWorkspace; + friend struct SLayerSurface; }; \ No newline at end of file diff --git a/src/helpers/WLClasses.cpp b/src/helpers/WLClasses.cpp new file mode 100644 index 00000000..82e41b4f --- /dev/null +++ b/src/helpers/WLClasses.cpp @@ -0,0 +1,7 @@ +#include "WLClasses.hpp" +#include "../config/ConfigManager.hpp" + +SLayerSurface::SLayerSurface() { + alpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE); + alpha.m_pLayer = this; +} \ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 544498f5..9d1cd6df 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -5,8 +5,11 @@ #include "../../wlr-layer-shell-unstable-v1-protocol.h" #include "../Window.hpp" #include "SubsurfaceTree.hpp" +#include "AnimatedVariable.hpp" struct SLayerSurface { + SLayerSurface(); + wlr_layer_surface_v1* layerSurface; wl_list link; @@ -22,6 +25,9 @@ struct SLayerSurface { int monitorID = -1; + CAnimatedVariable alpha; + bool fadingOut = false; + bool readyToDelete = false; // For the list lookup bool operator==(const SLayerSurface& rhs) { diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index a881b7d1..686d80dd 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -41,12 +41,16 @@ void CAnimationManager::tick() { // window stuff const auto PWINDOW = (CWindow*)av->m_pWindow; const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace; + const auto PLAYER = (SLayerSurface*)av->m_pLayer; + wlr_box WLRBOXPREV = {0,0,0,0}; if (PWINDOW) { WLRBOXPREV = {(int)PWINDOW->m_vRealPosition.vec().x - BORDERSIZE - 1, (int)PWINDOW->m_vRealPosition.vec().y - BORDERSIZE - 1, (int)PWINDOW->m_vRealSize.vec().x + 2 * BORDERSIZE + 2, (int)PWINDOW->m_vRealSize.vec().y + 2 * BORDERSIZE + 2}; } else if (PWORKSPACE) { const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; + } else if (PLAYER) { + WLRBOXPREV = PLAYER->geometry; } // check if it's disabled, if so, warp diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 80478de0..1711d08e 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -698,12 +698,57 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { wlr_output_rollback(PMONITOR->output); } +void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) { + // we trust the window is valid. + const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID); + wlr_output_attach_render(PMONITOR->output, nullptr); + + // we need to "damage" the entire monitor + // so that we render the entire window + // this is temporary, doesnt mess with the actual wlr damage + pixman_region32_t fakeDamage; + pixman_region32_init(&fakeDamage); + pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y); + + begin(PMONITOR, &fakeDamage); + + pixman_region32_fini(&fakeDamage); + + const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer]; + + PFRAMEBUFFER->m_tTransform = pLayer->layerSurface->surface->current.transform; + + PFRAMEBUFFER->alloc(PMONITOR->vecSize.x, PMONITOR->vecSize.y); + + PFRAMEBUFFER->bind(); + + clear(CColor(0, 0, 0, 0)); // JIC + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + // draw the layer + g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now); + +// restore original fb +#ifndef GLES2 + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb); +#else + glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb); +#endif + glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y); + + end(); + + wlr_output_rollback(PMONITOR->output); +} + void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { RASSERT(m_RenderData.pMonitor, "Tried to render snapshot rect without begin()!"); const auto PWINDOW = *pWindow; auto it = m_mWindowFramebuffers.begin(); - for (;it != m_mWindowFramebuffers.end(); it++) { + for (; it != m_mWindowFramebuffers.end(); it++) { if (it->first == PWINDOW) { break; } @@ -724,6 +769,32 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { pixman_region32_fini(&fakeDamage); } +void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) { + RASSERT(m_RenderData.pMonitor, "Tried to render snapshot rect without begin()!"); + const auto PLAYER = *pLayer; + + auto it = m_mLayerFramebuffers.begin(); + for (; it != m_mLayerFramebuffers.end(); it++) { + if (it->first == PLAYER) { + break; + } + } + + if (it == m_mLayerFramebuffers.end() || !it->second.m_cTex.m_iTexID) + return; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(PLAYER->monitorID); + + wlr_box windowBox = {0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + + pixman_region32_t fakeDamage; + pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y); + + renderTextureInternalWithDamage(it->second.m_cTex, &windowBox, PLAYER->alpha.fl(), &fakeDamage, 0); + + pixman_region32_fini(&fakeDamage); +} + void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 99de2a29..34b1a871 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -60,7 +60,9 @@ public: void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0); void makeWindowSnapshot(CWindow*); + void makeLayerSnapshot(SLayerSurface*); void renderSnapshot(CWindow**); + void renderSnapshot(SLayerSurface**); void clear(const CColor&); void clearWithTex(); @@ -78,6 +80,7 @@ public: pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region std::unordered_map m_mWindowFramebuffers; + std::unordered_map m_mLayerFramebuffers; std::unordered_map m_mMonitorRenderResources; std::unordered_map m_mMonitorBGTextures; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index be51336c..9509b30d 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -121,6 +121,17 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* } } +void CHyprRenderer::renderLayer(SLayerSurface* pLayer, SMonitor* pMonitor, timespec* time) { + if (pLayer->fadingOut) { + g_pHyprOpenGL->renderSnapshot(&pLayer); + return; + } + + SRenderData renderdata = {pMonitor->output, time, pLayer->geometry.x, pLayer->geometry.y}; + renderdata.fadeAlpha = pLayer->alpha.fl(); + wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); +} + void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { const auto PMONITOR = g_pCompositor->getMonitorFromID(ID); @@ -129,12 +140,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { // Render layer surfaces below windows for monitor for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - SRenderData renderdata = {PMONITOR->output, time, ls->geometry.x, ls->geometry.y}; - wlr_surface_for_each_surface(ls->layerSurface->surface, renderSurface, &renderdata); + renderLayer(ls, PMONITOR, time); } for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - SRenderData renderdata = {PMONITOR->output, time, ls->geometry.x, ls->geometry.y}; - wlr_surface_for_each_surface(ls->layerSurface->surface, renderSurface, &renderdata); + renderLayer(ls, PMONITOR, time); } // if there is a fullscreen window, render it and then do not render anymore. @@ -178,12 +187,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { // Render surfaces above windows for monitor for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - SRenderData renderdata = {PMONITOR->output, time, ls->geometry.x, ls->geometry.y}; - wlr_surface_for_each_surface(ls->layerSurface->surface, renderSurface, &renderdata); + renderLayer(ls, PMONITOR, time); } for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - SRenderData renderdata = {PMONITOR->output, time, ls->geometry.x, ls->geometry.y}; - wlr_surface_for_each_surface(ls->layerSurface->surface, renderSurface, &renderdata); + renderLayer(ls, PMONITOR, time); } renderDragIcon(PMONITOR, time); @@ -316,6 +323,9 @@ void CHyprRenderer::arrangeLayerArray(SMonitor* pMonitor, const std::listvecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { + if (ls->fadingOut) + continue; + const auto PLAYER = ls->layerSurface; const auto PSTATE = &PLAYER->current; if (exclusiveZone != (PSTATE->exclusive_zone > 0)) { diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b445c176..f879702b 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -37,6 +37,7 @@ private: void drawBorderForWindow(CWindow*, SMonitor*, float a = 255.f, const Vector2D& offset = Vector2D(0,0)); void renderWorkspaceWithFullscreenWindow(SMonitor*, CWorkspace*, timespec*); void renderWindow(CWindow*, SMonitor*, timespec*, bool); + void renderLayer(SLayerSurface*, SMonitor*, timespec*); void renderDragIcon(SMonitor*, timespec*);