Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qbasictimer.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qbasictimer.h"
7
8#include <private/qthread_p.h>
9
10using namespace std::chrono_literals;
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QBasicTimer
16 \inmodule QtCore
17 \brief The QBasicTimer class provides timer events for objects.
18
19 \ingroup events
20
21 This is a fast, lightweight, and low-level class used by Qt
22 internally. We recommend using the higher-level QTimer class
23 rather than this class if you want to use timers in your
24 applications. Note that this timer is a repeating timer that
25 will send subsequent timer events unless the stop() function is called.
26
27 To use this class, create a QBasicTimer, and call its start()
28 function with a timeout interval and with a pointer to a QObject
29 subclass. When the timer times out it will send a timer event to
30 the QObject subclass. The timer can be stopped at any time using
31 stop(). isActive() returns \c true for a timer that is running;
32 i.e. it has been started, has not reached the timeout time, and
33 has not been stopped. The timer's ID can be retrieved using
34 timerId().
35
36 Objects of this class cannot be copied, but can be moved, so you
37 can maintain a list of basic timers by holding them in container
38 that supports move-only types, e.g. std::vector.
39
40 \sa QTimer, QChronoTimer, QTimerEvent, QObject::timerEvent(),
41 Timers, {Affine Transformations}
42*/
43
44
45/*!
46 \fn QBasicTimer::QBasicTimer()
47
48 Constructs a basic timer.
49
50 \sa start()
51*/
52
53/*!
54 \fn QBasicTimer::QBasicTimer(QBasicTimer &&other)
55 \since 5.14
56
57 Move-constructs a basic timer from \a other, which is left
58 \l{isActive()}{inactive}.
59
60 \sa isActive(), swap()
61*/
62
63/*!
64 \fn QBasicTimer &QBasicTimer::operator=(QBasicTimer &&other)
65 \since 5.14
66
67 Move-assigns \a other to this basic timer. The timer
68 previously represented by this basic timer is stopped.
69 \a other is left as \l{isActive()}{inactive}.
70
71 \sa stop(), isActive(), swap()
72*/
73
74/*!
75 \fn QBasicTimer::~QBasicTimer()
76
77 Destroys the basic timer.
78*/
79
80/*!
81 \fn bool QBasicTimer::isActive() const
82
83 Returns \c true if the timer is running and has not been stopped; otherwise
84 returns \c false.
85
86 \sa start(), stop()
87*/
88
89/*!
90 \fn QBasicTimer::swap(QBasicTimer &other)
91 \since 5.14
92 \memberswap{timer}
93*/
94
95/*!
96 \fn swap(QBasicTimer &lhs, QBasicTimer &rhs)
97 \relates QBasicTimer
98 \since 5.14
99
100 Swaps the timer \a lhs with \a rhs.
101 This operation is very fast and never fails.
102*/
103
104/*!
105 \fn int QBasicTimer::timerId() const
106 \obsolete
107
108 Returns the timer's ID.
109
110 In new code use id() instead.
111
112 \sa QTimerEvent::timerId()
113*/
114
115/*!
116 \fn Qt::TimerId QBasicTimer::id() const
117 \since 6.8
118
119 Returns the timer's ID.
120
121 \sa QTimerEvent::id()
122*/
123
124/*!
125 \fn void QBasicTimer::start(int msec, QObject *object)
126
127 \obsolete Use chrono overload instead.
128*/
129
130/*!
131 \typedef QBasicTimer::Duration
132
133 A \c{std::chrono::duration} type that is used in various API in this class.
134 This type exists to facilitate a possible transition to a higher or lower
135 granularity.
136
137 In all current platforms, it is \c nanoseconds.
138*/
139
140/*!
141 \fn void QBasicTimer::start(Duration duration, QObject *object)
142 \since 6.5
143
144 Starts (or restarts) the timer with a \a duration timeout. The
145 timer will be a Qt::CoarseTimer. See Qt::TimerType for information on the
146 different timer types.
147
148 The given \a object will receive timer events.
149
150 \include timers-common.qdocinc negative-intervals-not-allowed
151
152//! [start-nanoseconds-note]
153 \note Starting from Qt 6.9 this method takes std::chrono::nanoseconds,
154 before that it took std::chrono::milliseconds. This change is
155 backwards compatible.
156//! [start-nanoseconds-note]
157
158 \sa stop(), isActive(), QObject::timerEvent(), Qt::CoarseTimer
159 */
160
161/*!
162 \fn QBasicTimer::start(int msec, Qt::TimerType timerType, QObject *obj)
163 \overload
164 \obsolete
165
166 Use chrono overload instead.
167*/
168
169/*!
170 \since 6.5
171 \overload
172
173 Starts (or restarts) the timer with a \a duration timeout and the
174 given \a timerType. See Qt::TimerType for information on the different
175 timer types.
176
177 \include timers-common.qdocinc negative-intervals-not-allowed
178
179 \a obj will receive timer events.
180
181 \include qbasictimer.cpp start-nanoseconds-note
182
183 \sa stop(), isActive(), QObject::timerEvent(), Qt::TimerType
184 */
185void QBasicTimer::start(Duration duration, Qt::TimerType timerType, QObject *obj)
186{
187 if (duration < 0ns) {
188 qWarning("QBasicTimer::start: negative intervals aren't allowed; the "
189 "interval will be set to 1ms.");
190 duration = 1ms;
191 }
192
193 QThreadData *currentData = QThreadData::current();
194 if (Q_UNLIKELY(obj && QObjectPrivate::get(obj)->threadData != currentData)) {
195 qWarning("QBasicTimer::start: Timers cannot be started from another thread");
196 return;
197 }
198
199 QAbstractEventDispatcher *eventDispatcher = currentData->eventDispatcher.loadRelaxed();
200 if (Q_UNLIKELY(!eventDispatcher)) {
201 qWarning("QBasicTimer::start: current thread's event dispatcher has already been destroyed");
202 return;
203 }
204 stop();
205 if (obj)
206 m_id = eventDispatcher->registerTimer(duration, timerType, obj);
207}
208
209/*!
210 Stops the timer.
211
212 \sa start(), isActive()
213*/
214void QBasicTimer::stop()
215{
216 if (isActive()) {
217 QAbstractEventDispatcher *eventDispatcher = nullptr;
218
219 // don't create the current thread data if it's already been destroyed
220 if (QThreadData *data = QThreadData::currentThreadData())
221 eventDispatcher = data->eventDispatcher.loadRelaxed();
222
223 if (eventDispatcher && !eventDispatcher->unregisterTimer(m_id)) {
224 qWarning("QBasicTimer::stop: Failed. Possibly trying to stop from a different thread");
225 return;
226 }
227 QAbstractEventDispatcherPrivate::releaseTimerId(m_id);
228 }
229 m_id = Qt::TimerId::Invalid;
230}
231
232QT_END_NAMESPACE