From e3da82d3b645260a314f60144f34ba446f1db3cf Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 28 Jun 2024 10:18:20 +0200 Subject: [PATCH] QSingleShotTimer: de-inline [1/4]: add .cpp file ... and split code between header and .cpp file. The goal here is to just sort the lines into header and .cpp, not to change them, so temporarily define inline away. This allows git to reliably track this as copy instead of independent changes. The inline define will be cleaned up in a follow-up patch; fixing inline and re-indenting would reduce the similarity score too much. Also includemocs and move qsingleshottimer* to the (lexicographically) correct position in CMakeLists.txt's SOURCES. Fixes -Wweak-vtable (and therefore prevents this class from being used outside QtCore (not exported atm)). Amends e0573e73645c0f57e46332a94160e28eb6c8ebac. Change-Id: Ia5304434fd1c9a56eb6f2f1988bd14a80ab61442 Reviewed-by: Thiago Macieira (cherry picked from commit 1ef5f50e28edd1bdfcb3828c3858640ba347b2bd) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/CMakeLists.txt | 2 +- src/corelib/kernel/qsingleshottimer.cpp | 89 +++++++++++++++++++++++++ src/corelib/kernel/qsingleshottimer_p.h | 73 +------------------- 3 files changed, 92 insertions(+), 72 deletions(-) create mode 100644 src/corelib/kernel/qsingleshottimer.cpp diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index e466c943a08..de28a6183e9 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -176,10 +176,10 @@ qt_internal_add_module(Core kernel/qpropertyprivate.h kernel/qsequentialiterable.cpp kernel/qsequentialiterable.h kernel/qsignalmapper.cpp kernel/qsignalmapper.h + kernel/qsingleshottimer.cpp kernel/qsingleshottimer_p.h 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 diff --git a/src/corelib/kernel/qsingleshottimer.cpp b/src/corelib/kernel/qsingleshottimer.cpp new file mode 100644 index 00000000000..ee2b2dc3807 --- /dev/null +++ b/src/corelib/kernel/qsingleshottimer.cpp @@ -0,0 +1,89 @@ +// 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 + +#include + +#include "qabstracteventdispatcher.h" +#include "qcoreapplication.h" +#include "qmetaobject_p.h" +#include "private/qnumeric_p.h" + +#include + +QT_BEGIN_NAMESPACE + +QSingleShotTimer::QSingleShotTimer(Duration interval, Qt::TimerType timerType, + const QObject *r, const char *member) + : QObject(QAbstractEventDispatcher::instance()) +{ + connect(this, SIGNAL(timeout()), r, member); + startTimerForReceiver(interval, timerType, r); +} + +QSingleShotTimer::QSingleShotTimer(Duration interval, 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(interval, timerType, r); +} + +QSingleShotTimer::~QSingleShotTimer() +{ + if (timerId > Qt::TimerId::Invalid) + 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(Duration interval, 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(interval, timerType); + auto invokable = [this, deadline, timerType] { + if (deadline.hasExpired()) { + Q_EMIT timeout(); + } else { + timerId = Qt::TimerId{startTimer(deadline.remainingTimeAsDuration(), timerType)}; + } + }; + QMetaObject::invokeMethod(this, invokable, Qt::QueuedConnection); + } else { + timerId = Qt::TimerId{startTimer(interval, 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 > Qt::TimerId::Invalid) + killTimer(std::exchange(timerId, Qt::TimerId::Invalid)); + + Q_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... + delete this; +} + +QT_END_NAMESPACE + +#include "moc_qsingleshottimer_p.cpp" diff --git a/src/corelib/kernel/qsingleshottimer_p.h b/src/corelib/kernel/qsingleshottimer_p.h index dd1402f63a1..44d00252db9 100644 --- a/src/corelib/kernel/qsingleshottimer_p.h +++ b/src/corelib/kernel/qsingleshottimer_p.h @@ -31,6 +31,7 @@ class QSingleShotTimer : public QObject Qt::TimerId timerId = Qt::TimerId::Invalid; +#define inline public: // use the same duration type using Duration = QAbstractEventDispatcher::Duration; @@ -63,79 +64,9 @@ Q_SIGNALS: private: inline void timerEvent(QTimerEvent *) override; +#undef inline }; -QSingleShotTimer::QSingleShotTimer(Duration interval, Qt::TimerType timerType, - const QObject *r, const char *member) - : QObject(QAbstractEventDispatcher::instance()) -{ - connect(this, SIGNAL(timeout()), r, member); - startTimerForReceiver(interval, timerType, r); -} - -QSingleShotTimer::QSingleShotTimer(Duration interval, 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(interval, timerType, r); -} - -QSingleShotTimer::~QSingleShotTimer() -{ - if (timerId > Qt::TimerId::Invalid) - 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(Duration interval, 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(interval, timerType); - auto invokable = [this, deadline, timerType] { - if (deadline.hasExpired()) { - Q_EMIT timeout(); - } else { - timerId = Qt::TimerId{startTimer(deadline.remainingTimeAsDuration(), timerType)}; - } - }; - QMetaObject::invokeMethod(this, invokable, Qt::QueuedConnection); - } else { - timerId = Qt::TimerId{startTimer(interval, 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 > Qt::TimerId::Invalid) - killTimer(std::exchange(timerId, Qt::TimerId::Invalid)); - - Q_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... - delete this; -} - QT_END_NAMESPACE #endif // QSINGLESHOTTIMER_P_H