/**************************************************************************** ** ** 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 "pysidequickregistertype.h" #include // Auto generated headers. #include "qquickitem_wrapper.h" #include "qquickpainteditem_wrapper.h" #include "qquickframebufferobject_wrapper.h" #include "pyside2_qtcore_python.h" #include "pyside2_qtquick_python.h" #include "pyside2_qtqml_python.h" #ifndef PYSIDE_MAX_QUICK_TYPES // Maximum number of different Qt Quick types the user can export to QML using // qmlRegisterType. This limit exists because the QML engine instantiates objects // by calling a function with one argument (a void* pointer where the object should // be created), and thus does not allow us to choose which object to create. Thus // we create a C++ factory function for each new registered type at compile time. # define PYSIDE_MAX_QUICK_TYPES 50 #endif // !PYSIDE_MAX_QUICK_TYPES // All registered python types and their creation functions. static PyObject *pyTypes[PYSIDE_MAX_QUICK_TYPES]; static void (*createFuncs[PYSIDE_MAX_QUICK_TYPES])(void*); // Mutex used to avoid race condition on PySide::nextQObjectMemoryAddr. static QMutex nextQmlElementMutex; // Python object factory functions. template struct ElementFactoryBase { static void createQuickItem(void *memory) { QMutexLocker locker(&nextQmlElementMutex); PySide::setNextQObjectMemoryAddr(memory); Shiboken::GilState state; PyObject *obj = PyObject_CallObject(pyTypes[N], 0); if (!obj || PyErr_Occurred()) PyErr_Print(); PySide::setNextQObjectMemoryAddr(0); } }; template struct ElementFactory : ElementFactoryBase { static void init() { createFuncs[N] = &ElementFactoryBase::createQuickItem; ElementFactory::init(); } }; template<> struct ElementFactory<0> : ElementFactoryBase<0> { static void init() { createFuncs[0] = &ElementFactoryBase<0>::createQuickItem; } }; #define PY_REGISTER_IF_INHERITS_FROM(className, typeToRegister,typePointerName, \ typeListName, typeMetaObject, type, registered) \ registerTypeIfInheritsFromClass(#className, typeToRegister, \ typePointerName, typeListName, \ typeMetaObject, type, registered) bool pyTypeObjectInheritsFromClass(PyTypeObject *pyObjType, QByteArray className) { className.append('*'); PyTypeObject *classPyType = Shiboken::Conversions::getPythonTypeObject(className.constData()); bool isDerived = PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast(classPyType)); return isDerived; } template void registerTypeIfInheritsFromClass( QByteArray className, PyTypeObject *typeToRegister, const QByteArray &typePointerName, const QByteArray &typeListName, QMetaObject *typeMetaObject, QQmlPrivate::RegisterType *type, bool ®istered) { bool shouldRegister = !registered && pyTypeObjectInheritsFromClass(typeToRegister, className); if (shouldRegister) { int ptrType = QMetaType::registerNormalizedType( typePointerName.constData(), QtMetaTypePrivate::QMetaTypeFunctionHelper::Destruct, QtMetaTypePrivate::QMetaTypeFunctionHelper::Construct, sizeof(WrapperClass *), static_cast< ::QFlags >(QtPrivate::QMetaTypeTypeFlags< WrapperClass *>::Flags), typeMetaObject); if (ptrType == -1) { PyErr_Format(PyExc_TypeError, "Meta type registration of \"%s\" for QML usage failed.", typePointerName.constData()); return; } int lstType = QMetaType::registerNormalizedType( typeListName.constData(), QtMetaTypePrivate::QMetaTypeFunctionHelper > ::Destruct, QtMetaTypePrivate::QMetaTypeFunctionHelper > ::Construct, sizeof(QQmlListProperty), static_cast< ::QFlags >( QtPrivate::QMetaTypeTypeFlags >::Flags), static_cast(0)); if (lstType == -1) { PyErr_Format(PyExc_TypeError, "Meta type registration of \"%s\" for QML usage failed.", typeListName.constData()); return; } type->typeId = ptrType; type->listId = lstType; type->attachedPropertiesFunction = QQmlPrivate::attachedPropertiesFunc(); type->attachedPropertiesMetaObject = QQmlPrivate::attachedPropertiesMetaObject(); type->parserStatusCast = QQmlPrivate::StaticCastSelector::cast(); type->valueSourceCast = QQmlPrivate::StaticCastSelector::cast(); type->valueInterceptorCast = QQmlPrivate::StaticCastSelector::cast(); type->objectSize = sizeof(WrapperClass); registered = true; } } bool quickRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlPrivate::RegisterType *type) { using namespace Shiboken; static int nextType = 0; if (nextType >= PYSIDE_MAX_QUICK_TYPES) { PyErr_Format(PyExc_TypeError, "You can only export %d Qt Quick types to QML.", PYSIDE_MAX_QUICK_TYPES); return false; } PyTypeObject *pyObjType = reinterpret_cast(pyObj); PyTypeObject *qQuickItemPyType = Shiboken::Conversions::getPythonTypeObject("QQuickItem*"); bool isQuickItem = PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast(qQuickItemPyType)); // Register only classes that inherit QQuickItem or its children. if (!isQuickItem) return false; // Used inside macros to register the type. QMetaObject *metaObject = reinterpret_cast( ObjectType::getTypeUserData(reinterpret_cast(pyObj))); Q_ASSERT(metaObject); // Incref the type object, don't worry about decref'ing it because // there's no way to unregister a QML type. Py_INCREF(pyObj); pyTypes[nextType] = pyObj; // Used in macro registration. QByteArray pointerName(qmlName); pointerName.append('*'); QByteArray listName(qmlName); listName.prepend("QQmlListProperty<"); listName.append('>'); bool registered = false; PY_REGISTER_IF_INHERITS_FROM(QQuickPaintedItem, pyObjType, pointerName, listName, metaObject, type, registered); PY_REGISTER_IF_INHERITS_FROM(QQuickFramebufferObject, pyObjType, pointerName, listName, metaObject, type, registered); PY_REGISTER_IF_INHERITS_FROM(QQuickItem, pyObjType, pointerName, listName, metaObject, type, registered); if (!registered) return false; type->create = createFuncs[nextType]; type->version = 0; type->uri = uri; type->versionMajor = versionMajor; type->versionMinor = versionMinor; type->elementName = qmlName; type->metaObject = metaObject; type->extensionObjectCreate = 0; type->extensionMetaObject = 0; type->customParser = 0; ++nextType; return true; } void PySide::initQuickSupport(PyObject *module) { Q_UNUSED(module); ElementFactory::init(); #ifdef PYSIDE_QML_SUPPORT setQuickRegisterItemFunction(quickRegisterType); #endif }