diff options
Diffstat (limited to 'sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp')
-rw-r--r-- | sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp new file mode 100644 index 000000000..6468068a3 --- /dev/null +++ b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $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 <pyside.h> + +// 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<int N> +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<int N> +struct ElementFactory : ElementFactoryBase<N> +{ + static void init() + { + createFuncs[N] = &ElementFactoryBase<N>::createQuickItem; + ElementFactory<N-1>::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##Wrapper>(#className, typeToRegister, \ + typePointerName, typeListName, \ + typeMetaObject, type, registered) + +bool pyTypeObjectInheritsFromClass(const PyTypeObject *pyObjType, QByteArray className) +{ + className.append('*'); + PyTypeObject *classPyType = Shiboken::Conversions::getPythonTypeObject(className.constData()); + bool isDerived = PySequence_Contains(pyObjType->tp_mro, + reinterpret_cast<PyObject *>(classPyType)); + return isDerived; +} + +template <class WrapperClass> +void registerTypeIfInheritsFromClass( + QByteArray className, + const 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<WrapperClass *>::Destruct, + QtMetaTypePrivate::QMetaTypeFunctionHelper<WrapperClass *>::Construct, + sizeof(WrapperClass *), + static_cast< ::QFlags<QMetaType::TypeFlag> >(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<QQmlListProperty<WrapperClass> > + ::Destruct, + QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<WrapperClass> > + ::Construct, + sizeof(QQmlListProperty<WrapperClass>), + static_cast< ::QFlags<QMetaType::TypeFlag> >( + QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<WrapperClass> >::Flags), + static_cast<QMetaObject*>(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<WrapperClass>(); + type->attachedPropertiesMetaObject = + QQmlPrivate::attachedPropertiesMetaObject<WrapperClass>(); + type->parserStatusCast = + QQmlPrivate::StaticCastSelector<WrapperClass, QQmlParserStatus>::cast(); + type->valueSourceCast = + QQmlPrivate::StaticCastSelector<WrapperClass, QQmlPropertyValueSource>::cast(); + type->valueInterceptorCast = + QQmlPrivate::StaticCastSelector<WrapperClass, QQmlPropertyValueInterceptor>::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<PyTypeObject *>(pyObj); + PyTypeObject *qQuickItemPyType = + Shiboken::Conversions::getPythonTypeObject("QQuickItem*"); + bool isQuickItem = PySequence_Contains(pyObjType->tp_mro, + reinterpret_cast<PyObject *>(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<QMetaObject *>( + ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType *>(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<PYSIDE_MAX_QUICK_TYPES - 1>::init(); +#ifdef PYSIDE_QML_SUPPORT + setQuickRegisterItemFunction(quickRegisterType); +#endif +} |