diff options
author | Mårten Nordheim <marten.nordheim@qt.io> | 2023-06-27 18:29:38 +0200 |
---|---|---|
committer | Mårten Nordheim <marten.nordheim@qt.io> | 2023-08-24 07:45:04 +0200 |
commit | a7d2855b3c7716467c827f27359259afb5c4cbea (patch) | |
tree | b3130eeed1d0af9ac371715f7c35215472ec1346 /src/corelib/kernel/qmetaobject.cpp | |
parent | 777a1ed19185c594d7f43296e0044e3e354690ca (diff) |
invokeMethod: enable passing parameters to overload taking functors
This was missing for a while, and there is nothing fundamentally
missing for it to work.
With the more recent work around slot objects and invokeMethod in
general, it is a good time to add support for this.
In this patch, when connecting to a functor, it automatically deduces
the overload to call based on the arguments passed to invokeMethod.
Sharing code with QObject::connect could be done, but they have a
key difference that makes it harder:
With signal emissions we throw away trailing arguments that are not
used: i.e. `signal(int, int)` can be connected to `slot(int)` or
`slot()`. With invokeMethod that's not a thing. So we will need a way
to toggle that behavior during resolution.
[ChangeLog][QtCore][QMetaObject] Added support for passing parameters
to the overload of QMetaObject::invokeMethod that takes a functor. These
new overloads must have the return-value passed through qReturnArg().
Change-Id: If4fcbb75515b19e72fab80115c109efa37e6626e
Reviewed-by: Ievgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qmetaobject.cpp')
-rw-r--r-- | src/corelib/kernel/qmetaobject.cpp | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index c6ab79718b..7445974404 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1612,12 +1612,16 @@ bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::Connect return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames, metaTypes); } -bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, - Qt::ConnectionType type, void *ret) +bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, + qsizetype parameterCount, const void *const *params, const char *const *names, + const QtPrivate::QMetaTypeInterface * const *metaTypes) { + // We don't need this now but maybe we want it later, or we may be able to + // share more code between the two invokeMethodImpl() overloads: + Q_UNUSED(names); auto slot = QtPrivate::SlotObjUniquePtr(slotObj); - if (! object) + if (! object) // ### only if the slot requires the object + not queued? return false; Qt::HANDLE currentThreadId = QThread::currentThreadId(); @@ -1629,8 +1633,7 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase * if (type == Qt::AutoConnection) type = receiverInSameThread ? Qt::DirectConnection : Qt::QueuedConnection; - void *argv[] = { ret }; - + void **argv = const_cast<void **>(params); if (type == Qt::DirectConnection) { slot->call(object, argv); } else if (type == Qt::QueuedConnection) { @@ -1639,8 +1642,16 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase * "queued connections"); return false; } + auto event = std::make_unique<QMetaCallEvent>(std::move(slot), nullptr, -1, parameterCount); + void **args = event->args(); + QMetaType *types = event->types(); - QCoreApplication::postEvent(object, new QMetaCallEvent(std::move(slot), nullptr, -1, 1)); + for (int i = 1; i < parameterCount; ++i) { + types[i] = QMetaType(metaTypes[i]); + args[i] = types[i].create(argv[i]); + } + + QCoreApplication::postEvent(object, event.release()); } else if (type == Qt::BlockingQueuedConnection) { #if QT_CONFIG(thread) if (receiverInSameThread) @@ -1734,6 +1745,31 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase * */ /*! + \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments) + \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments) + \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments) + \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Args &&...arguments) + + \since 6.7 + \threadsafe + + Invokes the \a function with \a arguments in the event loop of \a context. + \a function can be a functor or a pointer to a member function. Returns + \c true if the function could be invoked. The return value of the + function call is placed in \a ret. The object used for the \a ret argument + should be obtained by passing your object to qReturnArg(). For example: + + \badcode + MyClass *obj = ...; + int result = 0; + QMetaObject::invokeMethod(obj, &MyClass::myMethod, qReturnArg(result), parameter); + \endcode + + If \a type is set, then the function is invoked using that connection type. + Otherwise, Qt::AutoConnection will be used. +*/ + +/*! \fn QMetaObject::Connection &QMetaObject::Connection::operator=(Connection &&other) Move-assigns \a other to this object, and returns a reference. |