aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpysideqml
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpysideqml')
-rw-r--r--sources/pyside6/libpysideqml/CMakeLists.txt115
-rw-r--r--sources/pyside6/libpysideqml/PySide6QmlConfig-spec.cmake.in7
-rw-r--r--sources/pyside6/libpysideqml/PySide6QmlConfig.cmake.in5
-rw-r--r--sources/pyside6/libpysideqml/PySide6QmlConfigVersion.cmake.in10
-rw-r--r--sources/pyside6/libpysideqml/pysideqml.cpp35
-rw-r--r--sources/pyside6/libpysideqml/pysideqml.h18
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlattached.cpp216
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlattached.h28
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlattached_p.h21
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlextended.cpp145
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlextended_p.h21
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlforeign.cpp92
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlforeign_p.h17
-rw-r--r--sources/pyside6/libpysideqml/pysideqmllistproperty.cpp307
-rw-r--r--sources/pyside6/libpysideqml/pysideqmllistproperty_p.h13
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlmacros.h18
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlmetacallerror.cpp67
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlmetacallerror_p.h21
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlnamedelement.cpp74
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlnamedelement_p.h11
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlregistertype.cpp757
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlregistertype.h99
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlregistertype_p.h20
-rw-r--r--sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp70
-rw-r--r--sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h59
-rw-r--r--sources/pyside6/libpysideqml/pysideqmluncreatable.cpp118
-rw-r--r--sources/pyside6/libpysideqml/pysideqmluncreatable.h26
27 files changed, 2390 insertions, 0 deletions
diff --git a/sources/pyside6/libpysideqml/CMakeLists.txt b/sources/pyside6/libpysideqml/CMakeLists.txt
new file mode 100644
index 000000000..1af8c02cf
--- /dev/null
+++ b/sources/pyside6/libpysideqml/CMakeLists.txt
@@ -0,0 +1,115 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(libpysideqml_libraries Qt::Core Qt::CorePrivate Qt::Qml Qt::QmlPrivate)
+
+set(libpysideqml_HEADERS # installed below
+ pysideqmlattached.h
+ pysideqmlattached_p.h
+ pysideqmlextended_p.h
+ pysideqmlforeign_p.h
+ pysideqml.h
+ pysideqmllistproperty_p.h
+ pysideqmlmacros.h
+ pysideqmlmetacallerror_p.h
+ pysideqmlnamedelement_p.h
+ pysideqmlregistertype.h
+ pysideqmlregistertype_p.h
+ pysideqmltypeinfo_p.h
+ pysideqmluncreatable.h
+)
+
+set(libpysideqml_SRC
+ pysideqml.cpp
+ pysideqmlattached.cpp
+ pysideqmlforeign.cpp
+ pysideqmlextended.cpp
+ pysideqmlregistertype.cpp
+ pysideqmlmetacallerror.cpp
+ pysideqmllistproperty.cpp
+ pysideqmlnamedelement.cpp
+ pysideqmluncreatable.cpp
+ pysideqmltypeinfo.cpp
+ ${libpysideqml_HEADERS}
+)
+
+# Hack for // https://github.com/python/cpython/issues/86286 causes issues
+set_source_files_properties(
+ pysideqmlmetacallerror.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON
+)
+
+add_library(pyside6qml SHARED ${libpysideqml_SRC} ${other_files})
+add_library(PySide6::pyside6qml ALIAS pyside6qml)
+
+target_include_directories(pyside6qml PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:include/PySide6Qml>
+)
+
+target_compile_definitions(pyside6qml PRIVATE -DQT_LEAN_HEADERS=1 -DQT_NO_KEYWORDS=1)
+
+target_link_libraries(pyside6qml
+ PRIVATE PySide6::pyside6 Shiboken6::libshiboken ${libpysideqml_libraries})
+
+set_target_properties(pyside6qml PROPERTIES
+ VERSION ${BINDING_API_VERSION}
+ SOVERSION "${PYSIDE_SO_VERSION}"
+ OUTPUT_NAME "pyside6qml${pyside6_SUFFIX}${SHIBOKEN_PYTHON_SHARED_LIBRARY_SUFFIX}"
+ DEFINE_SYMBOL BUILD_LIBPYSIDEQML)
+
+target_compile_definitions(pyside6qml PRIVATE -DQT_LEAN_HEADERS=1)
+
+set_property(TARGET pyside6qml PROPERTY CXX_STANDARD 17)
+
+if(PYSIDE_QT_CONF_PREFIX)
+ set_property(SOURCE pysideqml.cpp
+ APPEND
+ PROPERTY COMPILE_DEFINITIONS
+ PYSIDE_QT_CONF_PREFIX=${PYSIDE_QT_CONF_PREFIX})
+endif()
+
+#
+# install stuff
+#
+
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(LIBRARY_OUTPUT_SUFFIX ${CMAKE_DEBUG_POSTFIX})
+else()
+ set(LIBRARY_OUTPUT_SUFFIX ${CMAKE_RELEASE_POSTFIX})
+endif()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_TO_ASCII")
+
+qfp_strip_library("pyside6qml")
+
+# Install-tree / relocatable package config file.
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/PySide6QmlConfig-spec.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6QmlConfig${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6Qml"
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/PySide6QmlConfig.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/PySide6QmlConfig.cmake" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/PySide6QmlConfigVersion.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/PySide6QmlConfigVersion.cmake" @ONLY)
+
+install(FILES ${libpysideqml_HEADERS}
+ DESTINATION include/${BINDING_NAME}${pyside6qml_SUFFIX})
+
+install(TARGETS pyside6qml EXPORT PySide6QmlTargets
+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+ ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
+ RUNTIME DESTINATION bin)
+install(EXPORT PySide6QmlTargets NAMESPACE PySide6Qml::
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6Qml")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/PySide6QmlConfig.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6Qml")
+
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6QmlConfig${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6Qml")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/PySide6QmlConfigVersion.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6Qml")
diff --git a/sources/pyside6/libpysideqml/PySide6QmlConfig-spec.cmake.in b/sources/pyside6/libpysideqml/PySide6QmlConfig-spec.cmake.in
new file mode 100644
index 000000000..36eb4123a
--- /dev/null
+++ b/sources/pyside6/libpysideqml/PySide6QmlConfig-spec.cmake.in
@@ -0,0 +1,7 @@
+@PACKAGE_INIT@
+
+# Import targets only when using an installed PySide6 config file (so not during a regular
+# PySide6 build, or during a super project build).
+if (NOT TARGET PySide6::pyside6qml)
+ include("${CMAKE_CURRENT_LIST_DIR}/PySide6QmlTargets.cmake")
+endif()
diff --git a/sources/pyside6/libpysideqml/PySide6QmlConfig.cmake.in b/sources/pyside6/libpysideqml/PySide6QmlConfig.cmake.in
new file mode 100644
index 000000000..dab0a6b13
--- /dev/null
+++ b/sources/pyside6/libpysideqml/PySide6QmlConfig.cmake.in
@@ -0,0 +1,5 @@
+if (NOT PYTHON_CONFIG_SUFFIX)
+ message(STATUS "PySide6QmlConfig: Using default python: @SHIBOKEN_PYTHON_CONFIG_SUFFIX@")
+ SET(PYTHON_CONFIG_SUFFIX @SHIBOKEN_PYTHON_CONFIG_SUFFIX@)
+endif()
+include(${CMAKE_CURRENT_LIST_DIR}/PySide6QmlConfig${PYTHON_CONFIG_SUFFIX}.cmake)
diff --git a/sources/pyside6/libpysideqml/PySide6QmlConfigVersion.cmake.in b/sources/pyside6/libpysideqml/PySide6QmlConfigVersion.cmake.in
new file mode 100644
index 000000000..f5073ce08
--- /dev/null
+++ b/sources/pyside6/libpysideqml/PySide6QmlConfigVersion.cmake.in
@@ -0,0 +1,10 @@
+set(PACKAGE_VERSION @BINDING_API_VERSION@)
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
diff --git a/sources/pyside6/libpysideqml/pysideqml.cpp b/sources/pyside6/libpysideqml/pysideqml.cpp
new file mode 100644
index 000000000..3fe673fdf
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqml.cpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqml.h"
+#include "pysideqmllistproperty_p.h"
+#include "pysideqmlattached_p.h"
+#include "pysideqmlextended_p.h"
+#include "pysideqmlforeign_p.h"
+#include "pysideqmlnamedelement_p.h"
+#include "pysideqmluncreatable.h"
+#include "pysideqmlmetacallerror_p.h"
+
+#include <QtQml/QQmlPropertyMap>
+#include <QtQml/QQmlComponent>
+
+#include <signalmanager.h>
+
+namespace PySide::Qml
+{
+
+void init(PyObject *module)
+{
+ initQtQmlListProperty(module);
+ initQmlAttached(module);
+ initQmlForeign(module);
+ initQmlExtended(module);
+ initQmlNamedElement(module);
+ initQmlUncreatable(module);
+ PySide::SignalManager::setQmlMetaCallErrorHandler(PySide::Qml::qmlMetaCallErrorHandler);
+
+ qRegisterMetaType<QQmlPropertyMap *>(); // PYSIDE-1845, QQmlPropertyMap * properties
+ qRegisterMetaType<QQmlComponent *>(); // PYSIDE-2415, QQmlComponent * properties
+}
+
+} //namespace PySide::Qml
diff --git a/sources/pyside6/libpysideqml/pysideqml.h b/sources/pyside6/libpysideqml/pysideqml.h
new file mode 100644
index 000000000..d975bcf97
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqml.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQML_H
+#define PYSIDEQML_H
+
+#include "pysideqmlmacros.h"
+
+#include <sbkpython.h>
+
+namespace PySide::Qml
+{
+
+PYSIDEQML_API void init(PyObject *module);
+
+} //namespace PySide::Qml
+
+#endif // PYSIDEQML_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlattached.cpp b/sources/pyside6/libpysideqml/pysideqmlattached.cpp
new file mode 100644
index 000000000..d484257e2
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlattached.cpp
@@ -0,0 +1,216 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#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 <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 std::shared_ptr<QmlTypeInfo> &info)
+{
+ PySide::Qml::QmlExtensionInfo result{nullptr, nullptr};
+ if (!info || 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..96f788268
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlattached.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLATTACHED_H
+#define PYSIDEQMLATTACHED_H
+
+#include <sbkpython.h>
+
+#include "pysideqmlmacros.h"
+
+#include <QtCore/qtconfigmacros.h>
+
+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..7c8a47fb8
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlattached_p.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLATTACHED_P_H
+#define PYSIDEQMLATTACHED_P_H
+
+#include <sbkpython.h>
+
+#include <memory>
+
+namespace PySide::Qml {
+struct QmlExtensionInfo;
+struct QmlTypeInfo;
+
+void initQmlAttached(PyObject *module);
+
+PySide::Qml::QmlExtensionInfo qmlAttachedInfo(PyTypeObject *t,
+ const std::shared_ptr<QmlTypeInfo> &info);
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLATTACHED_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlextended.cpp b/sources/pyside6/libpysideqml/pysideqmlextended.cpp
new file mode 100644
index 000000000..23543d589
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlextended.cpp
@@ -0,0 +1,145 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#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 <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 || 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 std::shared_ptr<QmlTypeInfo> &info)
+{
+ PySide::Qml::QmlExtensionInfo result{nullptr, nullptr};
+ if (info && 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..17d6dae64
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlextended_p.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLEXTENDED_P_H
+#define PYSIDEQMLEXTENDED_P_H
+
+#include <sbkpython.h>
+
+#include <memory>
+
+namespace PySide::Qml {
+struct QmlExtensionInfo;
+struct QmlTypeInfo;
+
+void initQmlExtended(PyObject *module);
+
+PySide::Qml::QmlExtensionInfo qmlExtendedInfo(PyObject *t,
+ const std::shared_ptr<QmlTypeInfo> &info);
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLEXTENDED_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlforeign.cpp b/sources/pyside6/libpysideqml/pysideqmlforeign.cpp
new file mode 100644
index 000000000..18d39d121
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlforeign.cpp
@@ -0,0 +1,92 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmlforeign_p.h"
+#include "pysideqmltypeinfo_p.h"
+
+#include <signalmanager.h>
+#include <pysideclassdecorator_p.h>
+
+#include <shiboken.h>
+#include <signature.h>
+#include <sbkstring.h>
+
+#include <QtCore/QDebug>
+
+// The QmlForeign decorator modifies QmlElement to create a different type
+// QmlElement.
+class PySideQmlForeignPrivate : 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 *PySideQmlForeignPrivate::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<PySideQmlForeignPrivate>(self);
+ const auto info = PySide::Qml::ensureQmlTypeInfo(klass);
+ info->foreignType = data->type();
+ // Insert an alias to be used by the factory functions of Decorators like
+ // @QmlExtended and @QmlAttached.
+ auto *foreignObj = reinterpret_cast<const PyObject *>(info->foreignType);
+ PySide::Qml::insertQmlTypeInfoAlias(foreignObj, info);
+
+ Py_INCREF(klass);
+ return klass;
+}
+
+const char *PySideQmlForeignPrivate::name() const
+{
+ return "QmlForeign";
+}
+
+extern "C" {
+
+static PyTypeObject *createPySideQmlForeignType(void)
+{
+ auto typeSlots =
+ PySide::ClassDecorator::Methods<PySideQmlForeignPrivate>::typeSlots();
+
+ PyType_Spec PySideQmlForeignType_spec = {
+ "2:PySide6.QtCore.qmlForeign",
+ sizeof(PySideClassDecorator),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeSlots.data()
+ };
+ return SbkType_FromSpec(&PySideQmlForeignType_spec);
+}
+
+PyTypeObject *PySideQmlForeign_TypeF(void)
+{
+ static auto *type = createPySideQmlForeignType();
+ return type;
+}
+
+} // extern "C"
+
+static const char *qmlForeign_SignatureStrings[] = {
+ "PySide6.QtQml.QmlForeign(self,type:type)",
+ nullptr // Sentinel
+};
+
+namespace PySide::Qml {
+
+void initQmlForeign(PyObject *module)
+{
+ if (InitSignatureStrings(PySideQmlForeign_TypeF(), qmlForeign_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideQmlForeign_TypeF());
+ PyModule_AddObject(module, "QmlForeign",
+ reinterpret_cast<PyObject *>(PySideQmlForeign_TypeF()));
+}
+
+} // namespace PySide::Qml
diff --git a/sources/pyside6/libpysideqml/pysideqmlforeign_p.h b/sources/pyside6/libpysideqml/pysideqmlforeign_p.h
new file mode 100644
index 000000000..85688aab0
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlforeign_p.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLFOREIGN_P_H
+#define PYSIDEQMLFOREIGN_P_H
+
+#include <sbkpython.h>
+
+namespace PySide::Qml {
+struct QmlExtensionInfo;
+struct QmlTypeInfo;
+
+void initQmlForeign(PyObject *module);
+
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLFOREIGN_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmllistproperty.cpp b/sources/pyside6/libpysideqml/pysideqmllistproperty.cpp
new file mode 100644
index 000000000..75bb5af96
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmllistproperty.cpp
@@ -0,0 +1,307 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmllistproperty_p.h"
+#include "pysideqmlregistertype_p.h"
+
+#include <shiboken.h>
+#include <pep384ext.h>
+#include <signature.h>
+
+#include <pysideproperty.h>
+#include <pysideproperty_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/QQmlListProperty>
+
+// This is the user data we store in the property.
+class QmlListPropertyPrivate : public PySidePropertyPrivate
+{
+public:
+ void metaCall(PyObject *source, QMetaObject::Call call, void **args) override;
+
+ PyTypeObject *type = nullptr;
+ PyObject *append = nullptr;
+ PyObject *count = nullptr;
+ PyObject *at = nullptr;
+ PyObject *clear = nullptr;
+ PyObject *replace = nullptr;
+ PyObject *removeLast = nullptr;
+};
+
+extern "C"
+{
+
+static PyObject *propList_tp_new(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+{
+ auto *me = PepExt_TypeCallAlloc<PySideProperty>(subtype, 0);
+ me->d = new QmlListPropertyPrivate;
+ return reinterpret_cast<PyObject *>(me);
+}
+
+static int propListTpInit(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {"type", "append", "count", "at", "clear",
+ "replace", "removeLast",
+ "doc", "notify", // PySideProperty
+ "designable", "scriptable", "stored",
+ "user", "constant", "final",
+ nullptr};
+ PySideProperty *pySelf = reinterpret_cast<PySideProperty *>(self);
+
+ auto *data = static_cast<QmlListPropertyPrivate *>(pySelf->d);
+
+ char *doc{};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O|OOOOOOsObbbbbb:QtQml.ListProperty",
+ const_cast<char **>(kwlist),
+ &data->type,
+ &data->append,
+ &data->count,
+ &data->at,
+ &data->clear,
+ &data->replace,
+ &data->removeLast,
+ /*s*/ &doc,
+ /*O*/ &(data->notify), // PySideProperty
+ /*bbb*/ &(data->designable),
+ &(data->scriptable),
+ &(data->stored),
+ /*bbb*/ &(data->user),
+ &(data->constant),
+ &(data->final))) {
+ return -1;
+ }
+
+ if (doc)
+ data->doc = doc;
+ else
+ data->doc.clear();
+
+ PyTypeObject *qobjectType = 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;
+ }
+
+ data->typeName = QByteArrayLiteral("QQmlListProperty<QObject>");
+
+ return 0;
+}
+
+static PyTypeObject *createPropertyListType()
+{
+ PyType_Slot PropertyListType_slots[] = {
+ {Py_tp_new, reinterpret_cast<void *>(propList_tp_new)},
+ {Py_tp_init, reinterpret_cast<void *>(propListTpInit)},
+ {0, nullptr}
+ };
+
+ PyType_Spec PropertyListType_spec = {
+ "2:PySide6.QtQml.ListProperty",
+ sizeof(PySideProperty),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PropertyListType_slots,
+ };
+
+ Shiboken::AutoDecRef bases(Py_BuildValue("(O)", PySideProperty_TypeF()));
+ return SbkType_FromSpecWithBases(&PropertyListType_spec, bases.object());
+}
+
+PyTypeObject *PropertyList_TypeF(void)
+{
+ // PYSIDE-2230: This was a wrong replacement by static AutoDecref.
+ // Never do that, deletes things way too late.
+ static PyTypeObject *type = createPropertyListType();
+ return type;
+}
+
+} // extern "C"
+
+// Implementation of QQmlListProperty<T>::AppendFunction callback
+void propListAppender(QQmlListProperty<QObject> *propList, QObject *item)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(2));
+ PyTypeObject *qobjectType = qObjectType();
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qobjectType, propList->object));
+ PyTuple_SET_ITEM(args, 1,
+ Shiboken::Conversions::pointerToPython(qobjectType, item));
+
+ auto *data = reinterpret_cast<QmlListPropertyPrivate *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->append, args));
+
+ if (PyErr_Occurred())
+ PyErr_Print();
+}
+
+// Implementation of QQmlListProperty<T>::CountFunction callback
+qsizetype propListCount(QQmlListProperty<QObject> *propList)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qObjectType(), propList->object));
+
+ auto *data = reinterpret_cast<QmlListPropertyPrivate *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->count, args));
+
+ // Check return type
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ return 0;
+ }
+
+ qsizetype cppResult = 0;
+ auto *converter = Shiboken::Conversions::PrimitiveTypeConverter<qsizetype>();
+ if (auto *pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(converter, retVal))
+ pythonToCpp(retVal, &cppResult);
+ return cppResult;
+}
+
+// Implementation of QQmlListProperty<T>::AtFunction callback
+QObject *propListAt(QQmlListProperty<QObject> *propList, qsizetype index)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(2));
+ PyTypeObject *qobjectType = qObjectType();
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qobjectType, propList->object));
+ auto *converter = Shiboken::Conversions::PrimitiveTypeConverter<qsizetype>();
+ PyTuple_SET_ITEM(args, 1,
+ Shiboken::Conversions::copyToPython(converter, &index));
+
+ auto *data = reinterpret_cast<QmlListPropertyPrivate *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->at, args));
+
+ QObject *result = 0;
+ if (PyErr_Occurred())
+ PyErr_Print();
+ else if (PyType_IsSubtype(Py_TYPE(retVal), data->type))
+ Shiboken::Conversions::pythonToCppPointer(qobjectType, retVal, &result);
+ return result;
+}
+
+// Implementation of QQmlListProperty<T>::ClearFunction callback
+void propListClear(QQmlListProperty<QObject> * propList)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTypeObject *qobjectType = qObjectType();
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qobjectType, propList->object));
+
+ auto *data = reinterpret_cast<QmlListPropertyPrivate *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->clear, args));
+
+ if (PyErr_Occurred())
+ PyErr_Print();
+}
+
+// Implementation of QQmlListProperty<T>::ReplaceFunction callback
+void propListReplace(QQmlListProperty<QObject> *propList, qsizetype index, QObject *value)
+{
+ Shiboken::GilState state;
+
+ Shiboken::AutoDecRef args(PyTuple_New(3));
+ PyTypeObject *qobjectType = qObjectType();
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qobjectType, propList->object));
+ auto *converter = Shiboken::Conversions::PrimitiveTypeConverter<qsizetype>();
+ PyTuple_SET_ITEM(args, 1,
+ Shiboken::Conversions::copyToPython(converter, &index));
+ PyTuple_SET_ITEM(args, 2,
+ Shiboken::Conversions::pointerToPython(qobjectType, value));
+
+ auto *data = reinterpret_cast<QmlListPropertyPrivate *>(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));
+ PyTypeObject *qobjectType = qObjectType();
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qobjectType, propList->object));
+
+ auto *data = reinterpret_cast<QmlListPropertyPrivate *>(propList->data);
+ Shiboken::AutoDecRef retVal(PyObject_CallObject(data->removeLast, args));
+
+ if (PyErr_Occurred())
+ PyErr_Print();
+}
+
+// qt_metacall specialization for ListProperties
+void QmlListPropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, void **args)
+{
+ if (call != QMetaObject::ReadProperty)
+ return;
+
+ QObject *qobj;
+ PyTypeObject *qobjectType = qObjectType();
+ Shiboken::Conversions::pythonToCppPointer(qobjectType, source, &qobj);
+ QQmlListProperty<QObject> declProp(
+ qobj, this,
+ append && append != Py_None ? &propListAppender : nullptr,
+ count && count != Py_None ? &propListCount : nullptr,
+ at && at != Py_None ? &propListAt : nullptr,
+ clear && clear != Py_None ? &propListClear : nullptr,
+ replace && replace != Py_None ? &propListReplace : nullptr,
+ removeLast && removeLast != Py_None ? &propListRemoveLast : nullptr);
+
+ // Copy the data to the memory location requested by the meta call
+ void *v = args[0];
+ *reinterpret_cast<QQmlListProperty<QObject> *>(v) = declProp;
+}
+
+static const char *PropertyList_SignatureStrings[] = {
+ "PySide6.QtQml.ListProperty(self,type:type,append:typing.Callable,"
+ "at:typing.Callable=None,clear:typing.Callable=None,count:typing.Callable=None)",
+ nullptr // Sentinel
+};
+
+namespace PySide::Qml {
+
+void initQtQmlListProperty(PyObject *module)
+{
+ // Export QmlListProperty type
+ if (InitSignatureStrings(PropertyList_TypeF(), PropertyList_SignatureStrings) < 0) {
+ PyErr_Print();
+ qWarning() << "Error initializing PropertyList type.";
+ return;
+ }
+
+ // Register QQmlListProperty metatype for use in QML
+ qRegisterMetaType<QQmlListProperty<QObject>>();
+
+ Py_INCREF(reinterpret_cast<PyObject *>(PropertyList_TypeF()));
+ PyModule_AddObject(module, PepType_GetNameStr(PropertyList_TypeF()),
+ reinterpret_cast<PyObject *>(PropertyList_TypeF()));
+}
+
+} // namespace PySide::Qml
diff --git a/sources/pyside6/libpysideqml/pysideqmllistproperty_p.h b/sources/pyside6/libpysideqml/pysideqmllistproperty_p.h
new file mode 100644
index 000000000..c00ffbf5b
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmllistproperty_p.h
@@ -0,0 +1,13 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLLISTPROPERTY_H
+#define PYSIDEQMLLISTPROPERTY_H
+
+#include <sbkpython.h>
+
+namespace PySide::Qml {
+void initQtQmlListProperty(PyObject *module);
+}
+
+#endif // PYSIDEQMLLISTPROPERTY_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlmacros.h b/sources/pyside6/libpysideqml/pysideqmlmacros.h
new file mode 100644
index 000000000..e9f24d269
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlmacros.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLMACROS_H
+#define PYSIDEQMLMACROS_H
+
+#include <shibokenmacros.h>
+
+#define PYSIDEQML_EXPORT LIBSHIBOKEN_EXPORT
+#define PYSIDEQML_IMPORT LIBSHIBOKEN_IMPORT
+
+#ifdef BUILD_LIBPYSIDEQML
+# define PYSIDEQML_API PYSIDEQML_EXPORT
+#else
+# define PYSIDEQML_API PYSIDEQML_IMPORT
+#endif
+
+#endif // PYSIDEQMLMACROS_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlmetacallerror.cpp b/sources/pyside6/libpysideqml/pysideqmlmetacallerror.cpp
new file mode 100644
index 000000000..63cefedb5
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlmetacallerror.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmlmetacallerror_p.h"
+
+#include <sbkpython.h>
+#include <sbkstring.h>
+#include <autodecref.h>
+
+// Remove deprecated MACRO of copysign for MSVC #86286
+// https://github.com/python/cpython/issues/86286
+#ifdef copysign
+# undef copysign
+#endif
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlListProperty>
+
+#if __has_include (<private/qv4engine_p.h>)
+# define QML_PRIVATE_API_SUPPORT
+# include <private/qv4engine_p.h>
+# include <private/qv4context_p.h>
+# include <private/qqmldata_p.h>
+#endif
+
+namespace PySide::Qml {
+
+std::optional<int> qmlMetaCallErrorHandler(QObject *object)
+{
+#ifdef QML_PRIVATE_API_SUPPORT
+ // This JS engine grabber based off of Qt 5.5's `qjsEngine` function
+ QQmlData *data = QQmlData::get(object, false);
+ if (!data || data->jsWrapper.isNullOrUndefined())
+ return {};
+
+ QV4::ExecutionEngine *engine = data->jsWrapper.engine();
+ if (engine->currentStackFrame == nullptr)
+ return {};
+
+ PyObject *errType, *errValue, *errTraceback;
+ PyErr_Fetch(&errType, &errValue, &errTraceback);
+ // PYSIDE-464: The error is only valid before PyErr_Restore,
+ // PYSIDE-464: therefore we take local copies.
+ Shiboken::AutoDecRef objStr(PyObject_Str(errValue));
+ const QString errString = QString::fromUtf8(Shiboken::String::toCString(objStr));
+ const bool isSyntaxError = errType == PyExc_SyntaxError;
+ const bool isTypeError = errType == PyExc_TypeError;
+ PyErr_Restore(errType, errValue, errTraceback);
+
+ PyErr_Print(); // Note: PyErr_Print clears the error.
+
+ if (isSyntaxError)
+ return engine->throwSyntaxError(errString);
+ if (isTypeError)
+ return engine->throwTypeError(errString);
+ return engine->throwError(errString);
+#else
+ Q_UNUSED(object);
+ qWarning("libpyside6qml was built without QML private API support, error handling will not work.");
+ return {};
+#endif // QML_PRIVATE_API_SUPPORT
+}
+
+} // namespace PySide::Qml
diff --git a/sources/pyside6/libpysideqml/pysideqmlmetacallerror_p.h b/sources/pyside6/libpysideqml/pysideqmlmetacallerror_p.h
new file mode 100644
index 000000000..fcbb6395d
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlmetacallerror_p.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLMETACALLERROR_P_H
+#define PYSIDEQMLMETACALLERROR_P_H
+
+#include <optional>
+
+#include <QtCore/qtclasshelpermacros.h>
+
+QT_FORWARD_DECLARE_CLASS(QObject)
+
+namespace PySide::Qml {
+
+// Helper for SignalManager::qt_metacall():
+// Bubbles Python exceptions up to the Javascript engine, if called from one
+std::optional<int> qmlMetaCallErrorHandler(QObject *object);
+
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLMETACALLERROR_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlnamedelement.cpp b/sources/pyside6/libpysideqml/pysideqmlnamedelement.cpp
new file mode 100644
index 000000000..faf3e4116
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlnamedelement.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmlnamedelement_p.h"
+#include <pysideclassdecorator_p.h>
+#include <pysideqmlregistertype_p.h>
+
+#include <shiboken.h>
+#include <signature.h>
+
+class PySideQmlNamedElementPrivate : public PySide::ClassDecorator::StringDecoratorPrivate
+{
+public:
+ PyObject *tp_call(PyObject *self, PyObject *args, PyObject * /* kw */) override;
+ const char *name() const override;
+};
+
+const char *PySideQmlNamedElementPrivate::name() const
+{
+ return "QmlNamedElement";
+}
+
+// The call operator is passed the class type and registers the type
+PyObject *PySideQmlNamedElementPrivate::tp_call(PyObject *self, PyObject *args, PyObject *)
+{
+ PyObject *klass = tp_call_check(args, CheckMode::WrappedType);
+ if (klass == nullptr)
+ return nullptr;
+
+ auto *data = DecoratorPrivate::get<PySideQmlNamedElementPrivate>(self);
+ auto *result = PySide::Qml::qmlNamedElementMacro(klass, data->string());
+ Py_XINCREF(result);
+ return result;
+}
+
+extern "C" {
+
+PyTypeObject *createPySideQmlNamedElementType(void)
+{
+ auto typeSlots =
+ PySide::ClassDecorator::Methods<PySideQmlNamedElementPrivate>::typeSlots();
+
+ PyType_Spec PySideQmlNamedElementType_spec = {
+ "2:PySide6.QtCore.qmlNamedElement",
+ sizeof(PySideClassDecorator),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeSlots.data()
+ };
+ return SbkType_FromSpec(&PySideQmlNamedElementType_spec);
+}
+
+PyTypeObject *PySideQmlNamedElement_TypeF(void)
+{
+ static auto *type = createPySideQmlNamedElementType();
+ return type;
+}
+
+} // extern "C"
+
+static const char *qmlNamedElement_SignatureStrings[] = {
+ "PySide6.QtQml.QmlNamedElement(self,reason:str)",
+ nullptr // Sentinel
+};
+
+void initQmlNamedElement(PyObject *module)
+{
+ if (InitSignatureStrings(PySideQmlNamedElement_TypeF(), qmlNamedElement_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideQmlNamedElement_TypeF());
+ PyModule_AddObject(module, "QmlNamedElement",
+ reinterpret_cast<PyObject *>(PySideQmlNamedElement_TypeF()));
+}
diff --git a/sources/pyside6/libpysideqml/pysideqmlnamedelement_p.h b/sources/pyside6/libpysideqml/pysideqmlnamedelement_p.h
new file mode 100644
index 000000000..4a4575de2
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlnamedelement_p.h
@@ -0,0 +1,11 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLNAMEDELEMENT_P_H
+#define PYSIDEQMLNAMEDELEMENT_P_H
+
+#include <sbkpython.h>
+
+void initQmlNamedElement(PyObject *module);
+
+#endif // PYSIDEQMLNAMEDELEMENT_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp
new file mode 100644
index 000000000..4ccd459d5
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp
@@ -0,0 +1,757 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmlregistertype.h"
+#include "pysideqmlregistertype_p.h"
+#include "pysideqmltypeinfo_p.h"
+#include "pysideqmlattached_p.h"
+#include "pysideqmlextended_p.h"
+#include "pysideqmluncreatable.h"
+
+#include <limits>
+#include <optional>
+
+// shiboken
+#include <shiboken.h>
+#include <sbkstring.h>
+
+// pyside
+#include <pyside.h>
+#include <pysideqobject.h>
+#include <pysideclassinfo.h>
+#include <pyside_p.h>
+
+#include <QtCore/QMutex>
+#include <QtCore/QTypeRevision>
+
+#include <QtQml/qqml.h>
+#include <QtQml/QJSValue>
+#include <QtQml/QQmlListProperty>
+#include <private/qqmlmetatype_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+
+#include <memory>
+
+using namespace Qt::StringLiterals;
+
+static PySide::Qml::QuickRegisterItemFunction quickRegisterItemFunction = nullptr;
+
+static const auto qmlElementKey = "QML.Element"_ba;
+
+static void createInto(void *memory, void *type)
+{
+ QMutexLocker locker(&PySide::nextQObjectMemoryAddrMutex());
+ PySide::setNextQObjectMemoryAddr(memory);
+ Shiboken::GilState state;
+ PyObject *obj = PyObject_CallObject(reinterpret_cast<PyObject *>(type), 0);
+ if (!obj || PyErr_Occurred())
+ PyErr_Print();
+ PySide::setNextQObjectMemoryAddr(nullptr);
+}
+
+PyTypeObject *qObjectType()
+{
+ static PyTypeObject *const result =
+ Shiboken::Conversions::getPythonTypeObject("QObject*");
+ assert(result);
+ return result;
+}
+
+static PyTypeObject *qQmlEngineType()
+{
+ static PyTypeObject *const result =
+ Shiboken::Conversions::getPythonTypeObject("QQmlEngine*");
+ assert(result);
+ return result;
+}
+
+static PyTypeObject *qQJSValueType()
+{
+ static PyTypeObject *const result =
+ Shiboken::Conversions::getPythonTypeObject("QJSValue*");
+ assert(result);
+ return result;
+}
+
+// Check if o inherits from baseClass
+static bool inheritsFrom(const QMetaObject *o, const char *baseClass)
+{
+ for (auto *base = o->superClass(); base ; base = base->superClass()) {
+ if (qstrcmp(base->className(), baseClass) == 0)
+ return true;
+ }
+ return false;
+}
+
+// Check if o inherits from QPyQmlPropertyValueSource.
+static inline bool isQmlPropertyValueSource(const QMetaObject *o)
+{
+ return inheritsFrom(o, "QPyQmlPropertyValueSource");
+}
+
+// Check if o inherits from QQmlParserStatus.
+static inline bool isQmlParserStatus(const QMetaObject *o)
+{
+ return inheritsFrom(o, "QPyQmlParserStatus");
+}
+
+static QByteArray getGlobalString(const char *name)
+{
+ PyObject *globalVar = PyDict_GetItemString(PyEval_GetGlobals(), name);
+
+ if (globalVar == nullptr || PyUnicode_Check(globalVar) == 0)
+ return {};
+
+ const char *stringValue = _PepUnicode_AsString(globalVar);
+ return stringValue != nullptr ? QByteArray(stringValue) : QByteArray{};
+}
+
+static int getGlobalInt(const char *name)
+{
+ PyObject *globalVar = PyDict_GetItemString(PyEval_GetGlobals(), name);
+
+ if (globalVar == nullptr || PyLong_Check(globalVar) == 0)
+ return -1;
+
+ long value = PyLong_AsLong(globalVar);
+
+ if (value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min())
+ return -1;
+
+ return value;
+}
+
+struct ImportData
+{
+ QByteArray importName;
+ int majorVersion = 0;
+ int minorVersion = 0;
+
+ QTypeRevision toTypeRevision() const;
+};
+
+QTypeRevision ImportData::toTypeRevision() const
+{
+ return QTypeRevision::fromVersion(majorVersion, minorVersion);
+}
+
+std::optional<ImportData> getGlobalImportData(const char *decoratorName)
+{
+ ImportData result{getGlobalString("QML_IMPORT_NAME"),
+ getGlobalInt("QML_IMPORT_MAJOR_VERSION"),
+ getGlobalInt("QML_IMPORT_MINOR_VERSION")};
+
+ if (result.importName.isEmpty()) {
+ PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_NAME in order to use %s.",
+ decoratorName);
+ return {};
+ }
+
+ if (result.majorVersion == -1) {
+ PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_MAJOR_VERSION in order to use %s.",
+ decoratorName);
+ return {};
+ }
+
+ // Specifying a minor version is optional
+ if (result.minorVersion == -1)
+ result.minorVersion = 0;
+ return result;
+}
+
+static PyTypeObject *checkTypeObject(PyObject *pyObj, const char *what)
+{
+ if (PyType_Check(pyObj) == 0) {
+ PyErr_Format(PyExc_TypeError, "%s can only be used for classes.", what);
+ return nullptr;
+ }
+ return reinterpret_cast<PyTypeObject *>(pyObj);
+}
+
+static bool setClassInfo(PyTypeObject *type, const QByteArray &key, const QByteArray &value)
+{
+ if (!PySide::ClassInfo::setClassInfo(type, key, value)) {
+ PyErr_Format(PyExc_TypeError, "Setting class info \"%s\" to \"%s\" on \"%s\" failed.",
+ key.constData(), value.constData(), type->tp_name);
+ return false;
+ }
+ return true;
+}
+
+static inline bool setSingletonClassInfo(PyTypeObject *type)
+{
+ return setClassInfo(type, "QML.Singleton"_ba, "true"_ba);
+}
+
+static QQmlCustomParser *defaultCustomParserFactory()
+{
+ return nullptr;
+}
+
+namespace PySide::Qml {
+
+// Modern (6.7) type registration using RegisterTypeAndRevisions
+// and information set to QMetaClassInfo.
+static int qmlRegisterType(PyObject *pyObj,
+ const ImportData &importData,
+ const QMetaObject *metaObject,
+ const QMetaObject *classInfoMetaObject = nullptr)
+{
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+
+ if (classInfoMetaObject == nullptr)
+ classInfoMetaObject = metaObject;
+
+ // Register as simple QObject rather than Qt Quick item.
+ // Incref the type object, don't worry about decref'ing it because
+ // there's no way to unregister a QML type.
+ Py_INCREF(pyObj);
+
+ const QByteArray typeName(pyObjType->tp_name);
+ QByteArray ptrType = typeName + '*';
+ QByteArray listType = QByteArrayLiteral("QQmlListProperty<") + typeName + '>';
+ const auto typeId = QMetaType(new QQmlMetaTypeInterface(ptrType));
+ const auto listId = QMetaType(new QQmlListMetaTypeInterface(listType, typeId.iface()));
+ const int objectSize = static_cast<int>(PySide::getSizeOfQObject(reinterpret_cast<PyTypeObject *>(pyObj)));
+
+ const auto typeInfo = qmlTypeInfo(pyObj);
+ const auto attachedInfo = qmlAttachedInfo(pyObjType, typeInfo);
+ const auto extendedInfo = qmlExtendedInfo(pyObj, typeInfo);
+
+ QList<int> ids;
+ QQmlPrivate::RegisterTypeAndRevisions type {
+ QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
+ typeId, listId, objectSize,
+ createInto, // create
+ pyObj, // userdata
+ nullptr, // createValueType (Remove in Qt 7)
+ importData.importName.constData(),
+ importData.toTypeRevision(), // version
+ metaObject,
+ classInfoMetaObject,
+ attachedInfo.factory, // attachedPropertiesFunction
+ attachedInfo.metaObject, // attachedPropertiesMetaObject
+ 0, 0, 0, // parserStatusCast, valueSourceCast, valueInterceptorCast
+ extendedInfo.factory, // extensionObjectCreate
+ extendedInfo.metaObject, // extensionMetaObject
+ defaultCustomParserFactory, // customParser
+ &ids, // qmlTypeIds
+ 0, // finalizerCast
+ false, // forceAnonymous
+ {} // listMetaSequence
+ };
+
+ // Allow registering Qt Quick items.
+ const bool isQuickType = quickRegisterItemFunction && quickRegisterItemFunction(pyObj, &type);
+
+ if (!isQuickType) { // values filled by the Quick registration
+ // QPyQmlParserStatus inherits QObject, QQmlParserStatus, so,
+ // it is found behind the QObject.
+ type.parserStatusCast = isQmlParserStatus(metaObject)
+ ? int(sizeof(QObject))
+ : QQmlPrivate::StaticCastSelector<QObject, QQmlParserStatus>::cast();
+ // Similar for QPyQmlPropertyValueSource
+ type.valueSourceCast = isQmlPropertyValueSource(metaObject)
+ ? int(sizeof(QObject))
+ : QQmlPrivate::StaticCastSelector<QObject, QQmlPropertyValueSource>::cast();
+ type.valueInterceptorCast =
+ QQmlPrivate::StaticCastSelector<QObject, QQmlPropertyValueInterceptor>::cast();
+ }
+
+ QQmlPrivate::qmlregister(QQmlPrivate::TypeAndRevisionsRegistration, &type);
+ const int qmlTypeId = ids.value(0, -1);
+ if (qmlTypeId == -1) {
+ PyErr_Format(PyExc_TypeError, "QML meta type registration of \"%s\" failed.",
+ typeName.constData());
+ }
+ return qmlTypeId;
+}
+
+static int qmlRegisterType(PyObject *pyObj, PyObject *pyClassInfoObj,
+ const ImportData &importData)
+{
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+ if (!isQObjectDerived(pyObjType, true))
+ return -1;
+
+ const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
+ Q_ASSERT(metaObject);
+ const QMetaObject *classInfoMetaObject = pyObj == pyClassInfoObj
+ ? metaObject : PySide::retrieveMetaObject(pyClassInfoObj);
+ return qmlRegisterType(pyObj, importData, metaObject, classInfoMetaObject);
+}
+
+// Legacy (pre 6.7) compatibility helper for the free register functions.
+int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, const char *noCreationReason,
+ bool creatable)
+{
+ auto *type = checkTypeObject(pyObj, "qmlRegisterType()");
+ if (type == nullptr || !PySide::isQObjectDerived(type, true))
+ return -1;
+
+ const QMetaObject *metaObject = PySide::retrieveMetaObject(type);
+ Q_ASSERT(metaObject);
+
+ // PYSIDE-2709: Use a separate QMetaObject for the class information
+ // as modifying metaObject breaks inheritance.
+ QMetaObjectBuilder classInfobuilder(&QObject::staticMetaObject);
+ classInfobuilder.addClassInfo(qmlElementKey, qmlName);
+ if (!creatable)
+ setUncreatableClassInfo(&classInfobuilder, noCreationReason);
+ auto *classInfoMetaObject = classInfobuilder.toMetaObject();
+
+ const int qmlTypeId = qmlRegisterType(pyObj, {uri, versionMajor, versionMinor},
+ metaObject, classInfoMetaObject);
+ free(classInfoMetaObject);
+ return qmlTypeId;
+}
+
+// Singleton helpers
+
+// Check the arguments of a singleton callback (C++: "QJSValue cb(QQmlEngine *, QJSEngine *)",
+// but we drop the QJSEngine since it will be the same as QQmlEngine when the latter exists.
+static bool checkSingletonCallback(PyObject *callback)
+{
+ if (callback == nullptr) {
+ PyErr_SetString(PyExc_TypeError, "No callback specified.");
+ return false;
+ }
+ if (PyCallable_Check(callback) == 0) {
+ PyErr_Format(PyExc_TypeError, "Invalid callback specified (%S).", callback);
+ return false;
+ }
+ Shiboken::AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__"));
+ if (funcCode.isNull()) {
+ PyErr_Format(PyExc_TypeError, "Cannot retrieve code of callback (%S).", callback);
+ return false;
+ }
+ Shiboken::AutoDecRef argCountAttr(PyObject_GetAttrString(funcCode, "co_argcount"));
+ const int argCount = PyLong_AsLong(argCountAttr.object());
+ if (argCount != 1) {
+ PyErr_Format(PyExc_TypeError, "Callback (%S) has %d parameter(s), expected one.",
+ callback, argCount);
+ return false;
+ }
+
+ return true;
+}
+
+// Shared data of a singleton creation callback which dereferences an object on
+// destruction.
+class SingletonQObjectCreationSharedData
+{
+public:
+ Q_DISABLE_COPY_MOVE(SingletonQObjectCreationSharedData)
+
+ SingletonQObjectCreationSharedData(PyObject *cb, PyObject *ref = nullptr) noexcept :
+ callable(cb), reference(ref)
+ {
+ Py_XINCREF(ref);
+ }
+
+ // FIXME: Currently, the QML registration data are in global static variables
+ // and thus cleaned up after Python terminates. Once they are cleaned up
+ // by the QML engine, the code can be activated for proper cleanup of the references.
+ ~SingletonQObjectCreationSharedData()
+#if 0 //
+ ~SingletonQObjectCreationSharedData()
+ {
+ if (reference != nullptr) {
+ Shiboken::GilState gil;
+ Py_DECREF(reference);
+ }
+ }
+#else
+ = default;
+#endif
+
+ PyObject *callable{}; // Callback, static method or type object to be invoked.
+ PyObject *reference{}; // Object to dereference when going out scope
+};
+
+// Base class for QML singleton creation callbacks with helper for error checking.
+class SingletonQObjectCreationBase
+{
+protected:
+ explicit SingletonQObjectCreationBase(PyObject *cb, PyObject *ref = nullptr) :
+ m_data(std::make_shared<SingletonQObjectCreationSharedData>(cb, ref))
+ {
+ }
+
+ static QObject *handleReturnValue(PyObject *retVal);
+
+ std::shared_ptr<SingletonQObjectCreationSharedData> data() const { return m_data; }
+
+private:
+ std::shared_ptr<SingletonQObjectCreationSharedData> m_data;
+};
+
+QObject *SingletonQObjectCreationBase::handleReturnValue(PyObject *retVal)
+{
+ using Shiboken::Conversions::isPythonToCppPointerConvertible;
+ // Make sure the callback returns something we can convert, else the entire application will crash.
+ if (retVal == nullptr) {
+ PyErr_Format(PyExc_TypeError, "Callback returns 0 value.");
+ return nullptr;
+ }
+ if (isPythonToCppPointerConvertible(qObjectType(), retVal) == nullptr) {
+ PyErr_Format(PyExc_TypeError, "Callback returns invalid value (%S).", retVal);
+ return nullptr;
+ }
+
+ QObject *obj = nullptr;
+ Shiboken::Conversions::pythonToCppPointer(qObjectType(), retVal, &obj);
+ return obj;
+}
+
+// QML singleton creation callback by invoking a type object
+class SingletonQObjectFromTypeCreation : public SingletonQObjectCreationBase
+{
+public:
+ explicit SingletonQObjectFromTypeCreation(PyObject *typeObj) :
+ SingletonQObjectCreationBase(typeObj, typeObj) {}
+
+ QObject *operator ()(QQmlEngine *, QJSEngine *) const
+ {
+ Shiboken::GilState gil;
+ Shiboken::AutoDecRef args(PyTuple_New(0));
+ PyObject *retVal = PyObject_CallObject(data()->callable, args);
+ QObject *result = handleReturnValue(retVal);
+ if (result == nullptr)
+ Py_XDECREF(retVal);
+ return result;
+ }
+};
+
+// QML singleton creation by invoking a callback, passing QQmlEngine. Keeps a
+// references to the the callback.
+class SingletonQObjectCallbackCreation : public SingletonQObjectCreationBase
+{
+public:
+ explicit SingletonQObjectCallbackCreation(PyObject *callback) :
+ SingletonQObjectCreationBase(callback, callback) {}
+ explicit SingletonQObjectCallbackCreation(PyObject *callback, PyObject *ref) :
+ SingletonQObjectCreationBase(callback, ref) {}
+
+ QObject *operator ()(QQmlEngine *engine, QJSEngine *) const
+ {
+ Shiboken::GilState gil;
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTuple_SET_ITEM(args, 0,
+ Shiboken::Conversions::pointerToPython(qQmlEngineType(), engine));
+ PyObject *retVal = PyObject_CallObject(data()->callable, args);
+ QObject *result = handleReturnValue(retVal);
+ if (result == nullptr)
+ Py_XDECREF(retVal);
+ return result;
+ }
+};
+
+using SingletonQObjectCreation = std::function<QObject*(QQmlEngine *, QJSEngine *)>;
+
+// Modern (6.7) singleton type registration using RegisterSingletonTypeAndRevisions
+// and information set to QMetaClassInfo (QObject only pending QTBUG-110467).
+static int qmlRegisterSingletonTypeV2(PyObject *pyObj, PyObject *pyClassInfoObj,
+ const ImportData &importData,
+ const SingletonQObjectCreation &callback)
+{
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+ if (!isQObjectDerived(pyObjType, true))
+ return -1;
+
+ const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
+ Q_ASSERT(metaObject);
+ const QMetaObject *classInfoMetaObject = pyObj == pyClassInfoObj
+ ? metaObject : PySide::retrieveMetaObject(pyClassInfoObj);
+
+ QList<int> ids;
+ QQmlPrivate::RegisterSingletonTypeAndRevisions type {
+ QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
+ importData.importName.constData(),
+ importData.toTypeRevision(), // version
+ callback, // qObjectApi,
+ metaObject,
+ classInfoMetaObject,
+ QMetaType(QMetaType::QObjectStar), // typeId
+ nullptr, // extensionMetaObject
+ nullptr, // extensionObjectCreate
+ &ids
+ };
+
+ QQmlPrivate::qmlregister(QQmlPrivate::SingletonAndRevisionsRegistration, &type);
+ const int qmlTypeId = ids.value(0, -1);
+ if (qmlTypeId == -1) {
+ PyErr_Format(PyExc_TypeError, "Singleton QML meta type registration of \"%s\" failed.",
+ pyObjType->tp_name);
+ }
+ return qmlTypeId;
+}
+
+// Legacy (pre 6.7) singleton type registration using RegisterSingletonType
+// for QObject and value types. Still used by qmlRegisterSingletonType()
+// for the hypothetical case of a value type.
+static int qmlRegisterSingletonType(PyObject *pyObj, const ImportData &importData,
+ const char *qmlName, PyObject *callback,
+ bool isQObject, bool hasCallback)
+{
+ if (hasCallback && !checkSingletonCallback(callback))
+ return -1;
+
+ const QMetaObject *metaObject = nullptr;
+
+ if (isQObject) {
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+
+ if (!isQObjectDerived(pyObjType, true))
+ return -1;
+
+ metaObject = PySide::retrieveMetaObject(pyObjType);
+ Q_ASSERT(metaObject);
+ }
+
+ QQmlPrivate::RegisterSingletonType type {
+ QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
+ importData.importName.constData(),
+ importData.toTypeRevision(), // version
+ qmlName, // typeName
+ {}, // scriptApi
+ {}, // qObjectApi
+ metaObject, // instanceMetaObject
+ {}, // typeId
+ nullptr, // extensionMetaObject
+ nullptr, // extensionObjectCreate
+ {} // revision
+ };
+
+ if (isQObject) {
+ // FIXME: Fix this to assign new type ids each time.
+ type.typeId = QMetaType(QMetaType::QObjectStar);
+
+ if (hasCallback)
+ type.qObjectApi = SingletonQObjectCallbackCreation(callback);
+ else
+ type.qObjectApi = SingletonQObjectFromTypeCreation(pyObj);
+ } else {
+ type.scriptApi =
+ [callback](QQmlEngine *engine, QJSEngine *) -> QJSValue {
+ using namespace Shiboken;
+
+ Shiboken::GilState gil;
+ AutoDecRef args(PyTuple_New(1));
+
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ qQmlEngineType(), engine));
+
+ AutoDecRef retVal(PyObject_CallObject(callback, args));
+
+ PyTypeObject *qjsvalueType = qQJSValueType();
+
+ // 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);
+}
+
+// Legacy (pre 6.7) compatibility helper for the free register functions.
+int qmlRegisterSingletonType(PyObject *pyObj,const char *uri,
+ int versionMajor, int versionMinor, const char *qmlName,
+ PyObject *callback, bool isQObject, bool hasCallback)
+{
+ return qmlRegisterSingletonType(pyObj, {uri, versionMajor, versionMinor}, qmlName,
+ callback, isQObject, hasCallback);
+}
+
+// Modern (6.7) singleton instance registration using RegisterSingletonTypeAndRevisions
+// and information set to QMetaClassInfo (QObject only).
+static int qmlRegisterSingletonInstance(PyObject *pyObj, const ImportData &importData,
+ PyObject *instanceObject)
+{
+ using namespace Shiboken;
+
+ // Check if the Python Type inherit from QObject
+ PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+
+ if (!isQObjectDerived(pyObjType, true))
+ return -1;
+
+ // Convert the instanceObject (PyObject) into a QObject
+ QObject *instanceQObject = PySide::convertToQObject(instanceObject, true);
+ if (instanceQObject == nullptr)
+ return -1;
+
+ // Create Singleton Functor to pass the QObject to the Type registration step
+ // similarly to the case when we have a callback
+ QQmlPrivate::SingletonInstanceFunctor registrationFunctor;
+ registrationFunctor.m_object = instanceQObject;
+
+ const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
+ Q_ASSERT(metaObject);
+
+ QList<int> ids;
+ QQmlPrivate::RegisterSingletonTypeAndRevisions type {
+ QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
+ importData.importName.constData(),
+ importData.toTypeRevision(), // version
+ registrationFunctor, // qObjectApi,
+ metaObject,
+ metaObject, // classInfoMetaObject
+ QMetaType(QMetaType::QObjectStar), // typeId
+ nullptr, // extensionMetaObject
+ nullptr, // extensionObjectCreate
+ &ids
+ };
+
+ QQmlPrivate::qmlregister(QQmlPrivate::SingletonAndRevisionsRegistration, &type);
+ return ids.value(0, -1);
+}
+
+// Legacy (pre 6.7) compatibility helper for the free register functions.
+int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName,
+ PyObject *instanceObject)
+{
+ auto *type = checkTypeObject(pyObj, "qmlRegisterSingletonInstance()");
+ if (type == nullptr || !setClassInfo(type, qmlElementKey, qmlName)
+ || !setSingletonClassInfo(type)) {
+ return -1;
+ }
+ return qmlRegisterSingletonInstance(pyObj, {uri, versionMajor, versionMinor},
+ instanceObject);
+}
+
+} // namespace PySide::Qml
+
+enum class RegisterMode {
+ Normal,
+ Singleton
+};
+
+namespace PySide::Qml {
+
+// Check for a static create() method on a decorated singleton.
+// Might set a Python error if the check fails.
+static std::optional<SingletonQObjectCreation>
+ singletonCreateMethod(PyTypeObject *pyObjType)
+{
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(pyObjType));
+ auto *create = PyDict_GetItemString(tpDict.object(), "create");
+ // Method decorated by "@staticmethod"
+ if (create == nullptr || std::strcmp(Py_TYPE(create)->tp_name, "staticmethod") != 0)
+ return std::nullopt;
+ // 3.10: "__wrapped__"
+ Shiboken::AutoDecRef function(PyObject_GetAttrString(create, "__func__"));
+ if (function.isNull()) {
+ PyErr_Format(PyExc_TypeError, "Cannot retrieve function of callback (%S).",
+ create);
+ return std::nullopt;
+ }
+ if (!checkSingletonCallback(function.object()))
+ return std::nullopt;
+ // Reference to the type needs to be kept.
+ return SingletonQObjectCallbackCreation(function.object(),
+ reinterpret_cast<PyObject *>(pyObjType));
+}
+
+PyObject *qmlElementMacro(PyObject *pyObj, const char *decoratorName,
+ const QByteArray &typeName)
+{
+ auto *pyObjType = checkTypeObject(pyObj, decoratorName);
+ if (pyObjType == nullptr)
+ return nullptr;
+
+ if (!PySide::isQObjectDerived(pyObjType, false)) {
+ PyErr_Format(PyExc_TypeError,
+ "%s can only be used with classes inherited from QObject, got %s.",
+ decoratorName, pyObjType->tp_name);
+ return nullptr;
+ }
+
+ if (!setClassInfo(pyObjType, qmlElementKey, typeName))
+ return nullptr;
+
+ RegisterMode mode = RegisterMode::Normal;
+ const auto info = PySide::Qml::qmlTypeInfo(pyObj);
+ auto *registerObject = pyObj;
+ if (info) {
+ if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Singleton)) {
+ mode = RegisterMode::Singleton;
+ setSingletonClassInfo(pyObjType);
+ }
+ if (info->foreignType)
+ registerObject = reinterpret_cast<PyObject *>(info->foreignType);
+ }
+
+ const auto importDataO = getGlobalImportData(decoratorName);
+ if (!importDataO.has_value())
+ return nullptr;
+ const auto importData = importDataO.value();
+
+ int result{};
+ if (mode == RegisterMode::Singleton) {
+ auto singletonCreateMethodO = singletonCreateMethod(pyObjType);
+ if (!singletonCreateMethodO.has_value()) {
+ if (PyErr_Occurred() != nullptr)
+ return nullptr;
+ singletonCreateMethodO = SingletonQObjectFromTypeCreation(pyObj);
+ }
+ result = PySide::Qml::qmlRegisterSingletonTypeV2(registerObject, pyObj, importData,
+ singletonCreateMethodO.value());
+ } else {
+ result = PySide::Qml::qmlRegisterType(registerObject, pyObj, importData);
+ }
+ if (result == -1) {
+ PyErr_Format(PyExc_TypeError, "%s: Failed to register type %s.",
+ decoratorName, pyObjType->tp_name);
+ return nullptr;
+ }
+
+ return pyObj;
+}
+
+PyObject *qmlElementMacro(PyObject *pyObj)
+{
+ return qmlElementMacro(pyObj, "QmlElement", "auto"_ba);
+}
+
+PyObject *qmlNamedElementMacro(PyObject *pyObj, const QByteArray &typeName)
+{
+ return qmlElementMacro(pyObj, "QmlNamedElement", typeName);
+}
+
+PyObject *qmlAnonymousMacro(PyObject *pyObj)
+{
+ return qmlElementMacro(pyObj, "QmlAnonymous", "anonymous"_ba);
+}
+
+PyObject *qmlSingletonMacro(PyObject *pyObj)
+{
+ PySide::Qml::ensureQmlTypeInfo(pyObj)->flags.setFlag(PySide::Qml::QmlTypeFlag::Singleton);
+ Py_INCREF(pyObj);
+ return pyObj;
+}
+
+QuickRegisterItemFunction getQuickRegisterItemFunction()
+{
+ return quickRegisterItemFunction;
+}
+
+void setQuickRegisterItemFunction(QuickRegisterItemFunction function)
+{
+ quickRegisterItemFunction = function;
+}
+
+} // namespace PySide::Qml
diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.h b/sources/pyside6/libpysideqml/pysideqmlregistertype.h
new file mode 100644
index 000000000..859172322
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlregistertype.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLREGISTERTYPE_H
+#define PYSIDEQMLREGISTERTYPE_H
+
+#include "pysideqmlmacros.h"
+
+#include <sbkpython.h>
+#include <QtCore/qtconfigmacros.h>
+
+QT_BEGIN_NAMESPACE
+namespace QQmlPrivate
+{
+struct RegisterTypeAndRevisions;
+}
+QT_END_NAMESPACE
+
+namespace PySide::Qml
+{
+
+/**
+ * PySide implementation of qmlRegisterType<T> function.
+ *
+ * This is a helper for the legacy free qmlRegisterType*() type functions.
+ * Decorators should be used instead.
+ *
+ * \param pyObj Python type to be registered.
+ * \param uri QML element uri.
+ * \param versionMajor QML component major version.
+ * \param versionMinor QML component minor version.
+ * \param qmlName QML element name
+ * \return the metatype id of the registered type.
+ */
+PYSIDEQML_API int qmlRegisterType(PyObject *pyObj, const char *uri,
+ int versionMajor, int versionMinor,
+ const char *qmlName, const char *noCreationReason = nullptr,
+ bool creatable = true);
+
+/**
+ * PySide implementation of qmlRegisterSingletonType<T> function.
+ *
+ * This is a helper for the legacy free qmlRegisterSingletonType<T> type function.
+ * Decorators should be used instead.
+ *
+ * \param pyObj Python type to be registered.
+ * \param uri QML element uri.
+ * \param versionMajor QML component major version.
+ * \param versionMinor QML component minor version.
+ * \param qmlName QML element name
+ * \param callback Registration callback
+ * \return the metatype id of the registered type.
+ */
+PYSIDEQML_API int qmlRegisterSingletonType(PyObject *pyObj,const char *uri,
+ int versionMajor, int versionMinor, const char *qmlName,
+ PyObject *callback, bool isQObject, bool hasCallback);
+
+/**
+ * PySide implementation of qmlRegisterSingletonInstance<T> function.
+ *
+ * \param pyObj Python type to be registered.
+ * \param uri QML element uri.
+ * \param versionMajor QML component major version.
+ * \param versionMinor QML component minor version.
+ * \param qmlName QML element name
+ * \param instanceObject singleton object to be registered.
+ * \return the metatype id of the registered type.
+ */
+PYSIDEQML_API int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri,
+ int versionMajor, int versionMinor,
+ const char *qmlName, PyObject *instanceObject);
+
+/**
+ * PySide implementation of the QML_ELEMENT macro
+ *
+ * \param pyObj Python type to be registered
+ */
+PYSIDEQML_API PyObject *qmlElementMacro(PyObject *pyObj);
+
+/// PySide implementation of the QML_ANONYMOUS macro
+/// \param pyObj Python type to be registered
+PYSIDEQML_API PyObject *qmlAnonymousMacro(PyObject *pyObj);
+
+/// PySide implementation of the QML_SINGLETON macro
+/// \param pyObj Python type to be registered
+PYSIDEQML_API PyObject *qmlSingletonMacro(PyObject *pyObj);
+
+
+// Used by QtQuick module to fill the QQmlPrivate::RegisterType::parserStatusCast,
+// valueSourceCast and valueInterceptorCast fields with the correct values.
+using QuickRegisterItemFunction =
+ bool (*)(PyObject *pyObj, QT_PREPEND_NAMESPACE(QQmlPrivate::RegisterTypeAndRevisions) *);
+
+PYSIDEQML_API QuickRegisterItemFunction getQuickRegisterItemFunction();
+PYSIDEQML_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function);
+
+} // namespace PySide::Qml
+
+#endif // PYSIDEQMLREGISTERTYPE_H
diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype_p.h b/sources/pyside6/libpysideqml/pysideqmlregistertype_p.h
new file mode 100644
index 000000000..f11f92241
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmlregistertype_p.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLREGISTERTYPE_P_H
+#define PYSIDEQMLREGISTERTYPE_P_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QByteArray>
+
+PyTypeObject *qObjectType();
+
+
+namespace PySide::Qml {
+
+PyObject *qmlNamedElementMacro(PyObject *pyObj, const QByteArray &typeName);
+
+}
+
+#endif // PYSIDEQMLREGISTERTYPE_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp
new file mode 100644
index 000000000..f369f7400
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmltypeinfo_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+
+#include <algorithm>
+
+namespace PySide::Qml {
+
+using QmlTypeInfoHash = QHash<const PyObject *, QmlTypeInfoPtr>;
+
+Q_GLOBAL_STATIC(QmlTypeInfoHash, qmlTypeInfoHashStatic);
+
+QmlTypeInfoPtr ensureQmlTypeInfo(const PyObject *o)
+{
+ auto *hash = qmlTypeInfoHashStatic();
+ auto it = hash->find(o);
+ if (it == hash->end())
+ it = hash->insert(o, std::make_shared<QmlTypeInfo>());
+ return it.value();
+}
+
+void insertQmlTypeInfoAlias(const PyObject *o, const QmlTypeInfoPtr &value)
+{
+ qmlTypeInfoHashStatic()->insert(o, value);
+}
+
+QmlTypeInfoPtr qmlTypeInfo(const PyObject *o)
+{
+ auto *hash = qmlTypeInfoHashStatic();
+ auto it = hash->constFind(o);
+ return it != hash->cend() ? it.value() : QmlTypeInfoPtr{};
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QmlTypeInfo &i)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "QmlTypeInfo(" << i.flags;
+ 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 << ')';
+ 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
new file mode 100644
index 000000000..112e127a7
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLTYPEINFO_P_H
+#define PYSIDEQMLTYPEINFO_P_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QFlags>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QObject)
+QT_FORWARD_DECLARE_STRUCT(QMetaObject)
+
+namespace PySide::Qml {
+
+enum class QmlTypeFlag
+{
+ Singleton = 0x1
+};
+
+Q_DECLARE_FLAGS(QmlTypeFlags, QmlTypeFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QmlTypeFlags)
+
+// Type information associated with QML type objects
+struct QmlTypeInfo
+{
+ QmlTypeFlags flags;
+ PyTypeObject *foreignType = nullptr;
+ PyTypeObject *attachedType = nullptr;
+ PyTypeObject *extensionType = nullptr;
+};
+
+using QmlTypeInfoPtr = std::shared_ptr<QmlTypeInfo>;
+
+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
+
+#endif // PYSIDEQMLTYPEINFO_P_H
diff --git a/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp b/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp
new file mode 100644
index 000000000..7c0f6b8ff
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp
@@ -0,0 +1,118 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "pysideqmluncreatable.h"
+#include <pysideclassdecorator_p.h>
+#include <pysideclassinfo.h>
+
+#include <shiboken.h>
+#include <signature.h>
+#include <sbkcppstring.h>
+
+#include <QtCore/qbytearray.h>
+#include <private/qmetaobjectbuilder_p.h>
+
+using namespace Qt::StringLiterals;
+
+class PySideQmlUncreatablePrivate : public PySide::ClassDecorator::StringDecoratorPrivate
+{
+public:
+ PyObject *tp_call(PyObject *self, PyObject *args, PyObject * /* kw */) override;
+ int tp_init(PyObject *self, PyObject *args, PyObject *kwds) override;
+ const char *name() const override;
+};
+
+const char *PySideQmlUncreatablePrivate::name() const
+{
+ return "QmlUncreatable";
+}
+
+// The call operator is passed the class type and registers the reason
+// in the uncreatableReasonMap()
+PyObject *PySideQmlUncreatablePrivate::tp_call(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ PyObject *klass = tp_call_check(args, CheckMode::WrappedType);
+ if (klass== nullptr)
+ return nullptr;
+
+ auto *type = reinterpret_cast<PyTypeObject *>(klass);
+ auto *data = DecoratorPrivate::get<PySideQmlUncreatablePrivate>(self);
+ setUncreatableClassInfo(type, data->string());
+
+ Py_INCREF(klass);
+ return klass;
+}
+
+int PySideQmlUncreatablePrivate::tp_init(PyObject *self, PyObject *args, PyObject * /* kwds */)
+{
+ int result = -1;
+ const auto argsCount = PyTuple_Size(args);
+ if (argsCount == 0) {
+ result = 0; // QML-generated reason
+ } else if (argsCount == 1) {
+ PyObject *arg = PyTuple_GET_ITEM(args, 0);
+ result = arg == Py_None
+ ? 0 // QML-generated reason
+ : convertToString(self, args);
+ }
+
+ if (result != 0) {
+ PyErr_Format(PyExc_TypeError,
+ "QmlUncreatable() takes a single string argument or no argument");
+ }
+
+ return result;
+}
+
+extern "C" {
+
+PyTypeObject *createPySideQmlUncreatableType(void)
+{
+ auto typeSlots =
+ PySide::ClassDecorator::Methods<PySideQmlUncreatablePrivate>::typeSlots();
+
+ PyType_Spec PySideQmlUncreatableType_spec = {
+ "2:PySide6.QtCore.qmlUncreatable",
+ sizeof(PySideClassDecorator),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeSlots.data()
+ };
+ return SbkType_FromSpec(&PySideQmlUncreatableType_spec);
+}
+
+PyTypeObject *PySideQmlUncreatable_TypeF(void)
+{
+ static auto *type = createPySideQmlUncreatableType();
+ return type;
+}
+
+} // extern "C"
+
+static const char *qmlUncreatable_SignatureStrings[] = {
+ "PySide6.QtQml.QmlUncreatable(self,reason:str)",
+ nullptr // Sentinel
+};
+
+void initQmlUncreatable(PyObject *module)
+{
+ if (InitSignatureStrings(PySideQmlUncreatable_TypeF(), qmlUncreatable_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideQmlUncreatable_TypeF());
+ PyModule_AddObject(module, "QmlUncreatable",
+ reinterpret_cast<PyObject *>(PySideQmlUncreatable_TypeF()));
+}
+
+void setUncreatableClassInfo(PyTypeObject *type, const QByteArray &reason)
+{
+ PySide::ClassInfo::setClassInfo(type, {
+ {"QML.Creatable"_ba, "false"_ba},
+ {"QML.UncreatableReason"_ba, reason} });
+}
+
+void setUncreatableClassInfo(QMetaObjectBuilder *builder, const QByteArray &reason)
+{
+ builder->addClassInfo("QML.Creatable", "false");
+ builder->addClassInfo("QML.UncreatableReason", reason);
+}
diff --git a/sources/pyside6/libpysideqml/pysideqmluncreatable.h b/sources/pyside6/libpysideqml/pysideqmluncreatable.h
new file mode 100644
index 000000000..8a8adb3c8
--- /dev/null
+++ b/sources/pyside6/libpysideqml/pysideqmluncreatable.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYSIDEQMLUNCREATABLE_H
+#define PYSIDEQMLUNCREATABLE_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QByteArray>
+
+QT_FORWARD_DECLARE_CLASS(QMetaObjectBuilder)
+
+// The QmlUncreatable decorator modifies QmlElement to register an uncreatable
+// type. Due to the (reverse) execution order of decorators, it needs to follow
+// QmlElement.
+extern "C"
+{
+ extern PyTypeObject *PySideQmlUncreatable_TypeF(void);
+}
+
+void initQmlUncreatable(PyObject *module);
+
+void setUncreatableClassInfo(PyTypeObject *type, const QByteArray &reason);
+void setUncreatableClassInfo(QMetaObjectBuilder *builder, const QByteArray &reason);
+
+#endif // PYSIDEQMLUNCREATABLE_H