QUnifiedTimer::QUnifiedTimer() :
QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false),
+ startAnimationPending(false), stopTimerPending(false),
slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0), profilerCallback(0)
{
time.invalidate();
}
}
+void QUnifiedTimer::startAnimations()
+{
+ startAnimationPending = false;
+ //we transfer the waiting animations into the "really running" state
+ animations += animationsToStart;
+ animationsToStart.clear();
+ if (!animations.isEmpty()) {
+ restartAnimationTimer();
+ if (!time.isValid()) {
+ lastTick = 0;
+ time.start();
+ }
+ }
+}
+
+void QUnifiedTimer::stopTimer()
+{
+ stopTimerPending = false;
+ if (animations.isEmpty()) {
+ animationTimer.stop();
+ isPauseTimerActive = false;
+ // invalidate the start reference time
+ time.invalidate();
+ }
+}
void QUnifiedTimer::timerEvent(QTimerEvent *event)
{
//in the case of consistent timing we make sure the orders in which events come is always the same
- //for that purpose we do as if the startstoptimer would always fire before the animation timer
- if ((consistentTiming && startStopAnimationTimer.isActive()) ||
- event->timerId() == startStopAnimationTimer.timerId()) {
- startStopAnimationTimer.stop();
-
- //we transfer the waiting animations into the "really running" state
- animations += animationsToStart;
- animationsToStart.clear();
- if (animations.isEmpty()) {
- animationTimer.stop();
- isPauseTimerActive = false;
- // invalidate the start reference time
- time.invalidate();
- } else {
- restartAnimationTimer();
- if (!time.isValid()) {
- lastTick = 0;
- time.start();
- }
- }
+ //for that purpose we do as if the startstoptimer would always fire before the animation timer
+ if (consistentTiming) {
+ if (stopTimerPending)
+ stopTimer();
+ if (startAnimationPending)
+ startAnimations();
}
if (event->timerId() == animationTimer.timerId()) {
Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
inst->animationsToStart << animation;
- if (!inst->startStopAnimationTimer.isActive())
- inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst);
+ if (!inst->startAnimationPending) {
+ inst->startAnimationPending = true;
+ QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
+ }
}
}
if (idx <= inst->currentAnimationIdx)
--inst->currentAnimationIdx;
- if (inst->animations.isEmpty() && !inst->startStopAnimationTimer.isActive())
- inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst);
+ if (inst->animations.isEmpty() && !inst->stopTimerPending) {
+ inst->stopTimerPending = true;
+ QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
+ }
} else {
inst->animationsToStart.removeOne(animation);
}
void loopCount();
void state();
void totalDuration();
+ void avoidJumpAtStart();
+ void avoidJumpAtStartWithStop();
};
class TestableQAbstractAnimation : public QAbstractAnimation
Q_OBJECT
public:
+ TestableQAbstractAnimation() : m_duration(10) {}
virtual ~TestableQAbstractAnimation() {};
- int duration() const { return 10; }
+ int duration() const { return m_duration; }
virtual void updateCurrentTime(int) {}
+
+ void setDuration(int duration) { m_duration = duration; }
+private:
+ int m_duration;
};
class DummyQAnimationGroup : public QAnimationGroup
QCOMPARE(anim.totalDuration(), 50);
}
+void tst_QAbstractAnimation::avoidJumpAtStart()
+{
+ TestableQAbstractAnimation anim;
+ anim.setDuration(1000);
+
+ /*
+ the timer shouldn't actually start until we hit the event loop,
+ so the sleep should have no effect
+ */
+ anim.start();
+ QTest::qSleep(300);
+ QCoreApplication::processEvents();
+ QVERIFY(anim.currentTime() < 50);
+}
+
+void tst_QAbstractAnimation::avoidJumpAtStartWithStop()
+{
+ TestableQAbstractAnimation anim;
+ anim.setDuration(1000);
+
+ TestableQAbstractAnimation anim2;
+ anim2.setDuration(1000);
+
+ anim.start();
+ QTest::qWait(300);
+ anim.stop();
+
+ /*
+ same test as avoidJumpAtStart, but after there is a
+ running animation that is stopped
+ */
+ anim2.start();
+ QTest::qSleep(300);
+ QCoreApplication::processEvents();
+ QVERIFY(anim2.currentTime() < 50);
+}
+
QTEST_MAIN(tst_QAbstractAnimation)
#include "tst_qabstractanimation.moc"