diff options
Diffstat (limited to 'src/corelib/kernel/qobject.h')
-rw-r--r-- | src/corelib/kernel/qobject.h | 287 |
1 files changed, 126 insertions, 161 deletions
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index e75cf3217e..06cfefd61b 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// 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 @@ -54,16 +18,15 @@ #include <QtCore/qmetatype.h> #include <QtCore/qobject_impl.h> -#include <QtCore/qproperty.h> +#include <QtCore/qbindingstorage.h> +#include <QtCore/qtcoreexports.h> -#if __has_include(<chrono>) -# include <chrono> -#endif +#include <chrono> QT_BEGIN_NAMESPACE -class QBindingStorage; +template <typename T> class QBindable; class QEvent; class QTimerEvent; class QChildEvent; @@ -81,13 +44,24 @@ struct QDynamicMetaObjectData; typedef QList<QObject*> QObjectList; +#if QT_CORE_REMOVED_SINCE(6, 7) Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options); +#endif +Q_CORE_EXPORT void qt_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 void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options); +#endif Q_CORE_EXPORT void qt_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 { @@ -107,8 +81,12 @@ public: uint receiveChildEvents : 1; uint isWindow : 1; // for QWindow uint deleteLaterCalled : 1; - uint unused : 24; - int postedEvents; + 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; @@ -136,45 +114,58 @@ public: virtual bool event(QEvent *event); virtual bool eventFilter(QObject *watched, QEvent *event); -#if defined(QT_NO_TRANSLATION) || defined(Q_CLANG_QDOC) +#if defined(QT_NO_TRANSLATION) || defined(Q_QDOC) static QString tr(const char *sourceText, const char * = nullptr, int = -1) { return QString::fromUtf8(sourceText); } #endif // QT_NO_TRANSLATION QString objectName() const; +#if QT_CORE_REMOVED_SINCE(6, 4) void setObjectName(const QString &name); +#endif + Q_WEAK_OVERLOAD + void setObjectName(const QString &name) { doSetObjectName(name); } + void setObjectName(QAnyStringView name); QBindable<QString> bindableObjectName(); inline bool isWidgetType() const { return d_ptr->isWidget; } inline bool isWindowType() const { return d_ptr->isWindow; } + inline bool isQuickItemType() const { return d_ptr->isQuickItem; } inline bool signalsBlocked() const noexcept { return d_ptr->blockSig; } bool blockSignals(bool b) noexcept; QThread *thread() const; +#if QT_CORE_REMOVED_SINCE(6, 7) void moveToThread(QThread *thread); +#endif + bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL); int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer); -#if __has_include(<chrono>) - Q_ALWAYS_INLINE - int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer) - { - return startTimer(int(time.count()), timerType); - } + +#if QT_CORE_REMOVED_SINCE(6, 8) + int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer); #endif + int startTimer(std::chrono::nanoseconds time, Qt::TimerType timerType = Qt::CoarseTimer); + void killTimer(int id); + void killTimer(Qt::TimerId id); template<typename T> - inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const + 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> - inline QList<T> findChildren(const QString &aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const + 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); @@ -182,13 +173,15 @@ public: } 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 { - typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType; - QList<T> list; - qt_qFindChildren_helper(this, ObjType::staticMetaObject, - reinterpret_cast<QList<void *> *>(&list), options); - return list; + return findChildren<T>(QAnyStringView{}, options); } #if QT_CONFIG(regularexpression) @@ -196,6 +189,8 @@ public: 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); @@ -219,7 +214,7 @@ public: inline QMetaObject::Connection connect(const QObject *sender, const char *signal, const char *member, Qt::ConnectionType type = Qt::AutoConnection) const; -#ifdef Q_CLANG_QDOC +#ifdef Q_QDOC template<typename PointerToMemberFunction> static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection); template<typename PointerToMemberFunction, typename Functor> @@ -227,54 +222,28 @@ public: template<typename PointerToMemberFunction, typename Functor> static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection); #else - //Connect a signal to a pointer to qobject member function + //connect with context 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 *receiver, Func2 slot, - Qt::ConnectionType type = Qt::AutoConnection) + static inline 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<Func2> SlotType; + typedef QtPrivate::FunctionPointer<std::decay_t<Func2>> SlotType; - static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value, - "No Q_OBJECT in the class with the signal"); + if constexpr (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 { + constexpr int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<std::decay_t<Func2>, typename SignalType::Arguments>::Value; + [[maybe_unused]] + constexpr int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0; + typedef typename QtPrivate::FunctorReturnType<std::decay_t<Func2>, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType; - //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(); - - return connectImpl(sender, reinterpret_cast<void **>(&signal), - receiver, reinterpret_cast<void **>(&slot), - new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, - typename SignalType::ReturnType>(slot), - type, types, &SignalType::Object::staticMetaObject); - } - - //connect to a function pointer (not a member) - template <typename Func1, typename Func2> - static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::type - connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot) - { - return connect(sender, signal, sender, slot, Qt::DirectConnection); - } - - //connect to a function pointer (not a member) - template <typename Func1, typename Func2> - static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 && - !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::type - connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot, - Qt::ConnectionType type = Qt::AutoConnection) - { - typedef QtPrivate::FunctionPointer<Func1> SignalType; - typedef QtPrivate::FunctionPointer<Func2> SlotType; + 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"); @@ -282,67 +251,35 @@ public: //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(); - return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr, - new QtPrivate::QStaticSlotObject<Func2, - typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, - typename SignalType::ReturnType>(slot), + void **pSlot = nullptr; + if constexpr (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."); + } + + return connectImpl(sender, reinterpret_cast<void **>(&signal), context, pSlot, + QtPrivate::makeCallableObject<Func1>(std::forward<Func2>(slot)), type, types, &SignalType::Object::staticMetaObject); } - //connect to a functor +#ifndef QT_NO_CONTEXTLESS_CONNECT + //connect without context template <typename Func1, typename Func2> - static inline typename std::enable_if< - QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 && - !std::is_convertible_v<Func2, const char*>, // don't match old-style connect - QMetaObject::Connection>::type - connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot) + static inline QMetaObject::Connection + connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot) { - return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection); - } - - //connect to a functor, with a "context" object defining in which event loop is going to be executed - template <typename Func1, typename Func2> - static inline typename std::enable_if< - QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 && - !std::is_convertible_v<Func2, const char*>, // don't match old-style connect - QMetaObject::Connection>::type - connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot, - Qt::ConnectionType type = Qt::AutoConnection) - { - typedef QtPrivate::FunctionPointer<Func1> SignalType; - const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value; - - static_assert((FunctorArgumentCount >= 0), - "Signal and slot arguments are not compatible."); - const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0; - typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value 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"); - - const int *types = nullptr; - if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) - types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); - - return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr, - new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount, - typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value, - typename SignalType::ReturnType>(std::move(slot)), - type, types, &SignalType::Object::staticMetaObject); + return connect(sender, signal, sender, std::forward<Func2>(slot), Qt::DirectConnection); } -#endif //Q_CLANG_QDOC +#endif // QT_NO_CONTEXTLESS_CONNECT +#endif //Q_QDOC static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member); @@ -355,7 +292,7 @@ public: { return disconnect(this, nullptr, receiver, member); } static bool disconnect(const QMetaObject::Connection &); -#ifdef Q_CLANG_QDOC +#ifdef Q_QDOC template<typename PointerToMemberFunction> static bool disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method); #else @@ -388,18 +325,18 @@ public: return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, zero, &SignalType::Object::staticMetaObject); } -#endif //Q_CLANG_QDOC +#endif //Q_QDOC void dumpObjectTree() const; void dumpObjectInfo() const; -#ifndef QT_NO_PROPERTIES + QT_CORE_INLINE_SINCE(6, 6) bool setProperty(const char *name, const QVariant &value); + inline bool setProperty(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; } -#endif // QT_NO_PROPERTIES Q_SIGNALS: void destroyed(QObject * = nullptr); @@ -447,8 +384,10 @@ protected: friend class QThreadData; private: + void doSetObjectName(const QString &name); + bool doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue); + Q_DISABLE_COPY(QObject) - Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *)) private: static QMetaObject::Connection connectImpl(const QObject *sender, void **signal, @@ -465,9 +404,22 @@ inline QMetaObject::Connection QObject::connect(const QObject *asender, const ch const char *amember, Qt::ConnectionType atype) const { return connect(asender, asignal, this, amember, atype); } +#if QT_CORE_INLINE_IMPL_SINCE(6, 6) +bool QObject::setProperty(const char *name, const QVariant &value) +{ + return doSetProperty(name, &value, nullptr); +} +#endif // inline since 6.6 +bool QObject::setProperty(const char *name, QVariant &&value) +{ + return doSetProperty(name, &value, &value); +} + template <class T> inline T qobject_cast(QObject *object) { + static_assert(std::is_pointer_v<T>, + "qobject_cast requires to cast towards a pointer type"); typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType; static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value, "qobject_cast requires the type to have a Q_OBJECT macro"); @@ -477,6 +429,10 @@ inline T qobject_cast(QObject *object) template <class T> inline T qobject_cast(const QObject *object) { + static_assert(std::is_pointer_v<T>, + "qobject_cast requires to cast towards a pointer type"); + static_assert(std::is_const_v<std::remove_pointer_t<T>>, + "qobject_cast cannot cast away constness (use const_cast)"); typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType; static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value, "qobject_cast requires the type to have a Q_OBJECT macro"); @@ -498,7 +454,7 @@ qobject_iid_cast(const QObject *object) return qobject_iid_cast<std::remove_cv_t<T>>(o); } -#if defined(Q_CLANG_QDOC) +#if defined(Q_QDOC) # define Q_DECLARE_INTERFACE(IFace, IId) #elif !defined(Q_MOC_RUN) # define Q_DECLARE_INTERFACE(IFace, IId) \ @@ -526,15 +482,19 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *); class QSignalBlocker { public: + Q_NODISCARD_CTOR inline explicit QSignalBlocker(QObject *o) noexcept; + Q_NODISCARD_CTOR inline explicit QSignalBlocker(QObject &o) noexcept; inline ~QSignalBlocker(); + Q_NODISCARD_CTOR inline QSignalBlocker(QSignalBlocker &&other) noexcept; inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept; inline void reblock() noexcept; inline void unblock() noexcept; + inline void dismiss() noexcept; private: Q_DISABLE_COPY(QSignalBlocker) @@ -599,11 +559,16 @@ void QSignalBlocker::unblock() noexcept m_inhibited = true; } +void QSignalBlocker::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(QLatin1String(#obj)) +#define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1StringView(#obj)) QT_END_NAMESPACE |