diff options
-rw-r--r-- | PySide2/CMakeLists.txt | 6 | ||||
-rw-r--r-- | PySide2/QtQml/CMakeLists.txt | 14 | ||||
-rw-r--r-- | PySide2/QtQml/pysideqmlregistertype.cpp | 147 | ||||
-rw-r--r-- | PySide2/QtQml/pysideqmlregistertype.h | 6 | ||||
-rw-r--r-- | PySide2/QtQml/typesystem_qml.xml | 23 | ||||
-rw-r--r-- | PySide2/QtQuick/CMakeLists.txt | 25 | ||||
-rw-r--r-- | PySide2/QtQuick/pysidequickregistertype.cpp | 251 | ||||
-rw-r--r-- | PySide2/QtQuick/pysidequickregistertype.h | 52 | ||||
-rw-r--r-- | PySide2/QtQuick/typesystem_quick.xml | 23 | ||||
-rw-r--r-- | libpyside/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 2 | ||||
-rw-r--r-- | libpyside/pyside.cpp | 14 | ||||
-rw-r--r-- | libpyside/pyside.h | 14 |
13 files changed, 470 insertions, 111 deletions
diff --git a/PySide2/CMakeLists.txt b/PySide2/CMakeLists.txt index 8bf5e53c..28f591d9 100644 --- a/PySide2/CMakeLists.txt +++ b/PySide2/CMakeLists.txt @@ -22,8 +22,8 @@ find_package(Qt5Script) find_package(Qt5ScriptTools) find_package(Qt5Help) find_package(Qt5Multimedia) -find_package(Qt5Quick) find_package(Qt5Qml) +find_package(Qt5Quick) find_package(Qt5QuickWidgets) find_package(Qt5WebChannel) find_package(Qt5WebEngineWidgets) @@ -134,8 +134,8 @@ CHECK_PACKAGE_FOUND(Qt5Script opt) CHECK_PACKAGE_FOUND(Qt5ScriptTools opt) CHECK_PACKAGE_FOUND(Qt5Help opt) CHECK_PACKAGE_FOUND(Qt5Multimedia opt) -CHECK_PACKAGE_FOUND(Qt5Quick opt) CHECK_PACKAGE_FOUND(Qt5Qml opt) +CHECK_PACKAGE_FOUND(Qt5Quick opt) CHECK_PACKAGE_FOUND(Qt5QuickWidgets opt) CHECK_PACKAGE_FOUND(Qt5WebChannel opt) CHECK_PACKAGE_FOUND(Qt5WebEngineWidgets opt) @@ -195,8 +195,8 @@ else() ENDIF() HAS_QT_MODULE(Qt5Help_FOUND QtHelp) HAS_QT_MODULE(Qt5Multimedia_FOUND QtMultimedia) -HAS_QT_MODULE(Qt5Quick_FOUND QtQuick) HAS_QT_MODULE(Qt5Qml_FOUND QtQml) +HAS_QT_MODULE(Qt5Quick_FOUND QtQuick) HAS_QT_MODULE(Qt5QuickWidgets_FOUND QtQuickWidgets) HAS_QT_MODULE(Qt5WebChannel_FOUND QtWebChannel) HAS_QT_MODULE(Qt5WebEngineWidgets_FOUND QtWebEngineWidgets) diff --git a/PySide2/QtQml/CMakeLists.txt b/PySide2/QtQml/CMakeLists.txt index b2118d29..12ccb0c0 100644 --- a/PySide2/QtQml/CMakeLists.txt +++ b/PySide2/QtQml/CMakeLists.txt @@ -8,7 +8,7 @@ ${QtQml_GEN_DIR}/qjsvalue_wrapper.cpp #${QtQml_GEN_DIR}/qjsvalueiterator_wrapper.cpp #${QtQml_GEN_DIR}/qqmlabstracturlinterceptor_wrapper.cpp ${QtQml_GEN_DIR}/qqmlapplicationengine_wrapper.cpp -#${QtQml_GEN_DIR}/qqmlcomponent_wrapper.cpp +${QtQml_GEN_DIR}/qqmlcomponent_wrapper.cpp ${QtQml_GEN_DIR}/qqmlcontext_wrapper.cpp ${QtQml_GEN_DIR}/qqmlerror_wrapper.cpp #${QtQml_GEN_DIR}/qqmldebuggingenabler_wrapper.cpp @@ -21,25 +21,24 @@ ${QtQml_GEN_DIR}/qqmlfileselector_wrapper.cpp #${QtQml_GEN_DIR}/qqmlincubator_wrapper.cpp #${QtQml_GEN_DIR}/qqmllistproperty_wrapper.cpp ${QtQml_GEN_DIR}/qqmllistreference_wrapper.cpp -#${QtQml_GEN_DIR}/qqmlparserstatus_wrapper.cpp +${QtQml_GEN_DIR}/qqmlparserstatus_wrapper.cpp ${QtQml_GEN_DIR}/qqmlproperty_wrapper.cpp -#${QtQml_GEN_DIR}/qqmlpropertymap_wrapper.cpp +${QtQml_GEN_DIR}/qqmlpropertymap_wrapper.cpp #${QtQml_GEN_DIR}/qqmlpropertyvaluesource_wrapper.cpp #${QtQml_GEN_DIR}/qqmlscriptstring_wrapper.cpp +${QtQml_GEN_DIR}/qqmlnetworkaccessmanagerfactory_wrapper.cpp # module is always needed ${QtQml_GEN_DIR}/qtqml_module_wrapper.cpp ) make_path(QtQml_typesystem_path ${QtCore_SOURCE_DIR} ${QtGui_SOURCE_DIR} ${QtNetwork_SOURCE_DIR} ${QtCore_BINARY_DIR} ${QtGui_BINARY_DIR} ${QtNetwork_BINARY_DIR} - ${QtQuick_SOURCE_DIR} ${QtQuick_BINARY_DIR} ${QtQml_SOURCE_DIR}) set(QtQml_include_dirs ${QtQml_SOURCE_DIR} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} - ${Qt5Quick_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${SHIBOKEN_PYTHON_INCLUDE_DIR} ${SHIBOKEN_INCLUDE_DIR} @@ -47,7 +46,6 @@ set(QtQml_include_dirs ${QtQml_SOURCE_DIR} ${QtGui_GEN_DIR} ${QtCore_GEN_DIR} ${QtNetwork_GEN_DIR} - ${QtQuick_GEN_DIR} ${QtQml_GEN_DIR}) set(QtQml_libraries pyside2 @@ -55,10 +53,9 @@ set(QtQml_libraries pyside2 ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Network_LIBRARIES} - ${Qt5Quick_LIBRARIES} ${Qt5Qml_LIBRARIES}) -set(QtQml_deps QtGui QtNetwork QtQuick) +set(QtQml_deps QtGui QtNetwork) create_pyside_module(QtQml QtQml_include_dirs @@ -66,5 +63,4 @@ create_pyside_module(QtQml QtQml_deps QtQml_typesystem_path QtQml_SRC -# "") QtQml_registerType) diff --git a/PySide2/QtQml/pysideqmlregistertype.cpp b/PySide2/QtQml/pysideqmlregistertype.cpp index 165b5fa9..00ceb02b 100644 --- a/PySide2/QtQml/pysideqmlregistertype.cpp +++ b/PySide2/QtQml/pysideqmlregistertype.cpp @@ -38,42 +38,36 @@ ****************************************************************************/ #include "pysideqmlregistertype.h" -// Qt -#include <QObject> -#include <QQmlEngine> -#include <QMutex> + // shiboken -#include <typeresolver.h> -#include <gilstate.h> -#include <sbkdbg.h> +#include <shiboken.h> + // pyside #include <pyside.h> -#include <dynamicqmetaobject.h> #include <pysideproperty.h> // auto generated headers -#include "qquickitem_wrapper.h" #include "pyside2_qtcore_python.h" -#include "pyside2_qtquick_python.h" #include "pyside2_qtqml_python.h" #ifndef PYSIDE_MAX_QML_TYPES -// Maximum number of different types the user can export to QML using qmlRegisterType. -// -// Qt5 Note: this is a vestige of the old QtDeclarative qmlRegisterType - it might be worth -// checking if this is still relevant to QtQml or if it's higher/lower. +// Maximum number of different Qt QML 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_QML_TYPES 50 #endif -// Forward declarations -static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args); +// Forward declarations. +static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, + void **args); - -// All registered python types +// All registered python types and their creation functions. static PyObject* pyTypes[PYSIDE_MAX_QML_TYPES]; static void (*createFuncs[PYSIDE_MAX_QML_TYPES])(void*); -// Mutex used to avoid race condition on PySide::nextQObjectMemoryAddr +// Mutex used to avoid race condition on PySide::nextQObjectMemoryAddr. static QMutex nextQmlElementMutex; template<int N> @@ -110,73 +104,85 @@ struct ElementFactory<0> : ElementFactoryBase<0> } }; -int PySide::qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor, int versionMinor, const char* qmlName) +int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, + int versionMinor, const char *qmlName) { using namespace Shiboken; - static PyTypeObject* qobjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); - static PyTypeObject* qquickType = Shiboken::Conversions::getPythonTypeObject("QQuickItem*"); + static PyTypeObject *qobjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); assert(qobjectType); static int nextType = 0; if (nextType >= PYSIDE_MAX_QML_TYPES) { - PyErr_Format(PyExc_TypeError, "QML doesn't really like language bindings, so you can only export %d types to QML.", PYSIDE_MAX_QML_TYPES); + PyErr_Format(PyExc_TypeError, "You can only export %d custom QML types to QML.", + PYSIDE_MAX_QML_TYPES); return -1; } - if (!PySequence_Contains(((PyTypeObject*)pyObj)->tp_mro, (PyObject*)qobjectType)) { - PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", qobjectType->tp_name, ((PyTypeObject*)pyObj)->tp_name); + 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; } - bool isQuickType = PySequence_Contains(((PyTypeObject*)pyObj)->tp_mro, (PyObject*)qquickType); - - QMetaObject* metaObject = reinterpret_cast<QMetaObject*>(ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(pyObj))); + QMetaObject *metaObject = reinterpret_cast<QMetaObject *>( + ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType *>(pyObj))); Q_ASSERT(metaObject); - // Inc ref the type object, don't worry about dec ref them because there's no way to unregister a QML type - Py_INCREF(pyObj); - - // All ready... now the ugly code begins... :-) - pyTypes[nextType] = pyObj; - - // Init proxy object static meta object QQmlPrivate::RegisterType type; type.version = 0; - if (isQuickType) { - type.typeId = qMetaTypeId<QQuickItem*>(); - type.listId = qMetaTypeId<QQmlListProperty<QQuickItem> >(); - type.attachedPropertiesFunction = QQmlPrivate::attachedPropertiesFunc<QQuickItem>(); - type.attachedPropertiesMetaObject = QQmlPrivate::attachedPropertiesMetaObject<QQuickItem>(); + // Allow registering Qt Quick items. + bool registered = false; + QuickRegisterItemFunction quickRegisterItemFunction = getQuickRegisterItemFunction(); + if (quickRegisterItemFunction) { + registered = quickRegisterItemFunction(pyObj, uri, versionMajor, versionMinor, + qmlName, &type); + } - type.parserStatusCast = QQmlPrivate::StaticCastSelector<QQuickItem, QQmlParserStatus>::cast(); - type.valueSourceCast = QQmlPrivate::StaticCastSelector<QQuickItem, QQmlPropertyValueSource>::cast(); - type.valueInterceptorCast = QQmlPrivate::StaticCastSelector<QQuickItem, QQmlPropertyValueInterceptor>::cast(); - } else { + // 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); + + pyTypes[nextType] = pyObj; + + // FIXME: Fix this to assign new type ids each time. type.typeId = qMetaTypeId<QObject*>(); type.listId = qMetaTypeId<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(); + 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<SbkObjectType *>(pyObj))); + type.objectSize = objectSize; + type.create = createFuncs[nextType]; + 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; } - type.objectSize = PySide::getSizeOfQObject(reinterpret_cast<SbkObjectType*>(pyObj)); - type.create = createFuncs[nextType]; - type.uri = uri; - type.versionMajor = versionMajor; - type.versionMinor = versionMinor; - type.elementName = qmlName; - type.metaObject = metaObject; - - type.extensionObjectCreate = 0; - type.extensionMetaObject = 0; - type.customParser = 0; int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); - ++nextType; + if (qmlTypeId == -1) { + PyErr_Format(PyExc_TypeError, "QML meta type registration of \"%s\" failed.", + qmlName); + } return qmlTypeId; } @@ -210,7 +216,7 @@ static int propListTpInit(PyObject* self, PyObject* args, PyObject* kwds) return 0; } PySide::Property::setMetaCallHandler(pySelf, &propListMetaCall); - PySide::Property::setTypeName(pySelf, "QQmlListProperty<QQuickItem>"); + PySide::Property::setTypeName(pySelf, "QQmlListProperty<QObject>"); PySide::Property::setUserData(pySelf, data); return 1; @@ -276,13 +282,13 @@ PyTypeObject PropertyListType = { } // extern "C" // Implementation of QQmlListProperty<T>::AppendFunction callback -void propListAppender(QQmlListProperty<QQuickItem>* propList, QQuickItem* item) +void propListAppender(QQmlListProperty<QObject> *propList, QObject *item) { Shiboken::GilState state; Shiboken::AutoDecRef args(PyTuple_New(2)); PyTuple_SET_ITEM(args, 0, Shiboken::Conversions::pointerToPython((SbkObjectType*)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], propList->object)); - PyTuple_SET_ITEM(args, 1, Shiboken::Conversions::pointerToPython((SbkObjectType*)SbkPySide2_QtQuickTypes[SBK_QQUICKITEM_IDX], item)); + PyTuple_SET_ITEM(args, 1, Shiboken::Conversions::pointerToPython((SbkObjectType*)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], item)); QmlListProperty* data = reinterpret_cast<QmlListProperty*>(propList->data); Shiboken::AutoDecRef retVal(PyObject_CallObject(data->append, args)); @@ -292,7 +298,7 @@ void propListAppender(QQmlListProperty<QQuickItem>* propList, QQuickItem* item) } // Implementation of QQmlListProperty<T>::CountFunction callback -int propListCount(QQmlListProperty<QQuickItem>* propList) +int propListCount(QQmlListProperty<QObject> *propList) { Shiboken::GilState state; @@ -313,7 +319,7 @@ int propListCount(QQmlListProperty<QQuickItem>* propList) } // Implementation of QQmlListProperty<T>::AtFunction callback -QQuickItem* propListAt(QQmlListProperty<QQuickItem>* propList, int index) +QObject *propListAt(QQmlListProperty<QObject> *propList, int index) { Shiboken::GilState state; @@ -324,16 +330,16 @@ QQuickItem* propListAt(QQmlListProperty<QQuickItem>* propList, int index) QmlListProperty* data = reinterpret_cast<QmlListProperty*>(propList->data); Shiboken::AutoDecRef retVal(PyObject_CallObject(data->at, args)); - QQuickItem* result = 0; + QObject *result = 0; if (PyErr_Occurred()) PyErr_Print(); else if (PyType_IsSubtype(Py_TYPE(retVal), data->type)) - Shiboken::Conversions::pythonToCppPointer((SbkObjectType*)SbkPySide2_QtCoreTypes[SBK_QQUICKITEM_IDX], retVal, &result); + Shiboken::Conversions::pythonToCppPointer((SbkObjectType*)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], retVal, &result); return result; } // Implementation of QQmlListProperty<T>::ClearFunction callback -void propListClear(QQmlListProperty<QQuickItem>* propList) +void propListClear(QQmlListProperty<QObject> * propList) { Shiboken::GilState state; @@ -356,14 +362,13 @@ static void propListMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Ca QmlListProperty* data = reinterpret_cast<QmlListProperty*>(PySide::Property::userData(pp)); QObject* qobj; Shiboken::Conversions::pythonToCppPointer((SbkObjectType*)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], self, &qobj); - QQmlListProperty<QQuickItem> declProp(qobj, data, &propListAppender, &propListCount, &propListAt, &propListClear); + QQmlListProperty<QObject> declProp(qobj, data, &propListAppender, &propListCount, &propListAt, &propListClear); // Copy the data to the memory location requested by the meta call void* v = args[0]; - *reinterpret_cast<QQmlListProperty<QQuickItem>*>(v) = declProp; + *reinterpret_cast<QQmlListProperty<QObject> *>(v) = declProp; } - void PySide::initQmlSupport(PyObject* module) { ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init(); @@ -374,6 +379,4 @@ void PySide::initQmlSupport(PyObject* module) Py_INCREF((PyObject*)&PropertyListType); PyModule_AddObject(module, PropertyListType.tp_name, (PyObject*)&PropertyListType); - } - diff --git a/PySide2/QtQml/pysideqmlregistertype.h b/PySide2/QtQml/pysideqmlregistertype.h index c68cc8df..af3d817a 100644 --- a/PySide2/QtQml/pysideqmlregistertype.h +++ b/PySide2/QtQml/pysideqmlregistertype.h @@ -67,8 +67,8 @@ void initQmlSupport(PyObject* module); * \param qmlName QML element name * \return the metatype id of the registered type. */ -int qmlRegisterType(PyObject* pyObj, const char* uri, int versionMajor, int versionMinor, const char* qmlName); - +int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor, + const char *qmlName); } -#endif
\ No newline at end of file +#endif diff --git a/PySide2/QtQml/typesystem_qml.xml b/PySide2/QtQml/typesystem_qml.xml index 28d5afdb..b0314cc2 100644 --- a/PySide2/QtQml/typesystem_qml.xml +++ b/PySide2/QtQml/typesystem_qml.xml @@ -39,7 +39,6 @@ <load-typesystem name="typesystem_core.xml" generate="no"/> <load-typesystem name="typesystem_network.xml" generate="no"/> <load-typesystem name="typesystem_gui.xml" generate="no"/> - <load-typesystem name="typesystem_quick.xml" generate="no"/> <add-function signature="qmlRegisterType(PyTypeObject, const char*, int, int, const char*)" return-type="int"> <inject-documentation format="target" mode="append"> @@ -71,7 +70,6 @@ <enum-type identified-by-value="QML_HAS_ATTACHED_PROPERTIES"> <extra-includes> - <include file-name="QtQuick" location="global"/> <include file-name="QtQml" location="global"/> <!-- FIXME The include tag doesn't work on modules --> <include file-name="pysideqmlregistertype.h" location="local"/> @@ -102,11 +100,11 @@ <enum-type name="DataType" /> </value-type> --> <object-type name="QQmlApplicationEngine" /> - <!-- TODO: More private method errors + <!-- TODO: More private method errors--> <object-type name="QQmlComponent"> <enum-type name="CompilationMode" /> <enum-type name="Status" /> - </object-type> --> + </object-type> <object-type name="QQmlContext" /> <value-type name="QQmlError" /> <!-- <object-type name="QQmlDebuggingEnabler" /> --> @@ -123,7 +121,7 @@ <object-type name="QQmlFileSelector" /> <!-- TODO: Abstract class <value-type name="QQmlImageProviderBase"> - <enum-type name="IncubationMode" /> + <enum-type name="IncubationMode" /> <enum-type name="Flag" flags="Flags" /> </value-type> --> <!-- TODO: More constructor issues @@ -136,14 +134,21 @@ Could not find type '::T*' for use in 'toPython' conversion. Make sure to use the full C++ name, e.g. 'Namespace::Class'. <value-type name="QQmlListProperty" /> --> <value-type name="QQmlListReference" /> - <!-- TODO: Constructor issues - <value-type name="QQmlParserStatus" /> --> + <!-- TODO: Constructor issues --> + <object-type name="QQmlParserStatus" /> <value-type name="QQmlProperty"> <enum-type name="PropertyTypeCategory" /> <enum-type name="Type" /> </value-type> + <object-type name="QQmlPropertyMap" /> <!-- TODO: these fail too - <value-type name="QQmlPropertyMap" /> <value-type name="QQmlPropertyValueSource" /> <value-type name="QQmlScriptString" /> --> -</typesystem>
\ No newline at end of file + <object-type name="QQmlNetworkAccessManagerFactory"> + <modify-function signature="create(QObject*)"> + <modify-argument index="return"> + <define-ownership class="native" owner="c++"/> + </modify-argument> + </modify-function> + </object-type> +</typesystem> diff --git a/PySide2/QtQuick/CMakeLists.txt b/PySide2/QtQuick/CMakeLists.txt index edecf82f..4d3df266 100644 --- a/PySide2/QtQuick/CMakeLists.txt +++ b/PySide2/QtQuick/CMakeLists.txt @@ -1,14 +1,17 @@ project(QtQuick) +set(QtQuick_registerType "${QtQuick_SOURCE_DIR}/pysidequickregistertype.cpp") + set(QtQuick_SRC -#${QtQuick_GEN_DIR}/qquickframebufferobject_wrapper.cpp +${QtQuick_GEN_DIR}/qquickframebufferobject_wrapper.cpp +${QtQuick_GEN_DIR}/qquickframebufferobject_renderer_wrapper.cpp #${QtQuick_GEN_DIR}/qquicktexturefactory_wrapper.cpp ${QtQuick_GEN_DIR}/qquickimageprovider_wrapper.cpp #${QtQuick_GEN_DIR}/qquicktransform_wrapper.cpp ${QtQuick_GEN_DIR}/qquickitem_wrapper.cpp #${QtQuick_GEN_DIR}/qquickitemgrabresult_wrapper.cpp -#${QtQuick_GEN_DIR}/qquickpainteditem_wrapper.cpp -#${QtQuick_GEN_DIR}/qquickrendercontrol_wrapper.cpp +${QtQuick_GEN_DIR}/qquickpainteditem_wrapper.cpp +${QtQuick_GEN_DIR}/qquickrendercontrol_wrapper.cpp ${QtQuick_GEN_DIR}/qquicktextdocument_wrapper.cpp ${QtQuick_GEN_DIR}/qquickview_wrapper.cpp ${QtQuick_GEN_DIR}/qquickwindow_wrapper.cpp @@ -16,28 +19,36 @@ ${QtQuick_GEN_DIR}/qquickwindow_wrapper.cpp ${QtQuick_GEN_DIR}/qtquick_module_wrapper.cpp ) -make_path(QtQuick_typesystem_path ${QtCore_SOURCE_DIR} ${QtGui_SOURCE_DIR} ${QtCore_BINARY_DIR} - ${QtGui_BINARY_DIR} +make_path(QtQuick_typesystem_path ${QtCore_SOURCE_DIR} ${QtCore_BINARY_DIR} + ${QtGui_SOURCE_DIR} ${QtGui_BINARY_DIR} + ${QtNetwork_SOURCE_DIR} ${QtNetwork_BINARY_DIR} + ${QtQml_SOURCE_DIR} ${QtQml_BINARY_DIR} ${QtQuick_SOURCE_DIR}) set(QtQuick_include_dirs ${QtQuick_SOURCE_DIR} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} + ${Qt5Network_INCLUDE_DIRS} + ${Qt5Qml_INCLUDE_DIRS} ${Qt5Quick_INCLUDE_DIRS} ${SHIBOKEN_PYTHON_INCLUDE_DIR} ${SHIBOKEN_INCLUDE_DIR} ${libpyside_SOURCE_DIR} ${QtGui_GEN_DIR} ${QtCore_GEN_DIR} + ${QtNetwork_GEN_DIR} + ${QtQml_GEN_DIR} ${QtQuick_GEN_DIR}) set(QtQuick_libraries pyside2 ${SHIBOKEN_PYTHON_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} + ${Qt5Network_LIBRARIES} + ${Qt5Qml_LIBRARIES} ${Qt5Quick_LIBRARIES}) -set(QtQuick_deps QtGui) +set(QtQuick_deps QtGui QtNetwork QtQml) create_pyside_module(QtQuick QtQuick_include_dirs @@ -45,4 +56,4 @@ create_pyside_module(QtQuick QtQuick_deps QtQuick_typesystem_path QtQuick_SRC - "") + QtQuick_registerType) diff --git a/PySide2/QtQuick/pysidequickregistertype.cpp b/PySide2/QtQuick/pysidequickregistertype.cpp new file mode 100644 index 00000000..22063838 --- /dev/null +++ b/PySide2/QtQuick/pysidequickregistertype.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** 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(); + setQuickRegisterItemFunction(quickRegisterType); +} diff --git a/PySide2/QtQuick/pysidequickregistertype.h b/PySide2/QtQuick/pysidequickregistertype.h new file mode 100644 index 00000000..35a66908 --- /dev/null +++ b/PySide2/QtQuick/pysidequickregistertype.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef PYSIDE_QUICK_REGISTER_TYPE_H +#define PYSIDE_QUICK_REGISTER_TYPE_H + +#include <Python.h> + +struct SbkObjectType; + +namespace PySide +{ +void initQuickSupport(PyObject *module); +} + +#endif // PYSIDE_QUICK_REGISTER_TYPE_H diff --git a/PySide2/QtQuick/typesystem_quick.xml b/PySide2/QtQuick/typesystem_quick.xml index 6c670355..7a91b915 100644 --- a/PySide2/QtQuick/typesystem_quick.xml +++ b/PySide2/QtQuick/typesystem_quick.xml @@ -37,10 +37,20 @@ --> <typesystem package="PySide2.QtQuick"> <load-typesystem name="typesystem_core.xml" generate="no"/> + <load-typesystem name="typesystem_network.xml" generate="no"/> <load-typesystem name="typesystem_gui.xml" generate="no"/> + <load-typesystem name="typesystem_qml.xml" generate="no"/> - <!-- TODO: Abstract - <object-type name="QQuickFramebufferObject" /> --> + <extra-includes> + <include file-name="pysidequickregistertype.h" location="local"/> + </extra-includes> + + <inject-code class="target" position="end"> + PySide::initQuickSupport(module); + </inject-code> + + <object-type name="QQuickFramebufferObject" /> + <object-type name="QQuickFramebufferObject::Renderer" /> <!-- TODO: Abstract <object-type name="QQuickTextureFactory" /> --> @@ -58,14 +68,13 @@ <!-- private <object-type name="QQuickItemGrabResult" /> --> - <!-- `unimplemented pure virtual method 'paint' in 'QQuickPaintedItemWrapper'` <object-type name="QQuickPaintedItem"> <enum-type name="RenderTarget" /> <enum-type name="PerformanceHint" flags="PerformanceHints" /> - </object-type> --> + </object-type> - <!-- private - <object-type name="QQuickRenderControl" /> --> + <!-- private--> + <object-type name="QQuickRenderControl" /> <object-type name="QQuickTextDocument" /> @@ -82,4 +91,4 @@ <!-- TODO: the scene graph (QSG*) classes --> -</typesystem>
\ No newline at end of file +</typesystem> diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt index f2c907d8..32efa58e 100644 --- a/libpyside/CMakeLists.txt +++ b/libpyside/CMakeLists.txt @@ -77,6 +77,10 @@ set_target_properties(pyside2 PROPERTIES OUTPUT_NAME "pyside2${pyside2_SUFFIX}${SHIBOKEN_PYTHON_EXTENSION_SUFFIX}" DEFINE_SYMBOL PYSIDE_EXPORTS) +if(QML_SUPPORT) + target_compile_definitions(pyside2 PUBLIC PYSIDE_QML_SUPPORT=1) +endif() + # # install stuff # diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index fa608312..5b2be98c 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -604,7 +604,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject* type) sig += data->signatures[i]; sig += ')'; if (d.superdata->indexOfSignal(sig) == -1) - addSignal(sig); + addSignal(sig, "void"); } } else if (PyFunction_Check(value)) { // Register slots if (PyObject_HasAttr(value, slotAttrName)) { diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp index 7545636f..6a439c6e 100644 --- a/libpyside/pyside.cpp +++ b/libpyside/pyside.cpp @@ -367,5 +367,19 @@ PyObject* getWrapperForQObject(QObject* cppSelf, SbkObjectType* sbk_type) return pyOut; } +#ifdef PYSIDE_QML_SUPPORT +static QuickRegisterItemFunction quickRegisterItem; + +QuickRegisterItemFunction getQuickRegisterItemFunction() +{ + return quickRegisterItem; +} + +void setQuickRegisterItemFunction(QuickRegisterItemFunction function) +{ + quickRegisterItem = function; +} +#endif // PYSIDE_QML_SUPPORT + } //namespace PySide diff --git a/libpyside/pyside.h b/libpyside/pyside.h index c59ae208..3619e287 100644 --- a/libpyside/pyside.h +++ b/libpyside/pyside.h @@ -42,6 +42,11 @@ #include <sbkpython.h> #include <pysidemacros.h> + +#ifdef PYSIDE_QML_SUPPORT +# include <qqml.h> +#endif + #include <QMetaType> #include <QHash> #include <QList> @@ -136,6 +141,15 @@ PYSIDE_API void setNextQObjectMemoryAddr(void* addr); PYSIDE_API PyObject* getWrapperForQObject(QObject* cppSelf, SbkObjectType* sbk_type); +#ifdef PYSIDE_QML_SUPPORT +// Used by QtQuick module to notify QtQml that custom QtQuick items can be registered. +typedef bool (*QuickRegisterItemFunction)(PyObject *pyObj, const char *uri, int versionMajor, + int versionMinor, const char *qmlName, + QQmlPrivate::RegisterType *); +PYSIDE_API QuickRegisterItemFunction getQuickRegisterItemFunction(); +PYSIDE_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function); +#endif // PYSIDE_QML_SUPPORT + } //namespace PySide |