src/corelib/animation/qabstractanimation.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
   159 #define DEFAULT_TIMER_INTERVAL 16
   159 #define DEFAULT_TIMER_INTERVAL 16
   160 #define STARTSTOP_TIMER_DELAY 0
   160 #define STARTSTOP_TIMER_DELAY 0
   161 
   161 
   162 QT_BEGIN_NAMESPACE
   162 QT_BEGIN_NAMESPACE
   163 
   163 
       
   164 #ifndef QT_NO_THREAD
   164 Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
   165 Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
       
   166 #endif
   165 
   167 
   166 QUnifiedTimer::QUnifiedTimer() :
   168 QUnifiedTimer::QUnifiedTimer() :
   167     QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
   169     QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
   168     currentAnimationIdx(0), consistentTiming(false), slowMode(false),
   170     currentAnimationIdx(0), consistentTiming(false), slowMode(false),
   169     isPauseTimerActive(false), runningLeafAnimations(0)
   171     isPauseTimerActive(false), runningLeafAnimations(0)
   170 {
   172 {
   171 }
   173     time.invalidate();
   172 
   174 }
   173 QUnifiedTimer *QUnifiedTimer::instance()
   175 
       
   176 
       
   177 QUnifiedTimer *QUnifiedTimer::instance(bool create)
   174 {
   178 {
   175     QUnifiedTimer *inst;
   179     QUnifiedTimer *inst;
   176     if (!unifiedTimer()->hasLocalData()) {
   180 #ifndef QT_NO_THREAD
       
   181     if (create && !unifiedTimer()->hasLocalData()) {
   177         inst = new QUnifiedTimer;
   182         inst = new QUnifiedTimer;
   178         unifiedTimer()->setLocalData(inst);
   183         unifiedTimer()->setLocalData(inst);
   179     } else {
   184     } else {
   180         inst = unifiedTimer()->localData();
   185         inst = unifiedTimer()->localData();
   181     }
   186     }
       
   187 #else
       
   188     static QUnifiedTimer unifiedTimer;
       
   189     inst = &unifiedTimer;
       
   190 #endif
   182     return inst;
   191     return inst;
   183 }
   192 }
   184 
   193 
       
   194 QUnifiedTimer *QUnifiedTimer::instance()
       
   195 {
       
   196     return instance(true);
       
   197 }
       
   198 
   185 void QUnifiedTimer::ensureTimerUpdate()
   199 void QUnifiedTimer::ensureTimerUpdate()
   186 {
   200 {
   187     if (isPauseTimerActive)
   201     QUnifiedTimer *inst = QUnifiedTimer::instance(false);
   188         updateAnimationsTime();
   202     if (inst && inst->isPauseTimerActive)
       
   203         inst->updateAnimationsTime();
   189 }
   204 }
   190 
   205 
   191 void QUnifiedTimer::updateAnimationsTime()
   206 void QUnifiedTimer::updateAnimationsTime()
   192 {
   207 {
   193     // ignore consistentTiming in case the pause timer is active
   208     // ignore consistentTiming in case the pause timer is active
   209         }
   224         }
   210         currentAnimationIdx = 0;
   225         currentAnimationIdx = 0;
   211     }
   226     }
   212 }
   227 }
   213 
   228 
       
   229 void QUnifiedTimer::updateAnimationTimer()
       
   230 {
       
   231     QUnifiedTimer *inst = QUnifiedTimer::instance(false);
       
   232     if (inst)
       
   233         inst->restartAnimationTimer();
       
   234 }
       
   235 
   214 void QUnifiedTimer::restartAnimationTimer()
   236 void QUnifiedTimer::restartAnimationTimer()
   215 {
   237 {
   216     if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) {
   238     if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) {
   217         int closestTimeToFinish = closestPauseAnimationTimeToFinish();
   239         int closestTimeToFinish = closestPauseAnimationTimeToFinish();
   218         if (closestTimeToFinish < 0) {
   240         if (closestTimeToFinish < 0) {
   240         animationsToStart.clear();
   262         animationsToStart.clear();
   241         if (animations.isEmpty()) {
   263         if (animations.isEmpty()) {
   242             animationTimer.stop();
   264             animationTimer.stop();
   243             isPauseTimerActive = false;
   265             isPauseTimerActive = false;
   244             // invalidate the start reference time
   266             // invalidate the start reference time
   245             time = QTime();
   267             time.invalidate();
   246         } else {
   268         } else {
   247             restartAnimationTimer();
   269             restartAnimationTimer();
   248             if (!time.isValid()) {
   270             if (!time.isValid()) {
   249                 lastTick = 0;
   271                 lastTick = 0;
   250                 time.start();
   272                 time.start();
   259     }
   281     }
   260 }
   282 }
   261 
   283 
   262 void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
   284 void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
   263 {
   285 {
   264     registerRunningAnimation(animation);
   286     QUnifiedTimer *inst = instance(true); //we create the instance if needed
       
   287     inst->registerRunningAnimation(animation);
   265     if (isTopLevel) {
   288     if (isTopLevel) {
   266         Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
   289         Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
   267         QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
   290         QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
   268         animationsToStart << animation;
   291         inst->animationsToStart << animation;
   269         if (!startStopAnimationTimer.isActive())
   292         if (!inst->startStopAnimationTimer.isActive())
   270             startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
   293             inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst);
   271     }
   294     }
   272 }
   295 }
   273 
   296 
   274 void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
   297 void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
   275 {
   298 {
   276     unregisterRunningAnimation(animation);
   299     QUnifiedTimer *inst = QUnifiedTimer::instance(false);
   277 
   300     if (inst) {
   278     if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
   301         //at this point the unified timer should have been created
   279         return;
   302         //but it might also have been already destroyed in case the application is shutting down
   280 
   303 
   281     int idx = animations.indexOf(animation);
   304         inst->unregisterRunningAnimation(animation);
   282     if (idx != -1) {
   305 
   283         animations.removeAt(idx);
   306         if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
   284         // this is needed if we unregister an animation while its running
   307             return;
   285         if (idx <= currentAnimationIdx)
   308 
   286             --currentAnimationIdx;
   309         int idx = inst->animations.indexOf(animation);
   287 
   310         if (idx != -1) {
   288         if (animations.isEmpty() && !startStopAnimationTimer.isActive())
   311             inst->animations.removeAt(idx);
   289             startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
   312             // this is needed if we unregister an animation while its running
   290     } else {
   313             if (idx <= inst->currentAnimationIdx)
   291         animationsToStart.removeOne(animation);
   314                 --inst->currentAnimationIdx;
       
   315 
       
   316             if (inst->animations.isEmpty() && !inst->startStopAnimationTimer.isActive())
       
   317                 inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst);
       
   318         } else {
       
   319             inst->animationsToStart.removeOne(animation);
       
   320         }
   292     }
   321     }
   293     QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
   322     QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
   294 }
   323 }
   295 
   324 
   296 void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation)
   325 void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation)
   336 
   365 
   337 void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
   366 void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
   338 {
   367 {
   339     Q_Q(QAbstractAnimation);
   368     Q_Q(QAbstractAnimation);
   340     if (state == newState)
   369     if (state == newState)
       
   370         return;
       
   371 
       
   372     if (loopCount == 0)
   341         return;
   373         return;
   342 
   374 
   343     QAbstractAnimation::State oldState = state;
   375     QAbstractAnimation::State oldState = state;
   344     int oldCurrentTime = currentTime;
   376     int oldCurrentTime = currentTime;
   345     int oldCurrentLoop = currentLoop;
   377     int oldCurrentLoop = currentLoop;
   361     //(un)registration of the animation must always happen before calls to
   393     //(un)registration of the animation must always happen before calls to
   362     //virtual function (updateState) to ensure a correct state of the timer
   394     //virtual function (updateState) to ensure a correct state of the timer
   363     bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
   395     bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
   364     if (oldState == QAbstractAnimation::Running) {
   396     if (oldState == QAbstractAnimation::Running) {
   365         if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
   397         if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
   366             QUnifiedTimer::instance()->ensureTimerUpdate();
   398             QUnifiedTimer::ensureTimerUpdate();
   367         //the animation, is not running any more
   399         //the animation, is not running any more
   368         QUnifiedTimer::instance()->unregisterAnimation(q);
   400         QUnifiedTimer::unregisterAnimation(q);
   369     } else if (newState == QAbstractAnimation::Running) {
   401     } else if (newState == QAbstractAnimation::Running) {
   370         QUnifiedTimer::instance()->registerAnimation(q, isTopLevel);
   402         QUnifiedTimer::registerAnimation(q, isTopLevel);
   371     }
   403     }
   372 
   404 
   373     q->updateState(newState, oldState);
   405     q->updateState(newState, oldState);
   374     if (!guard || newState != state) //this is to be safe if updateState changes the state
   406     if (!guard || newState != state) //this is to be safe if updateState changes the state
   375         return;
   407         return;
   387 
   419 
   388             // this ensures that the value is updated now that the animation is running
   420             // this ensures that the value is updated now that the animation is running
   389             if (oldState == QAbstractAnimation::Stopped) {
   421             if (oldState == QAbstractAnimation::Stopped) {
   390                 if (isTopLevel) {
   422                 if (isTopLevel) {
   391                     // currentTime needs to be updated if pauseTimer is active
   423                     // currentTime needs to be updated if pauseTimer is active
   392                     QUnifiedTimer::instance()->ensureTimerUpdate();
   424                     QUnifiedTimer::ensureTimerUpdate();
   393                     q->setCurrentTime(totalCurrentTime);
   425                     q->setCurrentTime(totalCurrentTime);
   394                 }
   426                 }
   395             }
   427             }
   396         }
   428         }
   397         break;
   429         break;
   446     if (d->state != Stopped) {
   478     if (d->state != Stopped) {
   447         QAbstractAnimation::State oldState = d->state;
   479         QAbstractAnimation::State oldState = d->state;
   448         d->state = Stopped;
   480         d->state = Stopped;
   449         emit stateChanged(oldState, d->state);
   481         emit stateChanged(oldState, d->state);
   450         if (oldState == QAbstractAnimation::Running)
   482         if (oldState == QAbstractAnimation::Running)
   451             QUnifiedTimer::instance()->unregisterAnimation(this);
   483             QUnifiedTimer::unregisterAnimation(this);
   452     }
   484     }
   453 }
   485 }
   454 
   486 
   455 /*!
   487 /*!
   456     \property QAbstractAnimation::state
   488     \property QAbstractAnimation::state
   545     }
   577     }
   546 
   578 
   547     // the commands order below is important: first we need to setCurrentTime with the old direction,
   579     // the commands order below is important: first we need to setCurrentTime with the old direction,
   548     // then update the direction on this and all children and finally restart the pauseTimer if needed
   580     // then update the direction on this and all children and finally restart the pauseTimer if needed
   549     if (d->hasRegisteredTimer)
   581     if (d->hasRegisteredTimer)
   550         QUnifiedTimer::instance()->ensureTimerUpdate();
   582         QUnifiedTimer::ensureTimerUpdate();
   551 
   583 
   552     d->direction = direction;
   584     d->direction = direction;
   553     updateDirection(direction);
   585     updateDirection(direction);
   554 
   586 
   555     if (d->hasRegisteredTimer)
   587     if (d->hasRegisteredTimer)
   556         // needed to update the timer interval in case of a pause animation
   588         // needed to update the timer interval in case of a pause animation
   557         QUnifiedTimer::instance()->restartAnimationTimer();
   589         QUnifiedTimer::updateAnimationTimer();
   558 
   590 
   559     emit directionChanged(direction);
   591     emit directionChanged(direction);
   560 }
   592 }
   561 
   593 
   562 /*!
   594 /*!