mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-28 10:23:48 -07:00
renderer: add popup fade-in-out (#11313)
Adds xdg popup fade-in and fade-out
This commit is contained in:
@@ -993,6 +993,9 @@ void CConfigManager::setDefaultAnimationVars() {
|
||||
m_animationTree.createNode("fadeLayers", "fade");
|
||||
m_animationTree.createNode("fadeLayersIn", "fadeLayers");
|
||||
m_animationTree.createNode("fadeLayersOut", "fadeLayers");
|
||||
m_animationTree.createNode("fadePopups", "fade");
|
||||
m_animationTree.createNode("fadePopupsIn", "fadePopups");
|
||||
m_animationTree.createNode("fadePopupsOut", "fadePopups");
|
||||
|
||||
// workspaces
|
||||
m_animationTree.createNode("workspacesIn", "workspaces");
|
||||
|
@@ -1,10 +1,12 @@
|
||||
#include "Popup.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../managers/SeatManager.hpp"
|
||||
#include "../managers/AnimationManager.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
#include "../render/Renderer.hpp"
|
||||
@@ -51,6 +53,20 @@ CPopup::~CPopup() {
|
||||
|
||||
void CPopup::initAllSignals() {
|
||||
|
||||
g_pAnimationManager->createAnimation(0.f, m_alpha, g_pConfigManager->getAnimationPropertyConfig("fade"), AVARDAMAGE_NONE);
|
||||
m_alpha->setUpdateCallback([this](auto) {
|
||||
//
|
||||
g_pHyprRenderer->damageBox(CBox{coordsGlobal(), size()});
|
||||
});
|
||||
m_alpha->setCallbackOnEnd(
|
||||
[this](auto) {
|
||||
if (inert()) {
|
||||
g_pHyprRenderer->damageBox(CBox{coordsGlobal(), size()});
|
||||
fullyDestroy();
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
||||
if (!m_resource) {
|
||||
if (!m_windowOwner.expired())
|
||||
m_listeners.newPopup = m_windowOwner->m_xdgSurface->m_events.newPopup.listen([this](const auto& resource) { this->onNewPopup(resource); });
|
||||
@@ -83,6 +99,23 @@ void CPopup::onDestroy() {
|
||||
if (!m_parent)
|
||||
return; // head node
|
||||
|
||||
m_subsurfaceHead.reset();
|
||||
m_children.clear();
|
||||
|
||||
if (m_fadingOut && m_alpha->isBeingAnimated()) {
|
||||
Debug::log(LOG, "popup {:x}: skipping full destroy, animating", (uintptr_t)this);
|
||||
return;
|
||||
}
|
||||
|
||||
fullyDestroy();
|
||||
}
|
||||
|
||||
void CPopup::fullyDestroy() {
|
||||
Debug::log(LOG, "popup {:x} fully destroying", (uintptr_t)this);
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
std::erase_if(g_pHyprOpenGL->m_popupFramebuffers, [&](const auto& other) { return other.first.expired() || other.first == m_self; });
|
||||
|
||||
std::erase_if(m_parent->m_children, [this](const auto& other) { return other.get() == this; });
|
||||
}
|
||||
|
||||
@@ -112,6 +145,9 @@ void CPopup::onMap() {
|
||||
|
||||
if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
|
||||
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer));
|
||||
|
||||
m_alpha->setValueAndWarp(0.F);
|
||||
*m_alpha = 1.F;
|
||||
}
|
||||
|
||||
void CPopup::onUnmap() {
|
||||
@@ -124,13 +160,12 @@ void CPopup::onUnmap() {
|
||||
return;
|
||||
}
|
||||
|
||||
m_mapped = false;
|
||||
|
||||
// if the popup committed a different size right now, we also need to damage the old size.
|
||||
const Vector2D MAX_DAMAGE_SIZE = {std::max(m_lastSize.x, m_resource->m_surface->m_surface->m_current.size.x),
|
||||
std::max(m_lastSize.y, m_resource->m_surface->m_surface->m_current.size.y)};
|
||||
|
||||
m_lastSize = m_resource->m_surface->m_surface->m_current.size;
|
||||
m_lastPos = coordsRelativeToParent();
|
||||
|
||||
const auto COORDS = coordsGlobal();
|
||||
|
||||
@@ -142,6 +177,16 @@ void CPopup::onUnmap() {
|
||||
box = CBox{COORDS, MAX_DAMAGE_SIZE}.expand(4);
|
||||
g_pHyprRenderer->damageBox(box);
|
||||
|
||||
m_lastSize = MAX_DAMAGE_SIZE;
|
||||
|
||||
g_pHyprRenderer->makeSnapshot(m_self);
|
||||
|
||||
m_fadingOut = true;
|
||||
m_alpha->setValueAndWarp(1.F);
|
||||
*m_alpha = 0.F;
|
||||
|
||||
m_mapped = false;
|
||||
|
||||
m_subsurfaceHead.reset();
|
||||
|
||||
if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
|
||||
@@ -245,7 +290,7 @@ Vector2D CPopup::coordsRelativeToParent() {
|
||||
Vector2D offset;
|
||||
|
||||
if (!m_resource)
|
||||
return {};
|
||||
return m_lastPos;
|
||||
|
||||
WP<CPopup> current = m_self;
|
||||
offset -= current->m_resource->m_surface->m_current.geometry.pos();
|
||||
@@ -381,3 +426,11 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
|
||||
bool CPopup::inert() const {
|
||||
return m_inert;
|
||||
}
|
||||
|
||||
PHLMONITOR CPopup::getMonitor() {
|
||||
if (!m_windowOwner.expired())
|
||||
return m_windowOwner->m_monitor.lock();
|
||||
if (!m_layerOwner.expired())
|
||||
return m_layerOwner->m_monitor.lock();
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "Subsurface.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
|
||||
class CXDGPopupResource;
|
||||
|
||||
@@ -21,6 +22,7 @@ class CPopup {
|
||||
SP<CWLSurface> getT1Owner();
|
||||
Vector2D coordsRelativeToParent();
|
||||
Vector2D coordsGlobal();
|
||||
PHLMONITOR getMonitor();
|
||||
|
||||
Vector2D size();
|
||||
|
||||
@@ -45,6 +47,10 @@ class CPopup {
|
||||
WP<CPopup> m_self;
|
||||
bool m_mapped = false;
|
||||
|
||||
// fade in-out
|
||||
PHLANIMVAR<float> m_alpha;
|
||||
bool m_fadingOut = false;
|
||||
|
||||
private:
|
||||
CPopup() = default;
|
||||
|
||||
@@ -82,6 +88,7 @@ class CPopup {
|
||||
void reposition();
|
||||
void recheckChildrenRecursive();
|
||||
void sendScale();
|
||||
void fullyDestroy();
|
||||
|
||||
Vector2D localToGlobal(const Vector2D& rel);
|
||||
Vector2D t1ParentCoords();
|
||||
|
@@ -298,6 +298,7 @@ class CHyprOpenGLImpl {
|
||||
|
||||
std::map<PHLWINDOWREF, CFramebuffer> m_windowFramebuffers;
|
||||
std::map<PHLLSREF, CFramebuffer> m_layerFramebuffers;
|
||||
std::map<WP<CPopup>, CFramebuffer> m_popupFramebuffers;
|
||||
std::map<PHLMONITORREF, SMonitorRenderData> m_monitorRenderResources;
|
||||
std::map<PHLMONITORREF, CFramebuffer> m_monitorBGFBs;
|
||||
|
||||
|
@@ -472,7 +472,6 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
|
||||
const auto PWORKSPACE = pWindow->m_workspace;
|
||||
const auto REALPOS = pWindow->m_realPosition->value() + (pWindow->m_pinned ? Vector2D{} : PWORKSPACE->m_renderOffset->value());
|
||||
static auto PDIMAROUND = CConfigValue<Hyprlang::FLOAT>("decoration:dim_around");
|
||||
static auto PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
|
||||
|
||||
CSurfacePassElement::SRenderData renderdata = {pMonitor, time};
|
||||
CBox textureBox = {REALPOS.x, REALPOS.y, std::max(pWindow->m_realSize->value().x, 5.0), std::max(pWindow->m_realSize->value().y, 5.0)};
|
||||
@@ -639,10 +638,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
renderdata.popup = true;
|
||||
|
||||
static CConfigValue PBLURPOPUPS = CConfigValue<Hyprlang::INT>("decoration:blur:popups");
|
||||
static CConfigValue PBLURIGNOREA = CConfigValue<Hyprlang::FLOAT>("decoration:blur:popups_ignorealpha");
|
||||
|
||||
renderdata.blur = *PBLURPOPUPS && *PBLUR;
|
||||
renderdata.blur = shouldBlur(pWindow->m_popupHead);
|
||||
|
||||
if (renderdata.blur) {
|
||||
renderdata.discardMode |= DISCARD_ALPHA;
|
||||
@@ -656,11 +654,17 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
|
||||
|
||||
pWindow->m_popupHead->breadthfirst(
|
||||
[this, &renderdata](WP<CPopup> popup, void* data) {
|
||||
if (popup->m_fadingOut) {
|
||||
renderSnapshot(popup);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!popup->m_wlSurface || !popup->m_wlSurface->resource() || !popup->m_mapped)
|
||||
return;
|
||||
const auto pos = popup->coordsRelativeToParent();
|
||||
const Vector2D oldPos = renderdata.pos;
|
||||
renderdata.pos += pos;
|
||||
renderdata.alpha = popup->m_alpha->value();
|
||||
|
||||
popup->m_wlSurface->resource()->breadthfirst(
|
||||
[this, &renderdata](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) {
|
||||
@@ -676,6 +680,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T
|
||||
renderdata.pos = oldPos;
|
||||
},
|
||||
&renderdata);
|
||||
|
||||
renderdata.alpha = 1.F;
|
||||
}
|
||||
|
||||
if (decorate) {
|
||||
@@ -2468,6 +2474,54 @@ void CHyprRenderer::makeSnapshot(PHLLS pLayer) {
|
||||
m_bRenderingSnapshot = false;
|
||||
}
|
||||
|
||||
void CHyprRenderer::makeSnapshot(WP<CPopup> popup) {
|
||||
// we trust the window is valid.
|
||||
const auto PMONITOR = popup->getMonitor();
|
||||
|
||||
if (!PMONITOR || !PMONITOR->m_output || PMONITOR->m_pixelSize.x <= 0 || PMONITOR->m_pixelSize.y <= 0)
|
||||
return;
|
||||
|
||||
if (!popup->m_wlSurface || !popup->m_wlSurface->resource() || !popup->m_mapped)
|
||||
return;
|
||||
|
||||
CRegion fakeDamage{0, 0, PMONITOR->m_transformedSize.x, PMONITOR->m_transformedSize.y};
|
||||
|
||||
makeEGLCurrent();
|
||||
|
||||
const auto PFRAMEBUFFER = &g_pHyprOpenGL->m_popupFramebuffers[popup];
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, DRM_FORMAT_ABGR8888);
|
||||
|
||||
beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
|
||||
|
||||
m_bRenderingSnapshot = true;
|
||||
|
||||
g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 0)); // JIC
|
||||
|
||||
CSurfacePassElement::SRenderData renderdata;
|
||||
renderdata.pos = popup->coordsGlobal() - PMONITOR->m_position;
|
||||
renderdata.alpha = 1.F;
|
||||
renderdata.dontRound = true; // don't round popups
|
||||
renderdata.pMonitor = PMONITOR;
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
renderdata.popup = true;
|
||||
|
||||
popup->m_wlSurface->resource()->breadthfirst(
|
||||
[this, &renderdata](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) {
|
||||
renderdata.localPos = offset;
|
||||
renderdata.texture = s->m_current.texture;
|
||||
renderdata.surface = s;
|
||||
renderdata.mainSurface = false;
|
||||
m_renderPass.add(makeUnique<CSurfacePassElement>(renderdata));
|
||||
renderdata.surfaceCounter++;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
endRender();
|
||||
|
||||
m_bRenderingSnapshot = false;
|
||||
}
|
||||
|
||||
void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) {
|
||||
static auto PDIMAROUND = CConfigValue<Hyprlang::FLOAT>("decoration:dim_around");
|
||||
|
||||
@@ -2570,6 +2624,41 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) {
|
||||
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
|
||||
}
|
||||
|
||||
void CHyprRenderer::renderSnapshot(WP<CPopup> popup) {
|
||||
if (!g_pHyprOpenGL->m_popupFramebuffers.contains(popup))
|
||||
return;
|
||||
|
||||
static CConfigValue PBLURIGNOREA = CConfigValue<Hyprlang::FLOAT>("decoration:blur:popups_ignorealpha");
|
||||
|
||||
const auto FBDATA = &g_pHyprOpenGL->m_popupFramebuffers.at(popup);
|
||||
|
||||
if (!FBDATA->getTexture())
|
||||
return;
|
||||
|
||||
const auto PMONITOR = popup->getMonitor();
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
CRegion fakeDamage{0, 0, PMONITOR->m_transformedSize.x, PMONITOR->m_transformedSize.y};
|
||||
|
||||
const bool SHOULD_BLUR = shouldBlur(popup);
|
||||
|
||||
CTexPassElement::SRenderData data;
|
||||
data.flipEndFrame = true;
|
||||
data.tex = FBDATA->getTexture();
|
||||
data.box = {{}, PMONITOR->m_transformedSize};
|
||||
data.a = popup->m_alpha->value();
|
||||
data.damage = fakeDamage;
|
||||
data.blur = SHOULD_BLUR;
|
||||
data.blurA = sqrt(popup->m_alpha->value()); // sqrt makes the blur fadeout more realistic.
|
||||
if (SHOULD_BLUR)
|
||||
data.ignoreAlpha = std::max(*PBLURIGNOREA, 0.01F); /* ignore the alpha 0 regions */
|
||||
;
|
||||
|
||||
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
|
||||
}
|
||||
|
||||
bool CHyprRenderer::shouldBlur(PHLLS ls) {
|
||||
if (m_bRenderingSnapshot)
|
||||
return false;
|
||||
@@ -2586,3 +2675,10 @@ bool CHyprRenderer::shouldBlur(PHLWINDOW w) {
|
||||
const bool DONT_BLUR = w->m_windowData.noBlur.valueOrDefault() || w->m_windowData.RGBX.valueOrDefault() || w->opaque();
|
||||
return *PBLUR && !DONT_BLUR;
|
||||
}
|
||||
|
||||
bool CHyprRenderer::shouldBlur(WP<CPopup> p) {
|
||||
static CConfigValue PBLURPOPUPS = CConfigValue<Hyprlang::INT>("decoration:blur:popups");
|
||||
static CConfigValue PBLUR = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
|
||||
|
||||
return *PBLURPOPUPS && *PBLUR;
|
||||
}
|
||||
|
@@ -81,8 +81,10 @@ class CHyprRenderer {
|
||||
void addWindowToRenderUnfocused(PHLWINDOW window);
|
||||
void makeSnapshot(PHLWINDOW);
|
||||
void makeSnapshot(PHLLS);
|
||||
void makeSnapshot(WP<CPopup>);
|
||||
void renderSnapshot(PHLWINDOW);
|
||||
void renderSnapshot(PHLLS);
|
||||
void renderSnapshot(WP<CPopup>);
|
||||
|
||||
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
||||
// otherwise, it will be the one used.
|
||||
@@ -134,6 +136,7 @@ class CHyprRenderer {
|
||||
|
||||
bool shouldBlur(PHLLS ls);
|
||||
bool shouldBlur(PHLWINDOW w);
|
||||
bool shouldBlur(WP<CPopup> p);
|
||||
|
||||
bool m_cursorHidden = false;
|
||||
bool m_cursorHasSurface = false;
|
||||
|
Reference in New Issue
Block a user