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