aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2016-10-19 10:54:52 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2016-10-19 10:38:15 +0000
commit5e5cdccca60d26c171d18dc718b703453e44dbc7 (patch)
treef7bc02e73ac2006ade7087f3bc8a35537eaf64e6
parentdc22a4e370cedc23371029543a919dec2b02a23d (diff)
Make QtQml / QtQuick work
Task-number: PYSIDE-355 Change-Id: I67366fb8ceacbcda80e7f17ad5e5ca80d6847902 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--PySide2/CMakeLists.txt6
-rw-r--r--PySide2/QtQml/CMakeLists.txt14
-rw-r--r--PySide2/QtQml/pysideqmlregistertype.cpp147
-rw-r--r--PySide2/QtQml/pysideqmlregistertype.h6
-rw-r--r--PySide2/QtQml/typesystem_qml.xml23
-rw-r--r--PySide2/QtQuick/CMakeLists.txt25
-rw-r--r--PySide2/QtQuick/pysidequickregistertype.cpp251
-rw-r--r--PySide2/QtQuick/pysidequickregistertype.h52
-rw-r--r--PySide2/QtQuick/typesystem_quick.xml23
-rw-r--r--libpyside/CMakeLists.txt4
-rw-r--r--libpyside/dynamicqmetaobject.cpp2
-rw-r--r--libpyside/pyside.cpp14
-rw-r--r--libpyside/pyside.h14
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 &registered)
+{
+ 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