1/****************************************************************************
2**
3** Copyright (C) 2017 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 {
129 QObject *sender;
130 QObject *receiver;
131 union {
132 StaticMetaCallFunction callFunction;
133 QtPrivate::QSlotObjectBase *slotObj;
134 };
135 // The next pointer for the singly-linked ConnectionList
136 Connection *nextConnectionList;
137 //senders linked list
138 Connection *next;
139 Connection **prev;
140 QAtomicPointer<const int> argumentTypes;
141 QAtomicInt ref_;
142 ushort method_offset;
143 ushort method_relative;
144 uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
145 ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
146 ushort isSlotObject : 1;
147 ushort ownArgumentTypes : 1;
148 Connection() : nextConnectionList(nullptr), ref_(2), ownArgumentTypes(true) {
149 //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
150 }
151 ~Connection();
152 int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
153 void ref() { ref_.ref(); }
154 void deref() {
155 if (!ref_.deref()) {
156 Q_ASSERT(!receiver);
157 delete this;
158 }
159 }
160 };
161 // ConnectionList is a singly-linked list
162 struct ConnectionList {
163 ConnectionList() : first(nullptr), last(nullptr) {}
164 Connection *first;
165 Connection *last;
166 };
167
168 struct Sender
169 {
170 Sender(QObject *receiver, QObject *sender, int signal)
171 : receiver(receiver), sender(sender), signal(signal)
172 {
173 if (receiver) {
174 ConnectionData *cd = receiver->d_func()->connections.load();
175 previous = cd->currentSender;
176 cd->currentSender = this;
177 }
178 }
179 ~Sender()
180 {
181 if (receiver)
182 receiver->d_func()->connections.load()->currentSender = previous;
183 }
184 void receiverDeleted()
185 {
186 Sender *s = this;
187 while (s) {
188 s->receiver = nullptr;
189 s = s->previous;
190 }
191 }
192 Sender *previous;
193 QObject *receiver;
194 QObject *sender;
195 int signal;
196 };
197
198 /*
199 This contains the all connections from and to an object.
200
201 The signalVector contains the lists of connections for a given signal. The index in the vector correspond
202 to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
203 QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
204 any signal emission. This is done by connecting to signal index -1.
205
206 This vector is protected by the object mutex (signalSlotLock())
207
208 Each Connection is also part of a 'senders' linked list. This one contains all connections connected
209 to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
210 linked list.
211 */
212 struct ConnectionData {
213 bool objectDeleted = false; //the QObject owner of this vector has been destroyed while the vector was inUse
214 struct Ref {
215 int _ref = 0;
216 void ref() { ++_ref; }
217 int deref() { return --_ref; }
218 operator int() const { return _ref; }
219 };
220
221 Ref ref;
222 bool dirty = false; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
223 ConnectionList allsignals;
224 QVector<ConnectionList> signalVector;
225 Connection *senders = nullptr;
226 Sender *currentSender = nullptr; // object currently activating the object
227
228 ConnectionList &connectionsForSignal(int signal)
229 {
230 return signal < 0 ? allsignals : signalVector[signal];
231 }
232 };
233
234 QObjectPrivate(int version = QObjectPrivateVersion);
235 virtual ~QObjectPrivate();
236 void deleteChildren();
237
238 void setParent_helper(QObject *);
239 void moveToThread_helper();
240 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
241 void _q_reregisterTimers(void *pointer);
242
243 bool isSender(const QObject *receiver, const char *signal) const;
244 QObjectList receiverList(const char *signal) const;
245 QObjectList senderList() const;
246
247 void addConnection(int signal, Connection *c);
248 void cleanConnectionLists();
249
250 static QObjectPrivate *get(QObject *o) {
251 return o->d_func();
252 }
253 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
254
255 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
256 bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
257 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
258
259 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
260 // the API public in QObject. This is used by QQmlNotifierEndpoint.
261 inline void connectNotify(const QMetaMethod &signal);
262 inline void disconnectNotify(const QMetaMethod &signal);
263
264 template <typename Func1, typename Func2>
265 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
266 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
267 Qt::ConnectionType type = Qt::AutoConnection);
268
269 template <typename Func1, typename Func2>
270 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
271 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
272
273 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
274 const QObject *receiver, void **slot,
275 QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
276 const int *types, const QMetaObject *senderMetaObject);
277 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
278 static bool disconnect(const QObject *sender, int signal_index, void **slot);
279
280 void ensureConnectionData()
281 {
282 if (connections.load())
283 return;
284 ConnectionData *cd = new ConnectionData;
285 cd->ref.ref();
286 connections.store(cd);
287 }
288public:
289 ExtraData *extraData; // extra data set by the user
290 QThreadData *threadData; // id of the thread that owns the object
291
292 using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
293 QAtomicPointer<ConnectionData> connections;
294
295 union {
296 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
297 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
298 };
299
300 // these objects are all used to indicate that a QObject was deleted
301 // plus QPointer, which keeps a separate list
302 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
303};
304
305Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE);
306
307inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
308{
309 return declarativeData && QAbstractDeclarativeData::isSignalConnected
310 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
311}
312
313inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
314{
315 q_ptr->connectNotify(signal);
316}
317
318inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
319{
320 q_ptr->disconnectNotify(signal);
321}
322
323namespace QtPrivate {
324template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
325{
326 typedef QtPrivate::FunctionPointer<Func> FuncType;
327 Func function;
328 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
329 {
330 switch (which) {
331 case Destroy:
332 delete static_cast<QPrivateSlotObject*>(this_);
333 break;
334 case Call:
335 FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
336 static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
337 break;
338 case Compare:
339 *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
340 break;
341 case NumOperations: ;
342 }
343 }
344public:
345 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
346};
347} //namespace QtPrivate
348
349template <typename Func1, typename Func2>
350inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
351 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
352 Qt::ConnectionType type)
353{
354 typedef QtPrivate::FunctionPointer<Func1> SignalType;
355 typedef QtPrivate::FunctionPointer<Func2> SlotType;
356 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
357 "No Q_OBJECT in the class with the signal");
358
359 //compilation error if the arguments does not match.
360 Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
361 "The slot requires more arguments than the signal provides.");
362 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
363 "Signal and slot arguments are not compatible.");
364 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
365 "Return type of the slot is not compatible with the return type of the signal.");
366
367 const int *types = nullptr;
368 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
369 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
370
371 return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
372 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
373 new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
374 typename SignalType::ReturnType>(slot),
375 type, types, &SignalType::Object::staticMetaObject);
376}
377
378template <typename Func1, typename Func2>
379bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
380 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
381{
382 typedef QtPrivate::FunctionPointer<Func1> SignalType;
383 typedef QtPrivate::FunctionPointer<Func2> SlotType;
384 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
385 "No Q_OBJECT in the class with the signal");
386 //compilation error if the arguments does not match.
387 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
388 "Signal and slot arguments are not compatible.");
389 return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
390 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
391 &SignalType::Object::staticMetaObject);
392}
393
394Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
395Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
396
397class QSemaphore;
398class Q_CORE_EXPORT QMetaCallEvent : public QEvent
399{
400public:
401 QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId,
402 int nargs = 0, int *types = nullptr, void **args = nullptr, QSemaphore *semaphore = nullptr);
403 /*! \internal
404 \a signalId is in the signal index range (see QObjectPrivate::signalIndex()).
405 */
406 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId,
407 int nargs = 0, int *types = nullptr, void **args = nullptr, QSemaphore *semaphore = nullptr);
408
409 ~QMetaCallEvent();
410
411 inline int id() const { return method_offset_ + method_relative_; }
412 inline const QObject *sender() const { return sender_; }
413 inline int signalId() const { return signalId_; }
414 inline void **args() const { return args_; }
415
416 virtual void placeMetaCall(QObject *object);
417
418private:
419 QtPrivate::QSlotObjectBase *slotObj_;
420 const QObject *sender_;
421 int signalId_;
422 int nargs_;
423 int *types_;
424 void **args_;
425 QSemaphore *semaphore_;
426 QObjectPrivate::StaticMetaCallFunction callFunction_;
427 ushort method_offset_;
428 ushort method_relative_;
429};
430
431class QBoolBlocker
432{
433 Q_DISABLE_COPY_MOVE(QBoolBlocker)
434public:
435 explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
436 inline ~QBoolBlocker(){block = reset; }
437private:
438 bool &block;
439 bool reset;
440};
441
442void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
443
444struct QAbstractDynamicMetaObject;
445struct Q_CORE_EXPORT QDynamicMetaObjectData
446{
447 virtual ~QDynamicMetaObjectData();
448 virtual void objectDestroyed(QObject *) { delete this; }
449
450 virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
451 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
452};
453
454struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
455{
456 ~QAbstractDynamicMetaObject();
457
458 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
459 virtual int createProperty(const char *, const char *) { return -1; }
460 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
461 { return metaCall(c, _id, a); }
462 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
463};
464
465QT_END_NAMESPACE
466
467#endif // QOBJECT_P_H
468