summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.h
blob: 813ccdb67353bc054eca370323bb4e558845f7cb (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
// Copyright (C) 2020 The Qt Company Ltd.// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#ifndef QOBJECT_H#define QOBJECT_H#ifndef QT_NO_QOBJECT#include <QtCore/qobjectdefs.h>#include <QtCore/qstring.h>#include <QtCore/qbytearray.h>#include <QtCore/qlist.h>#ifdef QT_INCLUDE_COMPAT#include <QtCore/qcoreevent.h>#endif#include <QtCore/qscopedpointer.h>#include <QtCore/qmetatype.h>#include <QtCore/qobject_impl.h>#include <QtCore/qbindingstorage.h>#include <QtCore/qtcoreexports.h>#include <chrono> QT_BEGIN_NAMESPACE template<typename T>class QBindable;class QEvent;class QTimerEvent;class QChildEvent;struct QMetaObject;class QVariant;class QObjectPrivate;class QObject;class QThread;class QWidget;class QAccessibleWidget;#if QT_CONFIG(regularexpression)class QRegularExpression;#endifstruct QDynamicMetaObjectData;typedef QList<QObject*> QObjectList;#if QT_CORE_REMOVED_SINCE(6, 7) Q_CORE_EXPORT voidqt_qFindChildren_helper(const QObject *parent,const QString &name,const QMetaObject &mo, QList<void*> *list,Qt::FindChildOptions options);#endif Q_CORE_EXPORT voidqt_qFindChildren_helper(const QObject *parent, QAnyStringView name,const QMetaObject &mo, QList<void*> *list,Qt::FindChildOptions options);#if QT_CORE_REMOVED_SINCE(6, 7) Q_CORE_EXPORT voidqt_qFindChildren_helper(const QObject *parent,const QMetaObject &mo, QList<void*> *list,Qt::FindChildOptions options);#endif Q_CORE_EXPORT voidqt_qFindChildren_helper(const QObject *parent,const QRegularExpression &re,const QMetaObject &mo, QList<void*> *list,Qt::FindChildOptions options);#if QT_CORE_REMOVED_SINCE(6, 7) Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent,const QString &name,const QMetaObject &mo,Qt::FindChildOptions options);#endif Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name,const QMetaObject &mo,Qt::FindChildOptions options);class Q_CORE_EXPORT QObjectData {Q_DISABLE_COPY(QObjectData)public:QObjectData() =default;virtual~QObjectData() =0; QObject *q_ptr; QObject *parent; QObjectList children; uint isWidget :1; uint blockSig :1; uint wasDeleted :1; uint isDeletingChildren :1; uint sendChildEvents :1; uint receiveChildEvents :1; uint isWindow :1;// for QWindow uint deleteLaterCalled :1; uint isQuickItem :1; uint willBeWidget :1;// for handling widget-specific bits in QObject's ctor uint wasWidget :1;// for properly cleaning up in QObject's dtor uint receiveParentEvents:1; uint unused :20; QAtomicInt postedEvents; QDynamicMetaObjectData *metaObject; QBindingStorage bindingStorage;#if QT_CORE_REMOVED_SINCE(6, 9) && defined(Q_COMPILER_MANGLES_RETURN_TYPE) QMetaObject *dynamicMetaObject()const;#elseconst QMetaObject *dynamicMetaObject()const;#endif#ifdef QT_DEBUGenum{ CheckForParentChildLoopsWarnDepth =4096};#endif};class Q_CORE_EXPORT QObject { Q_OBJECT Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged BINDABLE bindableObjectName)Q_DECLARE_PRIVATE(QObject)public: Q_INVOKABLE explicitQObject(QObject *parent =nullptr);virtual~QObject();virtualboolevent(QEvent *event);virtualbooleventFilter(QObject *watched, QEvent *event);#if defined(QT_NO_TRANSLATION) || defined(Q_QDOC)static QString tr(const char*sourceText,const char* =nullptr,int= -1){returnQString::fromUtf8(sourceText); }#endif// QT_NO_TRANSLATION QString objectName()const;#if QT_CORE_REMOVED_SINCE(6, 4)voidsetObjectName(const QString &name);#endif Q_WEAK_OVERLOAD voidsetObjectName(const QString &name) {doSetObjectName(name); }voidsetObjectName(QAnyStringView name); QBindable<QString>bindableObjectName();inlineboolisWidgetType()const{return d_ptr->isWidget; }inlineboolisWindowType()const{return d_ptr->isWindow; }inlineboolisQuickItemType()const{return d_ptr->isQuickItem; }inlineboolsignalsBlocked()const noexcept {return d_ptr->blockSig; }boolblockSignals(bool b) noexcept; QThread *thread()const;#if QT_CORE_REMOVED_SINCE(6, 7)voidmoveToThread(QThread *thread);#endifboolmoveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL);intstartTimer(int interval,Qt::TimerType timerType =Qt::CoarseTimer);#if QT_CORE_REMOVED_SINCE(6, 8)intstartTimer(std::chrono::milliseconds time,Qt::TimerType timerType =Qt::CoarseTimer);#endifintstartTimer(std::chrono::nanoseconds time,Qt::TimerType timerType =Qt::CoarseTimer);voidkillTimer(int id);voidkillTimer(Qt::TimerId id);template<typename T> T findChild(QAnyStringView aName,Qt::FindChildOptions options =Qt::FindChildrenRecursively)const{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"No Q_OBJECT in the class passed to QObject::findChild");return static_cast<T>(qt_qFindChild_helper(this, aName,ObjType::staticMetaObject, options));}template<typename T> QList<T>findChildren(QAnyStringView aName,Qt::FindChildOptions options =Qt::FindChildrenRecursively)const{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"No Q_OBJECT in the class passed to QObject::findChildren"); QList<T> list;qt_qFindChildren_helper(this, aName,ObjType::staticMetaObject,reinterpret_cast<QList<void*> *>(&list), options);return list;}template<typename T> T findChild(Qt::FindChildOptions options =Qt::FindChildrenRecursively)const{return findChild<T>({}, options);}template<typename T> QList<T>findChildren(Qt::FindChildOptions options =Qt::FindChildrenRecursively)const{return findChildren<T>(QAnyStringView{}, options);}#if QT_CONFIG(regularexpression)template<typename T>inline QList<T>findChildren(const QRegularExpression &re,Qt::FindChildOptions options =Qt::FindChildrenRecursively)const{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"No Q_OBJECT in the class passed to QObject::findChildren"); QList<T> list;qt_qFindChildren_helper(this, re,ObjType::staticMetaObject,reinterpret_cast<QList<void*> *>(&list), options);return list;}#endif// QT_CONFIG(regularexpression)inlineconst QObjectList &children()const{return d_ptr->children; }voidsetParent(QObject *parent);voidinstallEventFilter(QObject *filterObj);voidremoveEventFilter(QObject *obj);staticQMetaObject::Connection connect(const QObject *sender,const char*signal,const QObject *receiver,const char*member,Qt::ConnectionType =Qt::AutoConnection);staticQMetaObject::Connection connect(const QObject *sender,const QMetaMethod &signal,const QObject *receiver,const QMetaMethod &method,Qt::ConnectionType type =Qt::AutoConnection);inline QMetaObject::Connection connect(const QObject *sender,const char*signal,const char*member,Qt::ConnectionType type =Qt::AutoConnection)const;#ifdef Q_QDOCtemplate<typename PointerToMemberFunction>staticQMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal,const QObject *receiver, PointerToMemberFunction method,Qt::ConnectionType type =Qt::AutoConnection);template<typename PointerToMemberFunction, typename Functor>staticQMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);template<typename PointerToMemberFunction, typename Functor>staticQMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal,const QObject *context, Functor functor,Qt::ConnectionType type =Qt::AutoConnection);#else//connect with contexttemplate<typename Func1, typename Func2>staticinline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context, Func2 &&slot,Qt::ConnectionType type =Qt::AutoConnection){typedef QtPrivate::FunctionPointer<Func1> SignalType;typedef QtPrivate::FunctionPointer<std::decay_t<Func2>> SlotType;ifconstexpr(SlotType::ArgumentCount != -1) {static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),"Return type of the slot is not compatible with the return type of the signal.");}else{constexprint FunctorArgumentCount =QtPrivate::ComputeFunctorArgumentCount<std::decay_t<Func2>, typename SignalType::Arguments>::Value;[[maybe_unused]]constexprint SlotArgumentCount = (FunctorArgumentCount >=0) ? FunctorArgumentCount :0;typedef typename QtPrivate::FunctorReturnType<std::decay_t<Func2>, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::type SlotReturnType;static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),"Return type of the slot is not compatible with the return type of the signal.");}static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");//compilation error if the arguments does not match.static_assert(int(SignalType::ArgumentCount) >=int(SlotType::ArgumentCount),"The slot requires more arguments than the signal provides.");const int*types =nullptr;if(type ==Qt::QueuedConnection || type ==Qt::BlockingQueuedConnection) types =QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();void**pSlot =nullptr;ifconstexpr(std::is_member_function_pointer_v<std::decay_t<Func2>>) { pSlot =const_cast<void**>(reinterpret_cast<void*const*>(&slot));}else{Q_ASSERT_X((type &Qt::UniqueConnection) ==0,"","QObject::connect: Unique connection requires the slot to be a pointer to ""a member function of a QObject subclass.");}returnconnectImpl(sender,reinterpret_cast<void**>(&signal), context, pSlot,QtPrivate::makeCallableObject<Func1>(std::forward<Func2>(slot)), type, types, &SignalType::Object::staticMetaObject);}#ifndef QT_NO_CONTEXTLESS_CONNECT//connect without contexttemplate<typename Func1, typename Func2>staticinline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot){returnconnect(sender, signal, sender,std::forward<Func2>(slot),Qt::DirectConnection);}#endif// QT_NO_CONTEXTLESS_CONNECT#endif//Q_QDOCstatic booldisconnect(const QObject *sender,const char*signal,const QObject *receiver,const char*member);static booldisconnect(const QObject *sender,const QMetaMethod &signal,const QObject *receiver,const QMetaMethod &member);inlinebooldisconnect(const char*signal =nullptr,const QObject *receiver =nullptr,const char*member =nullptr)const{returndisconnect(this, signal, receiver, member); }inlinebooldisconnect(const QObject *receiver,const char*member =nullptr)const{returndisconnect(this,nullptr, receiver, member); }static booldisconnect(constQMetaObject::Connection &);#ifdef Q_QDOCtemplate<typename PointerToMemberFunction>static booldisconnect(const QObject *sender, PointerToMemberFunction signal,const QObject *receiver, PointerToMemberFunction method);#elsetemplate<typename Func1, typename Func2>staticinlinebooldisconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot){typedef QtPrivate::FunctionPointer<Func1> SignalType;typedef QtPrivate::FunctionPointer<Func2> SlotType;static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");//compilation error if the arguments does not match.static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),"Signal and slot arguments are not compatible.");returndisconnectImpl(sender,reinterpret_cast<void**>(&signal), receiver,reinterpret_cast<void**>(&slot),&SignalType::Object::staticMetaObject);}template<typename Func1>staticinlinebooldisconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const QObject *receiver,void**zero){// This is the overload for when one wish to disconnect a signal from any slot. (slot=nullptr)// Since the function template parameter cannot be deduced from '0', we use a// dummy void ** parameter that must be equal to 0Q_ASSERT(!zero);typedef QtPrivate::FunctionPointer<Func1> SignalType;returndisconnectImpl(sender,reinterpret_cast<void**>(&signal), receiver, zero,&SignalType::Object::staticMetaObject);}#endif//Q_QDOCvoiddumpObjectTree()const;voiddumpObjectInfo()const;QT_CORE_INLINE_SINCE(6,6)boolsetProperty(const char*name,const QVariant &value);inlineboolsetProperty(const char*name, QVariant &&value); QVariant property(const char*name)const; QList<QByteArray>dynamicPropertyNames()const; QBindingStorage *bindingStorage() {return&d_ptr->bindingStorage; }const QBindingStorage *bindingStorage()const{return&d_ptr->bindingStorage; } Q_SIGNALS:voiddestroyed(QObject * =nullptr);voidobjectNameChanged(const QString &objectName, QPrivateSignal);public:inline QObject *parent()const{return d_ptr->parent; }inlineboolinherits(const char*classname)const{return const_cast<QObject *>(this)->qt_metacast(classname) !=nullptr;}public Q_SLOTS:voiddeleteLater();protected: QObject *sender()const;intsenderSignalIndex()const;intreceivers(const char*signal)const;boolisSignalConnected(const QMetaMethod &signal)const;virtualvoidtimerEvent(QTimerEvent *event);virtualvoidchildEvent(QChildEvent *event);virtualvoidcustomEvent(QEvent *event);virtualvoidconnectNotify(const QMetaMethod &signal);virtualvoiddisconnectNotify(const QMetaMethod &signal);protected:QObject(QObjectPrivate &dd, QObject *parent =nullptr);protected: QScopedPointer<QObjectData> d_ptr;friendstruct QMetaObject;friendstruct QMetaObjectPrivate;friend class QMetaCallEvent;friend class QApplication;friend class QApplicationPrivate;friend class QCoreApplication;friend class QCoreApplicationPrivate;friend class QWidget;friend class QAccessibleWidget;friend class QThreadData;private:voiddoSetObjectName(const QString &name);booldoSetProperty(const char*name,const QVariant *lvalue, QVariant *rvalue);Q_DISABLE_COPY(QObject)private:staticQMetaObject::Connection connectImpl(const QObject *sender,void**signal,const QObject *receiver,void**slotPtr,QtPrivate::QSlotObjectBase *slot,Qt::ConnectionType type,const int*types,const QMetaObject *senderMetaObject);static booldisconnectImpl(const QObject *sender,void**signal,const QObject *receiver,void**slot,const QMetaObject *senderMetaObject);};inline QMetaObject::Connection QObject::connect(const QObject *asender,const char*asignal,const char*amember,Qt::ConnectionType atype)const{returnconnect(asender, asignal,this, amember, atype); }#if QT_CORE_INLINE_IMPL_SINCE(6, 6)boolQObject::setProperty(const char*name,const QVariant &value){returndoSetProperty(name, &value,nullptr);}#endif// inline since 6.6boolQObject::setProperty(const char*name, QVariant &&value){returndoSetProperty(name, &value, &value);}template<class T>inline T qobject_cast(QObject *object){returnQtPrivate::qobject_cast_helper<T>(object);}template<class T>inline T qobject_cast(const QObject *object){static_assert(std::is_const_v<std::remove_pointer_t<T>>,"qobject_cast cannot cast away constness (use const_cast)");returnQtPrivate::qobject_cast_helper<T>(object);}template<class T>constexprconst char*qobject_interface_iid() =delete;template<class T>inline T *qobject_iid_cast(QObject *object,const char*IId = qobject_interface_iid<T *>()){return reinterpret_cast<T *>((object ? object->qt_metacast(IId) :nullptr));}template<class T>inline std::enable_if_t<std::is_const<T>::value, T *>qobject_iid_cast(const QObject *object){// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) QObject *o =const_cast<QObject *>(object);return qobject_iid_cast<std::remove_cv_t<T>>(o);}#if defined(Q_QDOC)# define Q_DECLARE_INTERFACE(IFace, IId)#elif !defined(Q_MOC_RUN)# define Q_DECLARE_INTERFACE(IFace, IId) \ template <> constexpr const char *qobject_interface_iid<IFace *>() \ { return IId; } \ template <> inline IFace *qobject_cast<IFace *>(QObject *object) \ { return qobject_iid_cast<IFace>(object); } \ template <> inline const IFace *qobject_cast<const IFace *>(const QObject *object) \ { return qobject_iid_cast<const IFace>(object); }#endif// Q_MOC_RUNinlineconst QBindingStorage *qGetBindingStorage(const QObject *o){return o->bindingStorage();}inline QBindingStorage *qGetBindingStorage(QObject *o){return o->bindingStorage();}#ifndef QT_NO_DEBUG_STREAM Q_CORE_EXPORT QDebug operator<<(QDebug,const QObject *);#endifclass QSignalBlocker {public: Q_NODISCARD_CTOR inline explicitQSignalBlocker(QObject *o) noexcept; Q_NODISCARD_CTOR inline explicitQSignalBlocker(QObject &o) noexcept;inline~QSignalBlocker(); Q_NODISCARD_CTOR inlineQSignalBlocker(QSignalBlocker &&other) noexcept;inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept;inlinevoidreblock() noexcept;inlinevoidunblock() noexcept;inlinevoiddismiss() noexcept;private:Q_DISABLE_COPY(QSignalBlocker) QObject *m_o;bool m_blocked;bool m_inhibited;};QSignalBlocker::QSignalBlocker(QObject *o) noexcept :m_o(o),m_blocked(o && o->blockSignals(true)),m_inhibited(false){}QSignalBlocker::QSignalBlocker(QObject &o) noexcept :m_o(&o),m_blocked(o.blockSignals(true)),m_inhibited(false){}QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) noexcept :m_o(other.m_o),m_blocked(other.m_blocked),m_inhibited(other.m_inhibited){ other.m_o =nullptr;} QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) noexcept {if(this!= &other) {// if both *this and other block the same object's signals:// unblock *this iff our dtor would unblock, but other's wouldn'tif(m_o != other.m_o || (!m_inhibited && other.m_inhibited))unblock(); m_o = other.m_o; m_blocked = other.m_blocked; m_inhibited = other.m_inhibited;// disable other: other.m_o =nullptr;}return*this;}QSignalBlocker::~QSignalBlocker(){if(m_o && !m_inhibited) m_o->blockSignals(m_blocked);}voidQSignalBlocker::reblock() noexcept {if(m_o) m_o->blockSignals(true); m_inhibited =false;}voidQSignalBlocker::unblock() noexcept {if(m_o) m_o->blockSignals(m_blocked); m_inhibited =true;}voidQSignalBlocker::dismiss() noexcept { m_o =nullptr;}namespace QtPrivate {inline QObject &deref_for_methodcall(QObject &o) {return o; }inline QObject &deref_for_methodcall(QObject *o) {return*o; }}#define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1StringView(#obj)) QT_END_NAMESPACE #endif#endif// QOBJECT_H
close