animation: forceDisconnect outside of tick() and remove the pointer to the animation manager

This commit is contained in:
Maximilian Seidler 2025-01-26 13:29:42 +01:00
parent 60dbdc46cc
commit 1e0392e711
5 changed files with 58 additions and 56 deletions

View file

@ -27,7 +27,7 @@ namespace Hyprutils {
; // m_bDummy = true; ; // m_bDummy = true;
}; };
void create(CAnimationManager*, int, Memory::CSharedPointer<CBaseAnimatedVariable>); void create(int, Memory::CSharedPointer<CBaseAnimatedVariable>, Memory::CSharedPointer<SAnimVarEvents> events);
void connectToActive(); void connectToActive();
void disconnectFromActive(); void disconnectFromActive();
@ -36,7 +36,7 @@ namespace Hyprutils {
disconnectFromActive(); disconnectFromActive();
}; };
virtual void warp(bool endCallback = true) = 0; virtual void warp(bool endCallback = true, bool forceDisconnect = true) = 0;
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete; CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete; CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
@ -58,8 +58,9 @@ namespace Hyprutils {
/* returns the spent (completion) % */ /* returns the spent (completion) % */
float getPercent() const; float getPercent() const;
/* returns the current curve value */ /* returns the current curve value.
float getCurveValue() const; needs a reference to the animationmgr to get the bezier curve with the configured name from it */
float getCurveValue(CAnimationManager*) const;
/* checks if an animation is in progress */ /* checks if an animation is in progress */
bool isBeingAnimated() const { bool isBeingAnimated() const {
@ -100,6 +101,8 @@ namespace Hyprutils {
Memory::CWeakPointer<CBaseAnimatedVariable> m_pSelf; Memory::CWeakPointer<CBaseAnimatedVariable> m_pSelf;
Memory::CWeakPointer<SAnimVarEvents> m_events;
private: private:
Memory::CWeakPointer<SAnimationPropertyConfig> m_pConfig; Memory::CWeakPointer<SAnimationPropertyConfig> m_pConfig;
@ -107,18 +110,12 @@ namespace Hyprutils {
bool m_bDummy = true; bool m_bDummy = true;
// TODO: remove this pointer. We still need it for getBezier in getCurveValue. bool m_bRemoveEndAfterRan = true;
// getCurveValue is only used once in Hyprland. So either remove it or just pass pAnimationManager as a param. bool m_bRemoveBeginAfterRan = true;
CAnimationManager* m_pAnimationManager = nullptr;
Memory::CWeakPointer<SAnimVarEvents> m_events; CallbackFun m_fEndCallback;
CallbackFun m_fBeginCallback;
bool m_bRemoveEndAfterRan = true; CallbackFun m_fUpdateCallback;
bool m_bRemoveBeginAfterRan = true;
CallbackFun m_fEndCallback;
CallbackFun m_fBeginCallback;
CallbackFun m_fUpdateCallback;
}; };
/* This concept represents the minimum requirement for a type to be used with CGenericAnimatedVariable */ /* This concept represents the minimum requirement for a type to be used with CGenericAnimatedVariable */
@ -140,13 +137,13 @@ namespace Hyprutils {
public: public:
CGenericAnimatedVariable() = default; CGenericAnimatedVariable() = default;
void create(const int typeInfo, CAnimationManager* pAnimationManager, Memory::CSharedPointer<CGenericAnimatedVariable<VarType, AnimationContext>> pSelf, void create(const int typeInfo, Memory::CSharedPointer<CGenericAnimatedVariable<VarType, AnimationContext>> pSelf, Memory::CSharedPointer<SAnimVarEvents> events,
const VarType& initialValue) { const VarType& initialValue) {
m_Begun = initialValue; m_Begun = initialValue;
m_Value = initialValue; m_Value = initialValue;
m_Goal = initialValue; m_Goal = initialValue;
CBaseAnimatedVariable::create(pAnimationManager, typeInfo, pSelf); CBaseAnimatedVariable::create(typeInfo, pSelf, events);
} }
CGenericAnimatedVariable(const CGenericAnimatedVariable&) = delete; CGenericAnimatedVariable(const CGenericAnimatedVariable&) = delete;
@ -154,7 +151,7 @@ namespace Hyprutils {
CGenericAnimatedVariable& operator=(const CGenericAnimatedVariable&) = delete; CGenericAnimatedVariable& operator=(const CGenericAnimatedVariable&) = delete;
CGenericAnimatedVariable& operator=(CGenericAnimatedVariable&&) = delete; CGenericAnimatedVariable& operator=(CGenericAnimatedVariable&&) = delete;
virtual void warp(bool endCallback = true) { virtual void warp(bool endCallback = true, bool forceDisconnect = true) {
if (!m_bIsBeingAnimated) if (!m_bIsBeingAnimated)
return; return;
@ -166,6 +163,11 @@ namespace Hyprutils {
if (endCallback) if (endCallback)
onAnimationEnd(); onAnimationEnd();
if (forceDisconnect) {
if (const auto PEVENTS = m_events.lock())
PEVENTS->forceDisconnect.emit(static_cast<void*>(this));
}
} }
const VarType& value() const { const VarType& value() const {

View file

@ -33,26 +33,24 @@ namespace Hyprutils {
const std::unordered_map<std::string, Memory::CSharedPointer<CBezierCurve>>& getAllBeziers(); const std::unordered_map<std::string, Memory::CSharedPointer<CBezierCurve>>& getAllBeziers();
Memory::CSharedPointer<SAnimVarEvents> getEvents() const;
std::vector<Memory::CWeakPointer<CBaseAnimatedVariable>> m_vActiveAnimatedVariables; std::vector<Memory::CWeakPointer<CBaseAnimatedVariable>> m_vActiveAnimatedVariables;
Memory::CSharedPointer<SAnimVarEvents> m_events;
private: private:
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;
void connectListener(std::any data); void connectListener(std::any data);
void lazyDisconnectListener(std::any data);
void forceDisconnectListener(std::any data); void forceDisconnectListener(std::any data);
struct { struct {
Signal::CHyprSignalListener connect; Signal::CHyprSignalListener connect;
Signal::CHyprSignalListener forceDisconnect; Signal::CHyprSignalListener forceDisconnect;
Signal::CHyprSignalListener lazyDisconnect;
} m_sListeners; } m_sListeners;
Memory::CSharedPointer<SAnimVarEvents> m_events;
friend class CBaseAnimatedVariable; friend class CBaseAnimatedVariable;
}; };
} }

View file

@ -8,13 +8,11 @@ using namespace Hyprutils::Memory;
#define SP CSharedPointer #define SP CSharedPointer
#define WP CWeakPointer #define WP CWeakPointer
void CBaseAnimatedVariable::create(Hyprutils::Animation::CAnimationManager* pAnimationManager, int typeInfo, SP<CBaseAnimatedVariable> pSelf) { void CBaseAnimatedVariable::create(int typeInfo, SP<CBaseAnimatedVariable> pSelf, SP<SAnimVarEvents> events) {
m_pAnimationManager = pAnimationManager; m_Type = typeInfo;
m_Type = typeInfo; m_pSelf = pSelf;
m_pSelf = pSelf;
m_events = pAnimationManager->m_events;
m_events = events;
m_bDummy = false; m_bDummy = false;
} }
@ -77,16 +75,10 @@ float CBaseAnimatedVariable::getPercent() const {
return 1.f; return 1.f;
} }
float CBaseAnimatedVariable::getCurveValue() const { float CBaseAnimatedVariable::getCurveValue(CAnimationManager* pAnimationManager) const {
if (!m_bIsBeingAnimated || !m_pAnimationManager) if (!m_bIsBeingAnimated || !pAnimationManager)
return 1.f; return 1.f;
// Guard against m_pAnimationManager being deleted
// TODO: Remove this and m_pAnimationManager
if (m_events.expired()) {
return 1.f;
}
std::string bezierName = ""; std::string bezierName = "";
if (const auto PCONFIG = m_pConfig.lock()) { if (const auto PCONFIG = m_pConfig.lock()) {
const auto PVALUES = PCONFIG->pValues.lock(); const auto PVALUES = PCONFIG->pValues.lock();
@ -94,7 +86,7 @@ float CBaseAnimatedVariable::getCurveValue() const {
bezierName = PVALUES->internalBezier; bezierName = PVALUES->internalBezier;
} }
const auto BEZIER = m_pAnimationManager->getBezier(bezierName); const auto BEZIER = pAnimationManager->getBezier(bezierName);
if (!BEZIER) if (!BEZIER)
return 1.f; return 1.f;

View file

@ -18,7 +18,6 @@ CAnimationManager::CAnimationManager() {
m_sListeners.connect = m_events->connect.registerListener([this](std::any data) { connectListener(data); }); m_sListeners.connect = m_events->connect.registerListener([this](std::any data) { connectListener(data); });
m_sListeners.forceDisconnect = m_events->forceDisconnect.registerListener([this](std::any data) { forceDisconnectListener(data); }); m_sListeners.forceDisconnect = m_events->forceDisconnect.registerListener([this](std::any data) { forceDisconnectListener(data); });
m_sListeners.lazyDisconnect = m_events->lazyDisconnect.registerListener([this](std::any data) { lazyDisconnectListener(data); });
} }
void CAnimationManager::connectListener(std::any data) { void CAnimationManager::connectListener(std::any data) {
@ -32,12 +31,6 @@ void CAnimationManager::connectListener(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::forceDisconnectListener(std::any data) { void CAnimationManager::forceDisconnectListener(std::any data) {
@ -50,10 +43,6 @@ void CAnimationManager::forceDisconnectListener(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();
@ -95,7 +84,6 @@ void CAnimationManager::rotateActive() {
} }
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) {

View file

@ -54,7 +54,7 @@ class CMyAnimationManager : public CAnimationManager {
const auto PBEZIER = getBezier(PAV->getBezierName()); const auto PBEZIER = getBezier(PAV->getBezierName());
if (SPENT >= 1.f || !PAV->enabled()) { if (SPENT >= 1.f || !PAV->enabled()) {
PAV->warp(); PAV->warp(true, false);
continue; continue;
} }
@ -93,7 +93,7 @@ class CMyAnimationManager : public CAnimationManager {
constexpr const eAVTypes EAVTYPE = std::is_same_v<VarType, int> ? eAVTypes::INT : eAVTypes::TEST; constexpr const eAVTypes EAVTYPE = std::is_same_v<VarType, int> ? eAVTypes::INT : eAVTypes::TEST;
const auto PAV = makeShared<CGenericAnimatedVariable<VarType, EmtpyContext>>(); const auto PAV = makeShared<CGenericAnimatedVariable<VarType, EmtpyContext>>();
PAV->create(EAVTYPE, static_cast<CAnimationManager*>(this), PAV, v); PAV->create(EAVTYPE, PAV, m_events, v);
PAV->setConfig(animationTree.getConfig(animationConfigName)); PAV->setConfig(animationTree.getConfig(animationConfigName));
av = std::move(PAV); av = std::move(PAV);
} }
@ -326,6 +326,24 @@ int main(int argc, char** argv, char** envp) {
EXPECT(endCallbackRan, 4); EXPECT(endCallbackRan, 4);
EXPECT(s.m_iA->value(), 10); EXPECT(s.m_iA->value(), 10);
// test warp
*s.m_iA = 3;
s.m_iA->setCallbackOnEnd([&endCallbackRan](auto) { endCallbackRan++; }, false);
s.m_iA->warp(false);
EXPECT(endCallbackRan, 4);
*s.m_iA = 4;
s.m_iA->warp(true);
EXPECT(endCallbackRan, 5);
// test getCurveValue
*s.m_iA = 0;
EXPECT(s.m_iA->getCurveValue(pAnimationManager.get()), 0.f);
s.m_iA->warp();
EXPECT(s.m_iA->getCurveValue(pAnimationManager.get()), 1.f);
EXPECT(endCallbackRan, 6);
// Test duplicate active anim vars are not allowed // Test duplicate active anim vars are not allowed
{ {
EXPECT(pAnimationManager->m_vActiveAnimatedVariables.size(), 0); EXPECT(pAnimationManager->m_vActiveAnimatedVariables.size(), 0);
@ -337,7 +355,6 @@ int main(int argc, char** argv, char** envp) {
*a = 20; *a = 20;
EXPECT(pAnimationManager->m_vActiveAnimatedVariables.size(), 1); EXPECT(pAnimationManager->m_vActiveAnimatedVariables.size(), 1);
a->warp(); a->warp();
pAnimationManager->tick(); // trigger cleanup
EXPECT(pAnimationManager->m_vActiveAnimatedVariables.size(), 0); EXPECT(pAnimationManager->m_vActiveAnimatedVariables.size(), 0);
EXPECT(a->value(), 20); EXPECT(a->value(), 20);
} }
@ -348,10 +365,15 @@ int main(int argc, char** argv, char** envp) {
pAnimationManager->createAnimation(1, a, "default"); pAnimationManager->createAnimation(1, a, "default");
*a = 10; *a = 10;
pAnimationManager.reset(); pAnimationManager.reset();
} a->setValueAndWarp(11);
EXPECT(a->value(), 11);
*a = 12;
a->warp();
EXPECT(a->value(), 12);
*a = 13;
} // a gets destroyed
EXPECT(pAnimationManager.get(), nullptr); EXPECT(pAnimationManager.get(), nullptr);
*s.m_iA = 10;
return ret; return ret;
} }