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
qobject_p.h
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QOBJECT_P_H
6#define QOBJECT_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 for the convenience
13// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
14// file may change from version to version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtCore/private/qglobal_p.h>
20#include "QtCore/qcoreevent.h"
21#include <QtCore/qfunctionaltools_impl.h>
22#include "QtCore/qlist.h"
23#include "QtCore/qobject.h"
24#include "QtCore/qpointer.h"
25#include "QtCore/qvariant.h"
26#include "QtCore/qproperty.h"
27#include <QtCore/qshareddata.h>
28#include "QtCore/private/qproperty_p.h"
29
30#include <string>
31
32QT_BEGIN_NAMESPACE
33
34#ifdef Q_MOC_RUN
35#define QT_ANONYMOUS_PROPERTY(text) QT_ANONYMOUS_PROPERTY(text)
36#define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANONYMOUS_PRIVATE_PROPERTY(d, text)
37#elif !defined QT_NO_META_MACROS
38#define QT_ANONYMOUS_PROPERTY(...) QT_ANNOTATE_CLASS(qt_anonymous_property, __VA_ARGS__)
39#define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANNOTATE_CLASS2(qt_anonymous_private_property, d, text)
40#endif
41
42#define QT_CONCAT(B, M, m, u) QT_CONCAT2(B, M, m, u)
43#define QT_CONCAT2(B, M, m, u) B ## M ## _ ## m ## _ ## u
44#if defined(QT_BUILD_INTERNAL) && !QT_CONFIG(elf_private_full_version)
45// Don't check the version parameter in internal builds.
46// This allows incompatible versions to be loaded, possibly for testing.
47enum QObjectPrivateVersionEnum
48#else
49enum QT_CONCAT(QtPrivate_, QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH)
50#endif
51{ QObjectPrivateVersion = QT_VERSION };
52#undef QT_CONCAT
53#undef QT_CONCAT2
54
55class QVariant;
56class QThreadData;
57class QObjectConnectionListVector;
59
60/* for Qt Test */
62{
63 typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
64 typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
69};
70void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set);
71
72extern Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set;
73
74class Q_CORE_EXPORT QAbstractDeclarativeData
75{
76public:
77 static void (*destroyed)(QAbstractDeclarativeData *, QObject *);
78 static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **);
79 static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int);
80 static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int);
81 static void (*setWidgetParent)(QObject *, QObject *); // Used by the QML engine to specify parents for widgets. Set by QtWidgets.
82};
83
84class Q_CORE_EXPORT QObjectPrivate : public QObjectData
85{
86public:
87 Q_DECLARE_PUBLIC(QObject)
88
89 struct ExtraData
90 {
91 ExtraData(QObjectPrivate *ptr) : parent(ptr) { }
92
93 inline void setObjectNameForwarder(const QString &name)
94 {
95 parent->q_func()->setObjectName(name);
96 }
97
98 inline void nameChangedForwarder(const QString &name)
99 {
100 Q_EMIT parent->q_func()->objectNameChanged(name, QObject::QPrivateSignal());
101 }
102
103 QList<QByteArray> propertyNames;
104 QList<QVariant> propertyValues;
105 QList<Qt::TimerId> runningTimers;
106 QList<QPointer<QObject>> eventFilters;
107 Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, objectName,
108 &QObjectPrivate::ExtraData::setObjectNameForwarder,
109 &QObjectPrivate::ExtraData::nameChangedForwarder)
110 QObjectPrivate *parent;
111 };
112
113 void ensureExtraData()
114 {
115 if (!extraData)
116 extraData = new ExtraData(this);
117 }
118 void setObjectNameWithoutBindings(const QString &name);
119
120 typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
121 struct Connection;
122 struct ConnectionData;
123 struct ConnectionList;
124 struct ConnectionOrSignalVector;
125 struct SignalVector;
126 struct Sender;
127 struct TaggedSignalVector;
128
129 /*
130 This contains the all connections from and to an object.
131
132 The signalVector contains the lists of connections for a given signal. The index in the vector correspond
133 to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
134 QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
135 any signal emission. This is done by connecting to signal index -1.
136
137 This vector is protected by the object mutex (signalSlotLock())
138
139 Each Connection is also part of a 'senders' linked list. This one contains all connections connected
140 to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
141 linked list.
142 */
143
144 QObjectPrivate(decltype(QObjectPrivateVersion) version = QObjectPrivateVersion);
145 virtual ~QObjectPrivate();
146 void deleteChildren();
147 // used to clear binding storage early in ~QObject
148 void clearBindingStorage();
149
150 void setParent_helper(QObject *);
151 void moveToThread_helper();
152 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status);
153
154 QObjectList receiverList(const char *signal) const;
155
156 inline void ensureConnectionData();
157 inline void addConnection(int signal, Connection *c);
158 static inline bool removeConnection(Connection *c);
159
160 static QObjectPrivate *get(QObject *o) { return o->d_func(); }
161 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
162
163 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
164 bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
165 bool maybeSignalConnected(uint signalIndex) const;
166 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
167
168 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
169 // the API public in QObject. This is used by QQmlNotifierEndpoint.
170 inline void connectNotify(const QMetaMethod &signal);
171 inline void disconnectNotify(const QMetaMethod &signal);
172
173 void reinitBindingStorageAfterThreadMove();
174
175 template <typename Func1, typename Func2>
176 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
177 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
178 Qt::ConnectionType type = Qt::AutoConnection);
179
180 template <typename Func1, typename Func2>
181 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
182 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
183
184 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
185 const QObject *receiver, void **slot,
186 QtPrivate::QSlotObjectBase *slotObj, int type,
187 const int *types, const QMetaObject *senderMetaObject);
188 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
189 static QMetaObject::Connection connect(const QObject *sender, int signal_index,
190 const QObject *receiver,
191 QtPrivate::QSlotObjectBase *slotObj,
192 Qt::ConnectionType type);
193 static bool disconnect(const QObject *sender, int signal_index, void **slot);
194 static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver,
195 void **slot);
196
197 virtual std::string flagsForDumping() const;
198
199#ifndef QT_NO_DEBUG_STREAM
200 virtual void writeToDebugStream(QDebug &) const;
201#endif
202
203 QtPrivate::QPropertyAdaptorSlotObject *
204 getPropertyAdaptorSlotObject(const QMetaProperty &property);
205
206public:
207 mutable ExtraData *extraData; // extra data set by the user
208 // This atomic requires acquire/release semantics in a few places,
209 // e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
210 // because postEvent is thread-safe.
211 // However, most of the code paths involving QObject are only reentrant and
212 // not thread-safe, so synchronization should not be necessary there.
213 QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object
214
215 using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
216 QAtomicPointer<ConnectionData> connections;
217
218 union {
219 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
220 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
221 };
222
223 // these objects are all used to indicate that a QObject was deleted
224 // plus QPointer, which keeps a separate list
225 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
226};
227
228inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
229{
230 return !isDeletingChildren && declarativeData && QAbstractDeclarativeData::isSignalConnected
231 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
232}
233
234inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
235{
236 q_ptr->connectNotify(signal);
237}
238
239inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
240{
241 q_ptr->disconnectNotify(signal);
242}
243
244namespace QtPrivate {
245inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); }
246
247template <typename Func>
249
250template <typename ObjPrivate> inline void assertObjectType(QObjectPrivate *d)
251{
252 using Obj = std::remove_pointer_t<decltype(std::declval<ObjPrivate *>()->q_func())>;
254}
255
256template<typename Func, typename Args, typename R>
258{
259 typedef QtPrivate::FunctionPointer<Func> FuncType;
260#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
261 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
262#else
263 static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret)
264#endif
265 {
266 const auto that = static_cast<QPrivateSlotObject*>(this_);
267 switch (which) {
268 case Destroy:
269 delete that;
270 break;
271 case Call:
272 FuncType::template call<Args, R>(that->object(),
273 static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
274 break;
275 case Compare:
276 *ret = *reinterpret_cast<Func *>(a) == that->object();
277 break;
278 case NumOperations: ;
279 }
280 }
281public:
283};
284} //namespace QtPrivate
285
286template <typename Func1, typename Func2>
287inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
288 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
289 Qt::ConnectionType type)
290{
291 typedef QtPrivate::FunctionPointer<Func1> SignalType;
292 typedef QtPrivate::FunctionPointer<Func2> SlotType;
293 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
294 "No Q_OBJECT in the class with the signal");
295
296 //compilation error if the arguments does not match.
297 static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
298 "The slot requires more arguments than the signal provides.");
299 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
300 "Signal and slot arguments are not compatible.");
301 static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
302 "Return type of the slot is not compatible with the return type of the signal.");
303
304 const int *types = nullptr;
305 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
306 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
307
308 return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
309 QtPrivate::getQObject(receiverPrivate), reinterpret_cast<void **>(&slot),
310 new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
311 typename SignalType::ReturnType>(slot),
312 type, types, &SignalType::Object::staticMetaObject);
313}
314
315template <typename Func1, typename Func2>
316bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
317 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
318{
319 typedef QtPrivate::FunctionPointer<Func1> SignalType;
320 typedef QtPrivate::FunctionPointer<Func2> SlotType;
321 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
322 "No Q_OBJECT in the class with the signal");
323 //compilation error if the arguments does not match.
324 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
325 "Signal and slot arguments are not compatible.");
326 return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
327 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
328 &SignalType::Object::staticMetaObject);
329}
330
331class QSemaphore;
332class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent
333{
334public:
335 QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr)
336 : QEvent(MetaCall), signalId_(signalId), sender_(sender)
337#if QT_CONFIG(thread)
338 , semaphore_(semaphore)
339#endif
340 { Q_UNUSED(semaphore); }
341 ~QAbstractMetaCallEvent();
342
343 virtual void placeMetaCall(QObject *object) = 0;
344
345 inline const QObject *sender() const { return sender_; }
346 inline int signalId() const { return signalId_; }
347
348private:
349 int signalId_;
350 const QObject *sender_;
351#if QT_CONFIG(thread)
352 QSemaphore *semaphore_;
353#endif
354};
355
356class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
357{
358public:
359 // blocking queued with semaphore - args always owned by caller
360 QMetaCallEvent(ushort method_offset, ushort method_relative,
361 QObjectPrivate::StaticMetaCallFunction callFunction,
362 const QObject *sender, int signalId,
363 void **args, QSemaphore *semaphore);
364 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
365 const QObject *sender, int signalId,
366 void **args, QSemaphore *semaphore);
367 QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
368 const QObject *sender, int signalId,
369 void **args, QSemaphore *semaphore);
370
371 // queued - args allocated by event, copied by caller
372 QMetaCallEvent(ushort method_offset, ushort method_relative,
373 QObjectPrivate::StaticMetaCallFunction callFunction,
374 const QObject *sender, int signalId,
375 int nargs);
376 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
377 const QObject *sender, int signalId,
378 int nargs);
379 QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
380 const QObject *sender, int signalId,
381 int nargs);
382
383 ~QMetaCallEvent() override;
384
385 template<typename ...Args>
386 static QMetaCallEvent *create(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender,
387 int signal_index, const Args &...argv)
388 {
389 const void* const argp[] = { nullptr, std::addressof(argv)... };
390 const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... };
391 constexpr auto argc = sizeof...(Args) + 1;
392 return create_impl(slotObj, sender, signal_index, argc, argp, metaTypes);
393 }
394 template<typename ...Args>
395 static QMetaCallEvent *create(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender,
396 int signal_index, const Args &...argv)
397 {
398 const void* const argp[] = { nullptr, std::addressof(argv)... };
399 const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... };
400 constexpr auto argc = sizeof...(Args) + 1;
401 return create_impl(std::move(slotObj), sender, signal_index, argc, argp, metaTypes);
402 }
403
404 inline int id() const { return d.method_offset_ + d.method_relative_; }
405 inline const void * const* args() const { return d.args_; }
406 inline void ** args() { return d.args_; }
407 inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
408 inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
409
410 virtual void placeMetaCall(QObject *object) override;
411
412private:
413 static QMetaCallEvent *create_impl(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender,
414 int signal_index, size_t argc, const void * const argp[],
415 const QMetaType metaTypes[])
416 {
417 if (slotObj)
418 slotObj->ref();
419 return create_impl(QtPrivate::SlotObjUniquePtr{slotObj}, sender,
420 signal_index, argc, argp, metaTypes);
421 }
422 static QMetaCallEvent *create_impl(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender,
423 int signal_index, size_t argc, const void * const argp[],
424 const QMetaType metaTypes[]);
425 inline void allocArgs();
426
427 struct Data {
428 QtPrivate::SlotObjUniquePtr slotObj_;
429 void **args_;
430 QObjectPrivate::StaticMetaCallFunction callFunction_;
431 int nargs_;
432 ushort method_offset_;
433 ushort method_relative_;
434 } d;
435 // preallocate enough space for three arguments
436 alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)];
437};
438
439struct QAbstractDynamicMetaObject;
440struct Q_CORE_EXPORT QDynamicMetaObjectData
441{
442 virtual ~QDynamicMetaObjectData();
443 virtual void objectDestroyed(QObject *) { delete this; }
444
445#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
446 virtual const QMetaObject *toDynamicMetaObject(QObject *) const = 0;
447#else
448 virtual QMetaObject *toDynamicMetaObject(QObject *) = 0;
449#endif
450 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
451};
452
453struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
454{
455 ~QAbstractDynamicMetaObject();
456
457#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
458 const QMetaObject *toDynamicMetaObject(QObject *) const override { return this; }
459#else
460 QMetaObject *toDynamicMetaObject(QObject *) override { return this; }
461#endif
462 virtual int createProperty(const char *, const char *) { return -1; }
463 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
464 { return metaCall(c, _id, a); }
465 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
466};
467
468inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate *o)
469{
470 return &o->bindingStorage;
471}
472inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o)
473{
474 return &o->bindingStorage;
475}
476inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate::ExtraData *ed)
477{
478 return &ed->parent->bindingStorage;
479}
480inline QBindingStorage *qGetBindingStorage(QObjectPrivate::ExtraData *ed)
481{
482 return &ed->parent->bindingStorage;
483}
484
485QT_END_NAMESPACE
486
487#endif // QOBJECT_P_H
\inmodule QtCore
~QTimerPrivate() override
QTimerPrivate(QTimer *qq)
Definition qtimer_p.h:27
void setIntervalDuration(std::chrono::nanoseconds nsec)
Definition qtimer_p.h:42
static constexpr int INV_TIMER
Definition qtimer_p.h:40
void setInterval(int msec)
Definition qtimer_p.h:52
bool isActive() const
Definition qtimer_p.h:58
const bool isQTimer
Definition qtimer_p.h:70
QTimerPrivate(std::chrono::nanoseconds nsec, QChronoTimer *qq)
Definition qtimer_p.h:32
Qt::TimerId id
Definition qtimer_p.h:60
\inmodule QtCore
Definition qtimer.h:20
Combined button and popup list for selecting options.
void assertObjectType(QObjectPrivate *d)
Definition qobject_p.h:250
const QObject * getQObject(const QObjectPrivate *d)
Definition qobject_p.h:245
#define QT_CONCAT(B, M, m, u)
Definition qobject_p.h:42
QBindingStorage * qGetBindingStorage(QObjectPrivate *o)
Definition qobject_p.h:472
QBindingStorage * qGetBindingStorage(QObjectPrivate::ExtraData *ed)
Definition qobject_p.h:480
const QBindingStorage * qGetBindingStorage(const QObjectPrivate *o)
Definition qobject_p.h:468
#define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...)
Definition qproperty.h:1267
#define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...)
Definition qproperty.h:1356
#define Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(...)
void(* BeginCallback)(QObject *caller, int signal_or_method_index, void **argv)
Definition qobject_p.h:63
BeginCallback slot_begin_callback
Definition qobject_p.h:66
EndCallback slot_end_callback
Definition qobject_p.h:68
EndCallback signal_end_callback
Definition qobject_p.h:67
BeginCallback signal_begin_callback
Definition qobject_p.h:65
void(* EndCallback)(QObject *caller, int signal_or_method_index)
Definition qobject_p.h:64