diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ca66c53c..48f94ee9f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,7 @@ jobs: uses: actions/checkout@v6 - name: Ccache - uses: hendrikmuhs/ccache-action@v1.2.20 + uses: hendrikmuhs/ccache-action@v1.2.23 with: key: ${{ runner.os }}-ubuntu-${{ matrix.container_version }} evict-old-files: 'job' @@ -122,7 +122,7 @@ jobs: make check TESTARGS="-platform minimal" - name: Upload Wrappers - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: wrappers_ubuntu_${{ matrix.container_version }} path: generated_cpp @@ -195,7 +195,7 @@ jobs: make check TESTARGS="-platform offscreen" - name: Upload Wrappers - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: wrappers_${{ matrix.container_os }}-${{ matrix.container_os_version }}_${{ matrix.configuration }} path: generated_cpp @@ -235,7 +235,7 @@ jobs: uses: actions/checkout@v6 - name: Ccache - uses: hendrikmuhs/ccache-action@v1.2.20 + uses: hendrikmuhs/ccache-action@v1.2.23 with: key: ${{ runner.os }}-${{ matrix.qt-version }} evict-old-files: 'job' @@ -298,7 +298,7 @@ jobs: - name: Upload Wrappers if: ${{ contains(matrix.configuration, 'release') }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: wrappers_macos${{ steps.versions.outputs.MACOS_VERSION_SHORT }}_qt${{ steps.versions.outputs.QT_VERSION_SHORT }} path: generated_cpp @@ -347,7 +347,7 @@ jobs: uses: actions/checkout@v6 - name: Reset PATH - uses: egor-tensin/cleanup-path@v4 + uses: egor-tensin/cleanup-path@v5 - name: Install MSVC++ uses: ilammy/msvc-dev-cmd@v1 @@ -421,7 +421,7 @@ jobs: - name: Upload Wrappers if: (matrix.pythonqtall-config || '') == '' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: wrappers_${{ matrix.qt-arch }}_${{ steps.versions.outputs.QT_VERSION_SHORT }} path: generated_cpp diff --git a/.github/workflows/build_latest.yml b/.github/workflows/build_latest.yml index fe9729bc4..9d421f030 100644 --- a/.github/workflows/build_latest.yml +++ b/.github/workflows/build_latest.yml @@ -47,7 +47,7 @@ jobs: uses: actions/checkout@v6 - name: Ccache - uses: hendrikmuhs/ccache-action@v1.2.20 + uses: hendrikmuhs/ccache-action@v1.2.23 with: key: ${{ runner.os }}-${{ matrix.qt-version }} evict-old-files: 'job' @@ -92,7 +92,7 @@ jobs: --output-directory=. - name: Upload Wrappers - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: wrappers_${{ matrix.os }}_${{ steps.setenv.outputs.QT_VERSION_SHORT }} path: generated_cpp diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94fe31d6a..5db7b28b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: "v21.1.7" + rev: "v22.1.5" hooks: - id: clang-format diff --git a/generator/main.cpp b/generator/main.cpp index 251e41043..945d6b289 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -307,7 +307,8 @@ bool preprocess(const QString& sourceFile, const QString& targetFile, const QStr unsigned int getQtVersion(const QStringList& paths) { - QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); + QRegularExpression re(R"*(#define\s+QTCORE_VERSION_STR\s+"(\d+)\.(\d+)\.(\d+)")*", + QRegularExpression::CaseInsensitiveOption); // Iterate through provided paths to find the qtcoreversion.h header file for (const QString& path : paths) { @@ -340,14 +341,7 @@ unsigned int getQtVersion(const QStringList& paths) f.close(); auto match = re.match(content); if (match.isValid()) { - unsigned int result; - bool ok; - result = match.captured(1).toUInt(&ok, 16); - if (!ok) { - printf("Could not parse Qt version in file [%s] (looked for #define QTCORE_VERSION)\n", - qPrintable(filePath)); - } - return result; + return (match.captured(1).toUInt() << 16) + (match.captured(2).toUInt() << 8) + match.captured(3).toUInt(); } } } diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index 6678e9331..46d1b8508 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -75,6 +75,7 @@ + @@ -973,6 +974,24 @@ public: + + + + // Workaround for std::optional parameters in Qt 6.10 + bool mkpath(QDir* theWrappedObject, const QString& dirPath) const { + return theWrappedObject->mkpath(dirPath); + } + bool mkdir(QDir* theWrappedObject, const QString& dirName) const { + return theWrappedObject->mkdir(dirName); + } + bool mkpath(QDir* theWrappedObject, const QString& dirPath, QFile::Permissions permissions) const { + return theWrappedObject->mkpath(dirPath, permissions); + } + bool mkdir(QDir* theWrappedObject, const QString& dirName, QFile::Permissions permissions) const { + return theWrappedObject->mkdir(dirName, permissions); + } + @@ -2162,7 +2181,25 @@ public: - + + + + void py_set_offset(QJsonParseError* theWrappedObject, int offset){ + theWrappedObject->offset = offset; + } + int py_get_offset(QJsonParseError* theWrappedObject){ + return theWrappedObject->offset; + } + + + void py_set_offset(QJsonParseError* theWrappedObject, qint64 offset){ + theWrappedObject->offset = offset; + } + qint64 py_get_offset(QJsonParseError* theWrappedObject){ + return theWrappedObject->offset; + } + + diff --git a/generator/typesystem_gui.xml b/generator/typesystem_gui.xml index 90f7e2063..582994b46 100644 --- a/generator/typesystem_gui.xml +++ b/generator/typesystem_gui.xml @@ -974,6 +974,7 @@ + @@ -2336,6 +2337,7 @@ PyObject* constScanLine(QImage* image, int line) { + diff --git a/generator/typesystem_multimedia.xml b/generator/typesystem_multimedia.xml index b2c326978..26cb9c246 100644 --- a/generator/typesystem_multimedia.xml +++ b/generator/typesystem_multimedia.xml @@ -87,7 +87,15 @@ - + + + + float static_QAudio_convertVolume(float volume, QAudio::VolumeScale from, QAudio::VolumeScale to) + { + return (QtAudio::convertVolume(volume, from, to)); + } + + @@ -226,6 +234,7 @@ + diff --git a/generator/typesystem_xml.xml b/generator/typesystem_xml.xml index cc82bcf36..7191846b3 100644 --- a/generator/typesystem_xml.xml +++ b/generator/typesystem_xml.xml @@ -10,6 +10,7 @@ + diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 2b016ec83..c7e76ea61 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -121,7 +121,11 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList"); qRegisterMetaType>("QList"); - qRegisterMetaType("QObjectList"); + // QObjectList might already be registered by other modules (e.g. QtScript) or under different type names. + // To avoid conflicts or warnings, only register it if it is currently unknown. + if (QMetaType::type("QObjectList") == QMetaType::UnknownType) { + qRegisterMetaType("QObjectList"); + } qRegisterMetaType>("QList"); if (QT_POINTER_SIZE == 8) { qRegisterMetaType("size_t"); diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index 96da8be47..3021a04c5 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -592,24 +592,21 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { QByteArray bytes = PyObjGetBytesAllowString(obj, strict, ok); if (ok) { - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant(bytes), ptr); - ptr = (void*)((QVariant*)ptr)->constData(); + ptr = frame->establishPersistentPtr(alreadyAllocatedCPPObject, bytes); } } break; case QMetaType::QString: { QString str = PyObjGetString(obj, strict, ok); if (ok) { - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant(str), ptr); - ptr = (void*)((QVariant*)ptr)->constData(); + ptr = frame->establishPersistentPtr(alreadyAllocatedCPPObject, str); } } break; case QMetaType::QStringList: { QStringList l = PyObjToStringList(obj, strict, ok); if (ok) { - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant(l), ptr); - ptr = (void*)((QVariant*)ptr)->constData(); + ptr = frame->establishPersistentPtr(alreadyAllocatedCPPObject, l); } } break; @@ -649,7 +646,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i QString str = PyObjGetString(obj, strict, ok); if (ok) { void* ptr2 = nullptr; - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QVariant(str), ptr2); PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant::fromValue(QStringRef((const QString*)((QVariant*)ptr2)->constData())), ptr); ptr = (void*)((QVariant*)ptr)->constData(); @@ -663,12 +660,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // Handle QStringView, which needs a reference to a persistent QString QString str = PyObjGetString(obj, strict, ok); if (ok) { - void* ptr2 = nullptr; - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, - QVariant::fromValue(QStringView(*((const QString*)((QVariant*)ptr2)->constData()))), ptr); - ptr = (void*)((QVariant*)ptr)->constData(); - return ptr; + return frame->establishPersistentViewPtr(alreadyAllocatedCPPObject, str); } else { return nullptr; } @@ -676,12 +668,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // Handle QAnyStringView, which needs a reference to a persistent QString QString str = PyObjGetString(obj, strict, ok); if (ok) { - void* ptr2 = nullptr; - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(str), ptr2); - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, - QVariant::fromValue(QAnyStringView(*((const QString*)((QVariant*)ptr2)->constData()))), ptr); - ptr = (void*)((QVariant*)ptr)->constData(); - return ptr; + return frame->establishPersistentViewPtr(alreadyAllocatedCPPObject, str); } else { return nullptr; } @@ -689,12 +676,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // Handle QByteArrayView, which needs a reference to a persistent QByteArray QByteArray ba = PyObjGetBytesAllowString(obj, strict, ok); if (ok) { - void* ptr2 = nullptr; - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(nullptr, frame, QVariant(ba), ptr2); - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, - QVariant::fromValue(QByteArrayView(*((const QByteArray*)((QVariant*)ptr2)->constData()))), ptr); - ptr = (void*)((QVariant*)ptr)->constData(); - return ptr; + return frame->establishPersistentViewPtr(alreadyAllocatedCPPObject, ba); } else { return nullptr; } diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 2460876ab..f67d0a738 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -122,6 +122,7 @@ class PYTHONQT_EXPORT PythonQtConv static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data); //! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore) + //! If an alreadyAllocatedCPPObject is used it must have the same type as given by info.typeId static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame = nullptr); diff --git a/src/PythonQtMisc.h b/src/PythonQtMisc.h index 5c8a70b00..abc824163 100644 --- a/src/PythonQtMisc.h +++ b/src/PythonQtMisc.h @@ -121,6 +121,35 @@ class PythonQtArgumentFrame //! Get next pointer to a POD. quint64* nextPODPtr(); + template + void* establishPersistentPtr(void* alreadyAllocatedPtr, const Class& value) + { + if (alreadyAllocatedPtr) { + *reinterpret_cast(alreadyAllocatedPtr) = value; + return alreadyAllocatedPtr; + } else { + QVariant* item = nextVariantPtr(); + *item = QVariant(value); + return const_cast(item->constData()); + } + } + + template + void* establishPersistentViewPtr(void* alreadyAllocatedPtr, const Class& value) + { + QVariant* itemStore = nextVariantPtr(); + *itemStore = QVariant(value); + if (alreadyAllocatedPtr) { + *reinterpret_cast(alreadyAllocatedPtr) = + ViewClass(*reinterpret_cast(itemStore->constData())); + return alreadyAllocatedPtr; + } else { + QVariant* item = nextVariantPtr(); + *item = QVariant::fromValue(ViewClass(*reinterpret_cast(itemStore->constData()))); + return const_cast(item->constData()); + } + } + private: PythonQtArgumentFrame(); ~PythonQtArgumentFrame(); diff --git a/src/PythonQtStdDecorators.cpp b/src/PythonQtStdDecorators.cpp index 25ba6b300..2668949c3 100644 --- a/src/PythonQtStdDecorators.cpp +++ b/src/PythonQtStdDecorators.cpp @@ -270,17 +270,14 @@ QList PythonQtStdDecorators::findChildren(QObject* parent, PyObject* t return list; } -QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, const QMetaObject* meta, +QObject* PythonQtStdDecorators::findChild(const QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name) { const QObjectList& children = parent->children(); - int i; - for (i = 0; i < children.size(); ++i) { - QObject* obj = children.at(i); - + for (QObject* obj : children) { if (!obj) - return nullptr; + continue; // Skip if the name doesn't match. if (!name.isNull() && obj->objectName() != name) @@ -290,69 +287,55 @@ QObject* PythonQtStdDecorators::findChild(QObject* parent, const char* typeName, return obj; } - for (i = 0; i < children.size(); ++i) { - QObject* obj = findChild(children.at(i), typeName, meta, name); + for (QObject* child : children) { + if (child) { + QObject* obj = findChild(child, typeName, meta, name); - if (obj != nullptr) - return obj; + if (obj != nullptr) + return obj; + } } return nullptr; } -int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, +void PythonQtStdDecorators::findChildren(const QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList& list) { const QObjectList& children = parent->children(); - int i; - - for (i = 0; i < children.size(); ++i) { - QObject* obj = children.at(i); + for (QObject* obj : children) { if (!obj) - return -1; - - // Skip if the name doesn't match. - if (!name.isNull() && obj->objectName() != name) continue; - if ((typeName && obj->inherits(typeName)) || (meta && meta->cast(obj))) { - list += obj; + if (name.isNull() || obj->objectName() == name) { + if ((typeName && obj->inherits(typeName)) || (meta && meta->cast(obj))) { + list += obj; + } } - if (findChildren(obj, typeName, meta, name, list) < 0) - return -1; + findChildren(obj, typeName, meta, name, list); } - - return 0; } -int PythonQtStdDecorators::findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, +void PythonQtStdDecorators::findChildren(const QObject* parent, const char* typeName, const QMetaObject* meta, const QRegularExpression& regExp, QList& list) { const QObjectList& children = parent->children(); - int i; - - for (i = 0; i < children.size(); ++i) { - QObject* obj = children.at(i); + for (QObject* obj : children) { if (!obj) - return -1; - - // Skip if the name doesn't match. - QRegularExpressionMatch match = regExp.match(obj->objectName()); - if (match.hasMatch() == false) continue; - if ((typeName && obj->inherits(typeName)) || (meta && meta->cast(obj))) { - list += obj; + QRegularExpressionMatch match = regExp.match(obj->objectName()); + if (match.hasMatch()) { + if ((typeName && obj->inherits(typeName)) || (meta && meta->cast(obj))) { + list += obj; + } } - if (findChildren(obj, typeName, meta, regExp, list) < 0) - return -1; + findChildren(obj, typeName, meta, regExp, list); } - - return 0; } const QMetaObject* PythonQtStdDecorators::metaObject(QObject* obj) diff --git a/src/PythonQtStdDecorators.h b/src/PythonQtStdDecorators.h index aa5771c74..47467e3ce 100644 --- a/src/PythonQtStdDecorators.h +++ b/src/PythonQtStdDecorators.h @@ -151,11 +151,11 @@ public Q_SLOTS: void static_QTimer_singleShot(int msec, PyObject* callable); private: - QObject* findChild(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name); - int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, - QList& list); - int findChildren(QObject* parent, const char* typeName, const QMetaObject* meta, const QRegularExpression& regExp, + QObject* findChild(const QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name); + void findChildren(const QObject* parent, const char* typeName, const QMetaObject* meta, const QString& name, QList& list); + void findChildren(const QObject* parent, const char* typeName, const QMetaObject* meta, + const QRegularExpression& regExp, QList& list); }; class PythonQtSingleShotTimer : public QTimer