From 74a62125958af1ba93501c2db6b5a144597c383f Mon Sep 17 00:00:00 2001 From: "Aaron J. Seigo" Date: Tue, 9 Jun 2009 03:37:22 +0000 Subject: [PATCH] don't delete states when we're running animations: we call into other objects which may decide to stop or start other animations, which would cause double deletes. this one's bugged me (and our users; it's bee reported at least 18 times!) for a good long while, and finally tonight i figured it out :) BUG:192066 svn path=/trunk/KDE/kdelibs/; revision=979139 --- animator.cpp | 133 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 27 deletions(-) diff --git a/animator.cpp b/animator.cpp index a04da902f..3bbcac3ea 100644 --- a/animator.cpp +++ b/animator.cpp @@ -106,6 +106,7 @@ class AnimatorPrivate ~AnimatorPrivate() { + cleanupStates(); qDeleteAll(animatedItems); qDeleteAll(animatedElements); qDeleteAll(movingItems); @@ -168,7 +169,9 @@ class AnimatorPrivate } } + void init(Animator *q); + void cleanupStates(); void animatedItemDestroyed(QObject*); void movingItemDestroyed(QObject*); void animatedElementDestroyed(QObject*); @@ -180,13 +183,17 @@ class AnimatorPrivate QTime time; QTimeLine timeline; - //TODO: eventually perhaps we should allow multiple animations simulataneously - // which would imply changing this to a QMap > - // and really making the code fun ;) - QMap animatedItems; - QMap movingItems; - QMap animatedElements; - QMap customAnims; + // active items + QMap animatedItems; + QMap movingItems; + QMap animatedElements; + QMap customAnims; + + // items to cull + QList animatedItemsToDelete; + QList movingItemsToDelete; + QList animatedElementsToDelete; + QList customAnimsToDelete; }; class AnimatorSingleton @@ -223,7 +230,12 @@ void AnimatorPrivate::animatedItemDestroyed(QObject *o) //kDebug() << "comparing against" << it.value()->qobj; if (it.value()->qobj == o) { kDebug() << "found deleted animated item"; - delete it.value(); + if (timerId) { + animatedItemsToDelete.append(it.value()); + } else { + delete it.value(); + } + it.remove(); } } @@ -235,7 +247,12 @@ void AnimatorPrivate::movingItemDestroyed(QObject *o) while (it.hasNext()) { it.next(); if (it.value()->qobj == o) { - delete it.value(); + if (timerId) { + movingItemsToDelete.append(it.value()); + } else { + delete it.value(); + } + it.remove(); } } @@ -247,7 +264,12 @@ void AnimatorPrivate::animatedElementDestroyed(QObject *o) while (it.hasNext()) { it.next(); if (it.value()->qobj == o) { - delete it.value(); + if (timerId) { + animatedElementsToDelete.append(it.value()); + } else { + delete it.value(); + } + it.remove(); } } @@ -258,8 +280,13 @@ void AnimatorPrivate::customAnimReceiverDestroyed(QObject *o) QMutableMapIterator it(customAnims); while (it.hasNext()) { if (it.next().value()->receiver == o) { - delete[] it.value()->slot; - delete it.value(); + if (timerId) { + customAnimsToDelete.append(it.value()); + } else { + delete[] it.value()->slot; + delete it.value(); + } + it.remove(); } } @@ -272,7 +299,12 @@ int Animator::animateItem(QGraphicsItem *item, Animation animation) //TODO: shoudl we allow multiple anims per item? QMap::iterator it = d->animatedItems.find(item); if (it != d->animatedItems.end()) { - delete it.value(); + if (d->timerId) { + d->animatedItemsToDelete.append(it.value()); + } else { + delete it.value(); + } + d->animatedItems.erase(it); } @@ -322,8 +354,12 @@ int Animator::moveItem(QGraphicsItem *item, Movement movement, const QPoint &des //kDebug(); QMap::iterator it = d->movingItems.find(item); if (it != d->movingItems.end()) { - delete it.value(); - d->movingItems.erase(it); + if (d->timerId) { + d->movingItemsToDelete.append(it.value()); + } else { + delete it.value(); + d->movingItems.erase(it); + } } int frames = d->driver->movementAnimationFps(movement); @@ -410,8 +446,13 @@ void Animator::stopCustomAnimation(int id) { QMap::iterator it = d->customAnims.find(id); if (it != d->customAnims.end()) { - delete [] it.value()->slot; - delete it.value(); + if (d->timerId) { + d->customAnimsToDelete.append(it.value()); + } else { + delete [] it.value()->slot; + delete it.value(); + } + d->customAnims.erase(it); } //kDebug() << "stopCustomAnimation(AnimId " << id << ") done"; @@ -423,8 +464,13 @@ void Animator::stopItemAnimation(int id) while (it.hasNext()) { it.next(); if (it.value()->id == id) { - delete it.value(); - it.remove(); + if (d->timerId) { + d->animatedItemsToDelete.append(it.value()); + } else { + delete it.value(); + it.remove(); + } + return; } } @@ -436,8 +482,13 @@ void Animator::stopItemMovement(int id) while (it.hasNext()) { it.next(); if (it.value()->id == id) { - delete it.value(); - it.remove(); + if (d->timerId) { + d->movingItemsToDelete.append(it.value()); + } else { + delete it.value(); + it.remove(); + } + return; } } @@ -493,7 +544,12 @@ void Animator::stopElementAnimation(int id) { QMap::iterator it = d->animatedElements.find(id); if (it != d->animatedElements.end()) { - delete it.value(); + if (d->timerId) { + d->animatedElementsToDelete.append(it.value()); + } else { + delete it.value(); + } + d->animatedElements.erase(it); } //kDebug() << "stopElementAnimation(AnimId " << id << ") done"; @@ -582,7 +638,7 @@ void Animator::timerEvent(QTimerEvent *event) d->performAnimation(1, state); d->animatedItems.erase(d->animatedItems.find(state->item)); emit animationFinished(state->item, state->animation); - delete state; + d->animatedItemsToDelete.append(state); } } else { state->currentInterval -= elapsed; @@ -609,7 +665,7 @@ void Animator::timerEvent(QTimerEvent *event) d->performMovement(1, state); d->movingItems.erase(d->movingItems.find(state->item)); emit movementFinished(state->item); - delete state; + d->movingItemsToDelete.append(state); } } else { state->currentInterval -= elapsed; @@ -645,7 +701,7 @@ void Animator::timerEvent(QTimerEvent *event) } else { d->animatedElements.remove(state->id); emit elementAnimationFinished(state->id); - delete state; + d->animatedElementsToDelete.append(state); } } else { state->currentInterval -= elapsed; @@ -685,8 +741,7 @@ void Animator::timerEvent(QTimerEvent *event) } d->customAnims.erase(d->customAnims.find(state->id)); emit customAnimationFinished(state->id); - delete [] state->slot; - delete state; + d->customAnimsToDelete.append(state); } } else { state->currentInterval -= elapsed; @@ -698,6 +753,8 @@ void Animator::timerEvent(QTimerEvent *event) killTimer(d->timerId); d->timerId = 0; } + + d->cleanupStates(); } void AnimatorPrivate::init(Animator *q) @@ -732,6 +789,28 @@ void AnimatorPrivate::init(Animator *q) } } +void AnimatorPrivate::cleanupStates() +{ + /* + kDebug() << animatedItemsToDelete.count() << animatedElementsToDelete.count() + << movingItemsToDelete.count() << customAnimsToDelete.count(); + */ + qDeleteAll(animatedItemsToDelete); + animatedItemsToDelete.clear(); + qDeleteAll(animatedElementsToDelete); + animatedElementsToDelete.clear(); + qDeleteAll(movingItemsToDelete); + movingItemsToDelete.clear(); + + QListIterator it(customAnimsToDelete); + while (it.hasNext()) { + CustomAnimationState *state = it.next(); + delete[] state->slot; + delete state; + } + customAnimsToDelete.clear(); +} + } // namespace Plasma #include