diff --git a/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp b/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp index d2929f8..0af76fd 100644 --- a/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp +++ b/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp @@ -27,6 +27,11 @@ class ComponentAnimator::AnimationTask public: AnimationTask (Component* c) noexcept : component (c) {} + ~AnimationTask() + { + masterReference.clear(); + } + void reset (const Rectangle& finalBounds, float finalAlpha, int millisecondsToSpendMoving, @@ -71,6 +76,7 @@ public: if (newProgress >= 0 && newProgress < 1.0) { + const WeakReference weakRef (this); newProgress = timeToDistance (newProgress); const double delta = (newProgress - lastProgress) / (1.0 - lastProgress); jassert (newProgress >= lastProgress); @@ -99,6 +105,11 @@ public: } } + // The above call to setBounds may have cancelled the animation deleting + // the AnimationTask. If so, we need to bail out + if (weakRef.wasObjectDeleted()) + return false; + if (isChangingAlpha) { alpha += (destAlpha - alpha) * delta; @@ -169,6 +180,9 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProxyComponent) }; + WeakReference::Master masterReference; + friend class WeakReference; + WeakReference component; ScopedPointer proxy; @@ -312,12 +326,20 @@ void ComponentAnimator::timerCallback() const int elapsed = (int) (timeNow - lastTime); - for (int i = tasks.size(); --i >= 0;) + Array tasksToCheck (tasks.begin(), tasks.size()); + + for (int i = tasksToCheck.size(); --i >= 0;) { - if (! tasks.getUnchecked(i)->useTimeslice (elapsed)) + if (AnimationTask* task = tasksToCheck.getUnchecked (i)) { - tasks.remove (i); - sendChangeMessage(); + if (! tasks.contains (task)) + continue; + + if (! task->useTimeslice (elapsed)) + { + tasks.removeObject (task); + sendChangeMessage(); + } } }