diff options
Diffstat (limited to 'src/corelib/kernel/qtimer.cpp')
| -rw-r--r-- | src/corelib/kernel/qtimer.cpp | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 9c074a064f8..5d1a9c7497c 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -8,6 +8,7 @@ #include "qabstracteventdispatcher.h" #include "qcoreapplication.h" #include "qcoreapplication_p.h" +#include "qdeadlinetimer.h" #include "qmetaobject_p.h" #include "qobject_p.h" #include "qproperty_p.h" @@ -249,12 +250,14 @@ void QTimer::timerEvent(QTimerEvent *e) class QSingleShotTimer : public QObject { Q_OBJECT - int timerId; + int timerId = -1; 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); + void startTimerForReceiver(int msec, Qt::TimerType timerType, const QObject *receiver); + Q_SIGNALS: void timeout(); protected: @@ -264,27 +267,20 @@ protected: QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char *member) : QObject(QAbstractEventDispatcher::instance()) { - timerId = startTimer(std::chrono::milliseconds{msec}, timerType); connect(this, SIGNAL(timeout()), r, member); + + startTimerForReceiver(msec, timerType, r); } QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj) : QObject(QAbstractEventDispatcher::instance()) { - timerId = startTimer(std::chrono::milliseconds{msec}, timerType); - int signal_index = QMetaObjectPrivate::signalOffset(&staticMetaObject); Q_ASSERT(QMetaObjectPrivate::signal(&staticMetaObject, signal_index).name() == "timeout"); QObjectPrivate::connectImpl(this, signal_index, r ? r : this, nullptr, slotObj, Qt::AutoConnection, nullptr, &staticMetaObject); - // ### Why is this here? Why doesn't the case above need it? - if (r && thread() != r->thread()) { - // Avoid leaking the QSingleShotTimer instance in case the application exits before the timer fires - connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); - setParent(nullptr); - moveToThread(r->thread()); - } + startTimerForReceiver(msec, timerType, r); } QSingleShotTimer::~QSingleShotTimer() @@ -293,6 +289,32 @@ QSingleShotTimer::~QSingleShotTimer() killTimer(timerId); } +/* + Move the timer, and the dispatching and handling of the timer event, into + the same thread as where it will be handled, so that it fires reliably even + if the thread that set up the timer is busy. +*/ +void QSingleShotTimer::startTimerForReceiver(int msec, Qt::TimerType timerType, const QObject *receiver) +{ + if (receiver && receiver->thread() != thread()) { + // Avoid leaking the QSingleShotTimer instance in case the application exits before the timer fires + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); + setParent(nullptr); + moveToThread(receiver->thread()); + + QDeadlineTimer deadline(std::chrono::milliseconds{msec}, timerType); + QMetaObject::invokeMethod(this, [=]{ + if (deadline.hasExpired()) + emit timeout(); + else + timerId = startTimer(std::chrono::milliseconds{deadline.remainingTime()}, timerType); + }, Qt::QueuedConnection); + } else { + timerId = startTimer(std::chrono::milliseconds{msec}, timerType); + } +} + + void QSingleShotTimer::timerEvent(QTimerEvent *) { // need to kill the timer _before_ we emit timeout() in case the |
