summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject_p.h
blob: 2b6e1eebd03bfc2f021066918f0cc6352b343e54 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
// Copyright (C) 2019 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_P_H#define QOBJECT_P_H//// W A R N I N G// -------------//// This file is not part of the Qt API. It exists for the convenience// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header// file may change from version to version without notice, or even be removed.//// We mean it.//#include <QtCore/private/qglobal_p.h>#include"QtCore/qcoreevent.h"#include <QtCore/qfunctionaltools_impl.h>#include"QtCore/qlist.h"#include"QtCore/qobject.h"#include"QtCore/qpointer.h"#include"QtCore/qvariant.h"#include"QtCore/qproperty.h"#include <QtCore/qshareddata.h>#include"QtCore/private/qproperty_p.h"#include <string> QT_BEGIN_NAMESPACE #ifdef Q_MOC_RUN#define QT_ANONYMOUS_PROPERTY(text) QT_ANONYMOUS_PROPERTY(text)#define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANONYMOUS_PRIVATE_PROPERTY(d, text)#elif !defined QT_NO_META_MACROS#define QT_ANONYMOUS_PROPERTY(...) QT_ANNOTATE_CLASS(qt_anonymous_property, __VA_ARGS__)#define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANNOTATE_CLASS2(qt_anonymous_private_property, d, text)#endif#define QT_CONCAT(B, M, m, u) QT_CONCAT2(B, M, m, u)#define QT_CONCAT2(B, M, m, u) B ## M ## _ ## m ## _ ## u#if defined(QT_BUILD_INTERNAL) && !QT_CONFIG(elf_private_full_version)// Don't check the version parameter in internal builds.// This allows incompatible versions to be loaded, possibly for testing.enum QObjectPrivateVersionEnum #elseenumQT_CONCAT(QtPrivate_, QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH)#endif{ QObjectPrivateVersion = QT_VERSION };#undef QT_CONCAT#undef QT_CONCAT2class QVariant;class QThreadData;class QObjectConnectionListVector;namespace QtSharedPointer {struct ExternalRefCountData; }/* for Qt Test */struct QSignalSpyCallbackSet {typedefvoid(*BeginCallback)(QObject *caller,int signal_or_method_index,void**argv);typedefvoid(*EndCallback)(QObject *caller,int signal_or_method_index); BeginCallback signal_begin_callback, slot_begin_callback; EndCallback signal_end_callback, slot_end_callback;};void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set);extern Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set;class Q_CORE_EXPORT QAbstractDeclarativeData {public:static void(*destroyed)(QAbstractDeclarativeData *, QObject *);static void(*signalEmitted)(QAbstractDeclarativeData *, QObject *,int,void**);static int(*receivers)(QAbstractDeclarativeData *,const QObject *,int);static bool(*isSignalConnected)(QAbstractDeclarativeData *,const QObject *,int);static void(*setWidgetParent)(QObject *, QObject *);// Used by the QML engine to specify parents for widgets. Set by QtWidgets.};class Q_CORE_EXPORT QObjectPrivate :public QObjectData {public:Q_DECLARE_PUBLIC(QObject)struct ExtraData {ExtraData(QObjectPrivate *ptr) :parent(ptr) { }inlinevoidsetObjectNameForwarder(const QString &name){ parent->q_func()->setObjectName(name);}inlinevoidnameChangedForwarder(const QString &name){ Q_EMIT parent->q_func()->objectNameChanged(name,QObject::QPrivateSignal());} QList<QByteArray> propertyNames; QList<QVariant> propertyValues; QList<Qt::TimerId> runningTimers; QList<QPointer<QObject>> eventFilters;Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, objectName,&QObjectPrivate::ExtraData::setObjectNameForwarder,&QObjectPrivate::ExtraData::nameChangedForwarder) QObjectPrivate *parent;};voidensureExtraData(){if(!extraData) extraData =newExtraData(this);}voidsetObjectNameWithoutBindings(const QString &name);typedefvoid(*StaticMetaCallFunction)(QObject *,QMetaObject::Call,int,void**);struct Connection;struct ConnectionData;struct ConnectionList;struct ConnectionOrSignalVector;struct SignalVector;struct Sender;struct TaggedSignalVector;/* This contains the all connections from and to an object. The signalVector contains the lists of connections for a given signal. The index in the vector correspond to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on any signal emission. This is done by connecting to signal index -1. This vector is protected by the object mutex (signalSlotLock()) Each Connection is also part of a 'senders' linked list. This one contains all connections connected to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this linked list. */QObjectPrivate(decltype(QObjectPrivateVersion) version = QObjectPrivateVersion);virtual~QObjectPrivate();voiddeleteChildren();// used to clear binding storage early in ~QObjectvoidclearBindingStorage();voidsetParent_helper(QObject *);voidmoveToThread_helper();voidsetThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status); QObjectList receiverList(const char*signal)const;inlinevoidensureConnectionData();inlinevoidaddConnection(int signal, Connection *c);staticinlineboolremoveConnection(Connection *c);static QObjectPrivate *get(QObject *o) {return o->d_func(); }static const QObjectPrivate *get(const QObject *o) {return o->d_func(); }intsignalIndex(const char*signalName,const QMetaObject **meta =nullptr)const;boolisSignalConnected(uint signalIdx,bool checkDeclarative =true)const;boolmaybeSignalConnected(uint signalIndex)const;inlineboolisDeclarativeSignalConnected(uint signalIdx)const;// To allow abitrary objects to call connectNotify()/disconnectNotify() without making// the API public in QObject. This is used by QQmlNotifierEndpoint.inlinevoidconnectNotify(const QMetaMethod &signal);inlinevoiddisconnectNotify(const QMetaMethod &signal);voidreinitBindingStorageAfterThreadMove();template<typename Func1, typename Func2>staticinline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,Qt::ConnectionType type =Qt::AutoConnection);template<typename Func1, typename Func2>staticinlinebooldisconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);staticQMetaObject::Connection connectImpl(const QObject *sender,int signal_index,const QObject *receiver,void**slot,QtPrivate::QSlotObjectBase *slotObj,int type,const int*types,const QMetaObject *senderMetaObject);staticQMetaObject::Connection connect(const QObject *sender,int signal_index,QtPrivate::QSlotObjectBase *slotObj,Qt::ConnectionType type);staticQMetaObject::Connection connect(const QObject *sender,int signal_index,const QObject *receiver,QtPrivate::QSlotObjectBase *slotObj,Qt::ConnectionType type);static booldisconnect(const QObject *sender,int signal_index,void**slot);static booldisconnect(const QObject *sender,int signal_index,const QObject *receiver,void**slot);virtual std::string flagsForDumping()const;#ifndef QT_NO_DEBUG_STREAMvirtualvoidwriteToDebugStream(QDebug &)const;#endifQtPrivate::QPropertyAdaptorSlotObject *getPropertyAdaptorSlotObject(const QMetaProperty &property);public:mutable ExtraData *extraData;// extra data set by the user// This atomic requires acquire/release semantics in a few places,// e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,// because postEvent is thread-safe.// However, most of the code paths involving QObject are only reentrant and// not thread-safe, so synchronization should not be necessary there. QAtomicPointer<QThreadData> threadData;// id of the thread that owns the objectusing ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>; QAtomicPointer<ConnectionData> connections;union{ QObject *currentChildBeingDeleted;// should only be used when QObjectData::isDeletingChildren is set QAbstractDeclarativeData *declarativeData;//extra data used by the declarative module};// these objects are all used to indicate that a QObject was deleted// plus QPointer, which keeps a separate list QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;};inlineboolQObjectPrivate::isDeclarativeSignalConnected(uint signal_index)const{return!isDeletingChildren && declarativeData &&QAbstractDeclarativeData::isSignalConnected &&QAbstractDeclarativeData::isSignalConnected(declarativeData,q_func(), signal_index);}inlinevoidQObjectPrivate::connectNotify(const QMetaMethod &signal){ q_ptr->connectNotify(signal);}inlinevoidQObjectPrivate::disconnectNotify(const QMetaMethod &signal){ q_ptr->disconnectNotify(signal);}namespace QtPrivate {inlineconst QObject *getQObject(const QObjectPrivate *d) {return d->q_func(); }template<typename Func>using FunctionStorage =QtPrivate::CompactStorage<Func>;template<typename ObjPrivate>inlinevoidassertObjectType(QObjectPrivate *d){using Obj =std::remove_pointer_t<decltype(std::declval<ObjPrivate *>()->q_func())>; assertObjectType<Obj>(d->q_ptr);}template<typename Func, typename Args, typename R>class QPrivateSlotObject :public QSlotObjectBase,private FunctionStorage<Func>{typedef QtPrivate::FunctionPointer<Func> FuncType;#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)static voidimpl(int which, QSlotObjectBase *this_, QObject *r,void**a,bool*ret)#elsestatic voidimpl(QSlotObjectBase *this_, QObject *r,void**a,int which,bool*ret)#endif{constauto that =static_cast<QPrivateSlotObject*>(this_);switch(which) {case Destroy:delete that;break;case Call:FuncType::template call<Args, R>(that->object(),static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);break;case Compare:*ret = *reinterpret_cast<Func *>(a) == that->object();break;case NumOperations: ;}}public:explicitQPrivateSlotObject(Func f) :QSlotObjectBase(&impl), FunctionStorage<Func>{std::move(f)} {}};}//namespace QtPrivatetemplate<typename Func1, typename Func2>inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,Qt::ConnectionType type){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(int(SignalType::ArgumentCount) >=int(SlotType::ArgumentCount),"The slot requires more arguments than the signal provides.");static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),"Signal and slot arguments are not compatible.");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.");const int*types =nullptr;if(type ==Qt::QueuedConnection || type ==Qt::BlockingQueuedConnection) types =QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();returnQObject::connectImpl(sender,reinterpret_cast<void**>(&signal),QtPrivate::getQObject(receiverPrivate),reinterpret_cast<void**>(&slot),newQtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments,SlotType::ArgumentCount>::Value, typename SignalType::ReturnType>(slot), type, types, &SignalType::Object::staticMetaObject);}template<typename Func1, typename Func2>boolQObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, 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.");returnQObject::disconnectImpl(sender,reinterpret_cast<void**>(&signal), receiverPrivate->q_ptr,reinterpret_cast<void**>(&slot),&SignalType::Object::staticMetaObject);}class QSemaphore;class Q_CORE_EXPORT QAbstractMetaCallEvent :public QEvent {public:QAbstractMetaCallEvent(const QObject *sender,int signalId, QSemaphore *semaphore =nullptr):QEvent(MetaCall),signalId_(signalId),sender_(sender)#if QT_CONFIG(thread),semaphore_(semaphore)#endif{Q_UNUSED(semaphore); }~QAbstractMetaCallEvent();virtualvoidplaceMetaCall(QObject *object) =0;inlineconst QObject *sender()const{return sender_; }inlineintsignalId()const{return signalId_; }private:int signalId_;const QObject *sender_;#if QT_CONFIG(thread) QSemaphore *semaphore_;#endif};class Q_CORE_EXPORT QMetaCallEvent :public QAbstractMetaCallEvent {public:// blocking queued with semaphore - args always owned by callerQMetaCallEvent(ushort method_offset, ushort method_relative,QObjectPrivate::StaticMetaCallFunction callFunction,const QObject *sender,int signalId,void**args, QSemaphore *semaphore);QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,const QObject *sender,int signalId,void**args, QSemaphore *semaphore);QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,const QObject *sender,int signalId,void**args, QSemaphore *semaphore);// queued - args allocated by event, copied by callerQMetaCallEvent(ushort method_offset, ushort method_relative,QObjectPrivate::StaticMetaCallFunction callFunction,const QObject *sender,int signalId,int nargs);QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,const QObject *sender,int signalId,int nargs);QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,const QObject *sender,int signalId,int nargs);~QMetaCallEvent() override;template<typename ...Args>static QMetaCallEvent *create(QtPrivate::QSlotObjectBase *slotObj,const QObject *sender,int signal_index,const Args &...argv){const void*const argp[] = {nullptr,std::addressof(argv)... };const QMetaType metaTypes[] = {QMetaType::fromType<void>(),QMetaType::fromType<Args>()... };constexpr auto argc =sizeof...(Args) +1;returncreate_impl(slotObj, sender, signal_index, argc, argp, metaTypes);}template<typename ...Args>static QMetaCallEvent *create(QtPrivate::SlotObjUniquePtr slotObj,const QObject *sender,int signal_index,const Args &...argv){const void*const argp[] = {nullptr,std::addressof(argv)... };const QMetaType metaTypes[] = {QMetaType::fromType<void>(),QMetaType::fromType<Args>()... };constexpr auto argc =sizeof...(Args) +1;returncreate_impl(std::move(slotObj), sender, signal_index, argc, argp, metaTypes);}inlineintid()const{return d.method_offset_ + d.method_relative_; }inlineconst void*const*args()const{return d.args_; }inlinevoid**args() {return d.args_; }inlineconst QMetaType *types()const{return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }inline QMetaType *types() {return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }virtualvoidplaceMetaCall(QObject *object) override;private:static QMetaCallEvent *create_impl(QtPrivate::QSlotObjectBase *slotObj,const QObject *sender,int signal_index,size_t argc,const void*const argp[],const QMetaType metaTypes[]){if(slotObj) slotObj->ref();returncreate_impl(QtPrivate::SlotObjUniquePtr{slotObj}, sender, signal_index, argc, argp, metaTypes);}static QMetaCallEvent *create_impl(QtPrivate::SlotObjUniquePtr slotObj,const QObject *sender,int signal_index,size_t argc,const void*const argp[],const QMetaType metaTypes[]);inlinevoidallocArgs();struct Data {QtPrivate::SlotObjUniquePtr slotObj_;void**args_;QObjectPrivate::StaticMetaCallFunction callFunction_;int nargs_; ushort method_offset_; ushort method_relative_;} d;// preallocate enough space for three argumentsalignas(void*)char prealloc_[3*sizeof(void*) +3*sizeof(QMetaType)];};struct QAbstractDynamicMetaObject;struct Q_CORE_EXPORT QDynamicMetaObjectData {virtual~QDynamicMetaObjectData();virtualvoidobjectDestroyed(QObject *) {delete this; }#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)virtualconst QMetaObject *toDynamicMetaObject(QObject *)const=0;#elsevirtual QMetaObject *toDynamicMetaObject(QObject *) =0;#endifvirtualintmetaCall(QObject *,QMetaObject::Call,int _id,void**) =0;};struct Q_CORE_EXPORT QAbstractDynamicMetaObject :public QDynamicMetaObjectData,public QMetaObject {~QAbstractDynamicMetaObject();#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)const QMetaObject *toDynamicMetaObject(QObject *)const override {return this; }#else QMetaObject *toDynamicMetaObject(QObject *) override {return this; }#endifvirtualintcreateProperty(const char*,const char*) {return-1; }intmetaCall(QObject *,QMetaObject::Call c,int _id,void**a) override {returnmetaCall(c, _id, a); }virtualintmetaCall(QMetaObject::Call,int _id,void**) {return _id; }// Compat overload};inlineconst QBindingStorage *qGetBindingStorage(const QObjectPrivate *o){return&o->bindingStorage;}inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o){return&o->bindingStorage;}inlineconst QBindingStorage *qGetBindingStorage(constQObjectPrivate::ExtraData *ed){return&ed->parent->bindingStorage;}inline QBindingStorage *qGetBindingStorage(QObjectPrivate::ExtraData *ed){return&ed->parent->bindingStorage;} QT_END_NAMESPACE #endif// QOBJECT_P_H
close