aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2020-07-15 10:54:47 +0200
committerMaximilian Goldstein <max.goldstein@qt.io>2020-07-23 07:47:32 +0000
commit0864de0b26888a795808faa234d9717066e821b5 (patch)
tree92436abc623b241b82d9560dff89ba3003b9b954 /sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
parent6fcccf20dab907aa037cd9737b6349b2cad3323f (diff)
Implement qmlRegisterSingletonType
Task-number: PYSIDE-574 Change-Id: I8828e22da42a5a47b207bb2e02d2f4fe67746a0b Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp')
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index 046d62800..2381b3e73 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -52,6 +52,8 @@
#include "pyside2_qtcore_python.h"
#include "pyside2_qtqml_python.h"
+#include <QtQml/QJSValue>
+
// Forward declarations.
static void propListMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Call call,
void **args);
@@ -144,6 +146,126 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
return qmlTypeId;
}
+int PySide::qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName, PyObject *callback,
+ bool isQObject, bool hasCallback)
+{
+ using namespace Shiboken;
+
+ if (hasCallback) {
+ if (!PyCallable_Check(callback)) {
+ PyErr_Format(PyExc_TypeError, "Invalid callback specified.");
+ return -1;
+ }
+
+ AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__"));
+ AutoDecRef argCount(PyObject_GetAttrString(funcCode, "co_argcount"));
+
+ int count = PyInt_AsLong(argCount);
+
+ if (count != 1) {
+ PyErr_Format(PyExc_TypeError, "Callback has a bad parameter count.");
+ return -1;
+ }
+
+ // Make sure the callback never gets deallocated
+ Py_INCREF(callback);
+ }
+
+ const QMetaObject *metaObject = nullptr;
+
+ if (isQObject) {
+ static PyTypeObject *qobjectType = Conversions::getPythonTypeObject("QObject*");
+ assert(qobjectType);
+
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+ if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) {
+ PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.",
+ qobjectType->tp_name, pyObjType->tp_name);
+ return -1;
+ }
+
+ // If we don't have a callback we'll need the pyObj to stay allocated indefinitely
+ if (!hasCallback)
+ Py_INCREF(pyObj);
+
+ metaObject = PySide::retrieveMetaObject(pyObjType);
+ Q_ASSERT(metaObject);
+ }
+
+ QQmlPrivate::RegisterSingletonType type;
+ type.structVersion = 0;
+
+ type.uri = uri;
+ type.version = QTypeRevision::fromVersion(versionMajor, versionMinor);
+ type.typeName = qmlName;
+ type.instanceMetaObject = metaObject;
+
+ if (isQObject) {
+ // FIXME: Fix this to assign new type ids each time.
+ type.typeId = QMetaType(QMetaType::QObjectStar);
+
+ type.qObjectApi =
+ [callback, pyObj, hasCallback](QQmlEngine *engine, QJSEngine *) -> QObject * {
+ AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0));
+
+ if (hasCallback) {
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QQMLENGINE_IDX],
+ engine));
+ }
+
+ AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args));
+
+ SbkObjectType *qobjectType = (SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX];
+
+ // Make sure the callback returns something we can convert, else the entire application will crash.
+ if (retVal.isNull() ||
+ Conversions::isPythonToCppPointerConvertible(qobjectType, retVal) == nullptr) {
+ PyErr_Format(PyExc_TypeError, "Callback returns invalid value.");
+ return nullptr;
+ }
+
+ QObject *obj = nullptr;
+ Conversions::pythonToCppPointer(qobjectType, retVal, &obj);
+
+ if (obj != nullptr)
+ Py_INCREF(retVal);
+
+ return obj;
+ };
+ } else {
+ type.scriptApi =
+ [callback](QQmlEngine *engine, QJSEngine *) -> QJSValue {
+ AutoDecRef args(PyTuple_New(1));
+
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QQMLENGINE_IDX],
+ engine));
+
+ AutoDecRef retVal(PyObject_CallObject(callback, args));
+
+ SbkObjectType *qjsvalueType = (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QJSVALUE_IDX];
+
+ // Make sure the callback returns something we can convert, else the entire application will crash.
+ if (retVal.isNull() ||
+ Conversions::isPythonToCppPointerConvertible(qjsvalueType, retVal) == nullptr) {
+ PyErr_Format(PyExc_TypeError, "Callback returns invalid value.");
+ return QJSValue(QJSValue::UndefinedValue);
+ }
+
+ QJSValue *val = nullptr;
+ Conversions::pythonToCppPointer(qjsvalueType, retVal, &val);
+
+ Py_INCREF(retVal);
+
+ return *val;
+ };
+ }
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type);
+}
+
extern "C"
{