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
This commit is contained in:
Aaron J. Seigo 2009-06-09 03:37:22 +00:00
parent 8a4dc5460d
commit 74a6212595

View File

@ -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<QGraphicsItem*, QList<QTimeLine*> >
// and really making the code fun ;)
QMap<QGraphicsItem*, AnimationState*> animatedItems;
QMap<QGraphicsItem*, MovementState*> movingItems;
QMap<int, ElementAnimationState*> animatedElements;
QMap<int, CustomAnimationState*> customAnims;
// active items
QMap<QGraphicsItem *, AnimationState *> animatedItems;
QMap<QGraphicsItem *, MovementState *> movingItems;
QMap<int, ElementAnimationState *> animatedElements;
QMap<int, CustomAnimationState *> customAnims;
// items to cull
QList<AnimationState *> animatedItemsToDelete;
QList<MovementState *> movingItemsToDelete;
QList<ElementAnimationState *> animatedElementsToDelete;
QList<CustomAnimationState *> 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<int, CustomAnimationState*> 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<QGraphicsItem*, AnimationState*>::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<QGraphicsItem*, MovementState*>::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<int, CustomAnimationState*>::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<int, ElementAnimationState*>::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<CustomAnimationState*> it(customAnimsToDelete);
while (it.hasNext()) {
CustomAnimationState *state = it.next();
delete[] state->slot;
delete state;
}
customAnimsToDelete.clear();
}
} // namespace Plasma
#include <animator.moc>