diff options
Diffstat (limited to 'src/corelib/kernel/qtimer.cpp')
-rw-r--r-- | src/corelib/kernel/qtimer.cpp | 219 |
1 files changed, 196 insertions, 23 deletions
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index db6ff568bd..0803cf302e 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -260,26 +252,50 @@ class QSingleShotTimer : public QObject { Q_OBJECT int timerId; + bool hasValidReceiver; + QPointer<const QObject> receiver; + QtPrivate::QSlotObjectBase *slotObj; public: ~QSingleShotTimer(); QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char * m); + QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj); + Q_SIGNALS: void timeout(); protected: void timerEvent(QTimerEvent *); }; -QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member) - : QObject(QAbstractEventDispatcher::instance()) +QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char *member) + : QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(true), slotObj(0) +{ + timerId = startTimer(msec, timerType); + connect(this, SIGNAL(timeout()), r, member); +} + +QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj) + : QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(r), receiver(r), slotObj(slotObj) { - connect(this, SIGNAL(timeout()), receiver, member); timerId = startTimer(msec, timerType); + if (r && thread() != r->thread()) { + // We need the invocation to happen in the receiver object's thread. + // So, move QSingleShotTimer to the correct thread. Before that occurs, we + // shall remove the parent from the object. + setParent(0); + moveToThread(r->thread()); + + // Given we're also parentless now, we should take defence against leaks + // in case the application quits before we expire. + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); + } } QSingleShotTimer::~QSingleShotTimer() { if (timerId > 0) killTimer(timerId); + if (slotObj) + slotObj->destroyIfLastRef(); } void QSingleShotTimer::timerEvent(QTimerEvent *) @@ -289,7 +305,18 @@ void QSingleShotTimer::timerEvent(QTimerEvent *) if (timerId > 0) killTimer(timerId); timerId = -1; - emit timeout(); + + if (slotObj) { + // If the receiver was destroyed, skip this part + if (Q_LIKELY(!receiver.isNull() || !hasValidReceiver)) { + // We allocate only the return type - we previously checked the function had + // no arguments. + void *args[1] = { 0 }; + slotObj->call(const_cast<QObject*>(receiver.data()), args); + } + } else { + emit timeout(); + } // we would like to use delete later here, but it feels like a // waste to post a new event to handle this event, so we just unset the flag @@ -298,6 +325,25 @@ void QSingleShotTimer::timerEvent(QTimerEvent *) } /*! + \internal + + Implementation of the template version of singleShot + + \a msec is the timer interval + \a timerType is the timer type + \a receiver is the receiver object, can be null. In such a case, it will be the same + as the final sender class. + \a slot a pointer only used when using Qt::UniqueConnection + \a slotObj the slot object + */ +void QTimer::singleShotImpl(int msec, Qt::TimerType timerType, + const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj) +{ + new QSingleShotTimer(msec, timerType, receiver, slotObj); +} + +/*! \reentrant This static function calls a slot after a given time interval. @@ -341,6 +387,10 @@ void QTimer::singleShot(int msec, const QObject *receiver, const char *member) */ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member) { + if (Q_UNLIKELY(msec < 0)) { + qWarning("QTimer::singleShot: Timers cannot have negative timeouts"); + return; + } if (receiver && member) { if (msec == 0) { // special code shortpath for 0-timers @@ -357,6 +407,129 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv } } +/*!\fn void QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method) + + \since 5.4 + + \overload + \reentrant + This static function calls a member function of a QObject after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The \a receiver is the receiving object and the \a method is the member function. The + time interval is \a msec milliseconds. + + If \a receiver is destroyed before the interval occurs, the method will not be called. + The function will be run in the thread of \a receiver. The receiver's thread must have + a running Qt event loop. + + \sa start() +*/ + +/*!\fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, PointerToMemberFunction method) + + \since 5.4 + + \overload + \reentrant + This static function calls a member function of a QObject after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The \a receiver is the receiving object and the \a method is the member function. The + time interval is \a msec milliseconds. The \a timerType affects the + accuracy of the timer. + + If \a receiver is destroyed before the interval occurs, the method will not be called. + The function will be run in the thread of \a receiver. The receiver's thread must have + a running Qt event loop. + + \sa start() +*/ + +/*!\fn void QTimer::singleShot(int msec, Functor functor) + + \since 5.4 + + \overload + \reentrant + This static function calls \a functor after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The time interval is \a msec milliseconds. + + \sa start() +*/ + +/*!\fn void QTimer::singleShot(int msec, Qt::TimerType timerType, Functor functor) + + \since 5.4 + + \overload + \reentrant + This static function calls \a functor after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The time interval is \a msec milliseconds. The \a timerType affects the + accuracy of the timer. + + \sa start() +*/ + +/*!\fn void QTimer::singleShot(int msec, const QObject *context, Functor functor) + + \since 5.4 + + \overload + \reentrant + This static function calls \a functor after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The time interval is \a msec milliseconds. + + If \a context is destroyed before the interval occurs, the method will not be called. + The function will be run in the thread of \a context. The context's thread must have + a running Qt event loop. + + \sa start() +*/ + +/*!\fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor) + + \since 5.4 + + \overload + \reentrant + This static function calls \a functor after a given time interval. + + It is very convenient to use this function because you do not need + to bother with a \l{QObject::timerEvent()}{timerEvent} or + create a local QTimer object. + + The time interval is \a msec milliseconds. The \a timerType affects the + accuracy of the timer. + + If \a context is destroyed before the interval occurs, the method will not be called. + The function will be run in the thread of \a context. The context's thread must have + a running Qt event loop. + + \sa start() +*/ + /*! \property QTimer::singleShot \brief whether the timer is a single-shot timer |