aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-11-18 15:05:17 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-12-08 08:48:50 +0100
commit862948599999e4e5701452a3f479182606e16a89 (patch)
tree585769e3cc6891334ab340ff82c16e7352e41b06 /sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
parent244477a81445bf6f38cda3f8fe213daaa5908166 (diff)
Move the QML registration code into a library
This makes the code easier to maintain. Task-number: PYSIDE-1709 Change-Id: Idb75143a7e6d218637ab75463db88b6135cd4086 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp')
-rw-r--r--sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp455
1 files changed, 0 insertions, 455 deletions
diff --git a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
deleted file mode 100644
index 84fec16b6..000000000
--- a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp
+++ /dev/null
@@ -1,455 +0,0 @@
-/****************************************************************************
-**
-** 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 "pysideqmlregistertype.h"
-#include "pysideqmlregistertype_p.h"
-#include "pysideqmluncreatable.h"
-
-#include <limits>
-
-// shiboken
-#include <shiboken.h>
-#include <sbkstring.h>
-
-// pyside
-#include <pyside.h>
-#include <pysideqobject.h>
-#include <pyside_p.h>
-
-#include <QtCore/QMutex>
-#include <QtCore/QTypeRevision>
-
-#include <QtQml/qqml.h>
-#include <QtQml/QJSValue>
-#include <QtQml/QQmlListProperty>
-
-// Mutex used to avoid race condition on PySide::nextQObjectMemoryAddr.
-static QMutex nextQmlElementMutex;
-
-static void createInto(void *memory, void *type)
-{
- QMutexLocker locker(&nextQmlElementMutex);
- PySide::setNextQObjectMemoryAddr(memory);
- Shiboken::GilState state;
- PyObject *obj = PyObject_CallObject(reinterpret_cast<PyObject *>(type), 0);
- if (!obj || PyErr_Occurred())
- PyErr_Print();
- PySide::setNextQObjectMemoryAddr(0);
-}
-
-PyTypeObject *qObjectType()
-{
- static PyTypeObject *const result =
- Shiboken::Conversions::getPythonTypeObject("QObject*");
- assert(result);
- return result;
-}
-
-static PyTypeObject *qQmlEngineType()
-{
- static PyTypeObject *const result =
- Shiboken::Conversions::getPythonTypeObject("QQmlEngine*");
- assert(result);
- return result;
-}
-
-static PyTypeObject *qQJSValueType()
-{
- static PyTypeObject *const result =
- Shiboken::Conversions::getPythonTypeObject("QJSValue*");
- assert(result);
- return result;
-}
-
-int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
- int versionMinor, const char *qmlName, const char *noCreationReason,
- bool creatable)
-{
- using namespace Shiboken;
-
- PyTypeObject *qobjectType = 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;
- }
-
- const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
- Q_ASSERT(metaObject);
-
- QQmlPrivate::RegisterType type;
-
- // Allow registering Qt Quick items.
- bool registered = false;
- QuickRegisterItemFunction quickRegisterItemFunction = getQuickRegisterItemFunction();
- if (quickRegisterItemFunction) {
- registered =
- quickRegisterItemFunction(pyObj, uri, versionMajor, versionMinor,
- qmlName, creatable, noCreationReason, &type);
- }
-
- // Register as simple QObject rather than Qt Quick item.
- if (!registered) {
- // Incref the type object, don't worry about decref'ing it because
- // there's no way to unregister a QML type.
- Py_INCREF(pyObj);
-
- type.structVersion = 0;
-
- // FIXME: Fix this to assign new type ids each time.
- type.typeId = QMetaType(QMetaType::QObjectStar);
- type.listId = QMetaType::fromType<QQmlListProperty<QObject> >();
- type.attachedPropertiesFunction = QQmlPrivate::attachedPropertiesFunc<QObject>();
- type.attachedPropertiesMetaObject = QQmlPrivate::attachedPropertiesMetaObject<QObject>();
-
- type.parserStatusCast =
- QQmlPrivate::StaticCastSelector<QObject, QQmlParserStatus>::cast();
- type.valueSourceCast =
- QQmlPrivate::StaticCastSelector<QObject, QQmlPropertyValueSource>::cast();
- type.valueInterceptorCast =
- QQmlPrivate::StaticCastSelector<QObject, QQmlPropertyValueInterceptor>::cast();
-
- int objectSize = static_cast<int>(PySide::getSizeOfQObject(
- reinterpret_cast<PyTypeObject *>(pyObj)));
- type.objectSize = objectSize;
- type.create = creatable ? createInto : nullptr;
- type.noCreationReason = QString::fromUtf8(noCreationReason);
- type.userdata = pyObj;
- type.uri = uri;
- type.version = QTypeRevision::fromVersion(versionMajor, versionMinor);
- type.elementName = qmlName;
-
- type.extensionObjectCreate = 0;
- type.extensionMetaObject = 0;
- type.customParser = 0;
- }
- type.metaObject = metaObject; // Snapshot may have changed.
-
- int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
- if (qmlTypeId == -1) {
- PyErr_Format(PyExc_TypeError, "QML meta type registration of \"%s\" failed.",
- qmlName);
- }
- 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 = PyLong_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) {
- PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
-
- if (!isQObjectDerived(pyObjType, true))
- 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 * {
- Shiboken::GilState gil;
- AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0));
-
- if (hasCallback) {
- PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
- qQmlEngineType(), engine));
- }
-
- AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args));
-
- // 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 {
- Shiboken::GilState gil;
- AutoDecRef args(PyTuple_New(1));
-
- PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
- qQmlEngineType(), engine));
-
- AutoDecRef retVal(PyObject_CallObject(callback, args));
-
- PyTypeObject *qjsvalueType = qQJSValueType();
-
- // 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);
-}
-
-int PySide::qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor,
- int versionMinor, const char *qmlName,
- PyObject *instanceObject)
-{
- using namespace Shiboken;
-
- // Check if the Python Type inherit from QObject
- PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
-
- if (!isQObjectDerived(pyObjType, true))
- return -1;
-
- // Convert the instanceObject (PyObject) into a QObject
- QObject *instanceQObject = PySide::convertToQObject(instanceObject, true);
- if (instanceQObject == nullptr)
- return -1;
-
- // 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);
-}
-
-static std::string getGlobalString(const char *name)
-{
- using Shiboken::AutoDecRef;
-
- PyObject *globals = PyEval_GetGlobals();
-
- AutoDecRef pyName(Py_BuildValue("s", name));
-
- PyObject *globalVar = PyDict_GetItem(globals, pyName);
-
- if (globalVar == nullptr || !PyUnicode_Check(globalVar))
- return "";
-
- const char *stringValue = _PepUnicode_AsString(globalVar);
- return stringValue != nullptr ? stringValue : "";
-}
-
-static int getGlobalInt(const char *name)
-{
- using Shiboken::AutoDecRef;
-
- PyObject *globals = PyEval_GetGlobals();
-
- AutoDecRef pyName(Py_BuildValue("s", name));
-
- PyObject *globalVar = PyDict_GetItem(globals, pyName);
-
- if (globalVar == nullptr || !PyLong_Check(globalVar))
- return -1;
-
- long value = PyLong_AsLong(globalVar);
-
- if (value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min())
- return -1;
-
- return value;
-}
-
-enum class RegisterMode {
- Normal,
- Anonymous,
- Uncreatable,
- Singleton
-};
-
-static PyObject *qmlElementMacroHelper(PyObject *pyObj,
- const char *decoratorName,
- RegisterMode mode = RegisterMode::Normal,
- const char *noCreationReason = nullptr)
-{
- if (!PyType_Check(pyObj)) {
- PyErr_Format(PyExc_TypeError, "This decorator can only be used on classes.");
- return nullptr;
- }
-
- PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
- const char *typeName = pyObjType->tp_name;
- if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qObjectType()))) {
- PyErr_Format(PyExc_TypeError, "This decorator can only be used with classes inherited from QObject, got %s.",
- typeName);
- return nullptr;
- }
-
- std::string importName = getGlobalString("QML_IMPORT_NAME");
- int majorVersion = getGlobalInt("QML_IMPORT_MAJOR_VERSION");
- int minorVersion = getGlobalInt("QML_IMPORT_MINOR_VERSION");
-
- if (importName.empty()) {
- PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_NAME in order to use %s.",
- decoratorName);
- return nullptr;
- }
-
- if (majorVersion == -1) {
- PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_MAJOR_VERSION in order to use %s.",
- decoratorName);
- return nullptr;
- }
-
- // Specifying a minor version is optional
- if (minorVersion == -1)
- minorVersion = 0;
-
- const char *uri = importName.c_str();
- const int result = mode == RegisterMode::Singleton
- ? PySide::qmlRegisterSingletonType(pyObj, uri, majorVersion, minorVersion,
- typeName, nullptr,
- PySide::isQObjectDerived(pyObjType, false),
- false)
- : PySide::qmlRegisterType(pyObj, uri, majorVersion, minorVersion,
- mode != RegisterMode::Anonymous ? typeName : nullptr,
- noCreationReason,
- mode == RegisterMode::Normal);
-
- if (result == -1) {
- PyErr_Format(PyExc_TypeError, "%s: Failed to register type %s.",
- decoratorName, typeName);
- }
-
- return pyObj;
-}
-
-// FIXME: Store this in PySide::TypeUserData once it is moved to libpyside?
-static QList<PyObject *> decoratedSingletons;
-
-PyObject *PySide::qmlElementMacro(PyObject *pyObj)
-{
- const char *noCreationReason = nullptr;
- RegisterMode mode = RegisterMode::Normal;
- if (decoratedSingletons.contains(pyObj))
- mode = RegisterMode::Singleton;
- else if ((noCreationReason = PySide::qmlNoCreationReason(pyObj)))
- mode = RegisterMode::Uncreatable;
- return qmlElementMacroHelper(pyObj, "QmlElement", mode, noCreationReason);
-}
-
-PyObject *PySide::qmlAnonymousMacro(PyObject *pyObj)
-{
- return qmlElementMacroHelper(pyObj, "QmlAnonymous",
- RegisterMode::Anonymous);
-}
-
-PyObject *PySide::qmlSingletonMacro(PyObject *pyObj)
-{
- decoratedSingletons.append(pyObj);
- Py_INCREF(pyObj);
- return pyObj;
-}