1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qtimer.h"
43 #include "qabstracteventdispatcher.h"
44 #include "qcoreapplication.h"
45 #include "qobject_p.h"
46
47 QT_BEGIN_NAMESPACE
48
49 /*!
50 \class QTimer
51 \brief The QTimer class provides repetitive and single-shot timers.
52
53 \ingroup events
54
55
56 The QTimer class provides a high-level programming interface for
57 timers. To use it, create a QTimer, connect its timeout() signal
58 to the appropriate slots, and call start(). From then on it will
59 emit the timeout() signal at constant intervals.
60
61 Example for a one second (1000 millisecond) timer (from the
62 \l{widgets/analogclock}{Analog Clock} example):
63
64 \snippet examples/widgets/analogclock/analogclock.cpp 4
65 \snippet examples/widgets/analogclock/analogclock.cpp 5
66 \snippet examples/widgets/analogclock/analogclock.cpp 6
67
68 From then on, the \c update() slot is called every second.
69
70 You can set a timer to time out only once by calling
71 setSingleShot(true). You can also use the static
72 QTimer::singleShot() function to call a slot after a specified
73 interval:
74
75 \snippet doc/src/snippets/timers/timers.cpp 3
76
77 In multithreaded applications, you can use QTimer in any thread
78 that has an event loop. To start an event loop from a non-GUI
79 thread, use QThread::exec(). Qt uses the timer's
80 \l{QObject::thread()}{thread affinity} to determine which thread
81 will emit the \l{QTimer::}{timeout()} signal. Because of this, you
82 must start and stop the timer in its thread; it is not possible to
83 start a timer from another thread.
84
85 As a special case, a QTimer with a timeout of 0 will time out as
86 soon as all the events in the window system's event queue have
87 been processed. This can be used to do heavy work while providing
88 a snappy user interface:
89
90 \snippet doc/src/snippets/timers/timers.cpp 4
91 \snippet doc/src/snippets/timers/timers.cpp 5
92 \snippet doc/src/snippets/timers/timers.cpp 6
93
94 \c processOneThing() will from then on be called repeatedly. It
95 should be written in such a way that it always returns quickly
96 (typically after processing one data item) so that Qt can deliver
97 events to widgets and stop the timer as soon as it has done all
98 its work. This is the traditional way of implementing heavy work
99 in GUI applications; multithreading is now becoming available on
100 more and more platforms, and we expect that zero-millisecond
101 QTimers will gradually be replaced by \l{QThread}s.
102
103 \section1 Accuracy and Timer Resolution
104
105 Timers will never time out earlier than the specified timeout value
106 and they are not guaranteed to time out at the exact value specified.
107 In many situations, they may time out late by a period of time that
108 depends on the accuracy of the system timers.
109
110 The accuracy of timers depends on the underlying operating system
111 and hardware. Most platforms support a resolution of 1 millisecond,
112 though the accuracy of the timer will not equal this resolution
113 in many real-world situations.
114
115 If Qt is unable to deliver the requested number of timer clicks,
116 it will silently discard some.
117
118 \section1 Alternatives to QTimer
119
120 An alternative to using QTimer is to call QObject::startTimer()
121 for your object and reimplement the QObject::timerEvent() event
122 handler in your class (which must inherit QObject). The
123 disadvantage is that timerEvent() does not support such
124 high-level features as single-shot timers or signals.
125
126 Another alternative to using QTimer is to use QBasicTimer. It is
127 typically less cumbersome than using QObject::startTimer()
128 directly. See \l{Timers} for an overview of all three approaches.
129
130 Some operating systems limit the number of timers that may be
131 used; Qt tries to work around these limitations.
132
133 \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
134 {Analog Clock Example}, {Wiggly Example}
135 */
136
137
138 static const int INV_TIMER = -1; // invalid timer id
139
140 /*!
141 Constructs a timer with the given \a parent.
142 */
143
QTimer(QObject * parent)144 QTimer::QTimer(QObject *parent)
145 : QObject(parent), id(INV_TIMER), inter(0), del(0), single(0), nulltimer(0)
146 {
147 }
148
149
150 #ifdef QT3_SUPPORT
151 /*!
152 Constructs a timer called \a name, with a \a parent.
153 */
154
QTimer(QObject * parent,const char * name)155 QTimer::QTimer(QObject *parent, const char *name)
156 : QObject(parent), id(INV_TIMER), single(0), nulltimer(0)
157 {
158 setObjectName(QString::fromAscii(name));
159 }
160 #endif
161
162 /*!
163 Destroys the timer.
164 */
165
~QTimer()166 QTimer::~QTimer()
167 {
168 if (id != INV_TIMER) // stop running timer
169 stop();
170 }
171
172
173 /*!
174 \fn void QTimer::timeout()
175
176 This signal is emitted when the timer times out.
177
178 \sa interval, start(), stop()
179 */
180
181 /*!
182 \property QTimer::active
183 \since 4.3
184
185 This boolean property is true if the timer is running; otherwise
186 false.
187 */
188
189 /*!
190 \fn bool QTimer::isActive() const
191
192 Returns true if the timer is running (pending); otherwise returns
193 false.
194 */
195
196 /*!
197 \fn int QTimer::timerId() const
198
199 Returns the ID of the timer if the timer is running; otherwise returns
200 -1.
201 */
202
203
204 /*! \overload start()
205
206 Starts or restarts the timer with the timeout specified in \l interval.
207
208 If the timer is already running, it will be
209 \l{QTimer::stop()}{stopped} and restarted.
210
211 If \l singleShot is true, the timer will be activated only once.
212 */
start()213 void QTimer::start()
214 {
215 if (id != INV_TIMER) // stop running timer
216 stop();
217 nulltimer = (!inter && single);
218 id = QObject::startTimer(inter);
219 }
220
221 /*!
222 Starts or restarts the timer with a timeout interval of \a msec
223 milliseconds.
224
225 If the timer is already running, it will be
226 \l{QTimer::stop()}{stopped} and restarted.
227
228 If \l singleShot is true, the timer will be activated only once.
229
230 */
start(int msec)231 void QTimer::start(int msec)
232 {
233 inter = msec;
234 start();
235 }
236
237
238 #ifdef QT3_SUPPORT
239 /*! \overload start()
240
241 Call setSingleShot(\a sshot) and start(\a msec) instead.
242 */
243
start(int msec,bool sshot)244 int QTimer::start(int msec, bool sshot)
245 {
246 if (id >=0 && nulltimer && !msec && sshot)
247 return id;
248 stop();
249 setInterval(msec);
250 setSingleShot(sshot);
251 start();
252 return timerId();
253 }
254 #endif
255
256
257 /*!
258 Stops the timer.
259
260 \sa start()
261 */
262
stop()263 void QTimer::stop()
264 {
265 if (id != INV_TIMER) {
266 QObject::killTimer(id);
267 id = INV_TIMER;
268 }
269 }
270
271
272 /*!
273 \reimp
274 */
timerEvent(QTimerEvent * e)275 void QTimer::timerEvent(QTimerEvent *e)
276 {
277 if (e->timerId() == id) {
278 if (single)
279 stop();
280 emit timeout();
281 }
282 }
283
284 class QSingleShotTimer : public QObject
285 {
286 Q_OBJECT
287 int timerId;
288 public:
289 ~QSingleShotTimer();
290 QSingleShotTimer(int msec, QObject *r, const char * m);
291 Q_SIGNALS:
292 void timeout();
293 protected:
294 void timerEvent(QTimerEvent *);
295 };
296
QSingleShotTimer(int msec,QObject * receiver,const char * member)297 QSingleShotTimer::QSingleShotTimer(int msec, QObject *receiver, const char *member)
298 : QObject(QAbstractEventDispatcher::instance())
299 {
300 connect(this, SIGNAL(timeout()), receiver, member);
301 timerId = startTimer(msec);
302 }
303
~QSingleShotTimer()304 QSingleShotTimer::~QSingleShotTimer()
305 {
306 if (timerId > 0)
307 killTimer(timerId);
308 }
309
timerEvent(QTimerEvent *)310 void QSingleShotTimer::timerEvent(QTimerEvent *)
311 {
312 // need to kill the timer _before_ we emit timeout() in case the
313 // slot connected to timeout calls processEvents()
314 if (timerId > 0)
315 killTimer(timerId);
316 timerId = -1;
317 emit timeout();
318
319 // we would like to use delete later here, but it feels like a
320 // waste to post a new event to handle this event, so we just unset the flag
321 // and explicitly delete...
322 qDeleteInEventHandler(this);
323 }
324
325 QT_BEGIN_INCLUDE_NAMESPACE
326 #include "qtimer.moc"
327 QT_END_INCLUDE_NAMESPACE
328
329 /*!
330 \reentrant
331 This static function calls a slot after a given time interval.
332
333 It is very convenient to use this function because you do not need
334 to bother with a \link QObject::timerEvent() timerEvent\endlink or
335 create a local QTimer object.
336
337 Example:
338 \snippet doc/src/snippets/code/src_corelib_kernel_qtimer.cpp 0
339
340 This sample program automatically terminates after 10 minutes
341 (600,000 milliseconds).
342
343 The \a receiver is the receiving object and the \a member is the
344 slot. The time interval is \a msec milliseconds.
345
346 \sa start()
347 */
348
singleShot(int msec,QObject * receiver,const char * member)349 void QTimer::singleShot(int msec, QObject *receiver, const char *member)
350 {
351 if (receiver && member) {
352 if (msec == 0) {
353 // special code shortpath for 0-timers
354 const char* bracketPosition = strchr(member, '(');
355 if (!bracketPosition || !(member[0] >= '0' && member[0] <= '3')) {
356 qWarning("QTimer::singleShot: Invalid slot specification");
357 return;
358 }
359 QByteArray methodName(member+1, bracketPosition - 1 - member); // extract method name
360 QMetaObject::invokeMethod(receiver, methodName.constData(), Qt::QueuedConnection);
361 return;
362 }
363 (void) new QSingleShotTimer(msec, receiver, member);
364 }
365 }
366
367 /*!
368 \property QTimer::singleShot
369 \brief whether the timer is a single-shot timer
370
371 A single-shot timer fires only once, non-single-shot timers fire
372 every \l interval milliseconds.
373
374 \sa interval, singleShot()
375 */
376
377 /*!
378 \property QTimer::interval
379 \brief the timeout interval in milliseconds
380
381 The default value for this property is 0. A QTimer with a timeout
382 interval of 0 will time out as soon as all the events in the window
383 system's event queue have been processed.
384
385 Setting the interval of an active timer changes its timerId().
386
387 \sa singleShot
388 */
setInterval(int msec)389 void QTimer::setInterval(int msec)
390 {
391 inter = msec;
392 if (id != INV_TIMER) { // create new timer
393 QObject::killTimer(id); // restart timer
394 id = QObject::startTimer(msec);
395 }
396 }
397
398 /*! \fn void QTimer::changeInterval(int msec)
399
400 Use setInterval(msec) or start(msec) instead.
401 */
402
403 QT_END_NAMESPACE
404