1// Copyright (C) 2020 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_H
6#define QOBJECT_H
7
8#ifndef QT_NO_QOBJECT
9
10#include <QtCore/qobjectdefs.h>
11#include <QtCore/qstring.h>
12#include <QtCore/qbytearray.h>
13#include <QtCore/qlist.h>
14#ifdef QT_INCLUDE_COMPAT
15#include <QtCore/qcoreevent.h>
16#endif
17#include <QtCore/qscopedpointer.h>
18#include <QtCore/qmetatype.h>
19
20#include <QtCore/qobject_impl.h>
21#include <QtCore/qbindingstorage.h>
22
23#include <chrono>
24
25QT_BEGIN_NAMESPACE
26
27
28template <typename T> class QBindable;
29class QEvent;
30class QTimerEvent;
31class QChildEvent;
32struct QMetaObject;
33class QVariant;
34class QObjectPrivate;
35class QObject;
36class QThread;
37class QWidget;
38class QAccessibleWidget;
39#if QT_CONFIG(regularexpression)
40class QRegularExpression;
41#endif
42struct QDynamicMetaObjectData;
43
44typedef QList<QObject*> QObjectList;
45
46Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
47 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
48Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
49 QList<void *> *list, Qt::FindChildOptions options);
50Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
51 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
52Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);
53
54class Q_CORE_EXPORT QObjectData
55{
56 Q_DISABLE_COPY(QObjectData)
57public:
58 QObjectData() = default;
59 virtual ~QObjectData() = 0;
60 QObject *q_ptr;
61 QObject *parent;
62 QObjectList children;
63
64 uint isWidget : 1;
65 uint blockSig : 1;
66 uint wasDeleted : 1;
67 uint isDeletingChildren : 1;
68 uint sendChildEvents : 1;
69 uint receiveChildEvents : 1;
70 uint isWindow : 1; // for QWindow
71 uint deleteLaterCalled : 1;
72 uint isQuickItem : 1;
73 uint willBeWidget : 1; // for handling widget-specific bits in QObject's ctor
74 uint wasWidget : 1; // for properly cleaning up in QObject's dtor
75 uint unused : 21;
76 QAtomicInt postedEvents;
77 QDynamicMetaObjectData *metaObject;
78 QBindingStorage bindingStorage;
79
80 // ### Qt7: Make this return a const QMetaObject *. You should not mess with
81 // the metaobjects of existing objects.
82 QMetaObject *dynamicMetaObject() const;
83
84#ifdef QT_DEBUG
85 enum { CheckForParentChildLoopsWarnDepth = 4096 };
86#endif
87};
88
89class Q_CORE_EXPORT QObject
90{
91 Q_OBJECT
92
93 Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged
94 BINDABLE bindableObjectName)
95 Q_DECLARE_PRIVATE(QObject)
96
97public:
98 Q_INVOKABLE explicit QObject(QObject *parent = nullptr);
99 virtual ~QObject();
100
101 virtual bool event(QEvent *event);
102 virtual bool eventFilter(QObject *watched, QEvent *event);
103
104#if defined(QT_NO_TRANSLATION) || defined(Q_QDOC)
105 static QString tr(const char *sourceText, const char * = nullptr, int = -1)
106 { return QString::fromUtf8(sourceText); }
107#endif // QT_NO_TRANSLATION
108
109 QString objectName() const;
110#if QT_CORE_REMOVED_SINCE(6, 4)
111 void setObjectName(const QString &name);
112#endif
113 Q_WEAK_OVERLOAD
114 void setObjectName(const QString &name) { doSetObjectName(name); }
115 void setObjectName(QAnyStringView name);
116 QBindable<QString> bindableObjectName();
117
118 inline bool isWidgetType() const { return d_ptr->isWidget; }
119 inline bool isWindowType() const { return d_ptr->isWindow; }
120 inline bool isQuickItemType() const { return d_ptr->isQuickItem; }
121
122 inline bool signalsBlocked() const noexcept { return d_ptr->blockSig; }
123 bool blockSignals(bool b) noexcept;
124
125 QThread *thread() const;
126 void moveToThread(QThread *thread);
127
128 int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
129 int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
130 void killTimer(int id);
131
132 template<typename T>
133 inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
134 {
135 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
136 return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
137 }
138
139 template<typename T>
140 inline QList<T> findChildren(const QString &aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
141 {
142 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
143 QList<T> list;
144 qt_qFindChildren_helper(this, aName, ObjType::staticMetaObject,
145 reinterpret_cast<QList<void *> *>(&list), options);
146 return list;
147 }
148
149 template<typename T>
150 QList<T> findChildren(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
151 {
152 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
153 QList<T> list;
154 qt_qFindChildren_helper(this, ObjType::staticMetaObject,
155 reinterpret_cast<QList<void *> *>(&list), options);
156 return list;
157 }
158
159#if QT_CONFIG(regularexpression)
160 template<typename T>
161 inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
162 {
163 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
164 QList<T> list;
165 qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,
166 reinterpret_cast<QList<void *> *>(&list), options);
167 return list;
168 }
169#endif // QT_CONFIG(regularexpression)
170
171 inline const QObjectList &children() const { return d_ptr->children; }
172
173 void setParent(QObject *parent);
174 void installEventFilter(QObject *filterObj);
175 void removeEventFilter(QObject *obj);
176
177 static QMetaObject::Connection connect(const QObject *sender, const char *signal,
178 const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
179
180 static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
181 const QObject *receiver, const QMetaMethod &method,
182 Qt::ConnectionType type = Qt::AutoConnection);
183
184 inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
185 const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
186
187#ifdef Q_QDOC
188 template<typename PointerToMemberFunction>
189 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);
190 template<typename PointerToMemberFunction, typename Functor>
191 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
192 template<typename PointerToMemberFunction, typename Functor>
193 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
194#else
195 //connect with context
196 template <typename Func1, typename Func2>
197 static inline QMetaObject::Connection
198 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
199 const typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context, Func2 &&slot,
200 Qt::ConnectionType type = Qt::AutoConnection)
201 {
202 typedef QtPrivate::FunctionPointer<Func1> SignalType;
203 typedef QtPrivate::FunctionPointer<std::decay_t<Func2>> SlotType;
204
205 if constexpr (SlotType::ArgumentCount != -1) {
206 static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
207 "Return type of the slot is not compatible with the return type of the signal.");
208 } else {
209 constexpr int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<std::decay_t<Func2>, typename SignalType::Arguments>::Value;
210 [[maybe_unused]]
211 constexpr int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
212 typedef typename QtPrivate::FunctorReturnType<std::decay_t<Func2>, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
213
214 static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
215 "Return type of the slot is not compatible with the return type of the signal.");
216 }
217
218 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
219 "No Q_OBJECT in the class with the signal");
220
221 //compilation error if the arguments does not match.
222 static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
223 "The slot requires more arguments than the signal provides.");
224
225 const int *types = nullptr;
226 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
227 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
228
229 void **pSlot = nullptr;
230 if constexpr (std::is_member_function_pointer_v<std::decay_t<Func2>>)
231 pSlot = const_cast<void **>(reinterpret_cast<void *const *>(&slot));
232
233 return connectImpl(sender, signal: reinterpret_cast<void **>(&signal), receiver: context, slotPtr: pSlot,
234 slot: QtPrivate::makeCallableObject<Func1>(std::forward<Func2>(slot)),
235 type, types, senderMetaObject: &SignalType::Object::staticMetaObject);
236 }
237
238 //connect without context
239 template <typename Func1, typename Func2>
240 static inline QMetaObject::Connection
241 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot)
242 {
243 return connect(sender, signal, sender, std::forward<Func2>(slot), Qt::DirectConnection);
244 }
245#endif //Q_QDOC
246
247 static bool disconnect(const QObject *sender, const char *signal,
248 const QObject *receiver, const char *member);
249 static bool disconnect(const QObject *sender, const QMetaMethod &signal,
250 const QObject *receiver, const QMetaMethod &member);
251 inline bool disconnect(const char *signal = nullptr,
252 const QObject *receiver = nullptr, const char *member = nullptr) const
253 { return disconnect(sender: this, signal, receiver, member); }
254 inline bool disconnect(const QObject *receiver, const char *member = nullptr) const
255 { return disconnect(sender: this, signal: nullptr, receiver, member); }
256 static bool disconnect(const QMetaObject::Connection &);
257
258#ifdef Q_QDOC
259 template<typename PointerToMemberFunction>
260 static bool disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method);
261#else
262 template <typename Func1, typename Func2>
263 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
264 const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
265 {
266 typedef QtPrivate::FunctionPointer<Func1> SignalType;
267 typedef QtPrivate::FunctionPointer<Func2> SlotType;
268
269 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
270 "No Q_OBJECT in the class with the signal");
271
272 //compilation error if the arguments does not match.
273 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
274 "Signal and slot arguments are not compatible.");
275
276 return disconnectImpl(sender, signal: reinterpret_cast<void **>(&signal), receiver, slot: reinterpret_cast<void **>(&slot),
277 senderMetaObject: &SignalType::Object::staticMetaObject);
278 }
279 template <typename Func1>
280 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
281 const QObject *receiver, void **zero)
282 {
283 // This is the overload for when one wish to disconnect a signal from any slot. (slot=nullptr)
284 // Since the function template parameter cannot be deduced from '0', we use a
285 // dummy void ** parameter that must be equal to 0
286 Q_ASSERT(!zero);
287 typedef QtPrivate::FunctionPointer<Func1> SignalType;
288 return disconnectImpl(sender, signal: reinterpret_cast<void **>(&signal), receiver, slot: zero,
289 senderMetaObject: &SignalType::Object::staticMetaObject);
290 }
291#endif //Q_QDOC
292
293 void dumpObjectTree() const;
294 void dumpObjectInfo() const;
295
296 QT_CORE_INLINE_SINCE(6, 6)
297 bool setProperty(const char *name, const QVariant &value);
298 inline bool setProperty(const char *name, QVariant &&value);
299 QVariant property(const char *name) const;
300 QList<QByteArray> dynamicPropertyNames() const;
301 QBindingStorage *bindingStorage() { return &d_ptr->bindingStorage; }
302 const QBindingStorage *bindingStorage() const { return &d_ptr->bindingStorage; }
303
304Q_SIGNALS:
305 void destroyed(QObject * = nullptr);
306 void objectNameChanged(const QString &objectName, QPrivateSignal);
307
308public:
309 inline QObject *parent() const { return d_ptr->parent; }
310
311 inline bool inherits(const char *classname) const
312 {
313 return const_cast<QObject *>(this)->qt_metacast(classname) != nullptr;
314 }
315
316public Q_SLOTS:
317 void deleteLater();
318
319protected:
320 QObject *sender() const;
321 int senderSignalIndex() const;
322 int receivers(const char *signal) const;
323 bool isSignalConnected(const QMetaMethod &signal) const;
324
325 virtual void timerEvent(QTimerEvent *event);
326 virtual void childEvent(QChildEvent *event);
327 virtual void customEvent(QEvent *event);
328
329 virtual void connectNotify(const QMetaMethod &signal);
330 virtual void disconnectNotify(const QMetaMethod &signal);
331
332protected:
333 QObject(QObjectPrivate &dd, QObject *parent = nullptr);
334
335protected:
336 QScopedPointer<QObjectData> d_ptr;
337
338 friend struct QMetaObject;
339 friend struct QMetaObjectPrivate;
340 friend class QMetaCallEvent;
341 friend class QApplication;
342 friend class QApplicationPrivate;
343 friend class QCoreApplication;
344 friend class QCoreApplicationPrivate;
345 friend class QWidget;
346 friend class QAccessibleWidget;
347 friend class QThreadData;
348
349private:
350 void doSetObjectName(const QString &name);
351 bool doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue);
352
353 Q_DISABLE_COPY(QObject)
354 Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
355
356private:
357 static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
358 const QObject *receiver, void **slotPtr,
359 QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type,
360 const int *types, const QMetaObject *senderMetaObject);
361
362 static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,
363 const QMetaObject *senderMetaObject);
364
365};
366
367inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
368 const char *amember, Qt::ConnectionType atype) const
369{ return connect(sender: asender, signal: asignal, receiver: this, member: amember, atype); }
370
371#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
372bool QObject::setProperty(const char *name, const QVariant &value)
373{
374 return doSetProperty(name, lvalue: &value, rvalue: nullptr);
375}
376#endif // inline since 6.6
377bool QObject::setProperty(const char *name, QVariant &&value)
378{
379 return doSetProperty(name, lvalue: &value, rvalue: &value);
380}
381
382template <class T>
383inline T qobject_cast(QObject *object)
384{
385 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
386 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
387 "qobject_cast requires the type to have a Q_OBJECT macro");
388 return static_cast<T>(ObjType::staticMetaObject.cast(object));
389}
390
391template <class T>
392inline T qobject_cast(const QObject *object)
393{
394 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
395 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
396 "qobject_cast requires the type to have a Q_OBJECT macro");
397 return static_cast<T>(ObjType::staticMetaObject.cast(object));
398}
399
400
401template <class T> constexpr const char * qobject_interface_iid() = delete;
402template <class T> inline T *
403qobject_iid_cast(QObject *object, const char *IId = qobject_interface_iid<T *>())
404{
405 return reinterpret_cast<T *>((object ? object->qt_metacast(IId) : nullptr));
406}
407template <class T> inline std::enable_if_t<std::is_const<T>::value, T *>
408qobject_iid_cast(const QObject *object)
409{
410 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
411 QObject *o = const_cast<QObject *>(object);
412 return qobject_iid_cast<std::remove_cv_t<T>>(o);
413}
414
415#if defined(Q_QDOC)
416# define Q_DECLARE_INTERFACE(IFace, IId)
417#elif !defined(Q_MOC_RUN)
418# define Q_DECLARE_INTERFACE(IFace, IId) \
419 template <> constexpr const char *qobject_interface_iid<IFace *>() \
420 { return IId; } \
421 template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
422 { return qobject_iid_cast<IFace>(object); } \
423 template <> inline const IFace *qobject_cast<const IFace *>(const QObject *object) \
424 { return qobject_iid_cast<const IFace>(object); }
425#endif // Q_MOC_RUN
426
427inline const QBindingStorage *qGetBindingStorage(const QObject *o)
428{
429 return o->bindingStorage();
430}
431inline QBindingStorage *qGetBindingStorage(QObject *o)
432{
433 return o->bindingStorage();
434}
435
436#ifndef QT_NO_DEBUG_STREAM
437Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *);
438#endif
439
440class QSignalBlocker
441{
442public:
443 Q_NODISCARD_CTOR
444 inline explicit QSignalBlocker(QObject *o) noexcept;
445 Q_NODISCARD_CTOR
446 inline explicit QSignalBlocker(QObject &o) noexcept;
447 inline ~QSignalBlocker();
448
449 Q_NODISCARD_CTOR
450 inline QSignalBlocker(QSignalBlocker &&other) noexcept;
451 inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept;
452
453 inline void reblock() noexcept;
454 inline void unblock() noexcept;
455
456private:
457 Q_DISABLE_COPY(QSignalBlocker)
458 QObject *m_o;
459 bool m_blocked;
460 bool m_inhibited;
461};
462
463QSignalBlocker::QSignalBlocker(QObject *o) noexcept
464 : m_o(o),
465 m_blocked(o && o->blockSignals(b: true)),
466 m_inhibited(false)
467{}
468
469QSignalBlocker::QSignalBlocker(QObject &o) noexcept
470 : m_o(&o),
471 m_blocked(o.blockSignals(b: true)),
472 m_inhibited(false)
473{}
474
475QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) noexcept
476 : m_o(other.m_o),
477 m_blocked(other.m_blocked),
478 m_inhibited(other.m_inhibited)
479{
480 other.m_o = nullptr;
481}
482
483QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) noexcept
484{
485 if (this != &other) {
486 // if both *this and other block the same object's signals:
487 // unblock *this iff our dtor would unblock, but other's wouldn't
488 if (m_o != other.m_o || (!m_inhibited && other.m_inhibited))
489 unblock();
490 m_o = other.m_o;
491 m_blocked = other.m_blocked;
492 m_inhibited = other.m_inhibited;
493 // disable other:
494 other.m_o = nullptr;
495 }
496 return *this;
497}
498
499QSignalBlocker::~QSignalBlocker()
500{
501 if (m_o && !m_inhibited)
502 m_o->blockSignals(b: m_blocked);
503}
504
505void QSignalBlocker::reblock() noexcept
506{
507 if (m_o)
508 m_o->blockSignals(b: true);
509 m_inhibited = false;
510}
511
512void QSignalBlocker::unblock() noexcept
513{
514 if (m_o)
515 m_o->blockSignals(b: m_blocked);
516 m_inhibited = true;
517}
518
519namespace QtPrivate {
520 inline QObject & deref_for_methodcall(QObject &o) { return o; }
521 inline QObject & deref_for_methodcall(QObject *o) { return *o; }
522}
523#define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1StringView(#obj))
524
525QT_END_NAMESPACE
526
527#endif
528
529#endif // QOBJECT_H
530

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