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(const QSignalSpyCallbackSet &callback_set);
83
84extern QSignalSpyCallbackSet Q_CORE_EXPORT 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 QObject *sender;
171 int signal;
172 int ref;
173 };
174
175
176 QObjectPrivate(int version = QObjectPrivateVersion);
177 virtual ~QObjectPrivate();
178 void deleteChildren();
179
180 void setParent_helper(QObject *);
181 void moveToThread_helper();
182 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
183 void _q_reregisterTimers(void *pointer);
184
185 bool isSender(const QObject *receiver, const char *signal) const;
186 QObjectList receiverList(const char *signal) const;
187 QObjectList senderList() const;
188
189 void addConnection(int signal, Connection *c);
190 void cleanConnectionLists();
191
192 static inline Sender *setCurrentSender(QObject *receiver,
193 Sender *sender);
194 static inline void resetCurrentSender(QObject *receiver,
195 Sender *currentSender,
196 Sender *previousSender);
197
198 static QObjectPrivate *get(QObject *o) {
199 return o->d_func();
200 }
201 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
202
203 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
204 inline bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
205 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
206
207 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
208 // the API public in QObject. This is used by QQmlNotifierEndpoint.
209 inline void connectNotify(const QMetaMethod &signal);
210 inline void disconnectNotify(const QMetaMethod &signal);
211
212 template <typename Func1, typename Func2>
213 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
214 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
215 Qt::ConnectionType type = Qt::AutoConnection);
216
217 template <typename Func1, typename Func2>
218 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
219 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
220
221 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
222 const QObject *receiver, void **slot,
223 QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
224 const int *types, const QMetaObject *senderMetaObject);
225 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
226 static bool disconnect(const QObject *sender, int signal_index, void **slot);
227public:
228 ExtraData *extraData; // extra data set by the user
229 QThreadData *threadData; // id of the thread that owns the object
230
231 QObjectConnectionListVector *connectionLists;
232
233 Connection *senders; // linked list of connections connected to this object
234 Sender *currentSender; // object currently activating the object
235 mutable quint32 connectedSignals[2];
236
237 union {
238 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
239 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
240 };
241
242 // these objects are all used to indicate that a QObject was deleted
243 // plus QPointer, which keeps a separate list
244 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
245};
246
247Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE);
248
249/*! \internal
250
251 Returns \c true if the signal with index \a signal_index from object \a sender is connected.
252 Signals with indices above a certain range are always considered connected (see connectedSignals
253 in QObjectPrivate).
254
255 \a signal_index must be the index returned by QObjectPrivate::signalIndex;
256*/
257inline bool QObjectPrivate::isSignalConnected(uint signal_index, bool checkDeclarative) const
258{
259 return signal_index >= sizeof(connectedSignals) * 8
260 || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f))
261 || (checkDeclarative && isDeclarativeSignalConnected(signal_index)));
262}
263
264inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
265{
266 return declarativeData && QAbstractDeclarativeData::isSignalConnected
267 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
268}
269
270inline QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver,
271 Sender *sender)
272{
273 Sender *previousSender = receiver->d_func()->currentSender;
274 receiver->d_func()->currentSender = sender;
275 return previousSender;
276}
277
278inline void QObjectPrivate::resetCurrentSender(QObject *receiver,
279 Sender *currentSender,
280 Sender *previousSender)
281{
282 // ref is set to zero when this object is deleted during the metacall
283 if (currentSender->ref == 1)
284 receiver->d_func()->currentSender = previousSender;
285 // if we've recursed, we need to tell the caller about the objects deletion
286 if (previousSender)
287 previousSender->ref = currentSender->ref;
288}
289
290inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
291{
292 q_ptr->connectNotify(signal);
293}
294
295inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
296{
297 q_ptr->disconnectNotify(signal);
298}
299
300namespace QtPrivate {
301template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
302{
303 typedef QtPrivate::FunctionPointer<Func> FuncType;
304 Func function;
305 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
306 {
307 switch (which) {
308 case Destroy:
309 delete static_cast<QPrivateSlotObject*>(this_);
310 break;
311 case Call:
312 FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
313 static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
314 break;
315 case Compare:
316 *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
317 break;
318 case NumOperations: ;
319 }
320 }
321public:
322 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
323};
324} //namespace QtPrivate
325
326template <typename Func1, typename Func2>
327inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
328 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
329 Qt::ConnectionType type)
330{
331 typedef QtPrivate::FunctionPointer<Func1> SignalType;
332 typedef QtPrivate::FunctionPointer<Func2> SlotType;
333 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
334 "No Q_OBJECT in the class with the signal");
335
336 //compilation error if the arguments does not match.
337 Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
338 "The slot requires more arguments than the signal provides.");
339 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
340 "Signal and slot arguments are not compatible.");
341 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
342 "Return type of the slot is not compatible with the return type of the signal.");
343
344 const int *types = nullptr;
345 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
346 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
347
348 return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
349 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
350 new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
351 typename SignalType::ReturnType>(slot),
352 type, types, &SignalType::Object::staticMetaObject);
353}
354
355template <typename Func1, typename Func2>
356bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
357 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
358{
359 typedef QtPrivate::FunctionPointer<Func1> SignalType;
360 typedef QtPrivate::FunctionPointer<Func2> SlotType;
361 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
362 "No Q_OBJECT in the class with the signal");
363 //compilation error if the arguments does not match.
364 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
365 "Signal and slot arguments are not compatible.");
366 return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
367 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
368 &SignalType::Object::staticMetaObject);
369}
370
371Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
372Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
373
374class QSemaphore;
375class Q_CORE_EXPORT QMetaCallEvent : public QEvent
376{
377public:
378 QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId,
379 int nargs = 0, int *types = nullptr, void **args = nullptr, QSemaphore *semaphore = nullptr);
380 /*! \internal
381 \a signalId is in the signal index range (see QObjectPrivate::signalIndex()).
382 */
383 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId,
384 int nargs = 0, int *types = nullptr, void **args = nullptr, QSemaphore *semaphore = nullptr);
385
386 ~QMetaCallEvent();
387
388 inline int id() const { return method_offset_ + method_relative_; }
389 inline const QObject *sender() const { return sender_; }
390 inline int signalId() const { return signalId_; }
391 inline void **args() const { return args_; }
392
393 virtual void placeMetaCall(QObject *object);
394
395private:
396 QtPrivate::QSlotObjectBase *slotObj_;
397 const QObject *sender_;
398 int signalId_;
399 int nargs_;
400 int *types_;
401 void **args_;
402 QSemaphore *semaphore_;
403 QObjectPrivate::StaticMetaCallFunction callFunction_;
404 ushort method_offset_;
405 ushort method_relative_;
406};
407
408class QBoolBlocker
409{
410 Q_DISABLE_COPY(QBoolBlocker)
411public:
412 explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
413 inline ~QBoolBlocker(){block = reset; }
414private:
415 bool &block;
416 bool reset;
417};
418
419void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
420
421struct QAbstractDynamicMetaObject;
422struct Q_CORE_EXPORT QDynamicMetaObjectData
423{
424 virtual ~QDynamicMetaObjectData();
425 virtual void objectDestroyed(QObject *) { delete this; }
426
427 virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
428 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
429};
430
431struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
432{
433 ~QAbstractDynamicMetaObject();
434
435 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
436 virtual int createProperty(const char *, const char *) { return -1; }
437 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
438 { return metaCall(c, _id, a); }
439 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
440};
441
442QT_END_NAMESPACE
443
444#endif // QOBJECT_P_H
445