summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qtimer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qtimer.cpp')
-rw-r--r--src/corelib/kernel/qtimer.cpp44
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