1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // Copyright (C) 2016 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #include "qtimer.h" |
6 | #include "qtimer_p.h" |
7 | #include "qsingleshottimer_p.h" |
8 | |
9 | #include "qabstracteventdispatcher.h" |
10 | #include "qcoreapplication.h" |
11 | #include "qcoreapplication_p.h" |
12 | #include "qdeadlinetimer.h" |
13 | #include "qmetaobject_p.h" |
14 | #include "qobject_p.h" |
15 | #include "qproperty_p.h" |
16 | #include "qthread.h" |
17 | |
18 | using namespace std::chrono_literals; |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | QTimerPrivate::~QTimerPrivate() |
23 | = default; |
24 | |
25 | /*! |
26 | \class QTimer |
27 | \inmodule QtCore |
28 | \brief The QTimer class provides repetitive and single-shot timers. |
29 | |
30 | \ingroup events |
31 | |
32 | |
33 | The QTimer class provides a high-level programming interface for |
34 | timers. To use it, create a QTimer, connect its timeout() signal |
35 | to the appropriate slots, and call start(). From then on, it will |
36 | emit the timeout() signal at constant intervals. |
37 | |
38 | Example for a one second (1000 millisecond) timer (from the |
39 | \l{widgets/analogclock}{Analog Clock} example): |
40 | |
41 | \snippet ../widgets/widgets/analogclock/analogclock.cpp 4 |
42 | \snippet ../widgets/widgets/analogclock/analogclock.cpp 5 |
43 | \snippet ../widgets/widgets/analogclock/analogclock.cpp 6 |
44 | |
45 | From then on, the \c update() slot is called every second. |
46 | |
47 | You can set a timer to time out only once by calling |
48 | setSingleShot(true). You can also use the static |
49 | QTimer::singleShot() function to call a slot after a specified |
50 | interval: |
51 | |
52 | \snippet timers/timers.cpp 3 |
53 | |
54 | In multithreaded applications, you can use QTimer in any thread |
55 | that has an event loop. To start an event loop from a non-GUI |
56 | thread, use QThread::exec(). Qt uses the timer's |
57 | \l{QObject::thread()}{thread affinity} to determine which thread |
58 | will emit the \l{QTimer::}{timeout()} signal. Because of this, you |
59 | must start and stop the timer in its thread; it is not possible to |
60 | start a timer from another thread. |
61 | |
62 | As a special case, a QTimer with a timeout of 0 will time out as soon as |
63 | possible, though the ordering between zero timers and other sources of |
64 | events is unspecified. Zero timers can be used to do some work while still |
65 | providing a snappy user interface: |
66 | |
67 | \snippet timers/timers.cpp 4 |
68 | \snippet timers/timers.cpp 5 |
69 | \snippet timers/timers.cpp 6 |
70 | |
71 | From then on, \c processOneThing() will be called repeatedly. It |
72 | should be written in such a way that it always returns quickly |
73 | (typically after processing one data item) so that Qt can deliver |
74 | events to the user interface and stop the timer as soon as it has done all |
75 | its work. This is the traditional way of implementing heavy work |
76 | in GUI applications, but as multithreading is nowadays becoming available on |
77 | more and more platforms, we expect that zero-millisecond |
78 | QTimer objects will gradually be replaced by \l{QThread}s. |
79 | |
80 | \section1 Accuracy and Timer Resolution |
81 | |
82 | The accuracy of timers depends on the underlying operating system |
83 | and hardware. Most platforms support a resolution of 1 millisecond, |
84 | though the accuracy of the timer will not equal this resolution |
85 | in many real-world situations. |
86 | |
87 | The accuracy also depends on the \l{Qt::TimerType}{timer type}. For |
88 | Qt::PreciseTimer, QTimer will try to keep the accuracy at 1 millisecond. |
89 | Precise timers will also never time out earlier than expected. |
90 | |
91 | For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up |
92 | earlier than expected, within the margins for those types: 5% of the |
93 | interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer. |
94 | |
95 | All timer types may time out later than expected if the system is busy or |
96 | unable to provide the requested accuracy. In such a case of timeout |
97 | overrun, Qt will emit timeout() only once, even if multiple timeouts have |
98 | expired, and then will resume the original interval. |
99 | |
100 | \section1 Alternatives to QTimer |
101 | |
102 | Qt 6.8 introduced QChronoTimer. The main difference between the two |
103 | classes, is that QChronoTimer supports a larger interval range and a |
104 | higher precision (\c std::chrono::nanoseconds). For QTimer the maximum |
105 | supported interval is ±24 days, whereas for QChronoTimer it is ±292 |
106 | years (less chances of interger overflow with intervals longer than |
107 | \c std::numeric_limits<int>::max()). If you only need millisecond |
108 | resolution and ±24 days range, you can continue to use QTimer. |
109 | |
110 | \include timers-common.qdocinc q-chrono-timer-alternatives |
111 | |
112 | Some operating systems limit the number of timers that may be |
113 | used; Qt tries to work around these limitations. |
114 | |
115 | \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers, |
116 | {Analog Clock} |
117 | */ |
118 | |
119 | /*! |
120 | Constructs a timer with the given \a parent. |
121 | */ |
122 | |
123 | QTimer::QTimer(QObject *parent) |
124 | : QObject(*new QTimerPrivate(this), parent) |
125 | { |
126 | Q_ASSERT(d_func()->isQTimer); |
127 | } |
128 | |
129 | |
130 | /*! |
131 | Destroys the timer. |
132 | */ |
133 | |
134 | QTimer::~QTimer() |
135 | { |
136 | if (d_func()->isActive()) // stop running timer |
137 | stop(); |
138 | } |
139 | |
140 | |
141 | /*! |
142 | \fn void QTimer::timeout() |
143 | |
144 | This signal is emitted when the timer times out. |
145 | |
146 | \sa interval, start(), stop() |
147 | */ |
148 | |
149 | /*! |
150 | \property QTimer::active |
151 | \since 4.3 |
152 | |
153 | This boolean property is \c true if the timer is running; otherwise |
154 | false. |
155 | */ |
156 | |
157 | /*! |
158 | \fn bool QTimer::isActive() const |
159 | |
160 | Returns \c true if the timer is running; otherwise returns \c false. |
161 | */ |
162 | bool QTimer::isActive() const |
163 | { |
164 | return d_func()->isActiveData.value(); |
165 | } |
166 | |
167 | QBindable<bool> QTimer::bindableActive() |
168 | { |
169 | return QBindable<bool>(&d_func()->isActiveData); |
170 | } |
171 | |
172 | /*! |
173 | \fn int QTimer::timerId() const |
174 | |
175 | Returns the ID of the timer if the timer is running; otherwise returns |
176 | -1. |
177 | */ |
178 | int QTimer::timerId() const |
179 | { |
180 | auto v = qToUnderlying(e: id()); |
181 | return v == 0 ? -1 : v; |
182 | } |
183 | |
184 | /*! |
185 | \since 6.8 |
186 | Returns a Qt::TimerId representing the timer ID if the timer is running; |
187 | otherwise returns \c Qt::TimerId::Invalid. |
188 | |
189 | \sa Qt::TimerId |
190 | */ |
191 | Qt::TimerId QTimer::id() const |
192 | { |
193 | return d_func()->id; |
194 | } |
195 | |
196 | /*! \overload start() |
197 | |
198 | Starts or restarts the timer with the timeout specified in \l interval. |
199 | |
200 | //! [stop-restart-timer] |
201 | If the timer is already running, it will be |
202 | \l{QTimer::stop()}{stopped} and restarted. This will also change its id(). |
203 | //! [stop-restart-timer] |
204 | |
205 | //! [singleshot-activation] |
206 | If \l singleShot is true, the timer will be activated only once. |
207 | //! [singleshot-activation] |
208 | */ |
209 | void QTimer::start() |
210 | { |
211 | Q_D(QTimer); |
212 | if (d->isActive()) // stop running timer |
213 | stop(); |
214 | |
215 | Qt::TimerId newId{ QObject::startTimer(time: d->inter * 1ms, timerType: d->type) }; // overflow impossible |
216 | if (newId > Qt::TimerId::Invalid) { |
217 | d->id = newId; |
218 | d->isActiveData.notify(); |
219 | } |
220 | } |
221 | |
222 | /*! |
223 | Starts or restarts the timer with a timeout interval of \a msec |
224 | milliseconds. |
225 | |
226 | \include qtimer.cpp stop-restart-timer |
227 | |
228 | \include qtimer.cpp singleshot-activation |
229 | This is equivalent to: |
230 | |
231 | \code |
232 | timer.setInterval(msec); |
233 | timer.start(); |
234 | \endcode |
235 | |
236 | \note Keeping the event loop busy with a zero-timer is bound to |
237 | cause trouble and highly erratic behavior of the UI. |
238 | */ |
239 | void QTimer::start(int msec) |
240 | { |
241 | start(value: msec * 1ms); |
242 | } |
243 | |
244 | void QTimer::start(std::chrono::milliseconds interval) |
245 | { |
246 | Q_D(QTimer); |
247 | // This could be narrowing as the interval is stored in an `int` QProperty, |
248 | // and the type can't be changed in Qt6. |
249 | const int msec = interval.count(); |
250 | const bool intervalChanged = msec != d->inter; |
251 | d->inter.setValue(msec); |
252 | start(); |
253 | if (intervalChanged) |
254 | d->inter.notify(); |
255 | } |
256 | |
257 | |
258 | |
259 | /*! |
260 | Stops the timer. |
261 | |
262 | \sa start() |
263 | */ |
264 | |
265 | void QTimer::stop() |
266 | { |
267 | Q_D(QTimer); |
268 | if (d->isActive()) { |
269 | QObject::killTimer(id: d->id); |
270 | d->id = Qt::TimerId::Invalid; |
271 | d->isActiveData.notify(); |
272 | } |
273 | } |
274 | |
275 | |
276 | /*! |
277 | \reimp |
278 | */ |
279 | void QTimer::timerEvent(QTimerEvent *e) |
280 | { |
281 | Q_D(QTimer); |
282 | if (Qt::TimerId{e->timerId()} == d->id) { |
283 | if (d->single) |
284 | stop(); |
285 | emit timeout(QPrivateSignal()); |
286 | } |
287 | } |
288 | |
289 | QAbstractEventDispatcher::Duration // statically asserts that Duration is nanoseconds |
290 | QTimer::from_msecs(std::chrono::milliseconds ms) |
291 | { |
292 | using Duration = QAbstractEventDispatcher::Duration; |
293 | |
294 | using namespace std::chrono; |
295 | using ratio = std::ratio_divide<std::milli, Duration::period>; |
296 | static_assert(ratio::den == 1); |
297 | |
298 | Duration::rep r; |
299 | if (qMulOverflow<ratio::num>(v1: ms.count(), r: &r)) { |
300 | qWarning(msg: "QTimer::singleShot(std::chrono::milliseconds, ...): " |
301 | "interval argument overflowed when converted to nanoseconds." ); |
302 | return Duration::max(); |
303 | } |
304 | return Duration{r}; |
305 | } |
306 | |
307 | /*! |
308 | \internal |
309 | |
310 | Implementation of the template version of singleShot |
311 | |
312 | \a msec is the timer interval |
313 | \a timerType is the timer type |
314 | \a receiver is the receiver object, can be null. In such a case, it will be the same |
315 | as the final sender class. |
316 | \a slotObj the slot object |
317 | */ |
318 | void QTimer::singleShotImpl(std::chrono::nanoseconds ns, Qt::TimerType timerType, |
319 | const QObject *receiver, |
320 | QtPrivate::QSlotObjectBase *slotObj) |
321 | { |
322 | if (ns == 0ns) { |
323 | bool deleteReceiver = false; |
324 | // Optimize: set a receiver context when none is given, such that we can use |
325 | // QMetaObject::invokeMethod which is more efficient than going through a timer. |
326 | // We need a QObject living in the current thread. But the QThread itself lives |
327 | // in a different thread - with the exception of the main QThread which lives in |
328 | // itself. And QThread::currentThread() is among the few QObjects we know that will |
329 | // most certainly be there. Note that one can actually call singleShot before the |
330 | // QApplication is created! |
331 | if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) { |
332 | // reuse main thread as context object |
333 | receiver = QThread::currentThread(); |
334 | } else if (!receiver) { |
335 | // Create a receiver context object on-demand. According to the benchmarks, |
336 | // this is still more efficient than going through a timer. |
337 | receiver = new QObject; |
338 | deleteReceiver = true; |
339 | } |
340 | |
341 | auto h = QtPrivate::invokeMethodHelper(r: {}); |
342 | QMetaObject::invokeMethodImpl(object: const_cast<QObject *>(receiver), slotObj, |
343 | type: Qt::QueuedConnection, parameterCount: h.parameterCount(), params: h.parameters.data(), names: h.typeNames.data(), |
344 | metaTypes: h.metaTypes.data()); |
345 | |
346 | if (deleteReceiver) |
347 | const_cast<QObject *>(receiver)->deleteLater(); |
348 | return; |
349 | } |
350 | |
351 | (void) new QSingleShotTimer(ns, timerType, receiver, slotObj); |
352 | } |
353 | |
354 | /*! |
355 | \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member) |
356 | \reentrant |
357 | \deprecated [6.8] Use the chrono overloads. |
358 | This static function calls a slot after a given time interval. |
359 | |
360 | It is very convenient to use this function because you do not need |
361 | to bother with a \l{QObject::timerEvent()}{timerEvent} or |
362 | create a local QTimer object. |
363 | |
364 | Example: |
365 | \snippet code/src_corelib_kernel_qtimer.cpp 0 |
366 | |
367 | This sample program automatically terminates after 10 minutes |
368 | (600,000 milliseconds). |
369 | |
370 | The \a receiver is the receiving object and the \a member is the |
371 | slot. The time interval is \a msec milliseconds. |
372 | |
373 | \sa start() |
374 | */ |
375 | |
376 | /*! |
377 | \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member) |
378 | \overload |
379 | \reentrant |
380 | \deprecated [6.8] Use the chrono overloads. |
381 | This static function calls a slot after a given time interval. |
382 | |
383 | It is very convenient to use this function because you do not need |
384 | to bother with a \l{QObject::timerEvent()}{timerEvent} or |
385 | create a local QTimer object. |
386 | |
387 | The \a receiver is the receiving object and the \a member is the slot. The |
388 | time interval is \a msec milliseconds. The \a timerType affects the |
389 | accuracy of the timer. |
390 | |
391 | \sa start() |
392 | */ |
393 | |
394 | void QTimer::singleShot(std::chrono::nanoseconds ns, Qt::TimerType timerType, |
395 | const QObject *receiver, const char *member) |
396 | { |
397 | if (ns < 0ns) { |
398 | qWarning(msg: "QTimer::singleShot: Timers cannot have negative timeouts" ); |
399 | return; |
400 | } |
401 | if (receiver && member) { |
402 | if (ns == 0ns) { |
403 | // special code shortpath for 0-timers |
404 | const char* bracketPosition = strchr(s: member, c: '('); |
405 | if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) { |
406 | qWarning(msg: "QTimer::singleShot: Invalid slot specification" ); |
407 | return; |
408 | } |
409 | const auto methodName = QByteArrayView(member + 1, // extract method name |
410 | bracketPosition - 1 - member).trimmed(); |
411 | QMetaObject::invokeMethod(obj: const_cast<QObject *>(receiver), member: methodName.toByteArray().constData(), |
412 | c: Qt::QueuedConnection); |
413 | return; |
414 | } |
415 | (void) new QSingleShotTimer(ns, timerType, receiver, member); |
416 | } |
417 | } |
418 | |
419 | /*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, const QObject *context, Functor &&functor) |
420 | \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Functor &&functor) |
421 | \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Functor &&functor) |
422 | \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, Functor &&functor) |
423 | \since 5.4 |
424 | |
425 | \reentrant |
426 | This static function calls \a functor after \a interval. |
427 | |
428 | It is very convenient to use this function because you do not need |
429 | to bother with a \l{QObject::timerEvent()}{timerEvent} or |
430 | create a local QTimer object. |
431 | |
432 | If \a context is specified, then the \a functor will be called only if the |
433 | \a context object has not been destroyed before the interval occurs. The functor |
434 | will then be run the thread of \a context. The context's thread must have a |
435 | running Qt event loop. |
436 | |
437 | If \a functor is a member |
438 | function of \a context, then the function will be called on the object. |
439 | |
440 | The \a interval parameter can be an \c int (interpreted as a millisecond |
441 | count) or a \c std::chrono type that implicitly converts to nanoseconds. |
442 | |
443 | \note In Qt versions prior to 6.8, the chrono overloads took chrono::milliseconds, |
444 | not chrono::nanoseconds. The compiler will automatically convert for you, |
445 | but the conversion may overflow for extremely large milliseconds counts. |
446 | |
447 | \sa start() |
448 | */ |
449 | |
450 | /*! |
451 | \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member) |
452 | \since 5.8 |
453 | \overload |
454 | \reentrant |
455 | |
456 | This static function calls a slot after a given time interval. |
457 | |
458 | It is very convenient to use this function because you do not need |
459 | to bother with a \l{QObject::timerEvent()}{timerEvent} or |
460 | create a local QTimer object. |
461 | |
462 | The \a receiver is the receiving object and the \a member is the slot. The |
463 | time interval is given in the duration object \a nsec. |
464 | |
465 | //! [qtimer-ns-overflow] |
466 | \note In Qt versions prior to 6.8, this function took chrono::milliseconds, |
467 | not chrono::nanoseconds. The compiler will automatically convert for you, |
468 | but the conversion may overflow for extremely large milliseconds counts. |
469 | //! [qtimer-ns-overflow] |
470 | |
471 | \sa start() |
472 | */ |
473 | |
474 | /*! |
475 | \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member) |
476 | \since 5.8 |
477 | \overload |
478 | \reentrant |
479 | |
480 | This static function calls a slot after a given time interval. |
481 | |
482 | It is very convenient to use this function because you do not need |
483 | to bother with a \l{QObject::timerEvent()}{timerEvent} or |
484 | create a local QTimer object. |
485 | |
486 | The \a receiver is the receiving object and the \a member is the slot. The |
487 | time interval is given in the duration object \a nsec. The \a timerType affects the |
488 | accuracy of the timer. |
489 | |
490 | \include qtimer.cpp qtimer-ns-overflow |
491 | |
492 | \sa start() |
493 | */ |
494 | |
495 | /*! |
496 | \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot) |
497 | \since 5.12 |
498 | |
499 | Creates a connection from the timer's timeout() signal to \a slot. |
500 | Returns a handle to the connection. |
501 | |
502 | This method is provided for convenience. It's equivalent to calling: |
503 | \code |
504 | QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection); |
505 | \endcode |
506 | |
507 | \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is |
508 | defined, instead use the callOnTimeout() overload that takes a context object. |
509 | |
510 | \sa QObject::connect(), timeout() |
511 | */ |
512 | |
513 | /*! |
514 | \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection) |
515 | \since 5.12 |
516 | \overload callOnTimeout() |
517 | |
518 | Creates a connection from the timeout() signal to \a slot to be placed in a specific |
519 | event loop of \a context, and returns a handle to the connection. |
520 | |
521 | This method is provided for convenience. It's equivalent to calling: |
522 | \code |
523 | QObject::connect(timer, &QTimer::timeout, context, slot, connectionType); |
524 | \endcode |
525 | |
526 | \sa QObject::connect(), timeout() |
527 | */ |
528 | |
529 | /*! |
530 | \fn void QTimer::start(std::chrono::milliseconds msec) |
531 | \since 5.8 |
532 | \overload |
533 | |
534 | Starts or restarts the timer with a timeout of duration \a msec milliseconds. |
535 | |
536 | \include qtimer.cpp stop-restart-timer |
537 | |
538 | \include qtimer.cpp singleshot-activation |
539 | This is equivalent to: |
540 | |
541 | \code |
542 | timer.setInterval(msec); |
543 | timer.start(); |
544 | \endcode |
545 | */ |
546 | |
547 | /*! |
548 | \fn std::chrono::milliseconds QTimer::intervalAsDuration() const |
549 | \since 5.8 |
550 | |
551 | Returns the interval of this timer as a \c std::chrono::milliseconds object. |
552 | |
553 | \sa interval |
554 | */ |
555 | |
556 | /*! |
557 | \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const |
558 | \since 5.8 |
559 | |
560 | Returns the time remaining in this timer object as a \c |
561 | std::chrono::milliseconds object. If this timer is due or overdue, the |
562 | returned value is \c std::chrono::milliseconds::zero(). If the remaining |
563 | time could not be found or the timer is not running, this function returns a |
564 | negative duration. |
565 | |
566 | \sa remainingTime() |
567 | */ |
568 | |
569 | /*! |
570 | \property QTimer::singleShot |
571 | \brief whether the timer is a single-shot timer |
572 | |
573 | A single-shot timer fires only once, non-single-shot timers fire |
574 | every \l interval milliseconds. |
575 | |
576 | The default value for this property is \c false. |
577 | |
578 | \sa interval, singleShot() |
579 | */ |
580 | void QTimer::setSingleShot(bool singleShot) |
581 | { |
582 | d_func()->single = singleShot; |
583 | } |
584 | |
585 | bool QTimer::isSingleShot() const |
586 | { |
587 | return d_func()->single; |
588 | } |
589 | |
590 | QBindable<bool> QTimer::bindableSingleShot() |
591 | { |
592 | return QBindable<bool>(&d_func()->single); |
593 | } |
594 | |
595 | /*! |
596 | \property QTimer::interval |
597 | \brief the timeout interval in milliseconds |
598 | |
599 | The default value for this property is 0. A QTimer with a timeout |
600 | interval of 0 will time out as soon as all the events in the window |
601 | system's event queue have been processed. |
602 | |
603 | Setting the interval of a running timer will change the interval, |
604 | stop() and then start() the timer, and acquire a new id(). |
605 | If the timer is not running, only the interval is changed. |
606 | |
607 | \sa singleShot |
608 | */ |
609 | void QTimer::setInterval(int msec) |
610 | { |
611 | setInterval(std::chrono::milliseconds{msec}); |
612 | } |
613 | |
614 | void QTimer::setInterval(std::chrono::milliseconds interval) |
615 | { |
616 | Q_D(QTimer); |
617 | // This could be narrowing as the interval is stored in an `int` QProperty, |
618 | // and the type can't be changed in Qt6. |
619 | const int msec = interval.count(); |
620 | d->inter.removeBindingUnlessInWrapper(); |
621 | const bool intervalChanged = msec != d->inter.valueBypassingBindings(); |
622 | d->inter.setValueBypassingBindings(msec); |
623 | if (d->isActive()) { // create new timer |
624 | QObject::killTimer(id: d->id); // restart timer |
625 | Qt::TimerId newId{ QObject::startTimer(time: msec * 1ms, timerType: d->type) }; // overflow impossible |
626 | if (newId > Qt::TimerId::Invalid) { |
627 | // Restarted successfully. No need to update the active state. |
628 | d->id = newId; |
629 | } else { |
630 | // Failed to start the timer. |
631 | // Need to notify about active state change. |
632 | d->id = Qt::TimerId::Invalid; |
633 | d->isActiveData.notify(); |
634 | } |
635 | } |
636 | if (intervalChanged) |
637 | d->inter.notify(); |
638 | } |
639 | |
640 | int QTimer::interval() const |
641 | { |
642 | return d_func()->inter; |
643 | } |
644 | |
645 | QBindable<int> QTimer::bindableInterval() |
646 | { |
647 | return QBindable<int>(&d_func()->inter); |
648 | } |
649 | |
650 | /*! |
651 | \property QTimer::remainingTime |
652 | \since 5.0 |
653 | \brief the remaining time in milliseconds |
654 | |
655 | Returns the timer's remaining value in milliseconds left until the timeout. |
656 | If the timer is inactive, the returned value will be -1. If the timer is |
657 | overdue, the returned value will be 0. |
658 | |
659 | \sa interval |
660 | */ |
661 | int QTimer::remainingTime() const |
662 | { |
663 | Q_D(const QTimer); |
664 | if (d->isActive()) { |
665 | using namespace std::chrono; |
666 | auto remaining = QAbstractEventDispatcher::instance()->remainingTime(timerId: d->id); |
667 | return ceil<milliseconds>(d: remaining).count(); |
668 | } |
669 | |
670 | return -1; |
671 | } |
672 | |
673 | /*! |
674 | \property QTimer::timerType |
675 | \brief controls the accuracy of the timer |
676 | |
677 | The default value for this property is \c Qt::CoarseTimer. |
678 | |
679 | \sa Qt::TimerType |
680 | */ |
681 | void QTimer::setTimerType(Qt::TimerType atype) |
682 | { |
683 | d_func()->type = atype; |
684 | } |
685 | |
686 | Qt::TimerType QTimer::timerType() const |
687 | { |
688 | return d_func()->type; |
689 | } |
690 | |
691 | QBindable<Qt::TimerType> QTimer::bindableTimerType() |
692 | { |
693 | return QBindable<Qt::TimerType>(&d_func()->type); |
694 | } |
695 | |
696 | QT_END_NAMESPACE |
697 | |
698 | #include "moc_qtimer.cpp" |
699 | |