1/****************************************************************************
2**
3** Copyright (C) 2016 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_H
42#define QOBJECT_H
43
44#ifndef QT_NO_QOBJECT
45
46#include <QtCore/qobjectdefs.h>
47#include <QtCore/qstring.h>
48#include <QtCore/qbytearray.h>
49#include <QtCore/qlist.h>
50#ifdef QT_INCLUDE_COMPAT
51#include <QtCore/qcoreevent.h>
52#endif
53#include <QtCore/qscopedpointer.h>
54#include <QtCore/qmetatype.h>
55
56#include <QtCore/qobject_impl.h>
57
58#if QT_HAS_INCLUDE(<chrono>)
59# include <chrono>
60#endif
61
62QT_BEGIN_NAMESPACE
63
64
65class QEvent;
66class QTimerEvent;
67class QChildEvent;
68struct QMetaObject;
69class QVariant;
70class QObjectPrivate;
71class QObject;
72class QThread;
73class QWidget;
74class QAccessibleWidget;
75#ifndef QT_NO_REGEXP
76class QRegExp;
77#endif
78#if QT_CONFIG(regularexpression)
79class QRegularExpression;
80#endif
81#if !QT_DEPRECATED_SINCE(5, 14) || QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
82# define QT_NO_USERDATA
83#endif
84#ifndef QT_NO_USERDATA
85class QObjectUserData;
86#endif
87struct QDynamicMetaObjectData;
88
89typedef QList<QObject*> QObjectList;
90
91Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
92 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
93Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegExp &re,
94 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
95Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
96 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
97Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);
98
99class Q_CORE_EXPORT QObjectData {
100 Q_DISABLE_COPY(QObjectData)
101public:
102 QObjectData() = default;
103 virtual ~QObjectData() = 0;
104 QObject *q_ptr;
105 QObject *parent;
106 QObjectList children;
107
108 uint isWidget : 1;
109 uint blockSig : 1;
110 uint wasDeleted : 1;
111 uint isDeletingChildren : 1;
112 uint sendChildEvents : 1;
113 uint receiveChildEvents : 1;
114 uint isWindow : 1; //for QWindow
115 uint deleteLaterCalled : 1;
116 uint unused : 24;
117 int postedEvents;
118 QDynamicMetaObjectData *metaObject;
119 QMetaObject *dynamicMetaObject() const;
120
121#ifdef QT_DEBUG
122 enum { CheckForParentChildLoopsWarnDepth = 4096 };
123#endif
124};
125
126
127class Q_CORE_EXPORT QObject
128{
129 Q_OBJECT
130
131 Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
132 Q_DECLARE_PRIVATE(QObject)
133
134public:
135 Q_INVOKABLE explicit QObject(QObject *parent=nullptr);
136 virtual ~QObject();
137
138 virtual bool event(QEvent *event);
139 virtual bool eventFilter(QObject *watched, QEvent *event);
140
141#if defined(QT_NO_TRANSLATION) || defined(Q_CLANG_QDOC)
142 static QString tr(const char *sourceText, const char * = nullptr, int = -1)
143 { return QString::fromUtf8(sourceText); }
144#if QT_DEPRECATED_SINCE(5, 0)
145 QT_DEPRECATED static QString trUtf8(const char *sourceText, const char * = nullptr, int = -1)
146 { return QString::fromUtf8(sourceText); }
147#endif
148#endif //QT_NO_TRANSLATION
149
150 QString objectName() const;
151 void setObjectName(const QString &name);
152
153 inline bool isWidgetType() const { return d_ptr->isWidget; }
154 inline bool isWindowType() const { return d_ptr->isWindow; }
155
156 inline bool signalsBlocked() const noexcept { return d_ptr->blockSig; }
157 bool blockSignals(bool b) noexcept;
158
159 QThread *thread() const;
160 void moveToThread(QThread *thread);
161
162 int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
163#if QT_HAS_INCLUDE(<chrono>)
164 Q_ALWAYS_INLINE
165 int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
166 {
167 return startTimer(int(time.count()), timerType);
168 }
169#endif
170 void killTimer(int id);
171
172 template<typename T>
173 inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
174 {
175 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
176 return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
177 }
178
179 template<typename T>
180 inline QList<T> findChildren(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
181 {
182 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
183 QList<T> list;
184 qt_qFindChildren_helper(this, aName, ObjType::staticMetaObject,
185 reinterpret_cast<QList<void *> *>(&list), options);
186 return list;
187 }
188
189#ifndef QT_NO_REGEXP
190#if QT_DEPRECATED_SINCE(5, 13)
191 template<typename T>
192 QT_DEPRECATED_X("Use findChildren(const QRegularExpression &, ...) instead.")
193 inline QList<T> findChildren(const QRegExp &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
194 {
195 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
196 QList<T> list;
197 qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,
198 reinterpret_cast<QList<void *> *>(&list), options);
199 return list;
200 }
201#endif
202#endif
203
204#if QT_CONFIG(regularexpression)
205 template<typename T>
206 inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
207 {
208 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
209 QList<T> list;
210 qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,
211 reinterpret_cast<QList<void *> *>(&list), options);
212 return list;
213 }
214#endif // QT_CONFIG(regularexpression)
215
216 inline const QObjectList &children() const { return d_ptr->children; }
217
218 void setParent(QObject *parent);
219 void installEventFilter(QObject *filterObj);
220 void removeEventFilter(QObject *obj);
221
222 static QMetaObject::Connection connect(const QObject *sender, const char *signal,
223 const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
224
225 static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
226 const QObject *receiver, const QMetaMethod &method,
227 Qt::ConnectionType type = Qt::AutoConnection);
228
229 inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
230 const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
231
232#ifdef Q_CLANG_QDOC
233 template<typename PointerToMemberFunction>
234 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);
235 template<typename PointerToMemberFunction, typename Functor>
236 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
237 template<typename PointerToMemberFunction, typename Functor>
238 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
239#else
240 //Connect a signal to a pointer to qobject member function
241 template <typename Func1, typename Func2>
242 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
243 const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
244 Qt::ConnectionType type = Qt::AutoConnection)
245 {
246 typedef QtPrivate::FunctionPointer<Func1> SignalType;
247 typedef QtPrivate::FunctionPointer<Func2> SlotType;
248
249 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
250 "No Q_OBJECT in the class with the signal");
251
252 //compilation error if the arguments does not match.
253 Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
254 "The slot requires more arguments than the signal provides.");
255 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
256 "Signal and slot arguments are not compatible.");
257 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
258 "Return type of the slot is not compatible with the return type of the signal.");
259
260 const int *types = nullptr;
261 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
262 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
263
264 return connectImpl(sender, reinterpret_cast<void **>(&signal),
265 receiver, reinterpret_cast<void **>(&slot),
266 new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
267 typename SignalType::ReturnType>(slot),
268 type, types, &SignalType::Object::staticMetaObject);
269 }
270
271 //connect to a function pointer (not a member)
272 template <typename Func1, typename Func2>
273 static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::type
274 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
275 {
276 return connect(sender, signal, sender, slot, Qt::DirectConnection);
277 }
278
279 //connect to a function pointer (not a member)
280 template <typename Func1, typename Func2>
281 static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
282 !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::type
283 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
284 Qt::ConnectionType type = Qt::AutoConnection)
285 {
286 typedef QtPrivate::FunctionPointer<Func1> SignalType;
287 typedef QtPrivate::FunctionPointer<Func2> SlotType;
288
289 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
290 "No Q_OBJECT in the class with the signal");
291
292 //compilation error if the arguments does not match.
293 Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
294 "The slot requires more arguments than the signal provides.");
295 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
296 "Signal and slot arguments are not compatible.");
297 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
298 "Return type of the slot is not compatible with the return type of the signal.");
299
300 const int *types = nullptr;
301 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
302 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
303
304 return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
305 new QtPrivate::QStaticSlotObject<Func2,
306 typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
307 typename SignalType::ReturnType>(slot),
308 type, types, &SignalType::Object::staticMetaObject);
309 }
310
311 //connect to a functor
312 template <typename Func1, typename Func2>
313 static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
314 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
315 {
316 return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection);
317 }
318
319 //connect to a functor, with a "context" object defining in which event loop is going to be executed
320 template <typename Func1, typename Func2>
321 static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
322 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
323 Qt::ConnectionType type = Qt::AutoConnection)
324 {
325 typedef QtPrivate::FunctionPointer<Func1> SignalType;
326 const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
327
328 Q_STATIC_ASSERT_X((FunctorArgumentCount >= 0),
329 "Signal and slot arguments are not compatible.");
330 const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
331 typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
332
333 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
334 "Return type of the slot is not compatible with the return type of the signal.");
335
336 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
337 "No Q_OBJECT in the class with the signal");
338
339 const int *types = nullptr;
340 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
341 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
342
343 return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
344 new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
345 typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
346 typename SignalType::ReturnType>(std::move(slot)),
347 type, types, &SignalType::Object::staticMetaObject);
348 }
349#endif //Q_CLANG_QDOC
350
351 static bool disconnect(const QObject *sender, const char *signal,
352 const QObject *receiver, const char *member);
353 static bool disconnect(const QObject *sender, const QMetaMethod &signal,
354 const QObject *receiver, const QMetaMethod &member);
355 inline bool disconnect(const char *signal = nullptr,
356 const QObject *receiver = nullptr, const char *member = nullptr) const
357 { return disconnect(this, signal, receiver, member); }
358 inline bool disconnect(const QObject *receiver, const char *member = nullptr) const
359 { return disconnect(this, nullptr, receiver, member); }
360 static bool disconnect(const QMetaObject::Connection &);
361
362#ifdef Q_CLANG_QDOC
363 template<typename PointerToMemberFunction>
364 static bool disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method);
365#else
366 template <typename Func1, typename Func2>
367 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
368 const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
369 {
370 typedef QtPrivate::FunctionPointer<Func1> SignalType;
371 typedef QtPrivate::FunctionPointer<Func2> SlotType;
372
373 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
374 "No Q_OBJECT in the class with the signal");
375
376 //compilation error if the arguments does not match.
377 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
378 "Signal and slot arguments are not compatible.");
379
380 return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, reinterpret_cast<void **>(&slot),
381 &SignalType::Object::staticMetaObject);
382 }
383 template <typename Func1>
384 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
385 const QObject *receiver, void **zero)
386 {
387 // This is the overload for when one wish to disconnect a signal from any slot. (slot=nullptr)
388 // Since the function template parameter cannot be deduced from '0', we use a
389 // dummy void ** parameter that must be equal to 0
390 Q_ASSERT(!zero);
391 typedef QtPrivate::FunctionPointer<Func1> SignalType;
392 return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, zero,
393 &SignalType::Object::staticMetaObject);
394 }
395#endif //Q_CLANG_QDOC
396
397
398#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
399 void dumpObjectTree(); // ### Qt 6: remove
400 void dumpObjectInfo(); // ### Qt 6: remove
401#endif
402 void dumpObjectTree() const;
403 void dumpObjectInfo() const;
404
405#ifndef QT_NO_PROPERTIES
406 bool setProperty(const char *name, const QVariant &value);
407 QVariant property(const char *name) const;
408 QList<QByteArray> dynamicPropertyNames() const;
409#endif // QT_NO_PROPERTIES
410
411#ifndef QT_NO_USERDATA
412 QT_DEPRECATED_VERSION_5_14
413 static uint registerUserData();
414 QT_DEPRECATED_VERSION_X_5_14("Use setProperty()")
415 void setUserData(uint id, QObjectUserData* data);
416 QT_DEPRECATED_VERSION_X_5_14("Use property()")
417 QObjectUserData* userData(uint id) const;
418#endif // QT_NO_USERDATA
419
420Q_SIGNALS:
421 void destroyed(QObject * = nullptr);
422 void objectNameChanged(const QString &objectName, QPrivateSignal);
423
424public:
425 inline QObject *parent() const { return d_ptr->parent; }
426
427 inline bool inherits(const char *classname) const
428 { return const_cast<QObject *>(this)->qt_metacast(classname) != nullptr; }
429
430public Q_SLOTS:
431 void deleteLater();
432
433protected:
434 QObject *sender() const;
435 int senderSignalIndex() const;
436 int receivers(const char* signal) const;
437 bool isSignalConnected(const QMetaMethod &signal) const;
438
439 virtual void timerEvent(QTimerEvent *event);
440 virtual void childEvent(QChildEvent *event);
441 virtual void customEvent(QEvent *event);
442
443 virtual void connectNotify(const QMetaMethod &signal);
444 virtual void disconnectNotify(const QMetaMethod &signal);
445
446protected:
447 QObject(QObjectPrivate &dd, QObject *parent = nullptr);
448
449protected:
450 QScopedPointer<QObjectData> d_ptr;
451
452 static const QMetaObject staticQtMetaObject;
453 friend inline const QMetaObject *qt_getQtMetaObject() noexcept;
454
455 friend struct QMetaObject;
456 friend struct QMetaObjectPrivate;
457 friend class QMetaCallEvent;
458 friend class QApplication;
459 friend class QApplicationPrivate;
460 friend class QCoreApplication;
461 friend class QCoreApplicationPrivate;
462 friend class QWidget;
463 friend class QAccessibleWidget;
464 friend class QThreadData;
465
466private:
467 Q_DISABLE_COPY(QObject)
468 Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
469
470private:
471 static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
472 const QObject *receiver, void **slotPtr,
473 QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type,
474 const int *types, const QMetaObject *senderMetaObject);
475
476 static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,
477 const QMetaObject *senderMetaObject);
478
479};
480
481inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
482 const char *amember, Qt::ConnectionType atype) const
483{ return connect(asender, asignal, this, amember, atype); }
484
485inline const QMetaObject *qt_getQtMetaObject() noexcept
486{ return &QObject::staticQtMetaObject; }
487
488#ifndef QT_NO_USERDATA
489class Q_CORE_EXPORT QObjectUserData {
490 Q_DISABLE_COPY(QObjectUserData)
491public:
492 QObjectUserData() = default;
493 virtual ~QObjectUserData();
494};
495#endif
496
497#if QT_DEPRECATED_SINCE(5, 0)
498template<typename T>
499inline QT_DEPRECATED T qFindChild(const QObject *o, const QString &name = QString())
500{ return o->findChild<T>(name); }
501
502template<typename T>
503inline QT_DEPRECATED QList<T> qFindChildren(const QObject *o, const QString &name = QString())
504{
505 return o->findChildren<T>(name);
506}
507
508#if !defined(QT_NO_REGEXP) || defined(Q_CLANG_QDOC)
509template<typename T>
510inline QT_DEPRECATED QList<T> qFindChildren(const QObject *o, const QRegExp &re)
511{
512 return o->findChildren<T>(re);
513}
514#endif
515
516#endif //QT_DEPRECATED
517
518template <class T>
519inline T qobject_cast(QObject *object)
520{
521 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
522 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
523 "qobject_cast requires the type to have a Q_OBJECT macro");
524 return static_cast<T>(ObjType::staticMetaObject.cast(object));
525}
526
527template <class T>
528inline T qobject_cast(const QObject *object)
529{
530 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
531 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
532 "qobject_cast requires the type to have a Q_OBJECT macro");
533 return static_cast<T>(ObjType::staticMetaObject.cast(object));
534}
535
536
537template <class T> inline const char * qobject_interface_iid()
538{ return nullptr; }
539
540
541#if defined(Q_CLANG_QDOC)
542# define Q_DECLARE_INTERFACE(IFace, IId)
543#elif !defined(Q_MOC_RUN)
544# define Q_DECLARE_INTERFACE(IFace, IId) \
545 template <> inline const char *qobject_interface_iid<IFace *>() \
546 { return IId; } \
547 template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
548 { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : nullptr)); } \
549 template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
550 { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : nullptr)); }
551#endif // Q_MOC_RUN
552
553#ifndef QT_NO_DEBUG_STREAM
554Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *);
555#endif
556
557class QSignalBlocker
558{
559public:
560 inline explicit QSignalBlocker(QObject *o) noexcept;
561 inline explicit QSignalBlocker(QObject &o) noexcept;
562 inline ~QSignalBlocker();
563
564 inline QSignalBlocker(QSignalBlocker &&other) noexcept;
565 inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept;
566
567 inline void reblock() noexcept;
568 inline void unblock() noexcept;
569private:
570 Q_DISABLE_COPY(QSignalBlocker)
571 QObject * m_o;
572 bool m_blocked;
573 bool m_inhibited;
574};
575
576QSignalBlocker::QSignalBlocker(QObject *o) noexcept
577 : m_o(o),
578 m_blocked(o && o->blockSignals(true)),
579 m_inhibited(false)
580{}
581
582QSignalBlocker::QSignalBlocker(QObject &o) noexcept
583 : m_o(&o),
584 m_blocked(o.blockSignals(true)),
585 m_inhibited(false)
586{}
587
588QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) noexcept
589 : m_o(other.m_o),
590 m_blocked(other.m_blocked),
591 m_inhibited(other.m_inhibited)
592{
593 other.m_o = nullptr;
594}
595
596QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) noexcept
597{
598 if (this != &other) {
599 // if both *this and other block the same object's signals:
600 // unblock *this iff our dtor would unblock, but other's wouldn't
601 if (m_o != other.m_o || (!m_inhibited && other.m_inhibited))
602 unblock();
603 m_o = other.m_o;
604 m_blocked = other.m_blocked;
605 m_inhibited = other.m_inhibited;
606 // disable other:
607 other.m_o = nullptr;
608 }
609 return *this;
610}
611
612QSignalBlocker::~QSignalBlocker()
613{
614 if (m_o && !m_inhibited)
615 m_o->blockSignals(m_blocked);
616}
617
618void QSignalBlocker::reblock() noexcept
619{
620 if (m_o) m_o->blockSignals(true);
621 m_inhibited = false;
622}
623
624void QSignalBlocker::unblock() noexcept
625{
626 if (m_o) m_o->blockSignals(m_blocked);
627 m_inhibited = true;
628}
629
630namespace QtPrivate {
631 inline QObject & deref_for_methodcall(QObject &o) { return o; }
632 inline QObject & deref_for_methodcall(QObject *o) { return *o; }
633}
634#define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1String(#obj))
635
636QT_END_NAMESPACE
637
638#endif
639
640#endif // QOBJECT_H
641