aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2023-10-31 10:42:28 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-11-01 20:14:17 +0000
commita636c056c9d0d0f63641ac1c40f6267c9b98c549 (patch)
treec32e8b415b56718c509f0b48e9c216c238fde866
parent6bafa39e119f9702ddf8be9c5fc7c00c54ed7e1e (diff)
Fix QMetaObject method invocation to accept all of the 10 arguments
Refactor the helper injected into the QMetaObject wrapper code into helper functions in the QtCore glue code that handle all arguments of the QMetaObject::invokeMethod() overloads. Extract a std::function for the actuall call that helps to implement QMetaMethod::invoke() in a follow-up change. Task-number: PYSIDE-2500 Change-Id: I4f2b509a13d252dad92e388e1dfd607ae3eafcd1 Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> (cherry picked from commit dfbf935717996dd22e0dcf48f199492bf0935a1f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp84
-rw-r--r--sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h48
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml51
-rw-r--r--sources/pyside6/PySide6/glue/qtcore.cpp106
4 files changed, 220 insertions, 69 deletions
diff --git a/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp b/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
index b702f8df6..4266e868c 100644
--- a/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
+++ b/sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "core_snippets_p.h"
+#include "qtcorehelper.h"
#include "pysideqobject.h"
#include "shiboken.h"
@@ -10,6 +11,7 @@
#endif
#include "basewrapper.h"
#include "autodecref.h"
+#include "pysideutils.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
@@ -262,3 +264,85 @@ bool PyTime_ImportAndCheck(PyObject *pyIn)
PyDateTime_IMPORT;
return PyTime_Check(pyIn);
}
+
+PyObject *invokeMetaMethod(const InvokeMetaMethodFunc &f,
+ const QtCoreHelper::QGenericArgumentHolder &a0,
+ const QtCoreHelper::QGenericArgumentHolder &a1,
+ const QtCoreHelper::QGenericArgumentHolder &a2,
+ const QtCoreHelper::QGenericArgumentHolder &a3,
+ const QtCoreHelper::QGenericArgumentHolder &a4,
+ const QtCoreHelper::QGenericArgumentHolder &a5,
+ const QtCoreHelper::QGenericArgumentHolder &a6,
+ const QtCoreHelper::QGenericArgumentHolder &a7,
+ const QtCoreHelper::QGenericArgumentHolder &a8,
+ const QtCoreHelper::QGenericArgumentHolder &a9)
+{
+ PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
+ const bool resultB = f(a0.toGenericArgument(), a1.toGenericArgument(), a2.toGenericArgument(),
+ a3.toGenericArgument(), a4.toGenericArgument(), a5.toGenericArgument(),
+ a6.toGenericArgument(), a7.toGenericArgument(), a8.toGenericArgument(),
+ a9.toGenericArgument());
+ PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
+ PyObject *result = resultB ? Py_True : Py_False;
+ Py_INCREF(result);
+ return result;
+}
+
+// Convert a QGenericReturnArgument to Python for QMetaObject::invokeMethod
+static PyObject *convertGenericReturnArgument(const void *retData, QMetaType metaType)
+{
+ PyObject *result = nullptr;
+ switch (metaType.id()) {
+ case QMetaType::Bool:
+ result = *reinterpret_cast<const bool *>(retData) ? Py_True : Py_False;
+ Py_INCREF(result);
+ break;
+ case QMetaType::Int:
+ result = PyLong_FromLong(*reinterpret_cast<const int *>(retData));
+ break;
+ case QMetaType::Double:
+ result = PyFloat_FromDouble(*reinterpret_cast<const double *>(retData));
+ break;
+ case QMetaType::QString:
+ result = PySide::qStringToPyUnicode(*reinterpret_cast<const QString *>(retData));
+ break;
+ default: {
+ Shiboken::Conversions::SpecificConverter converter(metaType.name());
+ const auto type = converter.conversionType();
+ if (type == Shiboken::Conversions::SpecificConverter::InvalidConversion) {
+ PyErr_Format(PyExc_RuntimeError, "%s: Unable to find converter for \"%s\".",
+ __FUNCTION__, metaType.name());
+ return nullptr;
+ }
+ result = converter.toPython(retData);
+ }
+ }
+ return result;
+}
+
+PyObject *invokeMetaMethodWithReturn(const InvokeMetaMethodFuncWithReturn &f,
+ const QtCoreHelper::QGenericReturnArgumentHolder &r,
+ const QtCoreHelper::QGenericArgumentHolder &a0,
+ const QtCoreHelper::QGenericArgumentHolder &a1,
+ const QtCoreHelper::QGenericArgumentHolder &a2,
+ const QtCoreHelper::QGenericArgumentHolder &a3,
+ const QtCoreHelper::QGenericArgumentHolder &a4,
+ const QtCoreHelper::QGenericArgumentHolder &a5,
+ const QtCoreHelper::QGenericArgumentHolder &a6,
+ const QtCoreHelper::QGenericArgumentHolder &a7,
+ const QtCoreHelper::QGenericArgumentHolder &a8,
+ const QtCoreHelper::QGenericArgumentHolder &a9)
+{
+ PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
+ const bool callResult = f(r.toGenericReturnArgument(),
+ a0.toGenericArgument(), a1.toGenericArgument(), a2.toGenericArgument(),
+ a3.toGenericArgument(), a4.toGenericArgument(), a5.toGenericArgument(),
+ a6.toGenericArgument(), a7.toGenericArgument(), a8.toGenericArgument(),
+ a9.toGenericArgument());
+ PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
+ if (!callResult) {
+ PyErr_SetString(PyExc_RuntimeError, "QMetaMethod invocation failed.");
+ return nullptr;
+ }
+ return convertGenericReturnArgument(r.data(), r.metaType());
+}
diff --git a/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h b/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
index 9beddf376..eeeed98e7 100644
--- a/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
+++ b/sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
@@ -12,11 +12,18 @@
#include <functional>
+QT_FORWARD_DECLARE_CLASS(QGenericArgument)
+QT_FORWARD_DECLARE_CLASS(QGenericReturnArgument)
QT_FORWARD_DECLARE_CLASS(QMetaType)
QT_FORWARD_DECLARE_CLASS(QObject)
QT_FORWARD_DECLARE_CLASS(QRegularExpression)
QT_FORWARD_DECLARE_CLASS(QVariant);
+namespace QtCoreHelper {
+class QGenericArgumentHolder;
+class QGenericReturnArgumentHolder;
+}
+
// Helpers for QVariant conversion
QMetaType QVariant_resolveMetaType(PyTypeObject *type);
@@ -52,4 +59,45 @@ bool PyDate_ImportAndCheck(PyObject *pyIn);
bool PyDateTime_ImportAndCheck(PyObject *pyIn);
bool PyTime_ImportAndCheck(PyObject *pyIn);
+// Helpers for QMetaObject::invokeMethod(), QMetaMethod::invoke(). The std::function
+// serves to abstract from QMetaObject/QMetaMethod invocation parameters.
+using InvokeMetaMethodFunc =
+ std::function<bool(QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,
+ QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,
+ QGenericArgument,QGenericArgument)>;
+
+using InvokeMetaMethodFuncWithReturn =
+ std::function<bool(QGenericReturnArgument,
+ QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,
+ QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,
+ QGenericArgument,QGenericArgument)>;
+
+// Call a void meta method from Python passing the argument holder helpers.
+PyObject *invokeMetaMethod(const InvokeMetaMethodFunc &f,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &);
+
+// Call a meta method with a return value from Python passing the argument holder
+// helpers.
+PyObject *invokeMetaMethodWithReturn(const InvokeMetaMethodFuncWithReturn &f,
+ const QtCoreHelper::QGenericReturnArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &,
+ const QtCoreHelper::QGenericArgumentHolder &);
+
#endif // CORE_SNIPPETS_P_H
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index e533b8fdc..411f55149 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -3106,6 +3106,7 @@
<extra-includes>
<include file-name="dynamicqmetaobject.h" location="global"/>
<include file-name="pysidemetatype.h" location="global"/>
+ <include file-name="glue/core_snippets_p.h" location="local"/>
<include file-name="pysideutils.h" location="global"/> <!-- QString conversion -->
</extra-includes>
<inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
@@ -3118,22 +3119,64 @@
<declare-function signature="operator bool() const" return-type="bool"/>
</value-type>
<modify-function signature="^invokeMethod\(" allow-thread="yes"/>
- <add-function signature="invokeMethod(QObject*@object@,const char *@member@,Qt::ConnectionType@type@,QtCoreHelper::QGenericArgumentHolder@val0@={},QtCoreHelper::QGenericArgumentHolder@val1@={},QtCoreHelper::QGenericArgumentHolder@val2@={})"
+ <add-function signature="invokeMethod(QObject*@object@,const char *@member@,Qt::ConnectionType@type@,
+ QtCoreHelper::QGenericArgumentHolder@val0@={},
+ QtCoreHelper::QGenericArgumentHolder@val1@={},
+ QtCoreHelper::QGenericArgumentHolder@val2@={},
+ QtCoreHelper::QGenericArgumentHolder@val3@={},
+ QtCoreHelper::QGenericArgumentHolder@val4@={},
+ QtCoreHelper::QGenericArgumentHolder@val5@={},
+ QtCoreHelper::QGenericArgumentHolder@val6@={},
+ QtCoreHelper::QGenericArgumentHolder@val7@={},
+ QtCoreHelper::QGenericArgumentHolder@val8@={},
+ QtCoreHelper::QGenericArgumentHolder@val9@={})"
static="yes" return-type="bool">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp"
snippet="qmetaobject-invokemethod-conn-type-arg"/>
</add-function>
- <add-function signature="invokeMethod(QObject*@object@,const char *@member@,QtCoreHelper::QGenericArgumentHolder@val0@={},QtCoreHelper::QGenericArgumentHolder@val1@={},QtCoreHelper::QGenericArgumentHolder@val2@={})"
+ <add-function signature="invokeMethod(QObject*@object@,const char *@member@,
+ QtCoreHelper::QGenericArgumentHolder@val0@={},
+ QtCoreHelper::QGenericArgumentHolder@val1@={},
+ QtCoreHelper::QGenericArgumentHolder@val2@={},
+ QtCoreHelper::QGenericArgumentHolder@val3@={},
+ QtCoreHelper::QGenericArgumentHolder@val4@={},
+ QtCoreHelper::QGenericArgumentHolder@val5@={},
+ QtCoreHelper::QGenericArgumentHolder@val6@={},
+ QtCoreHelper::QGenericArgumentHolder@val7@={},
+ QtCoreHelper::QGenericArgumentHolder@val8@={},
+ QtCoreHelper::QGenericArgumentHolder@val9@={})"
static="yes" return-type="bool">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp"
snippet="qmetaobject-invokemethod-arg"/>
</add-function>
- <add-function signature="invokeMethod(QObject*@object@,const char *@member@,Qt::ConnectionType@type@,QtCoreHelper::QGenericReturnArgumentHolder@ret@,QtCoreHelper::QGenericArgumentHolder@val0@={},QtCoreHelper::QGenericArgumentHolder@val1@={},QtCoreHelper::QGenericArgumentHolder@val2@={})"
+ <add-function signature="invokeMethod(QObject*@object@,const char *@member@,Qt::ConnectionType@type@,
+ QtCoreHelper::QGenericReturnArgumentHolder@ret@,
+ QtCoreHelper::QGenericArgumentHolder@val0@={},
+ QtCoreHelper::QGenericArgumentHolder@val1@={},
+ QtCoreHelper::QGenericArgumentHolder@val2@={},
+ QtCoreHelper::QGenericArgumentHolder@val3@={},
+ QtCoreHelper::QGenericArgumentHolder@val4@={},
+ QtCoreHelper::QGenericArgumentHolder@val5@={},
+ QtCoreHelper::QGenericArgumentHolder@val6@={},
+ QtCoreHelper::QGenericArgumentHolder@val7@={},
+ QtCoreHelper::QGenericArgumentHolder@val8@={},
+ QtCoreHelper::QGenericArgumentHolder@val9@={})"
static="yes" return-type="PyObject*">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp"
snippet="qmetaobject-invokemethod-conn-type-return-arg"/>
</add-function>
- <add-function signature="invokeMethod(QObject*@object@,const char *@member@,QtCoreHelper::QGenericReturnArgumentHolder@ret@,QtCoreHelper::QGenericArgumentHolder@val0@={},QtCoreHelper::QGenericArgumentHolder@val1@={},QtCoreHelper::QGenericArgumentHolder@val2@={})"
+ <add-function signature="invokeMethod(QObject*@object@,const char *@member@,
+ QtCoreHelper::QGenericReturnArgumentHolder@ret@,
+ QtCoreHelper::QGenericArgumentHolder@val0@={},
+ QtCoreHelper::QGenericArgumentHolder@val1@={},
+ QtCoreHelper::QGenericArgumentHolder@val2@={},
+ QtCoreHelper::QGenericArgumentHolder@val3@={},
+ QtCoreHelper::QGenericArgumentHolder@val4@={},
+ QtCoreHelper::QGenericArgumentHolder@val5@={},
+ QtCoreHelper::QGenericArgumentHolder@val6@={},
+ QtCoreHelper::QGenericArgumentHolder@val7@={},
+ QtCoreHelper::QGenericArgumentHolder@val8@={},
+ QtCoreHelper::QGenericArgumentHolder@val9@={})"
static="yes" return-type="PyObject*">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp"
snippet="qmetaobject-invokemethod-return-arg"/>
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
index 6bf03a6bb..0dcd458bd 100644
--- a/sources/pyside6/PySide6/glue/qtcore.cpp
+++ b/sources/pyside6/PySide6/glue/qtcore.cpp
@@ -1750,85 +1750,61 @@ QtCoreHelper::QGenericReturnArgumentHolder result(qArgData.metaType, qArgData.da
%PYARG_0 = %CONVERTTOPYTHON[QtCoreHelper::QGenericReturnArgumentHolder](result);
// @snippet q_return_arg
+// @snippet qmetaobject-invokemethod-helpers
+static InvokeMetaMethodFunc
+ createInvokeMetaMethodFunc(QObject *object, const char *methodName,
+ Qt::ConnectionType type = Qt::AutoConnection)
+{
+ return [object, methodName, type](QGenericArgument a0, QGenericArgument a1,
+ QGenericArgument a2, QGenericArgument a3,
+ QGenericArgument a4, QGenericArgument a5,
+ QGenericArgument a6, QGenericArgument a7,
+ QGenericArgument a8, QGenericArgument a9) -> bool
+ {
+ return QMetaObject::invokeMethod(object, methodName, type,
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+}
+
+static InvokeMetaMethodFuncWithReturn
+ createInvokeMetaMethodFuncWithReturn(QObject *object, const char *methodName,
+ Qt::ConnectionType type = Qt::AutoConnection)
+{
+ return [object, methodName, type](QGenericReturnArgument r,
+ QGenericArgument a0, QGenericArgument a1,
+ QGenericArgument a2, QGenericArgument a3,
+ QGenericArgument a4, QGenericArgument a5,
+ QGenericArgument a6, QGenericArgument a7,
+ QGenericArgument a8, QGenericArgument a9) -> bool
+ {
+ return QMetaObject::invokeMethod(object, methodName, type,
+ r, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+}
+// @snippet qmetaobject-invokemethod-helpers
+
// invokeMethod(QObject *,const char *, QGenericArgument a0, a1, a2 )
// @snippet qmetaobject-invokemethod-arg
-PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
-const bool result = %CPPSELF.invokeMethod(%1, %2, %3.toGenericArgument(), %4.toGenericArgument(),
- %5.toGenericArgument());
-PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
-%PYARG_0 = %CONVERTTOPYTHON[bool](result);
+%PYARG_0 = invokeMetaMethod(createInvokeMetaMethodFunc(%1, %2),
+ %3, %4, %5, %6, %7, %8, %9, %10, %11, %12);
// @snippet qmetaobject-invokemethod-arg
// invokeMethod(QObject *,const char *,Qt::ConnectionType, QGenericArgument a0, a1, a2 )
// @snippet qmetaobject-invokemethod-conn-type-arg
-PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
-const bool result = %CPPSELF.invokeMethod(%1, %2, %3,
- %4.toGenericArgument(), %5.toGenericArgument(),
- %6.toGenericArgument());
-PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
-%PYARG_0 = %CONVERTTOPYTHON[bool](result);
+%PYARG_0 = invokeMetaMethod(createInvokeMetaMethodFunc(%1, %2, %3),
+ %4, %5, %6, %7, %8, %9, %10, %11, %12, %13);
// @snippet qmetaobject-invokemethod-conn-type-arg
-// @snippet qmetaobject-invokemethod-helpers
-static PyObject *invokeMethodHelper(QObject *obj, const char *member, Qt::ConnectionType type,
- const QtCoreHelper::QGenericReturnArgumentHolder &returnArg,
- const QtCoreHelper::QGenericArgumentHolder &v1,
- const QtCoreHelper::QGenericArgumentHolder &v2,
- const QtCoreHelper::QGenericArgumentHolder &v3)
-
-{
- PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
- const bool callResult = QMetaObject::invokeMethod(obj, member, type,
- returnArg.toGenericReturnArgument(),
- v1.toGenericArgument(), v2.toGenericArgument(),
- v3.toGenericArgument());
- PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
- if (!callResult) {
- PyErr_Format(PyExc_RuntimeError, "QMetaObject::invokeMethod(): Invocation of %s::%s() failed.",
- obj->metaObject()->className(), member);
- return nullptr;
- }
-
- PyObject *result = nullptr;
- const void *retData = returnArg.data();
- const QMetaType metaType = returnArg.metaType();
- switch (metaType.id()) {
- case QMetaType::Bool:
- result = *reinterpret_cast<const bool *>(retData) ? Py_True : Py_False;
- Py_INCREF(result);
- break;
- case QMetaType::Int:
- result = PyLong_FromLong(*reinterpret_cast<const int *>(retData));
- break;
- case QMetaType::Double:
- result = PyFloat_FromDouble(*reinterpret_cast<const double *>(retData));
- break;
- case QMetaType::QString:
- result = PySide::qStringToPyUnicode(*reinterpret_cast<const QString *>(retData));
- break;
- default: {
- Shiboken::Conversions::SpecificConverter converter(metaType.name());
- const auto type = converter.conversionType();
- if (type == Shiboken::Conversions::SpecificConverter::InvalidConversion) {
- PyErr_Format(PyExc_RuntimeError, "%s: Unable to find converter for \"%s\".",
- __FUNCTION__, metaType.name());
- return nullptr;
- }
- result = converter.toPython(retData);
- }
- }
- return result;
-}
-// @snippet qmetaobject-invokemethod-helpers
-
// invokeMethod(QObject *,const char *, Qt::ConnectionType, QGenericReturnArgument,QGenericArgument a0, a1, a2 )
// @snippet qmetaobject-invokemethod-conn-type-return-arg
-%PYARG_0 = invokeMethodHelper(%1, %2, %3, %4, %5, %6, %7);
+%PYARG_0 = invokeMetaMethodWithReturn(createInvokeMetaMethodFuncWithReturn(%1, %2, %3),
+ %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14);
// @snippet qmetaobject-invokemethod-conn-type-return-arg
// invokeMethod(QObject *,const char *, QGenericReturnArgument,QGenericArgument a0, a1, a2 )
// @snippet qmetaobject-invokemethod-return-arg
-%PYARG_0 = invokeMethodHelper(%1, %2, Qt::AutoConnection, %3, %4, %5, %6);
+%PYARG_0 = invokeMetaMethodWithReturn(createInvokeMetaMethodFuncWithReturn(%1, %2),
+ %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13);
// @snippet qmetaobject-invokemethod-return-arg
// @snippet keycombination-from-keycombination