aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp')
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp311
1 files changed, 228 insertions, 83 deletions
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index 2b60c5c7f..fd470cd71 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -52,74 +52,34 @@
#include "pyside2_qtcore_python.h"
#include "pyside2_qtqml_python.h"
-#ifndef PYSIDE_MAX_QML_TYPES
-// 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
+#include <QtQml/QJSValue>
// Forward declarations.
static void propListMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Call call,
void **args);
-// 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.
static QMutex nextQmlElementMutex;
-template<int N>
-struct ElementFactoryBase
+static void createInto(void *memory, void *type)
{
- static void createInto(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>::createInto;
- ElementFactory<N-1>::init();
- }
-};
-
-template<>
-struct ElementFactory<0> : ElementFactoryBase<0>
-{
- static void init()
- {
- createFuncs[0] = &ElementFactoryBase<0>::createInto;
- }
-};
+ 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);
+}
int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
- int versionMinor, const char *qmlName)
+ int versionMinor, const char *qmlName, const char *noCreationReason,
+ bool creatable)
{
using namespace Shiboken;
static PyTypeObject *qobjectType = Shiboken::Conversions::getPythonTypeObject("QObject*");
assert(qobjectType);
- static int nextType = 0;
-
- if (nextType >= PYSIDE_MAX_QML_TYPES) {
- PyErr_Format(PyExc_TypeError, "You can only export %d custom QML types to QML.",
- PYSIDE_MAX_QML_TYPES);
- return -1;
- }
PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) {
@@ -132,15 +92,15 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
Q_ASSERT(metaObject);
QQmlPrivate::RegisterType type;
- type.version = 0;
// Allow registering Qt Quick items.
bool registered = false;
#ifdef PYSIDE_QML_SUPPORT
QuickRegisterItemFunction quickRegisterItemFunction = getQuickRegisterItemFunction();
if (quickRegisterItemFunction) {
- registered = quickRegisterItemFunction(pyObj, uri, versionMajor, versionMinor,
- qmlName, &type);
+ registered =
+ quickRegisterItemFunction(pyObj, uri, versionMajor, versionMinor,
+ qmlName, creatable, noCreationReason, &type);
}
#endif
@@ -150,11 +110,11 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
// there's no way to unregister a QML type.
Py_INCREF(pyObj);
- pyTypes[nextType] = pyObj;
+ type.structVersion = 0;
// FIXME: Fix this to assign new type ids each time.
- type.typeId = qMetaTypeId<QObject *>();
- type.listId = qMetaTypeId<QQmlListProperty<QObject> >();
+ type.typeId = QMetaType(QMetaType::QObjectStar);
+ type.listId = QMetaType::fromType<QQmlListProperty<QObject> >();
type.attachedPropertiesFunction = QQmlPrivate::attachedPropertiesFunc<QObject>();
type.attachedPropertiesMetaObject = QQmlPrivate::attachedPropertiesMetaObject<QObject>();
@@ -168,16 +128,16 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
int objectSize = static_cast<int>(PySide::getSizeOfQObject(
reinterpret_cast<SbkObjectType *>(pyObj)));
type.objectSize = objectSize;
- type.create = createFuncs[nextType];
+ type.create = creatable ? createInto : nullptr;
+ type.noCreationReason = noCreationReason;
+ type.userdata = pyObj;
type.uri = uri;
- type.versionMajor = versionMajor;
- type.versionMinor = versionMinor;
+ type.version = QTypeRevision::fromVersion(versionMajor, versionMinor);
type.elementName = qmlName;
type.extensionObjectCreate = 0;
type.extensionMetaObject = 0;
type.customParser = 0;
- ++nextType;
}
type.metaObject = metaObject; // Snapshot may have changed.
@@ -189,6 +149,126 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
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 = PyInt_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) {
+ static PyTypeObject *qobjectType = Conversions::getPythonTypeObject("QObject*");
+ assert(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;
+ }
+
+ // 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 * {
+ AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0));
+
+ if (hasCallback) {
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QQMLENGINE_IDX],
+ engine));
+ }
+
+ AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args));
+
+ SbkObjectType *qobjectType = (SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX];
+
+ // 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 {
+ AutoDecRef args(PyTuple_New(1));
+
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QQMLENGINE_IDX],
+ engine));
+
+ AutoDecRef retVal(PyObject_CallObject(callback, args));
+
+ SbkObjectType *qjsvalueType = (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QJSVALUE_IDX];
+
+ // 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);
+}
+
extern "C"
{
@@ -197,27 +277,51 @@ struct QmlListProperty
{
PyTypeObject *type;
PyObject *append;
+ PyObject *count;
PyObject *at;
PyObject *clear;
- PyObject *count;
+ PyObject *replace;
+ PyObject *removeLast;
};
static int propListTpInit(PyObject *self, PyObject *args, PyObject *kwds)
{
- static const char *kwlist[] = {"type", "append", "at", "clear", "count", 0};
+ static const char *kwlist[] = {"type", "append", "count", "at", "clear", "replace", "removeLast", 0};
PySideProperty *pySelf = reinterpret_cast<PySideProperty *>(self);
QmlListProperty *data = new QmlListProperty;
memset(data, 0, sizeof(QmlListProperty));
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "OO|OOO:QtQml.ListProperty", (char **) kwlist,
+ "O|OOOOOO:QtQml.ListProperty", (char **) kwlist,
&data->type,
&data->append,
+ &data->count,
&data->at,
&data->clear,
- &data->count)) {
+ &data->replace,
+ &data->removeLast)) {
return -1;
}
+
+ static PyTypeObject *qobjectType = Shiboken::Conversions::getPythonTypeObject("QObject*");
+ assert(qobjectType);
+
+ if (!PySequence_Contains(data->type->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) {
+ PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.",
+ qobjectType->tp_name, data->type->tp_name);
+ return -1;
+ }
+
+ if ((data->append && data->append != Py_None && !PyCallable_Check(data->append)) ||
+ (data->count && data->count != Py_None && !PyCallable_Check(data->count)) ||
+ (data->at && data->at != Py_None && !PyCallable_Check(data->at)) ||
+ (data->clear && data->clear != Py_None && !PyCallable_Check(data->clear)) ||
+ (data->replace && data->replace != Py_None && !PyCallable_Check(data->replace)) ||
+ (data->removeLast && data->removeLast != Py_None && !PyCallable_Check(data->removeLast))) {
+ PyErr_Format(PyExc_TypeError, "Non-callable parameter given");
+ return -1;
+ }
+
PySide::Property::setMetaCallHandler(pySelf, &propListMetaCall);
PySide::Property::setTypeName(pySelf, "QQmlListProperty<QObject>");
PySide::Property::setUserData(pySelf, data);
@@ -333,6 +437,38 @@ void propListClear(QQmlListProperty<QObject> * propList)
PyErr_Print();
}
+// Implementation of QQmlListProperty<T>::ReplaceFunction callback
+void propListReplace(QQmlListProperty<QObject> *propList, int index, QObject *value)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(3));
+ PyTuple_SET_ITEM(args, 0, Shiboken::Conversions::pointerToPython((SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], propList->object));
+ PyTuple_SET_ITEM(args, 1, Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &index));
+ PyTuple_SET_ITEM(args, 2, Shiboken::Conversions::pointerToPython((SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], value));
+
+ auto data = reinterpret_cast<QmlListProperty *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->replace, args));
+
+ if (PyErr_Occurred())
+ PyErr_Print();
+}
+
+// Implementation of QQmlListProperty<T>::RemoveLastFunction callback
+void propListRemoveLast(QQmlListProperty<QObject> *propList)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTuple_SET_ITEM(args, 0, Shiboken::Conversions::pointerToPython((SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], propList->object));
+
+ auto data = reinterpret_cast<QmlListProperty *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->removeLast, args));
+
+ if (PyErr_Occurred())
+ PyErr_Print();
+}
+
// qt_metacall specialization for ListProperties
static void propListMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Call call, void **args)
{
@@ -342,7 +478,13 @@ static void propListMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Ca
auto data = reinterpret_cast<QmlListProperty *>(PySide::Property::userData(pp));
QObject *qobj;
Shiboken::Conversions::pythonToCppPointer((SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX], self, &qobj);
- QQmlListProperty<QObject> declProp(qobj, data, &propListAppender, &propListCount, &propListAt, &propListClear);
+ QQmlListProperty<QObject> declProp(qobj, data,
+ data->append && data->append != Py_None ? &propListAppender : nullptr,
+ data->count && data->count != Py_None ? &propListCount : nullptr,
+ data->at && data->at != Py_None ? &propListAt : nullptr,
+ data->clear && data->clear != Py_None ? &propListClear : nullptr,
+ data->replace && data->replace != Py_None ? &propListReplace : nullptr,
+ data->removeLast && data->removeLast != Py_None ? &propListRemoveLast : nullptr);
// Copy the data to the memory location requested by the meta call
void *v = args[0];
@@ -367,18 +509,23 @@ QtQml_VolatileBoolObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
QtQml_VolatileBoolObject *self
= reinterpret_cast<QtQml_VolatileBoolObject *>(type->tp_alloc(type, 0));
- if (self != Q_NULLPTR)
- self->flag = ok;
+ if (self != nullptr)
+ self->flag = new AtomicBool(ok);
return reinterpret_cast<PyObject *>(self);
}
+static void QtQml_VolatileBoolObject_dealloc(PyObject *self)
+{
+ auto volatileBool = reinterpret_cast<QtQml_VolatileBoolObject *>(self);
+ delete volatileBool->flag;
+ Sbk_object_dealloc(self);
+}
+
static PyObject *
QtQml_VolatileBoolObject_get(QtQml_VolatileBoolObject *self)
{
- if (self->flag)
- return Py_True;
- return Py_False;
+ return *self->flag ? Py_True : Py_False;
}
static PyObject *
@@ -397,10 +544,7 @@ QtQml_VolatileBoolObject_set(QtQml_VolatileBoolObject *self, PyObject *args)
return Q_NULLPTR;
}
- if (ok > 0)
- self->flag = true;
- else
- self->flag = false;
+ *self->flag = ok > 0;
Py_RETURN_NONE;
}
@@ -420,7 +564,7 @@ QtQml_VolatileBoolObject_repr(QtQml_VolatileBoolObject *self)
{
PyObject *s;
- if (self->flag)
+ if (*self->flag)
s = PyBytes_FromFormat("%s(True)",
Py_TYPE(self)->tp_name);
else
@@ -435,12 +579,12 @@ QtQml_VolatileBoolObject_str(QtQml_VolatileBoolObject *self)
{
PyObject *s;
- if (self->flag)
+ if (*self->flag)
s = PyBytes_FromFormat("%s(True) -> %p",
- Py_TYPE(self)->tp_name, &(self->flag));
+ Py_TYPE(self)->tp_name, self->flag);
else
s = PyBytes_FromFormat("%s(False) -> %p",
- Py_TYPE(self)->tp_name, &(self->flag));
+ Py_TYPE(self)->tp_name, self->flag);
Py_XINCREF(s);
return s;
}
@@ -450,7 +594,7 @@ static PyType_Slot QtQml_VolatileBoolType_slots[] = {
{Py_tp_str, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str)},
{Py_tp_methods, (void *)QtQml_VolatileBoolObject_methods},
{Py_tp_new, (void *)QtQml_VolatileBoolObject_new},
- {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {Py_tp_dealloc, (void *)QtQml_VolatileBoolObject_dealloc},
{0, 0}
};
static PyType_Spec QtQml_VolatileBoolType_spec = {
@@ -481,8 +625,6 @@ static const char *VolatileBool_SignatureStrings[] = {
void PySide::initQmlSupport(PyObject *module)
{
- ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init();
-
// Export QmlListProperty type
if (InitSignatureStrings(PropertyListTypeF(), PropertyList_SignatureStrings) < 0) {
PyErr_Print();
@@ -490,6 +632,9 @@ void PySide::initQmlSupport(PyObject *module)
return;
}
+ // Register QQmlListProperty metatype for use in QML
+ qRegisterMetaType<QQmlListProperty<QObject>>();
+
Py_INCREF(reinterpret_cast<PyObject *>(PropertyListTypeF()));
PyModule_AddObject(module, PepType_GetNameStr(PropertyListTypeF()),
reinterpret_cast<PyObject *>(PropertyListTypeF()));