diff options
131 files changed, 2473 insertions, 1247 deletions
diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index 405b5e22635..601592277fe 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -437,21 +437,6 @@ elseif(WASM) "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py" @ONLY) qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py" DESTINATION "${INSTALL_LIBEXECDIR}") - - if(QT_FEATURE_shared) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/wasm/preload/preload_qml_imports.py" - "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/preload_qml_imports.py" COPYONLY) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/wasm/preload/preload_qt_plugins.py" - "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/preload_qt_plugins.py" COPYONLY) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/wasm/preload/generate_default_preloads.sh.in" - "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/generate_default_preloads.sh.in" COPYONLY) - qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/preload_qml_imports.py" - DESTINATION "${INSTALL_LIBEXECDIR}") - qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/preload_qt_plugins.py" - DESTINATION "${INSTALL_LIBEXECDIR}") - qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/generate_default_preloads.sh.in" - DESTINATION "${INSTALL_LIBEXECDIR}") - endif() endif() # Install CI support files to libexec. diff --git a/cmake/QtBuildHelpers.cmake b/cmake/QtBuildHelpers.cmake index 1fb5c6350e1..df0aa33cda2 100644 --- a/cmake/QtBuildHelpers.cmake +++ b/cmake/QtBuildHelpers.cmake @@ -487,7 +487,6 @@ macro(qt_internal_setup_build_and_global_variables) qt_set_language_standards() qt_internal_set_use_ccache() - qt_internal_set_unity_build() qt_internal_set_allow_symlink_in_paths() qt_internal_set_skip_setup_deployment() qt_internal_set_qt_allow_download() diff --git a/cmake/QtBuildOptionsHelpers.cmake b/cmake/QtBuildOptionsHelpers.cmake index ccd054183d4..ae8cf51e016 100644 --- a/cmake/QtBuildOptionsHelpers.cmake +++ b/cmake/QtBuildOptionsHelpers.cmake @@ -444,10 +444,19 @@ endmacro() macro(qt_internal_set_unity_build) option(QT_UNITY_BUILD "Enable unity (jumbo) build") set(QT_UNITY_BUILD_BATCH_SIZE "32" CACHE STRING "Unity build batch size") - if(QT_UNITY_BUILD) - set(CMAKE_UNITY_BUILD ON) - set(CMAKE_UNITY_BUILD_BATCH_SIZE "${QT_UNITY_BUILD_BATCH_SIZE}") - endif() + + include(CMakeDependentOption) + string(TOLOWER "${PROJECT_NAME}" project_name_lower) + cmake_dependent_option( + "QT_UNITY_BUILD_PROJECT_${project_name_lower}" + "Enable unity builds for project ${PROJECT_NAME}" + TRUE + QT_UNITY_BUILD + FALSE + ) + + set(CMAKE_UNITY_BUILD "${QT_UNITY_BUILD_PROJECT_${project_name_lower}}") + set(CMAKE_UNITY_BUILD_BATCH_SIZE "${QT_UNITY_BUILD_BATCH_SIZE}") endmacro() macro(qt_internal_set_allow_symlink_in_paths) diff --git a/cmake/QtBuildRepoHelpers.cmake b/cmake/QtBuildRepoHelpers.cmake index 86107179475..70a066f11b2 100644 --- a/cmake/QtBuildRepoHelpers.cmake +++ b/cmake/QtBuildRepoHelpers.cmake @@ -355,6 +355,7 @@ macro(qt_build_repo_begin) endif() _qt_internal_sbom_auto_begin_qt_repo_project() + qt_internal_set_unity_build() endmacro() # Runs delayed actions on some of the Qt targets. diff --git a/coin/instructions/prepare_building_env.yaml b/coin/instructions/prepare_building_env.yaml index 0330369662d..ac2ad89027b 100644 --- a/coin/instructions/prepare_building_env.yaml +++ b/coin/instructions/prepare_building_env.yaml @@ -679,6 +679,9 @@ instructions: - type: AppendToEnvironmentVariable variableName: COMMON_NON_QTBASE_TARGET_CMAKE_ARGS variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_TARGET_TEST_CMAKE_ARGS + variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}" enable_if: condition: runtime env_var: USE_VCPKG diff --git a/src/corelib/Qt6WasmMacros.cmake b/src/corelib/Qt6WasmMacros.cmake index e185ef67490..eae356679bd 100644 --- a/src/corelib/Qt6WasmMacros.cmake +++ b/src/corelib/Qt6WasmMacros.cmake @@ -91,15 +91,6 @@ function(_qt_internal_wasm_add_target_helpers target) ${_target_directory}/qtloader.js COPYONLY) configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtlogo.svg" ${_target_directory}/qtlogo.svg COPYONLY) - if(QT_FEATURE_shared) - set(TARGET_DIR "${_target_directory}") - set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - set(QT_HOST_DIR "${QT_HOST_PATH}") - set(QT_WASM_DIR "${WASM_BUILD_DIR}") - set(QT_INSTALL_DIR "${QT6_INSTALL_PREFIX}") - configure_file("${WASM_BUILD_DIR}/libexec/generate_default_preloads.sh.in" - "${_target_directory}/generate_default_preloads_for_${target}.sh" @ONLY) - endif() endif() endif() endif() diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index a981163a6e7..61621f54911 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -1,14 +1,21 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] -label->setAlignment(Qt::AlignLeft | Qt::AlignTop); -label->setAlignment({ }); -//! [0] - +#if __has_include(<QLabel>) +#include <QLabel> +void label_example() +{ + QLabel *label = new QLabel; + //! [0] + label->setAlignment(Qt::AlignLeft | Qt::AlignTop); + label->setAlignment({ }); + //! [0] +} +#endif +#include <QMetaProperty> //! [1] -class MyClass +class MyClass_1 { public: enum Option { @@ -18,182 +25,226 @@ public: SqueezeBlank = 0x4 }; Q_DECLARE_FLAGS(Options, Option) - ... + //... }; -Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::Options) +Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass_1::Options) //! [1] +#if 0 //! [meta-object flags] Q_FLAG(Options) //! [meta-object flags] +#endif -//! [2] -typedef QFlags<Enum> Flags; -//! [2] +struct DummyDriver { + bool isOpen() const { return true; } + bool isOpenError() const { return false; } +}; -//! [4] -if (!driver()->isOpen() || driver()->isOpenError()) { - qWarning("QSqlQuery::exec: database not open"); - return false; +DummyDriver* driver() { + static DummyDriver d; + return &d; } -//! [4] - - -//! [5] -qint64 value = Q_INT64_C(932838457459459); -//! [5] - - -//! [6] -quint64 value = Q_UINT64_C(932838457459459); -//! [6] - -//! [8] -qint64 value = Q_INT64_C(932838457459459); -//! [8] +bool examples() +{ + enum Enum {}; + //! [2] + typedef QFlags<Enum> Flags; + //! [2] -//! [9] -quint64 value = Q_UINT64_C(932838457459459); -//! [9] + //! [4] + if (!driver()->isOpen() || driver()->isOpenError()) { + qWarning("QSqlQuery::exec: database not open"); + return false; + } + //! [4] + { + //! [5] + qint64 value = Q_INT64_C(932838457459459); + //! [5] + } -//! [10] -int absoluteValue; -int myValue = -4; + { + //! [6] + quint64 value = Q_UINT64_C(932838457459459); + //! [6] + } -absoluteValue = qAbs(myValue); -// absoluteValue == 4 -//! [10] + { + //! [8] + qint64 value = Q_INT64_C(932838457459459); + //! [8] + } + { + //! [9] + quint64 value = Q_UINT64_C(932838457459459); + //! [9] + } -//! [11A] -double valueA = 2.3; -double valueB = 2.7; + { + //! [10] + int absoluteValue; + int myValue = -4; -int roundedValueA = qRound(valueA); -// roundedValueA = 2 -int roundedValueB = qRound(valueB); -// roundedValueB = 3 -//! [11A] + absoluteValue = qAbs(myValue); + // absoluteValue == 4 + //! [10] + } -//! [11B] -float valueA = 2.3; -float valueB = 2.7; + { + //! [11A] + double valueA = 2.3; + double valueB = 2.7; -int roundedValueA = qRound(valueA); -// roundedValueA = 2 -int roundedValueB = qRound(valueB); -// roundedValueB = 3 -//! [11B] + int roundedValueA = qRound(valueA); + // roundedValueA = 2 + int roundedValueB = qRound(valueB); + // roundedValueB = 3 + //! [11A] + } + { + //! [11B] + float valueA = 2.3f; + float valueB = 2.7f; -//! [12A] -double valueA = 42949672960.3; -double valueB = 42949672960.7; + int roundedValueA = qRound(valueA); + // roundedValueA = 2 + int roundedValueB = qRound(valueB); + // roundedValueB = 3 + //! [11B] + } -qint64 roundedValueA = qRound64(valueA); -// roundedValueA = 42949672960 -qint64 roundedValueB = qRound64(valueB); -// roundedValueB = 42949672961 -//! [12A] + { + //! [12A] + double valueA = 42949672960.3; + double valueB = 42949672960.7; -//! [12B] -float valueA = 42949672960.3; -float valueB = 42949672960.7; + qint64 roundedValueA = qRound64(valueA); + // roundedValueA = 42949672960 + qint64 roundedValueB = qRound64(valueB); + // roundedValueB = 42949672961 + //! [12A] + } -qint64 roundedValueA = qRound64(valueA); -// roundedValueA = 42949672960 -qint64 roundedValueB = qRound64(valueB); -// roundedValueB = 42949672961 -//! [12B] + { + //! [12B] + float valueA = 42949672960.3f; + float valueB = 42949672960.7f; + qint64 roundedValueA = qRound64(valueA); + // roundedValueA = 42949672960 + qint64 roundedValueB = qRound64(valueB); + // roundedValueB = 42949672961 + //! [12B] + } -//! [13] -int myValue = 6; -int yourValue = 4; + { + //! [13] + int myValue = 6; + int yourValue = 4; -int minValue = qMin(myValue, yourValue); -// minValue == yourValue -//! [13] + int minValue = qMin(myValue, yourValue); + // minValue == yourValue + //! [13] + } + { + //! [14] + int myValue = 6; + int yourValue = 4; -//! [14] -int myValue = 6; -int yourValue = 4; + int maxValue = qMax(myValue, yourValue); + // maxValue == myValue + //! [14] + } -int maxValue = qMax(myValue, yourValue); -// maxValue == myValue -//! [14] + { + //! [15] + int myValue = 10; + int minValue = 2; + int maxValue = 6; + int boundedValue = qBound(minValue, myValue, maxValue); + // boundedValue == 6 + //! [15] + } -//! [15] -int myValue = 10; -int minValue = 2; -int maxValue = 6; + return true; +} -int boundedValue = qBound(minValue, myValue, maxValue); -// boundedValue == 6 -//! [15] +#if __has_include(<QStyle>) +#include <QStyle> +QStyle *style() +{ + static QStyle *s = nullptr; + return s; +} -//! [16] -#if QT_VERSION >= QT_VERSION_CHECK(4, 1, 0) - QIcon icon = style()->standardIcon(QStyle::SP_TrashIcon); -#else - QPixmap pixmap = style()->standardPixmap(QStyle::SP_TrashIcon); - QIcon icon(pixmap); +void snippet_16() +{ + //! [16] + #if QT_VERSION >= QT_VERSION_CHECK(4, 1, 0) + QIcon icon = style()->standardIcon(QStyle::SP_TrashIcon); + #else + QPixmap pixmap = style()->standardPixmap(QStyle::SP_TrashIcon); + QIcon icon(pixmap); + #endif + //! [16] +} #endif -//! [16] - -//! [17] +//! [17&19_include_open] // File: div.cpp #include <QtGlobal> int divide(int a, int b) { - Q_ASSERT(b != 0); - return a / b; -} -//! [17] - +//! [17&19_include_open] -//! [18] -ASSERT: "b != 0" in file div.cpp, line 7 -//! [18] + //! [17assert] + Q_ASSERT(b != 0); + //! [17assert] + //! [19assert] + Q_ASSERT_X(b != 0, "divide", "division by zero"); + //! [19assert] -//! [19] -// File: div.cpp - -#include <QtGlobal> - -int divide(int a, int b) -{ - Q_ASSERT_X(b != 0, "divide", "division by zero"); - return a / b; + //! [17&19_return_close] + return a / b; } -//! [19] +//! [17&19_return_close] +#if 0 +//! [18] +ASSERT: "b != 0" in file div.cpp, line 7 +//! [18] //! [20] ASSERT failure in divide: "division by zero", file div.cpp, line 7 //! [20] +#endif +#include <QtAssert> -//! [21] -int *a; - -Q_CHECK_PTR(a = new int[80]); // WRONG! +void pointer_example() +{ + //! [21] + int *a; -a = new (nothrow) int[80]; // Right -Q_CHECK_PTR(a); -//! [21] + Q_CHECK_PTR(a = new int[80]); // WRONG! + a = new (std::nothrow) int[80]; // Right + Q_CHECK_PTR(a); + //! [21] +} //! [22] template<typename TInputType> @@ -208,7 +259,7 @@ const TInputType &myMin(const TInputType &value1, const TInputType &value2) } //! [22] - +# if __has_include(<QWidget>) //! [23] #include <QApplication> #include <stdio.h> @@ -224,36 +275,44 @@ void logToFile(QtMsgType type, const QMessageLogContext &context, const QString fflush(f); if (originalHandler) - *originalHandler(type, context, msg); + originalHandler(type, context, msg); } int main(int argc, char **argv) { originalHandler = qInstallMessageHandler(logToFile); QApplication app(argc, argv); - ... + // ... return app.exec(); } //! [23] +#endif +#include <QBrush> -//! [24] -qDebug("Items in list: %d", myList.size()); -//! [24] +void debug_info_example() +{ + QList<int> myList; + QBrush myQBrush(Qt::red); + int i = 0; + //! [24] + qDebug("Items in list: %d", myList.size()); + //! [24] -//! [25] -qDebug() << "Brush:" << myQBrush << "Other value:" << i; -//! [25] + //! [25] + qDebug() << "Brush:" << myQBrush << "Other value:" << i; + //! [25] -//! [qInfo_printf] -qInfo("Items in list: %d", myList.size()); -//! [qInfo_printf] + //! [qInfo_printf] + qInfo("Items in list: %d", myList.size()); + //! [qInfo_printf] -//! [qInfo_stream] -qInfo() << "Brush:" << myQBrush << "Other value:" << i; -//! [qInfo_stream] + //! [qInfo_stream] + qInfo() << "Brush:" << myQBrush << "Other value:" << i; + //! [qInfo_stream] +} //! [26] void f(int c) @@ -263,12 +322,16 @@ void f(int c) } //! [26] +void warning_example() +{ + QBrush myQBrush(Qt::red); + int i = 0; + //! [27] + qWarning() << "Brush:" << myQBrush << "Other value:" << i; + //! [27] +} -//! [27] -qWarning() << "Brush:" << myQBrush << "Other value:" << i; -//! [27] - - +#include <QFile> //! [28] void load(const QString &fileName) { @@ -278,14 +341,17 @@ void load(const QString &fileName) } //! [28] - -//! [29] -qCritical() << "Brush:" << myQBrush << "Other value:" << i; -//! [29] - +void critical_example() +{ + QBrush myQBrush(Qt::red); + int i = 0; + //! [29] + qCritical() << "Brush:" << myQBrush << "Other value:" << i; + //! [29] +} //! [30] -int divide(int a, int b) +int divide_by_zero(int a, int b) { if (b == 0) // program error qFatal("divide: cannot divide by zero"); @@ -293,91 +359,150 @@ int divide(int a, int b) } //! [30] - -//! [31] -forever { - ... +void forever_example() +{ + //! [31] + forever { + // ... + } + //! [31] } -//! [31] - +# if 0 //! [32] CONFIG += no_keywords //! [32] +#endif +namespace snippet_34 +{ + class FriendlyConversation + { + public: + QString greeting(int type); + }; -//! [33] -CONFIG += no_keywords -//! [33] + QString tr(const char *) + { + return ""; + } + //! [34] + QString FriendlyConversation::greeting(int type) + { + static const char *greeting_strings[] = { + QT_TR_NOOP("Hello"), + QT_TR_NOOP("Goodbye") + }; + return tr(greeting_strings[type]); + } + //! [34] +} -//! [34] -QString FriendlyConversation::greeting(int type) +#if __has_include(<QApplication>) +namespace snippet_35 { - static const char *greeting_strings[] = { - QT_TR_NOOP("Hello"), - QT_TR_NOOP("Goodbye") + class FriendlyConversation + { + public: + QString greeting(int type); }; - return tr(greeting_strings[type]); -} -//! [34] + QString tr(const char *) + { + return ""; + } -//! [35] -static const char *greeting_strings[] = { - QT_TRANSLATE_NOOP("FriendlyConversation", "Hello"), - QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye") -}; -QString FriendlyConversation::greeting(int type) -{ - return tr(greeting_strings[type]); + //! [35] + static const char *greeting_strings[] = { + QT_TRANSLATE_NOOP("FriendlyConversation", "Hello"), + QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye") + }; + + QString FriendlyConversation::greeting(int type) + { + return tr(greeting_strings[type]); + } + + QString global_greeting(int type) + { + return qApp->translate("FriendlyConversation", + greeting_strings[type]); + } + //! [35] } -QString global_greeting(int type) +namespace snippet_36 { - return qApp->translate("FriendlyConversation", - greeting_strings[type]); -} -//! [35] + class FriendlyConversation + { + public: + QString greeting(int type); + }; + QString tr(const char *text, const char *comment) + { + return ""; + } -//! [36] -static { const char *source; const char *comment; } greeting_strings[] = -{ - QT_TRANSLATE_NOOP3("FriendlyConversation", "Hello", - "A really friendly hello"), - QT_TRANSLATE_NOOP3("FriendlyConversation", "Goodbye", - "A really friendly goodbye") -}; + //! [36] -QString FriendlyConversation::greeting(int type) -{ - return tr(greeting_strings[type].source, - greeting_strings[type].comment); + static struct { const char *source; const char *comment; } greeting_strings[] = + { + QT_TRANSLATE_NOOP3("FriendlyConversation", "Hello", + "A really friendly hello"), + QT_TRANSLATE_NOOP3("FriendlyConversation", "Goodbye", + "A really friendly goodbye") + }; + + QString FriendlyConversation::greeting(int type) + { + return tr(greeting_strings[type].source, + greeting_strings[type].comment); + } + + QString global_greeting(int type) + { + return qApp->translate("FriendlyConversation", + greeting_strings[type].source, + greeting_strings[type].comment); + } + //! [36] } +#endif // __has_include(<QApplication>) -QString global_greeting(int type) +namespace snippet_qttrnnoop { - return qApp->translate("FriendlyConversation", - greeting_strings[type].source, - greeting_strings[type].comment); -} -//! [36] + class StatusClass + { + public: + static QString status(int type, int count); + static const char * const status_strings[]; + }; + QString tr(const char *, const char *, int) + { + return ""; + } + //! [qttrnnoop] + const char * const StatusClass::status_strings[] = { + QT_TR_N_NOOP("There are %n new message(s)"), + QT_TR_N_NOOP("There are %n total message(s)") + }; -//! [qttrnnoop] -static const char * const StatusClass::status_strings[] = { - QT_TR_N_NOOP("There are %n new message(s)"), - QT_TR_N_NOOP("There are %n total message(s)") -}; + QString StatusClass::status(int type, int count) + { + return tr(status_strings[type], nullptr, count); + } + //! [qttrnnoop] +} -QString StatusClass::status(int type, int count) +QString translate(const char *, const char *, const char *, int) { - return tr(status_strings[type], nullptr, count); + return ""; } -//! [qttrnnoop] //! [qttranslatennoop] static const char * const greeting_strings[] = { @@ -391,88 +516,125 @@ QString global_greeting(int type, int msgcnt) } //! [qttranslatennoop] -//! [qttranslatennoop3] -static { const char * const source; const char * const comment; } status_strings[] = { - QT_TRANSLATE_N_NOOP3("Message Status", "Hello, you have %n message(s)", - "A login message status"), - QT_TRANSLATE_N_NOOP3("Message status", "You have %n new message(s)", - "A new message query status") -}; - -QString FriendlyConversation::greeting(int type, int count) +#if __has_include(<QApplication>) +namespace snippet_qttranslatennoop3 { - return tr(status_strings[type].source, - status_strings[type].comment, count); -} + class FriendlyConversation + { + public: + QString greeting(int type, int count); + }; -QString global_greeting(int type, int count) -{ - return qApp->translate("Message Status", - status_strings[type].source, - status_strings[type].comment, - count); -} -//! [qttranslatennoop3] + QString tr(const char *text, const char *comment, int n) + { + return ""; + } + //! [qttranslatennoop3] + static struct { const char * const source; const char * const comment; } status_strings[] = { + QT_TRANSLATE_N_NOOP3("Message Status", "Hello, you have %n message(s)", + "A login message status"), + QT_TRANSLATE_N_NOOP3("Message status", "You have %n new message(s)", + "A new message query status") + }; -//! [qttrid] + QString FriendlyConversation::greeting(int type, int count) + { + return tr(status_strings[type].source, + status_strings[type].comment, count); + } + + QString global_greeting(int type, int count) + { + return qApp->translate("Message Status", + status_strings[type].source, + status_strings[type].comment, + count); + } + //! [qttranslatennoop3] +} +#endif // __has_include(<QApplication>) + +void qttrid_example() +{ + int n = 0; + //! [qttrid] //% "%n fooish bar(s) found.\n" //% "Do you want to continue?" QString text = qtTrId("qtn_foo_bar", n); -//! [qttrid] + //! [qttrid] +} +#if __has_include(<QWidget>) +namespace qttrid_noop +{ + class TheClass : public QWidget + { + public: + TheClass(QWidget *parent = nullptr) : QWidget(parent) { + addLabels(); + } + void addLabels(); + }; -//! [qttrid_noop] -static const char * const ids[] = { - //% "This is the first text." - QT_TRID_NOOP("qtn_1st_text"), - //% "This is the second text." - QT_TRID_NOOP("qtn_2nd_text"), - 0 -}; + //! [qttrid_noop] + static const char * const ids[] = { + //% "This is the first text." + QT_TRID_NOOP("qtn_1st_text"), + //% "This is the second text." + QT_TRID_NOOP("qtn_2nd_text"), + 0 + }; -void TheClass::addLabels() -{ - for (int i = 0; ids[i]; ++i) - new QLabel(qtTrId(ids[i]), this); + void TheClass::addLabels() + { + for (int i = 0; ids[i]; ++i) + new QLabel(qtTrId(ids[i]), this); + } + //! [qttrid_noop] } -//! [qttrid_noop] - -//! [qttrid_n_noop] -static const char * const ids[] = { - //% "%n foo(s) found." - QT_TRID_N_NOOP("qtn_foo"), - //% "%n bar(s) found." - QT_TRID_N_NOOP("qtn_bar"), - 0 -}; +#endif -QString result(int type, int n) +namespace qttrid_n_noop { - return qtTrId(ids[type], n); + //! [qttrid_n_noop] + static const char * const ids[] = { + //% "%n foo(s) found." + QT_TRID_N_NOOP("qtn_foo"), + //% "%n bar(s) found." + QT_TRID_N_NOOP("qtn_bar"), + 0 + }; + + QString result(int type, int n) + { + return qtTrId(ids[type], n); + } + //! [qttrid_n_noop] } -//! [qttrid_n_noop] -//! [38] -struct Point2D +namespace for_struct { - int x; - int y; -}; - -Q_DECLARE_TYPEINFO(Point2D, Q_PRIMITIVE_TYPE); -//! [38] + //! [38] + struct Point2D + { + int x; + int y; + }; + Q_DECLARE_TYPEINFO(Point2D, Q_PRIMITIVE_TYPE); + //! [38] +} //! [39] class Point2D { public: Point2D() { data = new int[2]; } - Point2D(const Point2D &other) { ... } + Point2D(const Point2D &other) { /*...*/ } ~Point2D() { delete[] data; } - Point2D &operator=(const Point2D &other) { ... } + Point2D &operator=(const Point2D &other) { /*...*/ } int x() const { return data[0]; } int y() const { return data[1]; } @@ -487,13 +649,13 @@ Q_DECLARE_TYPEINFO(Point2D, Q_RELOCATABLE_TYPE); //! [40] #if Q_BYTE_ORDER == Q_BIG_ENDIAN -... +//... #endif -or +//or #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -... +//... #endif //! [40] @@ -502,7 +664,7 @@ or //! [41] #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -... +//... #endif //! [41] @@ -510,7 +672,7 @@ or //! [42] #if Q_BYTE_ORDER == Q_BIG_ENDIAN -... +//... #endif //! [42] @@ -523,14 +685,17 @@ namespace QT_NAMESPACE { } //! [end namespace macro] -//! [43] -class MyClass : public QObject +namespace snippet_43 { -private: - Q_DISABLE_COPY(MyClass) -}; + //! [43] + class MyClass : public QObject + { + private: + Q_DISABLE_COPY(MyClass) + }; -//! [43] + //! [43] +} //! [44] class MyClass : public QObject @@ -541,25 +706,33 @@ private: }; //! [44] -//! [45] -QWidget w = QWidget(); -//! [45] +#if __has_include(<QWidget>) +void qwidget_example() +{ + //! [45] + QWidget w = QWidget(); + //! [45] +} +#endif -//! [46] -// Instead of comparing with 0.0 -qFuzzyCompare(0.0, 1.0e-200); // This will return false -// Compare adding 1 to both values will fix the problem -qFuzzyCompare(1 + 0.0, 1 + 1.0e-200); // This will return true -//! [46] +void qfuzzycompare_example() +{ + //! [46] + // Instead of comparing with 0.0 + qFuzzyCompare(0.0, 1.0e-200); // This will return false + // Compare adding 1 to both values will fix the problem + qFuzzyCompare(1 + 0.0, 1 + 1.0e-200); // This will return true + //! [46] +} //! [49] void myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &); //! [49] //! [50] -class B {...}; -class C {...}; -class D {...}; +class B {/*...*/}; +class C {/*...*/}; +class D {/*...*/}; struct A : public B { C c; D d; @@ -570,33 +743,45 @@ struct A : public B { template<> class QTypeInfo<A> : public QTypeInfoMerger<A, B, C, D> {}; //! [51] -//! [52] +namespace snippet_52 +{ + //! [52] struct Foo { void overloadedFunction(); void overloadedFunction(int, const QString &); }; - ... qOverload<>(&Foo::overloadedFunction) - ... qOverload<int, const QString &>(&Foo::overloadedFunction) -//! [52] + auto ptr_1 = qOverload<>(&Foo::overloadedFunction); + auto ptr_2 = qOverload<int, const QString &>(&Foo::overloadedFunction); + //! [52] +} + //! [54] struct Foo { void overloadedFunction(int, const QString &); void overloadedFunction(int, const QString &) const; }; - ... qConstOverload<int, const QString &>(&Foo::overloadedFunction) - ... qNonConstOverload<int, const QString &>(&Foo::overloadedFunction) + auto ptr_1 = qConstOverload<int, const QString &>(&Foo::overloadedFunction); + auto ptr_2 = qNonConstOverload<int, const QString &>(&Foo::overloadedFunction); //! [54] -//! [qlikely] - // the condition inside the "if" will be successful most of the times - for (int i = 1; i <= 365; i++) { - if (Q_LIKELY(isWorkingDay(i))) { - ... +bool isWorkingDay(int day) +{ + return false; +} + +void qlikely_example() +{ + //! [qlikely] + // the condition inside the "if" will be successful most of the times + for (int i = 1; i <= 365; i++) { + if (Q_LIKELY(isWorkingDay(i))) { + //... + } + //... } - ... - } -//! [qlikely] + //! [qlikely] +} //! [qunlikely] bool readConfiguration(const QFile &file) @@ -607,7 +792,7 @@ bool readConfiguration(const QFile &file) return false; } - ... + //... return true; } //! [qunlikely] @@ -621,20 +806,29 @@ bool readConfiguration(const QFile &file) }; //! [qunreachable-enum] -//! [qunreachable-switch] - switch (shape) { - case Rectangle: - return rectangle(); - case Triangle: - return triangle(); - case Circle: - return circle(); - case NumShapes: - Q_UNREACHABLE(); - break; - } -//! [qunreachable-switch] +int rectangle() { return 0; } +int triangle() { return 1; } +int circle() { return 2; } + +int qunreachable_example(Shapes shape) +{ + //! [qunreachable-switch] + switch (shape) { + case Rectangle: + return rectangle(); + case Triangle: + return triangle(); + case Circle: + return circle(); + case NumShapes: + Q_UNREACHABLE(); + break; + } + //! [qunreachable-switch] + return -1; +} +# if __has_include(<QWidget>) //! [qt-version-check] #include <QtGlobal> @@ -644,68 +838,94 @@ bool readConfiguration(const QFile &file) #include <QtGui> #endif //! [qt-version-check] +#endif + +void qgetenv_examples() +{ + const char *varName = "MY_ENV_VAR"; + bool *ok = nullptr; + + //! [is-empty] + bool is_empty = qgetenv(varName).isEmpty(); + //! [is-empty] + + //! [to-int] + int to_int = qgetenv(varName).toInt(ok, 0); + //! [to-int] -//! [is-empty] - qgetenv(varName).isEmpty() -//! [is-empty] - -//! [to-int] - qgetenv(varName).toInt(ok, 0) -//! [to-int] - -//! [int-value_or] - qEnvironmentVariableIntegerValue(varName).value_or(0) -//! [int-value_or] - -//! [int-eq0] - qEnvironmentVariableIntegerValue(varName) == 0 -//! [int-eq0] - -//! [is-null] - !qgetenv(varName).isNull() -//! [is-null] - -//! [as-const-0] - QString s = ...; - for (QChar ch : s) // detaches 's' (performs a deep-copy if 's' was shared) - process(ch); - for (QChar ch : qAsConst(s)) // ok, no detach attempt - process(ch); -//! [as-const-0] - -//! [as-const-1] - const QString s = ...; - for (QChar ch : s) // ok, no detach attempt on const objects - process(ch); -//! [as-const-1] - -//! [as-const-2] - for (QChar ch : funcReturningQString()) - process(ch); // OK, the returned object is kept alive for the loop's duration -//! [as-const-2] - -//! [as-const-3] - for (QChar ch : qAsConst(funcReturningQString())) - process(ch); // ERROR: ch is copied from deleted memory -//! [as-const-3] - -//! [as-const-4] - for (QChar ch : qAsConst(funcReturningQString())) - process(ch); // ERROR: ch is copied from deleted memory -//! [as-const-4] - -//! [qdecloverride] - // generate error if this doesn't actually override anything: - virtual void MyWidget::paintEvent(QPaintEvent*) override; -//! [qdecloverride] - -//! [qdeclfinal-1] - // more-derived classes no longer permitted to override this: - virtual void MyWidget::paintEvent(QPaintEvent*) final; -//! [qdeclfinal-1] + //! [int-value_or] + auto value = qEnvironmentVariableIntegerValue(varName).value_or(0); + //! [int-value_or] + + //! [int-eq0] + bool equals_zero = qEnvironmentVariableIntegerValue(varName) == 0; + //! [int-eq0] + + //! [is-null] + bool is_not_null = !qgetenv(varName).isNull(); + //! [is-null] +} + +QString funcReturningQString() +{ + return "Hello, World!"; +} +void process(const QChar &ch) { } + +void qchar_examples() +{ + { + //! [as-const-0] + QString s = "..."; + for (QChar ch : s) // detaches 's' (performs a deep-copy if 's' was shared) + process(ch); + for (QChar ch : qAsConst(s)) // ok, no detach attempt + process(ch); + //! [as-const-0] + } + + //! [as-const-1] + const QString s = "..."; + for (QChar ch : s) // ok, no detach attempt on const objects + process(ch); + //! [as-const-1] + + //! [as-const-2] + for (QChar ch : funcReturningQString()) + process(ch); // OK, the returned object is kept alive for the loop's duration + //! [as-const-2] + +#if MAKE_ERRORS + //! [as-const-3] + for (QChar ch : qAsConst(funcReturningQString())) + process(ch); // ERROR: ch is copied from deleted memory + //! [as-const-3] + + //! [as-const-4] + for (QChar ch : qAsConst(funcReturningQString())) + process(ch); // ERROR: ch is copied from deleted memory + //! [as-const-4] +#endif +} + +class ExampleClass +{ +protected: +#if MAKE_ERRORS + //! [qdecloverride] + // generate error if this doesn't actually override anything: + virtual void override_func() override; + //! [qdecloverride] +#endif + + //! [qdeclfinal-1] + // more-derived classes no longer permitted to override this: + virtual void final_func() final; + //! [qdeclfinal-1] +}; //! [qdeclfinal-2] - class QRect final { // cannot be derived from + class SomeClass final { // cannot be derived from // ... }; //! [qdeclfinal-2] diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qlogging.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qlogging.cpp index 4a31a2e6617..d035606629c 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qlogging.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qlogging.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - +#if MESSAGE //! [0] QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz ttt} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}" //! [0] +#endif diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qnumeric.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qnumeric.cpp index d88675d8f15..94ee3abf4fa 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qnumeric.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qnumeric.cpp @@ -1,9 +1,14 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] - if (qFloatDistance(a, b) < (1 << 7)) { // The last 7 bits are not - // significant - // precise enough - } -//! [0] +#include <QtNumeric> + +void example(float a, float b) +{ + //! [0] + if (qFloatDistance(a, b) < (1 << 7)) { // The last 7 bits are not + // significant + // precise enough + } + //! [0] +} diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qoperatingsystemversion.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qoperatingsystemversion.cpp index d86d40bc981..ab49a634527 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qoperatingsystemversion.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qoperatingsystemversion.cpp @@ -1,14 +1,19 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] - QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9) -//! [0] +#include <QOperatingSystemVersion> -//! [1] - auto current = QOperatingSystemVersion::current(); - if (current >= QOperatingSystemVersion::OSXYosemite || - current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { - // returns true on macOS >= 10.10 and iOS >= 8.0, but false on macOS < 10.10 and iOS < 8.0 - } -//! [1] +void example() +{ + //! [0] + bool ios_higher_then_9 = QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9); + //! [0] + + //! [1] + auto current = QOperatingSystemVersion::current(); + if (current >= QOperatingSystemVersion::OSXYosemite || + current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { + // returns true on macOS >= 10.10 and iOS >= 8.0, but false on macOS < 10.10 and iOS < 8.0 + } + //! [1] +} diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qrandom.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qrandom.cpp index 8be3f91120f..c3112d11768 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qrandom.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qrandom.cpp @@ -2,83 +2,117 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] - quint32 value = QRandomGenerator::global()->generate(); -//! [0] - -//! [1] - QRandomGenerator prng1(1234), prng2(1234); - Q_ASSERT(prng1.generate() == prng2.generate()); - Q_ASSERT(prng1.generate64() == prng2.generate64()); -//! [1] - -//! [2] - int x = QRandomGenerator::global()->generate(); - int y = QRandomGenerator::global()->generate(); - int w = QRandomGenerator::global()->bounded(16384); - int h = QRandomGenerator::global()->bounded(16384); -//! [2] - -//! [3] - std::uniform_real_distribution dist(1, 2.5); - return dist(*QRandomGenerator::global()); -//! [3] - -//! [4] - std::seed_seq sseq(seedBuffer, seedBuffer + len); - QRandomGenerator generator(sseq); -//! [4] - -//! [5] - std::seed_seq sseq(begin, end); - QRandomGenerator generator(sseq); -//! [5] - -//! [6] - while (z--) - generator.generate(); -//! [6] - -//! [7] - std::generate(begin, end, [this]() { return generate(); }); -//! [7] - -//! [8] - std::generate(begin, end, []() { return QRandomGenerator::global()->generate64(); }); -//! [8] - -//! [9] - QList<quint32> list; - list.resize(16); - QRandomGenerator::global()->fillRange(list.data(), list.size()); -//! [9] - -//! [10] - quint32 array[2]; - QRandomGenerator::global()->fillRange(array); -//! [10] - -//! [11] - QRandomGenerator64 rd; - return std::generate_canonical<qreal, std::numeric_limits<qreal>::digits>(rd); -//! [11] - -//! [12] - return generateDouble() * highest; -//! [12] - -//! [13] - quint32 v = QRandomGenerator::global()->bounded(256); -//! [13] - -//! [14] - quint32 v = QRandomGenerator::global()->bounded(1000, 2000); -//! [14] - -//! [15] - return QColor::fromRgb(QRandomGenerator::global()->generate()); -//! [15] - -//! [16] - qint64 value = QRandomGenerator64::global()->generate() & std::numeric_limits<qint64>::max(); -//! [16] +#include <QRandomGenerator> +#include <QList> + +double snippets_1_2_3() +{ + //! [0] + quint32 value = QRandomGenerator::global()->generate(); + //! [0] + + //! [1] + QRandomGenerator prng1(1234), prng2(1234); + Q_ASSERT(prng1.generate() == prng2.generate()); + Q_ASSERT(prng1.generate64() == prng2.generate64()); + //! [1] + + //! [2] + int x = QRandomGenerator::global()->generate(); + int y = QRandomGenerator::global()->generate(); + int w = QRandomGenerator::global()->bounded(16384); + int h = QRandomGenerator::global()->bounded(16384); + //! [2] + + //! [3] + std::uniform_real_distribution<> dist(1, 2.5); + return dist(*QRandomGenerator::global()); + //! [3] +} +class Generator : public QRandomGenerator +{ + public: + qreal snippets_4_to_11(int z, quint32 *begin, quint32 *end, const quint32 *seedBuffer, size_t len); +}; + +qreal Generator::snippets_4_to_11(int z, quint32 *begin, quint32 *end, const quint32 *seedBuffer, size_t len) +{ + { + //! [4] + std::seed_seq sseq(seedBuffer, seedBuffer + len); + QRandomGenerator generator(sseq); + //! [4] + } + + //! [5] + std::seed_seq sseq(begin, end); + QRandomGenerator generator(sseq); + //! [5] + + //! [6] + while (z--) + generator.generate(); + //! [6] + + //! [7] + std::generate(begin, end, [this]() { return generate(); }); + //! [7] + + //! [8] + std::generate(begin, end, []() { return QRandomGenerator::global()->generate64(); }); + //! [8] + + //! [9] + QList<quint32> list; + list.resize(16); + QRandomGenerator::global()->fillRange(list.data(), list.size()); + //! [9] + + //! [10] + quint32 array[2]; + QRandomGenerator::global()->fillRange(array); + //! [10] + + //! [11] + QRandomGenerator64 rd; + return std::generate_canonical<qreal, std::numeric_limits<qreal>::digits>(rd); + //! [11] +} + +double generateDouble() +{ + return 0.0; +} + +double generateDoubleWithHighest(double highest) +{ + //! [12] + return generateDouble() * highest; + //! [12] +} + +#include <QColor> + +QColor snippets_13_to_15() +{ + { + //! [13] + quint32 v = QRandomGenerator::global()->bounded(256); + //! [13] + } + + //! [14] + quint32 v = QRandomGenerator::global()->bounded(1000, 2000); + //! [14] + + //! [15] + return QColor::fromRgb(QRandomGenerator::global()->generate()); + //! [15] +} + +void snippet_16() +{ + //! [16] + qint64 value = QRandomGenerator64::global()->generate() & std::numeric_limits<qint64>::max(); + //! [16] +} diff --git a/src/corelib/doc/src/cpp20-overview.qdoc b/src/corelib/doc/src/cpp20-overview.qdoc index ed48e10f94a..1231394c161 100644 --- a/src/corelib/doc/src/cpp20-overview.qdoc +++ b/src/corelib/doc/src/cpp20-overview.qdoc @@ -12,6 +12,16 @@ This page gives a brief overview of C++20 features available in Qt. + \section1 WebEngine and Module-Specific Requirements + + While Qt 6 only requires a C++17-compatible compiler in general, + the \l{Qt WebEngine} module requires a C++20-compatible compiler + due to its dependencies (such as Chromium). + + If you are building Qt WebEngine, ensure that your compiler fully supports C++20. + + See \l{qtwebengine-platform-notes.html}{Qt WebEngine Platform Notes} for detailed requirements. + \section1 Support for \c{std::chrono} Various classes related to date and time have support for \l diff --git a/src/corelib/global/qassert.cpp b/src/corelib/global/qassert.cpp index 208619fd5cc..4da8a0cb037 100644 --- a/src/corelib/global/qassert.cpp +++ b/src/corelib/global/qassert.cpp @@ -63,7 +63,9 @@ Q_NORETURN void qAbort() Example: - \snippet code/src_corelib_global_qglobal.cpp 17 + \snippet code/src_corelib_global_qglobal.cpp 17&19_include_open + \snippet code/src_corelib_global_qglobal.cpp 17assert + \snippet code/src_corelib_global_qglobal.cpp 17&19_return_close If \c b is zero, the Q_ASSERT statement will output the following message using the qFatal() function: @@ -86,7 +88,9 @@ Q_NORETURN void qAbort() Example: - \snippet code/src_corelib_global_qglobal.cpp 19 + \snippet code/src_corelib_global_qglobal.cpp 17&19_include_open + \snippet code/src_corelib_global_qglobal.cpp 19assert + \snippet code/src_corelib_global_qglobal.cpp 17&19_return_close If \c b is zero, the Q_ASSERT_X statement will output the following message using the qFatal() function: diff --git a/src/corelib/global/qforeach.qdoc b/src/corelib/global/qforeach.qdoc index e6abf0e29c8..bec01152c04 100644 --- a/src/corelib/global/qforeach.qdoc +++ b/src/corelib/global/qforeach.qdoc @@ -50,7 +50,7 @@ If you're worried about namespace pollution, you can disable this macro by adding the following line to your \c .pro file: - \snippet code/src_corelib_global_qglobal.cpp 33 + \snippet code/src_corelib_global_qglobal.cpp 32 \note Since Qt 5.7, the use of this macro is discouraged. Use C++11 range-based \c for, possibly with \c {std::as_const()}, diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 645f27798c4..5d6b5e06be6 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -200,7 +200,7 @@ template <typename Char> static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, size_t length, bool isUnicode = true) { QChar quote(u'"'); - d->write("e, 1); + d->write(quote); bool lastWasHexEscape = false; const Char *end = begin + length; @@ -227,8 +227,7 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, si continue; } } else if (isPrintable(*p) && *p != '\\' && *p != '"') { - QChar c = QLatin1Char(*p); - d->write(&c, 1); + d->write(char16_t{uchar(*p)}); continue; } @@ -302,7 +301,7 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, si d->write(reinterpret_cast<QChar *>(buf), buflen); } - d->write("e, 1); + d->write(quote); } /*! @@ -332,9 +331,14 @@ void QDebug::putByteArray(const char *begin, size_t length, Latin1Content conten if (stream->noQuotes) { // no quotes, write the string directly too (no pretty-printing) // this respects the QTextStream state, though - QString string = content == ContainsLatin1 ? QString::fromLatin1(begin, qsizetype(length)) - : QString::fromUtf8(begin, qsizetype(length)); - stream->ts.d_ptr->putString(string); + switch (content) { + case Latin1Content::ContainsLatin1: + stream->ts.d_ptr->putString(QLatin1StringView{begin, qsizetype(length)}); + break; + case Latin1Content::ContainsBinary: + stream->ts.d_ptr->putString(QUtf8StringView{begin, qsizetype(length)}); + break; + } } else { // we'll reset the QTextStream formatting mechanisms, so save the state QDebugStateSaver saver(*this); diff --git a/src/corelib/itemmodels/qrangemodel.cpp b/src/corelib/itemmodels/qrangemodel.cpp index 51043eb0e24..8ced35a4ae0 100644 --- a/src/corelib/itemmodels/qrangemodel.cpp +++ b/src/corelib/itemmodels/qrangemodel.cpp @@ -5,8 +5,48 @@ #include "qrangemodel.h" #include <QtCore/qsize.h> +#include <QtCore/private/qabstractitemmodel_p.h> + QT_BEGIN_NAMESPACE +class QRangeModelPrivate : QAbstractItemModelPrivate +{ + Q_DECLARE_PUBLIC(QRangeModel) + + struct Deleter { void operator()(QRangeModelImplBase *that) { that->destroy(); } }; + +public: + explicit QRangeModelPrivate(std::unique_ptr<QRangeModelImplBase, Deleter> impl) + : impl(std::move(impl)) + {} + + template <typename Ret, typename ...Args> + Ret call(QRangeModelImplBase::ConstOp op, const Args &...args) const + { + Ret ret = {}; + const auto tuple = std::tie(args...); + impl->callConst_fn(op, impl.get(), &ret, &tuple); + return ret; + } + + template <typename Ret, typename ...Args> + Ret call(QRangeModelImplBase::Op op, const Args &...args) + { + Ret ret = {}; + const auto tuple = std::tie(args...); + impl->call_fn(op, impl.get(), &ret, &tuple); + return ret; + } + +private: + std::unique_ptr<QRangeModelImplBase, Deleter> impl; +}; + +QRangeModel::QRangeModel(QRangeModelImplBase *impl, QObject *parent) + : QAbstractItemModel(*new QRangeModelPrivate({impl, {}}), parent) +{ +} + /*! \class QRangeModel \inmodule QtCore @@ -503,7 +543,8 @@ QRangeModel::~QRangeModel() = default; */ QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) const { - return impl->callConst<QModelIndex>(QRangeModelImplBase::Index, row, column, parent); + Q_D(const QRangeModel); + return d->call<QModelIndex>(QRangeModelImplBase::Index, row, column, parent); } /*! @@ -520,7 +561,8 @@ QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) c */ QModelIndex QRangeModel::parent(const QModelIndex &child) const { - return impl->callConst<QModelIndex>(QRangeModelImplBase::Parent, child); + Q_D(const QRangeModel); + return d->call<QModelIndex>(QRangeModelImplBase::Parent, child); } /*! @@ -536,7 +578,8 @@ QModelIndex QRangeModel::parent(const QModelIndex &child) const */ QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) const { - return impl->callConst<QModelIndex>(QRangeModelImplBase::Sibling, row, column, index); + Q_D(const QRangeModel); + return d->call<QModelIndex>(QRangeModelImplBase::Sibling, row, column, index); } /*! @@ -554,7 +597,8 @@ QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) */ int QRangeModel::rowCount(const QModelIndex &parent) const { - return impl->callConst<int>(QRangeModelImplBase::RowCount, parent); + Q_D(const QRangeModel); + return d->call<int>(QRangeModelImplBase::RowCount, parent); } /*! @@ -572,7 +616,8 @@ int QRangeModel::rowCount(const QModelIndex &parent) const */ int QRangeModel::columnCount(const QModelIndex &parent) const { - return impl->callConst<int>(QRangeModelImplBase::ColumnCount, parent); + Q_D(const QRangeModel); + return d->call<int>(QRangeModelImplBase::ColumnCount, parent); } /*! @@ -589,7 +634,8 @@ int QRangeModel::columnCount(const QModelIndex &parent) const */ Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const { - return impl->callConst<Qt::ItemFlags>(QRangeModelImplBase::Flags, index); + Q_D(const QRangeModel); + return d->call<Qt::ItemFlags>(QRangeModelImplBase::Flags, index); } /*! @@ -606,8 +652,8 @@ Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const */ QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int role) const { - return impl->callConst<QVariant>(QRangeModelImplBase::HeaderData, - section, orientation, role); + Q_D(const QRangeModel); + return d->call<QVariant>(QRangeModelImplBase::HeaderData, section, orientation, role); } /*! @@ -629,7 +675,8 @@ QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int r */ QVariant QRangeModel::data(const QModelIndex &index, int role) const { - return impl->callConst<QVariant>(QRangeModelImplBase::Data, index, role); + Q_D(const QRangeModel); + return d->call<QVariant>(QRangeModelImplBase::Data, index, role); } /*! @@ -654,7 +701,8 @@ QVariant QRangeModel::data(const QModelIndex &index, int role) const */ bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role) { - return impl->call<bool>(QRangeModelImplBase::SetData, index, data, role); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::SetData, index, data, role); } /*! @@ -677,7 +725,8 @@ bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int ro */ QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const { - return impl->callConst<QMap<int, QVariant>>(QRangeModelImplBase::ItemData, index); + Q_D(const QRangeModel); + return d->call<QMap<int, QVariant>>(QRangeModelImplBase::ItemData, index); } /*! @@ -708,7 +757,8 @@ QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const */ bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data) { - return impl->call<bool>(QRangeModelImplBase::SetItemData, index, data); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::SetItemData, index, data); } /*! @@ -721,7 +771,8 @@ bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant */ bool QRangeModel::clearItemData(const QModelIndex &index) { - return impl->call<bool>(QRangeModelImplBase::ClearItemData, index); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::ClearItemData, index); } /* @@ -746,7 +797,8 @@ bool QRangeModel::clearItemData(const QModelIndex &index) */ bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent) { - return impl->call<bool>(QRangeModelImplBase::InsertColumns, column, count, parent); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::InsertColumns, column, count, parent); } /*! @@ -760,7 +812,8 @@ bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent */ bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent) { - return impl->call<bool>(QRangeModelImplBase::RemoveColumns, column, count, parent); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::RemoveColumns, column, count, parent); } /*! @@ -775,9 +828,10 @@ bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationColumn) { - return impl->call<bool>(QRangeModelImplBase::MoveColumns, - sourceParent, sourceColumn, count, - destinationParent, destinationColumn); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::MoveColumns, + sourceParent, sourceColumn, count, + destinationParent, destinationColumn); } /* @@ -804,7 +858,8 @@ bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, */ bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent) { - return impl->call<bool>(QRangeModelImplBase::InsertRows, row, count, parent); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::InsertRows, row, count, parent); } /*! @@ -817,7 +872,8 @@ bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent) */ bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent) { - return impl->call<bool>(QRangeModelImplBase::RemoveRows, row, count, parent); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::RemoveRows, row, count, parent); } /*! @@ -832,9 +888,10 @@ bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent) bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow) { - return impl->call<bool>(QRangeModelImplBase::MoveRows, - sourceParent, sourceRow, count, - destinationParent, destinationRow); + Q_D(QRangeModel); + return d->call<bool>(QRangeModelImplBase::MoveRows, + sourceParent, sourceRow, count, + destinationParent, destinationRow); } /*! diff --git a/src/corelib/itemmodels/qrangemodel.h b/src/corelib/itemmodels/qrangemodel.h index 328966f26fd..0d9add5def3 100644 --- a/src/corelib/itemmodels/qrangemodel.h +++ b/src/corelib/itemmodels/qrangemodel.h @@ -9,6 +9,8 @@ QT_BEGIN_NAMESPACE +class QRangeModelPrivate; + class Q_CORE_EXPORT QRangeModel : public QAbstractItemModel { Q_OBJECT @@ -103,10 +105,10 @@ protected: private: Q_DISABLE_COPY_MOVE(QRangeModel) + Q_DECLARE_PRIVATE(QRangeModel) + explicit QRangeModel(QRangeModelImplBase *impl, QObject *parent); friend class QRangeModelImplBase; - struct Deleter { void operator()(QRangeModelImplBase *that) { that->destroy(); } }; - std::unique_ptr<QRangeModelImplBase, Deleter> impl; }; // implementation of forwarders @@ -193,21 +195,21 @@ const QAbstractItemModel &QRangeModelImplBase::itemModel() const template <typename Range, QRangeModelDetails::if_table_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent) - : QAbstractItemModel(parent) - , impl(new QGenericTableItemModelImpl<Range>(std::forward<Range>(range), this)) + : QRangeModel(new QGenericTableItemModelImpl<Range>(std::forward<Range>(range), this), parent) {} template <typename Range, QRangeModelDetails::if_tree_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent) - : QRangeModel(std::forward<Range>(range), - QRangeModelDetails::DefaultTreeProtocol<Range>{}, parent) + : QRangeModel(std::forward<Range>(range), QRangeModelDetails::DefaultTreeProtocol<Range>{}, + parent) {} template <typename Range, typename Protocol, QRangeModelDetails::if_tree_range<Range, Protocol>> QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent) - : QAbstractItemModel(parent) - , impl(new QGenericTreeItemModelImpl<Range, Protocol>(std::forward<Range>(range), - std::forward<Protocol>(protocol), this)) + : QRangeModel(new QGenericTreeItemModelImpl<Range, Protocol>(std::forward<Range>(range), + std::forward<Protocol>(protocol), + this), + parent) {} QT_END_NAMESPACE diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h index 38378fdcc64..34c9ba235a6 100644 --- a/src/corelib/itemmodels/qrangemodel_impl.h +++ b/src/corelib/itemmodels/qrangemodel_impl.h @@ -604,7 +604,7 @@ public: void destroy() { - call<bool>(Destroy); + call_fn(Destroy, this, nullptr, nullptr); } private: @@ -615,6 +615,7 @@ private: using CallConstFN = decltype(callConst); using CallTupleFN = decltype(call); + friend class QRangeModelPrivate; CallConstFN *callConst_fn; CallTupleFN *call_fn; QRangeModel *m_rangeModel; @@ -647,25 +648,6 @@ protected: inline void endMoveRows(); inline QAbstractItemModel &itemModel(); inline const QAbstractItemModel &itemModel() const; - -public: - template <typename Ret, typename ...Args> - Ret callConst(ConstOp op, const Args &...args) const - { - Ret ret = {}; - const auto tuple = std::tie(args...); - callConst_fn(op, this, &ret, &tuple); - return ret; - } - - template <typename Ret, typename ...Args> - Ret call(Op op, const Args &...args) - { - Ret ret = {}; - const auto tuple = std::tie(args...); - call_fn(op, this, &ret, &tuple); - return ret; - } }; template <typename Structure, typename Range, @@ -1357,7 +1339,7 @@ public: bool removeRows(int row, int count, const QModelIndex &parent = {}) { - if constexpr (Structure::canRemoveRows()) { + if constexpr (canRemoveRows()) { const int prevRowCount = that().rowCount(parent); if (row < 0 || row + count > prevRowCount) return false; @@ -1476,10 +1458,15 @@ protected: // row elements. return false; } else { - return Structure::canInsertRows(); + return Structure::canInsertRowsImpl(); } } + static constexpr bool canRemoveRows() + { + return Structure::canRemoveRowsImpl(); + } + template <typename F> bool writeAt(const QModelIndex &index, F&& writer) { @@ -1805,7 +1792,7 @@ protected: return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } - static constexpr bool canInsertRows() + static constexpr bool canInsertRowsImpl() { // We must not insert rows if we cannot adjust the parents of the // children of the following rows. We don't have to do that if the @@ -1814,7 +1801,7 @@ protected: && Base::dynamicRows() && range_features::has_insert; } - static constexpr bool canRemoveRows() + static constexpr bool canRemoveRowsImpl() { // We must not remove rows if we cannot adjust the parents of the // children of the following rows. We don't have to do that if the @@ -2090,12 +2077,12 @@ protected: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren; } - static constexpr bool canInsertRows() + static constexpr bool canInsertRowsImpl() { return Base::dynamicRows() && range_features::has_insert; } - static constexpr bool canRemoveRows() + static constexpr bool canRemoveRowsImpl() { return Base::dynamicRows() && range_features::has_erase; } diff --git a/src/corelib/kernel/qsystemerror.cpp b/src/corelib/kernel/qsystemerror.cpp index 428ce62984f..62741150144 100644 --- a/src/corelib/kernel/qsystemerror.cpp +++ b/src/corelib/kernel/qsystemerror.cpp @@ -137,9 +137,9 @@ QString QSystemError::windowsString(int errorCode) QString QSystemError::windowsComString(HRESULT hr) { const _com_error comError(hr); - QString result = "COM error 0x"_L1 + QString::number(ulong(hr), 16); + QString result = u"COM error 0x"_s + QString::number(ulong(hr), 16); if (const wchar_t *msg = comError.ErrorMessage()) - result += ": "_L1 + QString::fromWCharArray(msg); + result += u": "_s + QString::fromWCharArray(msg); return result; } diff --git a/src/corelib/platform/windows/qcomobject_p.h b/src/corelib/platform/windows/qcomobject_p.h index bbf7796445d..bd6f81d1c28 100644 --- a/src/corelib/platform/windows/qcomobject_p.h +++ b/src/corelib/platform/windows/qcomobject_p.h @@ -80,18 +80,21 @@ public: return tryQueryInterface<TFirstInterface, TAdditionalInterfaces...>(riid, ppvObject); } - // clang-format off STDMETHODIMP_(ULONG) AddRef() override { - return ++m_referenceCount; + return m_referenceCount.fetch_add(1, std::memory_order_relaxed) + 1; } - // clang-format on STDMETHODIMP_(ULONG) Release() override { - const LONG referenceCount = --m_referenceCount; - if (referenceCount == 0) + const LONG referenceCount = m_referenceCount.fetch_sub(1, std::memory_order_release) - 1; + if (referenceCount == 0) { + // This acquire fence synchronizes with the release operation in other threads. + // It ensures that all memory writes made to this object by other threads + // are visible to this thread before we proceed to delete it. + std::atomic_thread_fence(std::memory_order_acquire); delete this; + } return referenceCount; } @@ -103,6 +106,9 @@ protected: // Derived class should make its destructor private to force this behavior. virtual ~QComObject() = default; + // allow derived classes to access the reference count + std::atomic<LONG> m_referenceCount = 1; + private: template <typename TInterface, typename... TRest> HRESULT tryQueryInterface(REFIID riid, void **ppvObject) @@ -121,8 +127,6 @@ private: return E_NOINTERFACE; } - - std::atomic<LONG> m_referenceCount = 1; }; QT_END_NAMESPACE diff --git a/src/corelib/serialization/qtextstream.cpp b/src/corelib/serialization/qtextstream.cpp index 5e0eff698f9..c357d40c8f5 100644 --- a/src/corelib/serialization/qtextstream.cpp +++ b/src/corelib/serialization/qtextstream.cpp @@ -711,7 +711,7 @@ void QTextStreamPrivate::write(const QChar *data, qsizetype len) /*! \internal */ -inline void QTextStreamPrivate::write(QChar ch) +void QTextStreamPrivate::write(QChar ch) { if (string) { // ### What about seek()?? @@ -833,29 +833,29 @@ QTextStreamPrivate::PaddingResult QTextStreamPrivate::padding(qsizetype len) con /*! \internal */ -void QTextStreamPrivate::putString(const QChar *data, qsizetype len, bool number) +template <typename StringView> +void QTextStreamPrivate::putStringImpl(StringView data, bool number) { - if (Q_UNLIKELY(params.fieldWidth > len)) { + if (Q_UNLIKELY(params.fieldWidth > data.size())) { // handle padding: - const PaddingResult pad = padding(len); + const PaddingResult pad = padding(data.size()); if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) { - const QChar sign = len > 0 ? data[0] : QChar(); + const QChar sign = data.size() > 0 ? data.front() : QChar(); if (sign == locale.negativeSign() || sign == locale.positiveSign()) { // write the sign before the padding, then skip it later - write(&sign, 1); - ++data; - --len; + write(sign); + data = data.sliced(1); } } writePadding(pad.left); - write(data, len); + write(data); writePadding(pad.right); } else { - write(data, len); + write(data); } } @@ -864,29 +864,20 @@ void QTextStreamPrivate::putString(const QChar *data, qsizetype len, bool number */ void QTextStreamPrivate::putString(QLatin1StringView data, bool number) { - if (Q_UNLIKELY(params.fieldWidth > data.size())) { - - // handle padding - - const PaddingResult pad = padding(data.size()); - - if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) { - const QChar sign = data.size() > 0 ? QLatin1Char(*data.data()) : QChar(); - if (sign == locale.negativeSign() || sign == locale.positiveSign()) { - // write the sign before the padding, then skip it later - write(&sign, 1); - data = QLatin1StringView(data.data() + 1, data.size() - 1); - } - } + putStringImpl(data, number); +} - writePadding(pad.left); - write(data); - writePadding(pad.right); - } else { - write(data); - } +/*! + \internal +*/ +void QTextStreamPrivate::putString(QStringView data, bool number) +{ + putStringImpl(data, number); } +/*! + \internal +*/ void QTextStreamPrivate::putString(QUtf8StringView data, bool number) { putString(data.toString(), number); diff --git a/src/corelib/serialization/qtextstream_p.h b/src/corelib/serialization/qtextstream_p.h index 7227c29c8fe..2da7fe8e9d5 100644 --- a/src/corelib/serialization/qtextstream_p.h +++ b/src/corelib/serialization/qtextstream_p.h @@ -145,15 +145,13 @@ public: bool getReal(double *f); inline void write(QStringView data) { write(data.begin(), data.size()); } - inline void write(QChar ch); + void write(QChar ch); void write(const QChar *data, qsizetype len); void write(QLatin1StringView data); void writePadding(qsizetype len); - inline void putString(QStringView string, bool number = false) - { - putString(string.constData(), string.size(), number); - } - void putString(const QChar *data, qsizetype len, bool number = false); + void putString(QStringView string, bool number = false); + void putString(const QChar *data, qsizetype len, bool number = false) + { putString(QStringView{data, len}, number); } void putString(QLatin1StringView data, bool number = false); void putString(QUtf8StringView data, bool number = false); inline void putChar(QChar ch); @@ -168,6 +166,10 @@ public: bool fillReadBuffer(qint64 maxBytes = -1); void resetReadBuffer(); void flushWriteBuffer(); + +private: + template <typename StringView> + void putStringImpl(StringView view, bool number); }; QT_END_NAMESPACE diff --git a/src/corelib/tools/qduplicatetracker_p.h b/src/corelib/tools/qduplicatetracker_p.h index 4740047356b..f2bcaf7065d 100644 --- a/src/corelib/tools/qduplicatetracker_p.h +++ b/src/corelib/tools/qduplicatetracker_p.h @@ -136,6 +136,12 @@ public: set.clear(); #endif // __cpp_lib_memory_resource } + + using const_iterator = typename Set::const_iterator; + const_iterator begin() const { return set.cbegin(); } + const_iterator end() const { return set.cend(); } + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } }; QT_END_NAMESPACE diff --git a/src/dbus/dbus_minimal_p.h b/src/dbus/dbus_minimal_p.h index 36e7fab55d9..a87c07defcb 100644 --- a/src/dbus/dbus_minimal_p.h +++ b/src/dbus/dbus_minimal_p.h @@ -2,6 +2,7 @@ // Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later +// Qt-Security score:significant reason:default #ifndef DBUS_MINIMAL_P_H #define DBUS_MINIMAL_P_H diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index 78b7e049ef3..a3e3b202c12 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbusabstractadaptor.cpp b/src/dbus/qdbusabstractadaptor.cpp index df83cc6f462..b9c87797846 100644 --- a/src/dbus/qdbusabstractadaptor.cpp +++ b/src/dbus/qdbusabstractadaptor.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusabstractadaptor.h" #include "qdbusabstractadaptor_p.h" diff --git a/src/dbus/qdbusabstractadaptor.h b/src/dbus/qdbusabstractadaptor.h index f143056b43a..649dc4622d0 100644 --- a/src/dbus/qdbusabstractadaptor.h +++ b/src/dbus/qdbusabstractadaptor.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSABSTRACTADAPTOR_H #define QDBUSABSTRACTADAPTOR_H diff --git a/src/dbus/qdbusabstractadaptor_p.h b/src/dbus/qdbusabstractadaptor_p.h index c047af18211..51dc727b2fb 100644 --- a/src/dbus/qdbusabstractadaptor_p.h +++ b/src/dbus/qdbusabstractadaptor_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index 0c6dbf1b3b7..4e46fc8f743 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusabstractinterface.h" #include "qdbusabstractinterface_p.h" diff --git a/src/dbus/qdbusabstractinterface.h b/src/dbus/qdbusabstractinterface.h index 8d36fb37281..2bdbdc419db 100644 --- a/src/dbus/qdbusabstractinterface.h +++ b/src/dbus/qdbusabstractinterface.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSABSTRACTINTERFACE_H #define QDBUSABSTRACTINTERFACE_H diff --git a/src/dbus/qdbusabstractinterface_p.h b/src/dbus/qdbusabstractinterface_p.h index 1bd5e96f2d4..aca8ed23253 100644 --- a/src/dbus/qdbusabstractinterface_p.h +++ b/src/dbus/qdbusabstractinterface_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h index 8370de74bb6..b79f675a9e4 100644 --- a/src/dbus/qdbusargument.h +++ b/src/dbus/qdbusargument.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSARGUMENT_H #define QDBUSARGUMENT_H @@ -15,6 +16,8 @@ #include <QtCore/qvariant.h> #include <QtDBus/qdbusextratypes.h> +#include <tuple> + #ifndef QT_NO_DBUS QT_BEGIN_NAMESPACE @@ -117,6 +120,27 @@ protected: QDBusArgument(QDBusArgumentPrivate *d); friend class QDBusArgumentPrivate; mutable QDBusArgumentPrivate *d; + +private: + template <typename... T> + friend QDBusArgument &operator<<(QDBusArgument &argument, const std::tuple<T...> &tuple) + { + static_assert(sizeof...(T) != 0, "D-Bus doesn't allow empty structs"); + argument.beginStructure(); + std::apply([&argument](const auto &...elements) { (argument << ... << elements); }, tuple); + argument.endStructure(); + return argument; + } + + template <typename... T> + friend const QDBusArgument &operator>>(const QDBusArgument &argument, std::tuple<T...> &tuple) + { + static_assert(sizeof...(T) != 0, "D-Bus doesn't allow empty structs"); + argument.beginStructure(); + std::apply([&argument](auto &...elements) { (argument >> ... >> elements); }, tuple); + argument.endStructure(); + return argument; + } }; Q_DECLARE_SHARED(QDBusArgument) @@ -321,26 +345,6 @@ inline const QDBusArgument &operator>>(const QDBusArgument &arg, std::pair<T1, T return arg; } -template <typename... T> -QDBusArgument &operator<<(QDBusArgument &argument, const std::tuple<T...> &tuple) -{ - static_assert(std::tuple_size_v<std::tuple<T...>> != 0, "D-Bus doesn't allow empty structs"); - argument.beginStructure(); - std::apply([&argument](const auto &...elements) { (argument << ... << elements); }, tuple); - argument.endStructure(); - return argument; -} - -template <typename... T> -const QDBusArgument &operator>>(const QDBusArgument &argument, std::tuple<T...> &tuple) -{ - static_assert(std::tuple_size_v<std::tuple<T...>> != 0, "D-Bus doesn't allow empty structs"); - argument.beginStructure(); - std::apply([&argument](auto &...elements) { (argument >> ... >> elements); }, tuple); - argument.endStructure(); - return argument; -} - QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index d9a73827424..3d007ea2c7c 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSARGUMENT_P_H #define QDBUSARGUMENT_P_H diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 08cec30afa3..aa2ba432fa5 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusconnection.h" #include "qdbusconnection_p.h" diff --git a/src/dbus/qdbusconnection.h b/src/dbus/qdbusconnection.h index be8acdc4ea5..45d3850faed 100644 --- a/src/dbus/qdbusconnection.h +++ b/src/dbus/qdbusconnection.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSCONNECTION_H #define QDBUSCONNECTION_H diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 5cb175c1cdc..b553cd62a03 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbusconnectioninterface.cpp b/src/dbus/qdbusconnectioninterface.cpp index f7dbbb01563..36636b355b0 100644 --- a/src/dbus/qdbusconnectioninterface.cpp +++ b/src/dbus/qdbusconnectioninterface.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusconnectioninterface.h" diff --git a/src/dbus/qdbusconnectioninterface.h b/src/dbus/qdbusconnectioninterface.h index e728539a385..60742ea4043 100644 --- a/src/dbus/qdbusconnectioninterface.h +++ b/src/dbus/qdbusconnectioninterface.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSCONNECTIONINTERFACE_H #define QDBUSCONNECTIONINTERFACE_H diff --git a/src/dbus/qdbusconnectionmanager.cpp b/src/dbus/qdbusconnectionmanager.cpp index 73f11d82280..ef96231e1cc 100644 --- a/src/dbus/qdbusconnectionmanager.cpp +++ b/src/dbus/qdbusconnectionmanager.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusconnectionmanager_p.h" @@ -32,8 +33,8 @@ QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::B return nullptr; // we'll start in suspended delivery mode if we're in the main thread - // (the event loop will resume delivery) - bool suspendedDelivery = QThread::isMainThread(); + // (the event loop will resume delivery) and QCoreApplication already exists + bool suspendedDelivery = QThread::isMainThread() && qApp; const auto locker = qt_scoped_lock(defaultBusMutex); if (defaultBuses[type]) diff --git a/src/dbus/qdbusconnectionmanager_p.h b/src/dbus/qdbusconnectionmanager_p.h index 644c3c8fb1c..1ef048e5d72 100644 --- a/src/dbus/qdbusconnectionmanager_p.h +++ b/src/dbus/qdbusconnectionmanager_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbuscontext.cpp b/src/dbus/qdbuscontext.cpp index b8cb1dc8b10..f788b398186 100644 --- a/src/dbus/qdbuscontext.cpp +++ b/src/dbus/qdbuscontext.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusmessage.h" #include "qdbusconnection.h" diff --git a/src/dbus/qdbuscontext.h b/src/dbus/qdbuscontext.h index 02620449e18..47ced171171 100644 --- a/src/dbus/qdbuscontext.h +++ b/src/dbus/qdbuscontext.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSCONTEXT_H #define QDBUSCONTEXT_H diff --git a/src/dbus/qdbuscontext_p.h b/src/dbus/qdbuscontext_p.h index 1a544b8e44e..edd7aa068f0 100644 --- a/src/dbus/qdbuscontext_p.h +++ b/src/dbus/qdbuscontext_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp index 0a5ba30d3a3..c168d8d471c 100644 --- a/src/dbus/qdbuserror.cpp +++ b/src/dbus/qdbuserror.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbuserror.h" diff --git a/src/dbus/qdbuserror.h b/src/dbus/qdbuserror.h index 292f967acbe..dcb0c6666a0 100644 --- a/src/dbus/qdbuserror.h +++ b/src/dbus/qdbuserror.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSERROR_H #define QDBUSERROR_H diff --git a/src/dbus/qdbusextratypes.cpp b/src/dbus/qdbusextratypes.cpp index 042014ceab0..c27c1cbd5db 100644 --- a/src/dbus/qdbusextratypes.cpp +++ b/src/dbus/qdbusextratypes.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusextratypes.h" #include "qdbusutil_p.h" diff --git a/src/dbus/qdbusextratypes.h b/src/dbus/qdbusextratypes.h index 3b44bfc2175..3bfd38486a2 100644 --- a/src/dbus/qdbusextratypes.h +++ b/src/dbus/qdbusextratypes.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSEXTRATYPES_H #define QDBUSEXTRATYPES_H diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 4c9736dea6d..bfd3a092d39 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusintegrator_p.h" diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h index ac9adf02100..f6486d87256 100644 --- a/src/dbus/qdbusintegrator_p.h +++ b/src/dbus/qdbusintegrator_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbusinterface.cpp b/src/dbus/qdbusinterface.cpp index d4da36b35c4..7481229dccf 100644 --- a/src/dbus/qdbusinterface.cpp +++ b/src/dbus/qdbusinterface.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusinterface.h" #include "qdbusinterface_p.h" diff --git a/src/dbus/qdbusinterface.h b/src/dbus/qdbusinterface.h index fc02463ac72..bff0336fd82 100644 --- a/src/dbus/qdbusinterface.h +++ b/src/dbus/qdbusinterface.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSINTERFACE_H #define QDBUSINTERFACE_H diff --git a/src/dbus/qdbusinterface_p.h b/src/dbus/qdbusinterface_p.h index caf24e589d4..63b7196527f 100644 --- a/src/dbus/qdbusinterface_p.h +++ b/src/dbus/qdbusinterface_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp index 721564ed3cd..a46bc8e6c87 100644 --- a/src/dbus/qdbusinternalfilters.cpp +++ b/src/dbus/qdbusinternalfilters.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusconnection_p.h" diff --git a/src/dbus/qdbusintrospection.cpp b/src/dbus/qdbusintrospection.cpp index 04b5ab77519..4f6c40743a5 100644 --- a/src/dbus/qdbusintrospection.cpp +++ b/src/dbus/qdbusintrospection.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusintrospection_p.h" #include "qdbusxmlparser_p.h" diff --git a/src/dbus/qdbusintrospection_p.h b/src/dbus/qdbusintrospection_p.h index 766cdffb621..3eccef8b7b0 100644 --- a/src/dbus/qdbusintrospection_p.h +++ b/src/dbus/qdbusintrospection_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSINTROSPECTION_P_H #define QDBUSINTROSPECTION_P_H diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index b10266ac8b7..f0a056e3127 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusmessage.h" #include "qdbusmessage_p.h" diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h index 608b9779d22..5b631c2b847 100644 --- a/src/dbus/qdbusmessage.h +++ b/src/dbus/qdbusmessage.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSMESSAGE_H #define QDBUSMESSAGE_H diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h index 88ba78025e7..07cdeda4034 100644 --- a/src/dbus/qdbusmessage_p.h +++ b/src/dbus/qdbusmessage_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSMESSAGE_P_H #define QDBUSMESSAGE_P_H diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index c3590dc51cd..149392f9c3c 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusmetaobject_p.h" diff --git a/src/dbus/qdbusmetaobject_p.h b/src/dbus/qdbusmetaobject_p.h index 97d16d99d0e..473765a175c 100644 --- a/src/dbus/qdbusmetaobject_p.h +++ b/src/dbus/qdbusmetaobject_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSMETAOBJECT_P_H #define QDBUSMETAOBJECT_P_H diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index 3ae7589480e..5a862528026 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qdbusmetatype.h" #include "qdbusmetatype_p.h" diff --git a/src/dbus/qdbusmetatype.h b/src/dbus/qdbusmetatype.h index 3304a69e1ef..66b6b1b0456 100644 --- a/src/dbus/qdbusmetatype.h +++ b/src/dbus/qdbusmetatype.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSMETATYPE_H #define QDBUSMETATYPE_H diff --git a/src/dbus/qdbusmetatype_p.h b/src/dbus/qdbusmetatype_p.h index 86a59f587dd..b72c0c431e5 100644 --- a/src/dbus/qdbusmetatype_p.h +++ b/src/dbus/qdbusmetatype_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSMETATYPE_P_H #define QDBUSMETATYPE_P_H diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp index 635258c86d2..bf18b00d1cc 100644 --- a/src/dbus/qdbusmisc.cpp +++ b/src/dbus/qdbusmisc.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include <string.h> diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index cd222c9ffa5..c0b382ca114 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbuspendingcall.h" #include "qdbuspendingcall_p.h" @@ -228,7 +229,7 @@ void QDBusPendingCallPrivate::waitForFinishedWithGui() /*! \fn QDBusPendingCall::QDBusPendingCall(QDBusPendingCall &&other) - \since 6.11 + \since 6.10 Moves \a other into this object. diff --git a/src/dbus/qdbuspendingcall.h b/src/dbus/qdbuspendingcall.h index 0db6667e5ec..1907fab78b9 100644 --- a/src/dbus/qdbuspendingcall.h +++ b/src/dbus/qdbuspendingcall.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSPENDINGCALL_H #define QDBUSPENDINGCALL_H diff --git a/src/dbus/qdbuspendingcall_p.h b/src/dbus/qdbuspendingcall_p.h index 2795cc3ecf8..407537c9bb0 100644 --- a/src/dbus/qdbuspendingcall_p.h +++ b/src/dbus/qdbuspendingcall_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default // // W A R N I N G diff --git a/src/dbus/qdbuspendingreply.cpp b/src/dbus/qdbuspendingreply.cpp index 7bb23aa3e36..b0fb2d75af5 100644 --- a/src/dbus/qdbuspendingreply.cpp +++ b/src/dbus/qdbuspendingreply.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbuspendingreply.h" #include "qdbuspendingcall_p.h" diff --git a/src/dbus/qdbuspendingreply.h b/src/dbus/qdbuspendingreply.h index 72e1bbdc313..7b76bcd1b7c 100644 --- a/src/dbus/qdbuspendingreply.h +++ b/src/dbus/qdbuspendingreply.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSPENDINGREPLY_H #define QDBUSPENDINGREPLY_H diff --git a/src/dbus/qdbusreply.cpp b/src/dbus/qdbusreply.cpp index 5b26250b10d..a90e7354ed2 100644 --- a/src/dbus/qdbusreply.cpp +++ b/src/dbus/qdbusreply.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusreply.h" #include "qdbusmetatype.h" diff --git a/src/dbus/qdbusreply.h b/src/dbus/qdbusreply.h index df488208c85..5dfb63f3b4b 100644 --- a/src/dbus/qdbusreply.h +++ b/src/dbus/qdbusreply.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSREPLY_H #define QDBUSREPLY_H diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index e9131a14c4b..9e1063424a5 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusserver.h" #include "qdbusconnection_p.h" diff --git a/src/dbus/qdbusserver.h b/src/dbus/qdbusserver.h index 34985cc0554..04b7930d412 100644 --- a/src/dbus/qdbusserver.h +++ b/src/dbus/qdbusserver.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSSERVER_H #define QDBUSSERVER_H diff --git a/src/dbus/qdbusservicewatcher.cpp b/src/dbus/qdbusservicewatcher.cpp index bf94f54f564..6b9675c19ec 100644 --- a/src/dbus/qdbusservicewatcher.cpp +++ b/src/dbus/qdbusservicewatcher.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusservicewatcher.h" #include "qdbusconnection.h" diff --git a/src/dbus/qdbusservicewatcher.h b/src/dbus/qdbusservicewatcher.h index 71c63084b18..d07ae0fe5d2 100644 --- a/src/dbus/qdbusservicewatcher.h +++ b/src/dbus/qdbusservicewatcher.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSSERVICEWATCHER_H #define QDBUSSERVICEWATCHER_H diff --git a/src/dbus/qdbusthreaddebug_p.h b/src/dbus/qdbusthreaddebug_p.h index bcbd1efb494..70fbf762d19 100644 --- a/src/dbus/qdbusthreaddebug_p.h +++ b/src/dbus/qdbusthreaddebug_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSTHREADDEBUG_P_H #define QDBUSTHREADDEBUG_P_H diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp index 365f6cbc76c..bc38d142b95 100644 --- a/src/dbus/qdbusunixfiledescriptor.cpp +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusunixfiledescriptor.h" diff --git a/src/dbus/qdbusunixfiledescriptor.h b/src/dbus/qdbusunixfiledescriptor.h index cbcd8b53a95..c946ec1761b 100644 --- a/src/dbus/qdbusunixfiledescriptor.h +++ b/src/dbus/qdbusunixfiledescriptor.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSUNIXFILEDESCRIPTOR_H diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index 84ce5ed78dc..9c1c7e8edf3 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qdbusutil_p.h" diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h index 3db93849682..580a2b92c96 100644 --- a/src/dbus/qdbusutil_p.h +++ b/src/dbus/qdbusutil_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser // // W A R N I N G diff --git a/src/dbus/qdbusvirtualobject.cpp b/src/dbus/qdbusvirtualobject.cpp index 2e5df125d25..878152ad32d 100644 --- a/src/dbus/qdbusvirtualobject.cpp +++ b/src/dbus/qdbusvirtualobject.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdbusvirtualobject.h" diff --git a/src/dbus/qdbusvirtualobject.h b/src/dbus/qdbusvirtualobject.h index 573d731d201..451b0040069 100644 --- a/src/dbus/qdbusvirtualobject.h +++ b/src/dbus/qdbusvirtualobject.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSVIRTUALOBJECT_H #define QDBUSVIRTUALOBJECT_H diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp index 412ac180951..69d27a49f9f 100644 --- a/src/dbus/qdbusxmlgenerator.cpp +++ b/src/dbus/qdbusxmlgenerator.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include <QtCore/qmetaobject.h> #include <QtCore/qstringlist.h> diff --git a/src/dbus/qdbusxmlparser.cpp b/src/dbus/qdbusxmlparser.cpp index c2e8df8be7e..b3e1b6b78b6 100644 --- a/src/dbus/qdbusxmlparser.cpp +++ b/src/dbus/qdbusxmlparser.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qdbusxmlparser_p.h" #include "qdbusutil_p.h" diff --git a/src/dbus/qdbusxmlparser_p.h b/src/dbus/qdbusxmlparser_p.h index 0476ba36281..6cee2da76cc 100644 --- a/src/dbus/qdbusxmlparser_p.h +++ b/src/dbus/qdbusxmlparser_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDBUSXMLPARSER_P_H #define QDBUSXMLPARSER_P_H diff --git a/src/dbus/qtdbusglobal.h b/src/dbus/qtdbusglobal.h index 9724c066f6a..07cfa16a258 100644 --- a/src/dbus/qtdbusglobal.h +++ b/src/dbus/qtdbusglobal.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTDBUSGLOBAL_H #define QTDBUSGLOBAL_H diff --git a/src/dbus/qtdbusglobal_p.h b/src/dbus/qtdbusglobal_p.h index 9d315de75c8..6e748c20ae3 100644 --- a/src/dbus/qtdbusglobal_p.h +++ b/src/dbus/qtdbusglobal_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTDBUSGLOBAL_P_H #define QTDBUSGLOBAL_P_H diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 59c469ae6b6..b53e1a63870 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -552,7 +552,7 @@ void QSurfaceFormat::setAlphaBufferSize(int size) and used choice is the former (16-bit), for example when high dynamic range rendering is desired. - \since 6.10 + \since 6.11 \sa colorComponentType() */ @@ -567,7 +567,7 @@ void QSurfaceFormat::setColorComponentType(ColorComponentType type) /*! \return the color component type. - \since 6.10 + \since 6.11 \sa setColorComponentType() */ diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index 1703fa5b0fe..1e0f9295110 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -4,6 +4,8 @@ #include "qmatrix4x4.h" #include <QtCore/qmath.h> #include <QtCore/qvariant.h> + +#include <QtGui/qquaternion.h> #include <QtGui/qtransform.h> #include <cmath> diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index 80ba62ca36f..2ba274d4517 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -7,7 +7,6 @@ #include <QtGui/qtguiglobal.h> #include <QtGui/qvector3d.h> #include <QtGui/qvector4d.h> -#include <QtGui/qquaternion.h> #include <QtGui/qgenericmatrix.h> #include <QtCore/qrect.h> @@ -15,6 +14,9 @@ class tst_QMatrixNxN; QT_BEGIN_NAMESPACE +#ifndef QT_NO_QUATERNION +class QQuaternion; +#endif #ifndef QT_NO_MATRIX4X4 diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index b13b1bcad34..a6e540015d7 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -36,6 +36,8 @@ QT_BEGIN_NAMESPACE +QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QPainterPathPrivate) + static inline bool isValidCoord(qreal c) { if (sizeof(qreal) >= sizeof(double)) @@ -512,6 +514,15 @@ QPainterPath::QPainterPath() noexcept QPainterPath::QPainterPath(const QPainterPath &other) = default; /*! + \fn QPainterPath::QPainterPath(QPainterPath &&other) + \since 6.10 + + Move-constructs a new painter path from \a other. + + The moved-from object \a other is placed in the default-constructed state. +*/ + +/*! Creates a QPainterPath object with the given \a startPoint as its current position. */ @@ -3193,9 +3204,10 @@ qreal QPainterPath::slopeAtPercent(qreal t) const /*! \since 6.10 - Returns the section of the path between the length fractions \a f1 and \a f2. The effective range - of the fractions are from 0, denoting the start point of the path, to 1, denoting its end point. - The fractions are linear with respect to path length, in contrast to the percentage \e t values. + Returns the section of the path between the length fractions \a fromFraction and \a toFraction. + The effective range of the fractions are from 0, denoting the start point of the path, to 1, + denoting its end point. The fractions are linear with respect to path length, in contrast to the + percentage \e t values. The value of \a offset will be added to the fraction values. If that causes an over- or underflow of the [0, 1] range, the values will be wrapped around, as will the resulting path. The effective @@ -3206,13 +3218,13 @@ qreal QPainterPath::slopeAtPercent(qreal t) const \sa length(), percentAtLength(), setCachingEnabled() */ -QPainterPath QPainterPath::trimmed(qreal f1, qreal f2, qreal offset) const +QPainterPath QPainterPath::trimmed(qreal fromFraction, qreal toFraction, qreal offset) const { if (isEmpty()) return *this; - f1 = qBound(qreal(0), f1, qreal(1)); - f2 = qBound(qreal(0), f2, qreal(1)); + qreal f1 = qBound(qreal(0), fromFraction, qreal(1)); + qreal f2 = qBound(qreal(0), toFraction, qreal(1)); if (f1 > f2) qSwap(f1, f2); if (qFuzzyCompare(f2 - f1, qreal(1))) // Shortcut for no trimming diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index 2d502936dfd..2e449a8835e 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -17,7 +17,6 @@ QT_BEGIN_NAMESPACE class QFont; class QPainterPathPrivate; -struct QPainterPathPrivateDeleter; class QPainterPathStrokerPrivate; class QPen; class QPolygonF; @@ -25,6 +24,7 @@ class QRegion; class QTransform; class QVectorPath; +QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QPainterPathPrivate) class Q_GUI_EXPORT QPainterPath { public: @@ -56,6 +56,7 @@ public: explicit QPainterPath(const QPointF &startPoint); QPainterPath(const QPainterPath &other); QPainterPath &operator=(const QPainterPath &other); + QPainterPath(QPainterPath &&other) noexcept = default; QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPainterPath) ~QPainterPath(); @@ -141,7 +142,7 @@ public: QPointF pointAtPercent(qreal t) const; qreal angleAtPercent(qreal t) const; qreal slopeAtPercent(qreal t) const; - [[nodiscard]] QPainterPath trimmed(qreal f1, qreal f2, qreal offset = 0) const; + [[nodiscard]] QPainterPath trimmed(qreal fromFraction, qreal toFraction, qreal offset = 0) const; bool intersects(const QPainterPath &p) const; bool contains(const QPainterPath &p) const; diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h index de8aedb5be4..aaa22355cd8 100644 --- a/src/gui/painting/qpainterpath_p.h +++ b/src/gui/painting/qpainterpath_p.h @@ -100,7 +100,6 @@ public: friend class QPainterPathStrokerPrivate; friend class QTransform; friend class QVectorPath; - friend struct QPainterPathPrivateDeleter; #ifndef QT_NO_DATASTREAM friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPainterPath &); friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPainterPath &); diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp index 6f8a318dae0..9b339a19a24 100644 --- a/src/network/access/qhttp2connection.cpp +++ b/src/network/access/qhttp2connection.cpp @@ -663,8 +663,10 @@ void QHttp2Stream::handleDATA(const Frame &inboundFrame) { QHttp2Connection *connection = getConnection(); - qCDebug(qHttp2ConnectionLog, "[%p] stream %u, received DATA frame with payload of %u bytes", - connection, m_streamID, inboundFrame.payloadSize()); + qCDebug(qHttp2ConnectionLog, + "[%p] stream %u, received DATA frame with payload of %u bytes, closing stream? %s", + connection, m_streamID, inboundFrame.payloadSize(), + inboundFrame.flags().testFlag(Http2::FrameFlag::END_STREAM) ? "yes" : "no"); // RFC 9113, 6.1: If a DATA frame is received whose stream is not in the "open" or "half-closed // (local)" state, the recipient MUST respond with a stream error (Section 5.4.2) of type @@ -1426,7 +1428,8 @@ void QHttp2Connection::handleHEADERS() Q_ASSERT(inboundFrame.type() == FrameType::HEADERS); const auto streamID = inboundFrame.streamID(); - qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS frame on stream %d", this, streamID); + qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS frame on stream %d, end stream? %s", this, + streamID, inboundFrame.flags().testFlag(Http2::FrameFlag::END_STREAM) ? "yes" : "no"); // RFC 9113, 6.2: If a HEADERS frame is received whose Stream Identifier field is 0x00, the // recipient MUST respond with a connection error. @@ -1849,6 +1852,10 @@ void QHttp2Connection::handleWINDOW_UPDATE() void QHttp2Connection::handleCONTINUATION() { Q_ASSERT(inboundFrame.type() == FrameType::CONTINUATION); + auto streamID = inboundFrame.streamID(); + qCDebug(qHttp2ConnectionLog, + "[%p] Received CONTINUATION frame on stream %d, end stream? %s", this, streamID, + inboundFrame.flags().testFlag(Http2::FrameFlag::END_STREAM) ? "yes" : "no"); if (continuedFrames.empty()) return connectionError(PROTOCOL_ERROR, "CONTINUATION without a preceding HEADERS or PUSH_PROMISE"); diff --git a/src/network/kernel/qnetworkproxy_android.cpp b/src/network/kernel/qnetworkproxy_android.cpp index d5b56bba865..2261572fea7 100644 --- a/src/network/kernel/qnetworkproxy_android.cpp +++ b/src/network/kernel/qnetworkproxy_android.cpp @@ -3,6 +3,7 @@ #include "qnetworkproxy.h" +#include <QtCore/qapplicationstatic.h> #include <QtCore/qcoreapplication_platform.h> #include <QtCore/qjnienvironment.h> #include <QtCore/qjniobject.h> @@ -21,7 +22,7 @@ public: using namespace QNativeInterface; using namespace QtJniTypes; -Q_GLOBAL_STATIC(ProxyInfoObject, proxyInfoInstance) +Q_APPLICATION_STATIC(ProxyInfoObject, proxyInfoInstance) Q_DECLARE_JNI_CLASS(QtNetwork, "org/qtproject/qt/android/network/QtNetwork") Q_DECLARE_JNI_CLASS(ProxyInfo, "android/net/ProxyInfo") diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp index 6c02a73e7c8..7efe4d52d4c 100644 --- a/src/plugins/platforms/android/androidcontentfileengine.cpp +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2019 Volker Krause <[email protected]> // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -// Qt-Security score:critical reason:file-handling +// Qt-Security score:critical reason:data-parser #include "androidcontentfileengine.h" diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp index 48a2c4ecfaf..9160470e0cc 100644 --- a/src/plugins/platforms/android/extract.cpp +++ b/src/plugins/platforms/android/extract.cpp @@ -1,7 +1,6 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2014 BogDan Vatra <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -// Qt-Security score:critical reason:data-serializing #include <QtCore/QJniEnvironment> diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js index dc7f4583da8..909d8da8856 100644 --- a/src/plugins/platforms/wasm/qtloader.js +++ b/src/plugins/platforms/wasm/qtloader.js @@ -190,7 +190,8 @@ async function qtLoad(config) const originalLocateFile = config.locateFile; config.locateFile = filename => { const originalLocatedFilename = originalLocateFile ? originalLocateFile(filename) : filename; - if (originalLocatedFilename.startsWith('libQt6')) + if (originalLocatedFilename.startsWith( + 'libQt6')) // wasmqtdeploy rely on this behavior, update both in case of change return `${config.qt.qtdir}/lib/${originalLocatedFilename}`; return originalLocatedFilename; } diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp index e5392f33cd7..44db371ca4d 100644 --- a/src/plugins/platforms/wasm/qwasmclipboard.cpp +++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp @@ -48,10 +48,6 @@ static void commonCopyEvent(val event) void QWasmClipboard::cut(val event) { - QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext(); - if (wasmInput && wasmInput->usingTextInput()) - return; - if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi()) { // Send synthetic Ctrl+X to make the app cut data to Qt's clipboard QWindowSystemInterface::handleKeyEvent( @@ -63,10 +59,6 @@ void QWasmClipboard::cut(val event) void QWasmClipboard::copy(val event) { - QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext(); - if (wasmInput && wasmInput->usingTextInput()) - return; - if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi()) { // Send synthetic Ctrl+C to make the app copy data to Qt's clipboard QWindowSystemInterface::handleKeyEvent( @@ -77,10 +69,6 @@ void QWasmClipboard::copy(val event) void QWasmClipboard::paste(val event) { - QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext(); - if (wasmInput && wasmInput->usingTextInput()) - return; - event.call<void>("preventDefault"); // prevent browser from handling drop event QWasmIntegration::get()->getWasmClipboard()->sendClipboardData(event); @@ -183,86 +171,42 @@ void QWasmClipboard::writeToClipboardApi() { Q_ASSERT(m_hasClipboardApi); - // copy event - // browser event handler detected ctrl c if clipboard API - // or Qt call from keyboard event handler - - QMimeData *_mimes = mimeData(QClipboard::Clipboard); - if (!_mimes) + QMimeData *mimeData = this->mimeData(QClipboard::Clipboard); + if (!mimeData) return; - emscripten::val clipboardWriteArray = emscripten::val::array(); - QByteArray ba; - - for (auto mimetype : _mimes->formats()) { - // we need to treat binary and text differently, as the blob method below - // fails for text mimetypes - // ignore text types - - if (mimetype.contains("STRING", Qt::CaseSensitive) || mimetype.contains("TEXT", Qt::CaseSensitive)) - continue; - - if (_mimes->hasHtml()) { // prefer html over text - ba = _mimes->html().toLocal8Bit(); - // force this mime - mimetype = "text/html"; - } else if (mimetype.contains("text/plain")) { - ba = _mimes->text().toLocal8Bit(); - } else if (mimetype.contains("image")) { - QImage img = qvariant_cast<QImage>( _mimes->imageData()); + // Support for plain text, html and images (png) are standardized, + // copy those to the clipboard data object. + emscripten::val clipboardData = emscripten::val::object(); + for (const QString &mimetype: mimeData->formats()) { + if (mimetype == QLatin1String("text/plain")) { + emscripten::val text = mimeData->text().toEcmaString(); + clipboardData.set(mimetype.toEcmaString(), text); + } else if (mimetype == QLatin1String("text/html")) { + emscripten::val html = mimeData->html().toEcmaString(); + clipboardData.set(mimetype.toEcmaString(), html); + } else if (mimetype.contains(QLatin1String("image"))) { + // Serialize the Qt image data to browser supported png + QImage img = qvariant_cast<QImage>(mimeData->imageData()); + QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); img.save(&buffer, "PNG"); - mimetype = "image/png"; // chrome only allows png - // clipboard error "NotAllowedError" "Type application/x-qt-image not supported on write." - // safari silently fails - // so we use png internally for now - } else { - // DATA - ba = _mimes->data(mimetype); - } - // Create file data Blob - const char *content = ba.data(); - int dataLength = ba.length(); - if (dataLength < 1) { - qDebug() << "no content found"; - return; + qstdweb::Blob blob = qstdweb::Blob::fromArrayBuffer(qstdweb::Uint8Array::copyFrom(ba).buffer()); + clipboardData.set(std::string("image/png"), blob.val()); } - - emscripten::val document = emscripten::val::global("document"); - emscripten::val window = emscripten::val::global("window"); - - emscripten::val fileContentView = - emscripten::val(emscripten::typed_memory_view(dataLength, content)); - emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(dataLength); - emscripten::val fileContentCopyView = - emscripten::val::global("Uint8Array").new_(fileContentCopy); - fileContentCopyView.call<void>("set", fileContentView); - - emscripten::val contentArray = emscripten::val::array(); - contentArray.call<void>("push", fileContentCopyView); - - // we have a blob, now create a ClipboardItem - emscripten::val type = emscripten::val::array(); - type.set("type", mimetype.toEcmaString()); - - emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type); - - emscripten::val clipboardItemObject = emscripten::val::object(); - clipboardItemObject.set(mimetype.toEcmaString(), contentBlob); - - val clipboardItemData = val::global("ClipboardItem").new_(clipboardItemObject); - - clipboardWriteArray.call<void>("push", clipboardItemData); - - // Clipboard write is only supported with one ClipboardItem at the moment - // but somehow this still works? - // break; } - val navigator = val::global("navigator"); + // Return if there is no data (creating an empty ClipboardItem is an error) + if (val::global("Object").call<val>("keys", clipboardData)["length"].as<int>() == 0) + return; + // Write a single clipboard item containing the data formats to the clipboard + emscripten::val clipboardItem = val::global("ClipboardItem").new_(clipboardData); + emscripten::val clipboardItemArray = emscripten::val::array(); + clipboardItemArray.call<void>("push", clipboardItem); + val navigator = val::global("navigator"); qstdweb::Promise::make( navigator["clipboard"], "write", { @@ -272,7 +216,7 @@ void QWasmClipboard::writeToClipboardApi() << QString::fromStdString(error["message"].as<std::string>()); } }, - clipboardWriteArray); + clipboardItemArray); } void QWasmClipboard::writeToClipboard() diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp index 2df7066b8e2..191e2947629 100644 --- a/src/plugins/platforms/wasm/qwasminputcontext.cpp +++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp @@ -25,105 +25,88 @@ void QWasmInputContext::inputCallback(emscripten::val event) { qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "isComposing : " << event["isComposing"].as<bool>(); - QString inputStr = (event["data"] != emscripten::val::null() - && event["data"] != emscripten::val::undefined()) ? - QString::fromStdString(event["data"].as<std::string>()) : QString(); - - QWasmInputContext *wasmInput = - reinterpret_cast<QWasmInputContext *>(event["target"]["data-qinputcontext"].as<quintptr>()); - emscripten::val inputType = event["inputType"]; - if (inputType != emscripten::val::null() - && inputType != emscripten::val::undefined()) { - const auto inputTypeString = inputType.as<std::string>(); - // There are many inputTypes for InputEvent - // https://www.w3.org/TR/input-events-1/ - // Some of them should be implemented here later. - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType : " << inputTypeString; - if (!inputTypeString.compare("deleteContentBackward")) { - QWindowSystemInterface::handleKeyEvent(0, - QEvent::KeyPress, - Qt::Key_Backspace, - Qt::NoModifier); - QWindowSystemInterface::handleKeyEvent(0, - QEvent::KeyRelease, - Qt::Key_Backspace, - Qt::NoModifier); - event.call<void>("stopImmediatePropagation"); - return; - } else if (!inputTypeString.compare("deleteContentForward")) { - QWindowSystemInterface::handleKeyEvent(0, - QEvent::KeyPress, - Qt::Key_Delete, - Qt::NoModifier); - QWindowSystemInterface::handleKeyEvent(0, - QEvent::KeyRelease, - Qt::Key_Delete, - Qt::NoModifier); - event.call<void>("stopImmediatePropagation"); - return; - } else if (!inputTypeString.compare("insertCompositionText")) { - qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr; - wasmInput->insertPreedit(); - event.call<void>("stopImmediatePropagation"); - return; - } else if (!inputTypeString.compare("insertReplacementText")) { - qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr; - //auto ranges = event.call<emscripten::val>("getTargetRanges"); - //qCDebug(qLcQpaWasmInputContext) << ranges["length"].as<int>(); - // WA For Korean IME - // insertReplacementText should have targetRanges but - // Safari cannot have it and just it seems to be supposed - // to replace previous input. - wasmInput->insertText(inputStr, true); - - event.call<void>("stopImmediatePropagation"); - return; - } else if (!inputTypeString.compare("deleteCompositionText")) { - wasmInput->setPreeditString("", 0); - wasmInput->insertPreedit(); - event.call<void>("stopImmediatePropagation"); - return; - } else if (!inputTypeString.compare("insertFromComposition")) { - wasmInput->setPreeditString(inputStr, 0); - wasmInput->insertPreedit(); - event.call<void>("stopImmediatePropagation"); - return; - } else if (!inputTypeString.compare("insertText")) { - wasmInput->insertText(inputStr); - event.call<void>("stopImmediatePropagation"); + if (inputType.isNull() || inputType.isUndefined()) + return; + const auto inputTypeString = inputType.as<std::string>(); + + emscripten::val inputData = event["data"]; + QString inputStr = (!inputData.isNull() && !inputData.isUndefined()) + ? QString::fromEcmaString(inputData) : QString(); + + // There are many inputTypes for InputEvent + // https://www.w3.org/TR/input-events-1/ + // Some of them should be implemented here later. + qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType : " << inputTypeString; + if (!inputTypeString.compare("deleteContentBackward")) { + QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); + QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier); + event.call<void>("stopImmediatePropagation"); + return; + } else if (!inputTypeString.compare("deleteContentForward")) { + QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier); + QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_Delete, Qt::NoModifier); + event.call<void>("stopImmediatePropagation"); + return; + } else if (!inputTypeString.compare("insertCompositionText")) { + qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr; + insertPreedit(); + event.call<void>("stopImmediatePropagation"); + return; + } else if (!inputTypeString.compare("insertReplacementText")) { + qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr; + //auto ranges = event.call<emscripten::val>("getTargetRanges"); + //qCDebug(qLcQpaWasmInputContext) << ranges["length"].as<int>(); + // WA For Korean IME + // insertReplacementText should have targetRanges but + // Safari cannot have it and just it seems to be supposed + // to replace previous input. + insertText(inputStr, true); + + event.call<void>("stopImmediatePropagation"); + return; + } else if (!inputTypeString.compare("deleteCompositionText")) { + setPreeditString("", 0); + insertPreedit(); + event.call<void>("stopImmediatePropagation"); + return; + } else if (!inputTypeString.compare("insertFromComposition")) { + setPreeditString(inputStr, 0); + insertPreedit(); + event.call<void>("stopImmediatePropagation"); + return; + } else if (!inputTypeString.compare("insertText")) { + insertText(inputStr); + event.call<void>("stopImmediatePropagation"); #if QT_CONFIG(clipboard) - } else if (!inputTypeString.compare("insertFromPaste")) { - wasmInput->insertText(QGuiApplication::clipboard()->text()); - event.call<void>("stopImmediatePropagation"); - // These can be supported here, - // But now, keyCallback in QWasmWindow - // will take them as exceptions. - //} else if (!inputTypeString.compare("deleteByCut")) { + } else if (!inputTypeString.compare("insertFromPaste")) { + insertText(QGuiApplication::clipboard()->text()); + event.call<void>("stopImmediatePropagation"); + // These can be supported here, + // But now, keyCallback in QWasmWindow + // will take them as exceptions. + //} else if (!inputTypeString.compare("deleteByCut")) { #endif - } else { - qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType \"" << inputType.as<std::string>() << "\" is not supported in Qt yet"; - } + } else { + qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType \"" << + inputType.as<std::string>() << "\" is not supported in Qt yet"; } } void QWasmInputContext::compositionEndCallback(emscripten::val event) { - const auto inputStr = QString::fromStdString(event["data"].as<std::string>()); + const auto inputStr = QString::fromEcmaString(event["data"]); qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << inputStr; - QWasmInputContext *wasmInput = - reinterpret_cast<QWasmInputContext *>(event["target"]["data-qinputcontext"].as<quintptr>()); - - if (wasmInput->preeditString().isEmpty()) + if (preeditString().isEmpty()) return; - if (inputStr != wasmInput->preeditString()) { + if (inputStr != preeditString()) { qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO << "Composition string" << inputStr - << "is differ from" << wasmInput->preeditString(); + << "is differ from" << preeditString(); } - wasmInput->commitPreeditAndClear(); + commitPreeditAndClear(); } void QWasmInputContext::compositionStartCallback(emscripten::val event) @@ -151,19 +134,15 @@ static void beforeInputCallback(emscripten::val event) void QWasmInputContext::compositionUpdateCallback(emscripten::val event) { - const auto compositionStr = QString::fromStdString(event["data"].as<std::string>()); + const auto compositionStr = QString::fromEcmaString(event["data"]); qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << compositionStr; - QWasmInputContext *wasmInput = - reinterpret_cast<QWasmInputContext *>(event["target"]["data-qinputcontext"].as<quintptr>()); - // WA for IOS. // Not sure now because I cannot test it anymore. // int replaceSize = 0; // emscripten::val win = emscripten::val::global("window"); // emscripten::val sel = win.call<emscripten::val>("getSelection"); -// if (sel != emscripten::val::null() -// && sel != emscripten::val::undefined() +// if (!sel.isNull() && !sel.isUndefined() // && sel["rangeCount"].as<int>() > 0) { // QInputMethodQueryEvent queryEvent(Qt::ImQueryAll); // QCoreApplication::sendEvent(QGuiApplication::focusObject(), &queryEvent); @@ -172,8 +151,8 @@ void QWasmInputContext::compositionUpdateCallback(emscripten::val event) // qCDebug(qLcQpaWasmInputContext) << "Qt text before cursor: " << queryEvent.value(Qt::ImTextBeforeCursor).toString(); // qCDebug(qLcQpaWasmInputContext) << "Qt text after cursor: " << queryEvent.value(Qt::ImTextAfterCursor).toString(); // -// const QString &selectedStr = QString::fromUtf8(sel.call<emscripten::val>("toString").as<std::string>()); -// const auto &preeditStr = wasmInput->preeditString(); +// const QString &selectedStr = QString::fromEcmaString(sel.call<emscripten::val>("toString")); +// const auto &preeditStr = preeditString(); // qCDebug(qLcQpaWasmInputContext) << "Selection.type : " << sel["type"].as<std::string>(); // qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "Selected: " << selectedStr; // qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "PreeditString: " << preeditStr; @@ -189,90 +168,13 @@ void QWasmInputContext::compositionUpdateCallback(emscripten::val event) // qCDebug(qLcQpaWasmInputContext) << "Range.endOffset : " << range["endOffset"].as<int>(); // } // -// wasmInput->setPreeditString(compositionStr, replaceSize); - wasmInput->setPreeditString(compositionStr, 0); -} - -#if QT_CONFIG(clipboard) -static void copyCallback(emscripten::val event) -{ - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO; - - QClipboard *clipboard = QGuiApplication::clipboard(); - QString inputStr = clipboard->text(); - qCDebug(qLcQpaWasmInputContext) << "QClipboard : " << inputStr; - event["clipboardData"].call<void>("setData", - emscripten::val("text/plain"), - inputStr.toStdString()); - event.call<void>("preventDefault"); - event.call<void>("stopImmediatePropagation"); -} - -static void cutCallback(emscripten::val event) -{ - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO; - - QClipboard *clipboard = QGuiApplication::clipboard(); - QString inputStr = clipboard->text(); - qCDebug(qLcQpaWasmInputContext) << "QClipboard : " << inputStr; - event["clipboardData"].call<void>("setData", - emscripten::val("text/plain"), - inputStr.toStdString()); - event.call<void>("preventDefault"); - event.call<void>("stopImmediatePropagation"); +// setPreeditString(compositionStr, replaceSize); + setPreeditString(compositionStr, 0); } -static void pasteCallback(emscripten::val event) -{ - qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO; - - emscripten::val clipboardData = event["clipboardData"].call<emscripten::val>("getData", emscripten::val("text/plain")); - QString clipboardStr = QString::fromStdString(clipboardData.as<std::string>()); - qCDebug(qLcQpaWasmInputContext) << "wasm clipboard : " << clipboardStr; - QClipboard *clipboard = QGuiApplication::clipboard(); - if (clipboard->text() != clipboardStr) - clipboard->setText(clipboardStr); - - // propagate to input event (insertFromPaste) -} -#endif // QT_CONFIG(clipboard) - QWasmInputContext::QWasmInputContext() { qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO; - emscripten::val document = emscripten::val::global("document"); - // This 'input' can be an issue to handle multiple lines, - // 'textarea' can be used instead. - m_inputElement = document.call<emscripten::val>("createElement", std::string("input")); - m_inputElement.set("type", "text"); - m_inputElement.set("contenteditable","true"); - m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true")); - - m_inputElement["style"].set("position", "absolute"); - m_inputElement["style"].set("left", 0); - m_inputElement["style"].set("top", 0); - m_inputElement["style"].set("opacity", 0); - m_inputElement["style"].set("display", ""); - m_inputElement["style"].set("z-index", -2); - m_inputElement["style"].set("width", "1px"); - m_inputElement["style"].set("height", "1px"); - - m_inputElement.set("data-qinputcontext", - emscripten::val(quintptr(reinterpret_cast<void *>(this)))); - emscripten::val body = document["body"]; - body.call<void>("appendChild", m_inputElement); - - m_inputCallback = QWasmEventHandler(m_inputElement, "input", QWasmInputContext::inputCallback); - m_compositionEndCallback = QWasmEventHandler(m_inputElement, "compositionend", QWasmInputContext::compositionEndCallback); - m_compositionStartCallback = QWasmEventHandler(m_inputElement, "compositionstart", QWasmInputContext::compositionStartCallback); - m_compositionUpdateCallback = QWasmEventHandler(m_inputElement, "compositionupdate", QWasmInputContext::compositionUpdateCallback); - -#if QT_CONFIG(clipboard) - // Clipboard for InputContext - m_clipboardCut = QWasmEventHandler(m_inputElement, "cut", cutCallback); - m_clipboardCopy = QWasmEventHandler(m_inputElement, "copy", copyCallback); - m_clipboardPaste = QWasmEventHandler(m_inputElement, "paste", pasteCallback); -#endif } QWasmInputContext::~QWasmInputContext() @@ -303,6 +205,9 @@ void QWasmInputContext::showInputPanel() void QWasmInputContext::updateGeometry() { + if (m_inputElement.isNull()) + return; + const QWindow *focusWindow = QGuiApplication::focusWindow(); if (!m_focusObject || !focusWindow || !m_inputMethodAccepted) { m_inputElement["style"].set("left", "0px"); @@ -312,23 +217,12 @@ void QWasmInputContext::updateGeometry() Q_ASSERT(m_focusObject); Q_ASSERT(m_inputMethodAccepted); - // Set the geometry - QPoint globalPos; - const QRect cursorRectangle = QPlatformInputContext::cursorRectangle().toRect(); - if (cursorRectangle.isValid()) { - qCDebug(qLcQpaWasmInputContext) - << Q_FUNC_INFO << "cursorRectangle: " << cursorRectangle; - globalPos = focusWindow->mapToGlobal(cursorRectangle.topLeft()); - if (globalPos.x() > 0) - globalPos.setX(globalPos.x() - 1); - if (globalPos.y() > 0) - globalPos.setY(globalPos.y() - 1); - } - - const auto styleLeft = std::to_string(globalPos.x()) + "px"; - const auto styleTop = std::to_string(globalPos.y()) + "px"; - m_inputElement["style"].set("left", styleLeft); - m_inputElement["style"].set("top", styleTop); + const QRect inputItemRectangle = QPlatformInputContext::inputItemRectangle().toRect(); + qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "propagating inputItemRectangle:" << inputItemRectangle; + m_inputElement["style"].set("left", std::to_string(inputItemRectangle.x()) + "px"); + m_inputElement["style"].set("top", std::to_string(inputItemRectangle.y()) + "px"); + m_inputElement["style"].set("width", std::to_string(inputItemRectangle.width()) + "px"); + m_inputElement["style"].set("height", std::to_string(inputItemRectangle.height()) + "px"); } } @@ -341,16 +235,21 @@ void QWasmInputContext::updateInputElement() updateGeometry(); // If there is no focus object, or no visible input panel, remove focus - const QWindow *focusWindow = QGuiApplication::focusWindow(); + QWasmWindow *focusWindow = QWasmWindow::fromWindow(QGuiApplication::focusWindow()); if (!m_focusObject || !focusWindow || !m_inputMethodAccepted) { - m_inputElement.set("value", ""); + if (!m_inputElement.isNull()) { + m_inputElement.set("value", ""); + m_inputElement.set("inputMode", std::string("none")); + } - if (QWasmWindow *wasmwindow = QWasmWindow::fromWindow(focusWindow)) - wasmwindow->focus(); - else - m_inputElement.call<void>("blur"); + if (focusWindow) { + focusWindow->focus(); + } else { + if (!m_inputElement.isNull()) + m_inputElement.call<void>("blur"); + } - m_inputElement.set("inputMode", std::string("none")); + m_inputElement = emscripten::val::null(); return; } @@ -358,6 +257,8 @@ void QWasmInputContext::updateInputElement() Q_ASSERT(m_focusObject); Q_ASSERT(m_inputMethodAccepted); + m_inputElement = focusWindow->inputElement(); + qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << QRectF::fromDOMRect(m_inputElement.call<emscripten::val>("getBoundingClientRect")); // Set the text input @@ -375,7 +276,15 @@ void QWasmInputContext::updateInputElement() m_inputElement.set("selectionStart", queryEvent.value(Qt::ImAnchorPosition).toUInt()); m_inputElement.set("selectionEnd", queryEvent.value(Qt::ImCursorPosition).toUInt()); + QInputMethodQueryEvent query((Qt::InputMethodQueries(Qt::ImHints))); + QCoreApplication::sendEvent(m_focusObject, &query); + if (Qt::InputMethodHints(query.value(Qt::ImHints).toInt()).testFlag(Qt::ImhHiddenText)) + m_inputElement.set("type", "password"); + else + m_inputElement.set("type", "text"); + m_inputElement.set("inputMode", std::string("text")); + m_inputElement.call<void>("focus"); } @@ -383,16 +292,6 @@ void QWasmInputContext::setFocusObject(QObject *object) { qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << object << inputMethodAccepted(); - QInputMethodQueryEvent query(Qt::InputMethodQueries(Qt::ImEnabled | Qt::ImHints)); - QCoreApplication::sendEvent(object, &query); - if (query.value(Qt::ImEnabled).toBool() - && Qt::InputMethodHints(query.value(Qt::ImHints).toInt()).testFlag(Qt::ImhHiddenText)) { - m_inputElement.set("type", "password"); - } else { - if (m_inputElement["type"].as<std::string>() != std::string("text")) - m_inputElement.set("type", "text"); - } - // Commit the previous composition before change m_focusObject if (m_focusObject && !m_preeditString.isEmpty()) commitPreeditAndClear(); diff --git a/src/plugins/platforms/wasm/qwasminputcontext.h b/src/plugins/platforms/wasm/qwasminputcontext.h index 72476adfe1b..6d24c7fea0d 100644 --- a/src/plugins/platforms/wasm/qwasminputcontext.h +++ b/src/plugins/platforms/wasm/qwasminputcontext.h @@ -35,38 +35,33 @@ public: void setPreeditString(QString preeditStr, int replaceSize); void insertPreedit(); void commitPreeditAndClear(); - emscripten::val m_inputElement = emscripten::val::null(); void insertText(QString inputStr, bool replace = false); - QWasmEventHandler m_inputCallback; - QWasmEventHandler m_compositionEndCallback; - QWasmEventHandler m_compositionStartCallback; - QWasmEventHandler m_compositionUpdateCallback; - bool usingTextInput() const { return m_inputMethodAccepted; } void setFocusObject(QObject *object) override; - static void inputCallback(emscripten::val event); - static void compositionEndCallback(emscripten::val event); - static void compositionStartCallback(emscripten::val event); - static void compositionUpdateCallback(emscripten::val event); + void inputCallback(emscripten::val event); + void compositionEndCallback(emscripten::val event); + void compositionStartCallback(emscripten::val event); + void compositionUpdateCallback(emscripten::val event); void updateGeometry(); + bool isActive() const { + return m_focusObject && m_inputMethodAccepted; + } + private: void updateInputElement(); private: - QWasmEventHandler m_clipboardCut; - QWasmEventHandler m_clipboardCopy; - QWasmEventHandler m_clipboardPaste; - QString m_preeditString; int m_replaceSize = 0; bool m_inputMethodAccepted = false; QObject *m_focusObject = nullptr; + emscripten::val m_inputElement = emscripten::val::null(); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index d690bcfe10a..d27385be723 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -51,7 +51,10 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, m_decoratedWindow(m_document.call<emscripten::val>("createElement", emscripten::val("div"))), m_window(m_document.call<emscripten::val>("createElement", emscripten::val("div"))), m_a11yContainer(m_document.call<emscripten::val>("createElement", emscripten::val("div"))), - m_canvas(m_document.call<emscripten::val>("createElement", emscripten::val("canvas"))) + m_canvas(m_document.call<emscripten::val>("createElement", emscripten::val("canvas"))), + m_focusHelper(m_document.call<emscripten::val>("createElement", emscripten::val("div"))), + m_inputElement(m_document.call<emscripten::val>("createElement", emscripten::val("input"))) + { m_decoratedWindow.set("className", "qt-decorated-window"); m_decoratedWindow["style"].set("display", std::string("none")); @@ -80,17 +83,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, m_canvas["classList"].call<void>("add", emscripten::val("qt-window-canvas")); - // Set contentEditable for two reasons; - // 1) so that the window gets clipboard events, - // 2) For applications who will handle keyboard events, but without having inputMethodAccepted() - // - // Set inputMode to none to avoid keyboard popping up on push buttons - // This is a tradeoff, we are not able to separate between a push button and - // a widget that reads keyboard events. - m_canvas.call<void>("setAttribute", std::string("inputmode"), std::string("none")); - m_canvas.call<void>("setAttribute", std::string("contenteditable"), std::string("true")); - m_canvas["style"].set("outline", std::string("none")); - #if QT_CONFIG(clipboard) if (QWasmClipboard::shouldInstallWindowEventHandlers()) { m_cutCallback = QWasmEventHandler(m_canvas, "cut", QWasmClipboard::cut); @@ -99,9 +91,37 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, } #endif - // Set inputMode to none to stop the mobile keyboard from opening - // when the user clicks on the window. - m_window.set("inputMode", std::string("none")); + // Set up m_focusHelper, which is an invisible child element of the window which takes + // focus on behalf of the window any time the window has focus in general, but none + // of the special child elements such as the inputElment or a11y elements have focus. + // Set inputMode=none set to prevent the virtual keyboard from popping up. + m_focusHelper["classList"].call<void>("add", emscripten::val("qt-window-focus-helper")); + m_focusHelper.set("inputMode", std::string("none")); + m_focusHelper.call<void>("setAttribute", std::string("aria-hidden"), std::string("true")); + m_focusHelper.call<void>("setAttribute", std::string("contenteditable"), std::string("true")); + m_focusHelper["style"].set("position", "absolute"); + m_focusHelper["style"].set("left", 0); + m_focusHelper["style"].set("top", 0); + m_focusHelper["style"].set("width", "1px"); + m_focusHelper["style"].set("height", "1px"); + m_focusHelper["style"].set("z-index", -2); + m_focusHelper["style"].set("opacity", 0); + m_window.call<void>("appendChild", m_focusHelper); + + // Set up m_inputElement, which takes focus whenever a Qt text input UI element has + // foucus. + m_inputElement["classList"].call<void>("add", emscripten::val("qt-window-input-element")); + m_inputElement.set("type", "text"); + m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true")); + m_inputElement["style"].set("position", "absolute"); + m_inputElement["style"].set("left", 0); + m_inputElement["style"].set("top", 0); + m_inputElement["style"].set("width", "1px"); + m_inputElement["style"].set("height", "1px"); + m_inputElement["style"].set("z-index", -2); + m_inputElement["style"].set("opacity", 0); + m_inputElement["style"].set("display", ""); + m_window.call<void>("appendChild", m_inputElement); // Hide the canvas from screen readers. m_canvas.call<void>("setAttribute", std::string("aria-hidden"), std::string("true")); @@ -193,21 +213,20 @@ void QWasmWindow::registerEventHandlers() m_wheelEventCallback = QWasmEventHandler(m_window, "wheel", [this](emscripten::val event) { this->handleWheelEvent(event); }); - QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext(); - if (wasmInput) { - m_keyDownCallbackForInputContext = - QWasmEventHandler(wasmInput->m_inputElement, "keydown", - [this](emscripten::val event) { this->handleKeyForInputContextEvent(EventType::KeyDown, event); }); - m_keyUpCallbackForInputContext = - QWasmEventHandler(wasmInput->m_inputElement, "keyup", - [this](emscripten::val event) { this->handleKeyForInputContextEvent(EventType::KeyUp, event); }); - } - - m_keyDownCallback = QWasmEventHandler(m_canvas, "keydown", + m_keyDownCallback = QWasmEventHandler(m_window, "keydown", [this](emscripten::val event) { this->handleKeyEvent(KeyEvent(EventType::KeyDown, event, m_deadKeySupport)); }); - m_keyUpCallback =QWasmEventHandler(m_canvas, "keyup", + m_keyUpCallback =QWasmEventHandler(m_window, "keyup", [this](emscripten::val event) {this->handleKeyEvent(KeyEvent(EventType::KeyUp, event, m_deadKeySupport)); }); -} + + m_inputCallback = QWasmEventHandler(m_window, "input", + [this](emscripten::val event){ handleInputEvent(event); }); + m_compositionUpdateCallback = QWasmEventHandler(m_window, "compositionupdate", + [this](emscripten::val event){ handleCompositionUpdateEvent(event); }); + m_compositionStartCallback = QWasmEventHandler(m_window, "compositionstart", + [this](emscripten::val event){ handleCompositionStartEvent(event); }); + m_compositionEndCallback = QWasmEventHandler(m_window, "compositionend", + [this](emscripten::val event){ handleCompositionEndEvent(event); }); + } QWasmWindow::~QWasmWindow() { @@ -624,10 +643,15 @@ void QWasmWindow::commitParent(QWasmWindowTreeNode *parent) void QWasmWindow::handleKeyEvent(const KeyEvent &event) { - qCDebug(qLcQpaWasmInputContext) << "processKey as KeyEvent"; - if (processKey(event)) { - event.webEvent.call<void>("preventDefault"); - event.webEvent.call<void>("stopPropagation"); + qCDebug(qLcQpaWasmInputContext) << "handleKeyEvent"; + + if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) { + handleKeyForInputContextEvent(event); + } else { + if (processKey(event)) { + event.webEvent.call<void>("preventDefault"); + event.webEvent.call<void>("stopPropagation"); + } } } @@ -658,7 +682,7 @@ bool QWasmWindow::processKey(const KeyEvent &event) #endif } -void QWasmWindow::handleKeyForInputContextEvent(EventType eventType, const emscripten::val &event) +void QWasmWindow::handleKeyForInputContextEvent(const KeyEvent &keyEvent) { // // Things to consider: @@ -668,40 +692,43 @@ void QWasmWindow::handleKeyForInputContextEvent(EventType eventType, const emscr // complex (i.e Chinese et al) input handling // Multiline text edit backspace at start of line // - const QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext(); - if (wasmInput) { + emscripten::val event = keyEvent.webEvent; + bool useInputContext = [event]() -> bool { + const QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext(); + if (!wasmInput) + return false; + const auto keyString = QString::fromStdString(event["key"].as<std::string>()); qCDebug(qLcQpaWasmInputContext) << "Key callback" << keyString << keyString.size(); - if (keyString == "Unidentified") { - // Android makes a bunch of KeyEvents as "Unidentified" - // They will be processed just in InputContext. - return; - } else if (event["isComposing"].as<bool>()) { - // Handled by the input context - return; - } else if (event["ctrlKey"].as<bool>() - || event["altKey"].as<bool>() - || event["metaKey"].as<bool>()) { - // Not all platforms use 'isComposing' for '~' + 'a', in this - // case send the key with state ('ctrl', 'alt', or 'meta') to - // processKeyForInputContext - - ; // fallthrough - } else if (keyString.size() != 1) { - // This is like; 'Shift','ArrowRight','AltGraph', ... - // send all of these to processKeyForInputContext - - ; // fallthrough - } else if (wasmInput->inputMethodAccepted()) { - // processed in inputContext with skipping processKey - return; - } - } - qCDebug(qLcQpaWasmInputContext) << "processKey as KeyEvent"; - if (processKeyForInputContext(KeyEvent(eventType, event, m_deadKeySupport))) - event.call<void>("preventDefault"); - event.call<void>("stopImmediatePropagation"); + // Events with isComposing set are handled by the input context + bool composing = event["isComposing"].as<bool>(); + + // Android makes a bunch of KeyEvents as "Unidentified", + // make inputContext handle those. + bool androidUnidentified = (keyString == "Unidentified"); + + // Not all platforms use 'isComposing' for '~' + 'a', in this + // case send the key with state ('ctrl', 'alt', or 'meta') to + // processKeyForInputContext + bool hasModifiers = event["ctrlKey"].as<bool>() + || event["altKey"].as<bool>() + || event["metaKey"].as<bool>(); + + // This is like; 'Shift','ArrowRight','AltGraph', ... + // send all of these to processKeyForInputContext + bool hasNoncharacterKeyString = keyString.size() != 1; + + bool overrideCompose = !hasModifiers && !hasNoncharacterKeyString && wasmInput->inputMethodAccepted(); + return composing || androidUnidentified || overrideCompose; + }(); + + if (!useInputContext) { + qCDebug(qLcQpaWasmInputContext) << "processKey as KeyEvent"; + if (processKeyForInputContext(keyEvent)) + event.call<void>("preventDefault"); + event.call<void>("stopImmediatePropagation"); + } } bool QWasmWindow::processKeyForInputContext(const KeyEvent &event) @@ -729,6 +756,30 @@ bool QWasmWindow::processKeyForInputContext(const KeyEvent &event) return result; } +void QWasmWindow::handleInputEvent(emscripten::val event) +{ + if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) + inputContext->inputCallback(event); +} + +void QWasmWindow::handleCompositionStartEvent(emscripten::val event) +{ + if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) + inputContext->compositionStartCallback(event); +} + +void QWasmWindow::handleCompositionUpdateEvent(emscripten::val event) +{ + if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) + inputContext->compositionUpdateCallback(event); +} + +void QWasmWindow::handleCompositionEndEvent(emscripten::val event) +{ + if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) + inputContext->compositionEndCallback(event); +} + void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event) { if (processPointerEnterLeave(event)) @@ -1040,7 +1091,7 @@ void QWasmWindow::requestActivateWindow() void QWasmWindow::focus() { - m_canvas.call<void>("focus"); + m_focusHelper.call<void>("focus"); } bool QWasmWindow::setMouseGrabEnabled(bool grab) diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index 904e736a7e7..0c63ebdc16e 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -100,6 +100,7 @@ public: emscripten::val context2d() const { return m_context2d; } emscripten::val a11yContainer() const { return m_a11yContainer; } emscripten::val inputHandlerElement() const { return m_window; } + emscripten::val inputElement() const { return m_inputElement; } // QNativeInterface::Private::QWasmWindow emscripten::val document() const override { return m_document; } @@ -137,8 +138,13 @@ private: void handleKeyEvent(const KeyEvent &event); bool processKey(const KeyEvent &event); - void handleKeyForInputContextEvent(EventType eventType, const emscripten::val &event); + void handleKeyForInputContextEvent(const KeyEvent &event); bool processKeyForInputContext(const KeyEvent &event); + void handleInputEvent(emscripten::val event); + void handleCompositionStartEvent(emscripten::val event); + void handleCompositionUpdateEvent(emscripten::val event); + void handleCompositionEndEvent(emscripten::val event); + void handlePointerEnterLeaveEvent(const PointerEvent &event); bool processPointerEnterLeave(const PointerEvent &event); void processPointer(const PointerEvent &event); @@ -154,11 +160,14 @@ private: QWasmDeadKeySupport *m_deadKeySupport; QRect m_normalGeometry {0, 0, 0 ,0}; - emscripten::val m_document = emscripten::val::undefined(); - emscripten::val m_decoratedWindow = emscripten::val::undefined(); - emscripten::val m_window = emscripten::val::undefined(); - emscripten::val m_a11yContainer = emscripten::val::undefined(); - emscripten::val m_canvas = emscripten::val::undefined(); + emscripten::val m_document; + emscripten::val m_decoratedWindow; + emscripten::val m_window; + emscripten::val m_a11yContainer; + emscripten::val m_canvas; + emscripten::val m_focusHelper; + emscripten::val m_inputElement; + emscripten::val m_context2d = emscripten::val::undefined(); std::unique_ptr<NonClientArea> m_nonClientArea; @@ -169,6 +178,10 @@ private: QWasmEventHandler m_keyUpCallback; QWasmEventHandler m_keyDownCallbackForInputContext; QWasmEventHandler m_keyUpCallbackForInputContext; + QWasmEventHandler m_inputCallback; + QWasmEventHandler m_compositionStartCallback; + QWasmEventHandler m_compositionUpdateCallback; + QWasmEventHandler m_compositionEndCallback; QWasmEventHandler m_pointerDownCallback; QWasmEventHandler m_pointerMoveCallback; diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index 62269a21de1..84101b69e9f 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -2151,9 +2151,6 @@ void QWindows11Style::polish(QWidget* widget) widget->setWindowFlag(Qt::NoDropShadowWindowHint); widget->setAttribute(Qt::WA_RightToLeft, layoutDirection); widget->setAttribute(Qt::WA_WState_Created, wasCreated); - auto pal = widget->palette(); - pal.setColor(widget->backgroundRole(), Qt::transparent); - widget->setPalette(pal); if (!isScrollBar) { bool inGraphicsView = widget->graphicsProxyWidget() != nullptr; if (!inGraphicsView && comboBoxContainer && comboBoxContainer->parentWidget()) diff --git a/src/testlib/3rdparty/catch2/qt_attribution.json b/src/testlib/3rdparty/catch2/qt_attribution.json index 1e4f2c5297c..ad231efd426 100644 --- a/src/testlib/3rdparty/catch2/qt_attribution.json +++ b/src/testlib/3rdparty/catch2/qt_attribution.json @@ -5,6 +5,7 @@ "QDocModule": "qttestlib", "QtUsage": "Used for testing of the Qt Test module.", "Comment": { + "OldBranch": "Stick to its v2.x branch; no suitable file in v3", "UpstreamFile": "single_include/catch2/catch.hpp", "Generator": "scripts/generateSingleHeader.py", "General": "no relevant CPE found" diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 1ff52f8a84f..2f06cbcf67e 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -28,6 +28,10 @@ if(QT_FEATURE_macdeployqt) add_subdirectory(macdeployqt) endif() +if(QT_FEATURE_wasmdeployqt) + add_subdirectory(wasmdeployqt) +endif() + if(QT_FEATURE_windeployqt) add_subdirectory(windeployqt) endif() diff --git a/src/tools/configure.cmake b/src/tools/configure.cmake index 6a9c1b8e3f3..27ea90b89ac 100644 --- a/src/tools/configure.cmake +++ b/src/tools/configure.cmake @@ -18,6 +18,12 @@ qt_feature("macdeployqt" PRIVATE AUTODETECT CMAKE_HOST_APPLE CONDITION MACOS AND QT_FEATURE_thread) +qt_feature("wasmdeployqt" PRIVATE + SECTION "Deployment" + LABEL "WebAssembly deployment tool" + PURPOSE "The WebAssembly deployment tool is designed to automate the process of creating a deployable folder especially for dynamic linking case variant." + CONDITION QT_FEATURE_process) + qt_feature("windeployqt" PRIVATE SECTION "Deployment" LABEL "Windows deployment tool" diff --git a/src/tools/wasmdeployqt/CMakeLists.txt b/src/tools/wasmdeployqt/CMakeLists.txt new file mode 100644 index 00000000000..7305c14c269 --- /dev/null +++ b/src/tools/wasmdeployqt/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## wasmdeployqt Tool: +##################################################################### + +qt_get_tool_target_name(target_name wasmdeployqt) +qt_internal_add_tool(${target_name} + TOOLS_TARGET Core + USER_FACING + INSTALL_VERSIONED_LINK + TARGET_DESCRIPTION "Qt WebAssembly Deployment Tool" + SOURCES + main.cpp wasmbinary.cpp jsontools.cpp + LIBRARIES + Qt::CorePrivate +) +qt_internal_return_unless_building_tools() diff --git a/src/tools/wasmdeployqt/common.h b/src/tools/wasmdeployqt/common.h new file mode 100644 index 00000000000..258d6161e67 --- /dev/null +++ b/src/tools/wasmdeployqt/common.h @@ -0,0 +1,26 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef COMMON_H +#define COMMON_H + +#include <QHash> +#include <QString> + +struct PreloadEntry +{ + QString source; + QString destination; + + bool operator==(const PreloadEntry &other) const + { + return source == other.source && destination == other.destination; + } +}; + +inline uint qHash(const PreloadEntry &key, uint seed = 0) +{ + return qHash(key.source, seed) ^ qHash(key.destination, seed); +} + +#endif diff --git a/src/tools/wasmdeployqt/jsontools.cpp b/src/tools/wasmdeployqt/jsontools.cpp new file mode 100644 index 00000000000..d76f9190b73 --- /dev/null +++ b/src/tools/wasmdeployqt/jsontools.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QDir> +#include <QJsonArray> +#include <QJsonObject> + +#include "jsontools.h" +#include "common.h" + +#include <iostream> +#include <optional> + +namespace JsonTools { + +bool savePreloadFile(QSet<PreloadEntry> preload, QString destFile) +{ + + QJsonArray jsonArray; + for (const PreloadEntry &entry : preload) { + QJsonObject obj; + obj["source"] = entry.source; + obj["destination"] = entry.destination; + jsonArray.append(obj); + } + QJsonDocument doc(jsonArray); + + QFile outFile(destFile); + if (outFile.exists()) { + if (!outFile.remove()) { + std::cout << "ERROR: Failed to delete old file: " << outFile.fileName().toStdString() + << std::endl; + return false; + } + } + if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + std::cout << "ERROR: Failed to open file for writing:" << outFile.fileName().toStdString() + << std::endl; + return false; + } + if (outFile.write(doc.toJson(QJsonDocument::Indented)) == -1) { + std::cout << "ERROR: Failed writing into file :" << outFile.fileName().toStdString() + << std::endl; + return false; + } + if (!outFile.flush()) { + std::cout << "ERROR: Failed flushing the file :" << outFile.fileName().toStdString() + << std::endl; + return false; + } + outFile.close(); + return true; +} + +std::optional<QSet<PreloadEntry>> getPreloadsFromQmlImportScannerOutput(QString output) +{ + QString qtLibPath = "$QTDIR/lib"; + QString qtQmlPath = "$QTDIR/qml"; + QString qtDeployQmlPath = "/qt/qml"; + QSet<PreloadEntry> res; + auto addImport = [&res](const PreloadEntry &entry) { + // qDebug() << "adding " << entry.source << "" << entry.destination; + res.insert(entry); + }; + + QJsonParseError parseError; + QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8(), &parseError); + + if (parseError.error != QJsonParseError::NoError) { + std::cout << "ERROR: QmlImport JSON parse error: " << parseError.errorString().toStdString() + << std::endl; + return std::nullopt; + } + if (!doc.isArray()) { + std::cout << "ERROR: QmlImport JSON is not an array." << std::endl; + return std::nullopt; + } + + QJsonArray jsonArray = doc.array(); + for (const QJsonValue &value : jsonArray) { + if (value.isObject()) { + QJsonObject obj = value.toObject(); + auto relativePath = obj["relativePath"].toString(); + auto plugin = obj["plugin"].toString(); + if (plugin.isEmpty() || relativePath.isEmpty()) { + continue; + } + auto pluginFilename = "lib" + plugin + ".so"; + addImport(PreloadEntry{ + QDir::cleanPath(qtQmlPath + "/" + relativePath + "/" + pluginFilename), + QDir::cleanPath(qtDeployQmlPath + "/" + relativePath + "/" + pluginFilename) }); + addImport(PreloadEntry{ + QDir::cleanPath(qtQmlPath + "/" + relativePath + "/" + "qmldir"), + QDir::cleanPath(qtDeployQmlPath + "/" + relativePath + "/" + "qmldir") }); + } + } + + return res; +} + +}; // namespace JsonTools diff --git a/src/tools/wasmdeployqt/jsontools.h b/src/tools/wasmdeployqt/jsontools.h new file mode 100644 index 00000000000..a1691a2be8d --- /dev/null +++ b/src/tools/wasmdeployqt/jsontools.h @@ -0,0 +1,19 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef JSONTOOLS_H +#define JSONTOOLS_H + +#include <QFileInfo> +#include <QSet> + +#include "common.h" + +#include <optional> + +namespace JsonTools { +bool savePreloadFile(QSet<PreloadEntry> preload, QString destFile); +std::optional<QSet<PreloadEntry>> getPreloadsFromQmlImportScannerOutput(QString output); +}; // namespace JsonTools + +#endif diff --git a/src/tools/wasmdeployqt/main.cpp b/src/tools/wasmdeployqt/main.cpp new file mode 100644 index 00000000000..3bf2647cfaf --- /dev/null +++ b/src/tools/wasmdeployqt/main.cpp @@ -0,0 +1,417 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "common.h" +#include "jsontools.h" +#include "wasmbinary.h" + +#include <QCoreApplication> +#include <QDir> +#include <QDirListing> +#include <QDirIterator> +#include <QtGlobal> +#include <QLibraryInfo> +#include <QJsonDocument> +#include <QStringList> +#include <QtCore/QCommandLineOption> +#include <QtCore/QCommandLineParser> +#include <QtCore/QProcess> +#include <QQueue> +#include <QMap> +#include <QSet> + +#include <optional> +#include <iostream> +#include <ostream> + +struct Parameters +{ + std::optional<QString> argAppPath; + QString appWasmPath; + std::optional<QDir> qtHostDir; + std::optional<QDir> qtWasmDir; + QList<QDir> libPaths; + std::optional<QDir> qmlRootPath; + + QSet<QString> loadedQtLibraries; +}; + +bool parseArguments(Parameters ¶ms) +{ + QCoreApplication::setApplicationName("wasmdeployqt"); + QCoreApplication::setApplicationVersion("1.0"); + QCommandLineParser parser; + parser.setApplicationDescription( + QStringLiteral("Qt for WebAssembly deployment tool \n\n" + "Example:\n" + "wasmdeployqt app.wasm --qml-root-path=repo/myapp " + "--qt-wasm-dir=/home/user/qt/shared-qt-wasm/bin")); + parser.addHelpOption(); + + QStringList args = QCoreApplication::arguments(); + + parser.addPositionalArgument("app", "Path to the application."); + QCommandLineOption libPathOption("lib-path", "Colon-separated list of library directories.", + "paths"); + parser.addOption(libPathOption); + QCommandLineOption qtWasmDirOption("qt-wasm-dir", "Path to the Qt for WebAssembly directory.", + "dir"); + parser.addOption(qtWasmDirOption); + QCommandLineOption qtHostDirOption("qt-host-dir", "Path to the Qt host directory.", "dir"); + parser.addOption(qtHostDirOption); + QCommandLineOption qmlRootPathOption("qml-root-path", "Root directory for QML files.", "dir"); + parser.addOption(qmlRootPathOption); + parser.process(args); + + const QStringList positionalArgs = parser.positionalArguments(); + if (positionalArgs.size() > 1) { + std::cout << "ERROR: Expected only one positional argument with path to the app. Received: " + << positionalArgs.join(" ").toStdString() << std::endl; + return false; + } + if (!positionalArgs.isEmpty()) { + params.argAppPath = positionalArgs.first(); + } + + if (parser.isSet(libPathOption)) { + QStringList paths = parser.value(libPathOption).split(';', Qt::SkipEmptyParts); + for (const QString &path : paths) { + QDir dir(path); + if (dir.exists()) { + params.libPaths.append(dir); + } else { + std::cout << "ERROR: Directory does not exist: " << path.toStdString() << std::endl; + return false; + } + } + } + if (parser.isSet(qtWasmDirOption)) { + QDir dir(parser.value(qtWasmDirOption)); + if (dir.cdUp() && dir.exists()) + params.qtWasmDir = dir; + else { + std::cout << "ERROR: Directory does not exist: " << dir.absolutePath().toStdString() + << std::endl; + return false; + } + } + if (parser.isSet(qtHostDirOption)) { + QDir dir(parser.value(qtHostDirOption)); + if (dir.cdUp() && dir.exists()) + params.qtHostDir = dir; + else { + std::cout << "ERROR: Directory does not exist: " << dir.absolutePath().toStdString() + << std::endl; + return false; + } + } + if (parser.isSet(qmlRootPathOption)) { + QDir dir(parser.value(qmlRootPathOption)); + if (dir.exists()) { + params.qmlRootPath = dir; + } else { + std::cout << "ERROR: Directory specified for qml-root-path does not exist: " + << dir.absolutePath().toStdString() << std::endl; + return false; + } + } + return true; +} + +std::optional<QString> detectAppName() +{ + QDirIterator it(QDir::currentPath(), QStringList() << "*.html" << "*.wasm" << "*.js", + QDir::NoFilter); + QMap<QString, QSet<QString>> fileGroups; + while (it.hasNext()) { + QFileInfo fileInfo(it.next()); + QString baseName = fileInfo.completeBaseName(); + QString suffix = fileInfo.suffix(); + fileGroups[baseName].insert(suffix); + } + for (auto it = fileGroups.constBegin(); it != fileGroups.constEnd(); ++it) { + const QSet<QString> &extensions = it.value(); + if (extensions.contains("html") && extensions.contains("js") + && extensions.contains("wasm")) { + return it.key(); + } + } + return std::nullopt; +} + +bool verifyPaths(Parameters ¶ms) +{ + if (params.argAppPath) { + QFileInfo fileInfo(*params.argAppPath); + if (!fileInfo.exists()) { + std::cout << "ERROR: Cannot find " << params.argAppPath->toStdString() << std::endl; + std::cout << "Make sure that the path is valid." << std::endl; + return false; + } + params.appWasmPath = fileInfo.absoluteFilePath(); + } else { + auto appName = detectAppName(); + if (!appName) { + std::cout << "ERROR: Cannot find the application in current directory. Specify the " + "path as an argument:" + "wasmdeployqt <path-to-app-wasm-binary>" + << std::endl; + return false; + } + params.appWasmPath = QDir::current().filePath(*appName + ".wasm"); + std::cout << "Automatically detected " << params.appWasmPath.toStdString() << std::endl; + } + if (!params.qtWasmDir) { + std::cout << "ERROR: Please set path to Qt WebAssembly installation as " + "--qt-wasm-dir=<path_to_qt_wasm_bin>" + << std::endl; + return false; + } + if (!params.qtHostDir) { + auto qtHostPath = QLibraryInfo::path(QLibraryInfo::BinariesPath); + if (qtHostPath.length() == 0) { + std::cout << "ERROR: Cannot read Qt host path or detect it from environment. Please " + "pass it explicitly with --qt-host-dir=<path>. " + << std::endl; + } else { + auto qtHostDir = QDir(qtHostPath); + if (!qtHostDir.cdUp()) { + std::cout << "ERROR: Invalid Qt host path: " + << qtHostDir.absolutePath().toStdString() << std::endl; + return false; + } + params.qtHostDir = qtHostDir; + } + } + params.libPaths.push_front(params.qtWasmDir->filePath("lib")); + params.libPaths.push_front(*params.qtWasmDir); + return true; +} + +bool copyFile(QString srcPath, QString destPath) +{ + auto file = QFile(destPath); + if (file.exists()) { + file.remove(); + } + QFileInfo destInfo(destPath); + if (!QDir().mkpath(destInfo.path())) { + std::cout << "ERROR: Cannot create path " << destInfo.path().toStdString() << std::endl; + return false; + } + if (!QFile::copy(srcPath, destPath)) { + + std::cout << "ERROR: Failed to copy " << srcPath.toStdString() << " to " + << destPath.toStdString() << std::endl; + + return false; + } + return true; +} + +bool copyDirectDependencies(QList<QString> dependencies, const Parameters ¶ms) +{ + for (auto &&depFilename : dependencies) { + if (params.loadedQtLibraries.contains(depFilename)) { + continue; // dont copy library that has been already copied + } + + std::optional<QString> libPath; + for (auto &&libDir : params.libPaths) { + auto path = libDir.filePath(depFilename); + QFileInfo file(path); + if (file.exists()) { + libPath = path; + } + } + if (!libPath) { + std::cout << "ERROR: Cannot find required library " << depFilename.toStdString() + << std::endl; + return false; + } + if (!copyFile(*libPath, QDir::current().filePath(depFilename))) + return false; + } + std::cout << "INFO: Succesfully copied direct dependencies." << std::endl; + return true; +} + +QStringList findSoFiles(const QString &directory) +{ + QStringList soFiles; + QDir baseDir(directory); + if (!baseDir.exists()) + return soFiles; + + QDirIterator it(directory, QStringList() << "*.so", QDir::Files, QDirIterator::Subdirectories); + while (it.hasNext()) { + it.next(); + QString absPath = it.filePath(); + QString filePath = baseDir.relativeFilePath(absPath); + soFiles.append(filePath); + } + return soFiles; +} + +bool copyQtLibs(Parameters ¶ms) +{ + Q_ASSERT(params.qtWasmDir); + auto qtLibDir = *params.qtWasmDir; + if (!qtLibDir.cd("lib")) { + std::cout << "ERROR: Cannot find lib directory in Qt installation." << std::endl; + return false; + } + auto qtLibTargetDir = QDir(QDir(QDir::current().filePath("qt")).filePath("lib")); + + auto soFiles = findSoFiles(qtLibDir.absolutePath()); + for (auto &&soFilePath : soFiles) { + auto relativeFilePath = QDir("lib").filePath(soFilePath); + auto srcPath = qtLibDir.absoluteFilePath(soFilePath); + auto destPath = qtLibTargetDir.absoluteFilePath(soFilePath); + if (!copyFile(srcPath, destPath)) + return false; + params.loadedQtLibraries.insert(QFileInfo(srcPath).fileName()); + } + std::cout << "INFO: Succesfully deployed qt lib shared objects." << std::endl; + return true; +} + +bool copyPreloadPlugins(Parameters ¶ms) +{ + Q_ASSERT(params.qtWasmDir); + auto qtPluginsDir = *params.qtWasmDir; + if (!qtPluginsDir.cd("plugins")) { + std::cout << "ERROR: Cannot find plugins directory in Qt installation." << std::endl; + return false; + } + auto qtPluginsTargetDir = QDir(QDir(QDir::current().filePath("qt")).filePath("plugins")); + + // copy files + auto soFiles = findSoFiles(qtPluginsDir.absolutePath()); + for (auto &&soFilePath : soFiles) { + auto relativeFilePath = QDir("plugins").filePath(soFilePath); + params.loadedQtLibraries.insert(QFileInfo(relativeFilePath).fileName()); + auto srcPath = qtPluginsDir.absoluteFilePath(soFilePath); + auto destPath = qtPluginsTargetDir.absoluteFilePath(soFilePath); + if (!copyFile(srcPath, destPath)) + return false; + } + + // qt_plugins.json + QSet<PreloadEntry> preload{ { { "qt.conf" }, { "/qt.conf" } } }; + for (auto &&plugin : soFiles) { + PreloadEntry entry; + entry.source = QDir("$QTDIR").filePath("plugins") + QDir::separator() + + QDir(qtPluginsDir).relativeFilePath(plugin); + entry.destination = "/qt/plugins/" + QDir(qtPluginsTargetDir).relativeFilePath(plugin); + preload.insert(entry); + } + JsonTools::savePreloadFile(preload, QDir::current().filePath("qt_plugins.json")); + + QString qtconfContent = "[Paths]\nPrefix = /qt\n"; + QString filePath = QDir::current().filePath("qt.conf"); + + QFile file(filePath); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&file); + out << qtconfContent; + if (!file.flush()) { + std::cout << "ERROR: Failed flushing the file :" << file.fileName().toStdString() + << std::endl; + return false; + } + file.close(); + } else { + std::cout << "ERROR: Failed to write to qt.conf." << std::endl; + return false; + } + std::cout << "INFO: Succesfully deployed qt plugins." << std::endl; + return true; +} + +bool copyPreloadQmlImports(Parameters ¶ms) +{ + Q_ASSERT(params.qtWasmDir); + if (!params.qmlRootPath) { + std::cout << "WARNING: qml-root-path not specified. Skipping generating preloads for QML " + "imports." + << std::endl; + std::cout << "WARNING: This may lead to erronous behaviour if applications requires QML " + "imports." + << std::endl; + QSet<PreloadEntry> preload; + JsonTools::savePreloadFile(preload, QDir::current().filePath("qt_qml_imports.json")); + return true; + } + auto qmlImportScannerPath = params.qtHostDir + ? QDir(params.qtHostDir->filePath("libexec")).filePath("qmlimportscanner") + : "qmlimportscanner"; + QProcess process; + auto qmlImportPath = *params.qtWasmDir; + qmlImportPath.cd("qml"); + if (!qmlImportPath.exists()) { + std::cout << "ERROR: Cannot find qml import path: " + << qmlImportPath.absolutePath().toStdString() << std::endl; + return -1; + } + + QStringList args{ "-rootPath", params.qmlRootPath->absolutePath(), "-importPath", + qmlImportPath.absolutePath() }; + process.start(qmlImportScannerPath, args); + if (!process.waitForFinished()) { + std::cout << "ERROR: Failed to execute qmlImportScanner." << std::endl; + return false; + } + + QString stdoutOutput = process.readAllStandardOutput(); + auto qmlImports = JsonTools::getPreloadsFromQmlImportScannerOutput(stdoutOutput); + if (!qmlImports) { + return false; + } + JsonTools::savePreloadFile(*qmlImports, QDir::current().filePath("qt_qml_imports.json")); + for (const PreloadEntry &import : *qmlImports) { + auto relativePath = import.source; + relativePath.remove("$QTDIR/"); + + auto srcPath = params.qtWasmDir->absoluteFilePath(relativePath); + auto destPath = QDir(QDir::current().filePath("qt")).absoluteFilePath(relativePath); + if (!copyFile(srcPath, destPath)) + return false; + } + std::cout << "INFO: Succesfully deployed qml imports." << std::endl; + return true; +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + Parameters params; + if (!parseArguments(params)) { + return -1; + } + if (!verifyPaths(params)) { + return -1; + } + std::cout << "INFO: Target: " << params.appWasmPath.toStdString() << std::endl; + WasmBinary wasmBinary(params.appWasmPath); + if (wasmBinary.type == WasmBinary::Type::INVALID) { + return -1; + } else if (wasmBinary.type == WasmBinary::Type::STATIC) { + std::cout << "INFO: This is statically linked WebAssembly binary." << std::endl; + std::cout << "INFO: No extra steps required!" << std::endl; + return 0; + } + std::cout << "INFO: Verified as shared module." << std::endl; + + if (!copyQtLibs(params)) + return -1; + if (!copyPreloadPlugins(params)) + return -1; + if (!copyPreloadQmlImports(params)) + return -1; + if (!copyDirectDependencies(wasmBinary.dependencies, params)) + return -1; + + std::cout << "INFO: Deployment done!" << std::endl; + return 0; +} diff --git a/src/tools/wasmdeployqt/wasmbinary.cpp b/src/tools/wasmdeployqt/wasmbinary.cpp new file mode 100644 index 00000000000..1a041c94066 --- /dev/null +++ b/src/tools/wasmdeployqt/wasmbinary.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "wasmbinary.h" + +#include <QFile> + +#include <iostream> + +WasmBinary::WasmBinary(QString filepath) +{ + QFile file(filepath); + if (!file.open(QIODevice::ReadOnly)) { + std::cout << "ERROR: Cannot open the file " << filepath.toStdString() << std::endl; + std::cout << file.errorString().toStdString() << std::endl; + type = WasmBinary::Type::INVALID; + return; + } + auto bytes = file.readAll(); + if (!parsePreambule(bytes)) { + type = WasmBinary::Type::INVALID; + } +} + +bool WasmBinary::parsePreambule(QByteArrayView data) +{ + const auto preambuleSize = 24; + if (data.size() < preambuleSize) { + std::cout << "ERROR: Preambule of binary shorter than expected!" << std::endl; + return false; + } + uint32_t int32View[6]; + std::memcpy(int32View, data.data(), sizeof(int32View)); + if (int32View[0] != 0x6d736100) { + std::cout << "ERROR: Magic WASM number not found in binary. Binary corrupted?" << std::endl; + return false; + } + if (data[8] != 0) { + type = WasmBinary::Type::STATIC; + return true; + } else { + type = WasmBinary::Type::SHARED; + } + const auto sectionStart = 9; + size_t offset = sectionStart; + auto sectionSize = getLeb(data, offset); + auto sectionEnd = sectionStart + sectionSize; + auto name = getString(data, offset); + if (name != "dylink.0") { + type = WasmBinary::Type::INVALID; + std::cout << "ERROR: dylink.0 was not found in supposedly dynamically linked module" + << std::endl; + return false; + } + + const auto WASM_DYLINK_NEEDED = 0x2; + while (offset < sectionEnd) { + auto subsectionType = data[offset++]; + auto subsectionSize = getLeb(data, offset); + if (subsectionType == WASM_DYLINK_NEEDED) { + auto neededDynlibsCount = getLeb(data, offset); + while (neededDynlibsCount--) { + dependencies.append(getString(data, offset)); + } + } else { + offset += subsectionSize; + } + } + return true; +} + +size_t WasmBinary::getLeb(QByteArrayView data, size_t &offset) +{ + auto ret = 0; + auto mul = 1; + while (true) { + auto byte = data[offset++]; + ret += (byte & 0x7f) * mul; + mul *= 0x80; + if (!(byte & 0x80)) + break; + } + return ret; +} + +QString WasmBinary::getString(QByteArrayView data, size_t &offset) +{ + auto length = getLeb(data, offset); + offset += length; + return QString::fromUtf8(data.sliced(offset - length, length)); +} diff --git a/src/tools/wasmdeployqt/wasmbinary.h b/src/tools/wasmdeployqt/wasmbinary.h new file mode 100644 index 00000000000..c3bb3f0eaa4 --- /dev/null +++ b/src/tools/wasmdeployqt/wasmbinary.h @@ -0,0 +1,24 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef WASMBINARY_H +#define WASMBINARY_H + +#include <QString> +#include <QList> + +class WasmBinary +{ +public: + enum class Type { INVALID, STATIC, SHARED }; + WasmBinary(QString filepath); + Type type; + QList<QString> dependencies; + +private: + bool parsePreambule(QByteArrayView data); + size_t getLeb(QByteArrayView data, size_t &offset); + QString getString(QByteArrayView data, size_t &offset); +}; + +#endif diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp index e57cc732ee2..820a7b4bdb5 100644 --- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp @@ -7,7 +7,6 @@ #include <qfile.h> #include <qdatetime.h> #include <qdir.h> -#include <qset.h> #include <qstandardpaths.h> #include <qstring.h> #include <qtemporarydir.h> @@ -15,6 +14,9 @@ #include <QtTest/private/qtesthelpers_p.h> +#include <QtCore/private/qduplicatetracker_p.h> +#include <QtCore/qscopeguard.h> + #if defined(Q_OS_WIN) # include <shlwapi.h> # include <qt_windows.h> @@ -549,18 +551,20 @@ void tst_QTemporaryFile::openOnRootDrives() void tst_QTemporaryFile::stressTest() { - const int iterations = 1000; + constexpr int iterations = 1000; + + QDuplicateTracker<QString, iterations> names; + + const auto remover = qScopeGuard([&] { + for (const QString &s : std::as_const(names)) + QFile::remove(s); + }); - QSet<QString> names; for (int i = 0; i < iterations; ++i) { QTemporaryFile file; file.setAutoRemove(false); QVERIFY2(file.open(), qPrintable(file.errorString())); - QVERIFY(!names.contains(file.fileName())); - names.insert(file.fileName()); - } - for (QSet<QString>::const_iterator it = names.constBegin(); it != names.constEnd(); ++it) { - QFile::remove(*it); + QVERIFY(!names.hasSeen(file.fileName())); } } @@ -821,37 +825,26 @@ void tst_QTemporaryFile::autoRemoveAfterFailedRename() #if defined(Q_OS_VXWORKS) QSKIP("QTBUG-130066"); #endif - struct CleanOnReturn - { - ~CleanOnReturn() - { + + QString tempName; + auto cleaner = qScopeGuard([&] { if (!tempName.isEmpty()) QFile::remove(tempName); - } - - void reset() - { - tempName.clear(); - } - - QString tempName; - }; - - CleanOnReturn cleaner; + }); { QTemporaryFile file; QVERIFY( file.open() ); - cleaner.tempName = file.fileName(); + tempName = file.fileName(); - QVERIFY( QFile::exists(cleaner.tempName) ); + QVERIFY(QFile::exists(tempName)); QVERIFY( !QFileInfo("i-do-not-exist").isDir() ); QVERIFY( !file.rename("i-do-not-exist/file.txt") ); - QVERIFY( QFile::exists(cleaner.tempName) ); + QVERIFY(QFile::exists(tempName)); } - QVERIFY( !QFile::exists(cleaner.tempName) ); - cleaner.reset(); + QVERIFY(!QFile::exists(tempName)); + cleaner.dismiss(); // would fail: file is known to no longer exist } void tst_QTemporaryFile::createNativeFile_data() diff --git a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp index 0254cbd1360..f03be6cc69e 100644 --- a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp +++ b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp @@ -23,6 +23,8 @@ #include "../../../network-settings.h" #include <QtTest/private/qemulationdetector_p.h> +using namespace Qt::StringLiterals; + QT_BEGIN_NAMESPACE template<> struct QMetaTypeId<QIODevice::OpenModeFlag> { enum { Defined = 1 }; static inline int qt_metatype_id() { return QMetaType::Int; } }; @@ -1379,12 +1381,12 @@ void tst_QTextStream::pos2() // ------------------------------------------------------------------------------ void tst_QTextStream::pos3LargeFile() { + // NOTE: The unusual spacing is to ensure non-1-character whitespace. + constexpr auto lineString = " 0 1 2\t3 4\t \t5 6 7 8 9 \n"_L1; { QFile file(testFileName); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream out( &file ); - // NOTE: The unusual spacing is to ensure non-1-character whitespace. - QString lineString = " 0 1 2\t3 4\t \t5 6 7 8 9 \n"; // Approximately 5kb text file (more is too slow (QTBUG-138435)) const int NbLines = (5 * 1024) / lineString.size() + 1; for (int line = 0; line < NbLines; ++line) @@ -1395,8 +1397,15 @@ void tst_QTextStream::pos3LargeFile() QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); QTextStream in( &file ); constexpr int testValues[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + qint64 expectedLineEnd = 0; +#ifdef Q_OS_WIN // CRLF platform + constexpr int crlfAdjustment = 1; +#else + constexpr int crlfAdjustment = 0; +#endif + const auto expectedLineLength = lineString.size() + crlfAdjustment; + QCOMPARE(in.pos(), 0); while (true) { - in.pos(); for (size_t i = 0; i < std::size(testValues); ++i) { int value = -42; if (!(in >> value)) { @@ -1407,6 +1416,9 @@ void tst_QTextStream::pos3LargeFile() } QCOMPARE(value, testValues[i]); } + expectedLineEnd += expectedLineLength; + // Final space and newline are not consumed until next read. + QCOMPARE(in.pos(), expectedLineEnd - 2 - crlfAdjustment); } } @@ -2997,14 +3009,41 @@ void tst_QTextStream::int_write_with_locale_data() QTest::addColumn<int>("numberFlags"); QTest::addColumn<int>("input"); QTest::addColumn<QString>("output"); + QTest::addColumn<int>("fieldWidth"); + QTest::addColumn<QTextStream::FieldAlignment>("fieldAlignment"); + + const auto alignDefault = QTextStream().fieldAlignment(); + constexpr int forceSign = QTextStream::ForceSign; + + QTest::newRow("C -123") << u"C"_s << 0 << -123 << u"-123"_s << 0 << alignDefault; + QTest::newRow("C +123") << u"C"_s << forceSign << 123 << u"+123"_s << 0 << alignDefault; + QTest::newRow("C 12345") << u"C"_s << 0 << 12345 << u"12345"_s << 0 << alignDefault; - QTest::newRow("C -123") << QString("C") << 0 << -123 << QString("-123"); - QTest::newRow("C +123") << QString("C") << (int)QTextStream::ForceSign << 123 << QString("+123"); - QTest::newRow("C 12345") << QString("C") << 0 << 12345 << QString("12345"); + QTest::newRow("de_DE -123") << u"de_DE"_s << 0 << -123 << u"-123"_s << 0 << alignDefault; + QTest::newRow("de_DE +123") << u"de_DE"_s << forceSign << 123 << u"+123"_s << 0 << alignDefault; + QTest::newRow("de_DE 12345") << u"de_DE"_s << 0 << 12345 << u"12.345"_s << 0 << alignDefault; - QTest::newRow("de_DE -123") << QString("de_DE") << 0 << -123 << QString("-123"); - QTest::newRow("de_DE +123") << QString("de_DE") << (int)QTextStream::ForceSign << 123 << QString("+123"); - QTest::newRow("de_DE 12345") << QString("de_DE") << 0 << 12345 << QString("12.345"); + constexpr auto alignAccountingStyle = QTextStream::FieldAlignment::AlignAccountingStyle; + + { + const QLocale loc("ar_EG"_L1); + // Arabic as spoken in Egypt has a two-code-point negativeSign(): + const auto minus = loc.negativeSign(); + QCOMPARE(minus.size(), 2); + // ditto positiveSign(): + const auto plus = loc.positiveSign(); + QCOMPARE(plus.size(), 2); + + QTest::addRow("ar_EG -123") << u"ar_EG"_s << 0 << -123 + << (minus + u" ١٢٣") + << 10 << alignAccountingStyle; + QTest::newRow("ar_EG +123") << u"ar_EG"_s << forceSign << 123 + << (plus + u" ١٢٣") + << 10 << alignAccountingStyle; + QTest::newRow("ar_EG 12345") << u"ar_EG"_s << 0 << 12345 + << u" ١٢٬٣٤٥"_s + << 10 << alignAccountingStyle; + } } void tst_QTextStream::int_write_with_locale() @@ -3013,13 +3052,21 @@ void tst_QTextStream::int_write_with_locale() QFETCH(int, numberFlags); QFETCH(int, input); QFETCH(QString, output); + QFETCH(const int, fieldWidth); + QFETCH(const QTextStream::FieldAlignment, fieldAlignment); QString result; QTextStream stream(&result); stream.setLocale(QLocale(locale)); + stream.setFieldAlignment(fieldAlignment); if (numberFlags) stream.setNumberFlags(QTextStream::NumberFlags(numberFlags)); + if (fieldWidth) + stream.setFieldWidth(fieldWidth); + QVERIFY(stream << input); + QEXPECT_FAIL("ar_EG -123", "QTBUG-138484", Continue); + QEXPECT_FAIL("ar_EG +123", "QTBUG-138484", Continue); QCOMPARE(result, output); } diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index bfc6074689b..50e17728cf3 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -78,6 +78,9 @@ private slots: void negativeZero_data(); void negativeZero(); + void signsNeverCompareEqualToNullCharacter_data() { testNames_data(); } + void signsNeverCompareEqualToNullCharacter(); + void dayOfWeek(); void dayOfWeek_data(); void formatDate(); @@ -2114,6 +2117,19 @@ void tst_QLocale::negativeZero() QCOMPARE(locale.toString(std::copysign(0.0, -1.0)), expect); } +void tst_QLocale::signsNeverCompareEqualToNullCharacter() // otherwise QTextStream has a problem +{ + QFETCH(QLocale::Language, language); + QFETCH(const QLocale::Territory, country); + + if (language == QLocale::AnyLanguage && country == QLocale::AnyTerritory) + language = QLocale::C; + + const QLocale loc(language, country); + QCOMPARE_NE(loc.negativeSign(), QChar()); + QCOMPARE_NE(loc.positiveSign(), QChar()); +} + void tst_QLocale::dayOfWeek_data() { QTest::addColumn<QDate>("date"); diff --git a/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp b/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp index eecc8b52d28..bd95174c932 100644 --- a/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp +++ b/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp @@ -120,6 +120,11 @@ void tst_QDuplicateTracker::appendTo() QList<int> b; tracker.appendTo(b); + // iteration order is append order: + QVERIFY(std::equal(b.cbegin(), b.cend(), + tracker.cbegin(), tracker.cend())); + QVERIFY(std::equal(b.cbegin(), b.cend(), + tracker.begin(), tracker.end())); std::sort(b.begin(), b.end()); QCOMPARE(b, QList<int>({ 0, 1 })); diff --git a/tests/auto/dbus/qdbusconnection/CMakeLists.txt b/tests/auto/dbus/qdbusconnection/CMakeLists.txt index 56ae21f2911..cbbe76a7dc7 100644 --- a/tests/auto/dbus/qdbusconnection/CMakeLists.txt +++ b/tests/auto/dbus/qdbusconnection/CMakeLists.txt @@ -19,3 +19,15 @@ qt_internal_add_test(tst_qdbusconnection TESTDATA tst_qdbusconnection.conf ) + +qt_internal_add_executable(qdbusdelayeddeliveryreenablehelper + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" + SOURCES + qdbusdelayeddeliveryreenablehelper.cpp + LIBRARIES + Qt::DBus +) + +add_dependencies(tst_qdbusconnection + qdbusdelayeddeliveryreenablehelper +) diff --git a/tests/auto/dbus/qdbusconnection/qdbusdelayeddeliveryreenablehelper.cpp b/tests/auto/dbus/qdbusconnection/qdbusdelayeddeliveryreenablehelper.cpp new file mode 100644 index 00000000000..cd916d5b639 --- /dev/null +++ b/tests/auto/dbus/qdbusconnection/qdbusdelayeddeliveryreenablehelper.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2025 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtCore/QTimer> +#include <QtCore/QCoreApplication> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusMessage> + +#include <stdio.h> + +using namespace Qt::StringLiterals; +using namespace std::chrono_literals; + +static QString myInterface() +{ + return u"local.qdbusdelayeddeliveryreenablehelper"_s; +} + +static void makeSynchronousCall(QDBusConnection &conn) +{ + QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/", + "org.freedesktop.DBus.Peer", "Ping"); + conn.call(msg); +} + +static void emitSignal(QDBusConnection &conn) +{ + QDBusMessage msg = QDBusMessage::createSignal("/", myInterface(), "quit"); + conn.send(msg); +} + +int main(int argc, char **argv) +{ + // Open a connection to the bus *before* QCoreApplication exists; + // this will put the connection in delayed delivery mode + QDBusConnection session = QDBusConnection::sessionBus(); + if (!session.isConnected()) { + fprintf(stderr, "Session bus did not connect!"); + return 1; + } + makeSynchronousCall(session); + + QCoreApplication app(argc, argv); + QTimer::singleShot(15s, qApp, [] { + fprintf(stderr, "Did not receive signal.\n"); + qApp->exit(1); + }); + + // connect a remote, wildcard signal to qApp->quit() + session.connect(QString(), QString(), myInterface(), "quit", &app, SLOT(quit())); + + // send ourselves the signal to quit, via D-Bus + emitSignal(session); + + return app.exec(); +} diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp index ab750dff330..fe9214c5513 100644 --- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp +++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp @@ -13,11 +13,6 @@ #include <QDBusInterface> #include <QDBusConnectionInterface> -#ifdef Q_OS_UNIX -# include <sys/types.h> -# include <signal.h> -#endif - void MyObject::method(const QDBusMessage &msg) { path = msg.path(); @@ -1473,6 +1468,31 @@ void tst_QDBusConnection::parentClassSignal() QTRY_COMPARE(recv.signalsReceived, 2); } +// see also tst_qdbusconnection_delayed +void tst_QDBusConnection::delayedDeliveryReenabledAfterUsedInMainThread() +{ +#if !QT_CONFIG(process) + QSKIP("Test requires QProcess"); +#elif defined(HAS_HOOKSETUPFUNCTION) + QSKIP("No difference to run by tst_QDBusConnection"); +#else +# if defined(Q_OS_WIN) +# define EXE ".exe" +# else +# define EXE "" +# endif + if (!QCoreApplication::instance()) + QSKIP("Test requires a QCoreApplication"); + + QProcess process; + process.start(QFINDTESTDATA("qdbusdelayeddeliveryreenablehelper" EXE)); + QVERIFY2(process.waitForFinished(25000), qPrintable(process.errorString())); + QCOMPARE(process.readAllStandardError(), QString()); + QCOMPARE(process.exitCode(), 0); +# undef EXE +#endif +} + QString MyObject::path; QString MyObjectWithoutInterface::path; QString MyObjectWithoutInterface::interface; diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h index 4137859414c..dc37e3157b4 100644 --- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h +++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h @@ -126,6 +126,8 @@ private slots: void parentClassSignal(); + void delayedDeliveryReenabledAfterUsedInMainThread(); + public: QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; } bool callMethod(const QDBusConnection &conn, const QString &path); diff --git a/tests/benchmarks/corelib/CMakeLists.txt b/tests/benchmarks/corelib/CMakeLists.txt index 890cbcfc6b8..42e1d2cb96d 100644 --- a/tests/benchmarks/corelib/CMakeLists.txt +++ b/tests/benchmarks/corelib/CMakeLists.txt @@ -14,3 +14,4 @@ add_subdirectory(time) add_subdirectory(tools) add_subdirectory(plugin) add_subdirectory(serialization) +add_subdirectory(platform) diff --git a/tests/benchmarks/corelib/platform/CMakeLists.txt b/tests/benchmarks/corelib/platform/CMakeLists.txt new file mode 100644 index 00000000000..68844c1c8f7 --- /dev/null +++ b/tests/benchmarks/corelib/platform/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(ANDROID) + add_subdirectory(androiditemmodel) +endif() diff --git a/tests/benchmarks/corelib/platform/androiditemmodel/CMakeLists.txt b/tests/benchmarks/corelib/platform/androiditemmodel/CMakeLists.txt new file mode 100644 index 00000000000..b72d0564c1a --- /dev/null +++ b/tests/benchmarks/corelib/platform/androiditemmodel/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_androiditemmodel Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_bench_androiditemmodel LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_bench_androiditemmodel + SOURCES + tst_bench_androiditemmodel.cpp + LIBRARIES + Qt::Gui + Qt::CorePrivate +) + +set_property(TARGET tst_androiditemmodel PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/testdata +) diff --git a/tests/benchmarks/corelib/platform/androiditemmodel/testdata/src/org/qtproject/qt/android/benchmark/BenchQtAbstractItemModel.java b/tests/benchmarks/corelib/platform/androiditemmodel/testdata/src/org/qtproject/qt/android/benchmark/BenchQtAbstractItemModel.java new file mode 100644 index 00000000000..79b07b3fd04 --- /dev/null +++ b/tests/benchmarks/corelib/platform/androiditemmodel/testdata/src/org/qtproject/qt/android/benchmark/BenchQtAbstractItemModel.java @@ -0,0 +1,56 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +package org.qtproject.qt.android.benchmark; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.qtproject.qt.android.QtAbstractItemModel; +import org.qtproject.qt.android.QtModelIndex; + +public class BenchQtAbstractItemModel + extends QtAbstractItemModel +{ + int m_rows = 1; + int m_cols = 1; + + @Override + public int columnCount(QtModelIndex parent) + { + return m_cols; + } + + @Override + public Object data(QtModelIndex index, int role) + { + return null; + } + + @Override + public QtModelIndex index(int row, int column, QtModelIndex parent) + { + return createIndex(row, column, 0); + } + + @Override + public QtModelIndex parent(QtModelIndex qtModelIndex) + { + return new QtModelIndex(); + } + + @Override + public int rowCount(QtModelIndex parent) + { + return m_rows; + } + + @Override + public HashMap<Integer, String> roleNames() + { + final HashMap<Integer, String> roles = new HashMap<Integer, String>(); + roles.put(0, "integerRole"); + return roles; + } +} diff --git a/tests/benchmarks/corelib/platform/androiditemmodel/tst_bench_androiditemmodel.cpp b/tests/benchmarks/corelib/platform/androiditemmodel/tst_bench_androiditemmodel.cpp new file mode 100644 index 00000000000..c7079e147a7 --- /dev/null +++ b/tests/benchmarks/corelib/platform/androiditemmodel/tst_bench_androiditemmodel.cpp @@ -0,0 +1,144 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtTest/QTest> + +#include <QtCore/private/qandroiditemmodelproxy_p.h> +#include <QtCore/private/qandroidmodelindexproxy_p.h> +#include <QtCore/private/qandroidtypes_p.h> + +#include <QGuiApplication> +#include <QtCore/qabstractitemmodel.h> +#include <QtCore/qjniobject.h> +#include <QtCore/qjnitypes.h> +#include <QtCore/qstring.h> +#include <QSignalSpy> +#include <memory> + +using namespace Qt::Literals; + +Q_DECLARE_JNI_CLASS(BenchQtAbstractItemModel, + "org/qtproject/qt/android/benchmark/BenchQtAbstractItemModel") + +class BenchNativeAbstractItemModel : public QAbstractItemModel { + Q_OBJECT + int m_rows = 1; + int m_cols = 1; + + public: + + int columnCount(const QModelIndex &parent = QModelIndex()) const override { + return m_cols; + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const override { + return m_rows; + } + + QVariant data(const QModelIndex &index, int role) const override { + return QVariant(); + } + + QModelIndex index(int row, int column, const QModelIndex &parent) const override { + return createIndex(row, column, quintptr(0)); + } + + QModelIndex parent(const QModelIndex &index) const override + { + return QModelIndex(); + } + + QHash<int, QByteArray> roleNames() const override { + static QHash<int, QByteArray> roles = { + {0, "integerRole"} + }; + return roles; + } + +}; + +class tst_BenchAndroidItemModel : public QObject +{ + Q_OBJECT + QtJniTypes::BenchQtAbstractItemModel m_jModel; + std::unique_ptr<QAbstractItemModel> qProxy; + std::unique_ptr<QAbstractItemModel> nativeModel; + +private slots: + void init(); + + void proxiedData(); + void nativeData(); + + void proxiedRowCount(); + void nativeRowCount(); + + void proxiedColumnCount(); + void nativeColumnCount(); + + void proxiedIndex(); + void nativeIndex(); +}; + +void tst_BenchAndroidItemModel::init() +{ + m_jModel = QJniObject::construct<QtJniTypes::BenchQtAbstractItemModel>(); + QVERIFY(m_jModel.isValid()); + qProxy = std::unique_ptr<QAbstractItemModel>(QAndroidItemModelProxy::createNativeProxy(jModel)); + nativeModel = std::make_unique<BenchNativeAbstractItemModel>(); + QVERIFY(qProxy); +} + +void tst_BenchAndroidItemModel::proxiedData() +{ + QCOMPARE(qProxy->rowCount(), 1); + QCOMPARE(qProxy->columnCount(), 1); + + QModelIndex idx = qProxy->index(0, 0, QModelIndex()); + + QBENCHMARK { qProxy->data(idx, 0); } +} + +void tst_BenchAndroidItemModel::nativeData() +{ + QCOMPARE(nativeModel->rowCount(), 1); + QCOMPARE(nativeModel->columnCount(), 1); + + QModelIndex idx = nativeModel->index(0, 0, QModelIndex()); + + QBENCHMARK { nativeModel->data(idx, 0); } +} + +void tst_BenchAndroidItemModel::proxiedRowCount() +{ + QBENCHMARK { qProxy->rowCount(QModelIndex()); } +} + +void tst_BenchAndroidItemModel::nativeRowCount() +{ + QBENCHMARK { nativeModel->rowCount(QModelIndex()); } +} + +void tst_BenchAndroidItemModel::proxiedColumnCount() +{ + QBENCHMARK { qProxy->columnCount(QModelIndex()); } +} + +void tst_BenchAndroidItemModel::nativeColumnCount() +{ + QBENCHMARK { nativeModel->columnCount(QModelIndex()); } +} + +void tst_BenchAndroidItemModel::proxiedIndex() +{ + QBENCHMARK { qProxy->index(0, 0, QModelIndex()); } +} + +void tst_BenchAndroidItemModel::nativeIndex() +{ + QBENCHMARK { nativeModel->index(0, 0, QModelIndex()); } +} + +#include "tst_bench_androiditemmodel.moc" + +QTEST_MAIN(tst_BenchAndroidItemModel) diff --git a/tests/manual/wasm/eventloop/suspendresumecontrol_auto/main.cpp b/tests/manual/wasm/eventloop/suspendresumecontrol_auto/main.cpp index 59f1f00cc59..1fd6e0a0c4f 100644 --- a/tests/manual/wasm/eventloop/suspendresumecontrol_auto/main.cpp +++ b/tests/manual/wasm/eventloop/suspendresumecontrol_auto/main.cpp @@ -7,7 +7,7 @@ using namespace emscripten; -const int timerTimeout = 10; +const std::chrono::milliseconds timerTimeout{10}; // Test QWasmSuspendResumeControl suspend/resume and event processing, // via QWasmTimer native timer events. diff --git a/util/wasm/preload/generate_default_preloads.sh.in b/util/wasm/preload/generate_default_preloads.sh.in deleted file mode 100644 index b38d308fa45..00000000000 --- a/util/wasm/preload/generate_default_preloads.sh.in +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -TARGET_DIR="@TARGET_DIR@" -SOURCE_DIR="@SOURCE_DIR@" -QT_HOST_DIR="@QT_HOST_DIR@" -QT_WASM_DIR="@QT_WASM_DIR@" -QT_INSTALL_DIR="@QT_INSTALL_DIR@" - -python3 \ - "$QT_WASM_DIR/libexec/preload_qt_plugins.py" \ - "$QT_INSTALL_DIR" \ - "$TARGET_DIR" - -python3 \ - "$QT_WASM_DIR/libexec/preload_qml_imports.py" \ - "$SOURCE_DIR" \ - "$QT_HOST_DIR" \ - "$QT_INSTALL_DIR" \ - "$TARGET_DIR" diff --git a/util/wasm/preload/preload_qml_imports.py b/util/wasm/preload/preload_qml_imports.py deleted file mode 100755 index b78ef5ee744..00000000000 --- a/util/wasm/preload/preload_qml_imports.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2023 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -import os -import sys -import subprocess -import json - -# Paths to shared libraries and qml imports on the Qt installation on the web server. -# "$QTDIR" is replaced by qtloader.js at load time (defaults to "qt"), and makes -# possible to relocate the application build relative to the Qt build on the web server. -qt_lib_path = "$QTDIR/lib" -qt_qml_path = "$QTDIR/qml" - -# Path to QML imports on the in-memory file system provided by Emscripten. This script emits -# preload commands which copies QML imports to this directory. In addition, preload_qt_plugins.py -# creates (and preloads) a qt.conf file which makes Qt load QML plugins from this location. -qt_deploy_qml_path = "/qt/qml" - - -def preload_file(source, destination): - preload_files.append({"source": source, "destination": destination}) - - -def extract_preload_files_from_imports(imports): - libraries = [] - for qml_import in imports: - try: - relative_path = qml_import["relativePath"] - plugin = qml_import["plugin"] - - # plugin .so - plugin_filename = "lib" + plugin + ".so" - so_plugin_source_path = os.path.join( - qt_qml_path, relative_path, plugin_filename - ) - so_plugin_destination_path = os.path.join( - qt_deploy_qml_path, relative_path, plugin_filename - ) - - preload_file(so_plugin_source_path, so_plugin_destination_path) - so_plugin_qt_install_path = os.path.join( - qt_wasm_path, "qml", relative_path, plugin_filename - ) - - # qmldir file - qmldir_source_path = os.path.join(qt_qml_path, relative_path, "qmldir") - qmldir_destination_path = os.path.join( - qt_deploy_qml_path, relative_path, "qmldir" - ) - preload_file(qmldir_source_path, qmldir_destination_path) - except Exception as e: - continue - return libraries - - -if __name__ == "__main__": - if len(sys.argv) != 5: - print("Usage: python preload_qml_imports.py <qml-source-path> <qt-host-path> <qt-wasm-path> <output-dir>") - sys.exit(1) - - qml_source_path = sys.argv[1] - qt_host_path = sys.argv[2] - qt_wasm_path = sys.argv[3] - output_dir = sys.argv[4] - - qml_import_path = os.path.join(qt_wasm_path, "qml") - qmlimportsscanner_path = os.path.join(qt_host_path, "libexec/qmlimportscanner") - - command = [qmlimportsscanner_path, "-rootPath", qml_source_path, "-importPath", qml_import_path] - result = subprocess.run(command, stdout=subprocess.PIPE) - imports = json.loads(result.stdout) - - preload_files = [] - libraries = extract_preload_files_from_imports(imports) - - # Deploy plugin dependencies, that is, shared libraries used by the plugins. - # Skip some of the obvious libraries which will be - skip_libraries = [ - "libQt6Core.so", - "libQt6Gui.so", - "libQt6Quick.so", - "libQt6Qml.so" "libQt6Network.so", - "libQt6OpenGL.so", - ] - - libraries = set(libraries) - set(skip_libraries) - for library in libraries: - source = os.path.join(qt_lib_path, library) - # Emscripten looks for shared libraries on "/", shared libraries - # most be deployed there instead of at /qt/lib - destination = os.path.join("/", library) - preload_file(source, destination) - - with open(f"{output_dir}/qt_qml_imports.json", "w") as f: - f.write(json.dumps(preload_files, indent=2)) - diff --git a/util/wasm/preload/preload_qt_plugins.py b/util/wasm/preload/preload_qt_plugins.py deleted file mode 100755 index 4b9b3683a70..00000000000 --- a/util/wasm/preload/preload_qt_plugins.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2023 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -import os -import sys -import json - -# Path to plugins on the Qt installation on the web server. "$QTPATH" is replaced by qtloader.js -# at load time (defaults to "qt"), which makes it possible to relocate the application build relative -# to the Qt build on the web server. -qt_plugins_path = "$QTDIR/plugins" - -# Path to plugins on the in-memory file system provided by Emscripten. This script emits -# preload commands which copies plugins to this directory. -qt_deploy_plugins_path = "/qt/plugins" - - -def find_so_files(directory): - so_files = [] - for root, dirs, files in os.walk(directory): - for file in files: - if file.endswith(".so"): - relative_path = os.path.relpath(os.path.join(root, file), directory) - so_files.append(relative_path) - return so_files - - -if __name__ == "__main__": - if len(sys.argv) != 3: - print("Usage: python preload_qt_plugins.py <qt-wasm-path> <output-dir>") - sys.exit(1) - - qt_wasm_path = sys.argv[1] - output_dir = sys.argv[2] - - # preload all plugins - plugins = find_so_files(os.path.join(qt_wasm_path, "plugins")) - preload = [ - { - "source": os.path.join(qt_plugins_path, plugin), - "destination": os.path.join(qt_deploy_plugins_path, plugin), - } - for plugin in plugins - ] - - # Create and preload qt.conf which will tell Qt to look for plugins - # and QML imports in /qt/plugins and /qt/qml. The qt.conf file is - # written to the current directory. - qtconf = "[Paths]\nPrefix = /qt\n" - with open(f"{output_dir}/qt.conf", "w") as f: - f.write(qtconf) - preload.append({"source": "qt.conf", "destination": "/qt.conf"}) - - with open(f"{output_dir}/qt_plugins.json", "w") as f: - f.write(json.dumps(preload, indent=2)) - |