| 1 |
/**************************************************************************** |
| 2 |
** |
| 3 |
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). |
| 4 |
** All rights reserved. |
| 5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
| 6 |
** |
| 7 |
** This file is part of the QtCore module of the Qt Toolkit. |
| 8 |
** |
| 9 |
** $QT_BEGIN_LICENSE:LGPL$ |
| 10 |
** GNU Lesser General Public License Usage |
| 11 |
** This file may be used under the terms of the GNU Lesser General Public |
| 12 |
** License version 2.1 as published by the Free Software Foundation and |
| 13 |
** appearing in the file LICENSE.LGPL included in the packaging of this |
| 14 |
** file. Please review the following information to ensure the GNU Lesser |
| 15 |
** General Public License version 2.1 requirements will be met: |
| 16 |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 17 |
** |
| 18 |
** In addition, as a special exception, Nokia gives you certain additional |
| 19 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
| 20 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 21 |
** |
| 22 |
** GNU General Public License Usage |
| 23 |
** Alternatively, this file may be used under the terms of the GNU General |
| 24 |
** Public License version 3.0 as published by the Free Software Foundation |
| 25 |
** and appearing in the file LICENSE.GPL included in the packaging of this |
| 26 |
** file. Please review the following information to ensure the GNU General |
| 27 |
** Public License version 3.0 requirements will be met: |
| 28 |
** http://www.gnu.org/copyleft/gpl.html. |
| 29 |
** |
| 30 |
** Other Usage |
| 31 |
** Alternatively, this file may be used in accordance with the terms and |
| 32 |
** conditions contained in a signed written agreement between you and Nokia. |
| 33 |
** |
| 34 |
** |
| 35 |
** |
| 36 |
** |
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
*/ |
| 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 |
*/ |
| 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 |
|
| 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 |
|
| 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 |
*/ |
| 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 |
|
| 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 |
|
| 304 |
QSingleShotTimer::~QSingleShotTimer() |
| 305 |
{ |
| 306 |
if (timerId > 0) |
| 307 |
killTimer(timerId); |
| 308 |
} |
| 309 |
|
| 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 |
|
| 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 |
*/ |
| 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 |