animation: better cleanup

This commit is contained in:
Maximilian Seidler 2025-01-26 09:17:31 +01:00
parent 77ddb222fc
commit 27d35e8d08
4 changed files with 43 additions and 16 deletions

View file

@ -96,7 +96,8 @@ namespace Hyprutils {
struct { struct {
Memory::CWeakPointer<Signal::CSignal> connect; Memory::CWeakPointer<Signal::CSignal> connect;
Memory::CWeakPointer<Signal::CSignal> disconnect; Memory::CWeakPointer<Signal::CSignal> forceDisconnect;
Memory::CWeakPointer<Signal::CSignal> lazyDisconnect;
} m_sEvents; } m_sEvents;
private: private:

View file

@ -6,6 +6,7 @@
#include "../memory/WeakPtr.hpp" #include "../memory/WeakPtr.hpp"
#include "../signal/Signal.hpp" #include "../signal/Signal.hpp"
#include <cstdint>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -18,13 +19,15 @@ namespace Hyprutils {
virtual ~CAnimationManager() = default; virtual ~CAnimationManager() = default;
void tickDone(); void tickDone();
void rotateActive();
bool shouldTickForNext(); bool shouldTickForNext();
virtual void scheduleTick() = 0; virtual void scheduleTick() = 0;
virtual void onTicked() = 0; virtual void onTicked() = 0;
void connectVarListener(std::any data); void connectListener(std::any data);
void disconnectVarListener(std::any data); void lazyDisconnectListener(std::any data);
void forceDisconnectListener(std::any data);
void addBezierWithName(std::string, const Math::Vector2D&, const Math::Vector2D&); void addBezierWithName(std::string, const Math::Vector2D&, const Math::Vector2D&);
void removeAllBeziers(); void removeAllBeziers();
@ -40,16 +43,19 @@ namespace Hyprutils {
std::unordered_map<std::string, Memory::CSharedPointer<CBezierCurve>> m_mBezierCurves; std::unordered_map<std::string, Memory::CSharedPointer<CBezierCurve>> m_mBezierCurves;
bool m_bTickScheduled = false; bool m_bTickScheduled = false;
uint32_t m_pendingDisconnects = 0;
struct { struct {
Signal::CHyprSignalListener connect; Signal::CHyprSignalListener connect;
Signal::CHyprSignalListener disconnect; Signal::CHyprSignalListener forceDisconnect;
Signal::CHyprSignalListener lazyDisconnect;
} m_sListeners; } m_sListeners;
struct { struct {
// Those events are shared between animated vars // Those events are shared between animated vars
Memory::CSharedPointer<Signal::CSignal> connect; Memory::CSharedPointer<Signal::CSignal> connect;
Memory::CSharedPointer<Signal::CSignal> disconnect; Memory::CSharedPointer<Signal::CSignal> forceDisconnect;
Memory::CSharedPointer<Signal::CSignal> lazyDisconnect;
} m_sEvents; } m_sEvents;
friend class CBaseAnimatedVariable; friend class CBaseAnimatedVariable;

View file

@ -14,7 +14,8 @@ void CBaseAnimatedVariable::create(Hyprutils::Animation::CAnimationManager* pAni
m_pSelf = pSelf; m_pSelf = pSelf;
m_sEvents.connect = pAnimationManager->m_sEvents.connect; m_sEvents.connect = pAnimationManager->m_sEvents.connect;
m_sEvents.disconnect = pAnimationManager->m_sEvents.disconnect; m_sEvents.forceDisconnect = pAnimationManager->m_sEvents.forceDisconnect;
m_sEvents.lazyDisconnect = pAnimationManager->m_sEvents.lazyDisconnect;
m_bDummy = false; m_bDummy = false;
} }
@ -30,7 +31,7 @@ void CBaseAnimatedVariable::connectToActive() {
} }
void CBaseAnimatedVariable::disconnectFromActive() { void CBaseAnimatedVariable::disconnectFromActive() {
if (const auto DISCONNECT = m_sEvents.disconnect.lock()) if (const auto DISCONNECT = m_sEvents.forceDisconnect.lock())
DISCONNECT->emit(static_cast<void*>(this)); DISCONNECT->emit(static_cast<void*>(this));
m_bIsConnectedToActive = false; m_bIsConnectedToActive = false;
@ -142,7 +143,9 @@ void CBaseAnimatedVariable::resetAllCallbacks() {
void CBaseAnimatedVariable::onAnimationEnd() { void CBaseAnimatedVariable::onAnimationEnd() {
m_bIsBeingAnimated = false; m_bIsBeingAnimated = false;
/* We do not call disconnectFromActive here. The animation manager will remove it on a call to tickDone. */ /* lazy disconnect, since this animvar is atill alive */
if (const auto DISCONNECT = m_sEvents.lazyDisconnect.lock())
DISCONNECT->emit(static_cast<void*>(this));
if (m_fEndCallback) { if (m_fEndCallback) {
/* loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false. */ /* loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false. */

View file

@ -15,13 +15,15 @@ CAnimationManager::CAnimationManager() {
m_mBezierCurves["default"] = BEZIER; m_mBezierCurves["default"] = BEZIER;
m_sEvents.connect = makeShared<CSignal>(); m_sEvents.connect = makeShared<CSignal>();
m_sEvents.disconnect = makeShared<CSignal>(); m_sEvents.forceDisconnect = makeShared<CSignal>();
m_sEvents.lazyDisconnect = makeShared<CSignal>();
m_sListeners.connect = m_sEvents.connect->registerListener([this](std::any data) { connectVarListener(data); }); m_sListeners.connect = m_sEvents.connect->registerListener([this](std::any data) { connectListener(data); });
m_sListeners.disconnect = m_sEvents.disconnect->registerListener([this](std::any data) { disconnectVarListener(data); }); m_sListeners.forceDisconnect = m_sEvents.forceDisconnect->registerListener([this](std::any data) { forceDisconnectListener(data); });
m_sListeners.lazyDisconnect = m_sEvents.lazyDisconnect->registerListener([this](std::any data) { lazyDisconnectListener(data); });
} }
void CAnimationManager::connectVarListener(std::any data) { void CAnimationManager::connectListener(std::any data) {
if (!m_bTickScheduled) if (!m_bTickScheduled)
scheduleTick(); scheduleTick();
@ -32,9 +34,15 @@ void CAnimationManager::connectVarListener(std::any data) {
m_vActiveAnimatedVariables.emplace_back(PAV); m_vActiveAnimatedVariables.emplace_back(PAV);
} catch (const std::bad_any_cast&) { return; } } catch (const std::bad_any_cast&) { return; }
// When the animation manager ticks, it will cleanup the active list.
// If for some reason we don't tick for a while, but vars get warped a lot, we could end up with a lot of pending disconnects.
// So we rorate here, since we don't want the vector to grow too big for no reason.
if (m_pendingDisconnects > 100)
rotateActive();
} }
void CAnimationManager::disconnectVarListener(std::any data) { void CAnimationManager::forceDisconnectListener(std::any data) {
try { try {
const auto PAV = std::any_cast<void*>(data); const auto PAV = std::any_cast<void*>(data);
if (!PAV) if (!PAV)
@ -44,6 +52,10 @@ void CAnimationManager::disconnectVarListener(std::any data) {
} catch (const std::bad_any_cast&) { return; } } catch (const std::bad_any_cast&) { return; }
} }
void CAnimationManager::lazyDisconnectListener(std::any data) {
m_pendingDisconnects++;
}
void CAnimationManager::removeAllBeziers() { void CAnimationManager::removeAllBeziers() {
m_mBezierCurves.clear(); m_mBezierCurves.clear();
@ -67,6 +79,10 @@ bool CAnimationManager::shouldTickForNext() {
} }
void CAnimationManager::tickDone() { void CAnimationManager::tickDone() {
rotateActive();
}
void CAnimationManager::rotateActive() {
std::vector<CWeakPointer<CBaseAnimatedVariable>> active; std::vector<CWeakPointer<CBaseAnimatedVariable>> active;
active.reserve(m_vActiveAnimatedVariables.size()); // avoid reallocations active.reserve(m_vActiveAnimatedVariables.size()); // avoid reallocations
for (auto const& av : m_vActiveAnimatedVariables) { for (auto const& av : m_vActiveAnimatedVariables) {
@ -81,6 +97,7 @@ void CAnimationManager::tickDone() {
} }
m_vActiveAnimatedVariables = std::move(active); m_vActiveAnimatedVariables = std::move(active);
m_pendingDisconnects = 0;
} }
bool CAnimationManager::bezierExists(const std::string& bezier) { bool CAnimationManager::bezierExists(const std::string& bezier) {