QTimer: split QSingleShotTimer to a private header

So that it can be used in QTimer and soon-to-added QChronoTimer, this is
less code duplication.

Change-Id: Icc5f2028d776a34c06ba20fe41f571cd3821c64c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Ahmad Samir 2023-07-14 19:21:10 +03:00
parent 6f1449c7ae
commit e0573e7364
3 changed files with 121 additions and 85 deletions

View File

@ -181,6 +181,7 @@ qt_internal_add_module(Core
kernel/qsocketnotifier.cpp kernel/qsocketnotifier.h
kernel/qsystemerror.cpp kernel/qsystemerror_p.h
kernel/qtestsupport_core.cpp kernel/qtestsupport_core.h
kernel/qsingleshottimer_p.h
kernel/qtimer.cpp kernel/qtimer.h kernel/qtimer_p.h
kernel/qtranslator.cpp kernel/qtranslator.h kernel/qtranslator_p.h
kernel/qvariant.cpp kernel/qvariant.h kernel/qvariant_p.h

View File

@ -0,0 +1,119 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSINGLESHOTTIMER_P_H
#define QSINGLESHOTTIMER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
#include "qmetaobject_p.h"
QT_BEGIN_NAMESPACE
class QSingleShotTimer : public QObject
{
Q_OBJECT
int timerId = -1;
public:
inline ~QSingleShotTimer();
inline QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r,
const char *member);
inline QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r,
QtPrivate::QSlotObjectBase *slotObj);
inline void startTimerForReceiver(int msec, Qt::TimerType timerType, const QObject *receiver);
Q_SIGNALS:
void timeout();
protected:
inline void timerEvent(QTimerEvent *) override;
};
QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r,
const char *member)
: QObject(QAbstractEventDispatcher::instance())
{
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())
{
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);
startTimerForReceiver(msec, timerType, r);
}
QSingleShotTimer::~QSingleShotTimer()
{
if (timerId > 0)
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, [this, deadline, timerType] {
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
// slot connected to timeout calls processEvents()
if (timerId > 0)
killTimer(timerId);
timerId = -1;
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
// and explicitly delete...
qDeleteInEventHandler(this);
}
QT_END_NAMESPACE
#endif // qsingleshottimer_p.h

View File

@ -4,6 +4,7 @@
#include "qtimer.h"
#include "qtimer_p.h"
#include "qsingleshottimer_p.h"
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
@ -253,90 +254,6 @@ void QTimer::timerEvent(QTimerEvent *e)
}
}
class QSingleShotTimer : public QObject
{
Q_OBJECT
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:
void timerEvent(QTimerEvent *) override;
};
QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char *member)
: QObject(QAbstractEventDispatcher::instance())
{
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())
{
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);
startTimerForReceiver(msec, timerType, r);
}
QSingleShotTimer::~QSingleShotTimer()
{
if (timerId > 0)
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, [this, deadline, timerType]{
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
// slot connected to timeout calls processEvents()
if (timerId > 0)
killTimer(timerId);
timerId = -1;
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
// and explicitly delete...
qDeleteInEventHandler(this);
}
/*!
\internal
@ -699,5 +616,4 @@ QBindable<Qt::TimerType> QTimer::bindableTimerType()
QT_END_NAMESPACE
#include "qtimer.moc"
#include "moc_qtimer.cpp"