aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp58
-rw-r--r--sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h16
-rw-r--r--sources/pyside6/PySide6/QtQml/typesystem_qml.xml4
-rw-r--r--sources/pyside6/PySide6/glue/qtqml.cpp5
-rw-r--r--sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst25
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.cpp4
-rw-r--r--sources/pyside6/libpyside/pyside.cpp11
-rw-r--r--sources/pyside6/libpyside/pyside.h7
-rw-r--r--sources/pyside6/tests/QtQml/registersingletontype.py14
-rw-r--r--sources/pyside6/tests/QtQml/registersingletontype.qml4
10 files changed, 135 insertions, 13 deletions
diff --git a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
index d2b9b689e..873ec53ce 100644
--- a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
@@ -180,15 +180,10 @@ int PySide::qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versi
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);
+
+ if (!isQObjectDerived(pyObjType, true))
return -1;
- }
// If we don't have a callback we'll need the pyObj to stay allocated indefinitely
if (!hasCallback)
@@ -273,6 +268,55 @@ int PySide::qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versi
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type);
}
+int PySide::qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName,
+ PyObject *instanceObject)
+{
+ using namespace Shiboken;
+
+ static PyTypeObject *qobjectType = Conversions::getPythonTypeObject("QObject*");
+ assert(qobjectType);
+
+ // Check if the Python Type inherit from QObject
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+
+ if (!isQObjectDerived(pyObjType, true))
+ return -1;
+
+ // Check if the instance object derives from QObject
+ PyTypeObject *typeInstanceObject = instanceObject->ob_type;
+
+ if (!isQObjectDerived(typeInstanceObject, true))
+ return -1;
+
+ // Convert the instanceObject (PyObject) into a QObject
+ QObject *instanceQObject = reinterpret_cast<QObject*>(
+ Object::cppPointer(reinterpret_cast<SbkObject*>(instanceObject), qobjectType));
+
+ // Create Singleton Functor to pass the QObject to the Type registration step
+ // similarly to the case when we have a callback
+ QQmlPrivate::SingletonFunctor registrationFunctor;
+ registrationFunctor.m_object = instanceQObject;
+
+ const QMetaObject *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;
+
+ // FIXME: Fix this to assign new type ids each time.
+ type.typeId = QMetaType(QMetaType::QObjectStar);
+ type.qObjectApi = registrationFunctor;
+
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type);
+}
+
extern "C"
{
diff --git a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h
index 9cc7379e9..2a90a07e0 100644
--- a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h
+++ b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h
@@ -71,7 +71,7 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int vers
const char *qmlName, const char *noCreationReason = nullptr, bool creatable = true);
/**
- * PySide implementation of qmlRegisterType<T> function.
+ * PySide implementation of qmlRegisterSingletonType<T> function.
*
* \param pyObj Python type to be registered.
* \param uri QML element uri.
@@ -84,6 +84,20 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int vers
int qmlRegisterSingletonType(PyObject *pyObj,const char *uri, int versionMajor, int versionMinor, const char *qmlName,
PyObject *callback, bool isQObject, bool hasCallback);
+/**
+ * PySide implementation of qmlRegisterSingletonInstance<T> function.
+ *
+ * \param pyObj Python type to be registered.
+ * \param uri QML element uri.
+ * \param versionMajor QML component major version.
+ * \param versionMinor QML component minor version.
+ * \param qmlName QML element name
+ * \param instanceObject singleton object to be registered.
+ * \return the metatype id of the registered type.
+ */
+int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName, PyObject *instanceObject);
+
/**
* PySide implementation of the QML_ELEMENT macro
diff --git a/sources/pyside6/PySide6/QtQml/typesystem_qml.xml b/sources/pyside6/PySide6/QtQml/typesystem_qml.xml
index 1b855a073..ad883f09d 100644
--- a/sources/pyside6/PySide6/QtQml/typesystem_qml.xml
+++ b/sources/pyside6/PySide6/QtQml/typesystem_qml.xml
@@ -92,6 +92,10 @@
<inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qjsvalue"/>
</add-function>
+ <add-function signature="qmlRegisterSingletonInstance(PyTypeObject,const char*,int,int,const char*,PyObject*)" return-type="int">
+ <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletoninstance"/>
+ </add-function>
+
<add-function signature="qmlRegisterUncreatableType(PyTypeObject,const char*,int,int,const char*,const char*)" return-type="int">
<inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregisteruncreatabletype"/>
</add-function>
diff --git a/sources/pyside6/PySide6/glue/qtqml.cpp b/sources/pyside6/PySide6/glue/qtqml.cpp
index eab6eab95..99a1c441a 100644
--- a/sources/pyside6/PySide6/glue/qtqml.cpp
+++ b/sources/pyside6/PySide6/glue/qtqml.cpp
@@ -57,6 +57,11 @@ int %0 = PySide::qmlRegisterSingletonType(nullptr, %ARGUMENT_NAMES, false, true)
%PYARG_0 = %CONVERTTOPYTHON[int](%0);
// @snippet qmlregistersingletontype_qjsvalue
+// @snippet qmlregistersingletoninstance
+int %0 = PySide::qmlRegisterSingletonInstance(%ARGUMENT_NAMES);
+%PYARG_0 = %CONVERTTOPYTHON[int](%0);
+// @snippet qmlregistersingletoninstance
+
// @snippet qmlregisteruncreatabletype
int %0 = PySide::qmlRegisterType(%ARGUMENT_NAMES, false);
%PYARG_0 = %CONVERTTOPYTHON[int](%0);
diff --git a/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst b/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst
new file mode 100644
index 000000000..19d59893e
--- /dev/null
+++ b/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst
@@ -0,0 +1,25 @@
+.. currentmodule:: PySide6.QtQml
+.. _qmlRegisterSingletonInstance:
+
+qmlRegisterSingletonInstance
+****************************
+
+.. py:function:: qmlRegisterSingletonInstance(pytype: type,\
+ uri: str,\
+ versionMajor: int,\
+ versionMinor: int,\
+ typeName: str,\
+ instanceObject: object) -> int
+
+ :param type pytype: Python class
+ :param str uri: uri to use while importing the component in QML
+ :param int versionMajor: major version
+ :param int versionMinor: minor version
+ :param str typeName: name exposed to QML
+ :param object instanceObject: singleton object to be registered
+ :return: int (the QML type id)
+
+ This function registers a singleton Python object *instanceObject*, with a particular *uri* and
+ *typeName*. Its version is a combination of *versionMajor* and *versionMinor*.
+
+ Use this function to register an object of the given type *pytype* as a singleton type.
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
index b7febf492..5269067e7 100644
--- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
@@ -47,6 +47,7 @@
#include "pysideqenum.h"
#include <shiboken.h>
+#include <pyside.h>
#include <QtCore/QByteArray>
#include <QtCore/QObject>
@@ -466,7 +467,6 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
// existing connections.
const PyObject *mro = type->tp_mro;
const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro);
- PyTypeObject *qObjectType = Conversions::getPythonTypeObject("QObject*");
std::vector<PyTypeObject *> basesToCheck;
// Prepend the actual type that we are parsing.
@@ -478,7 +478,7 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
for (Py_ssize_t i = 0; i < basesCount; ++i) {
auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
if (baseType != sbkObjTypeF && baseType != baseObjType
- && PyType_IsSubtype(baseType, qObjectType) == 0) {
+ && !PySide::isQObjectDerived(baseType, false)) {
basesToCheck.push_back(baseType);
}
}
diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp
index 14b86f322..990b45694 100644
--- a/sources/pyside6/libpyside/pyside.cpp
+++ b/sources/pyside6/libpyside/pyside.cpp
@@ -656,6 +656,17 @@ bool registerInternalQtConf()
return isRegistered;
}
+bool isQObjectDerived(PyTypeObject *pyType, bool raiseError) {
+ static PyTypeObject *qobjectType = Shiboken::Conversions::getPythonTypeObject("QObject*");
+
+ if (!PyType_IsSubtype(pyType, qobjectType)) {
+ if (raiseError)
+ PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.",
+ qobjectType->tp_name, pyType->tp_name);
+ return false;
+ }
+ return true;
+}
} //namespace PySide
diff --git a/sources/pyside6/libpyside/pyside.h b/sources/pyside6/libpyside/pyside.h
index 1cb77b4c5..0c9ad92cf 100644
--- a/sources/pyside6/libpyside/pyside.h
+++ b/sources/pyside6/libpyside/pyside.h
@@ -105,6 +105,13 @@ PYSIDE_API void initQApp();
/// Return the size in bytes of a type that inherits QObject.
PYSIDE_API std::size_t getSizeOfQObject(SbkObjectType *type);
+/* Check if a PyTypeObject or its bases contains a QObject
+ * \param pyType is the PyTypeObject to check
+ * \param raiseError controls if a TypeError is raised when an object does not
+ * inherits from QObject
+ */
+PYSIDE_API bool isQObjectDerived(PyTypeObject *pyType, bool raiseError);
+
typedef void (*CleanupFunction)(void);
/**
diff --git a/sources/pyside6/tests/QtQml/registersingletontype.py b/sources/pyside6/tests/QtQml/registersingletontype.py
index 30844ff8c..c22f3706e 100644
--- a/sources/pyside6/tests/QtQml/registersingletontype.py
+++ b/sources/pyside6/tests/QtQml/registersingletontype.py
@@ -39,7 +39,7 @@ from helper.helper import quickview_errorstring
from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject
from PySide6.QtGui import QGuiApplication
-from PySide6.QtQml import qmlRegisterSingletonType
+from PySide6.QtQml import qmlRegisterSingletonType, qmlRegisterSingletonInstance
from PySide6.QtQuick import QQuickView
finalResult = 0
@@ -80,6 +80,16 @@ class TestQmlSupport(unittest.TestCase):
qmlRegisterSingletonType('Singletons', 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
+ # Accepts only QObject derived types
+ l = [1, 2]
+ with self.assertRaises(TypeError):
+ qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', l)
+
+ # Modify value on the instance
+ s = SingletonQObject()
+ s.setData(99)
+ qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', s)
+
view = QQuickView()
file = Path(__file__).resolve().parent / 'registersingletontype.qml'
self.assertTrue(file.is_file())
@@ -88,7 +98,7 @@ class TestQmlSupport(unittest.TestCase):
view.show()
QTimer.singleShot(250, view.close)
app.exec()
- self.assertEqual(finalResult, 200)
+ self.assertEqual(finalResult, 299)
if __name__ == '__main__':
diff --git a/sources/pyside6/tests/QtQml/registersingletontype.qml b/sources/pyside6/tests/QtQml/registersingletontype.qml
index c8b34e69a..2365cf201 100644
--- a/sources/pyside6/tests/QtQml/registersingletontype.qml
+++ b/sources/pyside6/tests/QtQml/registersingletontype.qml
@@ -31,6 +31,8 @@ import Singletons 1.0
Item {
Component.onCompleted: {
- SingletonQObjectCallback.data += SingletonQObjectNoCallback.data + SingletonQJSValue.data
+ SingletonQObjectCallback.data += SingletonQObjectNoCallback.data
+ + SingletonQJSValue.data
+ + SingletonInstance.data;
}
}