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

source code of qtbase/src/corelib/kernel/qobject_p.h