1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <QtCore/private/qsingleshottimer_p.h>
6
7#include "qcoreapplication.h"
8#include "qmetaobject_p.h"
9#include "private/qnumeric_p.h"
10
11QT_BEGIN_NAMESPACE
12
13QSingleShotTimer::QSingleShotTimer(Duration interval, Qt::TimerType timerType,
14 const QObject *r, const char *member)
15 : QObject(QAbstractEventDispatcher::instance())
16{
17 connect(sender: this, SIGNAL(timeout()), receiver: r, member);
18 startTimerForReceiver(interval, timerType, receiver: r);
19}
20
21QSingleShotTimer::QSingleShotTimer(Duration interval, Qt::TimerType timerType,
22 const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
23 : QObject(QAbstractEventDispatcher::instance())
24{
25 int signal_index = QMetaObjectPrivate::signalOffset(m: &staticMetaObject);
26 Q_ASSERT(QMetaObjectPrivate::signal(&staticMetaObject, signal_index).name() == "timeout");
27 QObjectPrivate::connectImpl(sender: this, signal_index, receiver: r ? r : this, slot: nullptr, slotObj,
28 type: Qt::AutoConnection, types: nullptr, senderMetaObject: &staticMetaObject);
29
30 startTimerForReceiver(interval, timerType, receiver: r);
31}
32
33QSingleShotTimer::~QSingleShotTimer()
34{
35 if (timerId > Qt::TimerId::Invalid)
36 killTimer(id: timerId);
37}
38
39/*
40 Move the timer, and the dispatching and handling of the timer event, into
41 the same thread as where it will be handled, so that it fires reliably even
42 if the thread that set up the timer is busy.
43*/
44void QSingleShotTimer::startTimerForReceiver(Duration interval, Qt::TimerType timerType,
45 const QObject *receiver)
46{
47 if (receiver && receiver->thread() != thread()) {
48 // Avoid leaking the QSingleShotTimer instance in case the application exits before the
49 // timer fires
50 connect(sender: QCoreApplication::instance(), signal: &QCoreApplication::aboutToQuit, context: this,
51 slot: &QObject::deleteLater);
52 setParent(nullptr);
53 moveToThread(thread: receiver->thread());
54
55 QDeadlineTimer deadline(interval, timerType);
56 auto invokable = [this, deadline, timerType] {
57 if (deadline.hasExpired()) {
58 Q_EMIT timeout();
59 } else {
60 timerId = Qt::TimerId{startTimer(time: deadline.remainingTimeAsDuration(), timerType)};
61 }
62 };
63 QMetaObject::invokeMethod(object: this, function&: invokable, type: Qt::QueuedConnection);
64 } else {
65 timerId = Qt::TimerId{startTimer(time: interval, timerType)};
66 }
67}
68
69void QSingleShotTimer::timerEvent(QTimerEvent *)
70{
71 // need to kill the timer _before_ we emit timeout() in case the
72 // slot connected to timeout calls processEvents()
73 if (timerId > Qt::TimerId::Invalid)
74 killTimer(id: std::exchange(obj&: timerId, new_val: Qt::TimerId::Invalid));
75
76 Q_EMIT timeout();
77
78 // we would like to use delete later here, but it feels like a
79 // waste to post a new event to handle this event, so we just unset the flag
80 // and explicitly delete...
81 delete this;
82}
83
84QT_END_NAMESPACE
85
86#include "moc_qsingleshottimer_p.cpp"
87

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/kernel/qsingleshottimer.cpp