| /**************************************************************************** |
| ** |
| ** Copyright (C) 2015 The Qt Company Ltd. |
| ** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> |
| ** Contact: http://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtCore module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL21$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see http://www.qt.io/terms-conditions. For further |
| ** information use the contact form at http://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 2.1 or version 3 as published by the Free |
| ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
| ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
| ** following information to ensure the GNU Lesser General Public License |
| ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** As a special exception, The Qt Company gives you certain additional |
| ** rights. These rights are described in The Qt Company LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #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/qobject.h" |
| #include "QtCore/qpointer.h" |
| #include "QtCore/qsharedpointer.h" |
| #include "QtCore/qcoreevent.h" |
| #include "QtCore/qlist.h" |
| #include "QtCore/qvector.h" |
| #include "QtCore/qvariant.h" |
| #include "QtCore/qreadwritelock.h" |
| |
| QT_BEGIN_NAMESPACE |
| |
| class QVariant; |
| class QThreadData; |
| class QObjectConnectionListVector; |
| namespace QtSharedPointer { struct ExternalRefCountData; } |
| |
| /* for Qt Test */ |
| struct QSignalSpyCallbackSet |
| { |
| typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv); |
| typedef void (*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(const QSignalSpyCallbackSet &callback_set); |
| |
| extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set; |
| |
| enum { QObjectPrivateVersion = QT_VERSION }; |
| |
| class Q_CORE_EXPORT QAbstractDeclarativeData |
| { |
| public: |
| static void (*destroyed)(QAbstractDeclarativeData *, QObject *); |
| static void (*destroyed_qml1)(QAbstractDeclarativeData *, QObject *); |
| static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, 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. |
| }; |
| |
| // This is an implementation of QAbstractDeclarativeData that is identical with |
| // the implementation in QtDeclarative and QtQml for the first bit |
| struct QAbstractDeclarativeDataImpl : public QAbstractDeclarativeData |
| { |
| quint32 ownedByQml1:1; |
| quint32 unused: 31; |
| }; |
| |
| class Q_CORE_EXPORT QObjectPrivate : public QObjectData |
| { |
| Q_DECLARE_PUBLIC(QObject) |
| |
| public: |
| struct ExtraData |
| { |
| ExtraData() {} |
| #ifndef QT_NO_USERDATA |
| QVector<QObjectUserData *> userData; |
| #endif |
| QList<QByteArray> propertyNames; |
| QList<QVariant> propertyValues; |
| QVector<int> runningTimers; |
| QList<QPointer<QObject> > eventFilters; |
| QString objectName; |
| }; |
| |
| typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **); |
| struct Connection |
| { |
| QObject *sender; |
| QObject *receiver; |
| union { |
| StaticMetaCallFunction callFunction; |
| QtPrivate::QSlotObjectBase *slotObj; |
| }; |
| // The next pointer for the singly-linked ConnectionList |
| Connection *nextConnectionList; |
| //senders linked list |
| Connection *next; |
| Connection **prev; |
| QAtomicPointer<const int> argumentTypes; |
| QAtomicInt ref_; |
| ushort method_offset; |
| ushort method_relative; |
| uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex()) |
| ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking |
| ushort isSlotObject : 1; |
| ushort ownArgumentTypes : 1; |
| Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) { |
| //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection |
| } |
| ~Connection(); |
| int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; } |
| void ref() { ref_.ref(); } |
| void deref() { |
| if (!ref_.deref()) { |
| Q_ASSERT(!receiver); |
| delete this; |
| } |
| } |
| }; |
| // ConnectionList is a singly-linked list |
| struct ConnectionList { |
| ConnectionList() : first(0), last(0) {} |
| Connection *first; |
| Connection *last; |
| }; |
| |
| struct Sender |
| { |
| QObject *sender; |
| int signal; |
| int ref; |
| }; |
| |
| |
| QObjectPrivate(int version = QObjectPrivateVersion); |
| virtual ~QObjectPrivate(); |
| void deleteChildren(); |
| |
| void setParent_helper(QObject *); |
| void moveToThread_helper(); |
| void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); |
| void _q_reregisterTimers(void *pointer); |
| |
| bool isSender(const QObject *receiver, const char *signal) const; |
| QObjectList receiverList(const char *signal) const; |
| QObjectList senderList() const; |
| |
| void addConnection(int signal, Connection *c); |
| void cleanConnectionLists(); |
| |
| static inline Sender *setCurrentSender(QObject *receiver, |
| Sender *sender); |
| static inline void resetCurrentSender(QObject *receiver, |
| Sender *currentSender, |
| Sender *previousSender); |
| |
| static QObjectPrivate *get(QObject *o) { |
| return o->d_func(); |
| } |
| |
| int signalIndex(const char *signalName, const QMetaObject **meta = 0) const; |
| inline bool isSignalConnected(uint signalIdx) const; |
| |
| // To allow abitrary objects to call connectNotify()/disconnectNotify() without making |
| // the API public in QObject. This is used by QQmlNotifierEndpoint. |
| inline void connectNotify(const QMetaMethod &signal); |
| inline void disconnectNotify(const QMetaMethod &signal); |
| |
| template <typename Func1, typename Func2> |
| static inline 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> |
| static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
| const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot); |
| |
| static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, |
| const QObject *receiver, void **slot, |
| QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, |
| const int *types, const QMetaObject *senderMetaObject); |
| static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); |
| static bool disconnect(const QObject *sender, int signal_index, void **slot); |
| public: |
| ExtraData *extraData; // extra data set by the user |
| QThreadData *threadData; // id of the thread that owns the object |
| |
| QObjectConnectionListVector *connectionLists; |
| |
| Connection *senders; // linked list of connections connected to this object |
| Sender *currentSender; // object currently activating the object |
| mutable quint32 connectedSignals[2]; |
| |
| union { |
| QObject *currentChildBeingDeleted; |
| 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; |
| }; |
| |
| |
| /*! \internal |
| |
| Returns \c true if the signal with index \a signal_index from object \a sender is connected. |
| Signals with indices above a certain range are always considered connected (see connectedSignals |
| in QObjectPrivate). |
| |
| \a signal_index must be the index returned by QObjectPrivate::signalIndex; |
| */ |
| inline bool QObjectPrivate::isSignalConnected(uint signal_index) const |
| { |
| return signal_index >= sizeof(connectedSignals) * 8 |
| || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f)) |
| || (declarativeData && QAbstractDeclarativeData::isSignalConnected |
| && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index))); |
| } |
| |
| inline QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, |
| Sender *sender) |
| { |
| Sender *previousSender = receiver->d_func()->currentSender; |
| receiver->d_func()->currentSender = sender; |
| return previousSender; |
| } |
| |
| inline void QObjectPrivate::resetCurrentSender(QObject *receiver, |
| Sender *currentSender, |
| Sender *previousSender) |
| { |
| // ref is set to zero when this object is deleted during the metacall |
| if (currentSender->ref == 1) |
| receiver->d_func()->currentSender = previousSender; |
| // if we've recursed, we need to tell the caller about the objects deletion |
| if (previousSender) |
| previousSender->ref = currentSender->ref; |
| } |
| |
| inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) |
| { |
| q_ptr->connectNotify(signal); |
| } |
| |
| inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) |
| { |
| q_ptr->disconnectNotify(signal); |
| } |
| |
| namespace QtPrivate { |
| template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase |
| { |
| typedef QtPrivate::FunctionPointer<Func> FuncType; |
| Func function; |
| static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) |
| { |
| switch (which) { |
| case Destroy: |
| delete static_cast<QPrivateSlotObject*>(this_); |
| break; |
| case Call: |
| FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function, |
| static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a); |
| break; |
| case Compare: |
| *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function; |
| break; |
| case NumOperations: ; |
| } |
| } |
| public: |
| explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} |
| }; |
| } //namespace QtPrivate |
| |
| template <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; |
| Q_STATIC_ASSERT_X(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. |
| Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), |
| "The slot requires more arguments than the signal provides."); |
| Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), |
| "Signal and slot arguments are not compatible."); |
| Q_STATIC_ASSERT_X((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 = 0; |
| if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) |
| types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); |
| |
| return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal), |
| receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot), |
| new QtPrivate::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> |
| bool QObjectPrivate::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; |
| Q_STATIC_ASSERT_X(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. |
| Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), |
| "Signal and slot arguments are not compatible."); |
| return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal), |
| receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot), |
| &SignalType::Object::staticMetaObject); |
| } |
| |
| Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE); |
| Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE); |
| |
| class QSemaphore; |
| class Q_CORE_EXPORT QMetaCallEvent : public QEvent |
| { |
| public: |
| QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId, |
| int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); |
| /*! \internal |
| \a signalId is in the signal index range (see QObjectPrivate::signalIndex()). |
| */ |
| QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId, |
| int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); |
| |
| ~QMetaCallEvent(); |
| |
| inline int id() const { return method_offset_ + method_relative_; } |
| inline const QObject *sender() const { return sender_; } |
| inline int signalId() const { return signalId_; } |
| inline void **args() const { return args_; } |
| |
| virtual void placeMetaCall(QObject *object); |
| |
| private: |
| QtPrivate::QSlotObjectBase *slotObj_; |
| const QObject *sender_; |
| int signalId_; |
| int nargs_; |
| int *types_; |
| void **args_; |
| QSemaphore *semaphore_; |
| QObjectPrivate::StaticMetaCallFunction callFunction_; |
| ushort method_offset_; |
| ushort method_relative_; |
| }; |
| |
| class QBoolBlocker |
| { |
| Q_DISABLE_COPY(QBoolBlocker) |
| public: |
| explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} |
| inline ~QBoolBlocker(){block = reset; } |
| private: |
| bool █ |
| bool reset; |
| }; |
| |
| void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); |
| |
| struct QAbstractDynamicMetaObject; |
| struct Q_CORE_EXPORT QDynamicMetaObjectData |
| { |
| virtual ~QDynamicMetaObjectData() {} |
| virtual void objectDestroyed(QObject *) { delete this; } |
| |
| virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0; |
| virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0; |
| }; |
| |
| struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject |
| { |
| virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) Q_DECL_OVERRIDE { return this; } |
| virtual int createProperty(const char *, const char *) { return -1; } |
| virtual int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) Q_DECL_OVERRIDE |
| { return metaCall(c, _id, a); } |
| virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload |
| }; |
| |
| QT_END_NAMESPACE |
| |
| #endif // QOBJECT_P_H |