diff options
author | Dario Freddi <dario.freddi@ispirata.com> | 2013-09-21 21:01:58 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-05-28 11:45:48 +0200 |
commit | e2df05f120ea76f7fb777926f5c00163dba4a92b (patch) | |
tree | 3000bf9873001419693be0dd229f3eae11fa2469 /src/corelib/kernel/qtimer.cpp | |
parent | 161d98a61a0365a952c6422ebeb722a4fa4b34be (diff) |
QTimer: add convenience singleShot methods for functors
This brings QTimer::singleShot on par with QObject::connect in
terms of the new Qt5 syntax. With this patch, it is now possible
to connect singleShot to a member pointer, a static function
pointer and a functor (with or without a context object).
The short code path for 0 msec is not yet implemented - it will
require further modifications to QMetaObject before it will be.
An additional SFINAE on the new singleShot overloads had to be
implemented to prevent tricking the compiler into believing
const char * might be a function pointer.
[ChangeLog][QtCore][QTimer] Implemented new style connect syntax,
including functors, in QTimer::singleShot
Task-number: QTBUG-26406
Change-Id: I31b2fa2c8369648030ec80b12e3ae10b92eb28b4
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Diffstat (limited to 'src/corelib/kernel/qtimer.cpp')
-rw-r--r-- | src/corelib/kernel/qtimer.cpp | 185 |
1 files changed, 181 insertions, 4 deletions
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index db6ff568bd..97aae6f7e0 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -260,26 +260,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 +313,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 +333,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. @@ -357,6 +411,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 |