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 {
Memory::CWeakPointer<Signal::CSignal> connect;
Memory::CWeakPointer<Signal::CSignal> disconnect;
Memory::CWeakPointer<Signal::CSignal> forceDisconnect;
Memory::CWeakPointer<Signal::CSignal> lazyDisconnect;
} m_sEvents;
private:

View file

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

View file

@ -14,7 +14,8 @@ void CBaseAnimatedVariable::create(Hyprutils::Animation::CAnimationManager* pAni
m_pSelf = pSelf;
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;
}
@ -30,7 +31,7 @@ void CBaseAnimatedVariable::connectToActive() {
}
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));
m_bIsConnectedToActive = false;
@ -142,7 +143,9 @@ void CBaseAnimatedVariable::resetAllCallbacks() {
void CBaseAnimatedVariable::onAnimationEnd() {
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) {
/* 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_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.disconnect = m_sEvents.disconnect->registerListener([this](std::any data) { disconnectVarListener(data); });
m_sListeners.connect = m_sEvents.connect->registerListener([this](std::any data) { connectListener(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)
scheduleTick();
@ -32,9 +34,15 @@ void CAnimationManager::connectVarListener(std::any data) {
m_vActiveAnimatedVariables.emplace_back(PAV);
} 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 {
const auto PAV = std::any_cast<void*>(data);
if (!PAV)
@ -44,6 +52,10 @@ void CAnimationManager::disconnectVarListener(std::any data) {
} catch (const std::bad_any_cast&) { return; }
}
void CAnimationManager::lazyDisconnectListener(std::any data) {
m_pendingDisconnects++;
}
void CAnimationManager::removeAllBeziers() {
m_mBezierCurves.clear();
@ -67,6 +79,10 @@ bool CAnimationManager::shouldTickForNext() {
}
void CAnimationManager::tickDone() {
rotateActive();
}
void CAnimationManager::rotateActive() {
std::vector<CWeakPointer<CBaseAnimatedVariable>> active;
active.reserve(m_vActiveAnimatedVariables.size()); // avoid reallocations
for (auto const& av : m_vActiveAnimatedVariables) {
@ -81,6 +97,7 @@ void CAnimationManager::tickDone() {
}
m_vActiveAnimatedVariables = std::move(active);
m_pendingDisconnects = 0;
}
bool CAnimationManager::bezierExists(const std::string& bezier) {