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