1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#ifndef QOBJECT_P_H
42#define QOBJECT_P_H
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists for the convenience
49// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
50// file may change from version to version without notice, or even be removed.
51//
52// We mean it.
53//
54
55#include <QtCore/private/qglobal_p.h>
56#include "QtCore/qobject.h"
57#include "QtCore/qpointer.h"
58#include "QtCore/qsharedpointer.h"
59#include "QtCore/qcoreevent.h"
60#include "QtCore/qlist.h"
61#include "QtCore/qvector.h"
62#include "QtCore/qvariant.h"
63#include "QtCore/qreadwritelock.h"
64
65QT_BEGIN_NAMESPACE
66
67class QVariant;
68class QThreadData;
69class QObjectConnectionListVector;
70namespace QtSharedPointer { struct ExternalRefCountData; }
71
72/* for Qt Test */
73struct QSignalSpyCallbackSet
74{
75 typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
76 typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
77 BeginCallback signal_begin_callback,
78 slot_begin_callback;
79 EndCallback signal_end_callback,
80 slot_end_callback;
81};
82void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set);
83
84extern Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set;
85
86enum { QObjectPrivateVersion = QT_VERSION };
87
88class Q_CORE_EXPORT QAbstractDeclarativeData
89{
90public:
91 static void (*destroyed)(QAbstractDeclarativeData *, QObject *);
92 static void (*destroyed_qml1)(QAbstractDeclarativeData *, QObject *);
93 static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *);
94 static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **);
95 static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int);
96 static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int);
97 static void (*setWidgetParent)(QObject *, QObject *); // Used by the QML engine to specify parents for widgets. Set by QtWidgets.
98};
99
100// This is an implementation of QAbstractDeclarativeData that is identical with
101// the implementation in QtDeclarative and QtQml for the first bit
102struct QAbstractDeclarativeDataImpl : public QAbstractDeclarativeData
103{
104 quint32 ownedByQml1:1;
105 quint32 unused: 31;
106};
107
108class Q_CORE_EXPORT QObjectPrivate : public QObjectData
109{
110 Q_DECLARE_PUBLIC(QObject)
111
112public:
113 struct ExtraData
114 {
115 ExtraData() {}
116 #ifndef QT_NO_USERDATA
117 QVector<QObjectUserData *> userData;
118 #endif
119 QList<QByteArray> propertyNames;
120 QVector<QVariant> propertyValues;
121 QVector<int> runningTimers;
122 QList<QPointer<QObject> > eventFilters;
123 QString objectName;
124 };
125
126 typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
127 struct Connection;
128 struct SignalVector;
129
130 struct ConnectionOrSignalVector {
131 union {
132 // linked list of orphaned connections that need cleaning up
133 ConnectionOrSignalVector *nextInOrphanList;
134 // linked list of connections connected to slots in this object
135 Connection *next;
136 };
137
138 static SignalVector *asSignalVector(ConnectionOrSignalVector *c) {
139 if (reinterpret_cast<quintptr>(c) & 1)
140 return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u));
141 return nullptr;
142 }
143 static Connection *fromSignalVector(SignalVector *v) {
144 return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u));
145 }
146 };
147
148 struct Connection : public ConnectionOrSignalVector
149 {
150 // linked list of connections connected to slots in this object, next is in base class
151 Connection **prev;
152 // linked list of connections connected to signals in this object
153 QAtomicPointer<Connection> nextConnectionList;
154 Connection *prevConnectionList;
155
156 QObject *sender;
157 QAtomicPointer<QObject> receiver;
158 QAtomicPointer<QThreadData> receiverThreadData;
159 union {
160 StaticMetaCallFunction callFunction;
161 QtPrivate::QSlotObjectBase *slotObj;
162 };
163 QAtomicPointer<const int> argumentTypes;
164 QAtomicInt ref_;
165 uint id = 0;
166 ushort method_offset;
167 ushort method_relative;
168 int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
169 ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
170 ushort isSlotObject : 1;
171 ushort ownArgumentTypes : 1;
172 Connection() : ref_(2), ownArgumentTypes(true) {
173 //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
174 }
175 ~Connection();
176 int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
177 void ref() { ref_.ref(); }
178 void freeSlotObject()
179 {
180 if (isSlotObject) {
181 slotObj->destroyIfLastRef();
182 isSlotObject = false;
183 }
184 }
185 void deref() {
186 if (!ref_.deref()) {
187 Q_ASSERT(!receiver.load());
188 Q_ASSERT(!isSlotObject);
189 delete this;
190 }
191 }
192 };
193 // ConnectionList is a singly-linked list
194 struct ConnectionList {
195 QAtomicPointer<Connection> first;
196 QAtomicPointer<Connection> last;
197 };
198
199 struct Sender
200 {
201 Sender(QObject *receiver, QObject *sender, int signal)
202 : receiver(receiver), sender(sender), signal(signal)
203 {
204 if (receiver) {
205 ConnectionData *cd = receiver->d_func()->connections.load();
206 previous = cd->currentSender;
207 cd->currentSender = this;
208 }
209 }
210 ~Sender()
211 {
212 if (receiver)
213 receiver->d_func()->connections.load()->currentSender = previous;
214 }
215 void receiverDeleted()
216 {
217 Sender *s = this;
218 while (s) {
219 s->receiver = nullptr;
220 s = s->previous;
221 }
222 }
223 Sender *previous;
224 QObject *receiver;
225 QObject *sender;
226 int signal;
227 };
228
229 struct SignalVector : public ConnectionOrSignalVector {
230 quintptr allocated;
231 // ConnectionList signals[]
232 ConnectionList &at(int i)
233 {
234 return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
235 }
236 const ConnectionList &at(int i) const
237 {
238 return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
239 }
240 int count() { return static_cast<int>(allocated); }
241 };
242
243
244
245 /*
246 This contains the all connections from and to an object.
247
248 The signalVector contains the lists of connections for a given signal. The index in the vector correspond
249 to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
250 QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
251 any signal emission. This is done by connecting to signal index -1.
252
253 This vector is protected by the object mutex (signalSlotLock())
254
255 Each Connection is also part of a 'senders' linked list. This one contains all connections connected
256 to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
257 linked list.
258 */
259 struct ConnectionData {
260 // the id below is used to avoid activating new connections. When the object gets
261 // deleted it's set to 0, so that signal emission stops
262 QAtomicInteger<uint> currentConnectionId;
263 QAtomicInt ref;
264 QAtomicPointer<SignalVector> signalVector;
265 Connection *senders = nullptr;
266 Sender *currentSender = nullptr; // object currently activating the object
267 QAtomicPointer<Connection> orphaned;
268
269 ~ConnectionData()
270 {
271 deleteOrphaned(orphaned.load());
272 SignalVector *v = signalVector.load();
273 if (v)
274 free(v);
275 }
276
277 // must be called on the senders connection data
278 // assumes the senders and receivers lock are held
279 void removeConnection(Connection *c);
280 void cleanOrphanedConnections(QObject *sender)
281 {
282 if (orphaned.load() && ref == 1)
283 cleanOrphanedConnectionsImpl(sender);
284 }
285 void cleanOrphanedConnectionsImpl(QObject *sender);
286
287 ConnectionList &connectionsForSignal(int signal)
288 {
289 return signalVector.load()->at(signal);
290 }
291
292 void resizeSignalVector(uint size) {
293 SignalVector *vector = this->signalVector.load();
294 if (vector && vector->allocated > size)
295 return;
296 size = (size + 7) & ~7;
297 SignalVector *newVector = reinterpret_cast<SignalVector *>(malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)));
298 int start = -1;
299 if (vector) {
300 memcpy(newVector, vector, sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList));
301 start = vector->count();
302 }
303 for (int i = start; i < int(size); ++i)
304 newVector->at(i) = ConnectionList();
305 newVector->next = nullptr;
306 newVector->allocated = size;
307
308 signalVector.store(newVector);
309 if (vector) {
310 vector->nextInOrphanList = orphaned.load();
311 orphaned.store(ConnectionOrSignalVector::fromSignalVector(vector));
312 }
313 }
314 int signalVectorCount() const {
315 return signalVector ? signalVector.load()->count() : -1;
316 }
317
318 static void deleteOrphaned(ConnectionOrSignalVector *c);
319 };
320
321 QObjectPrivate(int version = QObjectPrivateVersion);
322 virtual ~QObjectPrivate();
323 void deleteChildren();
324
325 void setParent_helper(QObject *);
326 void moveToThread_helper();
327 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
328 void _q_reregisterTimers(void *pointer);
329
330 bool isSender(const QObject *receiver, const char *signal) const;
331 QObjectList receiverList(const char *signal) const;
332 QObjectList senderList() const;
333
334 void addConnection(int signal, Connection *c);
335
336 static QObjectPrivate *get(QObject *o) {
337 return o->d_func();
338 }
339 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
340
341 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
342 bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
343 bool maybeSignalConnected(uint signalIndex) const;
344 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
345
346 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
347 // the API public in QObject. This is used by QQmlNotifierEndpoint.
348 inline void connectNotify(const QMetaMethod &signal);
349 inline void disconnectNotify(const QMetaMethod &signal);
350
351 template <typename Func1, typename Func2>
352 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
353 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
354 Qt::ConnectionType type = Qt::AutoConnection);
355
356 template <typename Func1, typename Func2>
357 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
358 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
359
360 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
361 const QObject *receiver, void **slot,
362 QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
363 const int *types, const QMetaObject *senderMetaObject);
364 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
365 static bool disconnect(const QObject *sender, int signal_index, void **slot);
366
367 void ensureConnectionData()
368 {
369 if (connections.load())
370 return;
371 ConnectionData *cd = new ConnectionData;
372 cd->ref.ref();
373 connections.store(cd);
374 }
375public:
376 ExtraData *extraData; // extra data set by the user
377 QThreadData *threadData; // id of the thread that owns the object
378
379 using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
380 QAtomicPointer<ConnectionData> connections;
381
382 union {
383 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
384 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
385 };
386
387 // these objects are all used to indicate that a QObject was deleted
388 // plus QPointer, which keeps a separate list
389 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
390};
391
392Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE);
393
394inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
395{
396 return declarativeData && QAbstractDeclarativeData::isSignalConnected
397 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
398}
399
400inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
401{
402 q_ptr->connectNotify(signal);
403}
404
405inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
406{
407 q_ptr->disconnectNotify(signal);
408}
409
410namespace QtPrivate {
411template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
412{
413 typedef QtPrivate::FunctionPointer<Func> FuncType;
414 Func function;
415 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
416 {
417 switch (which) {
418 case Destroy:
419 delete static_cast<QPrivateSlotObject*>(this_);
420 break;
421 case Call:
422 FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
423 static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
424 break;
425 case Compare:
426 *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
427 break;
428 case NumOperations: ;
429 }
430 }
431public:
432 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
433};
434} //namespace QtPrivate
435
436template <typename Func1, typename Func2>
437inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
438 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
439 Qt::ConnectionType type)
440{
441 typedef QtPrivate::FunctionPointer<Func1> SignalType;
442 typedef QtPrivate::FunctionPointer<Func2> SlotType;
443 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
444 "No Q_OBJECT in the class with the signal");
445
446 //compilation error if the arguments does not match.
447 Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
448 "The slot requires more arguments than the signal provides.");
449 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
450 "Signal and slot arguments are not compatible.");
451 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
452 "Return type of the slot is not compatible with the return type of the signal.");
453
454 const int *types = nullptr;
455 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
456 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
457
458 return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
459 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
460 new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
461 typename SignalType::ReturnType>(slot),
462 type, types, &SignalType::Object::staticMetaObject);
463}
464
465template <typename Func1, typename Func2>
466bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
467 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
468{
469 typedef QtPrivate::FunctionPointer<Func1> SignalType;
470 typedef QtPrivate::FunctionPointer<Func2> SlotType;
471 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
472 "No Q_OBJECT in the class with the signal");
473 //compilation error if the arguments does not match.
474 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
475 "Signal and slot arguments are not compatible.");
476 return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
477 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
478 &SignalType::Object::staticMetaObject);
479}
480
481Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
482Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
483
484class QSemaphore;
485class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent
486{
487public:
488 QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr)
489 : QEvent(MetaCall), signalId_(signalId), sender_(sender), semaphore_(semaphore)
490 {}
491 ~QAbstractMetaCallEvent();
492
493 virtual void placeMetaCall(QObject *object) = 0;
494
495 inline const QObject *sender() const { return sender_; }
496 inline int signalId() const { return signalId_; }
497
498private:
499 int signalId_;
500 const QObject *sender_;
501 QSemaphore *semaphore_;
502};
503
504class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
505{
506public:
507 QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId,
508 int nargs = 0, int *types = nullptr, void **args = nullptr, QSemaphore *semaphore = nullptr);
509 /*! \internal
510 \a signalId is in the signal index range (see QObjectPrivate::signalIndex()).
511 */
512 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId,
513 int nargs = 0, int *types = nullptr, void **args = nullptr, QSemaphore *semaphore = nullptr);
514
515 ~QMetaCallEvent() override;
516
517 inline int id() const { return method_offset_ + method_relative_; }
518 inline void **args() const { return args_; }
519
520 virtual void placeMetaCall(QObject *object) override;
521
522private:
523 QtPrivate::QSlotObjectBase *slotObj_;
524 int nargs_;
525 int *types_;
526 void **args_;
527 QObjectPrivate::StaticMetaCallFunction callFunction_;
528 ushort method_offset_;
529 ushort method_relative_;
530};
531
532class QBoolBlocker
533{
534 Q_DISABLE_COPY_MOVE(QBoolBlocker)
535public:
536 explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
537 inline ~QBoolBlocker(){block = reset; }
538private:
539 bool &block;
540 bool reset;
541};
542
543void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
544
545struct QAbstractDynamicMetaObject;
546struct Q_CORE_EXPORT QDynamicMetaObjectData
547{
548 virtual ~QDynamicMetaObjectData();
549 virtual void objectDestroyed(QObject *) { delete this; }
550
551 virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
552 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
553};
554
555struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
556{
557 ~QAbstractDynamicMetaObject();
558
559 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
560 virtual int createProperty(const char *, const char *) { return -1; }
561 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
562 { return metaCall(c, _id, a); }
563 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
564};
565
566QT_END_NAMESPACE
567
568#endif // QOBJECT_P_H
569