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 /*! |