Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlnotifier_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#ifndef QQMLNOTIFIER_P_H
6#define QQMLNOTIFIER_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtCore/qmetaobject.h>
20#include <private/qmetaobject_p.h>
21#include <private/qtqmlglobal_p.h>
22
23QT_BEGIN_NAMESPACE
24
25class QQmlNotifierEndpoint;
26class QQmlData;
27class Q_QML_EXPORT QQmlNotifier
28{
29public:
30 inline QQmlNotifier();
31 inline ~QQmlNotifier();
32 inline void notify();
33
34 static void notify(QQmlData *ddata, int notifierIndex);
35
36private:
37 friend class QQmlData;
38 friend class QQmlNotifierEndpoint;
39 friend class QQmlThreadNotifierProxyObject;
40
41 static void emitNotify(QQmlNotifierEndpoint *, void **a);
42 QQmlNotifierEndpoint *endpoints = nullptr;
43};
44
45class QQmlEngine;
47{
50public:
51 // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks.
52 // To add another callback, extend this enum and add the callback to the top
53 // of qqmlnotifier.cpp. Four bits are reserved for the callback, so there can
54 // be up to 15 of them (0 is reserved).
64
65 inline QQmlNotifierEndpoint(Callback callback);
66 inline ~QQmlNotifierEndpoint();
67
68 inline bool isConnected() const;
69 inline bool isConnected(QObject *source, int sourceSignal) const;
70 inline bool isConnected(QQmlNotifier *) const;
71
72 void connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify = true);
73 inline void connect(QQmlNotifier *);
74 inline void disconnect();
75
76 inline bool isNotifying() const;
77 inline void startNotifying(qintptr *originalSenderPtr);
78 inline void stopNotifying(qintptr *originalSenderPtr);
79
80 inline void cancelNotify();
81
82 inline int signalIndex() const { return sourceSignal; }
83
84 inline qintptr sender() const;
85 inline void setSender(qintptr sender);
86
87 inline QObject *senderAsObject() const;
88 inline QQmlNotifier *senderAsNotifier() const;
89
90private:
91 friend class QQmlData;
92 friend class QQmlNotifier;
93
94 // Contains either the QObject*, or the QQmlNotifier* that this
95 // endpoint is connected to. While the endpoint is notifying, the
96 // senderPtr points to another qintptr that contains this value.
97 qintptr senderPtr;
98
99 Callback callback:4;
100 int needsConnectNotify:1;
101 // The index is in the range returned by QObjectPrivate::signalIndex().
102 // This is different from QMetaMethod::methodIndex().
103 signed int sourceSignal:27;
104};
105
106QQmlNotifier::QQmlNotifier()
107{
108}
109
110QQmlNotifier::~QQmlNotifier()
111{
112 QQmlNotifierEndpoint *endpoint = endpoints;
113 while (endpoint) {
114 QQmlNotifierEndpoint *n = endpoint;
115 endpoint = n->next;
116 n->setSender(0x0);
117 n->next = nullptr;
118 n->prev = nullptr;
119 n->sourceSignal = -1;
120 }
121 endpoints = nullptr;
122}
123
124void QQmlNotifier::notify()
125{
126 void *args[] = { nullptr };
127 if (endpoints) emitNotify(endpoints, args);
128}
129
131: next(nullptr), prev(nullptr), senderPtr(0), callback(callback), needsConnectNotify(false), sourceSignal(-1)
132{
133}
134
139
141{
142 return prev != nullptr;
143}
144
145/*! \internal
146 \a sourceSignal MUST be in the signal index range (see QObjectPrivate::signalIndex()).
147 This is different from QMetaMethod::methodIndex().
148*/
149bool QQmlNotifierEndpoint::isConnected(QObject *source, int sourceSignal) const
150{
151 return this->sourceSignal != -1 && senderAsObject() == source &&
152 this->sourceSignal == sourceSignal;
153}
154
155bool QQmlNotifierEndpoint::isConnected(QQmlNotifier *notifier) const
156{
157 return sourceSignal == -1 && senderAsNotifier() == notifier;
158}
159
160void QQmlNotifierEndpoint::connect(QQmlNotifier *notifier)
161{
162 disconnect();
163
164 next = notifier->endpoints;
165 if (next) { next->prev = &next; }
166 notifier->endpoints = this;
167 prev = &notifier->endpoints;
168 setSender(qintptr(notifier));
169}
170
172{
173 // Remove from notifier chain before calling disconnectNotify(), so that that
174 // QObject::receivers() returns the correct value in there
175 if (next) next->prev = prev;
176 if (prev) *prev = next;
177
178 if (sourceSignal != -1 && needsConnectNotify) {
179 QObject * const obj = senderAsObject();
180 Q_ASSERT(obj);
181 QObjectPrivate * const priv = QObjectPrivate::get(obj);
182
183 // In some degenerate cases an object being destructed might be unable
184 // to produce a metaObject(). Therefore we check here.
185 if (const QMetaObject *mo = obj->metaObject())
186 priv->disconnectNotify(QMetaObjectPrivate::signal(mo, sourceSignal));
187 }
188
189 setSender(0x0);
190 next = nullptr;
191 prev = nullptr;
192 sourceSignal = -1;
193}
194
195/*!
196Returns true if a notify is in progress. This means that the signal or QQmlNotifier
197that this endpoing is connected to has been triggered, but this endpoint's callback has not
198yet been called.
199
200An in progress notify can be cancelled by calling cancelNotify.
201*/
203{
204 return senderPtr & 0x1;
205}
206
207void QQmlNotifierEndpoint::startNotifying(qintptr *originalSenderPtr)
208{
209 Q_ASSERT(*originalSenderPtr == 0);
210 // Set the endpoint to notifying:
211 // - Save the original senderPtr,
212 *originalSenderPtr = senderPtr;
213 // - Take a pointer of it,
214 // - And assign that to the senderPtr, including a flag to signify "notifying".
215 senderPtr = qintptr(originalSenderPtr) | 0x1;
216}
217
218void QQmlNotifierEndpoint::stopNotifying(qintptr *originalSenderPtr)
219{
220 // End of notifying, restore values
221 Q_ASSERT((senderPtr & ~0x1) == qintptr(originalSenderPtr));
222 senderPtr = *originalSenderPtr;
223 *originalSenderPtr = 0;
224}
225
226/*!
227Cancel any notifies that are in progress.
228*/
230{
231 if (isNotifying()) {
232 auto *ptr = (qintptr *)(senderPtr & ~0x1);
233 Q_ASSERT(ptr);
234 senderPtr = *ptr;
235 *ptr = 0;
236 }
237}
238
240{
241 return isNotifying() ? *(qintptr *)(senderPtr & ~0x1) : senderPtr;
242}
243
244void QQmlNotifierEndpoint::setSender(qintptr sender)
245{
246 // If we're just notifying, we write through to the originalSenderPtr
247 if (isNotifying())
248 *(qintptr *)(senderPtr & ~0x1) = sender;
249 else
250 senderPtr = sender;
251}
252
254{
255 return (QObject *)(sender());
256}
257
259{
260 return (QQmlNotifier *)(sender());
261}
262
263QT_END_NAMESPACE
264
265#endif // QQMLNOTIFIER_P_H
void setSender(qintptr sender)
void cancelNotify()
Cancel any notifies that are in progress.
bool isNotifying() const
Returns true if a notify is in progress.
QObject * senderAsObject() const
void connect(QObject *source, int sourceSignal, QQmlEngine *engine, bool doNotify=true)
QQmlNotifier * senderAsNotifier() const
bool isConnected(QQmlNotifier *) const
void stopNotifying(qintptr *originalSenderPtr)
qintptr sender() const
void connect(QQmlNotifier *)
bool isConnected(QObject *source, int sourceSignal) const
void startNotifying(qintptr *originalSenderPtr)
QQmlNotifierEndpoint(Callback callback)
Combined button and popup list for selecting options.
void QQmlUnbindableToUnbindableGuard_callback(QQmlNotifierEndpoint *, void **)
void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *, void **)
void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **)
void QQmlUnbindableToBindableGuard_callback(QQmlNotifierEndpoint *, void **)
QT_BEGIN_NAMESPACE typedef void(* Callback)(QQmlNotifierEndpoint *, void **)
void QQmlDirtyReferenceObject_callback(QQmlNotifierEndpoint *, void **)
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **)
static Callback QQmlNotifier_callbacks[]