diff options
Diffstat (limited to 'sources/pyside6/libpysideqml')
| -rw-r--r-- | sources/pyside6/libpysideqml/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqml.cpp | 2 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqmlextended.cpp | 182 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqmlextended_p.h | 57 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqmlregistertype.cpp | 7 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp | 16 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h | 13 |
7 files changed, 276 insertions, 2 deletions
diff --git a/sources/pyside6/libpysideqml/CMakeLists.txt b/sources/pyside6/libpysideqml/CMakeLists.txt index aa07a5077..28ec31721 100644 --- a/sources/pyside6/libpysideqml/CMakeLists.txt +++ b/sources/pyside6/libpysideqml/CMakeLists.txt @@ -3,6 +3,7 @@ set(libpysideqml_libraries Qt::Core Qt::CorePrivate Qt::Qml Qt::QmlPrivate) set(libpysideqml_SRC pysideqml.cpp pysideqmlforeign.cpp + pysideqmlextended.cpp pysideqmlregistertype.cpp pysideqmlmetacallerror.cpp pysideqmllistproperty.cpp diff --git a/sources/pyside6/libpysideqml/pysideqml.cpp b/sources/pyside6/libpysideqml/pysideqml.cpp index 06646a6e8..5babc7eee 100644 --- a/sources/pyside6/libpysideqml/pysideqml.cpp +++ b/sources/pyside6/libpysideqml/pysideqml.cpp @@ -39,6 +39,7 @@ #include "pysideqml.h" #include "pysideqmllistproperty_p.h" +#include "pysideqmlextended_p.h" #include "pysideqmlforeign_p.h" #include "pysideqmlnamedelement_p.h" #include "pysideqmluncreatable.h" @@ -53,6 +54,7 @@ void init(PyObject *module) { initQtQmlListProperty(module); initQmlForeign(module); + initQmlExtended(module); initQmlNamedElement(module); initQmlUncreatable(module); PySide::SignalManager::setQmlMetaCallErrorHandler(PySide::Qml::qmlMetaCallErrorHandler); diff --git a/sources/pyside6/libpysideqml/pysideqmlextended.cpp b/sources/pyside6/libpysideqml/pysideqmlextended.cpp new file mode 100644 index 000000000..2ae4afd83 --- /dev/null +++ b/sources/pyside6/libpysideqml/pysideqmlextended.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pysideqmlextended_p.h" +#include "pysideqmltypeinfo_p.h" +#include "pysideqmlregistertype_p.h" + +#include <pyside_p.h> +#include <pysideclassdecorator_p.h> + +#include <shiboken.h> +#include <signature.h> +#include <sbkstring.h> + +#include <QtCore/QtGlobal> +#include <QtQml/qqml.h> + +// The QmlExtended decorator modifies QmlElement to register an extension. +// Due to the (reverse) execution order of decorators, it needs to follow +// QmlElement. +class PySideQmlExtendedPrivate : public PySide::ClassDecorator::TypeDecoratorPrivate +{ +public: + PyObject *tp_call(PyObject *self, PyObject *args, PyObject * /* kw */) override; + const char *name() const override; +}; + +// The call operator is passed the class type and registers the type +// in QmlTypeInfo. +PyObject *PySideQmlExtendedPrivate::tp_call(PyObject *self, PyObject *args, PyObject * /* kw */) +{ + PyObject *klass = tp_call_check(args, CheckMode::WrappedType); + if (klass == nullptr) + return nullptr; + + auto *data = DecoratorPrivate::get<PySideQmlExtendedPrivate>(self); + PySide::Qml::ensureQmlTypeInfo(klass)->extensionType = data->type(); + + Py_INCREF(klass); + return klass; +} + +const char *PySideQmlExtendedPrivate::name() const +{ + return "QmlExtended"; +} + +extern "C" { + +static PyTypeObject *createPySideQmlExtendedType(void) +{ + auto typeSlots = + PySide::ClassDecorator::Methods<PySideQmlExtendedPrivate>::typeSlots(); + + PyType_Spec PySideQmlExtendedType_spec = { + "2:PySide6.QtCore.qmlExtended", + sizeof(PySideClassDecorator), + 0, + Py_TPFLAGS_DEFAULT, + typeSlots.data() + }; + return SbkType_FromSpec(&PySideQmlExtendedType_spec); +} + +PyTypeObject *PySideQmlExtended_TypeF(void) +{ + static auto *type = createPySideQmlExtendedType(); + return type; +} + +} // extern "C" + +static const char *qmlExtended_SignatureStrings[] = { + "PySide6.QtQml.QmlExtended(self,type:type)", + nullptr // Sentinel +}; + +namespace PySide::Qml { + +static QObject *extensionFactory(QObject *o) +{ + Shiboken::GilState gilState; + Shiboken::Conversions::SpecificConverter converter("QObject"); + Q_ASSERT(converter); + PyObject *pyObj = converter.toPython(&o); + Q_ASSERT(pyObj); + + // Search for the extension type and create an instance by invoking + // the call operator on type with the parent parameter. + // If there is an error and nullptr is returned, a crash occurs, + // so, errors should at least be printed. + + auto *pyObjType = Py_TYPE(pyObj); + const auto info = qmlTypeInfo(reinterpret_cast<PyObject *>(pyObjType)); + if (info.isNull() || info->extensionType == nullptr) { + qWarning("QmlExtended: Cannot find extension of %s.", pyObjType->tp_name); + return nullptr; + } + + Shiboken::AutoDecRef args(PyTuple_New(1)); + PyTuple_SET_ITEM(args.object(), 0, pyObj); + auto *extensionTypeObj = reinterpret_cast<PyObject *>(info->extensionType); + Shiboken::AutoDecRef pyResult(PyObject_Call(extensionTypeObj, args, nullptr)); + if (pyResult.isNull() || PyErr_Occurred()) { + PyErr_Print(); + return nullptr; + } + + if (PyType_IsSubtype(pyResult->ob_type, qObjectType()) == 0) { + qWarning("QmlExtended: Extension objects must inherit QObject, got %s.", + pyResult->ob_type->tp_name); + return nullptr; + } + + QObject *result = nullptr; + converter.toCpp(pyResult.object(), &result); + return result; +} + +void initQmlExtended(PyObject *module) +{ + if (InitSignatureStrings(PySideQmlExtended_TypeF(), qmlExtended_SignatureStrings) < 0) + return; + + Py_INCREF(PySideQmlExtended_TypeF()); + PyModule_AddObject(module, "QmlExtended", + reinterpret_cast<PyObject *>(PySideQmlExtended_TypeF())); +} + +PySide::Qml::QmlExtensionInfo qmlExtendedInfo(PyObject *t, + const QSharedPointer<QmlTypeInfo> &info) +{ + PySide::Qml::QmlExtensionInfo result{nullptr, nullptr}; + if (!info.isNull() && info->extensionType) { + result.metaObject = PySide::retrieveMetaObject(info->extensionType); + if (result.metaObject) { + result.factory = extensionFactory; + } else { + qWarning("Unable to retrieve meta object for %s", + reinterpret_cast<PyTypeObject *>(t)->tp_name); + } + } + return result; +} + +} // namespace PySide::Qml diff --git a/sources/pyside6/libpysideqml/pysideqmlextended_p.h b/sources/pyside6/libpysideqml/pysideqmlextended_p.h new file mode 100644 index 000000000..03551d1f4 --- /dev/null +++ b/sources/pyside6/libpysideqml/pysideqmlextended_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PYSIDEQMLEXTENDED_P_H +#define PYSIDEQMLEXTENDED_P_H + +#include <sbkpython.h> + +#include <QtCore/QSharedPointer> + +namespace PySide::Qml { +struct QmlExtensionInfo; +struct QmlTypeInfo; + +void initQmlExtended(PyObject *module); + +PySide::Qml::QmlExtensionInfo qmlExtendedInfo(PyObject *t, + const QSharedPointer<QmlTypeInfo> &info); +} // namespace PySide::Qml + +#endif // PYSIDEQMLEXTENDED_P_H diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp index 30f8f2bfb..aee013627 100644 --- a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp +++ b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp @@ -40,6 +40,7 @@ #include "pysideqmlregistertype.h" #include "pysideqmlregistertype_p.h" #include "pysideqmltypeinfo_p.h" +#include "pysideqmlextended_p.h" #include <limits> @@ -137,6 +138,7 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, // FIXME: Fix this to assign new type ids each time. type.typeId = QMetaType(QMetaType::QObjectStar); type.listId = QMetaType::fromType<QQmlListProperty<QObject> >(); + const auto typeInfo = qmlTypeInfo(pyObj); type.attachedPropertiesFunction = QQmlPrivate::attachedPropertiesFunc<QObject>(); type.attachedPropertiesMetaObject = QQmlPrivate::attachedPropertiesMetaObject<QObject>(); @@ -157,8 +159,9 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, type.version = QTypeRevision::fromVersion(versionMajor, versionMinor); type.elementName = qmlName; - type.extensionObjectCreate = 0; - type.extensionMetaObject = 0; + auto info = qmlExtendedInfo(pyObj, typeInfo); + type.extensionObjectCreate = info.factory; + type.extensionMetaObject = info.metaObject; type.customParser = 0; } type.metaObject = metaObject; // Snapshot may have changed. diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp index 2d5b48c98..f8256524f 100644 --- a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp +++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp @@ -82,9 +82,25 @@ QDebug operator<<(QDebug d, const QmlTypeInfo &i) d << ", noCreationReason=\"" << i.noCreationReason.c_str() << '"'; if (i.foreignType) d << ", foreignType=" << i.foreignType->tp_name; + if (i.extensionType) + d << ", extensionType=" << i.extensionType->tp_name; d << ')'; return d; } + +QDebug operator<<(QDebug d, const QmlExtensionInfo &e) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "QmlExtensionInfo("; + if (e.factory != nullptr && e.metaObject != nullptr) + d << '"' << e.metaObject->className() << "\", factory=" + << reinterpret_cast<const void *>(e.factory); + d << ')'; + return d; +} + #endif // QT_NO_DEBUG_STREAM } // namespace PySide::Qml diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h index 26ea782d3..17ca967c6 100644 --- a/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h +++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h @@ -48,6 +48,8 @@ #include <string> QT_FORWARD_DECLARE_CLASS(QDebug) +QT_FORWARD_DECLARE_CLASS(QObject) +QT_FORWARD_DECLARE_STRUCT(QMetaObject) namespace PySide::Qml { @@ -66,6 +68,7 @@ struct QmlTypeInfo QmlTypeFlags flags; std::string noCreationReason; PyTypeObject *foreignType = nullptr; + PyTypeObject *extensionType = nullptr; }; using QmlTypeInfoPtr = QSharedPointer<QmlTypeInfo>; @@ -74,8 +77,18 @@ QmlTypeInfoPtr ensureQmlTypeInfo(const PyObject *o); void insertQmlTypeInfoAlias(const PyObject *o, const QmlTypeInfoPtr &value); QmlTypeInfoPtr qmlTypeInfo(const PyObject *o); +// Meta Object and factory function for QmlExtended/QmlAttached +struct QmlExtensionInfo +{ + using Factory = QObject *(*)(QObject *); + + Factory factory; + const QMetaObject *metaObject; +}; + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QmlTypeInfo &); +QDebug operator<<(QDebug d, const QmlExtensionInfo &); #endif } // namespace PySide::Qml |
