aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside/pysidemetafunction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpyside/pysidemetafunction.cpp')
-rw-r--r--sources/pyside6/libpyside/pysidemetafunction.cpp231
1 files changed, 231 insertions, 0 deletions
diff --git a/sources/pyside6/libpyside/pysidemetafunction.cpp b/sources/pyside6/libpyside/pysidemetafunction.cpp
new file mode 100644
index 000000000..6d93e7629
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidemetafunction.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $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$
+**
+****************************************************************************/
+
+#include "pysidemetafunction.h"
+#include "pysidemetafunction_p.h"
+
+#include <shiboken.h>
+#include <signature.h>
+
+#include <QtCore/QMetaMethod>
+
+extern "C"
+{
+
+struct PySideMetaFunctionPrivate
+{
+ QObject *qobject;
+ int methodIndex;
+};
+
+//methods
+static void functionFree(void *);
+static PyObject *functionCall(PyObject *, PyObject *, PyObject *);
+
+static PyType_Slot PySideMetaFunctionType_slots[] = {
+ {Py_tp_call, (void *)functionCall},
+ {Py_tp_new, (void *)PyType_GenericNew},
+ {Py_tp_free, (void *)functionFree},
+ {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {0, 0}
+};
+static PyType_Spec PySideMetaFunctionType_spec = {
+ "2:PySide6.QtCore.MetaFunction",
+ sizeof(PySideMetaFunction),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideMetaFunctionType_slots,
+};
+
+
+PyTypeObject *PySideMetaFunctionTypeF(void)
+{
+ static PyTypeObject *type = reinterpret_cast<PyTypeObject *>(
+ SbkType_FromSpec(&PySideMetaFunctionType_spec));
+ return type;
+}
+
+void functionFree(void *self)
+{
+ PySideMetaFunction *function = reinterpret_cast<PySideMetaFunction *>(self);
+ delete function->d;
+}
+
+PyObject *functionCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ PySideMetaFunction *function = reinterpret_cast<PySideMetaFunction *>(self);
+
+ PyObject *retVal;
+ if (!PySide::MetaFunction::call(function->d->qobject, function->d->methodIndex, args, &retVal))
+ return 0;
+ return retVal;
+}
+
+} // extern "C"
+
+namespace PySide { namespace MetaFunction {
+
+static const char *MetaFunction_SignatureStrings[] = {
+ "PySide6.QtCore.MetaFunction.__call__(*args:typing.Any)->typing.Any",
+ nullptr}; // Sentinel
+
+void init(PyObject *module)
+{
+ if (InitSignatureStrings(PySideMetaFunctionTypeF(), MetaFunction_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideMetaFunctionTypeF());
+ PyModule_AddObject(module, "MetaFunction", reinterpret_cast<PyObject *>(PySideMetaFunctionTypeF()));
+}
+
+PySideMetaFunction *newObject(QObject *source, int methodIndex)
+{
+ if (methodIndex >= source->metaObject()->methodCount())
+ return 0;
+
+ QMetaMethod method = source->metaObject()->method(methodIndex);
+ if ((method.methodType() == QMetaMethod::Slot) ||
+ (method.methodType() == QMetaMethod::Method)) {
+ PySideMetaFunction *function = PyObject_New(PySideMetaFunction, PySideMetaFunctionTypeF());
+ function->d = new PySideMetaFunctionPrivate();
+ function->d->qobject = source;
+ function->d->methodIndex = methodIndex;
+ return function;
+ }
+ return 0;
+}
+
+bool call(QObject *self, int methodIndex, PyObject *args, PyObject **retVal)
+{
+
+ QMetaMethod method = self->metaObject()->method(methodIndex);
+ QList<QByteArray> argTypes = method.parameterTypes();
+
+ // args given plus return type
+ Shiboken::AutoDecRef sequence(PySequence_Fast(args, 0));
+ int numArgs = PySequence_Fast_GET_SIZE(sequence.object()) + 1;
+
+ if (numArgs - 1 > argTypes.count()) {
+ PyErr_Format(PyExc_TypeError, "%s only accepts %d argument(s), %d given!",
+ method.methodSignature().constData(),
+ argTypes.count(), numArgs - 1);
+ return false;
+ }
+
+ if (numArgs - 1 < argTypes.count()) {
+ PyErr_Format(PyExc_TypeError, "%s needs %d argument(s), %d given!",
+ method.methodSignature().constData(),
+ argTypes.count(), numArgs - 1);
+ return false;
+ }
+
+ QVariant *methValues = new QVariant[numArgs];
+ void **methArgs = new void *[numArgs];
+
+ // Prepare room for return type
+ const char *returnType = method.typeName();
+ if (returnType && std::strcmp("void", returnType))
+ argTypes.prepend(returnType);
+ else
+ argTypes.prepend(QByteArray());
+
+ int i;
+ for (i = 0; i < numArgs; ++i) {
+ const QByteArray &typeName = argTypes.at(i);
+ // This must happen only when the method hasn't return type.
+ if (typeName.isEmpty()) {
+ methArgs[i] = 0;
+ continue;
+ }
+
+ Shiboken::Conversions::SpecificConverter converter(typeName);
+ if (converter) {
+ QMetaType metaType = QMetaType::fromName(typeName);
+ if (!Shiboken::Conversions::pythonTypeIsObjectType(converter)) {
+ if (!metaType.isValid()) {
+ PyErr_Format(PyExc_TypeError, "Value types used on meta functions (including signals) need to be "
+ "registered on meta type: %s", typeName.data());
+ break;
+ }
+ methValues[i] = QVariant(metaType);
+ }
+ methArgs[i] = methValues[i].data();
+ if (i == 0) // Don't do this for return type
+ continue;
+ if (metaType.id() == QMetaType::QString) {
+ QString tmp;
+ converter.toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i - 1), &tmp);
+ methValues[i] = tmp;
+ } else {
+ converter.toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i - 1), methArgs[i]);
+ }
+ } else {
+ PyErr_Format(PyExc_TypeError, "Unknown type used to call meta function (that may be a signal): %s", argTypes[i].constData());
+ break;
+ }
+ }
+
+ bool ok = i == numArgs;
+ if (ok) {
+ Py_BEGIN_ALLOW_THREADS
+ QMetaObject::metacall(self, QMetaObject::InvokeMetaMethod, method.methodIndex(), methArgs);
+ Py_END_ALLOW_THREADS
+
+ if (retVal) {
+ if (methArgs[0]) {
+ static SbkConverter *qVariantTypeConverter = Shiboken::Conversions::getConverter("QVariant");
+ Q_ASSERT(qVariantTypeConverter);
+ *retVal = Shiboken::Conversions::copyToPython(qVariantTypeConverter, &methValues[0]);
+ } else {
+ *retVal = Py_None;
+ Py_INCREF(*retVal);
+ }
+ }
+ }
+
+ delete[] methArgs;
+ delete[] methValues;
+
+ return ok;
+}
+
+
+} //namespace MetaFunction
+} //namespace PySide
+