aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/PySide6/glue/qtcore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/PySide6/glue/qtcore.cpp')
-rw-r--r--sources/pyside6/PySide6/glue/qtcore.cpp1750
1 files changed, 968 insertions, 782 deletions
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
index 66fd3b004..bc51d26d7 100644
--- a/sources/pyside6/PySide6/glue/qtcore.cpp
+++ b/sources/pyside6/PySide6/glue/qtcore.cpp
@@ -1,59 +1,185 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*********************************************************************
* INJECT CODE
********************************************************************/
// @snippet include-pyside
-#include <pyside.h>
+#include <pysideinit.h>
#include <limits>
+#include "glue/core_snippets_p.h"
// @snippet include-pyside
+// @snippet core-snippets-p-h
+#include "glue/core_snippets_p.h"
+// @snippet core-snippets-p-h
+
+// @snippet qarg_helper
+
+// Helper for the Q_ARG/Q_RETURN_ARG functions, creating a meta type
+// and instance.
+struct QArgData
+{
+ operator bool() const { return metaType.isValid() && data != nullptr; }
+
+ QMetaType metaType;
+ void *data = nullptr;
+};
+
+QArgData qArgDataFromPyType(PyObject *t)
+{
+ QArgData result;
+ const char *typeName{};
+ if (PyType_Check(t)) {
+ auto *pyType = reinterpret_cast<PyTypeObject *>(t);
+ typeName = pyType->tp_name;
+ result.metaType = PySide::qMetaTypeFromPyType(pyType);
+ } else if (PyUnicode_Check(t)) {
+ typeName = Shiboken::String::toCString(t);
+ result.metaType = QMetaType::fromName(typeName);
+ } else {
+ PyErr_Format(PyExc_RuntimeError, "%s: Parameter should be a type or type string.",
+ __FUNCTION__);
+ return result;
+ }
+
+ if (!result.metaType.isValid()) {
+ PyErr_Format(PyExc_RuntimeError, "%s: Unable to find a QMetaType for \"%s\".",
+ __FUNCTION__, typeName);
+ return result;
+ }
+
+ result.data = result.metaType.create();
+ if (result.data == nullptr) {
+ PyErr_Format(PyExc_RuntimeError, "%s: Unable to create an instance of \"%s\" (%s).",
+ __FUNCTION__, typeName, result.metaType.name());
+ return result;
+ }
+ return result;
+}
+// @snippet qarg_helper
+
+// @snippet settings-value-helpers
+// Convert a QVariant to a desired primitive type
+static PyObject *convertToPrimitiveType(const QVariant &out, int metaTypeId)
+{
+ switch (metaTypeId) {
+ case QMetaType::QByteArray:
+ return PyBytes_FromString(out.toByteArray().constData());
+ case QMetaType::QString:
+ return PyUnicode_FromString(out.toByteArray().constData());
+ case QMetaType::Short:
+ case QMetaType::Long:
+ case QMetaType::LongLong:
+ case QMetaType::UShort:
+ case QMetaType::ULong:
+ case QMetaType::ULongLong:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return PyLong_FromDouble(out.toFloat());
+ case QMetaType::Double:
+ case QMetaType::Float:
+ case QMetaType::Float16:
+ return PyFloat_FromDouble(out.toFloat());
+ case QMetaType::Bool:
+ if (out.toBool()) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ Py_INCREF(Py_False);
+ return Py_False;
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+// Helper for QSettings::value() to convert a value to the desired type
+static PyObject *settingsTypeCoercion(const QVariant &out, PyTypeObject *typeObj)
+{
+ if (typeObj == &PyList_Type) {
+ // Convert any string, etc, to a list of 1 element
+ if (auto *primitiveValue = convertToPrimitiveType(out, out.typeId())) {
+ PyObject *list = PyList_New(1);
+ PyList_SET_ITEM(list, 0, primitiveValue);
+ return list;
+ }
+
+ const QByteArray out_ba = out.toByteArray();
+ if (out_ba.isEmpty())
+ return PyList_New(0);
+
+ const QByteArrayList valuesList = out_ba.split(',');
+ const Py_ssize_t valuesSize = valuesList.size();
+ PyObject *list = PyList_New(valuesSize);
+ for (Py_ssize_t i = 0; i < valuesSize; ++i) {
+ PyObject *item = PyUnicode_FromString(valuesList.at(i).constData());
+ PyList_SET_ITEM(list, i, item);
+ }
+ return list;
+ }
+
+ if (typeObj == &PyBytes_Type)
+ return convertToPrimitiveType(out, QMetaType::QByteArray);
+ if (typeObj == &PyUnicode_Type)
+ return convertToPrimitiveType(out, QMetaType::QString);
+ if (typeObj == &PyLong_Type)
+ return convertToPrimitiveType(out, QMetaType::Int);
+ if (typeObj == &PyFloat_Type)
+ return convertToPrimitiveType(out, QMetaType::Double);
+ if (typeObj == &PyBool_Type)
+ return convertToPrimitiveType(out, QMetaType::Bool);
+
+ // TODO: PyDict_Type and PyTuple_Type
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid type parameter.\n"
+ "\tUse 'list', 'bytes', 'str', 'int', 'float', 'bool', "
+ "or a Qt-derived type");
+ return nullptr;
+}
+
+static bool isEquivalentSettingsType(PyTypeObject *typeObj, int metaTypeId)
+{
+ switch (metaTypeId) {
+ case QMetaType::QVariantList:
+ case QMetaType::QStringList:
+ return typeObj == &PyList_Type;
+ case QMetaType::QByteArray:
+ return typeObj == &PyBytes_Type;
+ case QMetaType::QString:
+ return typeObj == &PyUnicode_Type;
+ case QMetaType::Short:
+ case QMetaType::Long:
+ case QMetaType::LongLong:
+ case QMetaType::UShort:
+ case QMetaType::ULong:
+ case QMetaType::ULongLong:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return typeObj == &PyLong_Type;
+ case QMetaType::Double:
+ case QMetaType::Float:
+ case QMetaType::Float16:
+ return typeObj == &PyFloat_Type;
+ case QMetaType::Bool:
+ return typeObj == &PyBool_Type;
+ default:
+ break;
+ }
+ return false;
+}
+// @snippet settings-value-helpers
+
// @snippet qsettings-value
// If we enter the kwds, means that we have a defaultValue or
// at least a type.
// This avoids that we are passing '0' as defaultValue.
// defaultValue can also be passed as positional argument,
// not only as keyword.
+// PySide-535: Allow for empty dict instead of nullptr in PyPy
QVariant out;
-if (kwds || numArgs > 1) {
+if ((kwds && PyDict_Size(kwds) > 0) || numArgs > 1) {
Py_BEGIN_ALLOW_THREADS
out = %CPPSELF.value(%1, %2);
Py_END_ALLOW_THREADS
@@ -65,77 +191,32 @@ if (kwds || numArgs > 1) {
PyTypeObject *typeObj = reinterpret_cast<PyTypeObject*>(%PYARG_3);
-if (typeObj && !Shiboken::ObjectType::checkType(typeObj)) {
- if (typeObj == &PyList_Type) {
- QByteArray out_ba = out.toByteArray();
- if (!out_ba.isEmpty()) {
- QByteArrayList valuesList = out_ba.split(',');
- const Py_ssize_t valuesSize = valuesList.size();
- if (valuesSize > 0) {
- PyObject *list = PyList_New(valuesSize);
- for (Py_ssize_t i = 0; i < valuesSize; ++i) {
- PyObject *item = PyUnicode_FromString(valuesList.at(i).constData());
- PyList_SET_ITEM(list, i, item);
- }
- %PYARG_0 = list;
-
- } else {
- %PYARG_0 = %CONVERTTOPYTHON[QVariant](out);
- }
- } else {
- %PYARG_0 = PyList_New(0);
- }
- } else if (typeObj == &PyBytes_Type) {
- QByteArray asByteArray = out.toByteArray();
- %PYARG_0 = PyBytes_FromString(asByteArray.constData());
- } else if (typeObj == &PyUnicode_Type) {
- QByteArray asByteArray = out.toByteArray();
- %PYARG_0 = PyUnicode_FromString(asByteArray.constData());
- } else if (typeObj == &PyLong_Type) {
- float asFloat = out.toFloat();
- pyResult = PyLong_FromDouble(asFloat);
- } else if (typeObj == &PyFloat_Type) {
- float asFloat = out.toFloat();
- %PYARG_0 = PyFloat_FromDouble(asFloat);
- } else if (typeObj == &PyBool_Type) {
- if (out.toBool()) {
- Py_INCREF(Py_True);
- %PYARG_0 = Py_True;
- } else {
- Py_INCREF(Py_False);
- %PYARG_0 = Py_False;
- }
+if (typeObj && !Shiboken::ObjectType::checkType(typeObj)
+ && !isEquivalentSettingsType(typeObj, out.typeId())) {
+ %PYARG_0 = settingsTypeCoercion(out, typeObj);
+} else {
+ if (out.isValid()) {
+ %PYARG_0 = %CONVERTTOPYTHON[QVariant](out);
} else {
- // TODO: PyDict_Type and PyTuple_Type
- PyErr_SetString(PyExc_TypeError,
- "Invalid type parameter.\n"
- "\tUse 'list', 'bytes', 'str', 'int', 'float', 'bool', "
- "or a Qt-derived type");
- return nullptr;
- }
-}
-else {
- if (!out.isValid()) {
Py_INCREF(Py_None);
%PYARG_0 = Py_None;
- } else {
- %PYARG_0 = %CONVERTTOPYTHON[QVariant](out);
}
}
// @snippet qsettings-value
+// @snippet metatype-from-type
+%0 = new %TYPE(PySide::qMetaTypeFromPyType(reinterpret_cast<PyTypeObject *>(%1)));
+// @snippet metatype-from-type
+
+// @snippet metatype-from-metatype-type
+Shiboken::AutoDecRef intArg(PyObject_GetAttrString(%PYARG_1, "value"));
+%0 = new %TYPE(PyLong_AsLong(intArg));
+// @snippet metatype-from-metatype-type
+
// @snippet conversion-pytypeobject-qmetatype
-if (Shiboken::String::checkType(reinterpret_cast<PyTypeObject *>(%in)))
- %out = QMetaType(QMetaType::QString);
-else if (%in == reinterpret_cast<PyObject *>(&PyFloat_Type))
- %out = QMetaType(QMetaType::Double);
-else if (%in == reinterpret_cast<PyObject *>(&PyLong_Type))
- %out = QMetaType(QMetaType::Int);
-else if (Py_TYPE(%in) == SbkObjectType_TypeF())
- %out = QMetaType::fromName(Shiboken::ObjectType::getOriginalName((SbkObjectType *)%in));
-else
- %out = QMetaType::fromName(reinterpret_cast<PyTypeObject *>(%in)->tp_name);
+auto *pyType = reinterpret_cast<PyTypeObject *>(%in);
+%out = PySide::qMetaTypeFromPyType(pyType);
// @snippet conversion-pytypeobject-qmetatype
// @snippet conversion-qmetatype-pytypeobject
@@ -146,97 +227,12 @@ return %out;
// @snippet conversion-qmetatype-pytypeobject
// @snippet qvariant-conversion
-static QMetaType QVariant_resolveMetaType(PyTypeObject *type)
-{
- if (PyObject_TypeCheck(type, SbkObjectType_TypeF())) {
- auto sbkType = reinterpret_cast<SbkObjectType *>(type);
- const char *typeName = Shiboken::ObjectType::getOriginalName(sbkType);
- if (!typeName)
- return {};
- const bool valueType = '*' != typeName[qstrlen(typeName) - 1];
- // Do not convert user type of value
- if (valueType && Shiboken::ObjectType::isUserType(type))
- return {};
- QMetaType metaType = QMetaType::fromName(typeName);
- if (metaType.isValid())
- return metaType;
- // Do not resolve types to value type
- if (valueType)
- return {};
- // Find in base types. First check tp_bases, and only after check tp_base, because
- // tp_base does not always point to the first base class, but rather to the first
- // that has added any python fields or slots to its object layout.
- // See https://mail.python.org/pipermail/python-list/2009-January/520733.html
- if (type->tp_bases) {
- for (int i = 0, size = PyTuple_GET_SIZE(type->tp_bases); i < size; ++i) {
- auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(type->tp_bases, i));
- const QMetaType derived = QVariant_resolveMetaType(baseType);
- if (derived.isValid())
- return derived;
- }
- } else if (type->tp_base) {
- return QVariant_resolveMetaType(type->tp_base);
- }
- }
- return {};
-}
-static QVariant QVariant_convertToValueList(PyObject *list)
-{
- if (PySequence_Size(list) < 0) {
- // clear the error if < 0 which means no length at all
- PyErr_Clear();
- return QVariant();
- }
-
- Shiboken::AutoDecRef element(PySequence_GetItem(list, 0));
-
- const QMetaType metaType = QVariant_resolveMetaType(element.cast<PyTypeObject *>());
- if (metaType.isValid()) {
- QByteArray listTypeName("QList<");
- listTypeName += metaType.name();
- listTypeName += '>';
- QMetaType metaType = QMetaType::fromName(listTypeName);
- if (metaType.isValid()) {
- Shiboken::Conversions::SpecificConverter converter(listTypeName);
- if (converter) {
- QVariant var(metaType);
- converter.toCpp(list, &var);
- return var;
- }
- qWarning() << "Type converter for :" << listTypeName << "not registered.";
- }
- }
- return QVariant();
-}
-static bool QVariant_isStringList(PyObject *list)
-{
- if (!PySequence_Check(list)) {
- // If it is not a list or a derived list class
- // we assume that will not be a String list neither.
- return false;
- }
-
- if (PySequence_Size(list) < 0) {
- // clear the error if < 0 which means no length at all
- PyErr_Clear();
- return false;
- }
-
- Shiboken::AutoDecRef fast(PySequence_Fast(list, "Failed to convert QVariantList"));
- const Py_ssize_t size = PySequence_Fast_GET_SIZE(fast.object());
- for (Py_ssize_t i = 0; i < size; ++i) {
- PyObject *item = PySequence_Fast_GET_ITEM(fast.object(), i);
- if (!%CHECKTYPE[QString](item))
- return false;
- }
- return true;
-}
static QVariant QVariant_convertToVariantMap(PyObject *map)
{
Py_ssize_t pos = 0;
Shiboken::AutoDecRef keys(PyDict_Keys(map));
if (!QVariant_isStringList(keys))
- return QVariant();
+ return {};
PyObject *key;
PyObject *value;
QMap<QString,QVariant> ret;
@@ -260,7 +256,7 @@ static QVariant QVariant_convertToVariantList(PyObject *list)
if (PySequence_Size(list) < 0) {
// clear the error if < 0 which means no length at all
PyErr_Clear();
- return QVariant();
+ return {};
}
QList<QVariant> lst;
@@ -273,6 +269,30 @@ static QVariant QVariant_convertToVariantList(PyObject *list)
}
return QVariant(lst);
}
+
+using SpecificConverter = Shiboken::Conversions::SpecificConverter;
+
+static std::optional<SpecificConverter> converterForQtType(const char *typeNameC)
+{
+ // Fix typedef "QGenericMatrix<3,3,float>" -> QMatrix3x3". The reverse
+ // conversion happens automatically in QMetaType::fromName() in
+ // QVariant_resolveMetaType().
+ QByteArrayView typeNameV(typeNameC);
+ if (typeNameV.startsWith("QGenericMatrix<") && typeNameV.endsWith(",float>")) {
+ QByteArray typeName = typeNameV.toByteArray();
+ typeName.remove(1, 7);
+ typeName.remove(7, 1); // '<'
+ typeName.chop(7);
+ typeName.replace(',', 'x');
+ SpecificConverter matrixConverter(typeName.constData());
+ if (matrixConverter)
+ return matrixConverter;
+ }
+ SpecificConverter converter(typeNameC);
+ if (converter)
+ return converter;
+ return std::nullopt;
+}
// @snippet qvariant-conversion
// @snippet qt-qabs
@@ -280,30 +300,6 @@ double _abs = qAbs(%1);
%PYARG_0 = %CONVERTTOPYTHON[double](_abs);
// @snippet qt-qabs
-// @snippet qt-postroutine
-namespace PySide {
-static QStack<PyObject *> globalPostRoutineFunctions;
-void globalPostRoutineCallback()
-{
- Shiboken::GilState state;
- for (auto *callback : globalPostRoutineFunctions) {
- Shiboken::AutoDecRef result(PyObject_CallObject(callback, nullptr));
- Py_DECREF(callback);
- }
- globalPostRoutineFunctions.clear();
-}
-void addPostRoutine(PyObject *callback)
-{
- if (PyCallable_Check(callback)) {
- globalPostRoutineFunctions << callback;
- Py_INCREF(callback);
- } else {
- PyErr_SetString(PyExc_TypeError, "qAddPostRoutine: The argument must be a callable object.");
- }
-}
-} // namespace
-// @snippet qt-postroutine
-
// @snippet qt-addpostroutine
PySide::addPostRoutine(%1);
// @snippet qt-addpostroutine
@@ -312,275 +308,70 @@ PySide::addPostRoutine(%1);
qAddPostRoutine(PySide::globalPostRoutineCallback);
// @snippet qt-qaddpostroutine
+// @snippet qcompress-buffer
+auto *ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1));
+QByteArray compressed = %FUNCTION_NAME(ptr, %2, %3);
+%PYARG_0 = %CONVERTTOPYTHON[QByteArray](compressed);
+// @snippet qcompress-buffer
+
+// @snippet quncompress-buffer
+auto *ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1));
+QByteArray uncompressed = %FUNCTION_NAME(ptr, %2);
+%PYARG_0 = %CONVERTTOPYTHON[QByteArray](uncompressed);
+// @snippet quncompress-buffer
+
// @snippet qt-version
QList<QByteArray> version = QByteArray(qVersion()).split('.');
PyObject *pyQtVersion = PyTuple_New(3);
for (int i = 0; i < 3; ++i)
- PyTuple_SET_ITEM(pyQtVersion, i, PyInt_FromLong(version[i].toInt()));
+ PyTuple_SET_ITEM(pyQtVersion, i, PyLong_FromLong(version[i].toInt()));
PyModule_AddObject(module, "__version_info__", pyQtVersion);
PyModule_AddStringConstant(module, "__version__", qVersion());
// @snippet qt-version
// @snippet qobject-connect
-static bool isMethodDecorator(PyObject *method, bool is_pymethod, PyObject *self)
-{
- Shiboken::AutoDecRef methodName(PyObject_GetAttr(method, Shiboken::PyMagicName::name()));
- if (!PyObject_HasAttr(self, methodName))
- return true;
- Shiboken::AutoDecRef otherMethod(PyObject_GetAttr(self, methodName));
-
- PyObject *function1, *function2;
-
- // PYSIDE-1523: Each could be a compiled method or a normal method here, for the
- // compiled ones we can use the attributes.
- if (PyMethod_Check(otherMethod.object())) {
- function1 = PyMethod_GET_FUNCTION(otherMethod.object());
- } else {
- function1 = PyObject_GetAttr(otherMethod.object(), Shiboken::PyName::im_func());
- Py_DECREF(function1);
- // Not retaining a reference inline with what PyMethod_GET_FUNCTION does.
- }
-
- if (is_pymethod) {
- function2 = PyMethod_GET_FUNCTION(method);
- } else {
- function2 = PyObject_GetAttr(method, Shiboken::PyName::im_func());
- Py_DECREF(function2);
- // Not retaining a reference inline with what PyMethod_GET_FUNCTION does.
- }
-
- return function1 != function2;
-}
-
-static bool getReceiver(QObject *source,
- const char *signal,
- PyObject *callback,
- QObject **receiver,
- PyObject **self,
- QByteArray *callbackSig)
-{
- bool forceGlobalReceiver = false;
- if (PyMethod_Check(callback)) {
- *self = PyMethod_GET_SELF(callback);
- if (%CHECKTYPE[QObject *](*self))
- *receiver = %CONVERTTOCPP[QObject *](*self);
- forceGlobalReceiver = isMethodDecorator(callback, true, *self);
- } else if (PyCFunction_Check(callback)) {
- *self = PyCFunction_GET_SELF(callback);
- if (*self && %CHECKTYPE[QObject *](*self))
- *receiver = %CONVERTTOCPP[QObject *](*self);
- } else if (PyObject_HasAttr(callback, Shiboken::PyName::im_func())
- && PyObject_HasAttr(callback, Shiboken::PyName::im_self())) {
- *self = PyObject_GetAttr(callback, Shiboken::PyName::im_self());
- Py_DECREF(*self);
-
- if (%CHECKTYPE[QObject *](*self))
- *receiver = %CONVERTTOCPP[QObject *](*self);
- forceGlobalReceiver = isMethodDecorator(callback, false, *self);
- } else if (PyCallable_Check(callback)) {
- // Ok, just a callable object
- *receiver = nullptr;
- *self = nullptr;
- }
-
- bool usingGlobalReceiver = !*receiver || forceGlobalReceiver;
-
- // Check if this callback is a overwrite of a non-virtual Qt slot.
- if (!usingGlobalReceiver && receiver && self) {
- *callbackSig = PySide::Signal::getCallbackSignature(signal, *receiver, callback, usingGlobalReceiver).toLatin1();
- const QMetaObject *metaObject = (*receiver)->metaObject();
- int slotIndex = metaObject->indexOfSlot(callbackSig->constData());
- if (slotIndex != -1 && slotIndex < metaObject->methodOffset() && PyMethod_Check(callback))
- usingGlobalReceiver = true;
- }
-
- const auto receiverThread = *receiver ? (*receiver)->thread() : nullptr;
-
- if (usingGlobalReceiver) {
- PySide::SignalManager &signalManager = PySide::SignalManager::instance();
- *receiver = signalManager.globalReceiver(source, callback);
- // PYSIDE-1354: Move the global receiver to the original receivers's thread
- // so that autoconnections work correctly.
- if (receiverThread && receiverThread != (*receiver)->thread())
- (*receiver)->moveToThread(receiverThread);
- *callbackSig = PySide::Signal::getCallbackSignature(signal, *receiver, callback, usingGlobalReceiver).toLatin1();
- }
-
- return usingGlobalReceiver;
-}
-
-static QMetaObject::Connection qobjectConnect(QObject *source, const char *signal,
- QObject *receiver, const char *slot,
- Qt::ConnectionType type)
-{
- if (!signal || !slot)
- return {};
-
- if (!PySide::Signal::checkQtSignal(signal))
- return {};
- signal++;
-
- if (!PySide::SignalManager::registerMetaMethod(source, signal, QMetaMethod::Signal))
- return {};
-
- bool isSignal = PySide::Signal::isQtSignal(slot);
- slot++;
- PySide::SignalManager::registerMetaMethod(receiver, slot, isSignal ? QMetaMethod::Signal : QMetaMethod::Slot);
- return QObject::connect(source, signal - 1, receiver, slot - 1, type);
-}
-
-static QMetaObject::Connection qobjectConnect(QObject *source, QMetaMethod signal,
- QObject *receiver, QMetaMethod slot,
- Qt::ConnectionType type)
-{
- return qobjectConnect(source, signal.methodSignature(), receiver, slot.methodSignature(), type);
-}
-
-static QMetaObject::Connection qobjectConnectCallback(QObject *source, const char *signal,
- PyObject *callback, Qt::ConnectionType type)
-{
- if (!signal || !PySide::Signal::checkQtSignal(signal))
- return {};
- signal++;
-
- int signalIndex = PySide::SignalManager::registerMetaMethodGetIndex(source, signal, QMetaMethod::Signal);
- if (signalIndex == -1)
- return {};
-
- PySide::SignalManager &signalManager = PySide::SignalManager::instance();
-
- // Extract receiver from callback
- QObject *receiver = nullptr;
- PyObject *self = nullptr;
- QByteArray callbackSig;
- bool usingGlobalReceiver = getReceiver(source, signal, callback, &receiver, &self, &callbackSig);
- if (receiver == nullptr && self == nullptr)
- return {};
-
- const QMetaObject *metaObject = receiver->metaObject();
- const char *slot = callbackSig.constData();
- int slotIndex = metaObject->indexOfSlot(slot);
- QMetaMethod signalMethod = metaObject->method(signalIndex);
-
- if (slotIndex == -1) {
- if (!usingGlobalReceiver && self && !Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))) {
- qWarning("You can't add dynamic slots on an object originated from C++.");
- if (usingGlobalReceiver)
- signalManager.releaseGlobalReceiver(source, receiver);
-
- return {};
- }
-
- if (usingGlobalReceiver)
- slotIndex = signalManager.globalReceiverSlotIndex(receiver, slot);
- else
- slotIndex = PySide::SignalManager::registerMetaMethodGetIndex(receiver, slot, QMetaMethod::Slot);
-
- if (slotIndex == -1) {
- if (usingGlobalReceiver)
- signalManager.releaseGlobalReceiver(source, receiver);
-
- return {};
- }
- }
- auto connection = QMetaObject::connect(source, signalIndex, receiver, slotIndex, type);
- if (connection) {
- if (usingGlobalReceiver)
- signalManager.notifyGlobalReceiver(receiver);
- #ifndef AVOID_PROTECTED_HACK
- source->connectNotify(signalMethod); //Qt5: QMetaMethod instead of char *
- #else
- // Need to cast to QObjectWrapper * and call the public version of
- // connectNotify when avoiding the protected hack.
- reinterpret_cast<QObjectWrapper *>(source)->connectNotify(signalMethod); //Qt5: QMetaMethod instead of char *
- #endif
-
- return connection;
- }
-
- if (usingGlobalReceiver)
- signalManager.releaseGlobalReceiver(source, receiver);
-
- return {};
-}
-
-
-static bool qobjectDisconnectCallback(QObject *source, const char *signal, PyObject *callback)
-{
- if (!PySide::Signal::checkQtSignal(signal))
- return false;
-
- PySide::SignalManager &signalManager = PySide::SignalManager::instance();
-
- // Extract receiver from callback
- QObject *receiver = nullptr;
- PyObject *self = nullptr;
- QByteArray callbackSig;
- QMetaMethod slotMethod;
- bool usingGlobalReceiver = getReceiver(nullptr, signal, callback, &receiver, &self, &callbackSig);
- if (receiver == nullptr && self == nullptr)
- return false;
-
- const QMetaObject *metaObject = receiver->metaObject();
- int signalIndex = source->metaObject()->indexOfSignal(++signal);
- int slotIndex = -1;
-
- slotIndex = metaObject->indexOfSlot(callbackSig);
- slotMethod = metaObject->method(slotIndex);
-
- bool disconnected;
- disconnected = QMetaObject::disconnectOne(source, signalIndex, receiver, slotIndex);
-
- if (disconnected) {
- if (usingGlobalReceiver)
- signalManager.releaseGlobalReceiver(source, receiver);
-
- #ifndef AVOID_PROTECTED_HACK
- source->disconnectNotify(slotMethod); //Qt5: QMetaMethod instead of char *
- #else
- // Need to cast to QObjectWrapper * and call the public version of
- // connectNotify when avoiding the protected hack.
- reinterpret_cast<QObjectWrapper *>(source)->disconnectNotify(slotMethod); //Qt5: QMetaMethod instead of char *
- #endif
- return true;
- }
- return false;
-}
+#include <qobjectconnect.h>
// @snippet qobject-connect
// @snippet qobject-connect-1
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectConnect(%1, %2, %CPPSELF, %3, %4);
+%RETURN_TYPE %0 = PySide::qobjectConnect(%1, %2, %CPPSELF, %3, %4);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-connect-1
// @snippet qobject-connect-2
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectConnect(%1, %2, %3, %4, %5);
+%RETURN_TYPE %0 = PySide::qobjectConnect(%1, %2, %3, %4, %5);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-connect-2
// @snippet qobject-connect-3
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectConnect(%1, %2, %3, %4, %5);
+%RETURN_TYPE %0 = PySide::qobjectConnect(%1, %2, %3, %4, %5);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-connect-3
// @snippet qobject-connect-4
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectConnectCallback(%1, %2, %PYARG_3, %4);
+%RETURN_TYPE %0 = PySide::qobjectConnectCallback(%1, %2, %PYARG_3, %4);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-connect-4
+// @snippet qobject-connect-4-context
+// %FUNCTION_NAME() - disable generation of function call.
+%RETURN_TYPE %0 = PySide::qobjectConnectCallback(%1, %2, %3, %PYARG_4, %5);
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet qobject-connect-4-context
+
// @snippet qobject-connect-5
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectConnectCallback(%CPPSELF, %1, %PYARG_2, %3);
+%RETURN_TYPE %0 = PySide::qobjectConnectCallback(%CPPSELF, %1, %PYARG_2, %3);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-connect-5
// @snippet qobject-connect-6
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectConnect(%CPPSELF, %1, %2, %3, %4);
+%RETURN_TYPE %0 = PySide::qobjectConnect(%CPPSELF, %1, %2, %3, %4);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-connect-6
@@ -591,13 +382,13 @@ static bool qobjectDisconnectCallback(QObject *source, const char *signal, PyObj
// @snippet qobject-disconnect-1
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectDisconnectCallback(%CPPSELF, %1, %2);
+%RETURN_TYPE %0 = PySide::qobjectDisconnectCallback(%CPPSELF, %1, %2);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-disconnect-1
// @snippet qobject-disconnect-2
// %FUNCTION_NAME() - disable generation of function call.
-%RETURN_TYPE %0 = qobjectDisconnectCallback(%1, %2, %3);
+%RETURN_TYPE %0 = PySide::qobjectDisconnectCallback(%1, %2, %3);
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-disconnect-2
@@ -628,10 +419,10 @@ PySide::Feature::init();
// @snippet qt-init-feature
// @snippet qt-pysideinit
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QSTRING_IDX], "unicode");
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QSTRING_IDX], "str");
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QTCORE_QLIST_QVARIANT_IDX], "QVariantList");
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QTCORE_QMAP_QSTRING_QVARIANT_IDX], "QVariantMap");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QString_IDX], "unicode");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QString_IDX], "str");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QtCore_QList_QVariant_IDX], "QVariantList");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QtCore_QMap_QString_QVariant_IDX], "QVariantMap");
PySide::registerInternalQtConf();
PySide::init(module);
@@ -649,8 +440,8 @@ static void msgHandlerCallback(QtMsgType type, const QMessageLogContext &ctx, co
PyTuple_SET_ITEM(arglist, 0, %CONVERTTOPYTHON[QtMsgType](type));
PyTuple_SET_ITEM(arglist, 1, %CONVERTTOPYTHON[QMessageLogContext &](ctx));
QByteArray array = msg.toUtf8(); // Python handler requires UTF-8
- char *data = array.data();
- PyTuple_SET_ITEM(arglist, 2, %CONVERTTOPYTHON[char *](data));
+ const char *data = array.constData();
+ PyTuple_SET_ITEM(arglist, 2, %CONVERTTOPYTHON[const char *](data));
Shiboken::AutoDecRef ret(PyObject_CallObject(qtmsghandler, arglist));
}
static void QtCoreModuleExit()
@@ -681,8 +472,7 @@ if (%PYARG_0 == Py_None)
namespace PySide {
template<> inline Py_ssize_t hash(const QLine &l)
{
- const int v[4] = {l.x1(), l.y1(), l.x2(), l.y2()};
- return qHashRange(v, v + 4);
+ return qHashMulti(0, l.x1(), l.y1(), l.x2(), l.y2());
}
};
// @snippet qline-hash
@@ -740,6 +530,12 @@ QTime time(%4, %5, %6);
%0 = new %TYPE(date, time);
// @snippet qdatetime-2
+// @snippet qdatetime-3
+QDate date(%1, %2, %3);
+QTime time(%4, %5, %6, %7);
+%0 = new %TYPE(date, time, %8);
+// @snippet qdatetime-3
+
// @snippet qdatetime-topython
QDate date = %CPPSELF.date();
QTime time = %CPPSELF.time();
@@ -748,31 +544,6 @@ if (!PyDateTimeAPI)
%PYARG_0 = PyDateTime_FromDateAndTime(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second(), time.msec()*1000);
// @snippet qdatetime-topython
-// @snippet qpoint
-namespace PySide {
- template<> inline Py_ssize_t hash(const QPoint &v) {
- return qHash(qMakePair(v.x(), v.y()));
- }
-};
-// @snippet qpoint
-
-// @snippet qrect
-namespace PySide {
- template<> inline Py_ssize_t hash(const QRect &r) {
- const int v[4] = {r.x(), r.y(), r.width(), r.height()};
- return qHashRange(v, v + 4);
- }
-};
-// @snippet qrect
-
-// @snippet qsize
-namespace PySide {
- template<> inline Py_ssize_t hash(const QSize &v) {
- return qHash(qMakePair(v.width(), v.height()));
- }
-};
-// @snippet qsize
-
// @snippet qtime-topython
if (!PyDateTimeAPI)
PyDateTime_IMPORT;
@@ -800,6 +571,11 @@ Py_XDECREF(result);
return !result ? -1 : 0;
// @snippet qbitarray-setitem
+// @snippet default-enter
+Py_INCREF(%PYSELF);
+pyResult = %PYSELF;
+// @snippet default-enter
+
// @snippet qsignalblocker-unblock
%CPPSELF.unblock();
// @snippet qsignalblocker-unblock
@@ -822,174 +598,87 @@ qRegisterMetaType<QList<int> >("QList<int>");
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qobject-metaobject
-// @snippet qobject-findchild-1
-static bool _findChildTypeMatch(const QObject *child, PyTypeObject *desiredType)
-{
- auto *pyChildType = PySide::getTypeForQObject(child);
- return pyChildType != nullptr && PyType_IsSubtype(pyChildType, desiredType);
-}
-
-static inline bool _findChildrenComparator(const QObject *child,
- const QRegularExpression &name)
-{
- return name.match(child->objectName()).hasMatch();
-}
-
-static inline bool _findChildrenComparator(const QObject *child,
- const QString &name)
-{
- return name.isNull() || name == child->objectName();
-}
-
-static QObject *_findChildHelper(const QObject *parent, const QString &name,
- PyTypeObject *desiredType,
- Qt::FindChildOptions options)
-{
- for (auto *child : parent->children()) {
- if (_findChildrenComparator(child, name)
- && _findChildTypeMatch(child, desiredType)) {
- return child;
- }
- }
-
- if (options.testFlag(Qt::FindChildrenRecursively)) {
- for (auto *child : parent->children()) {
- QObject *obj = _findChildHelper(child, name, desiredType, options);
- if (obj)
- return obj;
- }
- }
- return nullptr;
-}
-
-template<typename T> // QString/QRegularExpression
-static void _findChildrenHelper(const QObject *parent, const T& name, PyTypeObject *desiredType,
- Qt::FindChildOptions options,
- PyObject *result)
-{
- for (const auto *child : parent->children()) {
- if (_findChildrenComparator(child, name) &&
- _findChildTypeMatch(child, desiredType)) {
- Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child));
- PyList_Append(result, pyChild.object());
- }
- if (options.testFlag(Qt::FindChildrenRecursively))
- _findChildrenHelper(child, name, desiredType, options, result);
- }
-}
-// @snippet qobject-findchild-1
-
// @snippet qobject-findchild-2
-QObject *child = _findChildHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3);
+QObject *child = qObjectFindChild(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3);
%PYARG_0 = %CONVERTTOPYTHON[QObject *](child);
// @snippet qobject-findchild-2
// @snippet qobject-findchildren
%PYARG_0 = PyList_New(0);
-_findChildrenHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3, %PYARG_0);
+qObjectFindChildren(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3,
+ [%PYARG_0](QObject *child) {
+ Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child));
+ PyList_Append(%PYARG_0, pyChild.object());
+ });
// @snippet qobject-findchildren
-//////////////////////////////////////////////////////////////////////////////
-// PYSIDE-131: Use the class name as context where the calling function is
-// living. Derived Python classes have the wrong context.
-//
-// The original patch uses Python introspection to look up the current
-// function (from the frame stack) in the class __dict__ along the mro.
-//
-// The problem is that looking into the frame stack works for Python
-// functions, only. For including builtin function callers, the following
-// approach turned out to be much simpler:
-//
-// Walk the __mro__
-// - translate the string
-// - if the translated string is changed:
-// - return the translation.
-
// @snippet qobject-tr
-PyTypeObject *type = reinterpret_cast<PyTypeObject *>(%PYSELF);
-PyObject *mro = type->tp_mro;
-auto len = PyTuple_GET_SIZE(mro);
-QString result = QString::fromUtf8(%1);
-QString oldResult = result;
-static auto *sbkObjectType = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF());
-for (Py_ssize_t idx = 0; idx < len - 1; ++idx) {
- // Skip the last class which is `object`.
- auto *type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
- if (type == sbkObjectType)
- continue;
- const char *context = type->tp_name;
- const char *dotpos = strrchr(context, '.');
- if (dotpos != nullptr)
- context = dotpos + 1;
- result = QCoreApplication::translate(context, %1, %2, %3);
- if (result != oldResult)
- break;
-}
+const QString result = qObjectTr(reinterpret_cast<PyTypeObject *>(%PYSELF), %1, %2, %3);
%PYARG_0 = %CONVERTTOPYTHON[QString](result);
// @snippet qobject-tr
-// @snippet qobject-receivers
-// Avoid return +1 because SignalManager connect to "destroyed()" signal to control object timelife
-int ret = %CPPSELF.%FUNCTION_NAME(%1);
-if (ret > 0 && ((strcmp(%1, SIGNAL(destroyed())) == 0) || (strcmp(%1, SIGNAL(destroyed(QObject*))) == 0)))
- ret -= PySide::SignalManager::instance().countConnectionsWith(%CPPSELF);
-
-%PYARG_0 = %CONVERTTOPYTHON[int](ret);
-// @snippet qobject-receivers
+// @snippet qobject-sender
+// Retrieve the sender from a dynamic property set by GlobalReceiverV2 in case of a
+// non-C++ slot (Python callback).
+auto *ret = %CPPSELF.%FUNCTION_NAME();
+if (ret == nullptr) {
+ auto senderV = %CPPSELF.property("_q_pyside_sender");
+ if (senderV.typeId() == QMetaType::QObjectStar)
+ ret = senderV.value<QObject *>();
+}
+%PYARG_0 = %CONVERTTOPYTHON[QObject*](ret);
+// @snippet qobject-sender
// @snippet qbytearray-mgetitem
if (PyIndex_Check(_key)) {
- Py_ssize_t _i;
- _i = PyNumber_AsSsize_t(_key, PyExc_IndexError);
+ const Py_ssize_t _i = PyNumber_AsSsize_t(_key, PyExc_IndexError);
if (_i < 0 || _i >= %CPPSELF.size()) {
PyErr_SetString(PyExc_IndexError, "index out of bounds");
- return 0;
- } else {
- char res[2];
- res[0] = %CPPSELF.at(_i);
- res[1] = 0;
- return PyBytes_FromStringAndSize(res, 1);
- }
-} else if (PySlice_Check(_key)) {
- Py_ssize_t start, stop, step, slicelength, cur;
- if (PySlice_GetIndicesEx(_key, %CPPSELF.count(), &start, &stop, &step, &slicelength) < 0) {
return nullptr;
}
+ char res[2] = {%CPPSELF.at(_i), '\0'};
+ return PyBytes_FromStringAndSize(res, 1);
+}
- QByteArray ba;
- if (slicelength <= 0) {
- return %CONVERTTOPYTHON[QByteArray](ba);
- } else if (step == 1) {
- Py_ssize_t max = %CPPSELF.count();
- start = qBound(Py_ssize_t(0), start, max);
- stop = qBound(Py_ssize_t(0), stop, max);
- QByteArray ba;
- if (start < stop)
- ba = %CPPSELF.mid(start, stop - start);
- return %CONVERTTOPYTHON[QByteArray](ba);
- } else {
- QByteArray ba;
- for (cur = start; slicelength > 0; cur += static_cast<size_t>(step), slicelength--) {
- ba.append(%CPPSELF.at(cur));
- }
- return %CONVERTTOPYTHON[QByteArray](ba);
- }
-} else {
+if (PySlice_Check(_key) == 0) {
PyErr_Format(PyExc_TypeError,
"list indices must be integers or slices, not %.200s",
Py_TYPE(_key)->tp_name);
return nullptr;
}
+
+Py_ssize_t start, stop, step, slicelength;
+if (PySlice_GetIndicesEx(_key, %CPPSELF.size(), &start, &stop, &step, &slicelength) < 0)
+ return nullptr;
+
+QByteArray ba;
+if (slicelength <= 0)
+ return %CONVERTTOPYTHON[QByteArray](ba);
+
+if (step == 1) {
+ Py_ssize_t max = %CPPSELF.size();
+ start = qBound(Py_ssize_t(0), start, max);
+ stop = qBound(Py_ssize_t(0), stop, max);
+ if (start < stop)
+ ba = %CPPSELF.mid(start, stop - start);
+ return %CONVERTTOPYTHON[QByteArray](ba);
+}
+
+for (Py_ssize_t cur = start; slicelength > 0; cur += step, --slicelength)
+ ba.append(%CPPSELF.at(cur));
+
+return %CONVERTTOPYTHON[QByteArray](ba);
// @snippet qbytearray-mgetitem
// @snippet qbytearray-msetitem
+// PYSIDE-2404: Usage of the `get()` function not necessary, the type exists.
if (PyIndex_Check(_key)) {
Py_ssize_t _i = PyNumber_AsSsize_t(_key, PyExc_IndexError);
if (_i == -1 && PyErr_Occurred())
return -1;
if (_i < 0)
- _i += %CPPSELF.count();
+ _i += %CPPSELF.size();
if (_i < 0 || _i >= %CPPSELF.size()) {
PyErr_SetString(PyExc_IndexError, "QByteArray index out of range");
@@ -1007,7 +696,8 @@ if (PyIndex_Check(_key)) {
PyErr_SetString(PyExc_ValueError, "bytearray must be of size 1");
return -1;
}
- } else if (reinterpret_cast<PyTypeObject *>(Py_TYPE(_value)) == reinterpret_cast<PyTypeObject *>(SbkPySide6_QtCoreTypes[SBK_QBYTEARRAY_IDX])) {
+ } else if (Py_TYPE(_value) == reinterpret_cast<PyTypeObject *>(
+ SbkPySide6_QtCoreTypeStructs[SBK_QByteArray_IDX].type)) {
if (PyObject_Length(_value) != 1) {
PyErr_SetString(PyExc_ValueError, "QByteArray must be of size 1");
return -1;
@@ -1023,63 +713,64 @@ if (PyIndex_Check(_key)) {
PyObject *result = Sbk_QByteArrayFunc_insert(self, args);
Py_DECREF(args);
Py_XDECREF(result);
- return !result ? -1 : 0;
-} else if (PySlice_Check(_key)) {
- Py_ssize_t start, stop, step, slicelength, value_length;
- if (PySlice_GetIndicesEx(_key, %CPPSELF.count(), &start, &stop, &step, &slicelength) < 0) {
- return -1;
- }
- // The parameter candidates are: bytes/str, bytearray, QByteArray itself.
- // Not support iterable which contains ints between 0~255
-
- // case 1: value is nullpre, means delete the items within the range
- // case 2: step is 1, means shrink or expanse
- // case 3: step is not 1, then the number of slots have to equal the number of items in _value
- QByteArray ba;
- if (_value == nullptr || _value == Py_None) {
- ba = QByteArray();
- value_length = 0;
- } else if (!(PyBytes_Check(_value) || PyByteArray_Check(_value) || reinterpret_cast<PyTypeObject *>(Py_TYPE(_value)) == reinterpret_cast<PyTypeObject *>(SbkPySide6_QtCoreTypes[SBK_QBYTEARRAY_IDX]))) {
- PyErr_Format(PyExc_TypeError, "bytes, bytearray or QByteArray is required, not %.200s", Py_TYPE(_value)->tp_name);
- return -1;
- } else {
- value_length = PyObject_Length(_value);
- }
+ return result != nullptr ? 0: -1;
+}
- if (step != 1 && value_length != slicelength) {
- PyErr_Format(PyExc_ValueError, "attempt to assign %s of size %d to extended slice of size %d",
- Py_TYPE(_value)->tp_name, int(value_length), int(slicelength));
- return -1;
+if (PySlice_Check(_key) == 0) {
+ PyErr_Format(PyExc_TypeError, "QBytearray indices must be integers or slices, not %.200s",
+ Py_TYPE(_key)->tp_name);
+ return -1;
+}
+
+Py_ssize_t start, stop, step, slicelength;
+if (PySlice_GetIndicesEx(_key, %CPPSELF.size(), &start, &stop, &step, &slicelength) < 0)
+ return -1;
+
+// The parameter candidates are: bytes/str, bytearray, QByteArray itself.
+// Not supported are iterables containing ints between 0~255
+// case 1: value is nullpre, means delete the items within the range
+// case 2: step is 1, means shrink or expand
+// case 3: step is not 1, then the number of slots have to equal the number of items in _value
+Py_ssize_t value_length = 0;
+if (_value != nullptr && _value != Py_None) {
+ if (!(PyBytes_Check(_value) || PyByteArray_Check(_value)
+ || Py_TYPE(_value) == SbkPySide6_QtCoreTypeStructs[SBK_QByteArray_IDX].type)) {
+ PyErr_Format(PyExc_TypeError, "bytes, bytearray or QByteArray is required, not %.200s",
+ Py_TYPE(_value)->tp_name);
+ return -1;
}
+ value_length = PyObject_Length(_value);
+}
- if (step != 1) {
- int i = start;
- for (int j = 0; j < slicelength; j++) {
- PyObject *item = PyObject_GetItem(_value, PyLong_FromLong(j));
- QByteArray temp;
- if (PyLong_Check(item)) {
- int overflow;
- long ival = PyLong_AsLongAndOverflow(item, &overflow);
- // Not suppose to bigger than 255 because only bytes, bytearray, QByteArray were accept
- temp = QByteArray(reinterpret_cast<const char *>(&ival));
- } else {
- temp = %CONVERTTOCPP[QByteArray](item);
- }
-
- %CPPSELF.replace(i, 1, temp);
- i += step;
+if (step != 1 && value_length != slicelength) {
+ PyErr_Format(PyExc_ValueError, "attempt to assign %s of size %d to extended slice of size %d",
+ Py_TYPE(_value)->tp_name, int(value_length), int(slicelength));
+ return -1;
+}
+
+if (step != 1) {
+ Py_ssize_t i = start;
+ for (Py_ssize_t j = 0; j < slicelength; ++j) {
+ PyObject *item = PyObject_GetItem(_value, PyLong_FromSsize_t(j));
+ QByteArray temp;
+ if (PyLong_Check(item)) {
+ int overflow;
+ const long ival = PyLong_AsLongAndOverflow(item, &overflow);
+ // Not supposed to be bigger than 255 because only bytes,
+ // bytearray, QByteArray were accepted
+ temp.append(char(ival));
+ } else {
+ temp = %CONVERTTOCPP[QByteArray](item);
}
- return 0;
- } else {
- ba = %CONVERTTOCPP[QByteArray](_value);
- %CPPSELF.replace(start, slicelength, ba);
- return 0;
+ %CPPSELF.replace(i, 1, temp);
+ i += step;
}
-} else {
- PyErr_Format(PyExc_TypeError, "QBytearray indices must be integers or slices, not %.200s",
- Py_TYPE(_key)->tp_name);
- return -1;
+ return 0;
}
+
+QByteArray ba = %CONVERTTOCPP[QByteArray](_value);
+%CPPSELF.replace(start, slicelength, ba);
+return 0;
// @snippet qbytearray-msetitem
// @snippet qbytearray-bufferprotocol
@@ -1094,16 +785,16 @@ static int SbkQByteArray_getbufferproc(PyObject *obj, Py_buffer *view, int flags
QByteArray * cppSelf = %CONVERTTOCPP[QByteArray *](obj);
//XXX /|\ omitting this space crashes shiboken!
- #ifdef Py_LIMITED_API
+#ifdef Py_LIMITED_API
view->obj = obj;
view->buf = reinterpret_cast<void *>(cppSelf->data());
view->len = cppSelf->size();
view->readonly = 0;
view->itemsize = 1;
- view->format = const_cast<char *>("c");
+ view->format = (flags & PyBUF_FORMAT) == PyBUF_FORMAT ? const_cast<char *>("B") : nullptr;
view->ndim = 1;
view->shape = (flags & PyBUF_ND) == PyBUF_ND ? &(view->len) : nullptr;
- view->strides = &view->itemsize;
+ view->strides = (flags & PyBUF_STRIDES) == PyBUF_STRIDES ? &(view->itemsize) : nullptr;
view->suboffsets = nullptr;
view->internal = nullptr;
@@ -1235,7 +926,7 @@ Py_DECREF(aux);
// @snippet qbytearray-str
// @snippet qbytearray-len
-return %CPPSELF.count();
+return %CPPSELF.size();
// @snippet qbytearray-len
// @snippet qbytearray-getitem
@@ -1269,6 +960,13 @@ uchar *ptr = reinterpret_cast<uchar *>(Shiboken::Buffer::getPointer(%PYARG_1));
%PYARG_0 = Shiboken::Buffer::newObject(%CPPSELF.%FUNCTION_NAME(%1, %2, %3), %2, Shiboken::Buffer::ReadWrite);
// @snippet qfiledevice-map
+// @snippet qiodevice-bufferedread
+Py_ssize_t bufferLen;
+auto *data = reinterpret_cast<char*>(Shiboken::Buffer::getPointer(%PYARG_1, &bufferLen));
+%RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(data, PyLong_AsLongLong(%PYARG_2));
+return PyLong_FromLong(%0);
+// @snippet qiodevice-bufferedread
+
// @snippet qiodevice-readdata
QByteArray ba(1 + qsizetype(%2), char(0));
%CPPSELF.%FUNCTION_NAME(ba.data(), qint64(%2));
@@ -1279,6 +977,11 @@ QByteArray ba(1 + qsizetype(%2), char(0));
%CPPSELF.%FUNCTION_NAME(Shiboken::String::toCString(%PYARG_1), Shiboken::String::len(%PYARG_1));
// @snippet qcryptographichash-adddata
+// @snippet qmetaobject-repr
+const QByteArray repr = PySide::MetaObjectBuilder::formatMetaObject(%CPPSELF).toUtf8();
+%PYARG_0 = PyUnicode_FromString(repr.constData());
+// @snippet qmetaobject-repr
+
// @snippet qsocketdescriptor
#ifdef WIN32
using DescriptorType = Qt::HANDLE;
@@ -1311,63 +1014,124 @@ auto *ptr = reinterpret_cast<uchar *>(Shiboken::Buffer::getPointer(%PYARG_1, &si
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
// @snippet qtranslator-load
-// @snippet qtimer-singleshot-1
-// %FUNCTION_NAME() - disable generation of c++ function call
-(void) %2; // remove warning about unused variable
-Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
-auto *timerType = reinterpret_cast<PyTypeObject *>(Shiboken::SbkType<QTimer>());
-auto *pyTimer = timerType->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
-timerType->tp_init(pyTimer, emptyTuple, nullptr);
-
-auto timer = %CONVERTTOCPP[QTimer *](pyTimer);
-//XXX /|\ omitting this space crashes shiboken!
-Shiboken::AutoDecRef result(
- PyObject_CallMethod(pyTimer, "connect", "OsOs",
- pyTimer,
- SIGNAL(timeout()),
- %PYARG_2,
- %3)
-);
-Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
-Py_XDECREF(pyTimer);
-timer->setSingleShot(true);
-timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater);
-timer->start(%1);
-// @snippet qtimer-singleshot-1
-
-// @snippet qtimer-singleshot-2
-// %FUNCTION_NAME() - disable generation of c++ function call
+// @snippet qtimer-singleshot-functorclass
+struct QSingleShotTimerFunctor : public Shiboken::PyObjectHolder
+{
+public:
+ using Shiboken::PyObjectHolder::PyObjectHolder;
+
+ void operator()();
+};
+
+void QSingleShotTimerFunctor::operator()()
+{
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef arglist(PyTuple_New(0));
+ Shiboken::AutoDecRef ret(PyObject_CallObject(object(), arglist));
+ release(); // single shot
+}
+// @snippet qtimer-singleshot-functorclass
+
+// @snippet qtimer-singleshot-direct-mapping
Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
-auto *timerType = reinterpret_cast<PyTypeObject *>(Shiboken::SbkType<QTimer>());
-auto *pyTimer = timerType->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
-timerType->tp_init(pyTimer, emptyTuple, nullptr);
-QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
-timer->setSingleShot(true);
-
-if (PyObject_TypeCheck(%2, PySideSignalInstanceTypeF())) {
- PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2);
- Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance)));
- Shiboken::AutoDecRef result(
- PyObject_CallMethod(pyTimer, "connect", "OsOO",
- pyTimer,
- SIGNAL(timeout()),
- PySide::Signal::getObject(signalInstance),
- signalSignature.object())
- );
+%CPPSELF.%FUNCTION_NAME(%1, %2, %3);
+// @snippet qtimer-singleshot-direct-mapping
+
+// @snippet qtimer-singleshot-functor
+auto msec = %1;
+if (msec == 0) {
+ if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
+ auto *signal = %PYARG_2;
+ auto cppCallback = [signal]()
+ {
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef ret(PyObject_CallMethod(signal, "emit", "()"));
+ Py_DECREF(signal);
+ };
+
+ Py_INCREF(signal);
+ %CPPSELF.%FUNCTION_NAME(msec, cppCallback);
+ } else {
+ %CPPSELF.%FUNCTION_NAME(msec, QSingleShotTimerFunctor(%PYARG_2));
+ }
+} else {
+ // %FUNCTION_NAME() - disable generation of c++ function call
+ Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
+ auto *timerType = Shiboken::SbkType<QTimer>();
+ auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
+ auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
+ auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
+ initFunc(pyTimer, emptyTuple, nullptr);
+
+ QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
+ timer->setSingleShot(true);
+
+ if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
+ PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2);
+ Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance)));
+ Shiboken::AutoDecRef result(
+ PyObject_CallMethod(pyTimer, "connect", "OsOO",
+ pyTimer,
+ SIGNAL(timeout()),
+ PySide::Signal::getObject(signalInstance),
+ signalSignature.object())
+ );
+ } else {
+ Shiboken::AutoDecRef result(
+ PyObject_CallMethod(pyTimer, "connect", "OsO",
+ pyTimer,
+ SIGNAL(timeout()),
+ %PYARG_2)
+ );
+ }
+
+ timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
+ Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
+ Py_XDECREF(pyTimer);
+ timer->start(msec);
+}
+// @snippet qtimer-singleshot-functor
+
+// @snippet qtimer-singleshot-functor-context
+auto msec = %1;
+if (msec == 0) {
+ Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
+ auto *callable = %PYARG_3;
+ auto cppCallback = [callable]()
+ {
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef arglist(PyTuple_New(0));
+ Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
+ Py_DECREF(callable);
+ };
+
+ Py_INCREF(callable);
+ %CPPSELF.%FUNCTION_NAME(msec, %2, cppCallback);
} else {
+ Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
+ auto *timerType = Shiboken::SbkType<QTimer>();
+ auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
+ auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
+ auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
+ initFunc(pyTimer, emptyTuple, nullptr);
+
+ QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
+ timer->setSingleShot(true);
+
Shiboken::AutoDecRef result(
- PyObject_CallMethod(pyTimer, "connect", "OsO",
+ PyObject_CallMethod(pyTimer, "connect", "OsOO",
pyTimer,
SIGNAL(timeout()),
- %PYARG_2)
+ %PYARG_2,
+ %PYARG_3)
);
-}
-timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
-Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
-Py_XDECREF(pyTimer);
-timer->start(%1);
-// @snippet qtimer-singleshot-2
+ timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
+ Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
+ Py_XDECREF(pyTimer);
+ timer->start(msec);
+}
+// @snippet qtimer-singleshot-functor-context
// @snippet qprocess-startdetached
qint64 pid;
@@ -1429,10 +1193,20 @@ if (result == -1) {
Py_INCREF(Py_None);
%PYARG_0 = Py_None;
} else {
- %PYARG_0 = PyBytes_FromStringAndSize(data.data(), result);
+ %PYARG_0 = PyBytes_FromStringAndSize(data.constData(), result);
}
// @snippet qdatastream-readrawdata
+// @snippet qdatastream-writerawdata-pybuffer
+int r = 0;
+Py_ssize_t bufferLen;
+auto *data = reinterpret_cast<const char*>(Shiboken::Buffer::getPointer(%PYARG_1, &bufferLen));
+Py_BEGIN_ALLOW_THREADS
+r = %CPPSELF.%FUNCTION_NAME(data, bufferLen);
+Py_END_ALLOW_THREADS
+%PYARG_0 = %CONVERTTOPYTHON[int](r);
+// @snippet qdatastream-writerawdata-pybuffer
+
// @snippet qdatastream-writerawdata
int r = 0;
Py_BEGIN_ALLOW_THREADS
@@ -1548,11 +1322,11 @@ QString &res = *%0;
// @snippet return-readData
%RETURN_TYPE %0 = 0;
if (PyBytes_Check(%PYARG_0)) {
- %0 = PyBytes_GET_SIZE((PyObject *)%PYARG_0);
- memcpy(%1, PyBytes_AS_STRING((PyObject *)%PYARG_0), %0);
-} else if (Shiboken::String::check(%PYARG_0)) {
- %0 = Shiboken::String::len((PyObject *)%PYARG_0);
- memcpy(%1, Shiboken::String::toCString((PyObject *)%PYARG_0), %0);
+ %0 = PyBytes_GET_SIZE(%PYARG_0.object());
+ memcpy(%1, PyBytes_AS_STRING(%PYARG_0.object()), %0);
+} else if (Shiboken::String::check(%PYARG_0.object())) {
+ %0 = Shiboken::String::len(%PYARG_0.object());
+ memcpy(%1, Shiboken::String::toCString(%PYARG_0.object()), %0);
}
// @snippet return-readData
@@ -1571,7 +1345,7 @@ Py_END_ALLOW_THREADS
if (atexit.isNull()) {
qWarning("Module atexit not found for registering __moduleShutdown");
PyErr_Clear();
- }else{
+ } else {
regFunc.reset(PyObject_GetAttrString(atexit, "register"));
if (regFunc.isNull()) {
qWarning("Function atexit.register not found for registering __moduleShutdown");
@@ -1587,7 +1361,16 @@ Py_END_ALLOW_THREADS
}
}
// @snippet qt-module-shutdown
-//
+
+// @snippet qthread_init_pypy
+#ifdef PYPY_VERSION
+// PYSIDE-535: PyPy 7.3.8 needs this call, which is actually a no-op in Python 3.9
+// This function should be replaced by a `Py_Initialize` call, but
+// that is still undefined. So we don't rely yet on any PyPy version.
+PyEval_InitThreads();
+#endif
+// @snippet qthread_init_pypy
+
// @snippet qthread_exec_
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"'exec_' will be removed in the future. "
@@ -1668,10 +1451,6 @@ if (PyErr_WarnEx(PyExc_DeprecationWarning,
%out = %OUTTYPE(%in == Py_True);
// @snippet conversion-pybool
-// @snippet conversion-pylong
-%out = %OUTTYPE(PyLong_AsLong(%in));
-// @snippet conversion-pylong
-
// @snippet conversion-pylong-quintptr
#if QT_POINTER_SIZE == 8
%out = %OUTTYPE(PyLong_AsUnsignedLongLong(%in));
@@ -1681,28 +1460,11 @@ if (PyErr_WarnEx(PyExc_DeprecationWarning,
// @snippet conversion-pylong-quintptr
// @snippet conversion-pyunicode
-#ifndef Py_LIMITED_API
-void *data = PyUnicode_DATA(%in);
-Py_ssize_t len = PyUnicode_GetLength(%in);
-switch (PyUnicode_KIND(%in)) {
- case PyUnicode_1BYTE_KIND:
- %out = QString::fromLatin1(reinterpret_cast<const char *>(data));
- break;
- case PyUnicode_2BYTE_KIND:
- %out = QString::fromUtf16(reinterpret_cast<const char16_t *>(data), len);
- break;
- case PyUnicode_4BYTE_KIND:
- %out = QString::fromUcs4(reinterpret_cast<const char32_t *>(data), len);
- break;
-}
-#else
-wchar_t *temp = PyUnicode_AsWideCharString(%in, nullptr);
-%out = QString::fromWCharArray(temp);
-PyMem_Free(temp);
-#endif
+%out = PySide::pyUnicodeToQString(%in);
// @snippet conversion-pyunicode
// @snippet conversion-pynone
+SBK_UNUSED(%in)
%out = %OUTTYPE();
// @snippet conversion-pynone
@@ -1721,7 +1483,7 @@ auto res = (*%CPPSELF) + cppArg0;
// @snippet conversion-pystring-char
char c = %CONVERTTOCPP[char](%in);
-%out = %OUTTYPE(c);
+%out = %OUTTYPE(static_cast<unsigned short>(c));
// @snippet conversion-pystring-char
// @snippet conversion-pyint
@@ -1755,15 +1517,23 @@ double in = %CONVERTTOCPP[double](%in);
// @snippet conversion-sbkobject
// a class supported by QVariant?
const QMetaType metaType = QVariant_resolveMetaType(Py_TYPE(%in));
+bool ok = false;
if (metaType.isValid()) {
QVariant var(metaType);
- Shiboken::Conversions::SpecificConverter converter(metaType.name());
- converter.toCpp(pyIn, var.data());
- %out = var;
-} else {
- // If the type was not encountered, return a default PyObjectWrapper
- %out = QVariant::fromValue(PySide::PyObjectWrapper(%in));
+ auto converterO = converterForQtType(metaType.name());
+ ok = converterO.has_value();
+ if (ok) {
+ converterO.value().toCpp(pyIn, var.data());
+ %out = var;
+ } else {
+ qWarning("%s: Cannot find a converter for \"%s\".",
+ __FUNCTION__, metaType.name());
+ }
}
+
+// If the type was not encountered, return a default PyObjectWrapper
+if (!ok)
+ %out = QVariant::fromValue(PySide::PyObjectWrapper(%in));
// @snippet conversion-sbkobject
// @snippet conversion-pydict
@@ -1787,11 +1557,6 @@ QJsonValue val = QJsonValue::fromVariant(dict);
%out = val.toObject();
// @snippet conversion-qjsonobject-pydict
-// @snippet conversion-qpair-pysequence
-%out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0));
-%out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1));
-// @snippet conversion-qpair-pysequence
-
// @snippet conversion-qdate-pydate
int day = PyDateTime_GET_DAY(%in);
int month = PyDateTime_GET_MONTH(%in);
@@ -1854,11 +1619,44 @@ return PyLong_FromUnsignedLong(%in);
#endif
// @snippet return-pylong-quintptr
+// @snippet return-qfunctionpointer-pylong
+return PyLong_FromVoidPtr(reinterpret_cast<void *>(%in));
+// @snippet return-qfunctionpointer-pylong
+
+// @snippet conversion-pylong-qfunctionpointer
+%out = reinterpret_cast<QFunctionPointer>(PyLong_AsVoidPtr(%in));
+// @snippet conversion-pylong-qfunctionpointer
+
// @snippet return-pyunicode
-QByteArray ba = %in.toUtf8();
-return PyUnicode_FromStringAndSize(ba.constData(), ba.size());
+return PySide::qStringToPyUnicode(%in);
// @snippet return-pyunicode
+// @snippet return-pyunicode-from-qlatin1string
+#ifdef Py_LIMITED_API
+return PySide::qStringToPyUnicode(QString::fromLatin1(%in));
+#else
+return PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, %in.constData(), %in.size());
+#endif
+// @snippet return-pyunicode-from-qlatin1string
+
+// @snippet qlatin1string-check
+static bool qLatin1StringCheck(PyObject *o)
+{
+ return PyUnicode_CheckExact(o) != 0
+ && _PepUnicode_KIND(o) == PepUnicode_1BYTE_KIND;
+}
+// @snippet qlatin1string-check
+
+// @snippet conversion-pystring-qlatin1string
+const char *data = reinterpret_cast<const char *>(_PepUnicode_DATA(%in));
+const Py_ssize_t len = PyUnicode_GetLength(%in);
+%out = QLatin1String(data, len);
+// @snippet conversion-pystring-qlatin1string
+
+// @snippet return-pyunicode-from-qanystringview
+return PySide::qStringToPyUnicode(%in.toString());
+// @snippet return-pyunicode-from-qanystringview
+
// @snippet return-pyunicode-qchar
auto c = wchar_t(%in.unicode());
return PyUnicode_FromWideChar(&c, 1);
@@ -1893,11 +1691,10 @@ default:
break;
}
-Shiboken::Conversions::SpecificConverter converter(cppInRef.typeName());
-if (converter) {
- void *ptr = cppInRef.data();
- return converter.toPython(ptr);
-}
+auto converterO = converterForQtType(cppInRef.typeName());
+if (converterO.has_value())
+ return converterO.value().toPython(cppInRef.data());
+
PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s'.", %in.typeName());
return 0;
// @snippet return-qvariant
@@ -1912,16 +1709,8 @@ QVariant ret = val.toVariant();
return %CONVERTTOPYTHON[QVariant](ret);
// @snippet return-qjsonobject
-// @snippet return-qpair
-PyObject *%out = PyTuple_New(2);
-PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first));
-PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second));
-return %out;
-// @snippet return-qpair
-
// @snippet qthread_pthread_cleanup
#ifdef Q_OS_UNIX
-# include <stdio.h>
# include <pthread.h>
static void qthread_pthread_cleanup(void *arg)
{
@@ -1948,13 +1737,17 @@ pthread_cleanup_pop(0);
// @snippet qthread_pthread_cleanup_uninstall
// @snippet qlibraryinfo_build
-#if defined(Py_LIMITED_API)
-auto suffix = PyUnicode_FromString(" [limited API]");
auto oldResult = pyResult;
-pyResult = PyUnicode_Concat(pyResult, suffix);
-Py_DECREF(oldResult);
-Py_DECREF(suffix);
+const auto version = _PepRuntimeVersion();
+pyResult = PyUnicode_FromFormat(
+#ifdef Py_LIMITED_API
+ "%U [Python limited API %d.%d.%d]",
+#else
+ "%U [Python %d.%d.%d]",
#endif
+ oldResult, (version >> 16) & 0xFF,
+ (version >> 8) & 0xFF, version & 0xFF);
+Py_DECREF(oldResult);
// @snippet qlibraryinfo_build
// @snippet qsharedmemory_data_readonly
@@ -1966,3 +1759,396 @@ Py_DECREF(suffix);
%PYARG_0 = Shiboken::Buffer::newObject(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.size(),
Shiboken::Buffer::ReadWrite);
// @snippet qsharedmemory_data_readwrite
+
+// @snippet std-function-void-lambda
+auto *callable = %PYARG_1;
+auto cppCallback = [callable]()
+{
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef arglist(PyTuple_New(0));
+ Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
+ Py_DECREF(callable);
+};
+// @snippet std-function-void-lambda
+
+// @snippet qthreadpool-start
+Py_INCREF(callable);
+%CPPSELF.%FUNCTION_NAME(cppCallback, %2);
+// @snippet qthreadpool-start
+
+// @snippet qthreadpool-trystart
+Py_INCREF(callable);
+%RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(cppCallback);
+%PYARG_0 = %CONVERTTOPYTHON[int](cppResult);
+// @snippet qthreadpool-trystart
+
+// @snippet repr-qevent
+QString result;
+QDebug(&result).nospace() << "<PySide6.QtCore.QEvent(" << %CPPSELF->type() << ")>";
+%PYARG_0 = Shiboken::String::fromCString(qPrintable(result));
+// @snippet repr-qevent
+
+// @snippet qmetaproperty_write_enum
+if (Shiboken::Enum::check(%PYARG_2))
+ cppArg1 = QVariant(int(Shiboken::Enum::getValue(%PYARG_2)));
+// @snippet qmetaproperty_write_enum
+
+// @snippet qdatastream-read-bytes
+QByteArray data;
+data.resize(%2);
+auto dataChar = data.data();
+cppSelf->readBytes(dataChar, %2);
+const char *constDataChar = dataChar;
+if (dataChar == nullptr) {
+ Py_INCREF(Py_None);
+ %PYARG_0 = Py_None;
+} else {
+ %PYARG_0 = PyBytes_FromStringAndSize(constDataChar, %2);
+}
+// @snippet qdatastream-read-bytes
+
+// @snippet qloggingcategory_to_cpp
+// PYSIDE-2404: Usage of the `get()` function not necessary, the type exists.
+ QLoggingCategory *category{nullptr};
+ Shiboken::Conversions::pythonToCppPointer(SbkPySide6_QtCoreTypeStructs[SBK_QLoggingCategory_IDX].type,
+ pyArgs[0], &(category));
+// @snippet qloggingcategory_to_cpp
+
+// Q_ARG()-equivalent
+// @snippet q_arg
+const QArgData qArgData = qArgDataFromPyType(%1);
+if (!qArgData)
+ return nullptr;
+
+switch (qArgData.metaType.id()) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool *>(qArgData.data) = %2 == Py_True;
+ break;
+ case QMetaType::Int:
+ *reinterpret_cast<int *>(qArgData.data) = int(PyLong_AsLong(%2));
+ break;
+ case QMetaType::Double:
+ *reinterpret_cast<double *>(qArgData.data) = PyFloat_AsDouble(%2);
+ break;
+ case QMetaType::QString:
+ *reinterpret_cast<QString *>(qArgData.data) = PySide::pyUnicodeToQString(%2);
+ break;
+ default: {
+ Shiboken::Conversions::SpecificConverter converter(qArgData.metaType.name());
+ const auto type = converter.conversionType();
+ // Copy for values, Pointer for objects
+ if (type == Shiboken::Conversions::SpecificConverter::InvalidConversion) {
+ PyErr_Format(PyExc_RuntimeError, "%s: Unable to find converter for \"%s\".",
+ __FUNCTION__, qArgData.metaType.name());
+ return nullptr;
+ }
+ converter.toCpp(%2, qArgData.data);
+ }
+}
+
+QtCoreHelper::QGenericArgumentHolder result(qArgData.metaType, qArgData.data);
+%PYARG_0 = %CONVERTTOPYTHON[QtCoreHelper::QGenericArgumentHolder](result);
+// @snippet q_arg
+
+// Q_RETURN_ARG()-equivalent
+// @snippet q_return_arg
+const QArgData qArgData = qArgDataFromPyType(%1);
+if (!qArgData)
+ return nullptr;
+
+QtCoreHelper::QGenericReturnArgumentHolder result(qArgData.metaType, qArgData.data);
+%PYARG_0 = %CONVERTTOPYTHON[QtCoreHelper::QGenericReturnArgumentHolder](result);
+// @snippet q_return_arg
+
+// @snippet qmetamethod-invoke-helpers
+static InvokeMetaMethodFunc
+ createInvokeMetaMethodFunc(const QMetaMethod &method, QObject *object,
+ Qt::ConnectionType type = Qt::AutoConnection)
+{
+ return [&method, object, type](QGenericArgument a0, QGenericArgument a1,
+ QGenericArgument a2, QGenericArgument a3,
+ QGenericArgument a4, QGenericArgument a5,
+ QGenericArgument a6, QGenericArgument a7,
+ QGenericArgument a8, QGenericArgument a9) -> bool
+ {
+ return method.invoke(object, type, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+}
+
+static InvokeMetaMethodFuncWithReturn
+ createInvokeMetaMethodFuncWithReturn(const QMetaMethod &method, QObject *object,
+ Qt::ConnectionType type = Qt::AutoConnection)
+{
+ return [&method, object, type](QGenericReturnArgument r,
+ QGenericArgument a0, QGenericArgument a1,
+ QGenericArgument a2, QGenericArgument a3,
+ QGenericArgument a4, QGenericArgument a5,
+ QGenericArgument a6, QGenericArgument a7,
+ QGenericArgument a8, QGenericArgument a9) -> bool
+ {
+ return method.invoke(object, type, r, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+}
+// @snippet qmetamethod-invoke-helpers
+
+// @snippet qmetamethod-invoke-conn-type-return-arg
+%PYARG_0 = invokeMetaMethodWithReturn(createInvokeMetaMethodFuncWithReturn(*%CPPSELF, %1, %2),
+ %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13);
+// @snippet qmetamethod-invoke-conn-type-return-arg
+
+// @snippet qmetamethod-invoke-return-arg
+%PYARG_0 = invokeMetaMethodWithReturn(createInvokeMetaMethodFuncWithReturn(*%CPPSELF, %1),
+ %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12);
+// @snippet qmetamethod-invoke-return-arg
+
+// @snippet qmetamethod-invoke-conn-type
+%PYARG_0 = invokeMetaMethod(createInvokeMetaMethodFunc(*%CPPSELF, %1, %2),
+ %3, %4, %5, %6, %7, %8, %9, %10, %11, %12);
+// @snippet qmetamethod-invoke-conn-type
+
+// @snippet qmetamethod-invoke
+%PYARG_0 = invokeMetaMethod(createInvokeMetaMethodFunc(*%CPPSELF, %1),
+ %2, %3, %4, %5, %6, %7, %8, %9, %10, %11);
+// @snippet qmetamethod-invoke
+
+// @snippet qmetaobject-invokemethod-helpers
+static InvokeMetaMethodFunc
+ createInvokeMetaMethodFunc(QObject *object, const char *methodName,
+ Qt::ConnectionType type = Qt::AutoConnection)
+{
+ return [object, methodName, type](QGenericArgument a0, QGenericArgument a1,
+ QGenericArgument a2, QGenericArgument a3,
+ QGenericArgument a4, QGenericArgument a5,
+ QGenericArgument a6, QGenericArgument a7,
+ QGenericArgument a8, QGenericArgument a9) -> bool
+ {
+ return QMetaObject::invokeMethod(object, methodName, type,
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+}
+
+static InvokeMetaMethodFuncWithReturn
+ createInvokeMetaMethodFuncWithReturn(QObject *object, const char *methodName,
+ Qt::ConnectionType type = Qt::AutoConnection)
+{
+ return [object, methodName, type](QGenericReturnArgument r,
+ QGenericArgument a0, QGenericArgument a1,
+ QGenericArgument a2, QGenericArgument a3,
+ QGenericArgument a4, QGenericArgument a5,
+ QGenericArgument a6, QGenericArgument a7,
+ QGenericArgument a8, QGenericArgument a9) -> bool
+ {
+ return QMetaObject::invokeMethod(object, methodName, type,
+ r, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ };
+}
+// @snippet qmetaobject-invokemethod-helpers
+
+// invokeMethod(QObject *,const char *, QGenericArgument a0, a1, a2 )
+// @snippet qmetaobject-invokemethod-arg
+%PYARG_0 = invokeMetaMethod(createInvokeMetaMethodFunc(%1, %2),
+ %3, %4, %5, %6, %7, %8, %9, %10, %11, %12);
+// @snippet qmetaobject-invokemethod-arg
+
+// invokeMethod(QObject *,const char *,Qt::ConnectionType, QGenericArgument a0, a1, a2 )
+// @snippet qmetaobject-invokemethod-conn-type-arg
+%PYARG_0 = invokeMetaMethod(createInvokeMetaMethodFunc(%1, %2, %3),
+ %4, %5, %6, %7, %8, %9, %10, %11, %12, %13);
+// @snippet qmetaobject-invokemethod-conn-type-arg
+
+// invokeMethod(QObject *,const char *, Qt::ConnectionType, QGenericReturnArgument,QGenericArgument a0, a1, a2 )
+// @snippet qmetaobject-invokemethod-conn-type-return-arg
+%PYARG_0 = invokeMetaMethodWithReturn(createInvokeMetaMethodFuncWithReturn(%1, %2, %3),
+ %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14);
+// @snippet qmetaobject-invokemethod-conn-type-return-arg
+
+// invokeMethod(QObject *,const char *, QGenericReturnArgument,QGenericArgument a0, a1, a2 )
+// @snippet qmetaobject-invokemethod-return-arg
+%PYARG_0 = invokeMetaMethodWithReturn(createInvokeMetaMethodFuncWithReturn(%1, %2),
+ %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13);
+// @snippet qmetaobject-invokemethod-return-arg
+
+// @snippet keycombination-from-keycombination
+cptr = new ::%TYPE(%1);
+// @snippet keycombination-from-keycombination
+
+// @snippet keycombination-from-modifier
+cptr = new ::%TYPE(%1, %2);
+// @snippet keycombination-from-modifier
+
+// @snippet qmetamethod-from-signal
+auto *signalInst = reinterpret_cast<PySideSignalInstance *>(%PYARG_1);
+const auto data = PySide::Signal::getEmitterData(signalInst);
+const auto result = data.methodIndex != -1
+ ? data.emitter->metaObject()->method(data.methodIndex)
+ : QMetaMethod{};
+%PYARG_0 = %CONVERTTOPYTHON[QMetaMethod](result);
+// @snippet qmetamethod-from-signal
+
+// @snippet qrunnable_create
+auto callable = %PYARG_1;
+auto callback = [callable]() -> void
+{
+ if (!PyCallable_Check(callable)) {
+ qWarning("Argument 1 of %FUNCTION_NAME must be a callable.");
+ return;
+ }
+ Shiboken::GilState state;
+ Shiboken::AutoDecRef ret(PyObject_CallObject(callable, nullptr));
+ Py_DECREF(callable);
+};
+Py_INCREF(callable);
+%RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(callback);
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet qrunnable_create
+
+// @snippet qlocale_system
+// For darwin systems, QLocale::system() involves looking at the Info.plist of the application
+// bundle to detect the system localization. In the case of Qt for Python, the application bundle
+// is the used Python framework. To enable retreival of localized string, the property list key
+// CFBunldeAllowMixedLocalizations should be set to True inside the Info.plist file. Otherwise,
+// CFBundleDevelopmentRegion will be used to find the language preference of the user, which in the
+// case of Python is always english.
+// This is a hack until CFBunldeAllowMixedLocalizations will be set in the Python framework
+// installation in darwin systems.
+// Upstream issue in CPython: https://github.com/python/cpython/issues/108269
+#ifdef Q_OS_DARWIN
+ Shiboken::AutoDecRef locale(PyImport_ImportModule("locale"));
+ Shiboken::AutoDecRef getLocale(PyObject_GetAttrString(locale, "getlocale"));
+ Shiboken::AutoDecRef systemLocale(PyObject_CallObject(getLocale, nullptr));
+ PyObject* localeCode = PyTuple_GetItem(systemLocale, 0);
+ %RETURN_TYPE %0;
+ if (localeCode != Py_None) {
+ QString localeCodeStr = PySide::pyStringToQString(localeCode);
+ %0 = QLocale(localeCodeStr);
+ } else {
+ // The default locale is 'C' locale as mentioned in
+ // https://docs.python.org/3/library/locale.html
+ %0 = ::QLocale::c();
+ }
+#else
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME();
+#endif
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet qlocale_system
+
+// @snippet qcoreapplication-requestpermission
+auto permission = %1;
+auto callable = %PYARG_3;
+
+// check if callable
+if (!PyCallable_Check(callable)) {
+ qWarning("Functor of %FUNCTION_NAME is not a callable");
+ return {};
+}
+
+// find the number of arguments of callable. It should either be empy or accept a QPermission
+// object
+int count = 0;
+PyObject* fc = nullptr;
+bool classMethod = false;
+Shiboken::AutoDecRef func_ob(PyObject_GetAttr(callable, Shiboken::PyMagicName::func()));
+
+if (func_ob.isNull() && PyObject_HasAttr(callable, Shiboken::PyMagicName::code())) {
+ // variable `callable` is a function
+ fc = PyObject_GetAttr(callable, Shiboken::PyMagicName::code());
+} else {
+ // variable `callable` is a class method
+ fc = PyObject_GetAttr(func_ob, Shiboken::PyMagicName::code());
+ classMethod = true;
+}
+
+if (fc) {
+ PyObject* ac = PyObject_GetAttrString(fc, "co_argcount");
+ if (ac) {
+ count = PyLong_AsLong(ac);
+ Py_DECREF(ac);
+ }
+ Py_DECREF(fc);
+}
+
+if ((classMethod && (count > 2)) || (!classMethod && (count > 1))) {
+ qWarning("Functor of %FUNCTION_NAME must either have QPermission object as argument or none."
+ "The QPermission object store the result of requestPermission()");
+ return {};
+}
+
+bool arg_qpermission = (classMethod && (count == 2)) || (!classMethod && (count == 1));
+
+auto callback = [callable, count, arg_qpermission](const QPermission &permission) -> void
+{
+ Shiboken::GilState state;
+ if (arg_qpermission) {
+ Shiboken::AutoDecRef arglist(PyTuple_New(1));
+ PyTuple_SET_ITEM(arglist.object(), 0, %CONVERTTOPYTHON[QPermission](permission));
+ Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
+ } else {
+ Shiboken::AutoDecRef ret(PyObject_CallObject(callable, nullptr));
+ }
+ Py_DECREF(callable);
+};
+Py_INCREF(callable);
+
+Py_BEGIN_ALLOW_THREADS
+%CPPSELF.%FUNCTION_NAME(permission, %2, callback);
+Py_END_ALLOW_THREADS
+// @snippet qcoreapplication-requestpermission
+
+// @snippet qlockfile-getlockinfo
+qint64 pid{};
+QString hostname, appname;
+%CPPSELF.%FUNCTION_NAME(&pid, &hostname, &appname);
+%PYARG_0 = PyTuple_New(3);
+PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[qint64](pid));
+PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[QString](hostname));
+PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[QString](appname));
+// @snippet qlockfile-getlockinfo
+
+// @snippet darwin_permission_plugin
+#ifdef Q_OS_DARWIN
+#include<QtCore/qplugin.h>
+// register the static plugin and setup its metadata
+Q_IMPORT_PLUGIN(QDarwinCameraPermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinMicrophonePermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinBluetoothPermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinContactsPermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinCalendarPermissionPlugin)
+#endif
+// @snippet darwin_permission_plugin
+
+// @snippet qt-modifier
+PyObject *_inputDict = PyDict_New();
+// Note: The builtins line is no longer needed since Python 3.10. Undocumented!
+PyDict_SetItemString(_inputDict, "__builtins__", PyEval_GetBuiltins());
+PyDict_SetItemString(_inputDict, "QtCore", module);
+PyDict_SetItemString(_inputDict, "Qt", reinterpret_cast<PyObject *>(pyType));
+// Explicitly not dereferencing the result.
+PyRun_String(R"PY(if True:
+ from enum import Flag
+ from textwrap import dedent
+ from warnings import warn
+ # QtCore and Qt come as globals.
+
+ def func_or(self, other):
+ if isinstance(self, Flag) and isinstance(other, Flag):
+ # this is normal or-ing flags together
+ return Qt.KeyboardModifier(self.value | other.value)
+ return QtCore.QKeyCombination(self, other)
+
+ def func_add(self, other):
+ warn(dedent(f"""
+ The "+" operator is deprecated in Qt For Python 6.0 .
+ Please use "|" instead."""), stacklevel=2)
+ return func_or(self, other)
+
+ Qt.KeyboardModifier.__or__ = func_or
+ Qt.KeyboardModifier.__ror__ = func_or
+ Qt.Modifier.__or__ = func_or
+ Qt.Modifier.__ror__ = func_or
+ Qt.KeyboardModifier.__add__ = func_add
+ Qt.KeyboardModifier.__radd__ = func_add
+ Qt.Modifier.__add__ = func_add
+ Qt.Modifier.__radd__ = func_add
+
+)PY", Py_file_input, _inputDict, _inputDict);
+// @snippet qt-modifier