aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-11-02 16:11:52 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-11-02 16:12:04 +0000
commit25180730194bec25f915f32ab846ea583fb1493f (patch)
tree9a73e0336ecf21e085d99d6a651c5547b9eb99f8 /sources/pyside6/libpyside
parent6e3e7b9ca0548430aaa5e2555d6e02c64625fa3f (diff)
Rename PySide2 to PySide6
Adapt CMake files, build scripts, tests and examples. Task-number: PYSIDE-904 Change-Id: I845f7b006e9ad274fed5444ec4c1f9dbe176ff88 Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/pyside6/libpyside')
-rw-r--r--sources/pyside6/libpyside/CMakeLists.txt210
-rw-r--r--sources/pyside6/libpyside/PySide6Config-spec.cmake.in16
-rw-r--r--sources/pyside6/libpyside/PySide6Config.cmake.in5
-rw-r--r--sources/pyside6/libpyside/PySide6ConfigVersion.cmake.in10
-rw-r--r--sources/pyside6/libpyside/class_property.cpp158
-rw-r--r--sources/pyside6/libpyside/class_property.h69
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.cpp588
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.h84
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject_p.h107
-rw-r--r--sources/pyside6/libpyside/feature_select.cpp766
-rw-r--r--sources/pyside6/libpyside/feature_select.h56
-rw-r--r--sources/pyside6/libpyside/globalreceiverv2.cpp348
-rw-r--r--sources/pyside6/libpyside/globalreceiverv2.h150
-rw-r--r--sources/pyside6/libpyside/pyside.cpp616
-rw-r--r--sources/pyside6/libpyside/pyside.h173
-rw-r--r--sources/pyside6/libpyside/pyside6.pc.in15
-rw-r--r--sources/pyside6/libpyside/pyside_p.h71
-rw-r--r--sources/pyside6/libpyside/pysideclassinfo.cpp207
-rw-r--r--sources/pyside6/libpyside/pysideclassinfo.h70
-rw-r--r--sources/pyside6/libpyside/pysideclassinfo_p.h70
-rw-r--r--sources/pyside6/libpyside/pysidemacros.h55
-rw-r--r--sources/pyside6/libpyside/pysidemetafunction.cpp231
-rw-r--r--sources/pyside6/libpyside/pysidemetafunction.h75
-rw-r--r--sources/pyside6/libpyside/pysidemetafunction_p.h62
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp634
-rw-r--r--sources/pyside6/libpyside/pysideproperty.h116
-rw-r--r--sources/pyside6/libpyside/pysideproperty_p.h182
-rw-r--r--sources/pyside6/libpyside/pysideqenum.cpp258
-rw-r--r--sources/pyside6/libpyside/pysideqenum.h57
-rw-r--r--sources/pyside6/libpyside/pysideqflags.cpp205
-rw-r--r--sources/pyside6/libpyside/pysideqflags.h79
-rw-r--r--sources/pyside6/libpyside/pysidesignal.cpp1040
-rw-r--r--sources/pyside6/libpyside/pysidesignal.h163
-rw-r--r--sources/pyside6/libpyside/pysidesignal_p.h94
-rw-r--r--sources/pyside6/libpyside/pysideslot.cpp199
-rw-r--r--sources/pyside6/libpyside/pysideslot_p.h49
-rw-r--r--sources/pyside6/libpyside/pysidestaticstrings.cpp63
-rw-r--r--sources/pyside6/libpyside/pysidestaticstrings.h60
-rw-r--r--sources/pyside6/libpyside/pysideweakref.cpp114
-rw-r--r--sources/pyside6/libpyside/pysideweakref.h56
-rw-r--r--sources/pyside6/libpyside/signalmanager.cpp640
-rw-r--r--sources/pyside6/libpyside/signalmanager.h121
42 files changed, 8342 insertions, 0 deletions
diff --git a/sources/pyside6/libpyside/CMakeLists.txt b/sources/pyside6/libpyside/CMakeLists.txt
new file mode 100644
index 000000000..33e23063b
--- /dev/null
+++ b/sources/pyside6/libpyside/CMakeLists.txt
@@ -0,0 +1,210 @@
+project(libpyside)
+
+if(${Qt${QT_MAJOR_VERSION}Qml_FOUND})
+ if(NOT "${Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS}" MATCHES "/QtQml/")
+ string(REPLACE "/QtCore" "/QtQml" replaceme "${Qt${QT_MAJOR_VERSION}Core_PRIVATE_INCLUDE_DIRS}")
+ list(APPEND Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS ${replaceme})
+ list(REMOVE_DUPLICATES Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS)
+ endif()
+endif()
+
+if(${Qt${QT_MAJOR_VERSION}Quick_FOUND})
+ if(NOT "${Qt${QT_MAJOR_VERSION}Quick_PRIVATE_INCLUDE_DIRS}" MATCHES "/QtQuick/")
+ string(REPLACE "/QtCore" "/QtQuick" replaceme "${Qt${QT_MAJOR_VERSION}Core_PRIVATE_INCLUDE_DIRS}")
+ list(APPEND Qt${QT_MAJOR_VERSION}Quick_PRIVATE_INCLUDE_DIRS ${Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS})
+ list(APPEND Qt${QT_MAJOR_VERSION}Quick_PRIVATE_INCLUDE_DIRS ${replaceme})
+ list(REMOVE_DUPLICATES Qt${QT_MAJOR_VERSION}Quick_PRIVATE_INCLUDE_DIRS)
+ endif()
+endif()
+
+set(QML_PRIVATE_API_SUPPORT 0)
+if(Qt${QT_MAJOR_VERSION}Qml_FOUND)
+ # Used for registering custom QQuickItem classes defined in Python code.
+ set(QML_SUPPORT 1)
+ set(QML_INCLUDES ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS})
+ set(QML_LIBRARIES ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES})
+
+ if(Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS)
+ # Used for transforming QML exceptions into Python exceptions.
+ set(QML_PRIVATE_API_SUPPORT 1)
+ set(QML_INCLUDES ${QML_INCLUDES} ${Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS})
+ else()
+ message(WARNING "QML private API include files could not be found, support for catching QML exceptions inside Python code will not work.")
+ endif()
+else()
+ set(QML_SUPPORT 0)
+ set(QML_PRIVATE_API_SUPPORT 0)
+ set(QML_INCLUDES "")
+ set(QML_LIBRARIES "")
+endif()
+
+set(libpyside_SRC
+ class_property.cpp
+ dynamicqmetaobject.cpp
+ feature_select.cpp
+ signalmanager.cpp
+ globalreceiverv2.cpp
+ pysideclassinfo.cpp
+ pysideqenum.cpp
+ pysidemetafunction.cpp
+ pysidesignal.cpp
+ pysideslot.cpp
+ pysideproperty.cpp
+ pysideqflags.cpp
+ pysideweakref.cpp
+ pyside.cpp
+ pysidestaticstrings.cpp
+)
+
+# Add python files to project explorer in Qt Creator, when opening the CMakeLists.txt as a project,
+# so you can look up python files with the Locator.
+macro(add_other_files)
+ foreach(_it ${ARGN})
+ if(NOT IS_DIRECTORY ${_it})
+ get_filename_component(name ${_it} NAME)
+ if(NOT ${_it} MATCHES "^/\\\\..*$;~$")
+ set_source_files_properties(${_it} PROPERTIES HEADER_FILE_ONLY TRUE)
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+# Test files.
+file(GLOB_RECURSE pyside_folder_py_files "../*.py")
+
+# Mostly for setup.py.
+file(GLOB setup_folder_py_files "../../../*.py")
+
+set(other_files ${pyside_folder_py_files} ${setup_folder_py_files})
+add_other_files(${other_files})
+
+add_library(pyside6 SHARED ${libpyside_SRC} ${other_files})
+add_library(PySide6::pyside6 ALIAS pyside6)
+
+target_include_directories(pyside6 PRIVATE
+ ${QML_INCLUDES}
+ ${Qt${QT_MAJOR_VERSION}Core_PRIVATE_INCLUDE_DIRS}
+ ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
+)
+
+target_include_directories(pyside6 PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:include/PySide6>
+)
+
+target_link_libraries(pyside6
+ PRIVATE Shiboken6::libshiboken
+ PRIVATE ${QML_LIBRARIES}
+ PRIVATE ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES})
+
+set_target_properties(pyside6 PROPERTIES
+ VERSION ${BINDING_API_VERSION}
+ SOVERSION "${PYSIDE_SO_VERSION}"
+ OUTPUT_NAME "pyside6${pyside6_SUFFIX}${SHIBOKEN_PYTHON_SHARED_LIBRARY_SUFFIX}"
+ DEFINE_SYMBOL BUILD_LIBPYSIDE)
+
+if(${QT_MAJOR_VERSION} GREATER_EQUAL 6)
+ set_property(TARGET pyside6 PROPERTY CXX_STANDARD 17)
+else()
+ set_property(TARGET pyside6 PROPERTY CXX_STANDARD 11)
+endif()
+
+if(QML_SUPPORT)
+ target_compile_definitions(pyside6 PUBLIC PYSIDE_QML_SUPPORT=1)
+endif()
+target_compile_definitions(pyside6 PRIVATE PYSIDE_QML_PRIVATE_API_SUPPORT=${QML_PRIVATE_API_SUPPORT})
+
+if(PYSIDE_QT_CONF_PREFIX)
+ set_property(SOURCE pyside.cpp
+ APPEND
+ PROPERTY COMPILE_DEFINITIONS
+ PYSIDE_QT_CONF_PREFIX=${PYSIDE_QT_CONF_PREFIX})
+endif()
+
+#
+# install stuff
+#
+
+set(libpyside_HEADERS
+ class_property.h
+ dynamicqmetaobject.h
+ feature_select.h
+ pysideclassinfo.h
+ pysideqenum.h
+ pysidemacros.h
+ signalmanager.h
+ pyside.h
+ pysidestaticstrings.h
+ pysidemetafunction.h
+ pysidesignal.h
+ pysideproperty.h
+ pysideqflags.h
+ pysideweakref.h
+)
+
+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")
+
+# create pkg-config file
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pyside6.pc.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/pyside6${pyside6_SUFFIX}.pc" @ONLY)
+
+# for creating cmake-config files
+include(CMakePackageConfigHelpers)
+
+# Build-tree / super project package config file.
+set(PYSIDE_PYTHONPATH "${pysidebindings_BINARY_DIR}/PySide6")
+set(PYSIDE_TYPESYSTEMS "${pysidebindings_SOURCE_DIR}/PySide6/templates/")
+set(PYSIDE_GLUE "${pysidebindings_SOURCE_DIR}/PySide6/glue")
+
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/PySide6Config-spec.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}"
+ PATH_VARS PYSIDE_PYTHONPATH PYSIDE_TYPESYSTEMS PYSIDE_GLUE
+ INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}"
+)
+
+set(PYSIDE_PYTHONPATH "${PYTHON_SITE_PACKAGES}/PySide6")
+set(PYSIDE_TYPESYSTEMS "${CMAKE_INSTALL_PREFIX}/share/PySide6${pyside6_SUFFIX}/typesystems")
+set(PYSIDE_GLUE "${CMAKE_INSTALL_PREFIX}/share/PySide6${pyside6_SUFFIX}/glue")
+
+# Install-tree / relocatable package config file.
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/PySide6Config-spec.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6-${BINDING_API_VERSION}"
+ PATH_VARS PYSIDE_PYTHONPATH PYSIDE_TYPESYSTEMS PYSIDE_GLUE
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/PySide6Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/PySide6Config.cmake" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/PySide6ConfigVersion.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/PySide6ConfigVersion.cmake" @ONLY)
+
+install(FILES ${libpyside_HEADERS}
+ DESTINATION include/${BINDING_NAME}${pyside6_SUFFIX})
+
+install(TARGETS pyside6 EXPORT PySide6Targets
+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+ ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
+ RUNTIME DESTINATION bin)
+install(EXPORT PySide6Targets NAMESPACE PySide6::
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6-${BINDING_API_VERSION}")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pyside6${pyside6_SUFFIX}.pc"
+ DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/PySide6Config.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6-${BINDING_API_VERSION}")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6-${BINDING_API_VERSION}")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/PySide6ConfigVersion.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6-${BINDING_API_VERSION}")
diff --git a/sources/pyside6/libpyside/PySide6Config-spec.cmake.in b/sources/pyside6/libpyside/PySide6Config-spec.cmake.in
new file mode 100644
index 000000000..fd3de1e75
--- /dev/null
+++ b/sources/pyside6/libpyside/PySide6Config-spec.cmake.in
@@ -0,0 +1,16 @@
+# PYSIDE_PYTHONPATH - Path to where the PySide6 Python module files could be found
+# PYSIDE_TYPESYSTEMS - Type system files that should be used by other bindings extending PySide6
+# PYSIDE_GLUE - Path to module glue files.
+
+@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::pyside6)
+ include("${CMAKE_CURRENT_LIST_DIR}/PySide6Targets.cmake")
+endif()
+
+# Set relocatable variables.
+set_and_check(PYSIDE_PYTHONPATH "@PACKAGE_PYSIDE_PYTHONPATH@")
+set_and_check(PYSIDE_TYPESYSTEMS "@PACKAGE_PYSIDE_TYPESYSTEMS@")
+set_and_check(PYSIDE_GLUE "@PACKAGE_PYSIDE_GLUE@")
diff --git a/sources/pyside6/libpyside/PySide6Config.cmake.in b/sources/pyside6/libpyside/PySide6Config.cmake.in
new file mode 100644
index 000000000..037a5c44f
--- /dev/null
+++ b/sources/pyside6/libpyside/PySide6Config.cmake.in
@@ -0,0 +1,5 @@
+if (NOT PYTHON_CONFIG_SUFFIX)
+ message(STATUS "PySide6Config: Using default python: @SHIBOKEN_PYTHON_CONFIG_SUFFIX@")
+ SET(PYTHON_CONFIG_SUFFIX @SHIBOKEN_PYTHON_CONFIG_SUFFIX@)
+endif()
+include(${CMAKE_CURRENT_LIST_DIR}/PySide6Config${PYTHON_CONFIG_SUFFIX}.cmake)
diff --git a/sources/pyside6/libpyside/PySide6ConfigVersion.cmake.in b/sources/pyside6/libpyside/PySide6ConfigVersion.cmake.in
new file mode 100644
index 000000000..f5073ce08
--- /dev/null
+++ b/sources/pyside6/libpyside/PySide6ConfigVersion.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/libpyside/class_property.cpp b/sources/pyside6/libpyside/class_property.cpp
new file mode 100644
index 000000000..edbb63769
--- /dev/null
+++ b/sources/pyside6/libpyside/class_property.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "pyside.h"
+#include "pysidestaticstrings.h"
+#include "feature_select.h"
+#include "class_property.h"
+
+#include <shiboken.h>
+#include <sbkstaticstrings.h>
+
+extern "C" {
+
+/*
+ * A `classproperty` is the same as a `property` but the `__get__()` and `__set__()`
+ * methods are modified to always use the object class instead of a concrete instance.
+ *
+ * Note: A "static property" as it is often called does not exist per se.
+ * Static methods do not receive anything when created. Static methods which
+ * should participate in a property must be turned into class methods, before.
+ * See function `createProperty` in `feature_select.cpp`.
+ */
+
+// `class_property.__get__()`: Always pass the class instead of the instance.
+static PyObject *PyClassProperty_get(PyObject *self, PyObject * /*ob*/, PyObject *cls)
+{
+ return PyProperty_Type.tp_descr_get(self, cls, cls);
+}
+
+// `class_property.__set__()`: Just like the above `__get__()`.
+static int PyClassProperty_set(PyObject *self, PyObject *obj, PyObject *value)
+{
+ PyObject *cls = PyType_Check(obj) ? obj : reinterpret_cast<PyObject *>(Py_TYPE(obj));
+ return PyProperty_Type.tp_descr_set(self, cls, value);
+}
+
+// The property `__doc__` default does not work for class properties
+// because PyProperty_Type.tp_init thinks this is a subclass which needs PyObject_SetAttr.
+// We call `__init__` while pretending to be a PyProperty_Type instance.
+static int PyClassProperty_init(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ auto hold = Py_TYPE(self);
+ Py_TYPE(self) = &PyProperty_Type;
+ auto ret = PyProperty_Type.tp_init(self, args, kwargs);
+ Py_TYPE(self) = hold;
+ return ret;
+}
+
+static PyType_Slot PyClassProperty_slots[] = {
+ {Py_tp_getset, nullptr}, // will be set below
+ {Py_tp_base, reinterpret_cast<void *>(&PyProperty_Type)},
+ {Py_tp_descr_get, reinterpret_cast<void *>(PyClassProperty_get)},
+ {Py_tp_descr_set, reinterpret_cast<void *>(PyClassProperty_set)},
+ {Py_tp_init, reinterpret_cast<void *>(PyClassProperty_init)},
+ {0, 0}
+};
+
+static PyType_Spec PyClassProperty_spec = {
+ "PySide6.PyClassProperty",
+ sizeof(propertyobject),
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ PyClassProperty_slots,
+};
+
+PyTypeObject *PyClassPropertyTypeF()
+{
+ static PyTypeObject *type = nullptr;
+ if (type == nullptr) {
+ // Provide the same `tp_getset`, which is not inherited.
+ PyClassProperty_slots[0].pfunc = PyProperty_Type.tp_getset;
+ type = reinterpret_cast<PyTypeObject *>(
+ PyType_FromSpec(&PyClassProperty_spec));
+ }
+ return type;
+}
+
+/*
+ * Types with class properties need to handle `Type.class_prop = x` in a specific way.
+ * By default, Python replaces the `class_property` itself, but for wrapped C++ types
+ * we need to call `class_property.__set__()` in order to propagate the new value to
+ * the underlying C++ data structure.
+ */
+static int SbkObjectType_meta_setattro(PyObject *obj, PyObject *name, PyObject *value)
+{
+ // Use `_PepType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
+ // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
+ auto type = reinterpret_cast<PyTypeObject *>(obj);
+ PyObject *descr = _PepType_Lookup(type, name);
+
+ // The following assignment combinations are possible:
+ // 1. `Type.class_prop = value` --> descr_set: `Type.class_prop.__set__(value)`
+ // 2. `Type.class_prop = other_class_prop` --> setattro: replace existing `class_prop`
+ // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
+ const auto class_prop = reinterpret_cast<PyObject *>(PyClassPropertyTypeF());
+ const auto call_descr_set = descr && PyObject_IsInstance(descr, class_prop)
+ && !PyObject_IsInstance(value, class_prop);
+ if (call_descr_set) {
+ // Call `class_property.__set__()` instead of replacing the `class_property`.
+ return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
+ } else {
+ // Replace existing attribute.
+ return PyType_Type.tp_setattro(obj, name, value);
+ }
+}
+
+} // extern "C"
+
+/*
+ * These functions are added to the SbkObjectType_TypeF() dynamically.
+ */
+namespace PySide { namespace ClassProperty {
+
+void init()
+{
+ PyTypeObject *type = SbkObjectType_TypeF();
+ type->tp_setattro = SbkObjectType_meta_setattro;
+ Py_TYPE(PyClassPropertyTypeF()) = type;
+}
+
+} // namespace ClassProperty
+} // namespace PySide
diff --git a/sources/pyside6/libpyside/class_property.h b/sources/pyside6/libpyside/class_property.h
new file mode 100644
index 000000000..f94fdde31
--- /dev/null
+++ b/sources/pyside6/libpyside/class_property.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 CLASS_PROPERTY_H
+#define CLASS_PROPERTY_H
+
+#include "pysidemacros.h"
+#include <sbkpython.h>
+
+extern "C" {
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *prop_get;
+ PyObject *prop_set;
+ PyObject *prop_del;
+ PyObject *prop_doc;
+ int getter_doc;
+} propertyobject;
+
+PYSIDE_API PyTypeObject *PyClassPropertyTypeF();
+
+} // extern "C"
+
+namespace PySide {
+namespace ClassProperty {
+
+PYSIDE_API void init();
+
+} // namespace ClassProperty
+} // namespace PySide
+
+#endif // CLASS_PROPERTY_H
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
new file mode 100644
index 000000000..d63fa281b
--- /dev/null
+++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
@@ -0,0 +1,588 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "dynamicqmetaobject.h"
+#include "dynamicqmetaobject_p.h"
+#include "pysidesignal.h"
+#include "pysidesignal_p.h"
+#include "pysideproperty.h"
+#include "pysideproperty_p.h"
+#include "pysideslot_p.h"
+#include "pysideqenum.h"
+
+#include <shiboken.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+#include <QtCore/QVector>
+#include <private/qmetaobjectbuilder_p.h>
+
+#include <cstring>
+#include <vector>
+
+using namespace PySide;
+
+// MetaObjectBuilder: Provides the QMetaObject's returned by
+// QObject::metaObject() for PySide6 objects. There are several
+// scenarios to consider:
+// 1) A plain Qt class (say QTimer) is instantiated. In that case,
+// return the base meta object until a modification is made by
+// adding methods, properties or class info (cf qmetaobject_test.py).
+// In that case, instantiate a QMetaObjectBuilder inheriting the
+// base meta meta object, add the method and return the result
+// of QMetaObjectBuilder::toMetaObject() (with dirty handling should
+// further modifications be made).
+// 2) A Python class inheriting a Qt class is instantiated. For this,
+// instantiate a QMetaObjectBuilder and add the methods/properties
+// found by inspecting the Python class.
+
+class MetaObjectBuilderPrivate
+{
+public:
+ using MetaObjects = std::vector<const QMetaObject *>;
+
+ QMetaObjectBuilder *ensureBuilder();
+ void parsePythonType(PyTypeObject *type);
+ int indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const QByteArray &signature);
+ int addSlot(const QByteArray &signature, const QByteArray &type);
+ int addSignal(const QByteArray &signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
+ int getPropertyNotifyId(PySideProperty *property) const;
+ int addProperty(const QByteArray &property, PyObject *data);
+ void addInfo(const QByteArray &key, const QByteArray &value);
+ void addInfo(const QMap<QByteArray, QByteArray> &info);
+ void addEnumerator(const char *name,
+ bool flag,
+ bool scoped,
+ const QVector<QPair<QByteArray, int> > &entries);
+ void removeProperty(int index);
+ const QMetaObject *update();
+
+ QMetaObjectBuilder *m_builder = nullptr;
+
+ const QMetaObject *m_baseObject = nullptr;
+ MetaObjects m_cachedMetaObjects;
+ bool m_dirty = true;
+};
+
+QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder()
+{
+ if (!m_builder) {
+ m_builder = new QMetaObjectBuilder();
+ m_builder->setClassName(m_baseObject->className());
+ m_builder->setSuperClass(m_baseObject);
+ }
+ return m_builder;
+}
+
+MetaObjectBuilder::MetaObjectBuilder(const char *className, const QMetaObject *metaObject) :
+ m_d(new MetaObjectBuilderPrivate)
+{
+ m_d->m_baseObject = metaObject;
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->m_builder->setClassName(className);
+}
+
+MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject)
+ : m_d(new MetaObjectBuilderPrivate)
+{
+ m_d->m_baseObject = metaObject;
+ const char *className = type->tp_name;
+ if (const char *lastDot = strrchr(type->tp_name, '.'))
+ className = lastDot + 1;
+ // Different names indicate a Python class inheriting a Qt class.
+ // Parse the type.
+ if (strcmp(className, metaObject->className()) != 0) {
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->parsePythonType(type);
+ }
+}
+
+MetaObjectBuilder::~MetaObjectBuilder()
+{
+ for (auto *metaObject : m_d->m_cachedMetaObjects)
+ free(const_cast<QMetaObject*>(metaObject));
+ delete m_d->m_builder;
+ delete m_d;
+}
+
+int MetaObjectBuilderPrivate::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
+{
+ int result = -1;
+ if (m_builder) {
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_builder->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_builder->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_builder->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_builder->indexOfMethod(signature);
+ break;
+ }
+ if (result >= 0)
+ return result + m_baseObject->methodCount();
+ }
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_baseObject->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_baseObject->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_baseObject->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_baseObject->indexOfMethod(signature);
+ break;
+ }
+ return result;
+}
+
+int MetaObjectBuilder::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
+{
+ return m_d->indexOfMethod(mtype, signature);
+}
+
+int MetaObjectBuilderPrivate::indexOfProperty(const QByteArray &name) const
+{
+ if (m_builder) {
+ const int result = m_builder->indexOfProperty(name);
+ if (result >= 0)
+ return m_baseObject->propertyCount() + result;
+ }
+ return m_baseObject->indexOfProperty(name);
+}
+
+int MetaObjectBuilder::indexOfProperty(const QByteArray &name) const
+{
+ return m_d->indexOfProperty(name);
+}
+
+static bool checkMethodSignature(const QByteArray &signature)
+{
+ // Common mistake not to add parentheses to the signature.
+ const int openParen = signature.indexOf('(');
+ const int closingParen = signature.lastIndexOf(')');
+ const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen;
+ if (!ok) {
+ const QByteArray message =
+ "MetaObjectBuilder::addMethod: Invalid method signature provided for \""
+ + signature + '"';
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0);
+ }
+ return ok;
+}
+
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature)
+{
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSlot(signature).index();
+}
+
+int MetaObjectBuilder::addSlot(const char *signature)
+{
+ return m_d->addSlot(signature);
+}
+
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature,
+ const QByteArray &type)
+{
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature);
+ methodBuilder.setReturnType(type);
+ return m_baseObject->methodCount() + methodBuilder.index();
+}
+
+int MetaObjectBuilder::addSlot(const char *signature, const char *type)
+{
+ return m_d->addSlot(signature, type);
+}
+
+int MetaObjectBuilderPrivate::addSignal(const QByteArray &signature)
+{
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSignal(signature).index();
+}
+
+int MetaObjectBuilder::addSignal(const char *signature)
+{
+ return m_d->addSignal(signature);
+}
+
+void MetaObjectBuilderPrivate::removeMethod(QMetaMethod::MethodType mtype,
+ int index)
+{
+ index -= m_baseObject->methodCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->methodCount());
+ switch (mtype) {
+ case QMetaMethod::Constructor:
+ builder->removeConstructor(index);
+ break;
+ default:
+ builder->removeMethod(index);
+ break;
+ }
+ m_dirty = true;
+}
+
+void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index)
+{
+ m_d->removeMethod(mtype, index);
+}
+
+int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const
+{
+ int notifyId = -1;
+ if (property->d->notify) {
+ if (const char *signalNotify = PySide::Property::getNotifyName(property))
+ notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify);
+ }
+ return notifyId;
+}
+
+int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
+ PyObject *data)
+{
+ int index = indexOfProperty(propertyName);
+ if (index != -1)
+ return index;
+
+ PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
+ int propertyNotifyId = getPropertyNotifyId(property);
+ if (propertyNotifyId >= 0)
+ propertyNotifyId -= m_baseObject->methodCount();
+ auto newProperty =
+ ensureBuilder()->addProperty(propertyName, property->d->typeName,
+ propertyNotifyId);
+ // Adding property attributes
+ newProperty.setReadable(PySide::Property::isReadable(property));
+ newProperty.setWritable(PySide::Property::isWritable(property));
+ newProperty.setResettable(PySide::Property::hasReset(property));
+ newProperty.setDesignable(PySide::Property::isDesignable(property));
+ newProperty.setScriptable(PySide::Property::isScriptable(property));
+ newProperty.setStored(PySide::Property::isStored(property));
+ newProperty.setUser(PySide::Property::isUser(property));
+ newProperty.setConstant(PySide::Property::isConstant(property));
+ newProperty.setFinal(PySide::Property::isFinal(property));
+
+ index = newProperty.index() + m_baseObject->propertyCount();
+ m_dirty = true;
+ return index;
+}
+
+int MetaObjectBuilder::addProperty(const char *property, PyObject *data)
+{
+ return m_d->addProperty(property, data);
+}
+
+void MetaObjectBuilderPrivate::addInfo(const QByteArray &key,
+ const QByteArray &value)
+{
+ ensureBuilder()->addClassInfo(key, value);
+ m_dirty = true;
+}
+
+void MetaObjectBuilder::addInfo(const char *key, const char *value)
+{
+ m_d->addInfo(key, value);
+}
+
+void MetaObjectBuilderPrivate::addInfo(const QMap<QByteArray, QByteArray> &info)
+{
+ auto builder = ensureBuilder();
+ for (auto i = info.constBegin(), end = info.constEnd(); i != end; ++i)
+ builder->addClassInfo(i.key(), i.value());
+ m_dirty = true;
+}
+
+void MetaObjectBuilder::addInfo(const QMap<QByteArray, QByteArray> &info)
+{
+ m_d->addInfo(info);
+}
+
+void MetaObjectBuilder::addEnumerator(const char *name, bool flag, bool scoped,
+ const QVector<QPair<QByteArray, int> > &entries)
+{
+ m_d->addEnumerator(name, flag, scoped, entries);
+}
+
+void MetaObjectBuilderPrivate::addEnumerator(const char *name, bool flag, bool scoped,
+ const QVector<QPair<QByteArray, int> > &entries)
+{
+ auto builder = ensureBuilder();
+ int have_already = builder->indexOfEnumerator(name);
+ if (have_already >= 0)
+ builder->removeEnumerator(have_already);
+ auto enumbuilder = builder->addEnumerator(name);
+ enumbuilder.setIsFlag(flag);
+ enumbuilder.setIsScoped(scoped);
+
+ for (auto item : entries)
+ enumbuilder.addKey(item.first, item.second);
+ m_dirty = true;
+}
+
+void MetaObjectBuilderPrivate::removeProperty(int index)
+{
+ index -= m_baseObject->propertyCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->propertyCount());
+ builder->removeProperty(index);
+ m_dirty = true;
+}
+
+void MetaObjectBuilder::removeProperty(int index)
+{
+ m_d->removeProperty(index);
+}
+
+// PYSIDE-315: Instead of sorting the items and maybe breaking indices, we
+// ensure that the signals and slots are sorted by the improved
+// parsePythonType() (signals must go before slots). The order can only
+// become distorted if the class is modified after creation. In that
+// case, we give a warning.
+
+static QString msgMethodSortOrder(const QMetaObject *mo, int offendingIndex)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "\n\n*** Sort Warning ***\nSignals and slots in QMetaObject '"
+ << mo->className()
+ << "' are not ordered correctly, this may lead to issues.\n";
+ const int methodOffset = mo->methodOffset();
+ for (int m = methodOffset, methodCount = mo->methodCount(); m < methodCount; ++m) {
+ const auto method = mo->method(m);
+ str << (m - methodOffset + 1) << (m > offendingIndex ? '!' : ' ')
+ << (method.methodType() == QMetaMethod::Signal ? " Signal " : " Slot ")
+ << method.methodSignature() << '\n';
+ }
+ return result;
+}
+
+static void checkMethodOrder(const QMetaObject *metaObject)
+{
+ const int lastMethod = metaObject->methodCount() - 1;
+ for (int m = metaObject->methodOffset(); m < lastMethod; ++m) {
+ if (metaObject->method(m).methodType() == QMetaMethod::Slot
+ && metaObject->method(m + 1).methodType() == QMetaMethod::Signal) {
+ const auto message = msgMethodSortOrder(metaObject, m);
+ PyErr_WarnEx(PyExc_RuntimeWarning, qPrintable(message), 0);
+ // Prevent a warning from being turned into an error. We cannot easily unwind.
+ PyErr_Clear();
+ break;
+ }
+ }
+}
+
+const QMetaObject *MetaObjectBuilderPrivate::update()
+{
+ if (!m_builder)
+ return m_baseObject;
+ if (m_cachedMetaObjects.empty() || m_dirty) {
+ // PYSIDE-803: The dirty branch needs to be protected by the GIL.
+ // This was moved from SignalManager::retrieveMetaObject to here,
+ // which is only the update in "return builder->update()".
+ Shiboken::GilState gil;
+ m_cachedMetaObjects.push_back(m_builder->toMetaObject());
+ checkMethodOrder(m_cachedMetaObjects.back());
+ m_dirty = false;
+ }
+ return m_cachedMetaObjects.back();
+}
+
+const QMetaObject *MetaObjectBuilder::update()
+{
+ return m_d->update();
+}
+
+using namespace Shiboken;
+
+void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
+{
+ // Get all non-QObject-derived base types in method resolution order, filtering out the types
+ // that can't have signals, slots or properties.
+ // This enforces registering of all signals and slots at type parsing time, and not later at
+ // signal connection time, thus making sure no method indices change which would break
+ // existing connections.
+ const PyObject *mro = type->tp_mro;
+ const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro);
+ PyTypeObject *qObjectType = Conversions::getPythonTypeObject("QObject*");
+
+ std::vector<PyTypeObject *> basesToCheck;
+ // Prepend the actual type that we are parsing.
+ basesToCheck.reserve(1u + basesCount);
+ basesToCheck.push_back(type);
+
+ auto sbkObjTypeF = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF());
+ auto baseObjType = reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type);
+ for (Py_ssize_t i = 0; i < basesCount; ++i) {
+ auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
+ if (baseType != sbkObjTypeF && baseType != baseObjType
+ && PyType_IsSubtype(baseType, qObjectType) == 0) {
+ basesToCheck.push_back(baseType);
+ }
+ }
+
+ // PYSIDE-315: Handle all signals first, in all involved types.
+ // Leave the properties to be registered after signals because they may depend on
+ // notify signals.
+ for (PyTypeObject *baseType : basesToCheck) {
+ PyObject *attrs = baseType->tp_dict;
+ PyObject *key = nullptr;
+ PyObject *value = nullptr;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(attrs, &pos, &key, &value)) {
+ if (Signal::checkType(value)) {
+ // Register signals.
+ auto data = reinterpret_cast<PySideSignal *>(value);
+ if (data->data->signalName.isEmpty())
+ data->data->signalName = String::toCString(key);
+ for (const auto &s : data->data->signatures) {
+ const auto sig = data->data->signalName + '(' + s.signature + ')';
+ if (m_baseObject->indexOfSignal(sig) == -1) {
+ // Registering the parameterNames to the QMetaObject (PYSIDE-634)
+ // from:
+ // Signal(..., arguments=['...', ...]
+ // the arguments are now on data-data->signalArguments
+ if (!data->data->signalArguments->isEmpty()) {
+ m_builder->addSignal(sig).setParameterNames(*data->data->signalArguments);
+ } else {
+ m_builder->addSignal(sig);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ AutoDecRef slotAttrName(String::fromCString(PYSIDE_SLOT_LIST_ATTR));
+ // PYSIDE-315: Now take care of the rest.
+ // Signals and slots should be separated, unless the types are modified, later.
+ // We check for this using "is_sorted()". Sorting no longer happens at all.
+ for (PyTypeObject *baseType : basesToCheck) {
+ PyObject *attrs = baseType->tp_dict;
+ PyObject *key = nullptr;
+ PyObject *value = nullptr;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(attrs, &pos, &key, &value)) {
+ if (Property::checkType(value)) {
+ const int index = m_baseObject->indexOfProperty(String::toCString(key));
+ if (index == -1)
+ addProperty(String::toCString(key), value);
+ } else if (Py_TYPE(value)->tp_call != nullptr) {
+ // PYSIDE-198: PyFunction_Check does not work with Nuitka.
+ // Register slots.
+ if (PyObject_HasAttr(value, slotAttrName)) {
+ PyObject *signatureList = PyObject_GetAttr(value, slotAttrName);
+ for (Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) {
+ PyObject *pySignature = PyList_GET_ITEM(signatureList, i);
+ QByteArray signature(String::toCString(pySignature));
+ // Split the slot type and its signature.
+ QByteArray type;
+ const int spacePos = signature.indexOf(' ');
+ if (spacePos != -1) {
+ type = signature.left(spacePos);
+ signature.remove(0, spacePos + 1);
+ }
+ const int index = m_baseObject->indexOfSlot(signature);
+ if (index == -1) {
+ if (type.isEmpty() || type == "void")
+ addSlot(signature);
+ else
+ addSlot(signature, type);
+ }
+ }
+ }
+ }
+ }
+ }
+ // PYSIDE-957: Collect the delayed QEnums
+ auto collectedEnums = PySide::QEnum::resolveDelayedQEnums(type);
+ for (PyObject *obEnumType : collectedEnums) {
+ bool isFlag = PySide::QEnum::isFlag(obEnumType);
+ AutoDecRef obName(PyObject_GetAttr(obEnumType, PyMagicName::name()));
+ // Everything has been checked already in resolveDelayedQEnums.
+ // Therefore, we don't need to error-check here again.
+ auto name = String::toCString(obName);
+ AutoDecRef members(PyObject_GetAttr(obEnumType, PyMagicName::members()));
+ AutoDecRef items(PyMapping_Items(members));
+ Py_ssize_t nr_items = PySequence_Length(items);
+
+ QVector<QPair<QByteArray, int> > entries;
+ for (Py_ssize_t idx = 0; idx < nr_items; ++idx) {
+ AutoDecRef item(PySequence_GetItem(items, idx));
+ AutoDecRef key(PySequence_GetItem(item, 0));
+ AutoDecRef member(PySequence_GetItem(item, 1));
+ AutoDecRef value(PyObject_GetAttr(member, Shiboken::PyName::value()));
+ auto ckey = String::toCString(key);
+ auto ivalue = PyInt_AsSsize_t(value); // int/long cheating
+ auto thing = QPair<QByteArray, int>(ckey, int(ivalue));
+ entries.push_back(thing);
+ }
+ addEnumerator(name, isFlag, true, entries);
+ }
+}
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.h b/sources/pyside6/libpyside/dynamicqmetaobject.h
new file mode 100644
index 000000000..7279d5c26
--- /dev/null
+++ b/sources/pyside6/libpyside/dynamicqmetaobject.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 DYNAMICQMETAOBJECT_H
+#define DYNAMICQMETAOBJECT_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QMetaMethod>
+
+class MetaObjectBuilderPrivate;
+
+namespace PySide
+{
+
+class MetaObjectBuilder
+{
+ Q_DISABLE_COPY(MetaObjectBuilder)
+public:
+ MetaObjectBuilder(const char *className, const QMetaObject *metaObject);
+
+ MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject);
+ ~MetaObjectBuilder();
+
+ int indexOfMethod(QMetaMethod::MethodType mtype, const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const char *signature);
+ int addSlot(const char *signature, const char *type);
+ int addSignal(const char *signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
+ int addProperty(const char *property, PyObject *data);
+ void addInfo(const char *key, const char *value);
+ void addInfo(const QMap<QByteArray, QByteArray> &info);
+ void addEnumerator(const char *name,
+ bool flag,
+ bool scoped,
+ const QVector<QPair<QByteArray, int> > &entries);
+ void removeProperty(int index);
+
+ const QMetaObject *update();
+
+private:
+ MetaObjectBuilderPrivate *m_d;
+};
+
+}
+#endif
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject_p.h b/sources/pyside6/libpyside/dynamicqmetaobject_p.h
new file mode 100644
index 000000000..9199630b7
--- /dev/null
+++ b/sources/pyside6/libpyside/dynamicqmetaobject_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 DYNAMICMETAPROPERTY_P_H
+#define DYNAMICMETAPROPERTY_P_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QMetaMethod>
+
+struct PySideProperty;
+namespace PySide
+{
+ class MethodData
+ {
+ public:
+ MethodData();
+ /**
+ * \param signature method signature
+ * \param type method return type
+ */
+ MethodData(QMetaMethod::MethodType mtype,
+ const QByteArray &signature,
+ const QByteArray &rtype = QByteArray("void"));
+ void clear();
+ bool isValid() const;
+ const QByteArray &signature() const { return m_signature; }
+ const QByteArray &returnType() const { return m_rtype; }
+ QMetaMethod::MethodType methodType() const { return m_mtype; }
+ //Qt5 moc: now we have to store method parameter names, count, type
+ QList<QByteArray> parameterTypes() const;
+ int parameterCount() const;
+ QByteArray name() const;
+ bool operator==(const MethodData &other) const;
+
+ private:
+ QByteArray m_signature;
+ QByteArray m_rtype;
+ QMetaMethod::MethodType m_mtype;
+ static const QByteArray m_emptySig;
+ };
+
+ class PropertyData
+ {
+ public:
+ PropertyData();
+ PropertyData(const char *name, int cachedNotifyId = 0, PySideProperty *data = 0);
+ const QByteArray &name() const { return m_name; }
+ PySideProperty *data() const { return m_data; }
+ QByteArray type() const;
+ uint flags() const;
+ bool isValid() const;
+ int cachedNotifyId() const;
+ bool operator==(const PropertyData &other) const;
+ bool operator==(const char *name) const;
+
+ private:
+ QByteArray m_name;
+ int m_cachedNotifyId;
+ PySideProperty *m_data;
+ };
+
+inline bool MethodData::operator==(const MethodData &other) const
+{
+ return m_mtype == other.methodType() && m_signature == other.signature();
+}
+
+}
+
+#endif
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp
new file mode 100644
index 000000000..d6d77a530
--- /dev/null
+++ b/sources/pyside6/libpyside/feature_select.cpp
@@ -0,0 +1,766 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "feature_select.h"
+#include "pyside.h"
+#include "pysidestaticstrings.h"
+#include "class_property.h"
+
+#include <shiboken.h>
+#include <sbkstaticstrings.h>
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Support switchable extensions
+//
+// This functionality is no longer implemented in the signature module, since
+// the PyCFunction getsets do not have to be modified any longer.
+// Instead, we simply exchange the complete class dicts. This is done in the
+// basewrapper.cpp file and in every generated `tp_(get|set)attro`.
+//
+// This is the general framework of the switchable extensions.
+// A maximum of eight features is planned so far. This seems to be enough.
+// More features are possible, but then we must somehow register the
+// extra `select_id`s above 255.
+//
+
+/*****************************************************************************
+
+ How Does This Feature Selection Work?
+ -------------------------------------
+
+The basic idea is to replace the `tp_dict` of a QObject derived type.
+This way, we can replace the methods of the class in no time.
+
+The crucial point to understand is how the `tp_dict` is actually accessed:
+When you type "QObject.__dict__", the descriptor of `SbkObjectType_Type`
+is called. This descriptor is per default unassigned, so the base class
+PyType_Type provides the tp_getset method `type_dict`:
+
+ static PyObject *
+ type_dict(PyTypeObject *type, void *context)
+ {
+ if (type->tp_dict == NULL) {
+ Py_RETURN_NONE;
+ }
+ return PyDictProxy_New(type->tp_dict);
+ }
+
+In order to change that, we need to insert our own version into SbkObjectType:
+
+ static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context)
+ {
+ auto dict = type->tp_dict;
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (SelectFeatureSet != nullptr)
+ dict = SelectFeatureSet(type);
+ return PyDictProxy_New(dict);
+ }
+
+This way, the Python function `type_ready()` does not fill in the default,
+but uses our modified version. It a similar way, we overwrite type_getattro
+with our own version, again in SbkObjectType, replacing the default of
+PyType_Type.
+
+Now we can exchange the dict with a customized version.
+We have our own derived type `ChameleonDict` with additional attributes.
+These allow us to create a ring of dicts which can be rotated to the actual
+needed dict version:
+
+Every dict has a field `select_id` which is selected by the `from __feature__`
+import. The dicts are cyclic connected by the `dict_ring` field.
+
+When a class dict is required, now always `SelectFeatureSet` is called, which
+looks into the `__name__` attribute of the active module and decides which
+version of `tp_dict` is needed. Then the right dict is searched in the ring
+and created if not already there.
+
+Furthermore, we need to overwrite every `tp_(get|set)attro` with a version
+that switches dicts right before looking up methods.
+The dict changing must walk the whole `tp_mro` in order to change all names.
+
+This is everything that the following code does.
+
+*****************************************************************************/
+
+
+namespace PySide { namespace Feature {
+
+using namespace Shiboken;
+
+typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict, int id);
+
+static FeatureProc *featurePointer = nullptr;
+
+static PyObject *cached_globals = nullptr;
+static PyObject *last_select_id = nullptr;
+
+static PyObject *_fast_id_array[1 + 256] = {};
+// this will point to element 1 to allow indexing from -1
+static PyObject **fast_id_array;
+
+static inline PyObject *getFeatureSelectId()
+{
+ static PyObject *undef = fast_id_array[-1];
+ static PyObject *feature_dict = GetFeatureDict();
+ // these things are all borrowed
+ PyObject *globals = PyEval_GetGlobals();
+ if ( globals == nullptr
+ || globals == cached_globals)
+ return last_select_id;
+
+ PyObject *modname = PyDict_GetItem(globals, PyMagicName::name());
+ if (modname == nullptr)
+ return last_select_id;
+
+ PyObject *select_id = PyDict_GetItem(feature_dict, modname);
+ if ( select_id == nullptr
+ || !PyInt_Check(select_id) // int/long cheating
+ || select_id == undef)
+ return last_select_id;
+
+ cached_globals = globals;
+ last_select_id = select_id;
+ assert(PyInt_AsSsize_t(select_id) >= 0);
+ return select_id;
+}
+
+// Create a derived dict class
+static PyTypeObject *
+createDerivedDictType()
+{
+ // It is not easy to create a compatible dict object with the
+ // limited API. Easier is to use Python to create a derived
+ // type and to modify that a bit from the C code.
+ PyObject *ChameleonDict = PepRun_GetResult(R"CPP(if True:
+
+ class ChameleonDict(dict):
+ __slots__ = ("dict_ring", "select_id")
+
+ result = ChameleonDict
+
+ )CPP");
+ return reinterpret_cast<PyTypeObject *>(ChameleonDict);
+}
+
+static PyTypeObject *new_dict_type = nullptr;
+
+static void ensureNewDictType()
+{
+ if (new_dict_type == nullptr) {
+ new_dict_type = createDerivedDictType();
+ if (new_dict_type == nullptr)
+ Py_FatalError("PySide6: Problem creating ChameleonDict");
+ }
+}
+
+static inline PyObject *nextInCircle(PyObject *dict)
+{
+ // returns a borrowed ref
+ AutoDecRef next_dict(PyObject_GetAttr(dict, PyName::dict_ring()));
+ return next_dict;
+}
+
+static inline void setNextDict(PyObject *dict, PyObject *next_dict)
+{
+ PyObject_SetAttr(dict, PyName::dict_ring(), next_dict);
+}
+
+static inline void setSelectId(PyObject *dict, PyObject *select_id)
+{
+ PyObject_SetAttr(dict, PyName::select_id(), select_id);
+}
+
+static inline PyObject *getSelectId(PyObject *dict)
+{
+ auto select_id = PyObject_GetAttr(dict, PyName::select_id());
+ return select_id;
+}
+
+static inline void setCurrentSelectId(PyTypeObject *type, PyObject *select_id)
+{
+ SbkObjectType_SetReserved(type, PyInt_AsSsize_t(select_id)); // int/long cheating
+}
+
+static inline void setCurrentSelectId(PyTypeObject *type, int id)
+{
+ SbkObjectType_SetReserved(type, id);
+}
+
+static inline PyObject *getCurrentSelectId(PyTypeObject *type)
+{
+ int id = SbkObjectType_GetReserved(type);
+ // This can be too early.
+ if (id < 0)
+ id = 0;
+ return fast_id_array[id];
+}
+
+static bool replaceClassDict(PyTypeObject *type)
+{
+ /*
+ * Replace the type dict by the derived ChameleonDict.
+ * This is mandatory for all type dicts when they are touched.
+ */
+ ensureNewDictType();
+ PyObject *dict = type->tp_dict;
+ auto ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
+ PyObject *new_dict = PyObject_CallObject(ob_ndt, nullptr);
+ if (new_dict == nullptr || PyDict_Update(new_dict, dict) < 0)
+ return false;
+ // Insert the default id. Cannot fail for small numbers.
+ AutoDecRef select_id(PyInt_FromLong(0));
+ setSelectId(new_dict, select_id);
+ // insert the dict into itself as ring
+ setNextDict(new_dict, new_dict);
+ // We have now an exact copy of the dict with a new type.
+ // Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py)
+ Py_DECREF(type->tp_dict);
+ type->tp_dict = new_dict;
+ return true;
+}
+
+static bool addNewDict(PyTypeObject *type, PyObject *select_id)
+{
+ /*
+ * Add a new dict to the ring and set it as `type->tp_dict`.
+ * A 'false' return is fatal.
+ */
+ auto dict = type->tp_dict;
+ auto ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
+ auto new_dict = PyObject_CallObject(ob_ndt, nullptr);
+ if (new_dict == nullptr)
+ return false;
+ setSelectId(new_dict, select_id);
+ // insert the dict into the ring
+ auto next_dict = nextInCircle(dict);
+ setNextDict(dict, new_dict);
+ setNextDict(new_dict, next_dict);
+ type->tp_dict = new_dict;
+ return true;
+}
+
+static bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
+{
+ /*
+ * Rotate the ring to the given `select_id` and return `true`.
+ * If not found, stay at the current position and return `false`.
+ */
+ auto initial_dict = type->tp_dict;
+ auto dict = initial_dict;
+ do {
+ dict = nextInCircle(dict);
+ AutoDecRef current_id(getSelectId(dict));
+ // This works because small numbers are singleton objects.
+ if (current_id == select_id) {
+ type->tp_dict = dict;
+ setCurrentSelectId(type, select_id);
+ return true;
+ }
+ } while (dict != initial_dict);
+ type->tp_dict = initial_dict;
+ return false;
+}
+
+static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
+{
+ /*
+ * Create a new feature set.
+ * A `false` return value is a fatal error.
+ *
+ * A FeatureProc sees an empty `type->tp_dict` and the previous dict
+ * content in `prev_dict`. It is responsible of filling `type->tp_dict`
+ * with modified content.
+ */
+ static auto small_1 = PyInt_FromLong(255);
+ Q_UNUSED(small_1);
+ static auto small_2 = PyInt_FromLong(255);
+ Q_UNUSED(small_2);
+ // make sure that small integers are cached
+ assert(small_1 != nullptr && small_1 == small_2);
+
+ static auto zero = fast_id_array[0];
+ bool ok = moveToFeatureSet(type, zero);
+ Q_UNUSED(ok);
+ assert(ok);
+
+ AutoDecRef prev_dict(type->tp_dict);
+ Py_INCREF(prev_dict); // keep the first ref unchanged
+ if (!addNewDict(type, select_id))
+ return false;
+ auto id = PyInt_AsSsize_t(select_id); // int/long cheating
+ if (id == -1)
+ return false;
+ setCurrentSelectId(type, id);
+ FeatureProc *proc = featurePointer;
+ for (int idx = id; *proc != nullptr; ++proc, idx >>= 1) {
+ if (idx & 1) {
+ // clear the tp_dict that will get new content
+ PyDict_Clear(type->tp_dict);
+ // let the proc re-fill the tp_dict
+ if (!(*proc)(type, prev_dict, id))
+ return false;
+ // if there is still a step, prepare `prev_dict`
+ if (idx >> 1) {
+ prev_dict.reset(PyDict_Copy(type->tp_dict));
+ if (prev_dict.isNull())
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_id)
+{
+ /*
+ * This is the selector for one sublass. We need to call this for
+ * every subclass until no more subclasses or reaching the wanted id.
+ */
+ if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
+ // On first touch, we initialize the dynamic naming.
+ // The dict type will be replaced after the first call.
+ if (!replaceClassDict(type)) {
+ Py_FatalError("failed to replace class dict!");
+ return false;
+ }
+ }
+ if (!moveToFeatureSet(type, select_id)) {
+ if (!createNewFeatureSet(type, select_id)) {
+ Py_FatalError("failed to create a new feature set!");
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline PyObject *SelectFeatureSet(PyTypeObject *type)
+{
+ /*
+ * This is the main function of the module.
+ * The purpose of this function is to switch the dict of a class right
+ * before a (get|set)attro call is performed.
+ *
+ * Generated functions call this directly.
+ * Shiboken will assign it via a public hook of `basewrapper.cpp`.
+ */
+ if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
+ // We initialize the dynamic features by using our own dict type.
+ if (!replaceClassDict(type))
+ return nullptr;
+ }
+ PyObject *select_id = getFeatureSelectId(); // borrowed
+ PyObject *current_id = getCurrentSelectId(type); // borrowed
+ static PyObject *undef = fast_id_array[-1];
+
+ // PYSIDE-1019: During import PepType_SOTP is still zero.
+ if (current_id == undef)
+ current_id = select_id = fast_id_array[0];
+
+ if (select_id != current_id) {
+ PyObject *mro = type->tp_mro;
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ // We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2".
+ for (idx = 0; idx < n - 2; idx++) {
+ auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ // When any subtype is already resolved (false), we can stop.
+ if (!SelectFeatureSetSubtype(sub_type, select_id))
+ break;
+ }
+ }
+ return type->tp_dict;
+}
+
+// For cppgenerator:
+void Select(PyObject *obj)
+{
+ if (featurePointer == nullptr)
+ return;
+ auto type = Py_TYPE(obj);
+ type->tp_dict = SelectFeatureSet(type);
+}
+
+PyObject *Select(PyTypeObject *type)
+{
+ if (featurePointer != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+ return type->tp_dict;
+}
+
+static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_04_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_08_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_10_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_20_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_40_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
+static bool feature_80_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
+
+static FeatureProc featureProcArray[] = {
+ feature_01_addLowerNames,
+ feature_02_true_property,
+ feature_04_addDummyNames,
+ feature_08_addDummyNames,
+ feature_10_addDummyNames,
+ feature_20_addDummyNames,
+ feature_40_addDummyNames,
+ feature_80_addDummyNames,
+ nullptr
+};
+
+void finalize()
+{
+ for (int idx = -1; idx < 256; ++idx)
+ Py_DECREF(fast_id_array[idx]);
+}
+
+static bool patch_property_impl();
+
+void init()
+{
+ // This function can be called multiple times.
+ static bool is_initialized = false;
+ if (!is_initialized) {
+ fast_id_array = &_fast_id_array[1];
+ for (int idx = -1; idx < 256; ++idx)
+ fast_id_array[idx] = PyInt_FromLong(idx);
+ last_select_id = fast_id_array[0];
+ featurePointer = featureProcArray;
+ initSelectableFeature(SelectFeatureSet);
+ registerCleanupFunction(finalize);
+ patch_property_impl();
+ PySide::ClassProperty::init();
+ is_initialized = true;
+ }
+ // Reset the cache. This is called at any "from __feature__ import".
+ cached_globals = nullptr;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Support switchable extensions
+//
+// Feature 0x01: Allow snake_case instead of camelCase
+//
+// This functionality is no longer implemented in the signature module, since
+// the PyCFunction getsets do not have to be modified any longer.
+// Instead, we simply exchange the complete class dicts. This is done in the
+// basewrapper.cpp file.
+//
+
+static PyObject *methodWithNewName(PyTypeObject *type,
+ PyMethodDef *meth,
+ const char *new_name)
+{
+ /*
+ * Create a method with a lower case name.
+ */
+ auto obtype = reinterpret_cast<PyObject *>(type);
+ int len = strlen(new_name);
+ auto name = new char[len + 1];
+ strcpy(name, new_name);
+ auto new_meth = new PyMethodDef;
+ new_meth->ml_name = name;
+ new_meth->ml_meth = meth->ml_meth;
+ new_meth->ml_flags = meth->ml_flags;
+ new_meth->ml_doc = meth->ml_doc;
+ PyObject *descr = nullptr;
+ if (new_meth->ml_flags & METH_STATIC) {
+ AutoDecRef cfunc(PyCFunction_NewEx(new_meth, obtype, nullptr));
+ if (cfunc.isNull())
+ return nullptr;
+ descr = PyStaticMethod_New(cfunc);
+ }
+ else {
+ descr = PyDescr_NewMethod(type, new_meth);
+ }
+ return descr;
+}
+
+static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id)
+{
+ /*
+ * Add objects with lower names to `type->tp_dict` from 'prev_dict`.
+ */
+ PyObject *lower_dict = type->tp_dict;
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ // We first copy the things over which will not be changed:
+ while (PyDict_Next(prev_dict, &pos, &key, &value)) {
+ if ( Py_TYPE(value) != PepMethodDescr_TypePtr
+ && Py_TYPE(value) != PepStaticMethod_TypePtr) {
+ if (PyDict_SetItem(lower_dict, key, value))
+ return false;
+ continue;
+ }
+ }
+ // Then we walk over the tp_methods to get all methods and insert
+ // them with changed names.
+ PyMethodDef *meth = type->tp_methods;
+ if (!meth)
+ return true;
+
+ for (; meth != nullptr && meth->ml_name != nullptr; ++meth) {
+ const char *name = String::toCString(String::getSnakeCaseName(meth->ml_name, true));
+ AutoDecRef new_method(methodWithNewName(type, meth, name));
+ if (new_method.isNull())
+ return false;
+ if (PyDict_SetItemString(lower_dict, name, new_method) < 0)
+ return false;
+ }
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Support switchable extensions
+//
+// Feature 0x02: Use true properties instead of getters and setters
+//
+
+// This is the Python 2 version for inspection of m_ml, only.
+// The actual Python 3 version is larget.
+
+typedef struct {
+ PyObject_HEAD
+ PyMethodDef *m_ml; /* Description of the C function to call */
+ PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
+ PyObject *m_module; /* The __module__ attribute, can be anything */
+} PyCFunctionObject;
+
+static PyObject *modifyStaticToClassMethod(PyTypeObject *type, PyObject *sm)
+{
+ AutoDecRef func_ob(PyObject_GetAttr(sm, PyMagicName::func()));
+ if (func_ob.isNull())
+ return nullptr;
+ auto func = reinterpret_cast<PyCFunctionObject *>(func_ob.object());
+ auto new_func = new PyMethodDef;
+ new_func->ml_name = func->m_ml->ml_name;
+ new_func->ml_meth = func->m_ml->ml_meth;
+ new_func->ml_flags = (func->m_ml->ml_flags & ~METH_STATIC) | METH_CLASS;
+ new_func->ml_doc = func->m_ml->ml_doc;
+ auto cfunc = PyCFunction_NewEx(new_func, nullptr, nullptr);
+ cfunc = PyDescr_NewClassMethod(type, new_func);
+ return cfunc;
+}
+
+static PyObject *createProperty(PyTypeObject *type, PyObject *getter, PyObject *setter)
+{
+ bool chassprop = false;
+ assert(getter != nullptr);
+ if (setter == nullptr)
+ setter = Py_None;
+ auto ptype = &PyProperty_Type;
+ if (Py_TYPE(getter) == PepStaticMethod_TypePtr) {
+ ptype = PyClassPropertyTypeF();
+ chassprop = true;
+ getter = modifyStaticToClassMethod(type, getter);
+ if (setter != Py_None)
+ setter = modifyStaticToClassMethod(type, setter);
+ }
+ auto obtype = reinterpret_cast<PyObject *>(ptype);
+ PyObject *prop = PyObject_CallFunctionObjArgs(obtype, getter, setter, nullptr);
+ return prop;
+}
+
+static QStringList parseFields(const char *propstr)
+{
+ /*
+ * Break the string into subfields at ':' and add defaults.
+ */
+ QString s = QString(QLatin1String(propstr));
+ auto list = s.split(QLatin1Char(':'));
+ assert(list.size() == 2 || list.size() == 3);
+ auto name = list[0];
+ auto read = list[1];
+ if (read.size() == 0)
+ list[1] = name;
+ if (list.size() == 2)
+ return list;
+ auto write = list[2];
+ if (write.size() == 0) {
+ list[2] = QLatin1String("set") + name;
+ list[2][3] = list[2][3].toUpper();
+ }
+ return list;
+}
+
+static PyObject *make_snake_case(QString s, bool lower)
+{
+ if (s.isNull())
+ return nullptr;
+ return String::getSnakeCaseName(s.toLatin1().data(), lower);
+}
+
+static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id)
+{
+ /*
+ * Use the property info to create true Python property objects.
+ */
+
+ // The empty `tp_dict` gets populated by the previous dict.
+ PyObject *prop_dict = type->tp_dict;
+ if (PyDict_Update(prop_dict, prev_dict) < 0)
+ return false;
+
+ // We then replace methods by properties.
+ bool lower = (id & 0x01) != 0;
+ auto props = SbkObjectType_GetPropertyStrings(type);
+ if (props == nullptr || *props == nullptr)
+ return true;
+ for (; *props != nullptr; ++props) {
+ auto propstr = *props;
+ auto fields = parseFields(propstr);
+ bool haveWrite = fields.size() == 3;
+ PyObject *name = make_snake_case(fields[0], lower);
+ PyObject *read = make_snake_case(fields[1], lower);
+ PyObject *write = haveWrite ? make_snake_case(fields[2], lower) : nullptr;
+ PyObject *getter = PyDict_GetItem(prev_dict, read);
+ if (getter == nullptr || !(Py_TYPE(getter) == PepMethodDescr_TypePtr ||
+ Py_TYPE(getter) == PepStaticMethod_TypePtr))
+ continue;
+ PyObject *setter = haveWrite ? PyDict_GetItem(prev_dict, write) : nullptr;
+
+ AutoDecRef PyProperty(createProperty(type, getter, setter));
+ if (PyProperty.isNull())
+ return false;
+ if (PyDict_SetItem(prop_dict, name, PyProperty) < 0)
+ return false;
+ if (fields[0] != fields[1] && PyDict_GetItem(prop_dict, read))
+ if (PyDict_DelItem(prop_dict, read) < 0)
+ return false;
+ // Theoretically, we need to check for multiple signatures to be exact.
+ // But we don't do so intentionally because it would be confusing.
+ if (haveWrite && PyDict_GetItem(prop_dict, write))
+ if (PyDict_DelItem(prop_dict, write) < 0)
+ return false;
+ }
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// These are a number of patches to make Python's property object better
+// suitable for us.
+// We turn `__doc__` into a lazy attribute saving signature initialization.
+//
+// There is now also a class property implementation which inherits
+// from this one.
+//
+
+static PyObject *property_doc_get(PyObject *self, void *)
+{
+ auto po = reinterpret_cast<propertyobject *>(self);
+
+ if (po->prop_doc != nullptr && po->prop_doc != Py_None) {
+ Py_INCREF(po->prop_doc);
+ return po->prop_doc;
+ }
+ if (po->prop_get) {
+ // PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
+ auto txt = PyObject_GetAttr(po->prop_get, PyMagicName::doc());
+ if (txt != nullptr) {
+ Py_INCREF(txt);
+ po->prop_doc = txt;
+ Py_INCREF(txt);
+ return txt;
+ }
+ PyErr_Clear();
+ }
+ Py_RETURN_NONE;
+}
+
+static int property_doc_set(PyObject *self, PyObject *value, void *)
+{
+ auto po = reinterpret_cast<propertyobject *>(self);
+
+ Py_INCREF(value);
+ po->prop_doc = value;
+ return 0;
+}
+
+static PyGetSetDef property_getset[] = {
+ // This gets added to the existing getsets
+ {const_cast<char *>("__doc__"), property_doc_get, property_doc_set, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static bool patch_property_impl()
+{
+ // Turn `__doc__` into a computed attribute without changing writability.
+ auto gsp = property_getset;
+ auto type = &PyProperty_Type;
+ auto dict = type->tp_dict;
+ AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+ if (descr.isNull())
+ return false;
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ return false;
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Support switchable extensions
+//
+// Feature 0x04..0x40: A fake switchable option for testing
+//
+
+#define SIMILAR_FEATURE(xx) \
+static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id) \
+{ \
+ PyObject *dict = type->tp_dict; \
+ if (PyDict_Update(dict, prev_dict) < 0) \
+ return false; \
+ if (PyDict_SetItemString(dict, "fake_feature_" #xx, Py_None) < 0) \
+ return false; \
+ return true; \
+}
+
+SIMILAR_FEATURE(04)
+SIMILAR_FEATURE(08)
+SIMILAR_FEATURE(10)
+SIMILAR_FEATURE(20)
+SIMILAR_FEATURE(40)
+SIMILAR_FEATURE(80)
+
+} // namespace PySide
+} // namespace Feature
diff --git a/sources/pyside6/libpyside/feature_select.h b/sources/pyside6/libpyside/feature_select.h
new file mode 100644
index 000000000..845828a4c
--- /dev/null
+++ b/sources/pyside6/libpyside/feature_select.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 FEATURE_SELECT_H
+#define FEATURE_SELECT_H
+
+#include "pysidemacros.h"
+#include <sbkpython.h>
+
+namespace PySide {
+namespace Feature {
+
+PYSIDE_API void init();
+PYSIDE_API void Select(PyObject *obj);
+PYSIDE_API PyObject *Select(PyTypeObject *type);
+
+} // namespace Feature
+} // namespace PySide
+
+#endif // FEATURE_SELECT_H
diff --git a/sources/pyside6/libpyside/globalreceiverv2.cpp b/sources/pyside6/libpyside/globalreceiverv2.cpp
new file mode 100644
index 000000000..72197fe51
--- /dev/null
+++ b/sources/pyside6/libpyside/globalreceiverv2.cpp
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "globalreceiverv2.h"
+#include "dynamicqmetaobject_p.h"
+#include "pysideweakref.h"
+#include "signalmanager.h"
+
+#include <autodecref.h>
+#include <gilstate.h>
+
+#include <QtCore/QMetaMethod>
+#include <QtCore/QSet>
+
+#define RECEIVER_DESTROYED_SLOT_NAME "__receiverDestroyed__(QObject*)"
+
+namespace
+{
+ static int DESTROY_SIGNAL_ID = 0;
+ static int DESTROY_SLOT_ID = 0;
+}
+
+namespace PySide
+{
+class DynamicSlotDataV2
+{
+ Q_DISABLE_COPY(DynamicSlotDataV2)
+ public:
+ DynamicSlotDataV2(PyObject *callback, GlobalReceiverV2 *parent);
+ ~DynamicSlotDataV2();
+
+ int addSlot(const char *signature);
+ int id(const char *signature) const;
+ PyObject *callback();
+ QByteArray hash() const;
+ void notify();
+
+ static void onCallbackDestroyed(void *data);
+ static QByteArray hash(PyObject *callback);
+
+
+ private:
+ bool m_isMethod;
+ PyObject *m_callback;
+ PyObject *m_pythonSelf;
+ PyObject *m_pyClass;
+ PyObject *m_weakRef;
+ QMap<QByteArray, int> m_signatures;
+ GlobalReceiverV2 *m_parent;
+ QByteArray m_hash;
+};
+
+}
+
+using namespace PySide;
+
+DynamicSlotDataV2::DynamicSlotDataV2(PyObject *callback, GlobalReceiverV2 *parent)
+ : m_pythonSelf(0), m_pyClass(0), m_weakRef(0), m_parent(parent)
+{
+ Shiboken::GilState gil;
+
+ m_isMethod = PyMethod_Check(callback);
+ if (m_isMethod) {
+ //Can not store calback pointe because this will be destroyed at the end of the scope
+ //To avoid increment intance reference keep the callback information
+ m_callback = PyMethod_GET_FUNCTION(callback);
+ m_pythonSelf = PyMethod_GET_SELF(callback);
+
+ //monitor class from method lifetime
+ m_weakRef = WeakRef::create(m_pythonSelf, DynamicSlotDataV2::onCallbackDestroyed, this);
+
+ m_hash = QByteArray::number((qlonglong)PyObject_Hash(m_callback))
+ + QByteArray::number((qlonglong)PyObject_Hash(m_pythonSelf));
+
+ } else {
+ m_callback = callback;
+ Py_INCREF(m_callback);
+
+ m_hash = QByteArray::number((qlonglong)PyObject_Hash(m_callback));
+ }
+}
+
+QByteArray DynamicSlotDataV2::hash() const
+{
+ return m_hash;
+}
+
+QByteArray DynamicSlotDataV2::hash(PyObject *callback)
+{
+ Shiboken::GilState gil;
+ if (PyMethod_Check(callback)) {
+ return QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_FUNCTION(callback)))
+ + QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_SELF(callback)));
+ }
+ return QByteArray::number(qlonglong(PyObject_Hash(callback)));
+}
+
+PyObject *DynamicSlotDataV2::callback()
+{
+ PyObject *callback = m_callback;
+
+ //create a callback based on method data
+ if (m_isMethod)
+ callback = PyMethod_New(m_callback, m_pythonSelf);
+ else
+ Py_INCREF(callback);
+
+ return callback;
+}
+
+int DynamicSlotDataV2::id(const char *signature) const
+{
+ const auto it = m_signatures.constFind(signature);
+ return it != m_signatures.cend() ? it.value() : -1;
+}
+
+int DynamicSlotDataV2::addSlot(const char *signature)
+{
+ int index = id(signature);
+ if (index == -1)
+ index = m_signatures[signature] = m_parent->metaObjectBuilder().addSlot(signature);
+ return index;
+}
+
+void DynamicSlotDataV2::onCallbackDestroyed(void *data)
+{
+ auto self = reinterpret_cast<DynamicSlotDataV2 *>(data);
+ self->m_weakRef = 0;
+ Py_BEGIN_ALLOW_THREADS
+ delete self->m_parent;
+ Py_END_ALLOW_THREADS
+}
+
+DynamicSlotDataV2::~DynamicSlotDataV2()
+{
+ Shiboken::GilState gil;
+
+ Py_XDECREF(m_weakRef);
+ m_weakRef = 0;
+
+ if (!m_isMethod)
+ Py_DECREF(m_callback);
+}
+
+GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) :
+ QObject(nullptr),
+ m_metaObject("__GlobalReceiver__", &QObject::staticMetaObject),
+ m_sharedMap(std::move(map))
+{
+ m_data = new DynamicSlotDataV2(callback, this);
+ m_metaObject.addSlot(RECEIVER_DESTROYED_SLOT_NAME);
+ m_metaObject.update();
+ m_refs.append(NULL);
+
+
+ if (DESTROY_SIGNAL_ID == 0)
+ DESTROY_SIGNAL_ID = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+
+ if (DESTROY_SLOT_ID == 0)
+ DESTROY_SLOT_ID = m_metaObject.indexOfMethod(QMetaMethod::Slot, RECEIVER_DESTROYED_SLOT_NAME);
+
+
+}
+
+GlobalReceiverV2::~GlobalReceiverV2()
+{
+ m_refs.clear();
+ // Remove itself from map.
+ m_sharedMap->remove(m_data->hash());
+ // Suppress handling of destroyed() for objects whose last reference is contained inside
+ // the callback object that will now be deleted. The reference could be a default argument,
+ // a callback local variable, etc.
+ // The signal has to be suppressed because it would lead to the following situation:
+ // Callback is deleted, hence the last reference is decremented,
+ // leading to the object being deleted, which emits destroyed(), which would try to invoke
+ // the already deleted callback, and also try to delete the object again.
+ DynamicSlotDataV2 *data = m_data;
+ m_data = Q_NULLPTR;
+ delete data;
+}
+
+int GlobalReceiverV2::addSlot(const char *signature)
+{
+ return m_data->addSlot(signature);
+}
+
+void GlobalReceiverV2::incRef(const QObject *link)
+{
+ if (link) {
+ if (!m_refs.contains(link)) {
+ bool connected;
+ Py_BEGIN_ALLOW_THREADS
+ connected = QMetaObject::connect(link, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
+ Py_END_ALLOW_THREADS
+ if (connected)
+ m_refs.append(link);
+ else
+ Q_ASSERT(false);
+ } else {
+ m_refs.append(link);
+ }
+ } else {
+ m_refs.append(NULL);
+ }
+}
+
+void GlobalReceiverV2::decRef(const QObject *link)
+{
+ if (m_refs.empty())
+ return;
+
+
+ m_refs.removeOne(link);
+ if (link) {
+ if (!m_refs.contains(link)) {
+ bool result;
+ Py_BEGIN_ALLOW_THREADS
+ result = QMetaObject::disconnect(link, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
+ Py_END_ALLOW_THREADS
+ Q_ASSERT(result);
+ if (!result)
+ return;
+ }
+ }
+
+ if (m_refs.empty())
+ Py_BEGIN_ALLOW_THREADS
+ delete this;
+ Py_END_ALLOW_THREADS
+
+}
+
+int GlobalReceiverV2::refCount(const QObject *link) const
+{
+ if (link)
+ return m_refs.count(link);
+
+ return m_refs.size();
+}
+
+void GlobalReceiverV2::notify()
+{
+ const QSet<const QObject *> objSet(m_refs.cbegin(), m_refs.cend());
+ Py_BEGIN_ALLOW_THREADS
+ for (const QObject *o : objSet) {
+ QMetaObject::disconnect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
+ QMetaObject::connect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
+ }
+ Py_END_ALLOW_THREADS
+}
+
+QByteArray GlobalReceiverV2::hash() const
+{
+ return m_data->hash();
+}
+
+QByteArray GlobalReceiverV2::hash(PyObject *callback)
+{
+ return DynamicSlotDataV2::hash(callback);
+}
+
+const QMetaObject *GlobalReceiverV2::metaObject() const
+{
+ return const_cast<GlobalReceiverV2 *>(this)->m_metaObject.update();
+}
+
+int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void **args)
+{
+ Shiboken::GilState gil;
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+ Q_ASSERT(id >= QObject::staticMetaObject.methodCount());
+
+ QMetaMethod slot = metaObject()->method(id);
+ Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
+
+ if (!m_data) {
+ if (id != DESTROY_SLOT_ID) {
+ const QByteArray message = "PySide6 Warning: Skipping callback call "
+ + slot.methodSignature() + " because the callback object is being destructed.";
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0);
+ }
+ return -1;
+ }
+
+ if (id == DESTROY_SLOT_ID) {
+ if (m_refs.empty())
+ return -1;
+ auto obj = *reinterpret_cast<QObject **>(args[1]);
+ incRef(); //keep the object live (safe ref)
+ m_refs.removeAll(obj); // remove all refs to this object
+ decRef(); //remove the safe ref
+ } else {
+ bool isShortCuit = (strstr(slot.methodSignature(), "(") == 0);
+ Shiboken::AutoDecRef callback(m_data->callback());
+ SignalManager::callPythonMetaMethod(slot, args, callback, isShortCuit);
+ }
+
+ // SignalManager::callPythonMetaMethod might have failed, in that case we have to print the
+ // error so it considered "handled".
+ if (PyErr_Occurred()) {
+ int reclimit = Py_GetRecursionLimit();
+ // Inspired by Python's errors.c: PyErr_GivenExceptionMatches() function.
+ // Temporarily bump the recursion limit, so that PyErr_Print will not raise a recursion
+ // error again. Don't do it when the limit is already insanely high, to avoid overflow.
+ if (reclimit < (1 << 30))
+ Py_SetRecursionLimit(reclimit + 5);
+ PyErr_Print();
+ Py_SetRecursionLimit(reclimit);
+ }
+
+ return -1;
+}
diff --git a/sources/pyside6/libpyside/globalreceiverv2.h b/sources/pyside6/libpyside/globalreceiverv2.h
new file mode 100644
index 000000000..433f587a9
--- /dev/null
+++ b/sources/pyside6/libpyside/globalreceiverv2.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 GLOBALRECEIVER_V2_H
+#define GLOBALRECEIVER_V2_H
+
+#include <sbkpython.h>
+
+#include "dynamicqmetaobject.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QSharedPointer>
+
+namespace PySide
+{
+
+class DynamicSlotDataV2;
+class GlobalReceiverV2;
+
+typedef QMap<QByteArray, GlobalReceiverV2 *> GlobalReceiverV2Map;
+typedef QSharedPointer<GlobalReceiverV2Map> SharedMap;
+
+/**
+ * A class used to make the link between the C++ Signal/Slot and Python callback
+ * This class is used internally by SignalManager
+ **/
+
+class GlobalReceiverV2 : public QObject
+{
+public:
+ /**
+ * Create a GlobalReceiver object that will call 'callback' argumentent
+ *
+ * @param callback A Python callable object (can be a method or not)
+ * @param ma A SharedPointer used on Signal manager that contains all instaces of GlobalReceiver
+ **/
+ GlobalReceiverV2(PyObject *callback, SharedMap map);
+
+ /**
+ * Destructor
+ **/
+ ~GlobalReceiverV2() override;
+
+ /**
+ * Reimplemented function from QObject
+ **/
+ int qt_metacall(QMetaObject::Call call, int id, void **args) override;
+ const QMetaObject *metaObject() const override;
+
+ /**
+ * Add a extra slot to this object
+ *
+ * @param signature The signature of the slot to be added
+ * @return The index of this slot on metaobject
+ **/
+ int addSlot(const char *signature);
+
+ /**
+ * Notify to GlobalReceiver about when a new connection was made
+ **/
+ void notify();
+
+ /**
+ * Used to increment the reference of the GlobalReceiver object
+ *
+ * @param link This is a optional paramenter used to link the ref to some QObject life
+ **/
+ void incRef(const QObject *link = nullptr);
+
+ /**
+ * Used to decrement the reference of the GlobalReceiver object
+ *
+ * @param link This is a optional paramenter used to dismiss the link ref to some QObject
+ **/
+ void decRef(const QObject *link = nullptr);
+
+ /*
+ * Return the count of refs which the GlobalReceiver has
+ *
+ * @param link If any QObject was passed, the function return the number of references relative to this 'link' object
+ * @return The number of references
+ **/
+ int refCount(const QObject *link) const;
+
+ /**
+ * Use to retrieve the unique hash of this GlobalReceiver object
+ *
+ * @return a string with a unique id based on GlobalReceiver contents
+ **/
+ QByteArray hash() const;
+
+ /**
+ * Use to retrieve the unique hash of the PyObject based on GlobalReceiver rules
+ *
+ * @param callback The Python callable object used to calculate the id
+ * @return a string with a unique id based on GlobalReceiver contents
+ **/
+ static QByteArray hash(PyObject *callback);
+
+ const MetaObjectBuilder &metaObjectBuilder() const { return m_metaObject; }
+ MetaObjectBuilder &metaObjectBuilder() { return m_metaObject; }
+
+private:
+ MetaObjectBuilder m_metaObject;
+ DynamicSlotDataV2 *m_data;
+ QList<const QObject *> m_refs;
+ SharedMap m_sharedMap;
+};
+
+}
+
+#endif
diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp
new file mode 100644
index 000000000..3eca161fd
--- /dev/null
+++ b/sources/pyside6/libpyside/pyside.cpp
@@ -0,0 +1,616 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "pyside.h"
+#include "pyside_p.h"
+#include "signalmanager.h"
+#include "pysideclassinfo_p.h"
+#include "pysideproperty_p.h"
+#include "pysideproperty.h"
+#include "pysidesignal.h"
+#include "pysidesignal_p.h"
+#include "pysidestaticstrings.h"
+#include "pysideslot_p.h"
+#include "pysidemetafunction_p.h"
+#include "pysidemetafunction.h"
+#include "dynamicqmetaobject.h"
+
+#include <autodecref.h>
+#include <basewrapper.h>
+#include <bindingmanager.h>
+#include <gilstate.h>
+#include <sbkconverter.h>
+#include <sbkstring.h>
+#include <sbkstaticstrings.h>
+#include <qapp_macro.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStack>
+
+#include <algorithm>
+#include <cstring>
+#include <cctype>
+#include <typeinfo>
+
+static QStack<PySide::CleanupFunction> cleanupFunctionList;
+static void *qobjectNextAddr;
+
+QT_BEGIN_NAMESPACE
+extern bool qRegisterResourceData(int, const unsigned char *, const unsigned char *,
+ const unsigned char *);
+QT_END_NAMESPACE
+
+namespace PySide
+{
+
+void init(PyObject *module)
+{
+ qobjectNextAddr = 0;
+ ClassInfo::init(module);
+ Signal::init(module);
+ Slot::init(module);
+ Property::init(module);
+ MetaFunction::init(module);
+ // Init signal manager, so it will register some meta types used by QVariant.
+ SignalManager::instance();
+ initQApp();
+}
+
+static bool _setProperty(PyObject *qObj, PyObject *name, PyObject *value, bool *accept)
+{
+ QByteArray propName(Shiboken::String::toCString(name));
+ propName[0] = std::toupper(propName[0]);
+ propName.prepend("set");
+
+ Shiboken::AutoDecRef propSetter(PyObject_GetAttrString(qObj, propName.constData()));
+ if (!propSetter.isNull()) {
+ *accept = true;
+ Shiboken::AutoDecRef args(PyTuple_Pack(1, value));
+ Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args));
+ if (retval.isNull())
+ return false;
+ } else {
+ PyErr_Clear();
+ Shiboken::AutoDecRef attr(PyObject_GenericGetAttr(qObj, name));
+ if (PySide::Property::checkType(attr)) {
+ *accept = true;
+ if (PySide::Property::setValue(reinterpret_cast<PySideProperty *>(attr.object()), qObj, value) < 0)
+ return false;
+ }
+ }
+ return true;
+}
+
+bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds, const char **blackList, unsigned int blackListSize)
+{
+
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(kwds, &pos, &key, &value)) {
+ if (!blackListSize || !std::binary_search(blackList, blackList + blackListSize, std::string(Shiboken::String::toCString(key)))) {
+ QByteArray propName(Shiboken::String::toCString(key));
+ bool accept = false;
+ if (metaObj->indexOfProperty(propName) != -1) {
+ if (!_setProperty(qObj, key, value, &accept))
+ return false;
+ } else {
+ propName.append("()");
+ if (metaObj->indexOfSignal(propName) != -1) {
+ accept = true;
+ propName.prepend('2');
+ if (!PySide::Signal::connect(qObj, propName, value))
+ return false;
+ }
+ }
+ if (!accept) {
+ // PYSIDE-1019: Allow any existing attribute in the constructor.
+ if (!_setProperty(qObj, key, value, &accept))
+ return false;
+ }
+ if (!accept) {
+ PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal",
+ propName.constData());
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void registerCleanupFunction(CleanupFunction func)
+{
+ cleanupFunctionList.push(func);
+}
+
+void runCleanupFunctions()
+{
+ while (!cleanupFunctionList.isEmpty()) {
+ CleanupFunction f = cleanupFunctionList.pop();
+ f();
+ }
+}
+
+static void destructionVisitor(SbkObject *pyObj, void *data)
+{
+ auto realData = reinterpret_cast<void **>(data);
+ auto pyQApp = reinterpret_cast<SbkObject *>(realData[0]);
+ auto pyQObjectType = reinterpret_cast<PyTypeObject *>(realData[1]);
+
+ if (pyObj != pyQApp && PyObject_TypeCheck(pyObj, pyQObjectType)) {
+ if (Shiboken::Object::hasOwnership(pyObj) && Shiboken::Object::isValid(pyObj, false)) {
+ Shiboken::Object::setValidCpp(pyObj, false);
+
+ Py_BEGIN_ALLOW_THREADS
+ Shiboken::callCppDestructor<QObject>(Shiboken::Object::cppPointer(pyObj, pyQObjectType));
+ Py_END_ALLOW_THREADS
+ }
+ }
+
+};
+
+void destroyQCoreApplication()
+{
+ QCoreApplication *app = QCoreApplication::instance();
+ if (!app)
+ return;
+ SignalManager::instance().clear();
+
+ Shiboken::BindingManager &bm = Shiboken::BindingManager::instance();
+ SbkObject *pyQApp = bm.retrieveWrapper(app);
+ PyTypeObject *pyQObjectType = Shiboken::Conversions::getPythonTypeObject("QObject*");
+ assert(pyQObjectType);
+
+ void *data[2] = {pyQApp, pyQObjectType};
+ bm.visitAllPyObjects(&destructionVisitor, &data);
+
+ // in the end destroy app
+ // Allow threads because the destructor calls
+ // QThreadPool::globalInstance().waitForDone() which may deadlock on the GIL
+ // if there is a worker working with python objects.
+ Py_BEGIN_ALLOW_THREADS
+ delete app;
+ Py_END_ALLOW_THREADS
+ // PYSIDE-571: make sure to create a singleton deleted qApp.
+ Py_DECREF(MakeQAppWrapper(nullptr));
+}
+
+std::size_t getSizeOfQObject(SbkObjectType *type)
+{
+ return retrieveTypeUserData(type)->cppObjSize;
+}
+
+void initDynamicMetaObject(SbkObjectType *type, const QMetaObject *base, std::size_t cppObjSize)
+{
+ //create DynamicMetaObject based on python type
+ auto userData = new TypeUserData(reinterpret_cast<PyTypeObject *>(type), base, cppObjSize);
+ userData->mo.update();
+ Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>);
+
+ //initialize staticQMetaObject property
+ void *metaObjectPtr = const_cast<QMetaObject *>(userData->mo.update());
+ static SbkConverter *converter = Shiboken::Conversions::getConverter("QMetaObject");
+ if (!converter)
+ return;
+ Shiboken::AutoDecRef pyMetaObject(Shiboken::Conversions::pointerToPython(converter, metaObjectPtr));
+ PyObject_SetAttr(reinterpret_cast<PyObject *>(type),
+ PySide::PyName::qtStaticMetaObject(), pyMetaObject);
+}
+
+TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj)
+{
+ return reinterpret_cast<TypeUserData *>(Shiboken::ObjectType::getTypeUserData(sbkTypeObj));
+}
+
+TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj)
+{
+ return retrieveTypeUserData(reinterpret_cast<SbkObjectType *>(pyTypeObj));
+}
+
+TypeUserData *retrieveTypeUserData(PyObject *pyObj)
+{
+ auto pyTypeObj = PyType_Check(pyObj)
+ ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj);
+ return retrieveTypeUserData(pyTypeObj);
+}
+
+const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj)
+{
+ TypeUserData *userData = retrieveTypeUserData(pyTypeObj);
+ return userData ? userData->mo.update() : nullptr;
+}
+
+const QMetaObject *retrieveMetaObject(PyObject *pyObj)
+{
+ auto pyTypeObj = PyType_Check(pyObj)
+ ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj);
+ return retrieveMetaObject(pyTypeObj);
+}
+
+void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds */)
+{
+ PyTypeObject *qObjType = Shiboken::Conversions::getPythonTypeObject("QObject*");
+ QByteArray className(Shiboken::String::toCString(PyTuple_GET_ITEM(args, 0)));
+
+ PyObject *bases = PyTuple_GET_ITEM(args, 1);
+ int numBases = PyTuple_GET_SIZE(bases);
+
+ TypeUserData *userData = nullptr;
+
+ for (int i = 0; i < numBases; ++i) {
+ auto base = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, i));
+ if (PyType_IsSubtype(base, qObjType)) {
+ userData = retrieveTypeUserData(base);
+ break;
+ }
+ }
+ if (!userData) {
+ qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData());
+ return;
+ }
+ initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize);
+}
+
+void initQApp()
+{
+ /*
+ * qApp will not be initialized when embedding is active.
+ * That means that qApp exists already when PySide is initialized.
+ * We could solve that by creating a qApp variable, but in embedded
+ * mode, we also have the effect that the first assignment to qApp
+ * is persistent! Therefore, we can never be sure to have created
+ * qApp late enough to get the right type for the instance.
+ *
+ * I would appreciate very much if someone could explain or even fix
+ * this issue. It exists only when a pre-existing application exists.
+ */
+ if (!qApp)
+ Py_DECREF(MakeQAppWrapper(nullptr));
+}
+
+PyObject *getMetaDataFromQObject(QObject *cppSelf, PyObject *self, PyObject *name)
+{
+ PyObject *attr = PyObject_GenericGetAttr(self, name);
+ if (!Shiboken::Object::isValid(reinterpret_cast<SbkObject *>(self), false))
+ return attr;
+
+ if (attr && Property::checkType(attr)) {
+ PyObject *value = Property::getValue(reinterpret_cast<PySideProperty *>(attr), self);
+ Py_DECREF(attr);
+ if (!value)
+ return 0;
+ attr = value;
+ }
+
+ //mutate native signals to signal instance type
+ if (attr && PyObject_TypeCheck(attr, PySideSignalTypeF())) {
+ PyObject *signal = reinterpret_cast<PyObject *>(Signal::initialize(reinterpret_cast<PySideSignal *>(attr), name, self));
+ PyObject_SetAttr(self, name, reinterpret_cast<PyObject *>(signal));
+ return signal;
+ }
+
+ //search on metaobject (avoid internal attributes started with '__')
+ if (!attr) {
+ const char *cname = Shiboken::String::toCString(name);
+ uint cnameLen = qstrlen(cname);
+ if (std::strncmp("__", cname, 2)) {
+ const QMetaObject *metaObject = cppSelf->metaObject();
+ //signal
+ QList<QMetaMethod> signalList;
+ for(int i=0, i_max = metaObject->methodCount(); i < i_max; i++) {
+ QMetaMethod method = metaObject->method(i);
+ const QByteArray methSig_ = method.methodSignature();
+ const char *methSig = methSig_.constData();
+ bool methMacth = !std::strncmp(cname, methSig, cnameLen) && methSig[cnameLen] == '(';
+ if (methMacth) {
+ if (method.methodType() == QMetaMethod::Signal) {
+ signalList.append(method);
+ } else {
+ PySideMetaFunction *func = MetaFunction::newObject(cppSelf, i);
+ if (func) {
+ PyObject *result = reinterpret_cast<PyObject *>(func);
+ PyObject_SetAttr(self, name, result);
+ return result;
+ }
+ }
+ }
+ }
+ if (!signalList.empty()) {
+ PyObject *pySignal = reinterpret_cast<PyObject *>(Signal::newObjectFromMethod(self, signalList));
+ PyObject_SetAttr(self, name, pySignal);
+ return pySignal;
+ }
+ }
+ }
+ return attr;
+}
+
+bool inherits(PyTypeObject *objType, const char *class_name)
+{
+ if (strcmp(objType->tp_name, class_name) == 0)
+ return true;
+
+ PyTypeObject *base = objType->tp_base;
+ if (base == 0)
+ return false;
+
+ return inherits(base, class_name);
+}
+
+void *nextQObjectMemoryAddr()
+{
+ return qobjectNextAddr;
+}
+
+void setNextQObjectMemoryAddr(void *addr)
+{
+ qobjectNextAddr = addr;
+}
+
+} // namespace PySide
+
+// A QSharedPointer is used with a deletion function to invalidate a pointer
+// when the property value is cleared. This should be a QSharedPointer with
+// a void *pointer, but that isn't allowed
+typedef char any_t;
+Q_DECLARE_METATYPE(QSharedPointer<any_t>);
+
+namespace PySide
+{
+
+static void invalidatePtr(any_t *object)
+{
+ Shiboken::GilState state;
+
+ SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(object);
+ if (wrapper != NULL)
+ Shiboken::BindingManager::instance().releaseWrapper(wrapper);
+}
+
+static const char invalidatePropertyName[] = "_PySideInvalidatePtr";
+
+// PYSIDE-1214, when creating new wrappers for classes inheriting QObject but
+// not exposed to Python, try to find the best-matching (most-derived) Qt
+// class by walking up the meta objects.
+static const char *typeName(QObject *cppSelf)
+{
+ const char *typeName = typeid(*cppSelf).name();
+ if (!Shiboken::Conversions::getConverter(typeName)) {
+ for (auto metaObject = cppSelf->metaObject(); metaObject; metaObject = metaObject->superClass()) {
+ const char *name = metaObject->className();
+ if (Shiboken::Conversions::getConverter(name)) {
+ typeName = name;
+ break;
+ }
+ }
+ }
+ return typeName;
+}
+
+PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type)
+{
+ PyObject *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf));
+ if (pyOut) {
+ Py_INCREF(pyOut);
+ return pyOut;
+ }
+
+ // Setting the property will trigger an QEvent notification, which may call into
+ // code that creates the wrapper so only set the property if it isn't already
+ // set and check if it's created after the set call
+ QVariant existing = cppSelf->property(invalidatePropertyName);
+ if (!existing.isValid()) {
+ QSharedPointer<any_t> shared_with_del(reinterpret_cast<any_t *>(cppSelf), invalidatePtr);
+ cppSelf->setProperty(invalidatePropertyName, QVariant::fromValue(shared_with_del));
+ pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf));
+ if (pyOut) {
+ Py_INCREF(pyOut);
+ return pyOut;
+ }
+ }
+
+ pyOut = Shiboken::Object::newObject(sbk_type, cppSelf, false, false, typeName(cppSelf));
+
+ return pyOut;
+}
+
+#ifdef PYSIDE_QML_SUPPORT
+static QuickRegisterItemFunction quickRegisterItem;
+
+QuickRegisterItemFunction getQuickRegisterItemFunction()
+{
+ return quickRegisterItem;
+}
+
+void setQuickRegisterItemFunction(QuickRegisterItemFunction function)
+{
+ quickRegisterItem = function;
+}
+#endif // PYSIDE_QML_SUPPORT
+
+// Inspired by Shiboken::String::toCString;
+QString pyStringToQString(PyObject *str) {
+ if (str == Py_None)
+ return QString();
+
+ if (PyUnicode_Check(str)) {
+ const char *unicodeBuffer = _PepUnicode_AsString(str);
+ if (unicodeBuffer)
+ return QString::fromUtf8(unicodeBuffer);
+ }
+ if (PyBytes_Check(str)) {
+ const char *asciiBuffer = PyBytes_AS_STRING(str);
+ if (asciiBuffer)
+ return QString::fromLatin1(asciiBuffer);
+ }
+ return QString();
+}
+
+static const unsigned char qt_resource_name[] = {
+ // qt
+ 0x0,0x2,
+ 0x0,0x0,0x7,0x84,
+ 0x0,0x71,
+ 0x0,0x74,
+ // etc
+ 0x0,0x3,
+ 0x0,0x0,0x6c,0xa3,
+ 0x0,0x65,
+ 0x0,0x74,0x0,0x63,
+ // qt.conf
+ 0x0,0x7,
+ 0x8,0x74,0xa6,0xa6,
+ 0x0,0x71,
+ 0x0,0x74,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x66
+};
+
+static const unsigned char qt_resource_struct[] = {
+ // :
+ 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,
+ // :/qt
+ 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,
+ // :/qt/etc
+ 0x0,0x0,0x0,0xa,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3,
+ // :/qt/etc/qt.conf
+ 0x0,0x0,0x0,0x16,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0
+};
+
+bool registerInternalQtConf()
+{
+ // Guard to ensure single registration.
+#ifdef PYSIDE_QT_CONF_PREFIX
+ static bool registrationAttempted = false;
+#else
+ static bool registrationAttempted = true;
+#endif
+ static bool isRegistered = false;
+ if (registrationAttempted)
+ return isRegistered;
+ registrationAttempted = true;
+
+ // Support PyInstaller case when a qt.conf file might be provided next to the generated
+ // PyInstaller executable.
+ // This will disable the internal qt.conf which points to the PySide6 subdirectory (due to the
+ // subdirectory not existing anymore).
+ QString executablePath =
+ QString::fromWCharArray(Py_GetProgramFullPath());
+ QString appDirPath = QFileInfo(executablePath).absolutePath();
+ QString maybeQtConfPath = QDir(appDirPath).filePath(QStringLiteral("qt.conf"));
+ bool executableQtConfAvailable = QFileInfo::exists(maybeQtConfPath);
+ maybeQtConfPath = QDir::toNativeSeparators(maybeQtConfPath);
+
+ // Allow disabling the usage of the internal qt.conf. This is necessary for tests to work,
+ // because tests are executed before the package is installed, and thus the Prefix specified
+ // in qt.conf would point to a not yet existing location.
+ bool disableInternalQtConf =
+ qEnvironmentVariableIntValue("PYSIDE_DISABLE_INTERNAL_QT_CONF") > 0 ? true : false;
+ if (disableInternalQtConf || executableQtConfAvailable) {
+ registrationAttempted = true;
+ return false;
+ }
+
+ PyObject *pysideModule = PyImport_ImportModule("PySide6");
+ if (!pysideModule)
+ return false;
+
+ // Querying __file__ should be done only for modules that have finished their initialization.
+ // Thus querying for the top-level PySide6 package works for us whenever any Qt-wrapped module
+ // is loaded.
+ PyObject *pysideInitFilePath = PyObject_GetAttr(pysideModule, Shiboken::PyMagicName::file());
+ Py_DECREF(pysideModule);
+ if (!pysideInitFilePath)
+ return false;
+
+ QString initPath = pyStringToQString(pysideInitFilePath);
+ Py_DECREF(pysideInitFilePath);
+ if (initPath.isEmpty())
+ return false;
+
+ // pysideDir - absolute path to the directory containing the init file, which also contains
+ // the rest of the PySide6 modules.
+ // prefixPath - absolute path to the directory containing the installed Qt (prefix).
+ QDir pysideDir = QFileInfo(QDir::fromNativeSeparators(initPath)).absoluteDir();
+ QString setupPrefix;
+#ifdef PYSIDE_QT_CONF_PREFIX
+ setupPrefix = QStringLiteral(PYSIDE_QT_CONF_PREFIX);
+#endif
+ const QString prefixPathStr = pysideDir.absoluteFilePath(setupPrefix);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ const QByteArray prefixPath = prefixPathStr.toLocal8Bit();
+#else
+ // PYSIDE-972, QSettings used by QtCore uses Latin1
+ const QByteArray prefixPath = prefixPathStr.toLatin1();
+#endif
+
+ // rccData needs to be static, otherwise when it goes out of scope, the Qt resource system
+ // will point to invalid memory.
+ static QByteArray rccData = QByteArrayLiteral("[Paths]\nPrefix = ") + prefixPath
+#ifdef Q_OS_WIN
+ // LibraryExecutables needs to point to Prefix instead of ./bin because we don't
+ // currently conform to the Qt default directory layout on Windows. This is necessary
+ // for QtWebEngineCore to find the location of QtWebEngineProcess.exe.
+ + QByteArray("\nLibraryExecutables = ") + prefixPath
+#endif
+ ;
+ rccData.append('\n');
+
+ // The RCC data structure expects a 4-byte size value representing the actual data.
+ int size = rccData.size();
+
+ for (int i = 0; i < 4; ++i) {
+ rccData.prepend((size & 0xff));
+ size >>= 8;
+ }
+
+ const int version = 0x01;
+ isRegistered = qRegisterResourceData(version, qt_resource_struct, qt_resource_name,
+ reinterpret_cast<const unsigned char *>(
+ rccData.constData()));
+
+ return isRegistered;
+}
+
+
+
+} //namespace PySide
+
diff --git a/sources/pyside6/libpyside/pyside.h b/sources/pyside6/libpyside/pyside.h
new file mode 100644
index 000000000..e241ac74d
--- /dev/null
+++ b/sources/pyside6/libpyside/pyside.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_H
+#define PYSIDE_H
+
+#include <sbkpython.h>
+
+#include <pysidemacros.h>
+
+#ifdef PYSIDE_QML_SUPPORT
+# include <QtQml/qqml.h>
+#endif
+
+#include <QtCore/QMetaType>
+#include <QtCore/QHash>
+
+struct SbkObjectType;
+
+namespace PySide
+{
+
+PYSIDE_API void init(PyObject *module);
+
+/**
+ * Hash function used to enable hash on objects not supported on native Qt library which has toString function.
+ */
+template<class T>
+inline Py_ssize_t hash(const T& value)
+{
+ return qHash(value.toString());
+}
+
+/**
+ * Fill QObject properties and do signal connections using the values found in \p kwds dictonary.
+ * \param qObj PyObject fot the QObject.
+ * \param metaObj QMetaObject of \p qObj.
+ * \param blackList keys to be ignored in kwds dictionary, this string list MUST be sorted.
+ * \param blackListSize numbe rof elements in blackList.
+ * \param kwds key->value dictonary.
+ * \return True if everything goes well, false with a Python error setted otherwise.
+ */
+PYSIDE_API bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds, const char **blackList, unsigned int blackListSize);
+
+/**
+* If the type \p T was registered on Qt meta type system with Q_DECLARE_METATYPE macro, this class will initialize
+* the meta type.
+*
+* Initialize a meta type means register it on Qt meta type system, Qt itself only do this on the first call of
+* qMetaTypeId, and this is exactly what we do to init it. If we don't do that, calls to QMetaType::type("QMatrix2x2")
+* could return zero, causing QVariant to not recognize some C++ types, like QMatrix2x2.
+*/
+template<typename T, bool OK = QMetaTypeId<T>::Defined >
+struct initQtMetaType {
+ initQtMetaType()
+ {
+ qMetaTypeId<T>();
+ }
+};
+
+// Template specialization to do nothing when the type wasn't registered on Qt meta type system.
+template<typename T>
+struct initQtMetaType<T, false> {
+};
+
+PYSIDE_API void initDynamicMetaObject(SbkObjectType *type, const QMetaObject *base,
+ std::size_t cppObjSize);
+PYSIDE_API void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject *kwds);
+PYSIDE_API void initQApp();
+
+/// Return the size in bytes of a type that inherits QObject.
+PYSIDE_API std::size_t getSizeOfQObject(SbkObjectType *type);
+
+typedef void (*CleanupFunction)(void);
+
+/**
+ * Register a function to be called before python die
+ */
+PYSIDE_API void registerCleanupFunction(CleanupFunction func);
+PYSIDE_API void runCleanupFunctions();
+
+/**
+ * Destroy a QCoreApplication taking care of destroy all instances of QObject first.
+ */
+PYSIDE_API void destroyQCoreApplication();
+
+/**
+ * Check for properties and signals registered on MetaObject and return these
+ * \param cppSelf Is the QObject which contains the metaobject
+ * \param self Python object of cppSelf
+ * \param name Name of the argument which the function will try retrieve from MetaData
+ * \return The Python object which contains the Data obtained in metaObject or the Python attribute related with name
+ */
+PYSIDE_API PyObject *getMetaDataFromQObject(QObject *cppSelf, PyObject *self, PyObject *name);
+
+/**
+ * Check if self inherits from class_name
+ * \param self Python object
+ * \param class_name strict with the class name
+ * \return Returns true if self object inherits from class_name, otherwise returns false
+ */
+PYSIDE_API bool inherits(PyTypeObject *self, const char *class_name);
+
+PYSIDE_API void *nextQObjectMemoryAddr();
+PYSIDE_API void setNextQObjectMemoryAddr(void *addr);
+
+PYSIDE_API PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type);
+
+#ifdef PYSIDE_QML_SUPPORT
+// Used by QtQuick module to notify QtQml that custom QtQuick items can be registered.
+using QuickRegisterItemFunction =
+ bool (*)(PyObject *pyObj, const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName,
+ bool creatable, const char *noCreationReason,
+ QQmlPrivate::RegisterType *);
+PYSIDE_API QuickRegisterItemFunction getQuickRegisterItemFunction();
+PYSIDE_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function);
+#endif // PYSIDE_QML_SUPPORT
+
+/**
+ * Given A PyObject repesenting ASCII or Unicode data, returns an equivalent QString.
+ */
+PYSIDE_API QString pyStringToQString(PyObject *str);
+
+/**
+ * Registers a dynamic "qt.conf" file with the Qt resource system.
+ *
+ * This is used in a standalone build, to inform QLibraryInfo of the Qt prefix (where Qt libraries
+ * are installed) so that plugins can be successfully loaded.
+ */
+PYSIDE_API bool registerInternalQtConf();
+
+
+} //namespace PySide
+
+
+#endif // PYSIDE_H
diff --git a/sources/pyside6/libpyside/pyside6.pc.in b/sources/pyside6/libpyside/pyside6.pc.in
new file mode 100644
index 000000000..394372539
--- /dev/null
+++ b/sources/pyside6/libpyside/pyside6.pc.in
@@ -0,0 +1,15 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=@CMAKE_INSTALL_PREFIX@/include/PySide6@pyside6_SUFFIX@
+typesystemdir=@CMAKE_INSTALL_PREFIX@/share/PySide6@pyside6_SUFFIX@/typesystems
+gluedir=@CMAKE_INSTALL_PREFIX@/share/PySide6@pyside6_SUFFIX@/glue
+pythonpath=@PYTHON_SITE_PACKAGES@
+
+Name: PySide6@pyside6_SUFFIX@
+Description: Support library for Python bindings of Qt5-based libraries.
+Version: @BINDING_API_VERSION_FULL@
+Libs: -L${libdir} -lpyside6@pyside6_SUFFIX@@SHIBOKEN_PYTHON_CONFIG_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@
+Cflags: -I${includedir}
+Requires: shiboken6
+
diff --git a/sources/pyside6/libpyside/pyside_p.h b/sources/pyside6/libpyside/pyside_p.h
new file mode 100644
index 000000000..1084a40a1
--- /dev/null
+++ b/sources/pyside6/libpyside/pyside_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 PYSIDE_P_H
+#define PYSIDE_P_H
+
+#include <pysidemacros.h>
+
+#include <dynamicqmetaobject.h>
+
+struct SbkObjectType;
+
+namespace PySide
+{
+
+// Struct associated with QObject's via Shiboken::Object::getTypeUserData()
+struct TypeUserData
+{
+ explicit TypeUserData(PyTypeObject* type, const QMetaObject* metaobject, std::size_t size) :
+ mo(type, metaobject), cppObjSize(size) {}
+
+ MetaObjectBuilder mo;
+ std::size_t cppObjSize;
+};
+
+TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj);
+TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj);
+TypeUserData *retrieveTypeUserData(PyObject *pyObj);
+// For QML
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj);
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyObject *pyObj);
+
+} //namespace PySide
+
+#endif // PYSIDE_P_H
diff --git a/sources/pyside6/libpyside/pysideclassinfo.cpp b/sources/pyside6/libpyside/pysideclassinfo.cpp
new file mode 100644
index 000000000..67334f2f4
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideclassinfo.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 <sbkpython.h>
+
+#include "pysideclassinfo.h"
+#include "pyside_p.h"
+#include "pysideclassinfo_p.h"
+#include "dynamicqmetaobject.h"
+
+#include <shiboken.h>
+#include <signature.h>
+
+extern "C"
+{
+
+static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
+static int classInfoTpInit(PyObject *, PyObject *, PyObject *);
+static void classInfoFree(void *);
+static PyObject *classCall(PyObject *, PyObject *, PyObject *);
+
+static PyType_Slot PySideClassInfoType_slots[] = {
+ {Py_tp_call, (void *)classCall},
+ {Py_tp_init, (void *)classInfoTpInit},
+ {Py_tp_new, (void *)classInfoTpNew},
+ {Py_tp_free, (void *)classInfoFree},
+ {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {0, 0}
+};
+static PyType_Spec PySideClassInfoType_spec = {
+ "2:PySide6.QtCore.ClassInfo",
+ sizeof(PySideClassInfo),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideClassInfoType_slots,
+};
+
+
+PyTypeObject *PySideClassInfoTypeF(void)
+{
+ static PyTypeObject *type =
+ reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideClassInfoType_spec));
+ return type;
+}
+
+PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
+ PyErr_Format(PyExc_TypeError,
+ "The ClassInfo decorator takes exactly 1 positional argument (%zd given)",
+ PyTuple_Size(args));
+ return 0;
+ }
+
+ PySideClassInfo *data = reinterpret_cast<PySideClassInfo *>(self);
+ PySideClassInfoPrivate *pData = data->d;
+
+ if (pData->m_alreadyWrapped) {
+ PyErr_SetString(PyExc_TypeError, "This instance of ClassInfo() was already used to wrap an object");
+ return 0;
+ }
+
+ PyObject *klass = PyTuple_GetItem(args, 0);
+ bool validClass = false;
+
+ // This will sometimes segfault if you mistakenly use it on a function declaration
+ if (!PyType_Check(klass)) {
+ PyErr_SetString(PyExc_TypeError, "This decorator can only be used on class declarations");
+ return 0;
+ }
+
+ PyTypeObject *klassType = reinterpret_cast<PyTypeObject *>(klass);
+ if (Shiboken::ObjectType::checkType(klassType)) {
+ if (auto userData = PySide::retrieveTypeUserData(klassType)) {
+ PySide::MetaObjectBuilder &mo = userData->mo;
+ mo.addInfo(PySide::ClassInfo::getMap(data));
+ pData->m_alreadyWrapped = true;
+ validClass = true;
+ }
+ }
+
+ if (!validClass) {
+ PyErr_SetString(PyExc_TypeError, "This decorator can only be used on classes that are subclasses of QObject");
+ return 0;
+ }
+
+ Py_INCREF(klass);
+ return klass;
+}
+
+static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+{
+ PySideClassInfo *me = reinterpret_cast<PySideClassInfo *>(subtype->tp_alloc(subtype, 0));
+ me->d = new PySideClassInfoPrivate;
+
+ me->d->m_alreadyWrapped = false;
+
+ return reinterpret_cast<PyObject *>(me);
+}
+
+int classInfoTpInit(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ if (PyTuple_Check(args) && PyTuple_Size(args) > 0) {
+ PyErr_Format(PyExc_TypeError, "ClassInfo() takes exactly 0 positional arguments (%zd given)", PyTuple_Size(args));
+ return -1;
+ }
+
+ PySideClassInfo *data = reinterpret_cast<PySideClassInfo *>(self);
+ PySideClassInfoPrivate *pData = data->d;
+
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+
+ // PyDict_Next causes a segfault if kwds is empty
+ if (kwds && PyDict_Check(kwds) && PyDict_Size(kwds) > 0) {
+ while (PyDict_Next(kwds, &pos, &key, &value)) {
+ if (Shiboken::String::check(key) && Shiboken::String::check(value)) {
+ pData->m_data[Shiboken::String::toCString(key)] = Shiboken::String::toCString(value);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "All keys and values provided to ClassInfo() must be strings");
+ return -1;
+ }
+ }
+ }
+
+ return PyErr_Occurred() ? -1 : 0;
+}
+
+void classInfoFree(void *self)
+{
+ auto pySelf = reinterpret_cast<PyObject *>(self);
+ auto data = reinterpret_cast<PySideClassInfo *>(self);
+
+ delete data->d;
+ Py_TYPE(pySelf)->tp_base->tp_free(self);
+}
+
+
+} // extern "C"
+
+
+namespace PySide { namespace ClassInfo {
+
+static const char *ClassInfo_SignatureStrings[] = {
+ "PySide6.QtCore.ClassInfo(**info:typing.Dict[str,str])",
+ nullptr}; // Sentinel
+
+void init(PyObject *module)
+{
+ if (InitSignatureStrings(PySideClassInfoTypeF(), ClassInfo_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideClassInfoTypeF());
+ PyModule_AddObject(module, "ClassInfo", reinterpret_cast<PyObject *>(PySideClassInfoTypeF()));
+}
+
+bool checkType(PyObject *pyObj)
+{
+ if (pyObj)
+ return PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfoTypeF());
+ return false;
+}
+
+QMap<QByteArray, QByteArray> getMap(PySideClassInfo *obj)
+{
+ return obj->d->m_data;
+}
+
+} //namespace Property
+} //namespace PySide
diff --git a/sources/pyside6/libpyside/pysideclassinfo.h b/sources/pyside6/libpyside/pysideclassinfo.h
new file mode 100644
index 000000000..ff60b91c3
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideclassinfo.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_CLASSINFO_H
+#define PYSIDE_CLASSINFO_H
+
+#include <pysidemacros.h>
+
+#include <sbkpython.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QByteArray>
+
+extern "C"
+{
+ extern PYSIDE_API PyTypeObject *PySideClassInfoTypeF(void);
+
+ struct PySideClassInfoPrivate;
+ struct PYSIDE_API PySideClassInfo
+ {
+ PyObject_HEAD
+ PySideClassInfoPrivate* d;
+ };
+};
+
+namespace PySide { namespace ClassInfo {
+
+PYSIDE_API bool checkType(PyObject* pyObj);
+PYSIDE_API QMap<QByteArray, QByteArray> getMap(PySideClassInfo* obj);
+
+} //namespace ClassInfo
+} //namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysideclassinfo_p.h b/sources/pyside6/libpyside/pysideclassinfo_p.h
new file mode 100644
index 000000000..021aa58e9
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideclassinfo_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_CLASSINFO_P_H
+#define PYSIDE_CLASSINFO_P_H
+
+#include <sbkpython.h>
+#include <QMetaObject>
+#include "pysideclassinfo.h"
+
+struct PySideClassInfo;
+
+extern "C"
+{
+
+struct PySideClassInfoPrivate {
+ QMap<QByteArray, QByteArray> m_data;
+ bool m_alreadyWrapped;
+};
+
+} // extern "C"
+
+namespace PySide { namespace ClassInfo {
+
+/**
+ * Init PySide QProperty support system
+ */
+void init(PyObject* module);
+
+
+} // namespace ClassInfo
+} // namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysidemacros.h b/sources/pyside6/libpyside/pysidemacros.h
new file mode 100644
index 000000000..fcdfe3c6e
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidemacros.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 PYSIDEMACROS_H
+#define PYSIDEMACROS_H
+
+#include <shibokenmacros.h>
+
+#define PYSIDE_EXPORT LIBSHIBOKEN_EXPORT
+#define PYSIDE_IMPORT LIBSHIBOKEN_IMPORT
+#define PYSIDE_DEPRECATED(func) SBK_DEPRECATED(func)
+
+#ifdef BUILD_LIBPYSIDE
+# define PYSIDE_API PYSIDE_EXPORT
+#else
+# define PYSIDE_API PYSIDE_IMPORT
+#endif
+
+#endif // PYSIDEMACROS_H
diff --git a/sources/pyside6/libpyside/pysidemetafunction.cpp b/sources/pyside6/libpyside/pysidemetafunction.cpp
new file mode 100644
index 000000000..6d93e7629
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidemetafunction.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "pysidemetafunction.h"
+#include "pysidemetafunction_p.h"
+
+#include <shiboken.h>
+#include <signature.h>
+
+#include <QtCore/QMetaMethod>
+
+extern "C"
+{
+
+struct PySideMetaFunctionPrivate
+{
+ QObject *qobject;
+ int methodIndex;
+};
+
+//methods
+static void functionFree(void *);
+static PyObject *functionCall(PyObject *, PyObject *, PyObject *);
+
+static PyType_Slot PySideMetaFunctionType_slots[] = {
+ {Py_tp_call, (void *)functionCall},
+ {Py_tp_new, (void *)PyType_GenericNew},
+ {Py_tp_free, (void *)functionFree},
+ {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {0, 0}
+};
+static PyType_Spec PySideMetaFunctionType_spec = {
+ "2:PySide6.QtCore.MetaFunction",
+ sizeof(PySideMetaFunction),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideMetaFunctionType_slots,
+};
+
+
+PyTypeObject *PySideMetaFunctionTypeF(void)
+{
+ static PyTypeObject *type = reinterpret_cast<PyTypeObject *>(
+ SbkType_FromSpec(&PySideMetaFunctionType_spec));
+ return type;
+}
+
+void functionFree(void *self)
+{
+ PySideMetaFunction *function = reinterpret_cast<PySideMetaFunction *>(self);
+ delete function->d;
+}
+
+PyObject *functionCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ PySideMetaFunction *function = reinterpret_cast<PySideMetaFunction *>(self);
+
+ PyObject *retVal;
+ if (!PySide::MetaFunction::call(function->d->qobject, function->d->methodIndex, args, &retVal))
+ return 0;
+ return retVal;
+}
+
+} // extern "C"
+
+namespace PySide { namespace MetaFunction {
+
+static const char *MetaFunction_SignatureStrings[] = {
+ "PySide6.QtCore.MetaFunction.__call__(*args:typing.Any)->typing.Any",
+ nullptr}; // Sentinel
+
+void init(PyObject *module)
+{
+ if (InitSignatureStrings(PySideMetaFunctionTypeF(), MetaFunction_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideMetaFunctionTypeF());
+ PyModule_AddObject(module, "MetaFunction", reinterpret_cast<PyObject *>(PySideMetaFunctionTypeF()));
+}
+
+PySideMetaFunction *newObject(QObject *source, int methodIndex)
+{
+ if (methodIndex >= source->metaObject()->methodCount())
+ return 0;
+
+ QMetaMethod method = source->metaObject()->method(methodIndex);
+ if ((method.methodType() == QMetaMethod::Slot) ||
+ (method.methodType() == QMetaMethod::Method)) {
+ PySideMetaFunction *function = PyObject_New(PySideMetaFunction, PySideMetaFunctionTypeF());
+ function->d = new PySideMetaFunctionPrivate();
+ function->d->qobject = source;
+ function->d->methodIndex = methodIndex;
+ return function;
+ }
+ return 0;
+}
+
+bool call(QObject *self, int methodIndex, PyObject *args, PyObject **retVal)
+{
+
+ QMetaMethod method = self->metaObject()->method(methodIndex);
+ QList<QByteArray> argTypes = method.parameterTypes();
+
+ // args given plus return type
+ Shiboken::AutoDecRef sequence(PySequence_Fast(args, 0));
+ int numArgs = PySequence_Fast_GET_SIZE(sequence.object()) + 1;
+
+ if (numArgs - 1 > argTypes.count()) {
+ PyErr_Format(PyExc_TypeError, "%s only accepts %d argument(s), %d given!",
+ method.methodSignature().constData(),
+ argTypes.count(), numArgs - 1);
+ return false;
+ }
+
+ if (numArgs - 1 < argTypes.count()) {
+ PyErr_Format(PyExc_TypeError, "%s needs %d argument(s), %d given!",
+ method.methodSignature().constData(),
+ argTypes.count(), numArgs - 1);
+ return false;
+ }
+
+ QVariant *methValues = new QVariant[numArgs];
+ void **methArgs = new void *[numArgs];
+
+ // Prepare room for return type
+ const char *returnType = method.typeName();
+ if (returnType && std::strcmp("void", returnType))
+ argTypes.prepend(returnType);
+ else
+ argTypes.prepend(QByteArray());
+
+ int i;
+ for (i = 0; i < numArgs; ++i) {
+ const QByteArray &typeName = argTypes.at(i);
+ // This must happen only when the method hasn't return type.
+ if (typeName.isEmpty()) {
+ methArgs[i] = 0;
+ continue;
+ }
+
+ Shiboken::Conversions::SpecificConverter converter(typeName);
+ if (converter) {
+ QMetaType metaType = QMetaType::fromName(typeName);
+ if (!Shiboken::Conversions::pythonTypeIsObjectType(converter)) {
+ if (!metaType.isValid()) {
+ PyErr_Format(PyExc_TypeError, "Value types used on meta functions (including signals) need to be "
+ "registered on meta type: %s", typeName.data());
+ break;
+ }
+ methValues[i] = QVariant(metaType);
+ }
+ methArgs[i] = methValues[i].data();
+ if (i == 0) // Don't do this for return type
+ continue;
+ if (metaType.id() == QMetaType::QString) {
+ QString tmp;
+ converter.toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i - 1), &tmp);
+ methValues[i] = tmp;
+ } else {
+ converter.toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i - 1), methArgs[i]);
+ }
+ } else {
+ PyErr_Format(PyExc_TypeError, "Unknown type used to call meta function (that may be a signal): %s", argTypes[i].constData());
+ break;
+ }
+ }
+
+ bool ok = i == numArgs;
+ if (ok) {
+ Py_BEGIN_ALLOW_THREADS
+ QMetaObject::metacall(self, QMetaObject::InvokeMetaMethod, method.methodIndex(), methArgs);
+ Py_END_ALLOW_THREADS
+
+ if (retVal) {
+ if (methArgs[0]) {
+ static SbkConverter *qVariantTypeConverter = Shiboken::Conversions::getConverter("QVariant");
+ Q_ASSERT(qVariantTypeConverter);
+ *retVal = Shiboken::Conversions::copyToPython(qVariantTypeConverter, &methValues[0]);
+ } else {
+ *retVal = Py_None;
+ Py_INCREF(*retVal);
+ }
+ }
+ }
+
+ delete[] methArgs;
+ delete[] methValues;
+
+ return ok;
+}
+
+
+} //namespace MetaFunction
+} //namespace PySide
+
diff --git a/sources/pyside6/libpyside/pysidemetafunction.h b/sources/pyside6/libpyside/pysidemetafunction.h
new file mode 100644
index 000000000..f7cc5307b
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidemetafunction.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_METAFUNCTION_H
+#define PYSIDE_METAFUNCTION_H
+
+#include <pysidemacros.h>
+
+#include <sbkpython.h>
+
+#include <QtCore/QObject>
+
+extern "C"
+{
+ extern PYSIDE_API PyTypeObject *PySideMetaFunctionTypeF(void);
+
+ struct PySideMetaFunctionPrivate;
+ struct PYSIDE_API PySideMetaFunction
+ {
+ PyObject_HEAD
+ PySideMetaFunctionPrivate *d;
+ };
+}; //extern "C"
+
+namespace PySide { namespace MetaFunction {
+
+/**
+ * This function creates a MetaFunction object
+ *
+ * @param obj the QObject witch this fuction is part of
+ * @param methodIndex The index of this function on MetaObject
+ * @return Return a new reference of PySideMetaFunction
+ **/
+PYSIDE_API PySideMetaFunction *newObject(QObject *obj, int methodIndex);
+
+} //namespace MetaFunction
+} //namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysidemetafunction_p.h b/sources/pyside6/libpyside/pysidemetafunction_p.h
new file mode 100644
index 000000000..c67233857
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidemetafunction_p.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_METAFUNCTION_P_H
+#define PYSIDE_METAFUNCTION_P_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+class QObject;
+QT_END_NAMESPACE
+
+namespace PySide { namespace MetaFunction {
+
+ void init(PyObject *module);
+ /**
+ * Does a Qt metacall on a QObject
+ */
+ bool call(QObject *self, int methodIndex, PyObject *args, PyObject **retVal = nullptr);
+
+} //namespace MetaFunction
+} //namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp
new file mode 100644
index 000000000..b031c5b12
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideproperty.cpp
@@ -0,0 +1,634 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 <sbkpython.h>
+#include "pysideproperty.h"
+#include "pysideproperty_p.h"
+#include "dynamicqmetaobject_p.h"
+#include "pysidesignal.h"
+#include "pysidesignal_p.h"
+
+#include <shiboken.h>
+#include <signature.h>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
+static int qpropertyTpInit(PyObject *, PyObject *, PyObject *);
+static void qpropertyDeAlloc(PyObject *self);
+
+//methods
+static PyObject *qPropertyGetter(PyObject *, PyObject *);
+static PyObject *qPropertySetter(PyObject *, PyObject *);
+static PyObject *qPropertyResetter(PyObject *, PyObject *);
+static PyObject *qPropertyDeleter(PyObject *, PyObject *);
+static PyObject *qPropertyCall(PyObject *, PyObject *, PyObject *);
+static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg);
+static int qpropertyClear(PyObject *self);
+
+// Attributes
+static PyObject *qPropertyDocGet(PyObject *, void *);
+static int qPropertyDocSet(PyObject *, PyObject *, void *);
+static PyObject *qProperty_fget(PyObject *, void *);
+static PyObject *qProperty_fset(PyObject *, void *);
+static PyObject *qProperty_freset(PyObject *, void *);
+static PyObject *qProperty_fdel(PyObject *, void *);
+
+static PyMethodDef PySidePropertyMethods[] = {
+ {"getter", (PyCFunction)qPropertyGetter, METH_O, 0},
+ {"setter", (PyCFunction)qPropertySetter, METH_O, 0},
+ {"resetter", (PyCFunction)qPropertyResetter, METH_O, 0},
+ {"deleter", (PyCFunction)qPropertyDeleter, METH_O, 0},
+ // Synonyms from Qt
+ {"read", (PyCFunction)qPropertyGetter, METH_O, 0},
+ {"write", (PyCFunction)qPropertySetter, METH_O, 0},
+ {0, 0, 0, 0}
+};
+
+static PyGetSetDef PySidePropertyType_getset[] = {
+ // Note: we could not use `PyMemberDef` like Python's properties,
+ // because of the indirection of PySidePropertyPrivate.
+ {const_cast<char *>("fget"), qProperty_fget, nullptr, nullptr, nullptr},
+ {const_cast<char *>("fset"), qProperty_fset, nullptr, nullptr, nullptr},
+ {const_cast<char *>("freset"), qProperty_freset, nullptr, nullptr, nullptr},
+ {const_cast<char *>("fdel"), qProperty_fdel, nullptr, nullptr, nullptr},
+ {const_cast<char *>("__doc__"), qPropertyDocGet, qPropertyDocSet, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyType_Slot PySidePropertyType_slots[] = {
+ {Py_tp_dealloc, (void *)qpropertyDeAlloc},
+ {Py_tp_call, (void *)qPropertyCall},
+ {Py_tp_traverse, (void *)qpropertyTraverse},
+ {Py_tp_clear, (void *)qpropertyClear},
+ {Py_tp_methods, (void *)PySidePropertyMethods},
+ {Py_tp_init, (void *)qpropertyTpInit},
+ {Py_tp_new, (void *)qpropertyTpNew},
+ {Py_tp_getset, PySidePropertyType_getset},
+ {0, 0}
+};
+// Dotted modulename is crucial for SbkType_FromSpec to work. Is this name right?
+static PyType_Spec PySidePropertyType_spec = {
+ "2:PySide6.QtCore.Property",
+ sizeof(PySideProperty),
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE,
+ PySidePropertyType_slots,
+};
+
+
+PyTypeObject *PySidePropertyTypeF(void)
+{
+ static PyTypeObject *type = reinterpret_cast<PyTypeObject *>(
+ SbkType_FromSpec(&PySidePropertyType_spec));
+ return type;
+}
+
+static void qpropertyMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Call call, void **args)
+{
+ Shiboken::Conversions::SpecificConverter converter(pp->d->typeName);
+ Q_ASSERT(converter);
+
+ QByteArray type(pp->d->typeName);
+
+ switch(call) {
+ case QMetaObject::ReadProperty:
+ {
+ Shiboken::GilState gil;
+ PyObject *value = PySide::Property::getValue(pp, self);
+ if (value) {
+ converter.toCpp(value, args[0]);
+ Py_DECREF(value);
+ }
+ break;
+ }
+
+ case QMetaObject::WriteProperty:
+ {
+ Shiboken::GilState gil;
+ Shiboken::AutoDecRef value(converter.toPython(args[0]));
+ PySide::Property::setValue(pp, self, value);
+ break;
+ }
+
+ case QMetaObject::ResetProperty:
+ {
+ Shiboken::GilState gil;
+ PySide::Property::reset(pp, self);
+ break;
+ }
+
+ // just to avoid gcc warnings
+ case QMetaObject::BindableProperty:
+ case QMetaObject::InvokeMetaMethod:
+ case QMetaObject::CreateInstance:
+ case QMetaObject::IndexOfMethod:
+ case QMetaObject::RegisterPropertyMetaType:
+ case QMetaObject::RegisterMethodArgumentMetaType:
+ break;
+ }
+}
+
+
+static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+{
+ PySideProperty *me = reinterpret_cast<PySideProperty *>(subtype->tp_alloc(subtype, 0));
+ me->d = new PySidePropertyPrivate;
+ return reinterpret_cast<PyObject *>(me);
+}
+
+static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *type = nullptr;
+ auto data = reinterpret_cast<PySideProperty *>(self);
+ PySidePropertyPrivate *pData = data->d;
+ pData->metaCallHandler = &qpropertyMetaCall;
+
+ static const char *kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", "notify",
+ "designable", "scriptable", "stored",
+ "user", "constant", "final", 0};
+ char *doc{};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O|OOOOsObbbbbb:QtCore.Property",
+ const_cast<char **>(kwlist),
+ /*OO*/ &type, &(pData->fget),
+ /*OOO*/ &(pData->fset), &(pData->freset), &(pData->fdel),
+ /*s*/ &doc,
+ /*O*/ &(pData->notify),
+ /*bbb*/ &(pData->designable), &(pData->scriptable), &(pData->stored),
+ /*bbb*/ &(pData->user), &(pData->constant), &(pData->final))) {
+ return -1;
+ }
+
+ // PYSIDE-1019: Fetching the default `__doc__` from fget would fail for inherited functions
+ // because we don't initialize the mro with signatures (and we will not!).
+ // But it is efficient and in-time to do that on demand in qPropertyDocGet.
+ pData->getter_doc = false;
+ if (doc)
+ pData->doc = doc;
+ else
+ pData->doc.clear();
+
+ pData->typeName = PySide::Signal::getTypeName(type);
+
+ if (pData->typeName.isEmpty())
+ PyErr_SetString(PyExc_TypeError, "Invalid property type or type name.");
+ else if (pData->constant && (pData->fset || pData->notify))
+ PyErr_SetString(PyExc_TypeError, "A constant property cannot have a WRITE method or a NOTIFY signal.");
+
+ if (!PyErr_Occurred()) {
+ Py_XINCREF(pData->fget);
+ Py_XINCREF(pData->fset);
+ Py_XINCREF(pData->freset);
+ Py_XINCREF(pData->fdel);
+ Py_XINCREF(pData->notify);
+ return 0;
+ }
+ pData->fget = nullptr;
+ pData->fset = nullptr;
+ pData->freset = nullptr;
+ pData->fdel = nullptr;
+ pData->notify = nullptr;
+ return -1;
+}
+
+static void qpropertyDeAlloc(PyObject *self)
+{
+ qpropertyClear(self);
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(Py_TYPE(self));
+ }
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+_property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyObject *del)
+{
+ PySideProperty *pold = reinterpret_cast<PySideProperty *>(old);
+ PySidePropertyPrivate *pData = pold->d;
+
+ AutoDecRef type(PyObject_Type(old));
+ QByteArray doc{};
+ if (type.isNull())
+ return nullptr;
+
+ if (get == nullptr || get == Py_None) {
+ Py_XDECREF(get);
+ get = pData->fget ? pData->fget : Py_None;
+ }
+ if (set == nullptr || set == Py_None) {
+ Py_XDECREF(set);
+ set = pData->fset ? pData->fset : Py_None;
+ }
+ if (reset == nullptr || reset == Py_None) {
+ Py_XDECREF(reset);
+ reset = pData->freset ? pData->freset : Py_None;
+ }
+ if (del == nullptr || del == Py_None) {
+ Py_XDECREF(del);
+ del = pData->fdel ? pData->fdel : Py_None;
+ }
+ if (pData->getter_doc && get != Py_None) {
+ /* make _init use __doc__ from getter */
+ doc = "";
+ }
+ else {
+ doc = !pData->doc.isEmpty() ? pData->doc : "";
+ }
+ auto notify = pData->notify ? pData->notify : Py_None;
+
+ PyObject *typeName = String::fromCString(pData->typeName);
+ PyObject *obNew = PyObject_CallFunction(type, const_cast<char *>("OOOOOsO" "bbb" "bbb"),
+ typeName, get, set, reset, del, doc.data(), notify,
+ pData->designable, pData->scriptable, pData->stored,
+ pData->user, pData->constant, pData->final);
+
+ return obNew;
+}
+
+static PyObject *qPropertyGetter(PyObject *self, PyObject *getter)
+{
+ return _property_copy(self, getter, nullptr, nullptr, nullptr);
+}
+
+static PyObject *qPropertySetter(PyObject *self, PyObject *setter)
+{
+ return _property_copy(self, nullptr, setter, nullptr, nullptr);
+}
+
+static PyObject *qPropertyResetter(PyObject *self, PyObject *resetter)
+{
+ return _property_copy(self, nullptr, nullptr, resetter, nullptr);
+}
+
+static PyObject *qPropertyDeleter(PyObject *self, PyObject *deleter)
+{
+ return _property_copy(self, nullptr, nullptr, nullptr, deleter);
+}
+
+static PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ PyObject *getter = PyTuple_GetItem(args, 0);
+ return _property_copy(self, getter, nullptr, nullptr, nullptr);
+}
+
+// PYSIDE-1019: Provide the same getters as Pythons `PyProperty`.
+
+static PyObject *qProperty_fget(PyObject *self, void *)
+{
+ auto func = reinterpret_cast<PySideProperty *>(self)->d->fget;
+ auto ret = func != nullptr ? func : Py_None;
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *qProperty_fset(PyObject *self, void *)
+{
+ auto func = reinterpret_cast<PySideProperty *>(self)->d->fset;
+ auto ret = func != nullptr ? func : Py_None;
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *qProperty_freset(PyObject *self, void *)
+{
+ auto func = reinterpret_cast<PySideProperty *>(self)->d->freset;
+ auto ret = func != nullptr ? func : Py_None;
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *qProperty_fdel(PyObject *self, void *)
+{
+ auto func = reinterpret_cast<PySideProperty *>(self)->d->fdel;
+ auto ret = func != nullptr ? func : Py_None;
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *qPropertyDocGet(PyObject *self, void *)
+{
+ auto data = reinterpret_cast<PySideProperty *>(self);
+ PySidePropertyPrivate *pData = data->d;
+
+ QByteArray doc(pData->doc);
+ if (!doc.isEmpty())
+ return PyUnicode_FromString(doc);
+ if (pData->fget != nullptr) {
+ // PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
+ AutoDecRef get_doc(PyObject_GetAttr(pData->fget, PyMagicName::doc()));
+ if (!get_doc.isNull()) {
+ pData->doc = String::toCString(get_doc);
+ pData->getter_doc = true;
+ if (Py_TYPE(self) == PySidePropertyTypeF())
+ return qPropertyDocGet(self, nullptr);
+ /*
+ * If this is a property subclass, put __doc__ in dict of the
+ * subclass instance instead, otherwise it gets shadowed by
+ * __doc__ in the class's dict.
+ */
+ auto get_doc_obj = get_doc.object();
+ int err = PyObject_SetAttr(self, PyMagicName::doc(), get_doc);
+ return err < 0 ? nullptr : (Py_INCREF(get_doc_obj), get_doc_obj);
+ }
+ PyErr_Clear();
+ }
+ Py_RETURN_NONE;
+}
+
+static int qPropertyDocSet(PyObject *self, PyObject *value, void *)
+{
+ auto data = reinterpret_cast<PySideProperty *>(self);
+ PySidePropertyPrivate *pData = data->d;
+
+ if (String::check(value)) {
+ pData->doc = String::toCString(value);
+ return 0;
+ }
+ PyErr_SetString(PyExc_TypeError, "String argument expected.");
+ return -1;
+}
+
+static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg)
+{
+ PySidePropertyPrivate *data = reinterpret_cast<PySideProperty *>(self)->d;
+ if (!data)
+ return 0;
+
+ Py_VISIT(data->fget);
+ Py_VISIT(data->fset);
+ Py_VISIT(data->freset);
+ Py_VISIT(data->fdel);
+ Py_VISIT(data->notify);
+ return 0;
+}
+
+static int qpropertyClear(PyObject *self)
+{
+ PySidePropertyPrivate *data = reinterpret_cast<PySideProperty *>(self)->d;
+ if (!data)
+ return 0;
+
+ Py_CLEAR(data->fget);
+ Py_CLEAR(data->fset);
+ Py_CLEAR(data->freset);
+ Py_CLEAR(data->fdel);
+ Py_CLEAR(data->notify);
+
+
+ delete data;
+ reinterpret_cast<PySideProperty *>(self)->d = nullptr;
+ return 0;
+}
+
+} // extern "C"
+
+namespace {
+
+static PyObject *getFromType(PyTypeObject *type, PyObject *name)
+{
+ PyObject *attr = nullptr;
+ attr = PyDict_GetItem(type->tp_dict, name);
+ if (!attr) {
+ PyObject *bases = type->tp_bases;
+ int size = PyTuple_GET_SIZE(bases);
+ for(int i=0; i < size; i++) {
+ PyObject *base = PyTuple_GET_ITEM(bases, i);
+ attr = getFromType(reinterpret_cast<PyTypeObject *>(base), name);
+ if (attr)
+ return attr;
+ }
+ }
+ return attr;
+}
+
+} //namespace
+
+
+namespace PySide { namespace Property {
+
+static const char *Property_SignatureStrings[] = {
+ "PySide6.QtCore.Property(self,type:type,fget:typing.Callable=None,fset:typing.Callable=None,"
+ "freset:typing.Callable=None,fdel:typing.Callable=None,doc:str=None,"
+ "notify:typing.Callable=None,designable:bool=True,scriptable:bool=True,"
+ "stored:bool=True,user:bool=False,constant:bool=False,final:bool=False)"
+ "->PySide6.QtCore.Property",
+ "PySide6.QtCore.Property.deleter(self,func:typing.Callable)",
+ "PySide6.QtCore.Property.fdel(self)->typing.Callable",
+ "PySide6.QtCore.Property.fget(self)->typing.Callable",
+ "PySide6.QtCore.Property.freset(self)->typing.Callable",
+ "PySide6.QtCore.Property.fset(self)->typing.Callable",
+ "PySide6.QtCore.Property.getter(self,func:typing.Callable)",
+ "PySide6.QtCore.Property.read(self,func:typing.Callable)",
+ "PySide6.QtCore.Property.setter(self,func:typing.Callable)",
+ "PySide6.QtCore.Property.write(self,func:typing.Callable)",
+ nullptr}; // Sentinel
+
+void init(PyObject *module)
+{
+ if (InitSignatureStrings(PySidePropertyTypeF(), Property_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySidePropertyTypeF());
+ PyModule_AddObject(module, "Property", reinterpret_cast<PyObject *>(PySidePropertyTypeF()));
+}
+
+bool checkType(PyObject *pyObj)
+{
+ if (pyObj) {
+ return PyType_IsSubtype(Py_TYPE(pyObj), PySidePropertyTypeF());
+ }
+ return false;
+}
+
+int setValue(PySideProperty *self, PyObject *source, PyObject *value)
+{
+ PyObject *fset = self->d->fset;
+ if (fset && value) {
+ Shiboken::AutoDecRef args(PyTuple_New(2));
+ PyTuple_SET_ITEM(args, 0, source);
+ PyTuple_SET_ITEM(args, 1, value);
+ Py_INCREF(source);
+ Py_INCREF(value);
+ Shiboken::AutoDecRef result(PyObject_CallObject(fset, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ PyObject *fdel = self->d->fdel;
+ if (fdel) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTuple_SET_ITEM(args, 0, source);
+ Py_INCREF(source);
+ Shiboken::AutoDecRef result(PyObject_CallObject(fdel, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ PyErr_SetString(PyExc_AttributeError, "Attibute read only");
+ return -1;
+}
+
+PyObject *getValue(PySideProperty *self, PyObject *source)
+{
+ PyObject *fget = self->d->fget;
+ if (fget) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ Py_INCREF(source);
+ PyTuple_SET_ITEM(args, 0, source);
+ return PyObject_CallObject(fget, args);
+ }
+ return 0;
+}
+
+int reset(PySideProperty *self, PyObject *source)
+{
+ PyObject *freset = self->d->freset;
+ if (freset) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ Py_INCREF(source);
+ PyTuple_SET_ITEM(args, 0, source);
+ Shiboken::AutoDecRef result(PyObject_CallObject(freset, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ return -1;
+}
+
+const char *getTypeName(const PySideProperty *self)
+{
+ return self->d->typeName;
+}
+
+PySideProperty *getObject(PyObject *source, PyObject *name)
+{
+ PyObject *attr = nullptr;
+
+ attr = getFromType(Py_TYPE(source), name);
+ if (attr && checkType(attr)) {
+ Py_INCREF(attr);
+ return reinterpret_cast<PySideProperty *>(attr);
+ }
+
+ if (!attr)
+ PyErr_Clear(); //Clear possible error caused by PyObject_GenericGetAttr
+
+ return 0;
+}
+
+bool isReadable(const PySideProperty * /* self */)
+{
+ return true;
+}
+
+bool isWritable(const PySideProperty *self)
+{
+ return (self->d->fset != 0);
+}
+
+bool hasReset(const PySideProperty *self)
+{
+ return (self->d->freset != 0);
+}
+
+bool isDesignable(const PySideProperty *self)
+{
+ return self->d->designable;
+}
+
+bool isScriptable(const PySideProperty *self)
+{
+ return self->d->scriptable;
+}
+
+bool isStored(const PySideProperty *self)
+{
+ return self->d->stored;
+}
+
+bool isUser(const PySideProperty *self)
+{
+ return self->d->user;
+}
+
+bool isConstant(const PySideProperty *self)
+{
+ return self->d->constant;
+}
+
+bool isFinal(const PySideProperty *self)
+{
+ return self->d->final;
+}
+
+const char *getNotifyName(PySideProperty *self)
+{
+ if (self->d->notifySignature.isEmpty()) {
+ PyObject *str = PyObject_Str(self->d->notify);
+ self->d->notifySignature = Shiboken::String::toCString(str);
+ Py_DECREF(str);
+ }
+
+ return self->d->notifySignature.isEmpty()
+ ? nullptr : self->d->notifySignature.constData();
+}
+
+void setMetaCallHandler(PySideProperty *self, MetaCallHandler handler)
+{
+ self->d->metaCallHandler = handler;
+}
+
+void setTypeName(PySideProperty *self, const char *typeName)
+{
+ self->d->typeName = typeName;
+}
+
+void setUserData(PySideProperty *self, void *data)
+{
+ self->d->userData = data;
+}
+
+void *userData(PySideProperty *self)
+{
+ return self->d->userData;
+}
+
+} //namespace Property
+} //namespace PySide
diff --git a/sources/pyside6/libpyside/pysideproperty.h b/sources/pyside6/libpyside/pysideproperty.h
new file mode 100644
index 000000000..4a467b186
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideproperty.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_PROPERTY_H
+#define PYSIDE_PROPERTY_H
+
+#include <pysidemacros.h>
+
+#include <sbkpython.h>
+
+#include <QtCore/QMetaObject>
+
+extern "C"
+{
+ extern PYSIDE_API PyTypeObject *PySidePropertyTypeF(void);
+
+ struct PySidePropertyPrivate;
+ struct PYSIDE_API PySideProperty
+ {
+ PyObject_HEAD
+ PySidePropertyPrivate* d;
+ };
+};
+
+namespace PySide { namespace Property {
+
+typedef void (*MetaCallHandler)(PySideProperty*,PyObject*,QMetaObject::Call, void**);
+
+PYSIDE_API bool checkType(PyObject *pyObj);
+
+/**
+ * This function call set property function and pass value as arg
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @param source The QObject witch has the property
+ * @param value The value to set in property
+ * @return Return 0 if ok or -1 if this function fail
+ **/
+PYSIDE_API int setValue(PySideProperty *self, PyObject *source, PyObject *value);
+
+/**
+ * This function call get property function
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @param source The QObject witch has the property
+ * @return Return the result of property get function or 0 if this fail
+ **/
+PYSIDE_API PyObject *getValue(PySideProperty *self, PyObject *source);
+
+/**
+ * This function return the notify name used on this property
+ *
+ * @param self The property object
+ * @return Return a const char with the notify name used
+ **/
+PYSIDE_API const char *getNotifyName(PySideProperty *self);
+
+
+/**
+ * This function search in the source object for desired property
+ *
+ * @param source The QObject object
+ * @param name The property name
+ * @return Return a new reference to property object
+ **/
+PYSIDE_API PySideProperty *getObject(PyObject *source, PyObject *name);
+
+PYSIDE_API void setMetaCallHandler(PySideProperty *self, MetaCallHandler handler);
+
+PYSIDE_API void setTypeName(PySideProperty *self, const char *typeName);
+
+PYSIDE_API void setUserData(PySideProperty *self, void *data);
+PYSIDE_API void* userData(PySideProperty *self);
+
+} //namespace Property
+} //namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysideproperty_p.h b/sources/pyside6/libpyside/pysideproperty_p.h
new file mode 100644
index 000000000..e7b6e4d77
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideproperty_p.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_QPROPERTY_P_H
+#define PYSIDE_QPROPERTY_P_H
+
+#include <sbkpython.h>
+#include <QtCore/QByteArray>
+#include <QMetaObject>
+#include "pysideproperty.h"
+
+struct PySideProperty;
+
+struct PySidePropertyPrivate
+{
+ QByteArray typeName;
+ PySide::Property::MetaCallHandler metaCallHandler = nullptr;
+ PyObject *fget = nullptr;
+ PyObject *fset = nullptr;
+ PyObject *freset = nullptr;
+ PyObject *fdel = nullptr;
+ PyObject *notify = nullptr;
+ bool getter_doc = false;
+ QByteArray notifySignature;
+ QByteArray doc;
+ bool designable = true;
+ bool scriptable = true;
+ bool stored = true;
+ bool user = false;
+ bool constant = false;
+ bool final = false;
+ void *userData = nullptr;
+};
+
+namespace PySide { namespace Property {
+
+/**
+ * Init PySide QProperty support system
+ */
+void init(PyObject* module);
+
+/**
+ * This function call reset property function
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @param source The QObject witch has the property
+ * @return Return 0 if ok or -1 if this function fail
+ **/
+int reset(PySideProperty* self, PyObject* source);
+
+
+/**
+ * This function return the property type
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return the property type name
+ **/
+const char* getTypeName(const PySideProperty* self);
+
+/**
+ * This function check if property has read function
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isReadable(const PySideProperty* self);
+
+/**
+ * This function check if property has write function
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isWritable(const PySideProperty* self);
+
+/**
+ * This function check if property has reset function
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool hasReset(const PySideProperty* self);
+
+/**
+ * This function check if property has the flag DESIGNABLE setted
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isDesignable(const PySideProperty* self);
+
+/**
+ * This function check if property has the flag SCRIPTABLE setted
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isScriptable(const PySideProperty* self);
+
+/**
+ * This function check if property has the flag STORED setted
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isStored(const PySideProperty* self);
+
+/**
+ * This function check if property has the flag USER setted
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isUser(const PySideProperty* self);
+
+/**
+ * This function check if property has the flag CONSTANT setted
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isConstant(const PySideProperty* self);
+
+/**
+ * This function check if property has the flag FINAL setted
+ * This function does not check the property object type
+ *
+ * @param self The property object
+ * @return Return a boolean value
+ **/
+bool isFinal(const PySideProperty* self);
+
+} // namespace Property
+} // namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysideqenum.cpp b/sources/pyside6/libpyside/pysideqenum.cpp
new file mode 100644
index 000000000..07a548cb6
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideqenum.cpp
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 <shiboken.h>
+
+#include "pysideqenum.h"
+#include "dynamicqmetaobject.h"
+#include "pyside_p.h"
+
+
+///////////////////////////////////////////////////////////////
+//
+// PYSIDE-957: Create QEnum dynamically from Python Enum
+//
+//
+extern "C" {
+
+using namespace Shiboken;
+
+static PyObject *analyzePyEnum(PyObject *pyenum, PyObject *container = nullptr)
+{
+ /*
+ * This is the straight-forward implementation of QEnum/QFlag. It does no
+ * longer create an equivalent Qt enum but takes the Python enum as-is.
+ *
+ * It parses an Enum/Flag derived Python enum completely so that
+ * registering can be done without error checks. This would be impossible
+ * in MetaObjectBuilderPrivate::parsePythonType.
+ */
+ AutoDecRef members(PyObject_GetAttr(pyenum, Shiboken::PyMagicName::members()));
+ if (members.isNull())
+ return nullptr;
+ AutoDecRef items(PyMapping_Items(members));
+ if (items.isNull())
+ return nullptr;
+ int iflag = PySide::QEnum::isFlag(pyenum);
+ if (iflag < 0)
+ return nullptr;
+ Py_ssize_t nr_items = PySequence_Length(items);
+ if (nr_items < 0)
+ return nullptr;
+
+ for (Py_ssize_t idx = 0; idx < nr_items; ++idx) {
+ AutoDecRef item(PySequence_GetItem(items, idx));
+ if (item.isNull())
+ return nullptr;
+
+ // The item should be a 2-element sequence of the key name and an
+ // object containing the value.
+ AutoDecRef key(PySequence_GetItem(item, 0));
+ AutoDecRef member(PySequence_GetItem(item, 1));
+ if (key.isNull() || member.isNull())
+ return nullptr;
+ if (!Shiboken::String::check(key)) {
+ // '%.200s' is the safety stringbuffer size of most CPython functions.
+ PyErr_Format(PyExc_TypeError,
+ "QEnum expected a string mapping as __members__, got '%.200s'",
+ Py_TYPE(key)->tp_name);
+ return nullptr;
+ }
+
+ // Get the value.
+ AutoDecRef value(PyObject_GetAttr(member, Shiboken::PyName::value()));
+ if (value.isNull())
+ return nullptr;
+ if (!PyInt_Check(value)) { // int/long cheating
+ PyErr_Format(PyExc_TypeError,
+ "QEnum expected an int value as '%.200s', got '%.200s'",
+ Shiboken::String::toCString(key), Py_TYPE(value)->tp_name);
+ return nullptr;
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+static Py_ssize_t get_lineno()
+{
+ PyObject *frame = reinterpret_cast<PyObject *>(PyEval_GetFrame()); // borrowed ref
+ AutoDecRef ob_lineno(PyObject_GetAttr(frame, Shiboken::PyName::f_lineno()));
+ if (ob_lineno.isNull() || !PyInt_Check(ob_lineno)) // int/long cheating
+ return -1;
+ return PyInt_AsSsize_t(ob_lineno); // int/long cheating
+}
+
+static bool is_module_code()
+{
+ PyObject *frame = reinterpret_cast<PyObject *>(PyEval_GetFrame()); // borrowed ref
+ AutoDecRef ob_code(PyObject_GetAttr(frame, Shiboken::PyName::f_code()));
+ if (ob_code.isNull())
+ return false;
+ AutoDecRef ob_name(PyObject_GetAttr(ob_code, Shiboken::PyName::co_name()));
+ if (ob_name.isNull())
+ return false;
+ const char *codename = Shiboken::String::toCString(ob_name);
+ return strcmp(codename, "<module>") == 0;
+}
+
+} // extern "C"
+
+namespace PySide { namespace QEnum {
+
+static std::map<int, PyObject *> enumCollector;
+
+int isFlag(PyObject *obType)
+{
+ /*
+ * Find out if this is an Enum or a Flag derived class.
+ * It checks also if things come from the enum module and if it is
+ * an Enum or Flag class at all.
+ *
+ * The function is called in MetaObjectBuilderPrivate::parsePythonType
+ * again to obtain the flag value.
+ */
+ if (!PyType_Check(obType)) {
+ PyErr_Format(PyExc_TypeError, "a class argument was expected, not a '%.200s' instance",
+ Py_TYPE(obType)->tp_name);
+ return -1;
+ };
+ auto *type = reinterpret_cast<PyTypeObject *>(obType);
+ PyObject *mro = type->tp_mro;
+ Py_ssize_t i, n = PyTuple_GET_SIZE(mro);
+ bool right_module = false;
+ bool have_enum = false;
+ bool have_flag = false;
+ bool have_members = PyObject_HasAttr(obType, PyMagicName::members());
+ for (i = 0; i < n; i++) {
+ obType = PyTuple_GET_ITEM(mro, i);
+ type = reinterpret_cast<PyTypeObject *>(obType);
+ AutoDecRef mod(PyObject_GetAttr(obType, PyMagicName::module()));
+ QByteArray cmod = String::toCString(mod);
+ QByteArray cname = type->tp_name;
+ if (cmod == "enum") {
+ right_module = true;
+ if (cname == "Enum")
+ have_enum = true;
+ else if (cname == "Flag")
+ have_flag = true;
+ }
+ }
+ if (!right_module || !(have_enum || have_flag) || !have_members) {
+ PyErr_Format(PyExc_TypeError, "type %.200s does not inherit from 'Enum' or 'Flag'",
+ type->tp_name);
+ return -1;
+ }
+ return bool(have_flag);
+}
+
+PyObject *QEnumMacro(PyObject *pyenum, bool flag)
+{
+ /*
+ * This is the official interface of 'QEnum'. It first calls 'analyzePyEnum'.
+ * When called as toplevel enum, it simply returns after some checks.
+ * Otherwise, 'pyenum' is stored for later use by the meta class registation.
+ */
+ int computedFlag = isFlag(pyenum);
+ if (computedFlag < 0)
+ return nullptr;
+ if (bool(computedFlag) != flag) {
+ AutoDecRef name(PyObject_GetAttr(pyenum, PyMagicName::qualname()));
+ auto cname = String::toCString(name);
+ const char *e = "Enum";
+ const char *f = "Flag";
+ PyErr_Format(PyExc_TypeError, "expected '%s' but got '%s' (%.200s)",
+ flag ? f : e, flag ? e : f, cname);
+ return nullptr;
+ }
+ auto ok = analyzePyEnum(pyenum);
+ if (ok == nullptr)
+ return nullptr;
+ if (is_module_code()) {
+ // This is a toplevel enum which we resolve immediately.
+ Py_INCREF(pyenum);
+ return pyenum;
+ }
+
+ Py_ssize_t lineno = get_lineno();
+ if (lineno < 0)
+ return nullptr;
+ // Handle the rest via line number and the meta class.
+ Py_INCREF(pyenum);
+ Py_XDECREF(enumCollector[lineno]);
+ enumCollector[lineno] = pyenum;
+ Py_RETURN_NONE;
+}
+
+std::vector<PyObject *> resolveDelayedQEnums(PyTypeObject *containerType)
+{
+ /*
+ * This is the internal interface of 'QEnum'.
+ * It is called at the end of the meta class call 'SbkObjectTypeTpNew' via
+ * MetaObjectBuilderPrivate::parsePythonType and resolves the collected
+ * Python Enum arguments. The result is then registered.
+ */
+ if (enumCollector.empty())
+ return {};
+ PyObject *obContainerType = reinterpret_cast<PyObject *>(containerType);
+ Py_ssize_t lineno = get_lineno();
+
+ std::vector<PyObject *> result;
+
+ auto it = enumCollector.begin();
+ while (it != enumCollector.end()) {
+ int nr = it->first;
+ PyObject *pyenum = it->second;
+ if (nr >= lineno) {
+ AutoDecRef name(PyObject_GetAttr(pyenum, PyMagicName::name()));
+ if (name.isNull() || PyObject_SetAttr(obContainerType, name, pyenum) < 0)
+ return {};
+ result.push_back(pyenum);
+ it = enumCollector.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ return result;
+}
+
+} // namespace Enum
+} // namespace Shiboken
+
+//
+///////////////////////////////////////////////////////////////
diff --git a/sources/pyside6/libpyside/pysideqenum.h b/sources/pyside6/libpyside/pysideqenum.h
new file mode 100644
index 000000000..fc4e55982
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideqenum.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 PYSIDE_QENUM_H
+#define PYSIDE_QENUM_H
+
+#include <pysidemacros.h>
+#include <vector>
+
+namespace PySide { namespace QEnum {
+
+// PYSIDE-957: Support the QEnum macro
+PYSIDE_API PyObject *QEnumMacro(PyObject *, bool);
+PYSIDE_API int isFlag(PyObject *);
+PYSIDE_API std::vector<PyObject *> resolveDelayedQEnums(PyTypeObject *);
+PYSIDE_API void init();
+
+} // namespace QEnum
+} // namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysideqflags.cpp b/sources/pyside6/libpyside/pysideqflags.cpp
new file mode 100644
index 000000000..b07a73332
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideqflags.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "pysideqflags.h"
+
+#include <autodecref.h>
+#include <sbkenum.h>
+
+extern "C" {
+ struct SbkConverter;
+
+ struct PySideQFlagsTypePrivate
+ {
+ SbkConverter **converterPtr;
+ SbkConverter *converter;
+ };
+ /**
+ * Type of all QFlags
+ */
+ struct PySideQFlagsType
+ {
+ PyTypeObject type;
+ };
+
+ #define PYSIDE_QFLAGS(X) reinterpret_cast<PySideQFlagsObject *>(X)
+
+ PyObject *PySideQFlagsNew(PyTypeObject *type, PyObject *args, PyObject * /* kwds */)
+ {
+ long val = 0;
+ if (PyTuple_GET_SIZE(args)) {
+ PyObject *arg = PyTuple_GET_ITEM(args, 0);
+ if (Shiboken::isShibokenEnum(arg)) {// faster call
+ val = Shiboken::Enum::getValue(arg);
+ } else if (PyNumber_Check(arg)) {
+ Shiboken::AutoDecRef number(PyNumber_Long(arg));
+ val = PyLong_AsLong(number);
+ } else {
+ PyErr_SetString(PyExc_TypeError,"QFlags must be created using enums or numbers.");
+ return 0;
+ }
+ }
+ PySideQFlagsObject *self = PyObject_New(PySideQFlagsObject, type);
+ self->ob_value = val;
+ return reinterpret_cast<PyObject *>(self);
+ }
+
+ static long getNumberValue(PyObject *v)
+ {
+ Shiboken::AutoDecRef number(PyNumber_Long(v));
+ return PyLong_AsLong(number);
+ }
+
+ static PyObject *qflag_int(PyObject *self)
+ {
+ return PyLong_FromLong(reinterpret_cast<PySideQFlagsObject*>(self)->ob_value);
+ }
+
+ PyObject *PySideQFlagsRichCompare(PyObject *self, PyObject *other, int op)
+ {
+ int result = 0;
+ if (!PyNumber_Check(other)) {
+ PyErr_BadArgument();
+ return NULL;
+ }
+
+ long valA = PYSIDE_QFLAGS(self)->ob_value;
+ long valB = getNumberValue(other);
+
+ if (self == other) {
+ result = 1;
+ } else {
+ switch (op) {
+ case Py_EQ:
+ result = (valA == valB);
+ break;
+ case Py_NE:
+ result = (valA != valB);
+ break;
+ case Py_LE:
+ result = (valA <= valB);
+ break;
+ case Py_GE:
+ result = (valA >= valB);
+ break;
+ case Py_LT:
+ result = (valA < valB);
+ break;
+ case Py_GT:
+ result = (valA > valB);
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+ }
+ if (result)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }
+}
+
+namespace PySide
+{
+namespace QFlags
+{
+ static PyType_Slot SbkNewQFlagsType_slots[] = {
+ {Py_nb_bool, 0},
+ {Py_nb_invert, 0},
+ {Py_nb_and, 0},
+ {Py_nb_xor, 0},
+ {Py_nb_or, 0},
+ {Py_nb_int, reinterpret_cast<void*>(qflag_int)},
+ {Py_nb_index, reinterpret_cast<void*>(qflag_int)},
+ {Py_tp_new, (void *)PySideQFlagsNew},
+ {Py_tp_richcompare, (void *)PySideQFlagsRichCompare},
+ {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {0, 0}
+ };
+ static PyType_Spec SbkNewQFlagsType_spec = {
+ "missing QFlags name", // to be inserted later
+ sizeof(PySideQFlagsObject),
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES,
+ SbkNewQFlagsType_slots,
+ };
+
+ PyTypeObject *create(const char *name, PyType_Slot numberMethods[])
+ {
+ char qualname[200];
+ // PYSIDE-747: Here we insert now the full class name.
+ strcpy(qualname, name);
+ // Careful: SbkType_FromSpec does not allocate the string.
+ PyType_Spec newspec;
+ newspec.name = strdup(qualname);
+ newspec.basicsize = SbkNewQFlagsType_spec.basicsize;
+ newspec.itemsize = SbkNewQFlagsType_spec.itemsize;
+ newspec.flags = SbkNewQFlagsType_spec.flags;
+ int idx = -1;
+ while (numberMethods[++idx].slot) {
+ assert(SbkNewQFlagsType_slots[idx].slot == numberMethods[idx].slot);
+ SbkNewQFlagsType_slots[idx].pfunc = numberMethods[idx].pfunc;
+ }
+ newspec.slots = SbkNewQFlagsType_spec.slots;
+ PyTypeObject *type = (PyTypeObject *)SbkType_FromSpec(&newspec);
+ Py_TYPE(type) = &PyType_Type;
+
+ PySideQFlagsType *flagsType = reinterpret_cast<PySideQFlagsType *>(type);
+ PepType_PFTP(flagsType)->converterPtr = &PepType_PFTP(flagsType)->converter;
+
+ if (PyType_Ready(type) < 0)
+ return 0;
+
+ return type;
+ }
+
+ PySideQFlagsObject *newObject(long value, PyTypeObject *type)
+ {
+ PySideQFlagsObject *qflags = PyObject_New(PySideQFlagsObject, type);
+ qflags->ob_value = value;
+ return qflags;
+ }
+
+ long getValue(PySideQFlagsObject *self)
+ {
+ return self->ob_value;
+ }
+}
+}
diff --git a/sources/pyside6/libpyside/pysideqflags.h b/sources/pyside6/libpyside/pysideqflags.h
new file mode 100644
index 000000000..71f30808d
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideqflags.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_QFLAGS_H
+#define PYSIDE_QFLAGS_H
+
+#include <sbkpython.h>
+#include "pysidemacros.h"
+
+
+extern "C"
+{
+ struct PYSIDE_API PySideQFlagsObject {
+ PyObject_HEAD
+ long ob_value;
+ };
+
+ PYSIDE_API PyObject* PySideQFlagsNew(PyTypeObject *type, PyObject *args, PyObject *kwds);
+ PYSIDE_API PyObject* PySideQFlagsRichCompare(PyObject *self, PyObject *other, int op);
+}
+
+
+namespace PySide
+{
+namespace QFlags
+{
+ /**
+ * Creates a new QFlags type.
+ */
+ PYSIDE_API PyTypeObject *create(const char* name, PyType_Slot *numberMethods);
+ /**
+ * Creates a new QFlags instance of type \p type and value \p value.
+ */
+ PYSIDE_API PySideQFlagsObject* newObject(long value, PyTypeObject* type);
+ /**
+ * Returns the value held by a QFlag.
+ */
+ PYSIDE_API long getValue(PySideQFlagsObject* self);
+}
+}
+
+#endif
+
diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp
new file mode 100644
index 000000000..d14f32525
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidesignal.cpp
@@ -0,0 +1,1040 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 <sbkpython.h>
+#include "pysidesignal.h"
+#include "pysidesignal_p.h"
+#include "pysidestaticstrings.h"
+#include "signalmanager.h"
+
+#include <shiboken.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QMetaMethod>
+#include <QtCore/QMetaObject>
+#include <signature.h>
+
+#include <algorithm>
+#include <utility>
+
+#define QT_SIGNAL_SENTINEL '2'
+
+namespace PySide {
+namespace Signal {
+ //aux
+ class SignalSignature {
+ public:
+ SignalSignature() = default;
+ explicit SignalSignature(QByteArray parameterTypes) :
+ m_parameterTypes(std::move(parameterTypes)) {}
+ explicit SignalSignature(QByteArray parameterTypes, QMetaMethod::Attributes attributes) :
+ m_parameterTypes(std::move(parameterTypes)),
+ m_attributes(attributes) {}
+
+ QByteArray m_parameterTypes;
+ QMetaMethod::Attributes m_attributes = QMetaMethod::Compatibility;
+ };
+
+ static QByteArray buildSignature(const QByteArray &, const QByteArray &);
+ static void appendSignature(PySideSignal *, const SignalSignature &);
+ static void instanceInitialize(PySideSignalInstance *, PyObject *, PySideSignal *, PyObject *, int);
+ static QByteArray parseSignature(PyObject *);
+ static PyObject *buildQtCompatible(const QByteArray &);
+}
+}
+
+extern "C"
+{
+
+// Signal methods
+static int signalTpInit(PyObject *, PyObject *, PyObject *);
+static void signalFree(void *);
+static void signalInstanceFree(void *);
+static PyObject *signalGetItem(PyObject *self, PyObject *key);
+static PyObject *signalToString(PyObject *self);
+static PyObject *signalDescrGet(PyObject *self, PyObject *obj, PyObject *type);
+
+// Signal Instance methods
+static PyObject *signalInstanceConnect(PyObject *, PyObject *, PyObject *);
+static PyObject *signalInstanceDisconnect(PyObject *, PyObject *);
+static PyObject *signalInstanceEmit(PyObject *, PyObject *);
+static PyObject *signalInstanceGetItem(PyObject *, PyObject *);
+
+static PyObject *signalInstanceCall(PyObject *self, PyObject *args, PyObject *kw);
+static PyObject *signalCall(PyObject *, PyObject *, PyObject *);
+
+static PyObject *metaSignalCheck(PyObject *, PyObject *);
+
+
+static PyMethodDef MetaSignal_methods[] = {
+ {"__instancecheck__", (PyCFunction)metaSignalCheck, METH_O|METH_STATIC, NULL},
+ {0, 0, 0, 0}
+};
+
+static PyType_Slot PySideMetaSignalType_slots[] = {
+ {Py_tp_methods, reinterpret_cast<void *>(MetaSignal_methods)},
+ {Py_tp_base, reinterpret_cast<void *>(&PyType_Type)},
+ {Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)},
+ {0, 0}
+};
+static PyType_Spec PySideMetaSignalType_spec = {
+ "2:PySide6.QtCore.MetaSignal",
+ 0,
+ // sizeof(PyHeapTypeObject) is filled in by SbkType_FromSpecWithBases
+ // which calls PyType_Ready which calls inherit_special.
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideMetaSignalType_slots,
+};
+
+
+static PyTypeObject *PySideMetaSignalTypeF(void)
+{
+ static PyTypeObject *type = nullptr;
+ if (!type) {
+ PyObject *bases = Py_BuildValue("(O)", &PyType_Type);
+ type = (PyTypeObject *)SbkType_FromSpecWithBases(&PySideMetaSignalType_spec, bases);
+ Py_XDECREF(bases);
+ }
+ return type;
+}
+
+static PyType_Slot PySideSignalType_slots[] = {
+ {Py_mp_subscript, reinterpret_cast<void *>(signalGetItem)},
+ {Py_tp_descr_get, reinterpret_cast<void *>(signalDescrGet)},
+ {Py_tp_call, reinterpret_cast<void *>(signalCall)},
+ {Py_tp_str, reinterpret_cast<void *>(signalToString)},
+ {Py_tp_init, reinterpret_cast<void *>(signalTpInit)},
+ {Py_tp_new, reinterpret_cast<void *>(PyType_GenericNew)},
+ {Py_tp_free, reinterpret_cast<void *>(signalFree)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)},
+ {0, 0}
+};
+static PyType_Spec PySideSignalType_spec = {
+ "2:PySide6.QtCore.Signal",
+ sizeof(PySideSignal),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideSignalType_slots,
+};
+
+
+PyTypeObject *PySideSignalTypeF(void)
+{
+ static PyTypeObject *type = nullptr;
+ if (!type) {
+ type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideSignalType_spec));
+ PyTypeObject *hold = Py_TYPE(type);
+ Py_TYPE(type) = PySideMetaSignalTypeF();
+ Py_INCREF(Py_TYPE(type));
+ Py_DECREF(hold);
+ }
+ return type;
+}
+
+static PyMethodDef SignalInstance_methods[] = {
+ {"connect", (PyCFunction)signalInstanceConnect, METH_VARARGS|METH_KEYWORDS, 0},
+ {"disconnect", signalInstanceDisconnect, METH_VARARGS, 0},
+ {"emit", signalInstanceEmit, METH_VARARGS, 0},
+ {0, 0, 0, 0} /* Sentinel */
+};
+
+static PyType_Slot PySideSignalInstanceType_slots[] = {
+ {Py_mp_subscript, reinterpret_cast<void *>(signalInstanceGetItem)},
+ {Py_tp_call, reinterpret_cast<void *>(signalInstanceCall)},
+ {Py_tp_methods, reinterpret_cast<void *>(SignalInstance_methods)},
+ {Py_tp_new, reinterpret_cast<void *>(PyType_GenericNew)},
+ {Py_tp_free, reinterpret_cast<void *>(signalInstanceFree)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)},
+ {0, 0}
+};
+static PyType_Spec PySideSignalInstanceType_spec = {
+ "2:PySide6.QtCore.SignalInstance",
+ sizeof(PySideSignalInstance),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideSignalInstanceType_slots,
+};
+
+
+PyTypeObject *PySideSignalInstanceTypeF(void)
+{
+ static PyTypeObject *type =
+ reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideSignalInstanceType_spec));
+ return type;
+}
+
+static int signalTpInit(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static PyObject *emptyTuple = nullptr;
+ static const char *kwlist[] = {"name", "arguments", nullptr};
+ char *argName = nullptr;
+ PyObject *argArguments = nullptr;
+
+ if (emptyTuple == 0)
+ emptyTuple = PyTuple_New(0);
+
+ if (!PyArg_ParseTupleAndKeywords(emptyTuple, kwds,
+ "|sO:QtCore.Signal", const_cast<char **>(kwlist), &argName, &argArguments))
+ return -1;
+
+ bool tupledArgs = false;
+ PySideSignal *data = reinterpret_cast<PySideSignal *>(self);
+ if (!data->data)
+ data->data = new PySideSignalData;
+ if (argName)
+ data->data->signalName = argName;
+
+ data->data->signalArguments = new QByteArrayList();
+ if (argArguments && PySequence_Check(argArguments)) {
+ Py_ssize_t argument_size = PySequence_Size(argArguments);
+ for (Py_ssize_t i = 0; i < argument_size; ++i) {
+ PyObject *item = PySequence_GetItem(argArguments, i);
+ PyObject *strObj = PyUnicode_AsUTF8String(item);
+ char *s = PyBytes_AsString(strObj);
+ Py_DECREF(strObj);
+ Py_DECREF(item);
+ if (s != nullptr)
+ data->data->signalArguments->append(QByteArray(s));
+ }
+ }
+
+ for (Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) {
+ PyObject *arg = PyTuple_GET_ITEM(args, i);
+ if (PySequence_Check(arg) && !Shiboken::String::check(arg) && !PyEnumMeta_Check(arg)) {
+ tupledArgs = true;
+ const auto sig = PySide::Signal::parseSignature(arg);
+ PySide::Signal::appendSignature(
+ data,
+ PySide::Signal::SignalSignature(sig));
+ }
+ }
+
+ if (!tupledArgs) {
+ const auto sig = PySide::Signal::parseSignature(args);
+ PySide::Signal::appendSignature(
+ data,
+ PySide::Signal::SignalSignature(sig));
+ }
+
+ return 0;
+}
+
+static void signalFree(void *self)
+{
+ auto pySelf = reinterpret_cast<PyObject *>(self);
+ auto data = reinterpret_cast<PySideSignal *>(self);
+ delete data->data;
+ data->data = nullptr;
+ Py_XDECREF(data->homonymousMethod);
+ data->homonymousMethod = 0;
+
+ Py_TYPE(pySelf)->tp_base->tp_free(self);
+}
+
+static PyObject *signalGetItem(PyObject *self, PyObject *key)
+{
+ auto data = reinterpret_cast<PySideSignal *>(self);
+ QByteArray sigKey;
+ if (key) {
+ sigKey = PySide::Signal::parseSignature(key);
+ } else {
+ sigKey = data->data == nullptr || data->data->signatures.isEmpty()
+ ? PySide::Signal::voidType() : data->data->signatures.constFirst().signature;
+ }
+ auto sig = PySide::Signal::buildSignature(data->data->signalName, sigKey);
+ return Shiboken::String::fromCString(sig.constData());
+}
+
+
+static PyObject *signalToString(PyObject *self)
+{
+ return signalGetItem(self, 0);
+}
+
+static void signalInstanceFree(void *self)
+{
+ auto pySelf = reinterpret_cast<PyObject *>(self);
+ auto data = reinterpret_cast<PySideSignalInstance *>(self);
+
+ PySideSignalInstancePrivate *dataPvt = data->d;
+
+ Py_XDECREF(dataPvt->homonymousMethod);
+
+ if (dataPvt->next) {
+ Py_DECREF(dataPvt->next);
+ dataPvt->next = 0;
+ }
+ delete dataPvt;
+ data->d = 0;
+ Py_TYPE(pySelf)->tp_base->tp_free(self);
+}
+
+static PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *slot = nullptr;
+ PyObject *type = nullptr;
+ static const char *kwlist[] = {"slot", "type", nullptr};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O|O:SignalInstance", const_cast<char **>(kwlist), &slot, &type))
+ return 0;
+
+ PySideSignalInstance *source = reinterpret_cast<PySideSignalInstance *>(self);
+ Shiboken::AutoDecRef pyArgs(PyList_New(0));
+
+ bool match = false;
+ if (Py_TYPE(slot) == PySideSignalInstanceTypeF()) {
+ PySideSignalInstance *sourceWalk = source;
+ PySideSignalInstance *targetWalk;
+
+ //find best match
+ while (sourceWalk && !match) {
+ targetWalk = reinterpret_cast<PySideSignalInstance *>(slot);
+ while (targetWalk && !match) {
+ if (QMetaObject::checkConnectArgs(sourceWalk->d->signature, targetWalk->d->signature)) {
+ PyList_Append(pyArgs, sourceWalk->d->source);
+ Shiboken::AutoDecRef sourceSignature(PySide::Signal::buildQtCompatible(sourceWalk->d->signature));
+ PyList_Append(pyArgs, sourceSignature);
+
+ PyList_Append(pyArgs, targetWalk->d->source);
+ Shiboken::AutoDecRef targetSignature(PySide::Signal::buildQtCompatible(targetWalk->d->signature));
+ PyList_Append(pyArgs, targetSignature);
+
+ match = true;
+ }
+ targetWalk = reinterpret_cast<PySideSignalInstance *>(targetWalk->d->next);
+ }
+ sourceWalk = reinterpret_cast<PySideSignalInstance *>(sourceWalk->d->next);
+ }
+ } else {
+ // Check signature of the slot (method or function) to match signal
+ int slotArgs = -1;
+ bool useSelf = false;
+ bool isMethod = PyMethod_Check(slot);
+ bool isFunction = PyFunction_Check(slot);
+ bool matchedSlot = false;
+
+ QByteArray functionName;
+ PySideSignalInstance *it = source;
+
+ if (isMethod || isFunction) {
+ PyObject *function = isMethod ? PyMethod_GET_FUNCTION(slot) : slot;
+ auto *objCode = reinterpret_cast<PepCodeObject *>(PyFunction_GET_CODE(function));
+ useSelf = isMethod;
+ slotArgs = PepCode_GET_FLAGS(objCode) & CO_VARARGS ? -1 : PepCode_GET_ARGCOUNT(objCode);
+ if (useSelf)
+ slotArgs -= 1;
+
+ // Get signature args
+ bool isShortCircuit = false;
+ int signatureArgs = 0;
+ QStringList argsSignature;
+
+ argsSignature = PySide::Signal::getArgsFromSignature(it->d->signature,
+ &isShortCircuit);
+ signatureArgs = argsSignature.length();
+
+ // Iterate the possible types of connection for this signal and compare
+ // it with slot arguments
+ if (signatureArgs != slotArgs) {
+ while (it->d->next != nullptr) {
+ it = it->d->next;
+ argsSignature = PySide::Signal::getArgsFromSignature(it->d->signature,
+ &isShortCircuit);
+ signatureArgs = argsSignature.length();
+ if (signatureArgs == slotArgs) {
+ matchedSlot = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Adding references to pyArgs
+ PyList_Append(pyArgs, source->d->source);
+
+ if (matchedSlot) {
+ // If a slot matching the same number of arguments was found,
+ // include signature to the pyArgs
+ Shiboken::AutoDecRef signature(PySide::Signal::buildQtCompatible(it->d->signature));
+ PyList_Append(pyArgs, signature);
+ } else {
+ // Try the first by default if the slot was not found
+ Shiboken::AutoDecRef signature(PySide::Signal::buildQtCompatible(source->d->signature));
+ PyList_Append(pyArgs, signature);
+ }
+ PyList_Append(pyArgs, slot);
+ match = true;
+ }
+
+ if (type)
+ PyList_Append(pyArgs, type);
+
+ if (match) {
+ Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source,
+ PySide::PyName::qtConnect()));
+ if (pyMethod.isNull()) { // PYSIDE-79: check if pyMethod exists.
+ PyErr_SetString(PyExc_RuntimeError, "method 'connect' vanished!");
+ return 0;
+ }
+ PyObject *result = PyObject_CallObject(pyMethod, tupleArgs);
+ if (result == Py_True || result == Py_False)
+ return result;
+ Py_XDECREF(result);
+ }
+ if (!PyErr_Occurred()) // PYSIDE-79: inverse the logic. A Null return needs an error.
+ PyErr_Format(PyExc_RuntimeError, "Failed to connect signal %s.",
+ source->d->signature.constData());
+ return 0;
+}
+
+static int argCountInSignature(const char *signature)
+{
+ return QByteArray(signature).count(",") + 1;
+}
+
+static PyObject *signalInstanceEmit(PyObject *self, PyObject *args)
+{
+ PySideSignalInstance *source = reinterpret_cast<PySideSignalInstance *>(self);
+
+ Shiboken::AutoDecRef pyArgs(PyList_New(0));
+ int numArgsGiven = PySequence_Fast_GET_SIZE(args);
+ int numArgsInSignature = argCountInSignature(source->d->signature);
+
+ // If number of arguments given to emit is smaller than the first source signature expects,
+ // it is possible it's a case of emitting a signal with default parameters.
+ // Search through all the overloaded signals with the same name, and try to find a signature
+ // with the same number of arguments as given to emit, and is also marked as a cloned method
+ // (which in metaobject parlance means a signal with default parameters).
+ // @TODO: This should be improved to take into account argument types as well. The current
+ // assumption is there are no signals which are both overloaded on argument types and happen to
+ // have signatures with default parameters.
+ if (numArgsGiven < numArgsInSignature) {
+ PySideSignalInstance *possibleDefaultInstance = source;
+ while ((possibleDefaultInstance = possibleDefaultInstance->d->next)) {
+ if (possibleDefaultInstance->d->attributes & QMetaMethod::Cloned
+ && argCountInSignature(possibleDefaultInstance->d->signature) == numArgsGiven) {
+ source = possibleDefaultInstance;
+ break;
+ }
+ }
+ }
+ Shiboken::AutoDecRef sourceSignature(PySide::Signal::buildQtCompatible(source->d->signature));
+
+ PyList_Append(pyArgs, sourceSignature);
+ for (Py_ssize_t i = 0, max = PyTuple_Size(args); i < max; i++)
+ PyList_Append(pyArgs, PyTuple_GetItem(args, i));
+
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source,
+ PySide::PyName::qtEmit()));
+
+ Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
+ return PyObject_CallObject(pyMethod, tupleArgs);
+}
+
+static PyObject *signalInstanceGetItem(PyObject *self, PyObject *key)
+{
+ auto data = reinterpret_cast<PySideSignalInstance *>(self);
+ const auto sigName = data->d->signalName;
+ const auto sigKey = PySide::Signal::parseSignature(key);
+ const auto sig = PySide::Signal::buildSignature(sigName, sigKey);
+ while (data) {
+ if (data->d->signature == sig) {
+ PyObject *result = reinterpret_cast<PyObject *>(data);
+ Py_INCREF(result);
+ return result;
+ }
+ data = data->d->next;
+ }
+
+ PyErr_Format(PyExc_IndexError, "Signature %s not found for signal: %s",
+ sig.constData(), sigName.constData());
+ return 0;
+}
+
+static PyObject *signalInstanceDisconnect(PyObject *self, PyObject *args)
+{
+ auto source = reinterpret_cast<PySideSignalInstance *>(self);
+ Shiboken::AutoDecRef pyArgs(PyList_New(0));
+
+ PyObject *slot;
+ if (PyTuple_Check(args) && PyTuple_GET_SIZE(args))
+ slot = PyTuple_GET_ITEM(args, 0);
+ else
+ slot = Py_None;
+
+ bool match = false;
+ if (Py_TYPE(slot) == PySideSignalInstanceTypeF()) {
+ PySideSignalInstance *target = reinterpret_cast<PySideSignalInstance *>(slot);
+ if (QMetaObject::checkConnectArgs(source->d->signature, target->d->signature)) {
+ PyList_Append(pyArgs, source->d->source);
+ Shiboken::AutoDecRef source_signature(PySide::Signal::buildQtCompatible(source->d->signature));
+ PyList_Append(pyArgs, source_signature);
+
+ PyList_Append(pyArgs, target->d->source);
+ Shiboken::AutoDecRef target_signature(PySide::Signal::buildQtCompatible(target->d->signature));
+ PyList_Append(pyArgs, target_signature);
+ match = true;
+ }
+ } else {
+ //try the first signature
+ PyList_Append(pyArgs, source->d->source);
+ Shiboken::AutoDecRef signature(PySide::Signal::buildQtCompatible(source->d->signature));
+ PyList_Append(pyArgs, signature);
+
+ // disconnect all, so we need to use the c++ signature disconnect(qobj, signal, 0, 0)
+ if (slot == Py_None)
+ PyList_Append(pyArgs, slot);
+ PyList_Append(pyArgs, slot);
+ match = true;
+ }
+
+ if (match) {
+ Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source,
+ PySide::PyName::qtDisconnect()));
+ PyObject *result = PyObject_CallObject(pyMethod, tupleArgs);
+ if (!result || result == Py_True)
+ return result;
+ else
+ Py_DECREF(result);
+ }
+
+ PyErr_Format(PyExc_RuntimeError, "Failed to disconnect signal %s.",
+ source->d->signature.constData());
+ return 0;
+}
+
+// PYSIDE-68: Supply the missing __get__ function
+static PyObject *signalDescrGet(PyObject *self, PyObject *obj, PyObject * /*type*/)
+{
+ auto signal = reinterpret_cast<PySideSignal *>(self);
+ // Return the unbound signal if there is nothing to bind it to.
+ if (obj == nullptr || obj == Py_None) {
+ Py_INCREF(self);
+ return self;
+ }
+ Shiboken::AutoDecRef name(Py_BuildValue("s", signal->data->signalName.data()));
+ return reinterpret_cast<PyObject *>(PySide::Signal::initialize(signal, name, obj));
+}
+
+static PyObject *signalCall(PyObject *self, PyObject *args, PyObject *kw)
+{
+ auto signal = reinterpret_cast<PySideSignal *>(self);
+
+ // Native C++ signals can't be called like functions, thus we throw an exception.
+ // The only way calling a signal can succeed (the Python equivalent of C++'s operator() )
+ // is when a method with the same name as the signal is attached to an object.
+ // An example is QProcess::error() (don't check the docs, but the source code of qprocess.h).
+ if (!signal->homonymousMethod) {
+ PyErr_SetString(PyExc_TypeError, "native Qt signal is not callable");
+ return 0;
+ }
+
+ descrgetfunc getDescriptor = Py_TYPE(signal->homonymousMethod)->tp_descr_get;
+
+ // Check if there exists a method with the same name as the signal, which is also a static
+ // method in C++ land.
+ Shiboken::AutoDecRef homonymousMethod(getDescriptor(signal->homonymousMethod, 0, 0));
+ if (PyCFunction_Check(homonymousMethod)
+ && (PyCFunction_GET_FLAGS(homonymousMethod.object()) & METH_STATIC)) {
+#if PY_VERSION_HEX >= 0x03090000
+ return PyObject_Call(homonymousMethod, args, kw);
+#else
+ return PyCFunction_Call(homonymousMethod, args, kw);
+#endif
+ }
+
+ // Assumes homonymousMethod is not a static method.
+ ternaryfunc callFunc = Py_TYPE(signal->homonymousMethod)->tp_call;
+ return callFunc(homonymousMethod, args, kw);
+}
+
+static PyObject *signalInstanceCall(PyObject *self, PyObject *args, PyObject *kw)
+{
+ auto PySideSignal = reinterpret_cast<PySideSignalInstance *>(self);
+ if (!PySideSignal->d->homonymousMethod) {
+ PyErr_SetString(PyExc_TypeError, "native Qt signal is not callable");
+ return 0;
+ }
+
+ descrgetfunc getDescriptor = Py_TYPE(PySideSignal->d->homonymousMethod)->tp_descr_get;
+ Shiboken::AutoDecRef homonymousMethod(getDescriptor(PySideSignal->d->homonymousMethod, PySideSignal->d->source, 0));
+#if PY_VERSION_HEX >= 0x03090000
+ return PyObject_Call(homonymousMethod, args, kw);
+#else
+ return PyCFunction_Call(homonymousMethod, args, kw);
+#endif
+}
+
+static PyObject *metaSignalCheck(PyObject * /* klass */, PyObject *arg)
+{
+ if (PyType_IsSubtype(Py_TYPE(arg), PySideSignalInstanceTypeF()))
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+} // extern "C"
+
+namespace PySide {
+namespace Signal {
+
+static const char *MetaSignal_SignatureStrings[] = {
+ "PySide6.QtCore.MetaSignal.__instancecheck__(object:object)->bool",
+ nullptr}; // Sentinel
+
+static const char *Signal_SignatureStrings[] = {
+ "PySide6.QtCore.Signal(*types:type,name:str=nullptr,arguments:str=nullptr)",
+ nullptr}; // Sentinel
+
+static const char *SignalInstance_SignatureStrings[] = {
+ "PySide6.QtCore.SignalInstance.connect(slot:object,type:type=nullptr)",
+ "PySide6.QtCore.SignalInstance.disconnect(slot:object=nullptr)",
+ "PySide6.QtCore.SignalInstance.emit(*args:typing.Any)",
+ nullptr}; // Sentinel
+
+void init(PyObject *module)
+{
+ if (InitSignatureStrings(PySideMetaSignalTypeF(), MetaSignal_SignatureStrings) < 0)
+ return;
+ Py_INCREF(PySideMetaSignalTypeF());
+ PyModule_AddObject(module, "MetaSignal", reinterpret_cast<PyObject *>(PySideMetaSignalTypeF()));
+
+ if (InitSignatureStrings(PySideSignalTypeF(), Signal_SignatureStrings) < 0)
+ return;
+ Py_INCREF(PySideSignalTypeF());
+ PyModule_AddObject(module, "Signal", reinterpret_cast<PyObject *>(PySideSignalTypeF()));
+
+ if (InitSignatureStrings(PySideSignalInstanceTypeF(), SignalInstance_SignatureStrings) < 0)
+ return;
+ Py_INCREF(PySideSignalInstanceTypeF());
+ PyModule_AddObject(module, "SignalInstance", reinterpret_cast<PyObject *>(PySideSignalInstanceTypeF()));
+}
+
+bool checkType(PyObject *pyObj)
+{
+ if (pyObj)
+ return PyType_IsSubtype(Py_TYPE(pyObj), PySideSignalTypeF());
+ return false;
+}
+
+void updateSourceObject(PyObject *source)
+{
+ PyTypeObject *objType = reinterpret_cast<PyTypeObject *>(PyObject_Type(source));
+
+ Py_ssize_t pos = 0;
+ PyObject *value;
+ PyObject *key;
+
+ while (PyDict_Next(objType->tp_dict, &pos, &key, &value)) {
+ if (PyObject_TypeCheck(value, PySideSignalTypeF())) {
+ Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject *>(PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF())));
+ instanceInitialize(signalInstance.cast<PySideSignalInstance *>(), key, reinterpret_cast<PySideSignal *>(value), source, 0);
+ PyObject_SetAttr(source, key, signalInstance);
+ }
+ }
+
+ Py_XDECREF(objType);
+}
+
+QByteArray getTypeName(PyObject *type)
+{
+ if (PyType_Check(type)) {
+ if (PyType_IsSubtype(reinterpret_cast<PyTypeObject *>(type),
+ reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()))) {
+ auto objType = reinterpret_cast<SbkObjectType *>(type);
+ return Shiboken::ObjectType::getOriginalName(objType);
+ }
+ // Translate python types to Qt names
+ auto objType = reinterpret_cast<PyTypeObject *>(type);
+ if (Shiboken::String::checkType(objType))
+ return QByteArrayLiteral("QString");
+ if (objType == &PyInt_Type)
+ return QByteArrayLiteral("int");
+ if (objType == &PyLong_Type)
+ return QByteArrayLiteral("long");
+ if (objType == &PyFloat_Type)
+ return QByteArrayLiteral("double");
+ if (objType == &PyBool_Type)
+ return QByteArrayLiteral("bool");
+ if (objType == &PyList_Type)
+ return QByteArrayLiteral("QVariantList");
+ if (Py_TYPE(objType) == SbkEnumType_TypeF())
+ return Shiboken::Enum::getCppName(objType);
+ return QByteArrayLiteral("PyObject");
+ }
+ if (type == Py_None) // Must be checked before as Shiboken::String::check accepts Py_None
+ return voidType();
+ if (Shiboken::String::check(type)) {
+ QByteArray result = Shiboken::String::toCString(type);
+ if (result == "qreal")
+ result = sizeof(qreal) == sizeof(double) ? "double" : "float";
+ return result;
+ }
+ return QByteArray();
+}
+
+static QByteArray buildSignature(const QByteArray &name, const QByteArray &signature)
+{
+ return QMetaObject::normalizedSignature(name + '(' + signature + ')');
+}
+
+static QByteArray parseSignature(PyObject *args)
+{
+ if (args && (Shiboken::String::check(args) || !PySequence_Check(args)))
+ return getTypeName(args);
+
+ QByteArray signature;
+ for (Py_ssize_t i = 0, i_max = PySequence_Size(args); i < i_max; i++) {
+ Shiboken::AutoDecRef arg(PySequence_GetItem(args, i));
+ const auto typeName = getTypeName(arg);
+ if (!typeName.isEmpty()) {
+ if (!signature.isEmpty())
+ signature += ',';
+ signature += typeName;
+ }
+ }
+ return signature;
+}
+
+static void appendSignature(PySideSignal *self, const SignalSignature &signature)
+{
+ self->data->signatures.append({signature.m_parameterTypes, signature.m_attributes});
+}
+
+static void instanceInitialize(PySideSignalInstance *self, PyObject *name, PySideSignal *data, PyObject *source, int index)
+{
+ self->d = new PySideSignalInstancePrivate;
+ PySideSignalInstancePrivate *selfPvt = self->d;
+ selfPvt->next = nullptr;
+ if (data->data->signalName.isEmpty())
+ data->data->signalName = Shiboken::String::toCString(name);
+ selfPvt->signalName = data->data->signalName;
+
+ selfPvt->source = source;
+ const auto &signature = data->data->signatures.at(index);
+ selfPvt->signature = buildSignature(self->d->signalName, signature.signature);
+ selfPvt->attributes = signature.attributes;
+ selfPvt->homonymousMethod = 0;
+ if (data->homonymousMethod) {
+ selfPvt->homonymousMethod = data->homonymousMethod;
+ Py_INCREF(selfPvt->homonymousMethod);
+ }
+ index++;
+
+ if (index < data->data->signatures.size()) {
+ selfPvt->next = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF());
+ instanceInitialize(selfPvt->next, name, data, source, index);
+ }
+}
+
+PySideSignalInstance *initialize(PySideSignal *self, PyObject *name, PyObject *object)
+{
+ PySideSignalInstance *instance = PyObject_New(PySideSignalInstance,
+ PySideSignalInstanceTypeF());
+ instanceInitialize(instance, name, self, object, 0);
+ auto sbkObj = reinterpret_cast<SbkObject *>(object);
+ if (!Shiboken::Object::wasCreatedByPython(sbkObj))
+ Py_INCREF(object); // PYSIDE-79: this flag was crucial for a wrapper call.
+ return instance;
+}
+
+bool connect(PyObject *source, const char *signal, PyObject *callback)
+{
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source,
+ PySide::PyName::qtConnect()));
+ if (pyMethod.isNull())
+ return false;
+
+ Shiboken::AutoDecRef pySignature(Shiboken::String::fromCString(signal));
+ Shiboken::AutoDecRef pyArgs(PyTuple_Pack(3, source, pySignature.object(), callback));
+ PyObject *result = PyObject_CallObject(pyMethod, pyArgs);
+ if (result == Py_False) {
+ PyErr_Format(PyExc_RuntimeError, "Failed to connect signal %s, to python callable object.", signal);
+ Py_DECREF(result);
+ result = 0;
+ }
+ return result;
+}
+
+PySideSignalInstance *newObjectFromMethod(PyObject *source, const QList<QMetaMethod>& methodList)
+{
+ PySideSignalInstance *root = nullptr;
+ PySideSignalInstance *previous = nullptr;
+ for (const QMetaMethod &m : methodList) {
+ PySideSignalInstance *item = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF());
+ if (!root)
+ root = item;
+
+ if (previous)
+ previous->d->next = item;
+
+ item->d = new PySideSignalInstancePrivate;
+ PySideSignalInstancePrivate *selfPvt = item->d;
+ selfPvt->source = source;
+ Py_INCREF(selfPvt->source); // PYSIDE-79: an INCREF is missing.
+ QByteArray cppName(m.methodSignature());
+ cppName.truncate(cppName.indexOf('('));
+ // separe SignalName
+ selfPvt->signalName = cppName;
+ selfPvt->signature = m.methodSignature();
+ selfPvt->attributes = m.attributes();
+ selfPvt->homonymousMethod = 0;
+ selfPvt->next = 0;
+ }
+ return root;
+}
+
+template<typename T>
+static typename T::value_type join(T t, const char *sep)
+{
+ typename T::value_type res;
+ if (t.isEmpty())
+ return res;
+
+ typename T::const_iterator it = t.begin();
+ typename T::const_iterator end = t.end();
+ res += *it;
+ ++it;
+
+ while (it != end) {
+ res += sep;
+ res += *it;
+ ++it;
+ }
+ return res;
+}
+
+static void _addSignalToWrapper(SbkObjectType *wrapperType, const char *signalName, PySideSignal *signal)
+{
+ auto typeDict = reinterpret_cast<PyTypeObject *>(wrapperType)->tp_dict;
+ PyObject *homonymousMethod;
+ if ((homonymousMethod = PyDict_GetItemString(typeDict, signalName))) {
+ Py_INCREF(homonymousMethod);
+ signal->homonymousMethod = homonymousMethod;
+ }
+ PyDict_SetItemString(typeDict, signalName, reinterpret_cast<PyObject *>(signal));
+}
+
+// This function is used by qStableSort to promote empty signatures
+static bool compareSignals(const SignalSignature &sig1, const SignalSignature &)
+{
+ return sig1.m_parameterTypes.isEmpty();
+}
+
+static PyObject *buildQtCompatible(const QByteArray &signature)
+{
+ const auto ba = QT_SIGNAL_SENTINEL + signature;
+ return Shiboken::String::fromStringAndSize(ba, ba.size());
+}
+
+void registerSignals(SbkObjectType *pyObj, const QMetaObject *metaObject)
+{
+ typedef QHash<QByteArray, QList<SignalSignature> > SignalSigMap;
+ SignalSigMap signalsFound;
+ for (int i = metaObject->methodOffset(), max = metaObject->methodCount(); i < max; ++i) {
+ QMetaMethod method = metaObject->method(i);
+
+ if (method.methodType() == QMetaMethod::Signal) {
+ QByteArray methodName(method.methodSignature());
+ methodName.chop(methodName.size() - methodName.indexOf('('));
+ SignalSignature signature;
+ signature.m_parameterTypes = join(method.parameterTypes(), ",");
+ if (method.attributes() & QMetaMethod::Cloned)
+ signature.m_attributes = QMetaMethod::Cloned;
+ signalsFound[methodName] << signature;
+ }
+ }
+
+ SignalSigMap::Iterator it = signalsFound.begin();
+ SignalSigMap::Iterator end = signalsFound.end();
+ for (; it != end; ++it) {
+ PySideSignal *self = PyObject_New(PySideSignal, PySideSignalTypeF());
+ self->data = new PySideSignalData;
+ self->data->signalName = it.key();
+ self->homonymousMethod = 0;
+
+ // Empty signatures comes first! So they will be the default signal signature
+ std::stable_sort(it.value().begin(), it.value().end(), &compareSignals);
+ SignalSigMap::mapped_type::const_iterator j = it.value().begin();
+ SignalSigMap::mapped_type::const_iterator endJ = it.value().end();
+ for (; j != endJ; ++j) {
+ const SignalSignature &sig = *j;
+ appendSignature(self, sig);
+ }
+
+ _addSignalToWrapper(pyObj, it.key(), self);
+ Py_DECREF(reinterpret_cast<PyObject *>(self));
+ }
+}
+
+PyObject *getObject(PySideSignalInstance *signal)
+{
+ return signal->d->source;
+}
+
+const char *getSignature(PySideSignalInstance *signal)
+{
+ return signal->d->signature;
+}
+
+QStringList getArgsFromSignature(const char *signature, bool *isShortCircuit)
+{
+ QString qsignature = QString::fromLatin1(signature).trimmed();
+ QStringList result;
+
+ if (isShortCircuit)
+ *isShortCircuit = !qsignature.contains(QLatin1Char('('));
+ if (qsignature.contains(QLatin1String("()")) || qsignature.contains(QLatin1String("(void)")))
+ return result;
+ if (qsignature.endsWith(QLatin1Char(')'))) {
+ const int paren = qsignature.indexOf(QLatin1Char('('));
+ if (paren >= 0) {
+ qsignature.chop(1);
+ qsignature.remove(0, paren + 1);
+ result = qsignature.split(QLatin1Char(','));
+ for (QString &type : result)
+ type = type.trimmed();
+ }
+ }
+ return result;
+}
+
+QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *callback, bool encodeName)
+{
+ QByteArray functionName;
+ int numArgs = -1;
+ bool useSelf = false;
+ bool isMethod = PyMethod_Check(callback);
+ bool isFunction = PyFunction_Check(callback);
+
+ if (isMethod || isFunction) {
+ PyObject *function = isMethod ? PyMethod_GET_FUNCTION(callback) : callback;
+ auto objCode = reinterpret_cast<PepCodeObject *>(PyFunction_GET_CODE(function));
+ functionName = Shiboken::String::toCString(PepFunction_GetName(function));
+ useSelf = isMethod;
+ numArgs = PepCode_GET_FLAGS(objCode) & CO_VARARGS ? -1 : PepCode_GET_ARGCOUNT(objCode);
+ } else if (PyCFunction_Check(callback)) {
+ const PyCFunctionObject *funcObj = reinterpret_cast<const PyCFunctionObject *>(callback);
+ functionName = PepCFunction_GET_NAMESTR(funcObj);
+ useSelf = PyCFunction_GET_SELF(funcObj);
+ const int flags = PyCFunction_GET_FLAGS(funcObj);
+
+ if (receiver) {
+ //Search for signature on metaobject
+ const QMetaObject *mo = receiver->metaObject();
+ QByteArray prefix(functionName);
+ prefix += '(';
+ for (int i = 0; i < mo->methodCount(); i++) {
+ QMetaMethod me = mo->method(i);
+ if ((strncmp(me.methodSignature(), prefix, prefix.size()) == 0) &&
+ QMetaObject::checkConnectArgs(signal, me.methodSignature())) {
+ numArgs = me.parameterTypes().size() + useSelf;
+ break;
+ }
+ }
+ }
+
+ if (numArgs == -1) {
+ if (flags & METH_VARARGS)
+ numArgs = -1;
+ else if (flags & METH_NOARGS)
+ numArgs = 0;
+ }
+ } else if (PyCallable_Check(callback)) {
+ functionName = "__callback" + QByteArray::number((qlonglong)callback);
+ }
+
+ Q_ASSERT(!functionName.isEmpty());
+
+ bool isShortCircuit = false;
+
+ const QString functionNameS = QLatin1String(functionName);
+ QString signature = encodeName ? codeCallbackName(callback, functionNameS) : functionNameS;
+ QStringList args = getArgsFromSignature(signal, &isShortCircuit);
+
+ if (!isShortCircuit) {
+ signature.append(QLatin1Char('('));
+ if (numArgs == -1)
+ numArgs = std::numeric_limits<int>::max();
+ while (args.count() && (args.count() > (numArgs - useSelf))) {
+ args.removeLast();
+ }
+ signature.append(args.join(QLatin1Char(',')));
+ signature.append(QLatin1Char(')'));
+ }
+ return signature;
+}
+
+bool isQtSignal(const char *signal)
+{
+ return (signal && signal[0] == QT_SIGNAL_SENTINEL);
+}
+
+bool checkQtSignal(const char *signal)
+{
+ if (!isQtSignal(signal)) {
+ PyErr_SetString(PyExc_TypeError, "Use the function PySide6.QtCore.SIGNAL on signals");
+ return false;
+ }
+ return true;
+}
+
+QString codeCallbackName(PyObject *callback, const QString &funcName)
+{
+ if (PyMethod_Check(callback)) {
+ PyObject *self = PyMethod_GET_SELF(callback);
+ PyObject *func = PyMethod_GET_FUNCTION(callback);
+ return funcName + QString::number(quint64(self), 16) + QString::number(quint64(func), 16);
+ }
+ return funcName + QString::number(quint64(callback), 16);
+}
+
+QByteArray voidType()
+{
+ return QByteArrayLiteral("void");
+}
+
+} //namespace Signal
+} //namespace PySide
+
diff --git a/sources/pyside6/libpyside/pysidesignal.h b/sources/pyside6/libpyside/pysidesignal.h
new file mode 100644
index 000000000..973644b0a
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidesignal.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 PYSIDE_SIGNAL_H
+#define PYSIDE_SIGNAL_H
+
+#include <pysidemacros.h>
+
+#include <sbkpython.h>
+#include <basewrapper.h>
+
+#include <QtCore/QList>
+#include <QtCore/QMetaMethod>
+
+QT_BEGIN_NAMESPACE
+struct QMetaObject;
+class QObject;
+QT_END_NAMESPACE
+
+extern "C"
+{
+ extern PYSIDE_API PyTypeObject *PySideSignalTypeF(void);
+ extern PYSIDE_API PyTypeObject *PySideSignalInstanceTypeF(void);
+
+ // Internal object
+ struct PYSIDE_API PySideSignal;
+
+ struct PySideSignalInstancePrivate;
+ struct PYSIDE_API PySideSignalInstance
+ {
+ PyObject_HEAD
+ PySideSignalInstancePrivate *d;
+ };
+}; // extern "C"
+
+namespace PySide {
+namespace Signal {
+
+PYSIDE_API bool checkType(PyObject *type);
+
+/**
+ * Register all C++ signals of a QObject on Python type.
+ */
+PYSIDE_API void registerSignals(SbkObjectType *pyObj, const QMetaObject *metaObject);
+
+/**
+ * This function creates a Signal object which stays attached to QObject class based on a list of QMetaMethods
+ *
+ * @param source of the Signal to be registered on meta object
+ * @param methods a list of QMetaMethod wich contains the supported signature
+ * @return Return a new reference to PyObject* of type PySideSignal
+ **/
+PYSIDE_API PySideSignalInstance *newObjectFromMethod(PyObject *source, const QList<QMetaMethod> &methods);
+
+/**
+ * This function initializes the Signal object by creating a PySideSignalInstance
+ *
+ * @param self a Signal object used as base to PySideSignalInstance
+ * @param name the name to be used on PySideSignalInstance
+ * @param object the PyObject where the signal will be attached
+ * @return Return a new reference to PySideSignalInstance
+ **/
+PYSIDE_API PySideSignalInstance *initialize(PySideSignal *signal, PyObject *name, PyObject *object);
+
+/**
+ * This function is used to retrieve the object in which the signal is attached
+ *
+ * @param self The Signal object
+ * @return Return the internal reference to the parent object of the signal
+ **/
+PYSIDE_API PyObject *getObject(PySideSignalInstance *signal);
+
+/**
+ * This function is used to retrieve the signal signature
+ *
+ * @param self The Signal object
+ * @return Return the signal signature
+ **/
+PYSIDE_API const char *getSignature(PySideSignalInstance *signal);
+
+/**
+ * This function is used to retrieve the signal signature
+ *
+ * @param self The Signal object
+ * @return Return the signal signature
+ **/
+PYSIDE_API void updateSourceObject(PyObject *source);
+
+/**
+ * This function verifies if the signature is a QtSignal base on SIGNAL flag
+ * @param signature The signal signature
+ * @return Return true if this is a Qt Signal, otherwise return false
+ **/
+PYSIDE_API bool isQtSignal(const char *signature);
+
+/**
+ * This function is similar to isQtSignal, however if it fails, it'll raise a Python error instead.
+ *
+ * @param signature The signal signature
+ * @return Return true if this is a Qt Signal, otherwise return false
+ **/
+PYSIDE_API bool checkQtSignal(const char *signature);
+
+/**
+ * This function is used to retrieve the signature base on Signal and receiver callback
+ * @param signature The signal signature
+ * @param receiver The QObject which will receive the signal
+ * @param callback Callback function which will connect to the signal
+ * @param encodeName Used to specify if the returned signature will be encoded with Qt signal/slot style
+ * @return Return the callback signature
+ **/
+PYSIDE_API QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *callback, bool encodeName);
+
+/**
+ * This function parses the signature and then returns a list of argument types.
+ *
+ * @param signature The signal signature
+ * @param isShortCircuit If this is a shortCircuit(python<->python) signal
+ * @return Return true if this is a Qt Signal, otherwise return false
+ * @todo replace return type by QList<QByteArray>
+ **/
+QStringList getArgsFromSignature(const char *signature, bool *isShortCircuit = 0);
+
+} // namespace Signal
+} // namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysidesignal_p.h b/sources/pyside6/libpyside/pysidesignal_p.h
new file mode 100644
index 000000000..337feaa8a
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidesignal_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_QSIGNAL_P_H
+#define PYSIDE_QSIGNAL_P_H
+
+#include <sbkpython.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QVector>
+
+struct PySideSignalData
+{
+ struct Signature
+ {
+ QByteArray signature;
+ int attributes;
+ };
+
+ QByteArray signalName;
+ QVector<Signature> signatures;
+ QByteArrayList *signalArguments;
+};
+
+extern "C"
+{
+ extern PyTypeObject *PySideSignalTypeF(void);
+
+ struct PySideSignal {
+ PyObject_HEAD
+ PySideSignalData *data;
+ PyObject *homonymousMethod;
+ };
+
+ struct PySideSignalInstance;
+}; //extern "C"
+
+struct PySideSignalInstancePrivate
+{
+ QByteArray signalName;
+ QByteArray signature;
+ int attributes = 0;
+ PyObject *source = nullptr;
+ PyObject *homonymousMethod = nullptr;
+ PySideSignalInstance *next = nullptr;
+};
+
+namespace PySide { namespace Signal {
+
+ void init(PyObject *module);
+ bool connect(PyObject *source, const char *signal, PyObject *callback);
+ QByteArray getTypeName(PyObject *);
+ QString codeCallbackName(PyObject *callback, const QString &funcName);
+ QByteArray voidType();
+
+}} //namespace PySide
+
+#endif
diff --git a/sources/pyside6/libpyside/pysideslot.cpp b/sources/pyside6/libpyside/pysideslot.cpp
new file mode 100644
index 000000000..99c3cdf55
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideslot.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "dynamicqmetaobject_p.h"
+#include "pysidesignal_p.h"
+#include "pysideslot_p.h"
+
+#include <shiboken.h>
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QString>
+#include <signature.h>
+
+using namespace Shiboken;
+
+struct SlotData
+{
+ QByteArray name;
+ QByteArray args;
+ QByteArray resultType;
+};
+
+typedef struct
+{
+ PyObject_HEAD
+ SlotData *slotData;
+} PySideSlot;
+
+extern "C"
+{
+
+static int slotTpInit(PyObject *, PyObject *, PyObject *);
+static PyObject *slotCall(PyObject *, PyObject *, PyObject *);
+
+// Class Definition -----------------------------------------------
+static PyType_Slot PySideSlotType_slots[] = {
+ {Py_tp_call, (void *)slotCall},
+ {Py_tp_init, (void *)slotTpInit},
+ {Py_tp_new, (void *)PyType_GenericNew},
+ {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {0, 0}
+};
+static PyType_Spec PySideSlotType_spec = {
+ "2:PySide6.QtCore.Slot",
+ sizeof(PySideSlot),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideSlotType_slots,
+};
+
+
+static PyTypeObject *PySideSlotTypeF(void)
+{
+ static PyTypeObject *type = reinterpret_cast<PyTypeObject *>(
+ SbkType_FromSpec(&PySideSlotType_spec));
+ return type;
+}
+
+int slotTpInit(PyObject *self, PyObject *args, PyObject *kw)
+{
+ static PyObject *emptyTuple = nullptr;
+ static const char *kwlist[] = {"name", "result", nullptr};
+ char *argName = nullptr;
+ PyObject *argResult = nullptr;
+
+ if (emptyTuple == 0)
+ emptyTuple = PyTuple_New(0);
+
+ if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore.Slot",
+ const_cast<char **>(kwlist), &argName, &argResult)) {
+ return -1;
+ }
+
+ PySideSlot *data = reinterpret_cast<PySideSlot *>(self);
+ if (!data->slotData)
+ data->slotData = new SlotData;
+ for(Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) {
+ PyObject *argType = PyTuple_GET_ITEM(args, i);
+ const auto typeName = PySide::Signal::getTypeName(argType);
+ if (typeName.isEmpty()) {
+ PyErr_Format(PyExc_TypeError, "Unknown signal argument type: %s", Py_TYPE(argType)->tp_name);
+ return -1;
+ }
+ if (!data->slotData->args.isEmpty())
+ data->slotData->args += ',';
+ data->slotData->args += typeName;
+ }
+
+ if (argName)
+ data->slotData->name = argName;
+
+ data->slotData->resultType = argResult
+ ? PySide::Signal::getTypeName(argResult) : PySide::Signal::voidType();
+
+ return 0;
+}
+
+PyObject *slotCall(PyObject *self, PyObject *args, PyObject * /* kw */)
+{
+ static PyObject *pySlotName = nullptr;
+ PyObject *callback;
+ callback = PyTuple_GetItem(args, 0);
+ Py_INCREF(callback);
+
+ if (Py_TYPE(callback)->tp_call != nullptr) {
+ PySideSlot *data = reinterpret_cast<PySideSlot *>(self);
+
+ if (!data->slotData)
+ data->slotData = new SlotData;
+
+ if (data->slotData->name.isEmpty()) {
+ // PYSIDE-198: Use PyObject_GetAttr instead of PepFunction_GetName to support Nuitka.
+ AutoDecRef funcName(PyObject_GetAttr(callback, PyMagicName::name()));
+ data->slotData->name = String::toCString(funcName);
+ }
+ const QByteArray returnType = QMetaObject::normalizedType(data->slotData->resultType);
+ const QByteArray signature =
+ returnType + ' ' + data->slotData->name + '(' + data->slotData->args + ')';
+
+ if (!pySlotName)
+ pySlotName = String::fromCString(PYSIDE_SLOT_LIST_ATTR);
+
+ PyObject *pySignature = String::fromCString(signature);
+ PyObject *signatureList = 0;
+ if (PyObject_HasAttr(callback, pySlotName)) {
+ signatureList = PyObject_GetAttr(callback, pySlotName);
+ } else {
+ signatureList = PyList_New(0);
+ PyObject_SetAttr(callback, pySlotName, signatureList);
+ Py_DECREF(signatureList);
+ }
+
+ PyList_Append(signatureList, pySignature);
+ Py_DECREF(pySignature);
+
+ //clear data
+ delete data->slotData;
+ data->slotData = nullptr;
+ return callback;
+ }
+ return callback;
+}
+
+} // extern "C"
+
+namespace PySide {
+namespace Slot {
+
+static const char *Slot_SignatureStrings[] = {
+ "PySide6.QtCore.Slot(*types:type,name:str=nullptr,result:str=nullptr)->typing.Callable[...,typing.Optional[str]]",
+ nullptr}; // Sentinel
+
+void init(PyObject *module)
+{
+ if (InitSignatureStrings(PySideSlotTypeF(), Slot_SignatureStrings) < 0)
+ return;
+
+ Py_INCREF(PySideSlotTypeF());
+ PyModule_AddObject(module, "Slot", reinterpret_cast<PyObject *>(PySideSlotTypeF()));
+}
+
+} // namespace Slot
+} // namespace PySide
diff --git a/sources/pyside6/libpyside/pysideslot_p.h b/sources/pyside6/libpyside/pysideslot_p.h
new file mode 100644
index 000000000..3d98e15c4
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideslot_p.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PYSIDE_SLOT_P_H
+#define PYSIDE_SLOT_P_H
+
+#include <sbkpython.h>
+#define PYSIDE_SLOT_LIST_ATTR "_slots"
+
+namespace PySide { namespace Slot {
+ void init(PyObject* module);
+}}
+
+#endif
diff --git a/sources/pyside6/libpyside/pysidestaticstrings.cpp b/sources/pyside6/libpyside/pysidestaticstrings.cpp
new file mode 100644
index 000000000..760d77632
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidestaticstrings.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "pysidestaticstrings.h"
+#include <sbkstring.h>
+
+#define STATIC_STRING_IMPL(funcName, value) \
+PyObject *funcName() \
+{ \
+ static PyObject *const s = Shiboken::String::createStaticString(value); \
+ return s; \
+}
+
+namespace PySide
+{
+namespace PyName
+{
+STATIC_STRING_IMPL(qtStaticMetaObject, "staticMetaObject")
+STATIC_STRING_IMPL(qtConnect, "connect")
+STATIC_STRING_IMPL(qtDisconnect, "disconnect")
+STATIC_STRING_IMPL(qtEmit, "emit")
+STATIC_STRING_IMPL(dict_ring, "dict_ring")
+STATIC_STRING_IMPL(name, "name")
+STATIC_STRING_IMPL(property, "property")
+STATIC_STRING_IMPL(select_id, "select_id")
+} // namespace PyName
+} // namespace PySide
diff --git a/sources/pyside6/libpyside/pysidestaticstrings.h b/sources/pyside6/libpyside/pysidestaticstrings.h
new file mode 100644
index 000000000..1222d8f47
--- /dev/null
+++ b/sources/pyside6/libpyside/pysidestaticstrings.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 PYSIDESTRINGS_H
+#define PYSIDESTRINGS_H
+
+#include <sbkpython.h>
+
+namespace PySide
+{
+namespace PyName
+{
+PyObject *qtStaticMetaObject();
+PyObject *qtConnect();
+PyObject *qtDisconnect();
+PyObject *qtEmit();
+PyObject *dict_ring();
+PyObject *name();
+PyObject *property();
+PyObject *select_id();
+} // namespace PyName
+} // namespace PySide
+
+#endif // PYSIDESTRINGS_H
diff --git a/sources/pyside6/libpyside/pysideweakref.cpp b/sources/pyside6/libpyside/pysideweakref.cpp
new file mode 100644
index 000000000..cd90634bd
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideweakref.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "pysideweakref.h"
+
+#include <sbkpython.h>
+#include <shiboken.h>
+
+typedef struct {
+ PyObject_HEAD
+ /* Type-specific fields go here. */
+ PySideWeakRefFunction weakref_func;
+ void *user_data;
+} PySideCallableObject;
+
+static PyObject *CallableObject_call(PyObject *callable_object, PyObject *args, PyObject *kw);
+
+static PyType_Slot PySideCallableObjectType_slots[] = {
+ {Py_tp_call, (void *)CallableObject_call},
+ {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {0, 0}
+};
+static PyType_Spec PySideCallableObjectType_spec = {
+ "1:PySide.Callable",
+ sizeof(PySideCallableObject),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PySideCallableObjectType_slots,
+};
+
+
+static PyTypeObject *PySideCallableObjectTypeF()
+{
+ static PyTypeObject *type =
+ reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideCallableObjectType_spec));
+ return type;
+}
+
+static PyObject *CallableObject_call(PyObject *callable_object, PyObject *args, PyObject * /* kw */)
+{
+ PySideCallableObject *obj = reinterpret_cast<PySideCallableObject *>(callable_object);
+ obj->weakref_func(obj->user_data);
+
+ Py_XDECREF(PyTuple_GET_ITEM(args, 0)); //kill weak ref object
+ Py_RETURN_NONE;
+}
+
+namespace PySide { namespace WeakRef {
+
+PyObject *create(PyObject *obj, PySideWeakRefFunction func, void *userData)
+{
+ if (obj == Py_None)
+ return 0;
+
+ if (Py_TYPE(PySideCallableObjectTypeF()) == 0)
+ {
+ Py_TYPE(PySideCallableObjectTypeF()) = &PyType_Type;
+ PyType_Ready(PySideCallableObjectTypeF());
+ }
+
+ PyTypeObject *type = PySideCallableObjectTypeF();
+ PySideCallableObject *callable = PyObject_New(PySideCallableObject, type);
+ if (!callable || PyErr_Occurred())
+ return 0;
+
+ PyObject *weak = PyWeakref_NewRef(obj, reinterpret_cast<PyObject *>(callable));
+ if (!weak || PyErr_Occurred())
+ return 0;
+
+ callable->weakref_func = func;
+ callable->user_data = userData;
+ Py_DECREF(callable); // PYSIDE-79: after decref the callable is undefined (theoretically)
+
+ return reinterpret_cast<PyObject *>(weak);
+}
+
+} } //namespace
+
diff --git a/sources/pyside6/libpyside/pysideweakref.h b/sources/pyside6/libpyside/pysideweakref.h
new file mode 100644
index 000000000..628c1eda4
--- /dev/null
+++ b/sources/pyside6/libpyside/pysideweakref.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 __PYSIDEWEAKREF__
+#define __PYSIDEWEAKREF__
+
+#include <pysidemacros.h>
+#include <sbkpython.h>
+
+typedef void (*PySideWeakRefFunction)(void* userData);
+
+namespace PySide { namespace WeakRef {
+
+PYSIDE_API PyObject* create(PyObject* ob, PySideWeakRefFunction func, void* userData);
+
+} //PySide
+} //WeakRef
+
+
+#endif
diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp
new file mode 100644
index 000000000..0992cfcfd
--- /dev/null
+++ b/sources/pyside6/libpyside/signalmanager.cpp
@@ -0,0 +1,640 @@
+// -*- mode: cpp;-*-
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "signalmanager.h"
+#include "pysidesignal.h"
+#include "pysideproperty.h"
+#include "pysideproperty_p.h"
+#include "pyside.h"
+#include "pyside_p.h"
+#include "dynamicqmetaobject.h"
+#include "pysidemetafunction_p.h"
+
+#include <autodecref.h>
+#include <basewrapper.h>
+#include <bindingmanager.h>
+#include <gilstate.h>
+#include <sbkconverter.h>
+#include <sbkstring.h>
+#include <sbkstaticstrings.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+
+#include <algorithm>
+#include <limits>
+
+// These private headers are needed to throw JavaScript exceptions
+#if PYSIDE_QML_PRIVATE_API_SUPPORT
+ #include <private/qv4engine_p.h>
+ #include <private/qv4context_p.h>
+ #include <private/qqmldata_p.h>
+#endif
+
+#if QSLOT_CODE != 1 || QSIGNAL_CODE != 2
+#error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value!
+#endif
+#define PYSIDE_SLOT '1'
+#define PYSIDE_SIGNAL '2'
+#include "globalreceiverv2.h"
+
+namespace {
+ static PyObject *metaObjectAttr = 0;
+
+ static int callMethod(QObject *object, int id, void **args);
+ static PyObject *parseArguments(const QList< QByteArray >& paramTypes, void **args);
+ static bool emitShortCircuitSignal(QObject *source, int signalIndex, PyObject *args);
+
+ static void destroyMetaObject(PyObject *obj)
+ {
+ void *ptr = PyCapsule_GetPointer(obj, 0);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder *>(ptr);
+ SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
+ if (wrapper)
+ Shiboken::BindingManager::instance().releaseWrapper(wrapper);
+ delete meta;
+ }
+}
+
+namespace PySide {
+
+
+PyObjectWrapper::PyObjectWrapper()
+ :m_me(Py_None)
+{
+ // PYSIDE-813: When PYSIDE-164 was solved by adding some thread allowance,
+ // this code was no longer protected. It was hard to find this connection.
+ // See the website https://bugreports.qt.io/browse/PYSIDE-813 for details.
+ Shiboken::GilState gil;
+ Py_XINCREF(m_me);
+}
+
+PyObjectWrapper::PyObjectWrapper(PyObject *me)
+ : m_me(me)
+{
+ Shiboken::GilState gil;
+ Py_XINCREF(m_me);
+}
+
+PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other)
+ : m_me(other.m_me)
+{
+ Shiboken::GilState gil;
+ Py_XINCREF(m_me);
+}
+
+PyObjectWrapper::~PyObjectWrapper()
+{
+ // Check that Python is still initialized as sometimes this is called by a static destructor
+ // after Python interpeter is shutdown.
+ if (!Py_IsInitialized())
+ return;
+
+ Shiboken::GilState gil;
+ Py_XDECREF(m_me);
+}
+
+void PyObjectWrapper::reset(PyObject *o)
+{
+ Shiboken::GilState gil;
+ Py_XINCREF(o);
+ Py_XDECREF(m_me);
+ m_me = o;
+}
+
+PyObjectWrapper &PyObjectWrapper::operator=(const PySide::PyObjectWrapper &other)
+{
+ reset(other.m_me);
+ return *this;
+}
+
+PyObjectWrapper::operator PyObject *() const
+{
+ return m_me;
+}
+
+QDataStream &operator<<(QDataStream &out, const PyObjectWrapper &myObj)
+{
+ if (Py_IsInitialized() == 0) {
+ qWarning() << "Stream operator for PyObject called without python interpreter.";
+ return out;
+ }
+
+ static PyObject *reduce_func = 0;
+
+ Shiboken::GilState gil;
+ if (!reduce_func) {
+ Shiboken::AutoDecRef pickleModule(PyImport_ImportModule("pickle"));
+ reduce_func = PyObject_GetAttr(pickleModule, Shiboken::PyName::dumps());
+ }
+ Shiboken::AutoDecRef repr(PyObject_CallFunctionObjArgs(reduce_func, (PyObject *)myObj, NULL));
+ if (repr.object()) {
+ const char *buff = nullptr;
+ Py_ssize_t size = 0;
+ if (PyBytes_Check(repr.object())) {
+ buff = PyBytes_AS_STRING(repr.object());
+ size = PyBytes_GET_SIZE(repr.object());
+ } else if (Shiboken::String::check(repr.object())) {
+ buff = Shiboken::String::toCString(repr.object());
+ size = Shiboken::String::len(repr.object());
+ }
+ QByteArray data(buff, size);
+ out << data;
+ }
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, PyObjectWrapper &myObj)
+{
+ if (Py_IsInitialized() == 0) {
+ qWarning() << "Stream operator for PyObject called without python interpreter.";
+ return in;
+ }
+
+ static PyObject *eval_func = 0;
+
+ Shiboken::GilState gil;
+ if (!eval_func) {
+ Shiboken::AutoDecRef pickleModule(PyImport_ImportModule("pickle"));
+ eval_func = PyObject_GetAttr(pickleModule, Shiboken::PyName::loads());
+ }
+
+ QByteArray repr;
+ in >> repr;
+ Shiboken::AutoDecRef pyCode(PyBytes_FromStringAndSize(repr.data(), repr.size()));
+ Shiboken::AutoDecRef value(PyObject_CallFunctionObjArgs(eval_func, pyCode.object(), 0));
+ if (!value.object())
+ value.reset(Py_None);
+ myObj.reset(value);
+ return in;
+}
+
+};
+
+using namespace PySide;
+
+struct SignalManager::SignalManagerPrivate
+{
+ SharedMap m_globalReceivers;
+
+ SignalManagerPrivate()
+ {
+ m_globalReceivers = SharedMap( new QMap<QByteArray, GlobalReceiverV2 *>() );
+ }
+
+ ~SignalManagerPrivate()
+ {
+ if (!m_globalReceivers.isNull()) {
+ // Delete receivers by always retrieving the current first element, because deleting a
+ // receiver can indirectly delete another one, and if we use qDeleteAll, that could
+ // cause either a double delete, or iterator invalidation, and thus undefined behavior.
+ while (!m_globalReceivers->isEmpty())
+ delete *m_globalReceivers->cbegin();
+ Q_ASSERT(m_globalReceivers->isEmpty());
+ }
+ }
+};
+
+static void clearSignalManager()
+{
+ PySide::SignalManager::instance().clear();
+}
+
+static void PyObject_PythonToCpp_PyObject_PTR(PyObject *pyIn, void *cppOut)
+{
+ *reinterpret_cast<PyObject **>(cppOut) = pyIn;
+}
+static PythonToCppFunc is_PyObject_PythonToCpp_PyObject_PTR_Convertible(PyObject *pyIn)
+{
+ return PyObject_PythonToCpp_PyObject_PTR;
+}
+static PyObject *PyObject_PTR_CppToPython_PyObject(const void *cppIn)
+{
+ auto pyOut = reinterpret_cast<PyObject *>(const_cast<void *>(cppIn));
+ if (pyOut)
+ Py_INCREF(pyOut);
+ return pyOut;
+}
+
+SignalManager::SignalManager() : m_d(new SignalManagerPrivate)
+{
+ // Register Qt primitive typedefs used on signals.
+ using namespace Shiboken;
+
+ // Register PyObject type to use in queued signal and slot connections
+ qRegisterMetaType<PyObjectWrapper>("PyObject");
+
+ SbkConverter *converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type, nullptr);
+ Shiboken::Conversions::setCppPointerToPythonFunction(converter, PyObject_PTR_CppToPython_PyObject);
+ Shiboken::Conversions::setPythonToCppPointerFunctions(converter, PyObject_PythonToCpp_PyObject_PTR, is_PyObject_PythonToCpp_PyObject_PTR_Convertible);
+ Shiboken::Conversions::registerConverterName(converter, "PyObject");
+ Shiboken::Conversions::registerConverterName(converter, "object");
+ Shiboken::Conversions::registerConverterName(converter, "PyObjectWrapper");
+ Shiboken::Conversions::registerConverterName(converter, "PySide::PyObjectWrapper");
+
+ PySide::registerCleanupFunction(clearSignalManager);
+
+ if (!metaObjectAttr)
+ metaObjectAttr = Shiboken::String::fromCString("__METAOBJECT__");
+}
+
+void SignalManager::clear()
+{
+ delete m_d;
+ m_d = new SignalManagerPrivate();
+}
+
+SignalManager::~SignalManager()
+{
+ delete m_d;
+}
+
+SignalManager &SignalManager::instance()
+{
+ static SignalManager me;
+ return me;
+}
+
+QObject *SignalManager::globalReceiver(QObject *sender, PyObject *callback)
+{
+ SharedMap globalReceivers = m_d->m_globalReceivers;
+ QByteArray hash = GlobalReceiverV2::hash(callback);
+ GlobalReceiverV2 *gr = nullptr;
+ auto it = globalReceivers->find(hash);
+ if (it == globalReceivers->end()) {
+ gr = new GlobalReceiverV2(callback, globalReceivers);
+ globalReceivers->insert(hash, gr);
+ if (sender) {
+ gr->incRef(sender); // create a link reference
+ gr->decRef(); // remove extra reference
+ }
+ } else {
+ gr = it.value();
+ if (sender)
+ gr->incRef(sender);
+ }
+
+ return reinterpret_cast<QObject *>(gr);
+}
+
+int SignalManager::countConnectionsWith(const QObject *object)
+{
+ int count = 0;
+ for (GlobalReceiverV2Map::const_iterator it = m_d->m_globalReceivers->cbegin(), end = m_d->m_globalReceivers->cend(); it != end; ++it) {
+ if (it.value()->refCount(object))
+ count++;
+ }
+ return count;
+}
+
+void SignalManager::notifyGlobalReceiver(QObject *receiver)
+{
+ reinterpret_cast<GlobalReceiverV2 *>(receiver)->notify();
+}
+
+void SignalManager::releaseGlobalReceiver(const QObject *source, QObject *receiver)
+{
+ auto gr = reinterpret_cast<GlobalReceiverV2 *>(receiver);
+ gr->decRef(source);
+}
+
+int SignalManager::globalReceiverSlotIndex(QObject *receiver, const char *signature) const
+{
+ return reinterpret_cast<GlobalReceiverV2 *>(receiver)->addSlot(signature);
+}
+
+bool SignalManager::emitSignal(QObject *source, const char *signal, PyObject *args)
+{
+ if (!Signal::checkQtSignal(signal))
+ return false;
+ signal++;
+
+ int signalIndex = source->metaObject()->indexOfSignal(signal);
+ if (signalIndex != -1) {
+ // cryptic but works!
+ // if the signature doesn't have a '(' it's a shor circuited signal, i.e. std::find
+ // returned the string null terminator.
+ bool isShortCircuit = !*std::find(signal, signal + std::strlen(signal), '(');
+ if (isShortCircuit)
+ return emitShortCircuitSignal(source, signalIndex, args);
+ else
+ return MetaFunction::call(source, signalIndex, args);
+ }
+ return false;
+}
+
+int SignalManager::qt_metacall(QObject *object, QMetaObject::Call call, int id, void **args)
+{
+ const QMetaObject *metaObject = object->metaObject();
+ PySideProperty *pp = nullptr;
+ PyObject *pp_name = nullptr;
+ QMetaProperty mp;
+ PyObject *pySelf = nullptr;
+ int methodCount = metaObject->methodCount();
+ int propertyCount = metaObject->propertyCount();
+
+ if (call != QMetaObject::InvokeMetaMethod) {
+ mp = metaObject->property(id);
+ if (!mp.isValid()) {
+ return id - methodCount;
+ }
+
+ Shiboken::GilState gil;
+ pySelf = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(object));
+ Q_ASSERT(pySelf);
+ pp_name = Shiboken::String::fromCString(mp.name());
+ pp = Property::getObject(pySelf, pp_name);
+ if (!pp) {
+ qWarning("Invalid property: %s.", mp.name());
+ Py_XDECREF(pp_name);
+ return id - methodCount;
+ }
+ }
+
+ switch(call) {
+#ifndef QT_NO_PROPERTIES
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ pp->d->metaCallHandler(pp, pySelf, call, args);
+ break;
+#endif
+ case QMetaObject::InvokeMetaMethod:
+ id = callMethod(object, id, args);
+ break;
+
+ default:
+ qWarning("Unsupported meta invocation type.");
+ }
+
+ // WARNING Isn't safe to call any metaObject and/or object methods beyond this point
+ // because the object can be deleted inside the called slot.
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ id = id - methodCount;
+ } else {
+ id = id - propertyCount;
+ }
+
+ if (pp || pp_name) {
+ Shiboken::GilState gil;
+ Py_XDECREF(pp);
+ Py_XDECREF(pp_name);
+ }
+
+ // Bubbles Python exceptions up to the Javascript engine, if called from one
+ {
+ Shiboken::GilState gil;
+
+ if (PyErr_Occurred()) {
+
+#if PYSIDE_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()) {
+ QV4::ExecutionEngine *engine = data->jsWrapper.engine();
+ if (engine->currentStackFrame != nullptr) {
+ 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 = QLatin1String(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);
+ } else if (isTypeError) {
+ return engine->throwTypeError(errString);
+ } else {
+ return engine->throwError(errString);
+ }
+ }
+ }
+#endif // PYSIDE_QML_PRIVATE_API_SUPPORT
+
+ int reclimit = Py_GetRecursionLimit();
+ // Inspired by Python's errors.c: PyErr_GivenExceptionMatches() function.
+ // Temporarily bump the recursion limit, so that PyErr_Print will not raise a recursion
+ // error again. Don't do it when the limit is already insanely high, to avoid overflow.
+ if (reclimit < (1 << 30))
+ Py_SetRecursionLimit(reclimit + 5);
+ PyErr_Print();
+ Py_SetRecursionLimit(reclimit);
+ }
+ }
+
+ return id;
+}
+
+int SignalManager::callPythonMetaMethod(const QMetaMethod &method, void **args, PyObject *pyMethod, bool isShortCuit)
+{
+ Q_ASSERT(pyMethod);
+
+ Shiboken::GilState gil;
+ PyObject *pyArguments = nullptr;
+
+ if (isShortCuit){
+ pyArguments = reinterpret_cast<PyObject *>(args[1]);
+ } else {
+ pyArguments = parseArguments(method.parameterTypes(), args);
+ }
+
+ if (pyArguments) {
+ Shiboken::Conversions::SpecificConverter *retConverter = nullptr;
+ const char *returnType = method.typeName();
+ if (returnType && std::strcmp("", returnType) && std::strcmp("void", returnType)) {
+ retConverter = new Shiboken::Conversions::SpecificConverter(returnType);
+ if (!retConverter || !*retConverter) {
+ PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s' to call Python meta method.", returnType);
+ return -1;
+ }
+ }
+
+ Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, pyArguments));
+
+ if (!isShortCuit && pyArguments){
+ Py_DECREF(pyArguments);
+ }
+
+ if (!retval.isNull() && retval != Py_None && !PyErr_Occurred() && retConverter) {
+ retConverter->toCpp(retval, args[0]);
+ }
+ delete retConverter;
+ }
+
+ return -1;
+}
+
+bool SignalManager::registerMetaMethod(QObject *source, const char *signature, QMetaMethod::MethodType type)
+{
+ int ret = registerMetaMethodGetIndex(source, signature, type);
+ return (ret != -1);
+}
+
+static MetaObjectBuilder *metaBuilderFromDict(PyObject *dict)
+{
+ // PYSIDE-803: The dict in this function is the ob_dict of an SbkObject.
+ // The "metaObjectAttr" entry is only handled in this file. There is no
+ // way in this function to involve the interpreter. Therefore, we need
+ // no GIL.
+ // Note that "SignalManager::registerMetaMethodGetIndex" has write actions
+ // that might involve the interpreter, but in that context the GIL is held.
+ if (!dict || !PyDict_Contains(dict, metaObjectAttr))
+ return nullptr;
+
+ // PYSIDE-813: The above assumption is not true in debug mode:
+ // PyDict_GetItem would touch PyThreadState_GET and the global error state.
+ // PyDict_GetItemWithError instead can work without GIL.
+ PyObject *pyBuilder = PyDict_GetItemWithError(dict, metaObjectAttr);
+ return reinterpret_cast<MetaObjectBuilder *>(PyCapsule_GetPointer(pyBuilder, nullptr));
+}
+
+int SignalManager::registerMetaMethodGetIndex(QObject *source, const char *signature, QMetaMethod::MethodType type)
+{
+ if (!source) {
+ qWarning("SignalManager::registerMetaMethodGetIndex(\"%s\") called with source=nullptr.",
+ signature);
+ return -1;
+ }
+ const QMetaObject *metaObject = source->metaObject();
+ int methodIndex = metaObject->indexOfMethod(signature);
+ // Create the dynamic signal is needed
+ if (methodIndex == -1) {
+ SbkObject *self = Shiboken::BindingManager::instance().retrieveWrapper(source);
+ if (!Shiboken::Object::hasCppWrapper(self)) {
+ qWarning() << "Invalid Signal signature:" << signature;
+ return -1;
+ } else {
+ auto pySelf = reinterpret_cast<PyObject *>(self);
+ PyObject *dict = self->ob_dict;
+ MetaObjectBuilder *dmo = metaBuilderFromDict(dict);
+
+ // Create a instance meta object
+ if (!dmo) {
+ dmo = new MetaObjectBuilder(Py_TYPE(pySelf), metaObject);
+ PyObject *pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject);
+ PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo);
+ Py_DECREF(pyDmo);
+ }
+
+ if (type == QMetaMethod::Signal)
+ return dmo->addSignal(signature);
+ else
+ return dmo->addSlot(signature);
+ }
+ }
+ return methodIndex;
+}
+
+const QMetaObject *SignalManager::retrieveMetaObject(PyObject *self)
+{
+ // PYSIDE-803: Avoid the GIL in SignalManager::retrieveMetaObject
+ // This function had the GIL. We do not use the GIL unless we have to.
+ // metaBuilderFromDict accesses a Python dict, but in that context there
+ // is no way to reach the interpreter, see "metaBuilderFromDict".
+ //
+ // The update function is MetaObjectBuilderPrivate::update in
+ // dynamicmetaobject.c . That function now uses the GIL when the
+ // m_dirty flag is set.
+ Q_ASSERT(self);
+
+ MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject *>(self)->ob_dict);
+ if (!builder)
+ builder = &(retrieveTypeUserData(self)->mo);
+
+ return builder->update();
+}
+
+namespace {
+
+static int callMethod(QObject *object, int id, void **args)
+{
+ const QMetaObject *metaObject = object->metaObject();
+ QMetaMethod method = metaObject->method(id);
+
+ if (method.methodType() == QMetaMethod::Signal) {
+ // emit python signal
+ QMetaObject::activate(object, id, args);
+ } else {
+ Shiboken::GilState gil;
+ auto self = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(object));
+ QByteArray methodName = method.methodSignature();
+ methodName.truncate(methodName.indexOf('('));
+ Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(self, methodName));
+ return SignalManager::callPythonMetaMethod(method, args, pyMethod, false);
+ }
+ return -1;
+}
+
+
+static PyObject *parseArguments(const QList<QByteArray>& paramTypes, void **args)
+{
+ int argsSize = paramTypes.count();
+ PyObject *preparedArgs = PyTuple_New(argsSize);
+
+ for (int i = 0, max = argsSize; i < max; ++i) {
+ void *data = args[i+1];
+ const char *dataType = paramTypes[i].constData();
+ Shiboken::Conversions::SpecificConverter converter(dataType);
+ if (converter) {
+ PyTuple_SET_ITEM(preparedArgs, i, converter.toPython(data));
+ } else {
+ PyErr_Format(PyExc_TypeError, "Can't call meta function because I have no idea how to handle %s", dataType);
+ Py_DECREF(preparedArgs);
+ return 0;
+ }
+ }
+ return preparedArgs;
+}
+
+static bool emitShortCircuitSignal(QObject *source, int signalIndex, PyObject *args)
+{
+ void *signalArgs[2] = {nullptr, args};
+ source->qt_metacall(QMetaObject::InvokeMetaMethod, signalIndex, signalArgs);
+ return true;
+}
+
+} //namespace
diff --git a/sources/pyside6/libpyside/signalmanager.h b/sources/pyside6/libpyside/signalmanager.h
new file mode 100644
index 000000000..fe077bd1a
--- /dev/null
+++ b/sources/pyside6/libpyside/signalmanager.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 SIGNALMANAGER_H
+#define SIGNALMANAGER_H
+
+#include "pysidemacros.h"
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+#include <QtCore/QMetaMethod>
+
+QT_FORWARD_DECLARE_CLASS(QDataStream)
+
+namespace PySide
+{
+
+/// Thin wrapper for PyObject which increases the reference count at the constructor but *NOT* at destructor.
+class PYSIDE_API PyObjectWrapper
+{
+public:
+ PyObjectWrapper(PyObjectWrapper&&) = delete;
+ PyObjectWrapper& operator=(PyObjectWrapper &&) = delete;
+
+ PyObjectWrapper();
+ explicit PyObjectWrapper(PyObject* me);
+ PyObjectWrapper(const PyObjectWrapper &other);
+ PyObjectWrapper& operator=(const PyObjectWrapper &other);
+
+ void reset(PyObject *o);
+
+ ~PyObjectWrapper();
+ operator PyObject*() const;
+
+private:
+ PyObject* m_me;
+};
+
+PYSIDE_API QDataStream &operator<<(QDataStream& out, const PyObjectWrapper& myObj);
+PYSIDE_API QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj);
+
+class PYSIDE_API SignalManager
+{
+ Q_DISABLE_COPY(SignalManager)
+public:
+ static SignalManager& instance();
+
+ QObject* globalReceiver(QObject* sender, PyObject* callback);
+ void releaseGlobalReceiver(const QObject* sender, QObject* receiver);
+ int globalReceiverSlotIndex(QObject* sender, const char* slotSignature) const;
+ void notifyGlobalReceiver(QObject* receiver);
+
+ bool emitSignal(QObject* source, const char* signal, PyObject* args);
+ static int qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args);
+
+ // Used to register a new signal/slot on QMetaobject of source.
+ static bool registerMetaMethod(QObject* source, const char* signature, QMetaMethod::MethodType type);
+ static int registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type);
+
+ // used to discovery metaobject
+ static const QMetaObject* retrieveMetaObject(PyObject* self);
+
+ // Used to discovery if SignalManager was connected with object "destroyed()" signal.
+ int countConnectionsWith(const QObject *object);
+
+ // Disconnect all signals managed by Globalreceiver
+ void clear();
+
+ // Utility function to call a python method usign args received in qt_metacall
+ static int callPythonMetaMethod(const QMetaMethod& method, void** args, PyObject* obj, bool isShortCuit);
+
+private:
+ struct SignalManagerPrivate;
+ SignalManagerPrivate* m_d;
+
+ SignalManager();
+ ~SignalManager();
+};
+
+}
+
+Q_DECLARE_METATYPE(PySide::PyObjectWrapper)
+
+#endif