aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpysideqml
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpysideqml')
-rw-r--r--sources/pyside6/libpysideqml/CMakeLists.txt1
-rw-r--r--sources/pyside6/libpysideqml/pysideqml.cpp2
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlattached.cpp253
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlattached.h64
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlattached_p.h57
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlregistertype.cpp8
-rw-r--r--sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp2
-rw-r--r--sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h1
8 files changed, 385 insertions, 3 deletions
diff --git a/sources/pyside6/libpysideqml/CMakeLists.txt b/sources/pyside6/libpysideqml/CMakeLists.txt
index 28ec31721..33bfce1c6 100644
--- a/sources/pyside6/libpysideqml/CMakeLists.txt
+++ b/sources/pyside6/libpysideqml/CMakeLists.txt
@@ -2,6 +2,7 @@ set(libpysideqml_libraries Qt::Core Qt::CorePrivate Qt::Qml Qt::QmlPrivate)
set(libpysideqml_SRC
pysideqml.cpp
+ pysideqmlattached.cpp
pysideqmlforeign.cpp
pysideqmlextended.cpp
pysideqmlregistertype.cpp
diff --git a/sources/pyside6/libpysideqml/pysideqml.cpp b/sources/pyside6/libpysideqml/pysideqml.cpp
index 5babc7eee..f88413f78 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 "pysideqmlattached_p.h"
#include "pysideqmlextended_p.h"
#include "pysideqmlforeign_p.h"
#include "pysideqmlnamedelement_p.h"
@@ -53,6 +54,7 @@ namespace PySide::Qml
void init(PyObject *module)
{
initQtQmlListProperty(module);
+ initQmlAttached(module);
initQmlForeign(module);
initQmlExtended(module);
initQmlNamedElement(module);
diff --git a/sources/pyside6/libpysideqml/pysideqmlattached.cpp b/sources/pyside6/libpysideqml/pysideqmlattached.cpp
new file mode 100644
index 000000000..ad8a6ac1a
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlattached.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** 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 "pysideqmlattached.h"
+#include "pysideqmlattached_p.h"
+#include "pysideqmltypeinfo_p.h"
+#include "pysideqmlregistertype_p.h"
+
+#include <signalmanager.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>
+
+#include <algorithm>
+
+// The QmlAttached decorator modifies QmlElement to register an attached property
+// type. Due to the (reverse) execution order of decorators, it needs to follow
+// QmlElement.
+class PySideQmlAttachedPrivate : 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 *PySideQmlAttachedPrivate::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<PySideQmlAttachedPrivate>(self);
+ PySide::Qml::ensureQmlTypeInfo(klass)->attachedType = data->type();
+
+ Py_INCREF(klass);
+ return klass;
+}
+
+const char *PySideQmlAttachedPrivate::name() const
+{
+ return "QmlAttached";
+}
+
+extern "C" {
+
+static PyTypeObject *createPySideQmlAttachedType(void)
+{
+ auto typeSlots =
+ PySide::ClassDecorator::Methods<PySideQmlAttachedPrivate>::typeSlots();
+
+ PyType_Spec PySideQmlAttachedType_spec = {
+ "2:PySide6.QtCore.qmlAttached",
+ sizeof(PySideClassDecorator),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeSlots.data()
+ };
+ return SbkType_FromSpec(&PySideQmlAttachedType_spec);
+}
+
+PyTypeObject *PySideQmlAttached_TypeF(void)
+{
+ static auto *type = createPySideQmlAttachedType();
+ return type;
+}
+
+} // extern "C"
+
+static const char *qmlAttached_SignatureStrings[] = {
+ "PySide6.QtQml.QmlAttached(self,type:type)",
+ nullptr // Sentinel
+};
+
+namespace PySide::Qml {
+
+static QObject *attachedFactoryHelper(PyTypeObject *attachingType, QObject *o)
+{
+ // Call static qmlAttachedProperties() on type. If there is an error
+ // and nullptr is returned, a crash occurs. So, errors should at least be
+ // printed.
+
+ Shiboken::GilState gilState;
+ Shiboken::Conversions::SpecificConverter converter("QObject");
+ Q_ASSERT(converter);
+
+ static const char methodName[] = "qmlAttachedProperties";
+ static PyObject *const pyMethodName = Shiboken::String::createStaticString(methodName);
+ PyObject *attachingTypeObj = reinterpret_cast<PyObject *>(attachingType);
+ Shiboken::AutoDecRef pyResult(PyObject_CallMethodObjArgs(attachingTypeObj, pyMethodName,
+ attachingTypeObj /* self */,
+ converter.toPython(&o),
+ nullptr));
+ if (pyResult.isNull() || PyErr_Occurred()) {
+ PyErr_Print();
+ return nullptr;
+ }
+
+ if (PyType_IsSubtype(pyResult->ob_type, qObjectType()) == 0) {
+ qWarning("QmlAttached: Attached objects must inherit QObject, got %s.",
+ pyResult->ob_type->tp_name);
+ return nullptr;
+ }
+
+ QObject *result = nullptr;
+ converter.toCpp(pyResult.object(), &result);
+ return result;
+}
+
+// Since the required attached factory signature does not have a void *user
+// parameter to store the attaching type, we employ a template trick, storing
+// the attaching types in an array and create non-type-template (int) functions
+// taking the array index as template parameter.
+// We initialize the attachedFactories array with factory functions
+// accessing the attachingTypes[N] using template metaprogramming.
+
+enum { MAX_ATTACHING_TYPES = 50};
+
+using AttachedFactory = QObject *(*)(QObject *);
+
+static int nextAttachingType = 0;
+static PyTypeObject *attachingTypes[MAX_ATTACHING_TYPES];
+static AttachedFactory attachedFactories[MAX_ATTACHING_TYPES];
+
+template <int N>
+static QObject *attachedFactory(QObject *o)
+{
+ return attachedFactoryHelper(attachingTypes[N], o);
+}
+
+template<int N>
+struct AttachedFactoryInitializerBase
+{
+};
+
+template<int N>
+struct AttachedFactoryInitializer : AttachedFactoryInitializerBase<N>
+{
+ static void init()
+ {
+ attachedFactories[N] = attachedFactory<N>;
+ AttachedFactoryInitializer<N-1>::init();
+ }
+};
+
+template<>
+struct AttachedFactoryInitializer<0> : AttachedFactoryInitializerBase<0>
+{
+ static void init()
+ {
+ attachedFactories[0] = attachedFactory<0>;
+ }
+};
+
+void initQmlAttached(PyObject *module)
+{
+ std::fill(attachingTypes, attachingTypes + MAX_ATTACHING_TYPES, nullptr);
+ AttachedFactoryInitializer<MAX_ATTACHING_TYPES - 1>::init();
+
+ if (InitSignatureStrings(PySideQmlAttached_TypeF(), qmlAttached_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideQmlAttached_TypeF());
+ PyModule_AddObject(module, "QmlAttached",
+ reinterpret_cast<PyObject *>(PySideQmlAttached_TypeF()));
+}
+
+PySide::Qml::QmlExtensionInfo qmlAttachedInfo(PyTypeObject *t,
+ const QSharedPointer<QmlTypeInfo> &info)
+{
+ PySide::Qml::QmlExtensionInfo result{nullptr, nullptr};
+ if (info.isNull() || info->attachedType == nullptr)
+ return result;
+
+ auto *name = reinterpret_cast<PyTypeObject *>(t)->tp_name;
+ if (nextAttachingType >= MAX_ATTACHING_TYPES) {
+ qWarning("Unable to initialize attached type \"%s\": "
+ "The limit %d of attached types has been reached.",
+ name, MAX_ATTACHING_TYPES);
+ return result;
+ }
+
+ result.metaObject = PySide::retrieveMetaObject(info->attachedType);
+ if (result.metaObject == nullptr) {
+ qWarning("Unable to retrieve meta object for %s", name);
+ return result;
+ }
+
+ attachingTypes[nextAttachingType] = t;
+ result.factory = attachedFactories[nextAttachingType];
+ ++nextAttachingType;
+
+ return result;
+}
+
+QObject *qmlAttachedPropertiesObject(PyObject *typeObject, QObject *obj, bool create)
+{
+ auto *type = reinterpret_cast<PyTypeObject *>(typeObject);
+ auto *end = attachingTypes + nextAttachingType;
+ auto *typePtr = std::find(attachingTypes, end, type);
+ if (typePtr == end) {
+ qWarning("%s: Attaching type \"%s\" not found.", __FUNCTION__, type->tp_name);
+ return nullptr;
+ }
+
+ auto func = attachedFactories[std::uintptr_t(typePtr - attachingTypes)];
+ return ::qmlAttachedPropertiesObject(obj, func, create);
+}
+
+} // namespace PySide::Qml
diff --git a/sources/pyside6/libpysideqml/pysideqmlattached.h b/sources/pyside6/libpysideqml/pysideqmlattached.h
new file mode 100644
index 000000000..d2d1554af
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlattached.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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 PYSIDEQMLATTACHED_H
+#define PYSIDEQMLATTACHED_H
+
+#include <sbkpython.h>
+
+#include "pysideqmlmacros.h"
+
+#include <QtCore/QtGlobal>
+
+QT_FORWARD_DECLARE_CLASS(QObject)
+
+namespace PySide::Qml
+{
+
+/// PySide implementation of qmlAttachedPropertiesObject<T> function.
+/// \param typeObject attaching type
+/// \param obj attachee
+/// \param create Whether to create the Attachment object
+/// \return Attachment object instance
+PYSIDEQML_API QObject *qmlAttachedPropertiesObject(PyObject *typeObject, QObject *obj,
+ bool create = true);
+
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLATTACHED_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlattached_p.h b/sources/pyside6/libpysideqml/pysideqmlattached_p.h
new file mode 100644
index 000000000..7305ec6f5
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlattached_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 PYSIDEQMLATTACHED_P_H
+#define PYSIDEQMLATTACHED_P_H
+
+#include <sbkpython.h>
+
+#include <QSharedPointer>
+
+namespace PySide::Qml {
+struct QmlExtensionInfo;
+struct QmlTypeInfo;
+
+void initQmlAttached(PyObject *module);
+
+PySide::Qml::QmlExtensionInfo qmlAttachedInfo(PyTypeObject *t,
+ const QSharedPointer<QmlTypeInfo> &info);
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLATTACHED_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp
index aee013627..e935b5627 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 "pysideqmlattached_p.h"
#include "pysideqmlextended_p.h"
#include <limits>
@@ -139,8 +140,9 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
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>();
+ auto info = qmlAttachedInfo(pyObjType, typeInfo);
+ type.attachedPropertiesFunction = info.factory;
+ type.attachedPropertiesMetaObject = info.metaObject;
type.parserStatusCast =
QQmlPrivate::StaticCastSelector<QObject, QQmlParserStatus>::cast();
@@ -159,7 +161,7 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
type.version = QTypeRevision::fromVersion(versionMajor, versionMinor);
type.elementName = qmlName;
- auto info = qmlExtendedInfo(pyObj, typeInfo);
+ info = qmlExtendedInfo(pyObj, typeInfo);
type.extensionObjectCreate = info.factory;
type.extensionMetaObject = info.metaObject;
type.customParser = 0;
diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp
index f8256524f..7ae707330 100644
--- a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp
+++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp
@@ -82,6 +82,8 @@ QDebug operator<<(QDebug d, const QmlTypeInfo &i)
d << ", noCreationReason=\"" << i.noCreationReason.c_str() << '"';
if (i.foreignType)
d << ", foreignType=" << i.foreignType->tp_name;
+ if (i.attachedType)
+ d << ", attachedType=" << i.attachedType->tp_name;
if (i.extensionType)
d << ", extensionType=" << i.extensionType->tp_name;
d << ')';
diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h
index 17ca967c6..fa47891f6 100644
--- a/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h
+++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h
@@ -68,6 +68,7 @@ struct QmlTypeInfo
QmlTypeFlags flags;
std::string noCreationReason;
PyTypeObject *foreignType = nullptr;
+ PyTypeObject *attachedType = nullptr;
PyTypeObject *extensionType = nullptr;
};