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