diff options
61 files changed, 1157 insertions, 536 deletions
diff --git a/cmake/QtAutoDetectHelpers.cmake b/cmake/QtAutoDetectHelpers.cmake index fe6087748d6..6e6473da641 100644 --- a/cmake/QtAutoDetectHelpers.cmake +++ b/cmake/QtAutoDetectHelpers.cmake @@ -64,6 +64,41 @@ function(qt_auto_detect_wasm) endif() endfunction() +# Handle assignment of CMAKE_POLICY_VERSION_MINIMUM for Android NDK cmake toolchain files shipped +# with NDK < r28, to avoid deprecation warnings. +# +# NOTE: If updating the version, also update +# qt_internal_get_android_qt_default_cmake_policy_version_minimum. +# +# Use a macro, to make propagation of the variable in the parent scope of the calling function +# easier. +macro(qt_auto_detect_set_android_cmake_policy_version_minimum is_android_detected) + if("${is_android_detected}" + AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0" + AND NOT QT_NO_SET_ANDROID_CMAKE_POLICY_VERSION_MINIMUM + ) + + if(QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM) + set(min_policy_version "${QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM}") + elseif(CMAKE_POLICY_VERSION_MINIMUM) + set(min_policy_version "${CMAKE_POLICY_VERSION_MINIMUM}") + else() + set(min_policy_version "3.10") + endif() + + message(DEBUG + "Setting CMAKE_POLICY_VERSION_MINIMUM to ${min_policy_version} for Android builds.") + + # Set the variable in the qtbase directory scope for easier reading. + set(CMAKE_POLICY_VERSION_MINIMUM "${min_policy_version}" PARENT_SCOPE) + + # Also set the environment variable, otherwise any try_compile project that's started + # by CMake itself, rather than Qt (e.g. compiler detection), will not inherit the + # assignment. + set(ENV{CMAKE_POLICY_VERSION_MINIMUM} "${min_policy_version}") + endif() +endmacro() + function(qt_auto_detect_android) # Don't assume an Android build if we're requesting to build Java documentation on the host. if(QT_BUILD_HOST_JAVA_DOCS) @@ -154,6 +189,8 @@ function(qt_auto_detect_android) elseif (QT_AUTODETECT_ANDROID) message(STATUS "Android build detected") endif() + + qt_auto_detect_set_android_cmake_policy_version_minimum("${android_detected}") endfunction() function(qt_auto_detect_vcpkg) diff --git a/cmake/QtBaseConfigureTests.cmake b/cmake/QtBaseConfigureTests.cmake index fcc3b1a3f1c..da97e2b4f8b 100644 --- a/cmake/QtBaseConfigureTests.cmake +++ b/cmake/QtBaseConfigureTests.cmake @@ -306,6 +306,36 @@ function(qt_internal_print_cmake_host_and_target_info) message(STATUS "CMAKE_SYSTEM_PROCESSOR: \"${CMAKE_SYSTEM_PROCESSOR}\"") message(STATUS "CMAKE_CROSSCOMPILING: \"${CMAKE_CROSSCOMPILING}\"") + + message(STATUS "CMAKE_CXX_COMPILER_ID: \"${CMAKE_CXX_COMPILER_ID}\"") + message(STATUS "CMAKE_CXX_COMPILER_VERSION: \"${CMAKE_CXX_COMPILER_VERSION}\"") + + # The variables might not be defined depending on platform and CMake version. + if(CMAKE_CXX_COMPILER_TARGET) + message(STATUS "CMAKE_CXX_COMPILER_TARGET: \"${CMAKE_CXX_COMPILER_TARGET}\"") + endif() + if(CMAKE_CXX_COMPILER_ARCHITECTURE_ID) + message(STATUS + "CMAKE_CXX_COMPILER_ARCHITECTURE_ID: \"${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}\"") + endif() + if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT) + message(STATUS + "CMAKE_CXX_COMPILER_FRONTEND_VARIANT: \"${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}\"") + endif() + + if(CMAKE_CXX_COMPILER_LINKER_ID) + message(STATUS "CMAKE_CXX_COMPILER_LINKER_ID: \"${CMAKE_CXX_COMPILER_LINKER_ID}\"") + endif() + + if(CMAKE_CXX_COMPILER_LINKER_VERSION) + message(STATUS + "CMAKE_CXX_COMPILER_LINKER_VERSION: \"${CMAKE_CXX_COMPILER_LINKER_VERSION}\"") + endif() + + if(CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT) + message(STATUS "CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT: " + "\"${CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT}\"") + endif() endfunction() qt_internal_print_cmake_host_and_target_info() diff --git a/cmake/QtCMakeVersionHelpers.cmake b/cmake/QtCMakeVersionHelpers.cmake index 3a3ba0fc750..73b40b4a610 100644 --- a/cmake/QtCMakeVersionHelpers.cmake +++ b/cmake/QtCMakeVersionHelpers.cmake @@ -300,3 +300,90 @@ function(qt_internal_upgrade_cmake_policies) qt_internal_get_max_new_policy_cmake_version(upper_version) cmake_minimum_required(VERSION ${lower_version}...${upper_version}) endfunction() + +# Get which version to use for CMAKE_POLICY_VERSION_MINIMUM on Android. +# Allow various overrides via QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM and reading an existing +# CMAKE_POLICY_VERSION_MINIMUM. +function(qt_internal_get_android_cmake_policy_version_minimum_value out_var) + if(QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM) + set(value "${QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM}") + elseif(CMAKE_POLICY_VERSION_MINIMUM) + set(value "${CMAKE_POLICY_VERSION_MINIMUM}") + else() + qt_internal_get_android_qt_default_cmake_policy_version_minimum(default_value) + set(value "${default_value}") + endif() + + set(${out_var} "${value}" PARENT_SCOPE) +endfunction() + +# NOTE: If updating the version, also update +# qt_auto_detect_set_android_cmake_policy_version_minimum. +function(qt_internal_get_android_qt_default_cmake_policy_version_minimum out_var) + set(${out_var} "3.10" PARENT_SCOPE) +endfunction() + +# Handle assignment of CMAKE_POLICY_VERSION_MINIMUM for Android NDK cmake toolchain files shipped +# with NDK < r28, to avoid deprecation warnings. +# See https://github.com/android/ndk/issues/2100 +# and https://android.googlesource.com/platform/ndk/+/799e5a2d44cc2cc6c7d67f52f2d67957944b7680 +# The function is to get the appropriate var asisgnment for try_compile calls, +# as well as writing it to the Qt generated toolchain file. +# Various opt-outs and opt-ins are provided via QT_NO_SET_ANDROID_CMAKE_POLICY_VERSION_MINIMUM +# and QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM. +# +# See also usage in qt_auto_detect_set_android_cmake_policy_version_minimum. +function(qt_internal_get_android_cmake_policy_version_minimum_assignment out_var) + set(option_args "") + set(single_args + TYPE + ) + set(multi_args "") + + cmake_parse_arguments(PARSE_ARGV 1 arg + "${option_args}" + "${single_args}" + "${multi_args}" + ) + _qt_internal_validate_all_args_are_parsed(arg) + + set(value "") + if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0" + AND NOT QT_NO_SET_ANDROID_CMAKE_POLICY_VERSION_MINIMUM + ) + qt_internal_get_android_cmake_policy_version_minimum_value(version) + + if(arg_TYPE STREQUAL "COMMAND_LINE") + set(value "-DCMAKE_POLICY_VERSION_MINIMUM=${version}") + + elseif(arg_TYPE STREQUAL "TOOLCHAIN_FILE_ASSIGNMENT") + set(value " +# Avoid deprecation warnings in Android ndk cmake toolchain file < r28 +set(__qt_initially_configured_android_cmake_policy_version_minimum \"${version}\") +if(CMAKE_VERSION VERSION_GREATER_EQUAL \"4.0\" + AND NOT QT_NO_SET_ANDROID_CMAKE_POLICY_VERSION_MINIMUM + ) + if(QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM) + set(__qt_toolchain_cmake_policy_version_minimum + \"\${QT_ANDROID_CMAKE_POLICY_VERSION_MINIMUM}\") + elseif(CMAKE_POLICY_VERSION_MINIMUM) + set(__qt_toolchain_cmake_policy_version_minimum + \"\${CMAKE_POLICY_VERSION_MINIMUM}\") + else() + set(__qt_toolchain_cmake_policy_version_minimum + \"\${__qt_initially_configured_android_cmake_policy_version_minimum}\") + endif() + set(CMAKE_POLICY_VERSION_MINIMUM \"\${__qt_toolchain_cmake_policy_version_minimum}\") + message(DEBUG + \"Setting CMAKE_POLICY_VERSION_MINIMUM to \" + \"\${__qt_toolchain_cmake_policy_version_minimum}\ in toolchain file.\") +endif() +") + else() + message(FATAL_ERROR "Unknown TYPE value '${arg_TYPE}'. " + " Supported values are COMMAND_LINE and VAR_ASSIGNMENT.") + endif() + endif() + + set(${out_var} "${value}" PARENT_SCOPE) +endfunction() diff --git a/cmake/QtFeature.cmake b/cmake/QtFeature.cmake index e8ae3dd5163..de0323214c5 100644 --- a/cmake/QtFeature.cmake +++ b/cmake/QtFeature.cmake @@ -1737,6 +1737,14 @@ function(qt_get_platform_try_compile_vars out_var) list(APPEND flags_cmd_line "-DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH:BOOL=OFF") endif() + if(ANDROID) + qt_internal_get_android_cmake_policy_version_minimum_assignment( + android_cmake_policy_version_minimum TYPE COMMAND_LINE) + if(android_cmake_policy_version_minimum) + list(APPEND flags_cmd_line "${android_cmake_policy_version_minimum}") + endif() + endif() + set("${out_var}" "${flags_cmd_line}" PARENT_SCOPE) endfunction() diff --git a/cmake/QtToolchainHelpers.cmake b/cmake/QtToolchainHelpers.cmake index 9407fd0ebe5..348a3c25603 100644 --- a/cmake/QtToolchainHelpers.cmake +++ b/cmake/QtToolchainHelpers.cmake @@ -309,6 +309,13 @@ endif()") " \"Please specify the toolchain file with -DQT_CHAINLOAD_TOOLCHAIN_FILE=<file>.\")") list(APPEND init_platform " endif()") list(APPEND init_platform "endif()") + + qt_internal_get_android_cmake_policy_version_minimum_assignment( + android_cmake_policy_version_minimum TYPE TOOLCHAIN_FILE_ASSIGNMENT) + if(android_cmake_policy_version_minimum) + list(APPEND init_platform "${android_cmake_policy_version_minimum}") + endif() + elseif(EMSCRIPTEN) list(APPEND init_platform "include(\${CMAKE_CURRENT_LIST_DIR}/QtPublicWasmToolchainHelpers.cmake) diff --git a/coin/instructions/vxworks_testrunner.yaml b/coin/instructions/vxworks_testrunner.yaml index e348290d6d4..177a2ce7cf1 100644 --- a/coin/instructions/vxworks_testrunner.yaml +++ b/coin/instructions/vxworks_testrunner.yaml @@ -7,7 +7,7 @@ instructions: #!/bin/bash # Seconds of serial silence before triggering an SSH probe; also the cadence for repeated probes - EMPTY_READ_GRACE=20 + EMPTY_READ_GRACE=60 # Maximum time (s) with no output while waiting; exceeding this triggers a timeout failure MAX_WAIT_TIME=700 @@ -15,8 +15,10 @@ instructions: quoted_args=`python3 -c 'import sys, shlex; print(shlex.join(sys.argv[2:]))' "$@"` ssh_cmd() { - LD_LIBRARY_PATH=/usr/lib ssh -n -q \ + LD_LIBRARY_PATH=/usr/lib ssh -n -q -T \ -o BatchMode=yes -o ConnectTimeout=1 -o HostKeyAlgorithms=+ssh-rsa \ + -o PreferredAuthentications=publickey \ + -o NumberOfPasswordPrompts=0 \ ${VXWORKS_SSH} "$@" </dev/null } @@ -90,13 +92,12 @@ instructions: echo $line done < /tmp/guest.out - echo "cmd cd $testdir" > /tmp/guest.in - sleep 1 + echo "cmd cd $testdir; echo done" > /tmp/guest.in # Empty line before result of cd read -t 1 line_cmd </tmp/guest.out - if read -t 5 cdline </tmp/guest.out; then + if read -t 1 cdline </tmp/guest.out; then cdline_clean=$(printf '%s' "$cdline" | tr -d '\r') if printf '%s' "$cdline_clean" | /usr/bin/grep -Eq 'error\s*='; then printf 'entering %s: %s\n' "$testdir" "$cdline_clean" @@ -139,10 +140,6 @@ instructions: read -t 1 line</tmp/guest.out echo "$line" exitcode=$(echo "$line" | sed -nr 's/qtest_in_vxworks_complete: (-?[0-9]+)/\1/gp' | tr -d '\r') - probe="$(ssh_probe_status)" - if [[ "$probe" != "FINISHED" ]]; then - echo "final SSH probe: ${probe}" - fi exit $exitcode fi diff --git a/examples/widgets/gallery/main.cpp b/examples/widgets/gallery/main.cpp index 95fffbdd3c1..b85706e1015 100644 --- a/examples/widgets/gallery/main.cpp +++ b/examples/widgets/gallery/main.cpp @@ -9,7 +9,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); - app.styleHints()->setColorScheme(Qt::ColorScheme::Dark); + QGuiApplication::styleHints()->setColorScheme(Qt::ColorScheme::Dark); WidgetGallery gallery; gallery.show(); return QCoreApplication::exec(); diff --git a/examples/widgets/gallery/widgetgallery.cpp b/examples/widgets/gallery/widgetgallery.cpp index deef6b42181..e2ffec50e81 100644 --- a/examples/widgets/gallery/widgetgallery.cpp +++ b/examples/widgets/gallery/widgetgallery.cpp @@ -13,10 +13,10 @@ #include <QFileSystemModel> #include <QGridLayout> #include <QGroupBox> -#include <QMenu> #include <QLabel> #include <QLineEdit> #include <QListWidget> +#include <QMenu> #include <QPlainTextEdit> #include <QProgressBar> #include <QPushButton> @@ -26,26 +26,30 @@ #include <QSpinBox> #include <QStandardItemModel> #include <QStyle> -#include <QStyleHints> #include <QStyleFactory> -#include <QTextBrowser> -#include <QTreeView> +#include <QStyleHints> #include <QTableWidget> +#include <QTextBrowser> #include <QTextEdit> #include <QToolBox> #include <QToolButton> +#include <QTreeView> -#include <QIcon> #include <QDesktopServices> +#include <QIcon> #include <QScreen> #include <QWindow> +#include <QAnyStringView> #include <QDebug> #include <QLibraryInfo> +#include <QStringView> #include <QSysInfo> #include <QTextStream> #include <QTimer> +using namespace Qt::StringLiterals; + static inline QString className(const QObject *o) { return QString::fromUtf8(o->metaObject()->className()); @@ -56,7 +60,7 @@ static inline void setClassNameToolTip(QWidget *w) w->setToolTip(className(w)); } -static QString helpUrl(const QString &page) +static QString helpUrl(QStringView page) { QString result; QTextStream(&result) << "https://doc.qt.io/qt-" << QT_VERSION_MAJOR @@ -76,23 +80,23 @@ static void launchHelp(const QWidget *w) static void launchModuleHelp() { - QDesktopServices::openUrl(helpUrl(QLatin1String("qtwidgets-index"))); + QDesktopServices::openUrl(helpUrl(u"qtwidgets-index")); } template <class Widget> -Widget *createWidget(const char *name, QWidget *parent = nullptr) +Widget *createWidget(QAnyStringView name, QWidget *parent = nullptr) { - auto result = new Widget(parent); - result->setObjectName(QLatin1String(name)); + auto *result = new Widget(parent); + result->setObjectName(name); setClassNameToolTip(result); return result; } template <class Widget, class Parameter> -Widget *createWidget1(const Parameter &p1, const char *name, QWidget *parent = nullptr) +Widget *createWidget1(const Parameter &p1, QAnyStringView name, QWidget *parent = nullptr) { - auto result = new Widget(p1, parent); - result->setObjectName(QLatin1String(name)); + auto *result = new Widget(p1, parent); + result->setObjectName(name); setClassNameToolTip(result); return result; } @@ -108,9 +112,9 @@ static QString highDpiScaleFactorRoundingPolicy() { QString result; QDebug(&result) << QGuiApplication::highDpiScaleFactorRoundingPolicy(); - if (result.endsWith(QLatin1Char(')'))) + if (result.endsWith(u')')) result.chop(1); - const int lastSep = result.lastIndexOf(QLatin1String("::")); + const auto lastSep = result.lastIndexOf("::"_L1); if (lastSep != -1) result.remove(0, lastSep + 2); return result; @@ -122,10 +126,10 @@ WidgetGallery::WidgetGallery(QWidget *parent) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - auto styleComboBox = createWidget<QComboBox>("styleComboBox"); + auto *styleComboBox = createWidget<QComboBox>("styleComboBox"); const QString defaultStyleName = QApplication::style()->objectName(); QStringList styleNames = QStyleFactory::keys(); - for (int i = 1, size = styleNames.size(); i < size; ++i) { + for (qsizetype i = 1, size = styleNames.size(); i < size; ++i) { if (defaultStyleName.compare(styleNames.at(i), Qt::CaseInsensitive) == 0) { styleNames.swapItemsAt(0, i); break; @@ -133,16 +137,16 @@ WidgetGallery::WidgetGallery(QWidget *parent) } styleComboBox->addItems(styleNames); - auto styleLabel = createWidget1<QLabel>(tr("&Style:"), "styleLabel"); + auto *styleLabel = createWidget1<QLabel>(tr("&Style:"), "styleLabel"); styleLabel->setBuddy(styleComboBox); - auto colorSchemeComboBox = createWidget<QComboBox>("colorSchemeComboBox"); + auto *colorSchemeComboBox = createWidget<QComboBox>("colorSchemeComboBox"); colorSchemeComboBox->addItem(tr("Auto")); colorSchemeComboBox->addItem(tr("Light")); colorSchemeComboBox->addItem(tr("Dark")); colorSchemeComboBox->setCurrentIndex(static_cast<int>(qApp->styleHints()->colorScheme())); - auto colorSchemeLabel = createWidget1<QLabel>(tr("&Color Scheme:"), "colorSchemeLabel"); + auto *colorSchemeLabel = createWidget1<QLabel>(tr("&Color Scheme:"), "colorSchemeLabel"); colorSchemeLabel->setBuddy(colorSchemeComboBox); connect(colorSchemeComboBox, &QComboBox::currentIndexChanged, this, [](int index){ @@ -150,15 +154,16 @@ WidgetGallery::WidgetGallery(QWidget *parent) }); const QKeySequence helpKeySequence(QKeySequence::HelpContents); - auto helpLabel = createWidget1<QLabel>(tr("Press <kbd>%1</kbd> over a widget to see Documentation") - .arg(helpKeySequence.toString(QKeySequence::NativeText)), "helpLabel"); + const QString helpText = tr("Press <kbd>%1</kbd> over a widget to see Documentation") + .arg(helpKeySequence.toString(QKeySequence::NativeText)); + auto *helpLabel = createWidget1<QLabel>(helpText, "helpLabel"); - auto disableWidgetsCheckBox = createWidget1<QCheckBox>(tr("&Disable widgets"), "disableWidgetsCheckBox"); + auto *disableWidgetsCheckBox = createWidget1<QCheckBox>(tr("&Disable widgets"), "disableWidgetsCheckBox"); - auto buttonsGroupBox = createButtonsGroupBox(); - auto itemViewTabWidget = createItemViewTabWidget(); - auto simpleInputWidgetsGroupBox = createSimpleInputWidgetsGroupBox(); - auto textToolBox = createTextToolBox(); + auto *buttonsGroupBox = createButtonsGroupBox(); + auto *itemViewTabWidget = createItemViewTabWidget(); + auto *simpleInputWidgetsGroupBox = createSimpleInputWidgetsGroupBox(); + auto *textToolBox = createTextToolBox(); connect(styleComboBox, &QComboBox::textActivated, this, &WidgetGallery::changeStyle); @@ -171,8 +176,8 @@ WidgetGallery::WidgetGallery(QWidget *parent) connect(disableWidgetsCheckBox, &QCheckBox::toggled, simpleInputWidgetsGroupBox, &QWidget::setDisabled); - auto topLayout = new QHBoxLayout; - auto appearanceLayout = new QGridLayout; + auto *topLayout = new QHBoxLayout; + auto *appearanceLayout = new QGridLayout; appearanceLayout->addWidget(styleLabel, 0, 0); appearanceLayout->addWidget(styleComboBox, 0, 1); appearanceLayout->addWidget(colorSchemeLabel, 1, 0); @@ -183,12 +188,12 @@ WidgetGallery::WidgetGallery(QWidget *parent) topLayout->addStretch(1); topLayout->addWidget(disableWidgetsCheckBox); - auto dialogButtonBox = createWidget1<QDialogButtonBox>(QDialogButtonBox::Help | QDialogButtonBox::Close, - "dialogButtonBox"); + auto *dialogButtonBox = createWidget1<QDialogButtonBox>( + QDialogButtonBox::Help | QDialogButtonBox::Close, "dialogButtonBox"); connect(dialogButtonBox, &QDialogButtonBox::helpRequested, this, launchModuleHelp); connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - auto mainLayout = new QGridLayout(this); + auto *mainLayout = new QGridLayout(this); mainLayout->addLayout(topLayout, 0, 0, 1, 2); mainLayout->addWidget(buttonsGroupBox, 1, 0); mainLayout->addWidget(simpleInputWidgetsGroupBox, 1, 1); @@ -225,38 +230,38 @@ void WidgetGallery::advanceProgressBar() QGroupBox *WidgetGallery::createButtonsGroupBox() { - auto result = createWidget1<QGroupBox>(tr("Buttons"), "buttonsGroupBox"); + auto *result = createWidget1<QGroupBox>(tr("Buttons"), "buttonsGroupBox"); - auto defaultPushButton = createWidget1<QPushButton>(tr("Default Push Button"), "defaultPushButton"); + auto *defaultPushButton = createWidget1<QPushButton>(tr("Default Push Button"), "defaultPushButton"); defaultPushButton->setDefault(true); - auto togglePushButton = createWidget1<QPushButton>(tr("Toggle Push Button"), "togglePushButton"); + auto *togglePushButton = createWidget1<QPushButton>(tr("Toggle Push Button"), "togglePushButton"); togglePushButton->setCheckable(true); togglePushButton->setChecked(true); - auto flatPushButton = createWidget1<QPushButton>(tr("Flat Push Button"), "flatPushButton"); + auto *flatPushButton = createWidget1<QPushButton>(tr("Flat Push Button"), "flatPushButton"); flatPushButton->setFlat(true); - auto toolButton = createWidget<QToolButton>("toolButton"); + auto *toolButton = createWidget<QToolButton>("toolButton"); toolButton->setText(tr("Tool Button")); - auto menuToolButton = createWidget<QToolButton>("menuButton"); + auto *menuToolButton = createWidget<QToolButton>("menuButton"); menuToolButton->setText(tr("Menu Button")); - auto toolMenu = new QMenu(menuToolButton); + auto *toolMenu = new QMenu(menuToolButton); menuToolButton->setPopupMode(QToolButton::InstantPopup); toolMenu->addAction("Option"); toolMenu->addSeparator(); - auto action = toolMenu->addAction("Checkable Option"); + auto *action = toolMenu->addAction("Checkable Option"); action->setCheckable(true); menuToolButton->setMenu(toolMenu); - auto toolLayout = new QHBoxLayout; + auto *toolLayout = new QHBoxLayout; toolLayout->addWidget(toolButton); toolLayout->addWidget(menuToolButton); - auto commandLinkButton = createWidget1<QCommandLinkButton>(tr("Command Link Button"), "commandLinkButton"); + auto *commandLinkButton = createWidget1<QCommandLinkButton>(tr("Command Link Button"), "commandLinkButton"); commandLinkButton->setDescription(tr("Description")); - auto buttonLayout = new QVBoxLayout; + auto *buttonLayout = new QVBoxLayout; buttonLayout->addWidget(defaultPushButton); buttonLayout->addWidget(togglePushButton); buttonLayout->addWidget(flatPushButton); @@ -264,23 +269,23 @@ QGroupBox *WidgetGallery::createButtonsGroupBox() buttonLayout->addWidget(commandLinkButton); buttonLayout->addStretch(1); - auto radioButton1 = createWidget1<QRadioButton>(tr("Radio button 1"), "radioButton1"); - auto radioButton2 = createWidget1<QRadioButton>(tr("Radio button 2"), "radioButton2"); - auto radioButton3 = createWidget1<QRadioButton>(tr("Radio button 3"), "radioButton3"); + auto *radioButton1 = createWidget1<QRadioButton>(tr("Radio button 1"), "radioButton1"); + auto *radioButton2 = createWidget1<QRadioButton>(tr("Radio button 2"), "radioButton2"); + auto *radioButton3 = createWidget1<QRadioButton>(tr("Radio button 3"), "radioButton3"); radioButton1->setChecked(true); - auto checkBox = createWidget1<QCheckBox>(tr("Tri-state check box"), "checkBox"); + auto *checkBox = createWidget1<QCheckBox>(tr("Tri-state check box"), "checkBox"); checkBox->setTristate(true); checkBox->setCheckState(Qt::PartiallyChecked); - auto checkableLayout = new QVBoxLayout; + auto *checkableLayout = new QVBoxLayout; checkableLayout->addWidget(radioButton1); checkableLayout->addWidget(radioButton2); checkableLayout->addWidget(radioButton3); checkableLayout->addWidget(checkBox); checkableLayout->addStretch(1); - auto mainLayout = new QHBoxLayout(result); + auto *mainLayout = new QHBoxLayout(result); mainLayout->addLayout(buttonLayout); mainLayout->addLayout(checkableLayout); mainLayout->addStretch(); @@ -289,8 +294,8 @@ QGroupBox *WidgetGallery::createButtonsGroupBox() static QWidget *embedIntoHBoxLayout(QWidget *w, int margin = 5) { - auto result = new QWidget; - auto layout = new QHBoxLayout(result); + auto *result = new QWidget; + auto *layout = new QHBoxLayout(result); layout->setContentsMargins(margin, margin, margin, margin); layout->addWidget(w); return result; @@ -298,7 +303,7 @@ static QWidget *embedIntoHBoxLayout(QWidget *w, int margin = 5) QToolBox *WidgetGallery::createTextToolBox() { - auto result = createWidget<QToolBox>("toolBox"); + auto *result = createWidget<QToolBox>("toolBox"); const QString plainText = tr("Twinkle, twinkle, little star,\n" "How I wonder what you are.\n" @@ -307,13 +312,13 @@ QToolBox *WidgetGallery::createTextToolBox() "Twinkle, twinkle, little star,\n" "How I wonder what you are!\n"); // Create centered/italic HTML rich text - QString richText = QLatin1String("<html><head/><body><i>"); - for (const auto &line : QStringView{ plainText }.split(QLatin1Char('\n'))) - richText += QString::fromLatin1("<center>%1</center>").arg(line); - richText += QLatin1String("</i></body></html>"); + QString richText = "<html><head/><body><i>"_L1; + for (const auto &line : QStringView{ plainText }.split(u'\n')) + richText += "<center>"_L1 + line + "</center>"_L1; + richText += "</i></body></html>"_L1; - auto textEdit = createWidget1<QTextEdit>(richText, "textEdit"); - auto plainTextEdit = createWidget1<QPlainTextEdit>(plainText, "plainTextEdit"); + auto *textEdit = createWidget1<QTextEdit>(richText, "textEdit"); + auto *plainTextEdit = createWidget1<QPlainTextEdit>(plainText, "plainTextEdit"); systemInfoTextBrowser = createWidget<QTextBrowser>("systemInfoTextBrowser"); @@ -325,28 +330,28 @@ QToolBox *WidgetGallery::createTextToolBox() QTabWidget *WidgetGallery::createItemViewTabWidget() { - auto result = createWidget<QTabWidget>("bottomLeftTabWidget"); + auto *result = createWidget<QTabWidget>("bottomLeftTabWidget"); result->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored); - auto treeView = createWidget<QTreeView>("treeView"); - auto fileSystemModel = new QFileSystemModel(treeView); + auto *treeView = createWidget<QTreeView>("treeView"); + auto *fileSystemModel = new QFileSystemModel(treeView); fileSystemModel->setRootPath(QDir::rootPath()); treeView->setModel(fileSystemModel); - auto tableWidget = createWidget<QTableWidget>("tableWidget"); + auto *tableWidget = createWidget<QTableWidget>("tableWidget"); tableWidget->setRowCount(10); tableWidget->setColumnCount(10); - auto listModel = new QStandardItemModel(0, 1, result); - listModel->appendRow(new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-128.png")), + auto *listModel = new QStandardItemModel(0, 1, result); + listModel->appendRow(new QStandardItem(QIcon(":/qt-project.org/styles/commonstyle/images/diropen-128.png"_L1), tr("Directory"))); - listModel->appendRow(new QStandardItem(QIcon(QLatin1String(":/qt-project.org/styles/commonstyle/images/computer-32.png")), + listModel->appendRow(new QStandardItem(QIcon(":/qt-project.org/styles/commonstyle/images/computer-32.png"_L1), tr("Computer"))); - auto listView = createWidget<QListView>("listView"); + auto *listView = createWidget<QListView>("listView"); listView->setModel(listModel); - auto iconModeListView = createWidget<QListView>("iconModeListView"); + auto *iconModeListView = createWidget<QListView>("iconModeListView"); iconModeListView->setViewMode(QListView::IconMode); iconModeListView->setModel(listModel); @@ -359,34 +364,34 @@ QTabWidget *WidgetGallery::createItemViewTabWidget() QGroupBox *WidgetGallery::createSimpleInputWidgetsGroupBox() { - auto result = createWidget1<QGroupBox>(tr("Simple Input Widgets"), "bottomRightGroupBox"); + auto *result = createWidget1<QGroupBox>(tr("Simple Input Widgets"), "bottomRightGroupBox"); result->setCheckable(true); result->setChecked(true); - auto lineEdit = createWidget1<QLineEdit>("s3cRe7", "lineEdit"); + auto *lineEdit = createWidget1<QLineEdit>("s3cRe7", "lineEdit"); lineEdit->setClearButtonEnabled(true); lineEdit->setEchoMode(QLineEdit::Password); - auto spinBox = createWidget<QSpinBox>("spinBox", result); + auto *spinBox = createWidget<QSpinBox>("spinBox", result); spinBox->setValue(50); - auto dateTimeEdit = createWidget<QDateTimeEdit>("dateTimeEdit", result); + auto *dateTimeEdit = createWidget<QDateTimeEdit>("dateTimeEdit", result); dateTimeEdit->setDateTime(QDateTime::currentDateTime()); - auto slider = createWidget<QSlider>("slider", result); + auto *slider = createWidget<QSlider>("slider", result); slider->setOrientation(Qt::Horizontal); slider->setValue(40); - auto scrollBar = createWidget<QScrollBar>("scrollBar", result); + auto *scrollBar = createWidget<QScrollBar>("scrollBar", result); scrollBar->setOrientation(Qt::Horizontal); setClassNameToolTip(scrollBar); scrollBar->setValue(60); - auto dial = createWidget<QDial>("dial", result); + auto *dial = createWidget<QDial>("dial", result); dial->setValue(30); dial->setNotchesVisible(true); - auto layout = new QGridLayout(result); + auto *layout = new QGridLayout(result); layout->addWidget(lineEdit, 0, 0, 1, 2); layout->addWidget(spinBox, 1, 0, 1, 2); layout->addWidget(dateTimeEdit, 2, 0, 1, 2); @@ -399,11 +404,11 @@ QGroupBox *WidgetGallery::createSimpleInputWidgetsGroupBox() QProgressBar *WidgetGallery::createProgressBar() { - auto result = createWidget<QProgressBar>("progressBar"); + auto *result = createWidget<QProgressBar>("progressBar"); result->setRange(0, 10000); result->setValue(0); - auto timer = new QTimer(this); + auto *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &WidgetGallery::advanceProgressBar); timer->start(1000); return result; @@ -414,11 +419,12 @@ void WidgetGallery::updateSystemInfo() QString systemInfo; QTextStream str(&systemInfo); str << "<html><head/><body><h3>Build</h3><p>" << QLibraryInfo::build() << "</p>" - << "<h3>Operating System</h3><p>" << QSysInfo::prettyProductName() << "</p>" + << "<h3>Operating System</h3><p>\"" << QSysInfo::prettyProductName() << "\" / " + << QGuiApplication::platformName() << "</p>" << "<h3>Screens</h3><p>High DPI scale factor rounding policy: " << highDpiScaleFactorRoundingPolicy() << "</p><ol>"; const auto screens = QGuiApplication::screens(); - for (auto screen : screens) { + for (const auto *screen : screens) { const bool current = screen == this->screen(); str << "<li>"; if (current) @@ -437,9 +443,9 @@ void WidgetGallery::updateSystemInfo() void WidgetGallery::helpOnCurrentWidget() { // Skip over internal widgets - for (auto w = QApplication::widgetAt(QCursor::pos(screen())); w; w = w->parentWidget()) { + for (const auto *w = QApplication::widgetAt(QCursor::pos(screen())); w; w = w->parentWidget()) { const QString name = w->objectName(); - if (!name.isEmpty() && !name.startsWith(QLatin1String("qt_"))) { + if (!name.isEmpty() && !name.startsWith("qt_"_L1)) { launchHelp(w); break; } diff --git a/examples/widgets/gallery/widgetgallery.h b/examples/widgets/gallery/widgetgallery.h index c96437a4667..f220847a0cd 100644 --- a/examples/widgets/gallery/widgetgallery.h +++ b/examples/widgets/gallery/widgetgallery.h @@ -37,7 +37,7 @@ private: QProgressBar *createProgressBar(); QProgressBar *progressBar; - QTextBrowser *systemInfoTextBrowser; + QTextBrowser *systemInfoTextBrowser{}; }; #endif // WIDGETGALLERY_H diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 82179cfd89a..8aad11dfca7 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -1157,6 +1157,18 @@ function(_qt_internal_assign_to_internal_targets_folder target) endif() endfunction() +# Returns the metatypes build dir where the Qt build system places module metatypes json files and +# other supporting metatypes files like ${target}_json_file_list.txt. +# The path is usually the target's BINARY_DIR + "/meta_types" +function(_qt_internal_get_metatypes_build_dir out_var target) + get_target_property(target_binary_dir "${target}" BINARY_DIR) + set(out_dir "${target_binary_dir}/meta_types") + set(${out_var} "${out_dir}" PARENT_SCOPE) +endfunction() + +# The AUTOGEN build dir is the location where all the generated .cpp files are placed, as well +# as the moc_predefs.h, timestamp file and deps files. +# E.g. ${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/moc_predefs.h function(_qt_internal_get_target_autogen_build_dir target out_var) get_property(target_autogen_build_dir TARGET ${target} PROPERTY AUTOGEN_BUILD_DIR) if(target_autogen_build_dir) @@ -1167,6 +1179,14 @@ function(_qt_internal_get_target_autogen_build_dir target out_var) endif() endfunction() +# The AUTOGEN info dir is the location where AutogenInfo.json and ParseCache.txt files are placed. +# E.g. ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}_autogen.dir/ParseCache.txt +function(_qt_internal_get_target_autogen_info_dir target out_var) + get_target_property(target_binary_dir ${target} BINARY_DIR) + set(autogen_info_dir "${target_binary_dir}/CMakeFiles/${target}_autogen.dir") + set(${out_var} "${autogen_info_dir}" PARENT_SCOPE) +endfunction() + function(_qt_internal_should_install_metatypes target) set(args_option INTERNAL_INSTALL @@ -1354,12 +1374,14 @@ function(qt6_extract_metatypes target) return() endif() - get_target_property(target_binary_dir ${target} BINARY_DIR) - set(type_list_file "${target_binary_dir}/meta_types/${target}_json_file_list.txt") - set(type_list_file_manual "${target_binary_dir}/meta_types/${target}_json_file_list_manual.txt") + _qt_internal_get_metatypes_build_dir(metatypes_dir "${target}") + + set(type_list_file "${metatypes_dir}/${target}_json_file_list.txt") + set(type_list_file_manual "${metatypes_dir}/${target}_json_file_list_manual.txt") set(target_autogen_build_dir "") _qt_internal_get_target_autogen_build_dir(${target} target_autogen_build_dir) + _qt_internal_get_target_autogen_info_dir(${target} target_autogen_info_dir) get_target_property(uses_automoc ${target} AUTOMOC) set(automoc_args) @@ -1373,21 +1395,18 @@ function(qt6_extract_metatypes target) get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(NOT is_multi_config) - set(cmake_autogen_cache_file - "${target_binary_dir}/CMakeFiles/${target}_autogen.dir/ParseCache.txt") + set(cmake_autogen_cache_file "${target_autogen_info_dir}/ParseCache.txt") set(multi_config_args --cmake-autogen-include-dir-path "${target_autogen_build_dir}/include" ) else() - set(cmake_autogen_cache_file - "${target_binary_dir}/CMakeFiles/${target}_autogen.dir/ParseCache_$<CONFIG>.txt") + set(cmake_autogen_cache_file "${target_autogen_info_dir}/ParseCache_$<CONFIG>.txt") set(multi_config_args --cmake-autogen-include-dir-path "${target_autogen_build_dir}/include_$<CONFIG>" "--cmake-multi-config") endif() - set(cmake_autogen_info_file - "${target_binary_dir}/CMakeFiles/${target}_autogen.dir/AutogenInfo.json") + set(cmake_autogen_info_file "${target_autogen_info_dir}/AutogenInfo.json") set (use_dep_files FALSE) if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.17") # Requires automoc changes present only in 3.17 @@ -1502,11 +1521,11 @@ function(qt6_extract_metatypes target) string(TOLOWER ${target} target_lowercase) set(metatypes_file_name "qt6${target_lowercase}_metatypes.json") - set(metatypes_file "${target_binary_dir}/meta_types/${metatypes_file_name}") - set(metatypes_file_gen "${target_binary_dir}/meta_types/${metatypes_file_name}.gen") + set(metatypes_file "${metatypes_dir}/${metatypes_file_name}") + set(metatypes_file_gen "${metatypes_dir}/${metatypes_file_name}.gen") set(metatypes_dep_file_name "qt6${target_lowercase}_metatypes_dep.txt") - set(metatypes_dep_file "${target_binary_dir}/meta_types/${metatypes_dep_file_name}") + set(metatypes_dep_file "${metatypes_dir}/${metatypes_dep_file_name}") # Due to generated source file dependency rules being tied to the directory # scope in which they are created it is not possible for other targets which @@ -1517,7 +1536,7 @@ function(qt6_extract_metatypes target) # file is then replaced with the contents of the generated file during # build. if (NOT EXISTS ${metatypes_file}) - file(MAKE_DIRECTORY "${target_binary_dir}/meta_types") + file(MAKE_DIRECTORY "${metatypes_dir}") file(TOUCH ${metatypes_file}) endif() diff --git a/src/corelib/global/qalloc.h b/src/corelib/global/qalloc.h index 9d40f4261d3..a05c09ac63c 100644 --- a/src/corelib/global/qalloc.h +++ b/src/corelib/global/qalloc.h @@ -21,6 +21,7 @@ #include <QtCore/qtypeinfo.h> #include <cstddef> +#include <cstdlib> QT_BEGIN_NAMESPACE diff --git a/src/corelib/global/qassert.h b/src/corelib/global/qassert.h index d1d306fd3ed..05210acb2d4 100644 --- a/src/corelib/global/qassert.h +++ b/src/corelib/global/qassert.h @@ -100,6 +100,25 @@ inline bool qt_assume_is_deprecated(bool cond) noexcept { return cond; } Q_ASSUME_IMPL(valueOfExpression);\ }(qt_assume_is_deprecated(Expr)) + +#if __has_builtin(__builtin_assume) +// Clang has this intrinsic and won't warn about its use in C++20 mode +# define Q_PRESUME_IMPL(assumption) __builtin_assume(assumption) +#elif __has_cpp_attribute(assume) +// GCC has implemented this attribute and allows its use in C++20 mode +# define Q_PRESUME_IMPL(assumption) [[assume(assumption)]] +#elif defined(Q_CC_MSVC) +# define Q_PRESUME_IMPL(assumption) __assume(assumption) +#else +# define Q_PRESUME_IMPL(assumption) (void)0 +#endif + +#define Q_PRESUME(assumption) \ + [&] { \ + Q_ASSERT(assumption); \ + Q_PRESUME_IMPL(assumption); \ + }() + // Don't use these in C++ mode, use static_assert directly. // These are here only to keep old code compiling. # define Q_STATIC_ASSERT(Condition) static_assert(bool(Condition), #Condition) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 700c59ab3c7..df55baf3120 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -1443,6 +1443,10 @@ QT_WARNING_DISABLE_MSVC(4706) /* assignment within conditional expression */ QT_WARNING_DISABLE_MSVC(4355) /* 'this' : used in base member initializer list */ QT_WARNING_DISABLE_MSVC(4710) /* function not inlined */ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc */ +# elif defined(Q_CC_CLANG_ONLY) +# if Q_CC_CLANG >= 2100 + QT_WARNING_DISABLE_CLANG("-Wcharacter-conversion") /* until https://github.com/llvm/llvm-project/issues/163719 is fixed */ +# endif # elif defined(Q_CC_BOR) # pragma option -w-inl # pragma option -w-aus diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h index 723a462bae1..6caf3510f8a 100644 --- a/src/corelib/global/qnumeric.h +++ b/src/corelib/global/qnumeric.h @@ -27,6 +27,8 @@ # include <QtCore/qstdlibdetection.h> # if defined(Q_CC_GNU_ONLY) && (defined(Q_STL_LIBCPP) || Q_CC_GNU_ONLY < 1500) // broken - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121811 +# elif defined(Q_OS_FREEBSD) && __FreeBSD_version <= 1500000 +// broken - https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=290299 # else # include <stdckdint.h> # endif diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp index 908db7b9d38..47229c8e6a1 100644 --- a/src/corelib/io/qlockfile.cpp +++ b/src/corelib/io/qlockfile.cpp @@ -24,19 +24,6 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; -namespace { -struct LockFileInfo -{ - qint64 pid; - QString appname; - QString hostname; - QByteArray hostid; - QByteArray bootid; -}; -} - -static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info); - static QString machineName() { #ifdef Q_OS_WIN @@ -364,8 +351,8 @@ bool QLockFile::tryLock(std::chrono::milliseconds timeout) bool QLockFile::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const { Q_D(const QLockFile); - LockFileInfo info; - if (!getLockInfo_helper(d->fileName, &info)) + QLockFilePrivate::LockFileInfo info; + if (!QLockFilePrivate::getLockInfo_helper(d->fileName, &info)) return false; if (pid) *pid = info.pid; @@ -399,11 +386,16 @@ QByteArray QLockFilePrivate::lockFileContents() const % QSysInfo::bootUniqueId() % '\n'; } -static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info) +bool QLockFilePrivate::getLockInfo_helper(const QString &fileName, LockFileInfo *info) { - QFile reader(fileName); - if (!reader.open(QIODevice::ReadOnly | QIODevice::Text)) + int fd = openNewFileDescriptor(fileName); + if (fd < 0) + return false; + QFile reader; + if (!reader.open(fd, QFile::ReadOnly | QFile::Text, QFile::AutoCloseHandle)) { + QT_CLOSE(fd); return false; + } QByteArray pidLine = reader.readLine(); pidLine.chop(1); diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h index 2a7ebe1926d..ea9b29e9f57 100644 --- a/src/corelib/io/qlockfile_p.h +++ b/src/corelib/io/qlockfile_p.h @@ -25,6 +25,15 @@ QT_BEGIN_NAMESPACE class QLockFilePrivate { public: + struct LockFileInfo + { + qint64 pid; + QString appname; + QString hostname; + QByteArray hostid; + QByteArray bootid; + }; + explicit QLockFilePrivate(const QString &fn); ~QLockFilePrivate(); @@ -41,6 +50,9 @@ public: QString fileName; + static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info); + static int openNewFileDescriptor(const QString &fileName); + #ifdef Q_OS_WIN Qt::HANDLE fileHandle; #else diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 87faac8b33d..34276373a1f 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -285,6 +285,11 @@ QString QLockFilePrivate::processNameByPid(qint64 pid) #endif } +int QLockFilePrivate::openNewFileDescriptor(const QString &fileName) +{ + return QT_OPEN(fileName.toLocal8Bit().constData(), QT_OPEN_RDONLY); +} + void QLockFile::unlock() { Q_D(QLockFile); diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index 12a668def0f..ef5d49fb20e 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -16,6 +16,8 @@ #include <qt_windows.h> #include <psapi.h> +#include <io.h> +#include <fcntl.h> QT_BEGIN_NAMESPACE @@ -53,9 +55,10 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys() const QFileSystemEntry fileEntry(fileName); // When writing, allow others to read. // When reading, QFile will allow others to read and write, all good. - // Adding FILE_SHARE_DELETE would allow forceful deletion of stale files, - // but Windows doesn't allow recreating it while this handle is open anyway, - // so this would only create confusion (can't lock, but no lock file to read from). + // ### Open the file with DELETE permission and use + // SetFileInformationByHandle to delete the file without needing to close + // the handle first, to avoid someone opening the handle again without the + // FILE_SHARE_DELETE flag in-between closure and deletion. const DWORD dwShareMode = FILE_SHARE_READ; SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; HANDLE fh = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(), @@ -142,6 +145,30 @@ QString QLockFilePrivate::processNameByPid(qint64 pid) return name; } +int QLockFilePrivate::openNewFileDescriptor(const QString &fileName) +{ + // We currently open with FILE_SHARE_DELETE, which would allow deletion to + // be requested even while other processes have the file open. We mostly + // want to do this so we can later open the file with the DELETE permission + // to delete the file using SetFileInformationByHandle, avoiding the need + // to close the handle first, where e.g. search indexer or antivirus may + // see their chance to open the file before we can delete it. + // We can't make this change immediately because currently-deployed + // applications will not be using FILE_SHARE_DELETE, so they would suddenly + // be unable to read the lockfile information. + HANDLE handle = CreateFile(reinterpret_cast<const wchar_t *>(fileName.utf16()), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (handle == INVALID_HANDLE_VALUE) + return -1; + int fd = _open_osfhandle(intptr_t(handle), _O_RDONLY); + if (fd == -1) { + CloseHandle(handle); + return -1; + } + return fd; +} + void QLockFile::unlock() { Q_D(QLockFile); diff --git a/src/corelib/io/qrandomaccessasyncfile_p_p.h b/src/corelib/io/qrandomaccessasyncfile_p_p.h index 7b10edc6728..ef996c37f07 100644 --- a/src/corelib/io/qrandomaccessasyncfile_p_p.h +++ b/src/corelib/io/qrandomaccessasyncfile_p_p.h @@ -39,7 +39,7 @@ class QRandomAccessAsyncFilePrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QRandomAccessAsyncFile) Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate) public: - QRandomAccessAsyncFilePrivate(decltype(QObjectPrivateVersion) version = QObjectPrivateVersion); + QRandomAccessAsyncFilePrivate(); ~QRandomAccessAsyncFilePrivate() override; static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file) diff --git a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp index 42d38cc3adb..4ebcf554655 100644 --- a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp +++ b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp @@ -64,8 +64,8 @@ static SharedThreadPool asyncFileThreadPool; } // anonymous namespace -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate(decltype(QObjectPrivateVersion) version) : - QObjectPrivate(version) +QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() : + QObjectPrivate() { asyncFileThreadPool.ref(); } diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index a2719f97da7..6065bf2baea 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1339,7 +1339,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, [[maybe_unused]] int flags = prop.flags; - if (isBuiltinType(prop.type)) + if (!isBuiltinType(prop.type)) flags |= EnumOrFlag; if constexpr (mode == Construct) { diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index ef30d5e0da1..9fb832545f8 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -512,10 +512,8 @@ public: } constexpr qsizetype size() const noexcept { -#if __has_cpp_attribute(assume) constexpr size_t MaxSize = maxSize(); - [[assume(size_t(d.size) <= MaxSize)]]; -#endif + Q_PRESUME(size_t(d.size) <= MaxSize); return d.size; } #if QT_DEPRECATED_SINCE(6, 4) diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp index 167ba9e84d0..6be19473b85 100644 --- a/src/corelib/text/qchar.cpp +++ b/src/corelib/text/qchar.cpp @@ -1999,26 +1999,34 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, qs qsizetype pos = from; while (pos < l) { qsizetype p2 = pos+1; - char32_t u1 = s.at(pos).unicode(); - if (QChar::isHighSurrogate(u1)) { + char32_t u1; + if (const char16_t hi = s.at(pos).unicode(); QChar::isHighSurrogate(hi)) { const char16_t low = s.at(p2).unicode(); if (QChar::isLowSurrogate(low)) { - u1 = QChar::surrogateToUcs4(u1, low); + u1 = QChar::surrogateToUcs4(hi, low); if (p2 >= l) break; ++p2; + } else { + u1 = hi; } + } else { + u1 = hi; } ushort c1 = 0; advance: - char32_t u2 = s.at(p2).unicode(); - if (QChar::isHighSurrogate(u2) && p2 < l) { + char32_t u2; + if (const char16_t hi = s.at(p2).unicode(); QChar::isHighSurrogate(hi) && p2 < l) { const char16_t low = s.at(p2+1).unicode(); if (QChar::isLowSurrogate(low)) { - u2 = QChar::surrogateToUcs4(u2, low); + u2 = QChar::surrogateToUcs4(hi, low); ++p2; + } else { + u2 = hi; } + } else { + u2 = hi; } ushort c2 = 0; diff --git a/src/corelib/text/qchar.h b/src/corelib/text/qchar.h index 008282232fb..4a3aad0ca0c 100644 --- a/src/corelib/text/qchar.h +++ b/src/corelib/text/qchar.h @@ -499,26 +499,26 @@ public: Unicode_16_0, }; - inline Category category() const noexcept { return QChar::category(ucs); } - inline Direction direction() const noexcept { return QChar::direction(ucs); } - inline JoiningType joiningType() const noexcept { return QChar::joiningType(ucs); } - inline unsigned char combiningClass() const noexcept { return QChar::combiningClass(ucs); } + Category category() const noexcept { return QChar::category(char32_t(ucs)); } + Direction direction() const noexcept { return QChar::direction(char32_t(ucs)); } + JoiningType joiningType() const noexcept { return QChar::joiningType(char32_t(ucs)); } + unsigned char combiningClass() const noexcept { return QChar::combiningClass(char32_t(ucs)); } - inline QChar mirroredChar() const noexcept { return QChar(QChar::mirroredChar(ucs)); } - inline bool hasMirrored() const noexcept { return QChar::hasMirrored(ucs); } + QChar mirroredChar() const noexcept { return QChar(QChar::mirroredChar(char32_t(ucs))); } + bool hasMirrored() const noexcept { return QChar::hasMirrored(char32_t(ucs)); } QString decomposition() const; - inline Decomposition decompositionTag() const noexcept { return QChar::decompositionTag(ucs); } + Decomposition decompositionTag() const noexcept { return QChar::decompositionTag(char32_t(ucs)); } - inline int digitValue() const noexcept { return QChar::digitValue(ucs); } - inline QChar toLower() const noexcept { return QChar(QChar::toLower(ucs)); } - inline QChar toUpper() const noexcept { return QChar(QChar::toUpper(ucs)); } - inline QChar toTitleCase() const noexcept { return QChar(QChar::toTitleCase(ucs)); } - inline QChar toCaseFolded() const noexcept { return QChar(QChar::toCaseFolded(ucs)); } + int digitValue() const noexcept { return QChar::digitValue(char32_t(ucs)); } + QChar toLower() const noexcept { return QChar(QChar::toLower(char32_t(ucs))); } + QChar toUpper() const noexcept { return QChar(QChar::toUpper(char32_t(ucs))); } + QChar toTitleCase() const noexcept { return QChar(QChar::toTitleCase(char32_t(ucs))); } + QChar toCaseFolded() const noexcept { return QChar(QChar::toCaseFolded(char32_t(ucs))); } - inline Script script() const noexcept { return QChar::script(ucs); } + Script script() const noexcept { return QChar::script(char32_t(ucs)); } - inline UnicodeVersion unicodeVersion() const noexcept { return QChar::unicodeVersion(ucs); } + UnicodeVersion unicodeVersion() const noexcept { return QChar::unicodeVersion(char32_t(ucs)); } constexpr inline char toLatin1() const noexcept { return ucs > 0xff ? '\0' : char(ucs); } constexpr inline char16_t unicode() const noexcept { return ucs; } @@ -528,23 +528,23 @@ public: constexpr inline bool isNull() const noexcept { return ucs == 0; } - inline bool isPrint() const noexcept { return QChar::isPrint(ucs); } - constexpr inline bool isSpace() const noexcept { return QChar::isSpace(ucs); } - inline bool isMark() const noexcept { return QChar::isMark(ucs); } - inline bool isPunct() const noexcept { return QChar::isPunct(ucs); } - inline bool isSymbol() const noexcept { return QChar::isSymbol(ucs); } - constexpr inline bool isLetter() const noexcept { return QChar::isLetter(ucs); } - constexpr inline bool isNumber() const noexcept { return QChar::isNumber(ucs); } - constexpr inline bool isLetterOrNumber() const noexcept { return QChar::isLetterOrNumber(ucs); } - constexpr inline bool isDigit() const noexcept { return QChar::isDigit(ucs); } - constexpr inline bool isLower() const noexcept { return QChar::isLower(ucs); } - constexpr inline bool isUpper() const noexcept { return QChar::isUpper(ucs); } - constexpr inline bool isTitleCase() const noexcept { return QChar::isTitleCase(ucs); } - - constexpr inline bool isNonCharacter() const noexcept { return QChar::isNonCharacter(ucs); } - constexpr inline bool isHighSurrogate() const noexcept { return QChar::isHighSurrogate(ucs); } - constexpr inline bool isLowSurrogate() const noexcept { return QChar::isLowSurrogate(ucs); } - constexpr inline bool isSurrogate() const noexcept { return QChar::isSurrogate(ucs); } + bool isPrint() const noexcept { return QChar::isPrint(char32_t(ucs)); } + constexpr bool isSpace() const noexcept { return QChar::isSpace(char32_t(ucs)); } + bool isMark() const noexcept { return QChar::isMark(char32_t(ucs)); } + bool isPunct() const noexcept { return QChar::isPunct(char32_t(ucs)); } + bool isSymbol() const noexcept { return QChar::isSymbol(char32_t(ucs)); } + constexpr bool isLetter() const noexcept { return QChar::isLetter(char32_t(ucs)); } + constexpr bool isNumber() const noexcept { return QChar::isNumber(char32_t(ucs)); } + constexpr bool isLetterOrNumber() const noexcept { return QChar::isLetterOrNumber(char32_t(ucs)); } + constexpr bool isDigit() const noexcept { return QChar::isDigit(char32_t(ucs)); } + constexpr bool isLower() const noexcept { return QChar::isLower(char32_t(ucs)); } + constexpr bool isUpper() const noexcept { return QChar::isUpper(char32_t(ucs)); } + constexpr bool isTitleCase() const noexcept { return QChar::isTitleCase(char32_t(ucs)); } + + constexpr bool isNonCharacter() const noexcept { return QChar::isNonCharacter(char32_t(ucs)); } + constexpr bool isHighSurrogate() const noexcept { return QChar::isHighSurrogate(char32_t(ucs)); } + constexpr bool isLowSurrogate() const noexcept { return QChar::isLowSurrogate(char32_t(ucs)); } + constexpr bool isSurrogate() const noexcept { return QChar::isSurrogate(char32_t(ucs)); } constexpr inline uchar cell() const noexcept { return uchar(ucs & 0xff); } constexpr inline uchar row() const noexcept { return uchar((ucs>>8)&0xff); } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index b8acf7c923d..506d669d356 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -273,10 +273,8 @@ public: } constexpr qsizetype size() const noexcept { -#if __has_cpp_attribute(assume) constexpr size_t MaxSize = maxSize(); - [[assume(size_t(d.size) <= MaxSize)]]; -#endif + Q_PRESUME(size_t(d.size) <= MaxSize); return d.size; } #if QT_DEPRECATED_SINCE(6, 4) diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp index 0de30d3b9f9..a308c4419e2 100644 --- a/src/corelib/thread/qsemaphore.cpp +++ b/src/corelib/thread/qsemaphore.cpp @@ -12,6 +12,9 @@ #include "qwaitcondition_p.h" #include <chrono> +#if !QT_CONFIG(thread) +#include <limits> +#endif QT_BEGIN_NAMESPACE @@ -684,7 +687,7 @@ bool QSemaphore::tryAcquire(int n, QDeadlineTimer timer) // the calling thread (which is the only thread in the no-thread // configuraton) -QSemaphore::QSemaphore(int n) +QSemaphore::QSemaphore(int) { } @@ -704,6 +707,21 @@ void QSemaphore::release(int) } +int QSemaphore::available() const +{ + return std::numeric_limits<int>::max(); +} + +bool QSemaphore::tryAcquire(int) +{ + return true; +} + +bool QSemaphore::tryAcquire(int, QDeadlineTimer) +{ + return true; +} + #endif QT_END_NAMESPACE diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h index 611c8e4b5e7..2714c67b093 100644 --- a/src/corelib/time/qtimezoneprivate_p.h +++ b/src/corelib/time/qtimezoneprivate_p.h @@ -162,7 +162,7 @@ public: QByteArray ianaId; qsizetype nameLength = 0; QTimeZone::TimeType timeType = QTimeZone::GenericTime; - operator bool() { return nameLength > 0; } + operator bool() const { return nameLength > 0; } }; static NamePrefixMatch findLongNamePrefix(QStringView text, const QLocale &locale, std::optional<qint64> atEpochMillis = std::nullopt); diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 80641c4a281..c6259354de9 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -916,8 +916,10 @@ public: void assign(InputIterator first, InputIterator last, Projection proj = {}) { // This function only provides the basic exception guarantee. - using Category = typename std::iterator_traits<InputIterator>::iterator_category; - constexpr bool IsFwdIt = std::is_convertible_v<Category, std::forward_iterator_tag>; + constexpr bool IsFwdIt = std::is_convertible_v< + typename std::iterator_traits<InputIterator>::iterator_category, + std::forward_iterator_tag>; + constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>; const qsizetype n = IsFwdIt ? std::distance(first, last) : 0; bool undoPrependOptimization = true; @@ -993,23 +995,26 @@ public: } } - assign_impl(first, last, dst, dend, proj, Category{}); - } - - template <typename InputIterator, typename Projection> - void assign_impl(InputIterator first, InputIterator last, T *dst, T *dend, Projection proj, - std::input_iterator_tag) - { while (true) { if (first == last) { // ran out of elements to assign std::destroy(dst, dend); break; } if (dst == dend) { // ran out of existing elements to overwrite - do { - this->emplace(this->size, std::invoke(proj, *first)); - } while (++first != last); - return; // size() is already correct (and dst invalidated)! + if constexpr (IsFwdIt && IsIdentity) { + dst = std::uninitialized_copy(first, last, dst); + break; + } else if constexpr (IsFwdIt && !IsIdentity + && std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) { + for (; first != last; ++dst, ++first) // uninitialized_copy with projection + q20::construct_at(dst, std::invoke(proj, *first)); + break; + } else { + do { + this->emplace(this->size, std::invoke(proj, *first)); + } while (++first != last); + return; // size() is already correct (and dst invalidated)! + } } *dst = std::invoke(proj, *first); // overwrite existing element ++dst; @@ -1017,38 +1022,6 @@ public: } this->size = dst - this->begin(); } - - template <typename InputIterator, typename Projection> - void assign_impl(InputIterator first, InputIterator last, T *dst, T *, Projection proj, - std::forward_iterator_tag) - { - constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>; - const qsizetype n = std::distance(first, last); - if constexpr (IsIdentity && !QTypeInfo<T>::isComplex) { - // For non-complex types, we prefer a single std::copy() -> memcpy() - // call. We can do that because either the default constructor is - // trivial (so the lifetime has started) or the copy constructor is - // (and won't care what the stored value is). - std::copy(first, last, dst); - } else { - // overwrite existing elements and create new - qsizetype i = 0; - qsizetype size = this->size; - for ( ; i < size; ++i) { - *dst = std::invoke(proj, *first); // overwrite existing element - ++first; - ++dst; - } - for ( ; i < n; ++i) { - q20::construct_at(dst, std::invoke(proj, *first)); - ++first; - ++dst; - } - if (i < size) - std::destroy_n(dst, size - i); - } - this->size = n; - } }; } // namespace QtPrivate diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index fea5bdfa906..092ff46b084 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -235,6 +235,8 @@ public: // when not called from the static hash() function, this function needs to be // called with finalizeMutex held (finalize() will do that): void finalizeUnchecked() noexcept; + QSpan<uchar> finalizeUnchecked(QSpan<uchar> buffer) noexcept; + // END functions that need to be called with finalizeMutex held QByteArrayView resultView() const noexcept { return result.toByteArrayView(); } static bool supportsAlgorithm(QCryptographicHash::Algorithm method); @@ -268,7 +270,7 @@ public: explicit EVP(QCryptographicHash::Algorithm method); void reset() noexcept; - void finalizeUnchecked(HashResult &result) noexcept; + void finalizeUnchecked(QSpan<uchar> buffer) noexcept; }; #endif @@ -281,7 +283,7 @@ public: void reset(QCryptographicHash::Algorithm method) noexcept; void addData(QCryptographicHash::Algorithm method, QByteArrayView data) noexcept; - void finalizeUnchecked(QCryptographicHash::Algorithm method, HashResult &result) noexcept; + void finalizeUnchecked(QCryptographicHash::Algorithm method, QSpan<uchar> buffer) noexcept; Sha1State sha1Context; #ifdef USING_OPENSSL30 @@ -297,7 +299,7 @@ public: SHA3Context sha3Context; enum class Sha3Variant { Sha3, Keccak }; - static void sha3Finish(SHA3Context &ctx, HashResult &result, Sha3Variant sha3Variant); + static void sha3Finish(SHA3Context &ctx, QSpan<uchar> result, Sha3Variant sha3Variant); blake2b_state blake2bContext; blake2s_state blake2sContext; } state; @@ -308,7 +310,7 @@ public: const QCryptographicHash::Algorithm method; }; -void QCryptographicHashPrivate::State::sha3Finish(SHA3Context &ctx, HashResult &result, +void QCryptographicHashPrivate::State::sha3Finish(SHA3Context &ctx, QSpan<uchar> result, Sha3Variant sha3Variant) { /* @@ -981,9 +983,23 @@ void QCryptographicHashPrivate::finalizeUnchecked() noexcept state.finalizeUnchecked(method, result); } +/*! + \internal + + Must be called with finalizeMutex held, except when called from the static + hash() function, where no sharing can take place. +*/ +QSpan<uchar> QCryptographicHashPrivate::finalizeUnchecked(QSpan<uchar> buffer) noexcept +{ + buffer = buffer.first(hashLengthInternal(method)); + state.finalizeUnchecked(method, buffer); + Q_ASSERT(result.size() == 0); // internal buffer wasn't used + return buffer; +} + #ifdef USING_OPENSSL30 void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method, - HashResult &result) noexcept + QSpan<uchar> result) noexcept { switch (method) { case QCryptographicHash::Keccak_224: @@ -1030,7 +1046,7 @@ void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Alg } } -void QCryptographicHashPrivate::EVP::finalizeUnchecked(HashResult &result) noexcept +void QCryptographicHashPrivate::EVP::finalizeUnchecked(QSpan<uchar> result) noexcept { if (!initializationFailed) { EVP_MD_CTX_ptr copy = EVP_MD_CTX_ptr(EVP_MD_CTX_new()); @@ -1043,7 +1059,7 @@ void QCryptographicHashPrivate::EVP::finalizeUnchecked(HashResult &result) noexc #else // USING_OPENSSL30 void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method, - HashResult &result) noexcept + QSpan<uchar> result) noexcept { switch (method) { case QCryptographicHash::Sha1: { @@ -1166,12 +1182,8 @@ QByteArrayView QCryptographicHash::hashInto(QSpan<std::byte> buffer, QCryptographicHashPrivate hash(method); for (QByteArrayView part : data) hash.addData(part); - hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash' - auto result = hash.resultView(); - Q_ASSERT(buffer.size() >= result.size()); - // ### optimize: have the method directly write into `buffer` - memcpy(buffer.data(), result.data(), result.size()); - return buffer.first(result.size()); + auto span = QSpan{reinterpret_cast<uchar *>(buffer.data()), buffer.size()}; + return hash.finalizeUnchecked(span); // no mutex needed: no-one but us has access to 'hash' } /*! diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 79b367b199c..93f7ddb9465 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -446,10 +446,8 @@ public: static constexpr qsizetype maxSize() { return Data::maxSize(); } constexpr qsizetype size() const noexcept { -#if __has_cpp_attribute(assume) constexpr size_t MaxSize = maxSize(); - [[assume(size_t(d.size) <= MaxSize)]]; -#endif + Q_PRESUME(size_t(d.size) <= MaxSize); return d.size; } constexpr qsizetype count() const noexcept { return size(); } diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 7d0cec8c899..595efd7e3bf 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -4,16 +4,35 @@ #ifndef QSHAREDDATA_H #define QSHAREDDATA_H -#include <QtCore/qglobal.h> #include <QtCore/qatomic.h> #include <QtCore/qcompare.h> #include <QtCore/qhashfunctions.h> - QT_BEGIN_NAMESPACE - template <class T> class QSharedDataPointer; +template <class T> class QExplicitlySharedDataPointer; + +namespace QtPrivate { +template <template <typename> class P, typename T> struct QSharedDataPointerTraits; +template <typename T> struct QSharedDataPointerTraits<QSharedDataPointer, T> +{ + static constexpr bool ImplicitlyDetaches = true; + using Type = T; + using pointer = T *; + // for const-qualified functions: + using constT = const T; +}; + +template <typename T> struct QSharedDataPointerTraits<QExplicitlySharedDataPointer, T> +{ + static constexpr bool ImplicitlyDetaches = false; + using Type = T; + using pointer = T *; + // for const-qualified functions: + using constT = T; +}; +} class QSharedData { @@ -30,41 +49,38 @@ public: struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; }; -template <typename T> -class QSharedDataPointer +// CRTP common base class for both QSharedDataPointer and QExplicitlySharedDataPointer +template <template <typename> class P, typename T> class QSharedDataPointerBase { +#ifndef Q_QDOC + using Self = P<T>; + using Traits = QtPrivate::QSharedDataPointerTraits<P, T>; + using constT = typename Traits::constT; + +protected: + constexpr QSharedDataPointerBase(T *ptr = nullptr) noexcept : d(ptr) {} + public: - typedef T Type; - typedef T *pointer; + // When adding anything public to this class, make sure to add the doc version to + // both QSharedDataPointer and QExplicitlySharedDataPointer. + + using Type = T; + using pointer = T *; void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } - T &operator*() { detach(); return *(d.get()); } - const T &operator*() const { return *(d.get()); } - T *operator->() { detach(); return d.get(); } - const T *operator->() const noexcept { return d.get(); } - operator T *() { detach(); return d.get(); } + T &operator*() { implicitlyDetach(); return *(d.get()); } + constT &operator*() const { return *(d.get()); } + T *operator->() { implicitlyDetach(); return d.get(); } + constT *operator->() const noexcept { return d.get(); } + operator T *() { implicitlyDetach(); return d.get(); } operator const T *() const noexcept { return d.get(); } - T *data() { detach(); return d.get(); } - T *get() { detach(); return d.get(); } + T *data() { implicitlyDetach(); return d.get(); } + T *get() { implicitlyDetach(); return d.get(); } const T *data() const noexcept { return d.get(); } const T *get() const noexcept { return d.get(); } const T *constData() const noexcept { return d.get(); } T *take() noexcept { return std::exchange(d, nullptr).get(); } - Q_NODISCARD_CTOR - QSharedDataPointer() noexcept : d(nullptr) { } - ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d.get(); } - - Q_NODISCARD_CTOR - explicit QSharedDataPointer(T *data) noexcept : d(data) - { if (d) d->ref.ref(); } - Q_NODISCARD_CTOR - QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data) - {} - Q_NODISCARD_CTOR - QSharedDataPointer(const QSharedDataPointer &o) noexcept : d(o.d) - { if (d) d->ref.ref(); } - void reset(T *ptr = nullptr) noexcept { if (ptr != d.get()) { @@ -72,10 +88,97 @@ public: ptr->ref.ref(); T *old = std::exchange(d, Qt::totally_ordered_wrapper(ptr)).get(); if (old && !old->ref.deref()) - delete old; + destroy(old); } } + operator bool () const noexcept { return d != nullptr; } + bool operator!() const noexcept { return d == nullptr; } + + void swap(Self &other) noexcept + { qt_ptr_swap(d, other.d); } + +private: + // The concrete class MUST override these, otherwise we will be calling + // ourselves. + T *clone() { return static_cast<Self *>(this)->clone(); } + template <typename... Args> static T *create(Args &&... args) + { return Self::create(std::forward(args)...); } + static void destroy(T *ptr) { Self::destroy(ptr); } + + void implicitlyDetach() + { + if constexpr (Traits::ImplicitlyDetaches) + static_cast<Self *>(this)->detach(); + } + + friend bool comparesEqual(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept + { return lhs.d == rhs.d; } + friend Qt::strong_ordering + compareThreeWay(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept + { return Qt::compareThreeWay(lhs.d, rhs.d); } + + friend bool comparesEqual(const QSharedDataPointerBase &lhs, const T *rhs) noexcept + { return lhs.d == rhs; } + friend Qt::strong_ordering + compareThreeWay(const QSharedDataPointerBase &lhs, const T *rhs) noexcept + { return Qt::compareThreeWay(lhs.d, rhs); } + + friend bool comparesEqual(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept + { return lhs.d == nullptr; } + friend Qt::strong_ordering + compareThreeWay(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept + { return Qt::compareThreeWay(lhs.d, nullptr); } + + friend size_t qHash(const QSharedDataPointerBase &ptr, size_t seed = 0) noexcept + { return qHash(ptr.data(), seed); } + +protected: + void detach_helper(); + + Qt::totally_ordered_wrapper<T *> d; +#endif // !Q_QDOC +}; + +template <typename T> +class QSharedDataPointer : public QSharedDataPointerBase<QSharedDataPointer, T> +{ + using Base = QSharedDataPointerBase<QSharedDataPointer, T>; + friend Base; +public: + typedef T Type; + typedef T *pointer; + + void detach() { Base::detach(); } +#ifdef Q_QDOC + T &operator*(); + const T &operator*() const; + T *operator->(); + const T *operator->() const noexcept; + operator T *(); + operator const T *() const noexcept; + T *data(); + T *get(); + const T *data() const noexcept; + const T *get() const noexcept; + const T *constData() const noexcept; + T *take() noexcept; +#endif + + Q_NODISCARD_CTOR + QSharedDataPointer() noexcept : Base(nullptr) { } + ~QSharedDataPointer() { if (d && !d->ref.deref()) destroy(d.get()); } + + Q_NODISCARD_CTOR + explicit QSharedDataPointer(T *data) noexcept : Base(data) + { if (d) d->ref.ref(); } + Q_NODISCARD_CTOR + QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : Base(data) + {} + Q_NODISCARD_CTOR + QSharedDataPointer(const QSharedDataPointer &o) noexcept : Base(o.d.get()) + { if (d) d->ref.ref(); } + QSharedDataPointer &operator=(const QSharedDataPointer &o) noexcept { reset(o.d.get()); @@ -87,76 +190,80 @@ public: return *this; } Q_NODISCARD_CTOR - QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {} + QSharedDataPointer(QSharedDataPointer &&o) noexcept + : Base(std::exchange(o.d, nullptr).get()) + {} QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer) - operator bool () const noexcept { return d != nullptr; } - bool operator!() const noexcept { return d == nullptr; } +#ifdef Q_QDOC + void reset(T *ptr = nullptr) noexcept; - void swap(QSharedDataPointer &other) noexcept - { qt_ptr_swap(d, other.d); } + operator bool () const noexcept; + bool operator!() const noexcept; + + void swap(QSharedDataPointer &other) noexcept; +#else + using Base::reset; + using Base::swap; +#endif protected: T *clone(); + template <typename... Args> static T *create(Args &&... args) + { return new T(std::forward(args)...); } + static void destroy(T *ptr) { delete ptr; } private: - friend bool comparesEqual(const QSharedDataPointer &lhs, const QSharedDataPointer &rhs) noexcept - { return lhs.d == rhs.d; } - friend Qt::strong_ordering - compareThreeWay(const QSharedDataPointer &lhs, const QSharedDataPointer &rhs) noexcept - { return Qt::compareThreeWay(lhs.d, rhs.d); } Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer) - - friend bool comparesEqual(const QSharedDataPointer &lhs, const T *rhs) noexcept - { return lhs.d == rhs; } - friend Qt::strong_ordering - compareThreeWay(const QSharedDataPointer &lhs, const T *rhs) noexcept - { return Qt::compareThreeWay(lhs.d, rhs); } Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer, T*) - - friend bool comparesEqual(const QSharedDataPointer &lhs, std::nullptr_t) noexcept - { return lhs.d == nullptr; } - friend Qt::strong_ordering - compareThreeWay(const QSharedDataPointer &lhs, std::nullptr_t) noexcept - { return Qt::compareThreeWay(lhs.d, nullptr); } Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer, std::nullptr_t) - void detach_helper(); - - Qt::totally_ordered_wrapper<T *> d; + using Base::d; }; template <typename T> -class QExplicitlySharedDataPointer +class QExplicitlySharedDataPointer : public QSharedDataPointerBase<QExplicitlySharedDataPointer, T> { + using Base = QSharedDataPointerBase<QExplicitlySharedDataPointer, T>; + friend Base; public: typedef T Type; typedef T *pointer; - T &operator*() const { return *(d.get()); } - T *operator->() noexcept { return d.get(); } - T *operator->() const noexcept { return d.get(); } + // override to make explicit. Can use explicit(!ImplicitlyShared) once we + // can depend on C++20. explicit operator T *() { return d.get(); } explicit operator const T *() const noexcept { return d.get(); } + + // override to make const. There is no const(cond), but we could use + // requires(!ImplicitlyShared) T *data() const noexcept { return d.get(); } T *get() const noexcept { return d.get(); } - const T *constData() const noexcept { return d.get(); } - T *take() noexcept { return std::exchange(d, nullptr).get(); } - void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } +#ifdef Q_QDOC + T &operator*() const; + T *operator->() noexcept; + T *operator->() const noexcept; + T *data() const noexcept; + T *get() const noexcept; + const T *constData() const noexcept; + T *take() noexcept; +#endif + + void detach() { Base::detach(); } Q_NODISCARD_CTOR - QExplicitlySharedDataPointer() noexcept : d(nullptr) { } + QExplicitlySharedDataPointer() noexcept : Base(nullptr) { } ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d.get(); } Q_NODISCARD_CTOR - explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data) + explicit QExplicitlySharedDataPointer(T *data) noexcept : Base(data) { if (d) d->ref.ref(); } Q_NODISCARD_CTOR - QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data) + QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : Base(data) {} Q_NODISCARD_CTOR - QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : d(o.d) + QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : Base(o.d.get()) { if (d) d->ref.ref(); } template<typename X> @@ -165,20 +272,9 @@ public: #ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST #error This macro has been removed in Qt 6.9. #endif - : d(o.data()) + : Base(o.data()) { if (d) d->ref.ref(); } - void reset(T *ptr = nullptr) noexcept - { - if (ptr != d) { - if (ptr) - ptr->ref.ref(); - T *old = std::exchange(d, Qt::totally_ordered_wrapper(ptr)).get(); - if (old && !old->ref.deref()) - delete old; - } - } - QExplicitlySharedDataPointer &operator=(const QExplicitlySharedDataPointer &o) noexcept { reset(o.d.get()); @@ -190,72 +286,52 @@ public: return *this; } Q_NODISCARD_CTOR - QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {} + QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept + : Base(std::exchange(o.d, nullptr).get()) + {} QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QExplicitlySharedDataPointer) - operator bool () const noexcept { return d != nullptr; } - bool operator!() const noexcept { return d == nullptr; } +#ifdef Q_QDOC + void reset(T *ptr = nullptr) noexcept; - void swap(QExplicitlySharedDataPointer &other) noexcept - { qt_ptr_swap(d, other.d); } + operator bool () const noexcept; + bool operator!() const noexcept; + + void swap(QExplicitlySharedDataPointer &other) noexcept; +#else + using Base::swap; + using Base::reset; +#endif protected: T *clone(); + template <typename... Args> static T *create(Args &&... args) + { return new T(std::forward(args)...); } + static void destroy(T *ptr) { delete ptr; } private: - friend bool comparesEqual(const QExplicitlySharedDataPointer &lhs, - const QExplicitlySharedDataPointer &rhs) noexcept - { return lhs.d == rhs.d; } - friend Qt::strong_ordering - compareThreeWay(const QExplicitlySharedDataPointer &lhs, - const QExplicitlySharedDataPointer &rhs) noexcept - { return Qt::compareThreeWay(lhs.d, rhs.d); } Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer) - - friend bool comparesEqual(const QExplicitlySharedDataPointer &lhs, const T *rhs) noexcept - { return lhs.d == rhs; } - friend Qt::strong_ordering - compareThreeWay(const QExplicitlySharedDataPointer &lhs, const T *rhs) noexcept - { return Qt::compareThreeWay(lhs.d, rhs); } Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer, const T*) - - friend bool comparesEqual(const QExplicitlySharedDataPointer &lhs, std::nullptr_t) noexcept - { return lhs.d == nullptr; } - friend Qt::strong_ordering - compareThreeWay(const QExplicitlySharedDataPointer &lhs, std::nullptr_t) noexcept - { return Qt::compareThreeWay(lhs.d, nullptr); } Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer, std::nullptr_t) - void detach_helper(); - - Qt::totally_ordered_wrapper<T *> d; + using Base::d; }; // Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time. template <typename T> Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone() { - return new T(*d); -} - -template <typename T> -Q_OUTOFLINE_TEMPLATE void QSharedDataPointer<T>::detach_helper() -{ - T *x = clone(); - x->ref.ref(); - if (!d.get()->ref.deref()) - delete d.get(); - d.reset(x); + return new T(*this->d); } template <typename T> Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone() { - return new T(*d.get()); + return new T(*this->d.get()); } -template <typename T> -Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer<T>::detach_helper() +template <template <typename> class P, typename T> Q_OUTOFLINE_TEMPLATE void +QSharedDataPointerBase<P, T>::detach_helper() { T *x = clone(); x->ref.ref(); @@ -272,17 +348,6 @@ template <typename T> void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2) noexcept { p1.swap(p2); } -template <typename T> -size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept -{ - return qHash(ptr.data(), seed); -} -template <typename T> -size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept -{ - return qHash(ptr.data(), seed); -} - template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE); template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_RELOCATABLE_TYPE); diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp index a2977360951..d1eab7f6ed3 100644 --- a/src/gui/image/qplatformpixmap.cpp +++ b/src/gui/image/qplatformpixmap.cpp @@ -36,7 +36,6 @@ QPlatformPixmap::QPlatformPixmap(PixelType pixelType, int objectId) h(0), d(0), is_null(true), - ref(0), detach_no(0), type(pixelType), id(objectId), diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h index be86bf8850f..5621afa4da5 100644 --- a/src/gui/image/qplatformpixmap.h +++ b/src/gui/image/qplatformpixmap.h @@ -22,7 +22,7 @@ QT_BEGIN_NAMESPACE class QImageReader; -class Q_GUI_EXPORT QPlatformPixmap +class Q_GUI_EXPORT QPlatformPixmap : public QSharedData { public: enum PixelType { @@ -113,10 +113,7 @@ private: friend class QPixmap; friend class QX11PlatformPixmap; friend class QImagePixmapCleanupHooks; // Needs to set is_cached - friend class QOpenGLTextureCache; //Needs to check the reference count - friend class QExplicitlySharedDataPointer<QPlatformPixmap>; - QAtomicInt ref; int detach_no; PixelType type; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 098d0331327..e44d9b1468b 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2626,6 +2626,7 @@ void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::En } currentMouseWindow = e->enter; + lastCursorPosition = e->globalPos; // TODO later: EnterEvent must report _which_ mouse entered the window; for now we assume primaryPointingDevice() QEnterEvent event(e->localPos, e->localPos, e->globalPos); diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index 72853be6e97..d7496845197 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -1525,7 +1525,7 @@ void QT_FASTCALL storeRGBA16FFromARGB32PM_avx2(uchar *dest, const uint *src, int const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3)); __m128 vsr = _mm_rcp_ps(vsa); vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa))); - vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30); + vsr = _mm_insert_ps(vsr, vf, 0x30); vsf = _mm_mul_ps(vsf, vsr); } _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0)); diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 028ae6d682a..6154f4121d2 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -726,9 +726,18 @@ namespace QtAndroidAccessibility break; } + float min = info.minValue.toFloat(); + float max = info.maxValue.toFloat(); + float current = info.currentValue.toFloat(); + if (info.role == QAccessible::ProgressBar) { + rangeType = 2; // RANGE_TYPE_PERCENT + current = 100 * (current - min) / (max - min); + min = 0.0f; + max = 100.0f; + } + QJniObject rangeInfo("android/view/accessibility/AccessibilityNodeInfo$RangeInfo", - "(IFFF)V", rangeType, info.minValue.toFloat(), - info.maxValue.toFloat(), info.currentValue.toFloat()); + "(IFFF)V", rangeType, min, max, current); if (rangeInfo.isValid()) { env->CallVoidMethod(node, m_setRangeInfoMethodID, rangeInfo.object()); diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm index aab01a7b439..e9ef769ec4b 100644 --- a/src/plugins/platforms/cocoa/qnsview_keys.mm +++ b/src/plugins/platforms/cocoa/qnsview_keys.mm @@ -114,6 +114,9 @@ static bool sendAsShortcut(const KeyEvent &keyEvent, QWindow *window) qCDebug(lcQpaKeys) << "Interpreting key event for focus object" << focusObject; m_currentlyInterpretedKeyEvent = nsevent; + // Asking the input context to handle the event will involve both + // the current input method, as well as NSKeyBindingManager, which + // may result in action callbacks to doCommandBySelector. if (![self.inputContext handleEvent:nsevent]) { qCDebug(lcQpaKeys) << "Input context did not consume event"; m_sendKeyEvent = true; diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp index 35e804531bc..5fa79482217 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -323,8 +323,9 @@ void QWasmAccessibility::setProperty(emscripten::val element, const std::string } -void QWasmAccessibility::addEventListener(emscripten::val element, const char *eventType) +void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripten::val element, const char *eventType) { + element.set("data-qta11yinterface", reinterpret_cast<size_t>(iface)); element.call<void>("addEventListener", emscripten::val(eventType), QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); @@ -352,7 +353,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac case QAccessible::Button: { element = document.call<emscripten::val>("createElement", std::string("button")); - addEventListener(element, "click"); + addEventListener(iface, element, "click"); } break; case QAccessible::CheckBox: { @@ -360,7 +361,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac setAttribute(element, "type", "checkbox"); setAttribute(element, "checked", iface->state().checked); setProperty(element, "indeterminate", iface->state().checkStateMixed); - addEventListener(element, "change"); + addEventListener(iface, element, "change"); } break; case QAccessible::Switch: { @@ -371,7 +372,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac setAttribute(element, "aria-checked", "true"); else setAttribute(element, "aria-checked", "false"); - addEventListener(element, "change"); + addEventListener(iface, element, "change"); } break; case QAccessible::RadioButton: { @@ -379,7 +380,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac setAttribute(element, "type", "radio"); setAttribute(element, "checked", iface->state().checked); setProperty(element, "name", "buttonGroup"); - addEventListener(element, "change"); + addEventListener(iface, element, "change"); } break; case QAccessible::SpinBox: @@ -413,7 +414,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac element = document.call<emscripten::val>("createElement", std::string("button")); setAttribute(element, "role", "tab"); setAttribute(element, "title", text.toStdString()); - addEventListener(element, "click"); + addEventListener(iface, element, "click"); } break; case QAccessible::ScrollBar: { @@ -422,7 +423,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac element = document.call<emscripten::val>("createElement", std::string("div")); setAttribute(element, "role", "scrollbar"); setAttribute(element, "aria-valuenow", valueString); - addEventListener(element, "change"); + addEventListener(iface, element, "change"); } break; case QAccessible::StaticText: { @@ -436,7 +437,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac element = document.call<emscripten::val>("createElement", std::string("div")); setAttribute(element, "role", "toolbar"); setAttribute(element, "title", text.toStdString()); - addEventListener(element, "click"); + addEventListener(iface, element, "click"); }break; case QAccessible::MenuItem: case QAccessible::ButtonMenu: { @@ -444,7 +445,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac element = document.call<emscripten::val>("createElement", std::string("button")); setAttribute(element, "role", "menuitem"); setAttribute(element, "title", text.toStdString()); - addEventListener(element, "click"); + addEventListener(iface, element, "click"); }break; case QAccessible::MenuBar: case QAccessible::PopupMenu: { @@ -471,7 +472,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac element = document.call<emscripten::val>("createElement", std::string("div")); } - addEventListener(element, "focus"); + addEventListener(iface, element, "focus"); return element; }(); @@ -542,6 +543,7 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface) { emscripten::val element = getHtmlElement(iface); emscripten::val container = getElementContainer(iface); + if (container.isUndefined() || element.isUndefined()) return; @@ -554,21 +556,21 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface) emscripten::val next = emscripten::val::undefined(); const int thisIndex = iface->parent()->indexOfChild(iface); - Q_ASSERT(thisIndex >= 0 && thisIndex < iface->parent()->childCount()); - for (int i = thisIndex + 1; i < iface->parent()->childCount(); ++i) { - const auto elementI = getHtmlElement(iface->parent()->child(i)); - if (!elementI.isUndefined() && - elementI["parentElement"] == container) { - next = elementI; - break; + if (thisIndex >= 0) { + Q_ASSERT(thisIndex < iface->parent()->childCount()); + for (int i = thisIndex + 1; i < iface->parent()->childCount(); ++i) { + const auto elementI = getHtmlElement(iface->parent()->child(i)); + if (!elementI.isUndefined() && + elementI["parentElement"] == container) { + next = elementI; + break; + } } + if (next.isUndefined()) + container.call<void>("appendChild", element); + else + container.call<void>("insertBefore", element, next); } - if (next.isUndefined()) { - container.call<void>("appendChild", element); - } else { - container.call<void>("insertBefore", element, next); - } - const auto activeElementAfter = emscripten::val::take_ownership( getActiveElement_js(emscripten::val::undefined().as_handle())); if (activeElementBefore != activeElementAfter) { @@ -712,22 +714,26 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event) { - QAccessibleInterface *iface = m_elements.key(event["target"]); + if (event["target"].isNull() || event["target"].isUndefined()) + return; - if (iface == nullptr) { + if (event["target"]["data-qta11yinterface"].isNull() || event["target"]["data-qta11yinterface"].isUndefined()) return; - } else { - QString eventType = QString::fromStdString(event["type"].as<std::string>()); - const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface); - - if (eventType == "focus") { - if (actionNames.contains(QAccessibleActionInterface::setFocusAction())) - iface->actionInterface()->doAction(QAccessibleActionInterface::setFocusAction()); - } else if (actionNames.contains(QAccessibleActionInterface::pressAction())) { - iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction()); - } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) { - iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction()); - } + + auto iface = reinterpret_cast<QAccessibleInterface *>(event["target"]["data-qta11yinterface"].as<size_t>()); + if (m_elements.find(iface) == m_elements.end()) + return; + + const QString eventType = QString::fromStdString(event["type"].as<std::string>()); + const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface); + + if (eventType == "focus") { + if (actionNames.contains(QAccessibleActionInterface::setFocusAction())) + iface->actionInterface()->doAction(QAccessibleActionInterface::setFocusAction()); + } else if (actionNames.contains(QAccessibleActionInterface::pressAction())) { + iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction()); + } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) { + iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction()); } } diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h index 2b4716d64e7..26f3e0e9afe 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.h +++ b/src/plugins/platforms/wasm/qwasmaccessibility.h @@ -116,7 +116,7 @@ private: void setProperty(emscripten::val element, const std::string &attr, const char *val); void setProperty(emscripten::val element, const std::string &attr, bool val); - void addEventListener(emscripten::val element, const char *eventType); + void addEventListener(QAccessibleInterface *, emscripten::val element, const char *eventType); private: static QWasmAccessibility *s_instance; diff --git a/src/testinternal/QtRunCMakeTestWrappers.cmake b/src/testinternal/QtRunCMakeTestWrappers.cmake index fdf93692e1f..cead9e52c82 100644 --- a/src/testinternal/QtRunCMakeTestWrappers.cmake +++ b/src/testinternal/QtRunCMakeTestWrappers.cmake @@ -30,10 +30,24 @@ function(qt_internal_add_RunCMake_test test) string(JOIN "\n" pre_run_code ${_qt_internal_skip_build_test_pre_run}) + set(android_code "") + if(ANDROID) + qt_internal_get_android_cmake_policy_version_minimum_value(version) + string(APPEND android_code " +# Avoid cmake policy deprecation warnings with older android NDKs appearing in stderr, which +# causes test failures if the test doesn't set +# set(RunCMake_TEST_OUTPUT_MERGE 1) +# to avoid stderr being polluted. +if(NOT QT_NO_SET_RUN_CMAKE_TESTS_CMAKE_POLICY_VERSION_MINIMUM) + set(ENV{CMAKE_POLICY_VERSION_MINIMUM} ${version}) +endif()") + endif() + _qt_internal_configure_file(CONFIGURE OUTPUT "${wrapper_file}" CONTENT " ${pre_run_code} +${android_code} include(\"${script_path_to_include}\") ") diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index c749cbd492f..431f91d5474 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -181,29 +181,17 @@ inline bool qCompare(quint32 const &t1, quint64 const &t2, const char *actual, } namespace Internal { -template <typename T> -class HasInitMain // SFINAE test for the presence of initMain() -{ -private: - using YesType = char[1]; - using NoType = char[2]; - - template <typename C> static YesType& test( decltype(&C::initMain) ) ; - template <typename C> static NoType& test(...); - -public: - enum { value = sizeof(test<T>(nullptr)) == sizeof(YesType) }; -}; +template <typename T, typename = void> +struct HasInitMain : std::false_type{}; -template<typename T> -typename std::enable_if<HasInitMain<T>::value, void>::type callInitMain() -{ - T::initMain(); -} +template <typename T> +struct HasInitMain<T, std::void_t<decltype(&T::initMain)>> : std::true_type {}; template<typename T> -typename std::enable_if<!HasInitMain<T>::value, void>::type callInitMain() +void callInitMain() { + if constexpr (HasInitMain<T>::value) + T::initMain(); } } // namespace Internal diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 6c7e71294ed..784e69d2486 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -393,6 +393,7 @@ static QString mainSourcePath; static bool inTestFunction = false; #if defined(Q_OS_MACOS) +static std::optional<QTestPrivate::AppNapDisabler> appNapDisabler; static IOPMAssertionID macPowerSavingDisabled = 0; #endif @@ -1881,13 +1882,12 @@ void QTest::qInit(QObject *testObject, int argc, char **argv) QTestPrivate::disableWindowRestore(); // Disable App Nap which may cause tests to stall - QTestPrivate::AppNapDisabler appNapDisabler; + if (!appNapDisabler) + appNapDisabler.emplace(); - if (qApp && (qstrcmp(qApp->metaObject()->className(), "QApplication") == 0)) { - IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, - kIOPMAssertionLevelOn, CFSTR("QtTest running tests"), - &macPowerSavingDisabled); - } + IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, + kIOPMAssertionLevelOn, CFSTR("QtTest running tests"), + &macPowerSavingDisabled); #endif QTestPrivate::parseBlackList(); @@ -2041,6 +2041,7 @@ void QTest::qCleanup() #if defined(Q_OS_MACOS) IOPMAssertionRelease(macPowerSavingDisabled); + appNapDisabler = std::nullopt; #endif } diff --git a/src/widgets/doc/src/external-resources.qdoc b/src/widgets/doc/src/external-resources.qdoc index 17459b6a5bc..96117546a29 100644 --- a/src/widgets/doc/src/external-resources.qdoc +++ b/src/widgets/doc/src/external-resources.qdoc @@ -8,7 +8,7 @@ */ /*! - \externalpage http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm + \externalpage https://rk.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm \title Sinclair Spectrum */ /*! diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 51aea4079a1..6288aae096a 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3108,7 +3108,8 @@ void QAbstractItemView::keyboardSearch(const QString &search) QModelIndex startMatch; QModelIndexList previous; do { - match = d->model->match(current, Qt::DisplayRole, d->keyboardInput); + match = d->model->match(current, Qt::DisplayRole, d->keyboardInput, 1, + d->keyboardSearchFlags); if (match == previous) break; firstMatch = match.value(0); @@ -3251,6 +3252,30 @@ void QAbstractItemView::setUpdateThreshold(int threshold) } /*! + \property QAbstractItemView::keyboardSearchFlags + \since 6.11 + This property determines how the default implementation of + keyboardSearch() matches the given string against the model's data. + + The default value is \c{Qt::MatchStartsWith|Qt::MatchWrap}. + + \sa keyboardSearch() + \sa QAbstractItemModel::match() +*/ + +Qt::MatchFlags QAbstractItemView::keyboardSearchFlags() const +{ + Q_D(const QAbstractItemView); + return d->keyboardSearchFlags; +} + +void QAbstractItemView::setKeyboardSearchFlags(Qt::MatchFlags searchFlags) +{ + Q_D(QAbstractItemView); + d->keyboardSearchFlags = searchFlags; +} + +/*! Opens a persistent editor on the item at the given \a index. If no editor exists, the delegate will create a new editor. diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h index 63adac8d6f2..973a9b044cb 100644 --- a/src/widgets/itemviews/qabstractitemview.h +++ b/src/widgets/itemviews/qabstractitemview.h @@ -48,6 +48,8 @@ class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode WRITE setHorizontalScrollMode RESET resetHorizontalScrollMode) Q_PROPERTY(int updateThreshold READ updateThreshold WRITE setUpdateThreshold) + Q_PROPERTY(Qt::MatchFlags keyboardSearchFlags READ keyboardSearchFlags + WRITE setKeyboardSearchFlags) public: enum SelectionMode { @@ -182,6 +184,9 @@ public: int updateThreshold() const; void setUpdateThreshold(int threshold); + Qt::MatchFlags keyboardSearchFlags() const; + void setKeyboardSearchFlags(Qt::MatchFlags searchFlags); + void openPersistentEditor(const QModelIndex &index); void closePersistentEditor(const QModelIndex &index); bool isPersistentEditorOpen(const QModelIndex &index) const; diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index b24b2d21c33..60799fb8a50 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -383,6 +383,7 @@ public: QString keyboardInput; QElapsedTimer keyboardInputTime; + Qt::MatchFlags keyboardSearchFlags = Qt::MatchStartsWith | Qt::MatchWrap; bool autoScroll; QBasicTimer autoScrollTimer; diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index da1fbbd60df..84ff04c9f34 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -1030,7 +1030,8 @@ void QTreeView::keyboardSearch(const QString &search) searchFrom = searchFrom.sibling(searchFrom.row(), start.column()); if (searchFrom.parent() == start.parent()) searchFrom = start; - QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString); + QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString, 1, + keyboardSearchFlags()); if (match.size()) { int hitIndex = d->viewIndex(match.at(0)); if (hitIndex >= 0 && hitIndex < startIndex) diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 1708a53f163..055d8f3d11e 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -572,8 +572,6 @@ bool QDockWidgetGroupWindow::hasNativeDecos() const #endif } -QT_WARNING_PUSH -QT_WARNING_DISABLE_GCC("-Waggressive-loop-optimizations") /* The given widget is hovered over this floating group. This function will save the state and create a gap in the actual state. @@ -625,7 +623,6 @@ bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem, const QPoint &mouseP layoutInfo()->apply(opts & QMainWindow::AnimatedDocks); return true; } -QT_WARNING_POP void QDockWidgetGroupWindow::updateCurrentGapRect() { diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 3177ed5c2d4..69548c4e17e 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -771,7 +771,8 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason #endif hideMenu(hideActiveMenu); } else if (!currentAction || !currentAction->menu()) { - sloppyState.startTimerIfNotRunning(); + if (reason != SelectionReason::SelectedFromAPI) + sloppyState.startTimerIfNotRunning(); } } } @@ -2172,7 +2173,7 @@ void QMenu::hideTearOffMenu() void QMenu::setActiveAction(QAction *act) { Q_D(QMenu); - d->setCurrentAction(act, 0); + d->setCurrentAction(act, 0, QMenuPrivate::SelectionReason::SelectedFromAPI); if (d->scroll && act) d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter); } diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index dd1f058a288..d9dcd7d0362 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -362,7 +362,8 @@ public: } delayState; enum SelectionReason { SelectedFromKeyboard, - SelectedFromElsewhere + SelectedFromAPI, + SelectedFromElsewhere, }; enum class SelectionDirection { Up, diff --git a/tests/auto/cmake/test_qt_add_ui_common/functions.cmake b/tests/auto/cmake/test_qt_add_ui_common/functions.cmake index b06ba25e21f..d3878da3fbc 100644 --- a/tests/auto/cmake/test_qt_add_ui_common/functions.cmake +++ b/tests/auto/cmake/test_qt_add_ui_common/functions.cmake @@ -8,7 +8,30 @@ function(generate_hash_folder target_name infile out_folder) set(${out_folder} "${short_hash}" PARENT_SCOPE) endfunction() +function(check_generator_works out_var generator_name) + message(STATUS "Checking if generator '${generator_name}' works") + string(CONCAT source_dir + "${CMAKE_CURRENT_SOURCE_DIR}/../" + "test_qt_add_ui_common/vs_generator_test") + set(build_dir + "${CMAKE_CURRENT_BINARY_DIR}/vs_generator_test-build") + run_cmake_configure(SOURCE_DIR "${source_dir}" + BUILD_DIR "${build_dir}" + GENERATOR "${generator_name}" + CLEAN_FIRST + RESULT_VARIABLE cmake_result) + + if("${cmake_result}" EQUAL 0) + set(generator_works "TRUE") + else() + set(generator_works "FALSE") + endif() + message(STATUS "Checking if generator '${generator_name}' works - ${generator_works}") + set(${out_var} "${generator_works}" PARENT_SCOPE) +endfunction() + function(get_latest_vs_generator output) + message(STATUS "Checking which latest Visual Studio generator can be used.") execute_process(COMMAND ${CMAKE_COMMAND} -G ERROR_VARIABLE CMAKE_GENERATORS_ERROR OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -23,7 +46,14 @@ function(get_latest_vs_generator output) set(last_generator "") foreach(generator IN LISTS vs_generators) string(REGEX MATCH "Visual Studio ([0-9]+) [0-9]+" unused "${generator}") + if("${CMAKE_MATCH_1}" VERSION_GREATER "${last_version}") + # Skip Visual Studio 18 2026 because it's not installed in CI yet + check_generator_works(generator_works "${CMAKE_MATCH_0}") + if(NOT generator_works) + continue() + endif() + set(last_version "${CMAKE_MATCH_1}") set(last_generator "${CMAKE_MATCH_0}") endif() diff --git a/tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt new file mode 100644 index 00000000000..dbde5e369e5 --- /dev/null +++ b/tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +project(VsGeneratorTest LANGUAGES CXX) diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index 3804f53cae9..0b65673c393 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -92,6 +92,7 @@ private slots: void qIsNull(); void for_each(); void qassert(); + void qpresume(); void qtry(); void checkptr(); void qstaticassert(); @@ -266,6 +267,18 @@ void tst_QGlobal::qassert() QVERIFY(passed); } +/*non-static*/ Q_NEVER_INLINE char presumedValue(const char *str) +{ + Q_PRESUME(str); + // an optimizing compiler should delete the str? check + return str ? str[0] : '\0'; +} + +void tst_QGlobal::qpresume() +{ + QCOMPARE(presumedValue("Hello World"), 'H'); +} + void tst_QGlobal::qtry() { int i = 0; diff --git a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp index 3a8ea31740c..593cae6ddfc 100644 --- a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp +++ b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp @@ -874,14 +874,13 @@ void tst_QDirListing::uncPaths() void tst_QDirListing::hiddenFiles() { QStringList expected = { - "hiddenDirs_hiddenFiles/normalFile"_L1, + "hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile"_L1, + "hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile"_L1, "hiddenDirs_hiddenFiles/.hiddenFile"_L1, - "hiddenDirs_hiddenFiles/normalDirectory/normalFile"_L1, "hiddenDirs_hiddenFiles/normalDirectory/.hiddenFile"_L1, - "hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile"_L1, - "hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile"_L1, + "hiddenDirs_hiddenFiles/normalDirectory/normalFile"_L1, + "hiddenDirs_hiddenFiles/normalFile"_L1, }; - expected.sort(); constexpr auto flags = ItFlag::ExcludeDirs | ItFlag::IncludeHidden | ItFlag::Recursive; QStringList list; @@ -898,14 +897,13 @@ void tst_QDirListing::hiddenFiles() void tst_QDirListing::hiddenDirs() { QStringList expected = { - "hiddenDirs_hiddenFiles/normalDirectory"_L1, - "hiddenDirs_hiddenFiles/normalDirectory/subdir"_L1, - "hiddenDirs_hiddenFiles/normalDirectory/.hidden-subdir"_L1, "hiddenDirs_hiddenFiles/.hiddenDirectory"_L1, - "hiddenDirs_hiddenFiles/.hiddenDirectory/subdir"_L1, "hiddenDirs_hiddenFiles/.hiddenDirectory/.hidden-subdir"_L1, + "hiddenDirs_hiddenFiles/.hiddenDirectory/subdir"_L1, + "hiddenDirs_hiddenFiles/normalDirectory"_L1, + "hiddenDirs_hiddenFiles/normalDirectory/.hidden-subdir"_L1, + "hiddenDirs_hiddenFiles/normalDirectory/subdir"_L1, }; - expected.sort(); constexpr auto flags = ItFlag::ExcludeFiles | ItFlag::IncludeHidden | ItFlag::Recursive; QStringList list; diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp index 3dd36bdae35..5453237cadb 100644 --- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp +++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp @@ -182,7 +182,16 @@ private slots: void childKeys(); void testIniParsing_data(); void testIniParsing(); + void testEscapes(); + void testEscapedKeys_data(); + void testEscapedKeys(); + void testUnescapedKeys_data(); + void testUnescapedKeys(); + void testEscapedStringList_data(); + void testEscapedStringList(); + void testUnescapedStringList_data(); + void testUnescapedStringList(); void testNormalizedKey_data(); void testNormalizedKey(); void testVariantTypes_data() { populateWithFormats(); } @@ -2831,35 +2840,6 @@ void tst_QSettings::testEscapes() { QSettings settings(QSettings::UserScope, "software.org", "KillerAPP"); -#define testEscapedKey(plainKey, escKey) \ - QCOMPARE(iniEscapedKey(plainKey), QByteArray(escKey)); \ - QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); - -#define testUnescapedKey(escKey, plainKey, reescKey) \ - QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); \ - QCOMPARE(iniEscapedKey(plainKey), QByteArray(reescKey)); \ - QCOMPARE(iniUnescapedKey(reescKey), QString(plainKey)); - -#define testEscapedStringList(plainStrList, escStrList) \ - { \ - QStringList plainList(plainStrList); \ - QByteArray escList(escStrList); \ - QCOMPARE(iniEscapedStringList(plainList), escList); \ - QCOMPARE(iniUnescapedStringList(escList), plainList); \ - } \ - - -#define testUnescapedStringList(escStrList, plainStrList, reescStrList) \ - { \ - QStringList plainList(plainStrList); \ - QByteArray escList(escStrList); \ - QByteArray reescList(reescStrList); \ - QCOMPARE(iniUnescapedStringList(escList), plainList); \ - QCOMPARE(iniEscapedStringList(plainList), reescList); \ - QCOMPARE(iniUnescapedStringList(reescList), plainList); \ - } \ - - #define testVariant(val, escStr, func) \ { \ QVariant v(val); \ @@ -2875,57 +2855,6 @@ void tst_QSettings::testEscapes() QCOMPARE(v.toString(), QString(vStr)); \ } - testEscapedKey("", ""); - testEscapedKey(" ", "%20"); - testEscapedKey(" 0123 abcd ", "%200123%20abcd%20"); - testEscapedKey("~!@#$%^&*()_+.-/\\=", "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D"); - testEscapedKey(QString() + QChar(0xabcd) + QChar(0x1234) + QChar(0x0081), "%UABCD%U1234%81"); - testEscapedKey(QString() + QChar(0xFE) + QChar(0xFF) + QChar(0x100) + QChar(0x101), "%FE%FF%U0100%U0101"); - - testUnescapedKey("", "", ""); - testUnescapedKey("%20", " ", "%20"); - testUnescapedKey("/alpha/beta", "/alpha/beta", "\\alpha\\beta"); - testUnescapedKey("\\alpha\\beta", "/alpha/beta", "\\alpha\\beta"); - testUnescapedKey("%5Calpha%5Cbeta", "\\alpha\\beta", "%5Calpha%5Cbeta"); - testUnescapedKey("%", "%", "%25"); - testUnescapedKey("%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%", QString("%f%!%%%%1x%x1%U%Uz%U123") + QChar(0x1234) + "\x12" + "34%", - "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25"); - - testEscapedStringList("", ""); - testEscapedStringList(" ", "\" \""); - testEscapedStringList(";", "\";\""); - testEscapedStringList(",", "\",\""); - testEscapedStringList("=", "\"=\""); - testEscapedStringList("abc-def", "abc-def"); - testEscapedStringList(QChar(0) + QString("0"), "\\0\\x30"); - testEscapedStringList("~!@#$%^&*()_+.-/\\=", "\"~!@#$%^&*()_+.-/\\\\=\""); - testEscapedStringList("~!@#$%^&*()_+.-/\\", "~!@#$%^&*()_+.-/\\\\"); - testEscapedStringList(QString("\x7F") + "12aFz", QByteArray("\x7f") + "12aFz"); - testEscapedStringList(QString(" \t\n\\n") + QChar(0x123) + QChar(0x4567), "\" \\t\\n\\\\n\xC4\xA3\xE4\x95\xA7\""); - testEscapedStringList(QString("\a\b\f\n\r\t\v'\"?\001\002\x03\x04"), "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4"); - testEscapedStringList(QStringList() << "," << ";" << "a" << "ab, \tc, d ", "\",\", \";\", a, \"ab, \\tc, d \""); - - /* - Test .ini syntax that cannot be generated by QSettings (but can be entered by users). - */ - testUnescapedStringList("", "", ""); - testUnescapedStringList("\"\"", "", ""); - testUnescapedStringList("\"abcdef\"", "abcdef", "abcdef"); - testUnescapedStringList("\"\\?\\'\\\"\"", "?'\"", "?'\\\""); - testUnescapedStringList("\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\", - QString() + QChar(0) + QChar(0) + QChar(0) + QChar(0) + QChar(1) - + QChar(0111) + QChar(011111) + QChar(0) + QChar(0xCDEF) + "GH" - + QChar(0x3456), - "\\0\\0\\0\\0\\x1I\xE1\x89\x89\\0\xEC\xB7\xAFGH\xE3\x91\x96"); - testUnescapedStringList(QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16), "\f", "\\f"); - testUnescapedStringList("\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,", - QStringList() << "a" << "bc " << " d" << "ef " << "" << "g" << "hi i" - << "" << "" << "" << "", - "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , "); - testUnescapedStringList("a , b , c d , efg ", - QStringList() << "a" << "b" << "c d" << "efg", - "a, b, c d, efg"); - // streaming qvariant into a string testVariant(QString("Hello World!"), QString("Hello World!"), toString); testVariant(QString("Hello, World!"), QString("Hello, World!"), toString); @@ -2949,6 +2878,190 @@ void tst_QSettings::testEscapes() testBadEscape("@Rect(1 2 3)", "@Rect(1 2 3)"); testBadEscape("@@Rect(1 2 3)", "@Rect(1 2 3)"); } + +void tst_QSettings::testEscapedKeys_data() +{ + QTest::addColumn<QString>("plainKey"); + QTest::addColumn<QByteArray>("escKey"); + + QTest::newRow("empty-string") << u""_s << ""_ba; + QTest::newRow("space") << u" "_s << "%20"_ba; + QTest::newRow(" 0123 abcd ") << " 0123 abcd " << "%200123%20abcd%20"_ba; + + QTest::newRow("special-characters") + << "~!@#$%^&*()_+.-/\\=" + << "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D"_ba; + + const std::array arr1 = {QChar(0xabcd), QChar(0x1234), QChar(0x0081)}; + QTest::newRow("qchar-array1") << QString(arr1) << "%UABCD%U1234%81"_ba; + + const std::array arr2 = {QChar(0xFE), QChar(0xFF), QChar(0x100), QChar(0x101)}; + QTest::newRow("qchar-array2") << QString(arr2) << "%FE%FF%U0100%U0101"_ba; +} + +void tst_QSettings::testEscapedKeys() +{ + QFETCH(QString, plainKey); + QFETCH(QByteArray, escKey); + + QSettings settings(QSettings::UserScope, "example.org", "KillerAPP"); + + QCOMPARE(iniEscapedKey(plainKey), escKey); + QCOMPARE(iniUnescapedKey(escKey), plainKey); +} + +void tst_QSettings::testUnescapedKeys_data() +{ + QTest::addColumn<QByteArray>("escKey"); + QTest::addColumn<QString>("plainKey"); + QTest::addColumn<QByteArray>("reescKey"); + + QTest::newRow("empty-string") << ""_ba << u""_s << ""_ba; + QTest::newRow("space") << "%20"_ba << u" "_s << "%20"_ba; + QTest::newRow("%") << "%"_ba << u"%"_s << "%25"_ba; + + QTest::newRow("/alpha/beta") << "/alpha/beta"_ba << "/alpha/beta" << "\\alpha\\beta"_ba; + QTest::newRow("\\alpha\\beta") << "\\alpha\\beta"_ba << "/alpha/beta" << "\\alpha\\beta"_ba; + QTest::newRow("%5Calpha%5Cbeta") << "%5Calpha%5Cbeta"_ba << "\\alpha\\beta" << "%5Calpha%5Cbeta"_ba; + + QTest::newRow("many-percent") + << "%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%"_ba + << QString("%f%!%%%%1x%x1%U%Uz%U123"_L1 + QChar(0x1234) + "\x12" + "34%") + << "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25"_ba; +} + +void tst_QSettings::testUnescapedKeys() +{ + QFETCH(QByteArray, escKey); + QFETCH(QString, plainKey); + QFETCH(QByteArray, reescKey); + + QSettings settings(QSettings::UserScope, "example.org", "KillerAPP"); + + QCOMPARE(iniUnescapedKey(escKey), plainKey); + QCOMPARE(iniEscapedKey(plainKey), reescKey); + QCOMPARE(iniUnescapedKey(reescKey), plainKey); +} + +void tst_QSettings::testEscapedStringList_data() +{ + QTest::addColumn<QStringList>("plainStrList"); + QTest::addColumn<QByteArray>("escapedList"); + + QTest::newRow("empty-string") << QStringList{u""_s} << ""_ba; + QTest::newRow("space") << QStringList{u" "_s} << "\" \""_ba; + QTest::newRow(";") << QStringList{u";"_s} << "\";\""_ba; + QTest::newRow(",") << QStringList{u","_s} << "\",\""_ba; + QTest::newRow("=") << QStringList{u"="_s} << "\"=\""_ba; + QTest::newRow("abc-def") << QStringList{u"abc-def"_s} << "abc-def"_ba; + + QTest::newRow("starts-with-NUL") + << QStringList{QChar(0) + u"0"_s} + << "\\0\\x30"_ba; + + QTest::newRow("special-characters1") + << QStringList{u"~!@#$%^&*()_+.-/\\="_s} + << "\"~!@#$%^&*()_+.-/\\\\=\""_ba; + + QTest::newRow("special-characters2") + << QStringList{u"~!@#$%^&*()_+.-/\\"_s} + << "~!@#$%^&*()_+.-/\\\\"_ba; + + QTest::newRow("DEL-character") + << QStringList{u"\x7F"_s + u"12aFz"_s} + << "\x7f"_ba + "12aFz"_ba; + + QTest::newRow("tab-newline") + << QStringList{u" \t\n\\n"_s + QChar(0x123) + QChar(0x4567)} + << "\" \\t\\n\\\\n\xC4\xA3\xE4\x95\xA7\""_ba; + + QTest::newRow("backslash-espcaped-input") + << QStringList{u"\a\b\f\n\r\t\v'\"?\001\002\x03\x04"_s} + << "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4"_ba; + + QTest::newRow("stringlist-with-tab") + << QStringList{u","_s, u";"_s, u"a"_s, u"ab, \tc, d "_s} + << "\",\", \";\", a, \"ab, \\tc, d \""_ba; +} + +void tst_QSettings::testEscapedStringList() +{ + QFETCH(QStringList, plainStrList); + QFETCH(QByteArray, escapedList); + + QSettings settings(QSettings::UserScope, "example.org", "KillerAPP"); + + QCOMPARE(iniEscapedStringList(plainStrList), escapedList); + QCOMPARE(iniUnescapedStringList(escapedList), plainStrList); +} + +void tst_QSettings::testUnescapedStringList_data() +{ + QTest::addColumn<QByteArray>("escStrList"); + QTest::addColumn<QStringList>("plainStrList"); + QTest::addColumn<QByteArray>("reescStrList"); + + /* + Test .ini syntax that cannot be generated by QSettings (but can be entered by users). + */ + QTest::newRow("empty") + << ""_ba + << QStringList{u""_s} + << ""_ba; + + QTest::newRow("empty-double-quotes") + << "\"\""_ba + << QStringList{u""_s} + << ""_ba; + + QTest::newRow("plain-quoted-string") + << "\"abcdef\""_ba + << QStringList{u"abcdef"_s} + << "abcdef"_ba; + + QTest::newRow("backslash-non-letter-characters") + << "\"\\?\\'\\\"\""_ba + << QStringList{u"?'\""_s} + << "?'\\\""_ba; + + const std::array arr = {QChar(0), QChar(0), QChar(0), QChar(0), QChar(1), + QChar(0111), QChar(011111), QChar(0), QChar(0xCDEF), + QChar(u'G'), QChar(u'H'), QChar(0x3456)}; + QTest::newRow("array-of-qchar") + << "\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\"_ba + << QStringList{QString{arr}} + << "\\0\\0\\0\\0\\x1I\xE1\x89\x89\\0\xEC\xB7\xAFGH\xE3\x91\x96"_ba; + + QTest::newRow("backslash-escapes") + << QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16) + << QStringList{u"\f"_s} + << "\\f"_ba; + + QTest::newRow("double-quotes-tab-character") + << "\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,"_ba + << QStringList{u"a"_s, u"bc "_s, u" d"_s, u"ef "_s, u""_s, u"g"_s, + u"hi i"_s, u""_s, u""_s, u""_s, u""_s} + << "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , "_ba; + + QTest::newRow("abcdefg-extra-whitespaces") + << "a , b , c d , efg "_ba + << QStringList{u"a"_s, u"b"_s, u"c d"_s, u"efg"_s} + << "a, b, c d, efg"_ba; +} + +void tst_QSettings::testUnescapedStringList() +{ + QFETCH(QByteArray, escStrList); + QFETCH(QStringList, plainStrList); + QFETCH(QByteArray, reescStrList); + + QSettings settings(QSettings::UserScope, "example.org", "KillerAPP"); + + QCOMPARE(iniUnescapedStringList(escStrList), plainStrList); + QCOMPARE(iniEscapedStringList(plainStrList), reescStrList); + QCOMPARE(iniUnescapedStringList(reescStrList), plainStrList); +} + #endif void tst_QSettings::testCaseSensitivity() diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 7c0e5e10b71..291b7136bce 100644 --- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -22,6 +22,7 @@ private slots: void variantProperty(); void notifySignal(); void enumerator(); + void enumProperty(); void classInfo(); void relatedMetaObject(); void staticMetacall(); @@ -1019,6 +1020,26 @@ void tst_QMetaObjectBuilder::enumerator() QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators)); } +void tst_QMetaObjectBuilder::enumProperty() +{ + // When adding property with an enumeration type, QMetaProperty::isEnumType() + // should return true. + QMetaObjectBuilder builder; + builder.setSuperClass(QObject::metaObject()); + + auto enumMetaType = QMetaType::fromType<Qt::Orientation>(); + QVERIFY(enumMetaType.isValid()); + + builder.addProperty("orientation", "Qt::Orientation", enumMetaType); + + auto *mo = builder.toMetaObject(); + QVERIFY(mo != nullptr); + const int index = mo->indexOfProperty("orientation"); + QVERIFY(index != -1); + QVERIFY(mo->property(index).isEnumType()); + free(mo); +} + void tst_QMetaObjectBuilder::classInfo() { QMetaObjectBuilder builder; diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index f7c5af53310..9c61cb503fb 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -3250,6 +3250,7 @@ void tst_QWindow::enterLeaveOnWindowShowHide() ++expectedEnter; QTRY_COMPARE_WITH_TIMEOUT(window.numEnterEvents, expectedEnter, 250); QCOMPARE(window.enterPosition, window.mapFromGlobal(QCursor::pos())); + QCOMPARE(QGuiApplicationPrivate::lastCursorPosition, cursorPos); QWindow secondary; secondary.setFlag(windowType); diff --git a/tests/auto/testlib/initmain/tst_initmain.cpp b/tests/auto/testlib/initmain/tst_initmain.cpp index 75a0d9ceb4d..cdaac0c14f4 100644 --- a/tests/auto/testlib/initmain/tst_initmain.cpp +++ b/tests/auto/testlib/initmain/tst_initmain.cpp @@ -19,6 +19,9 @@ private: static bool m_initMainCalled; }; +static_assert(QTest::Internals::HasInitMain<tst_InitMain>::value); +static_assert(!QTest::Internals::HasInitMain<QObject>::value); + bool tst_InitMain::m_initMainCalled = false; void tst_InitMain::testcase() diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST index 8f8c065560a..7bde411761b 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST @@ -9,3 +9,6 @@ android android [windowOpacity] macos # QTBUG-139950 +[clickFocus] +windows-10 # QTBUG-141386 + diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 8ee122ece18..6859f22c044 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -842,6 +842,20 @@ void tst_QComboBox::virtualAutocompletion() QApplication::sendEvent(testWidget, &kp2); QApplication::sendEvent(testWidget, &kr2); QTRY_COMPARE(testWidget->currentIndex(), 3); + + QKeyEvent kp3(QEvent::KeyPress, Qt::Key_R, {}, "r"); + QKeyEvent kr3(QEvent::KeyRelease, Qt::Key_R, {}, "r"); + QTest::qWait(QApplication::keyboardInputInterval()); + QApplication::sendEvent(testWidget, &kp3); + QApplication::sendEvent(testWidget, &kr3); + QTRY_COMPARE(testWidget->currentIndex(), 3); + + QTest::qWait(QApplication::keyboardInputInterval()); + testWidget->view()->setKeyboardSearchFlags(Qt::MatchContains | Qt::MatchWrap); + QApplication::sendEvent(testWidget, &kp3); + QApplication::sendEvent(testWidget, &kr3); + QTRY_COMPARE(testWidget->currentIndex(), 1); + #if defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS) QApplication::setKeyboardInputInterval(oldInterval); #endif diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 4de87cdb7a4..704770edfcc 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -19,8 +19,9 @@ #include <QTranslator> #include <qscreen.h> -#include <qobject.h> +#include <QtCore/qobject.h> #include <QtCore/qscopeguard.h> +#include <QtCore/qtimer.h> #include <QtWidgets/private/qapplication_p.h> @@ -129,6 +130,8 @@ private slots: void pressDragRelease_data(); void pressDragRelease(); + void setActiveAction_disablesSloppyTimer(); + protected slots: void onSimpleActivated( QAction*); void onComplexActionTriggered(); @@ -1525,6 +1528,50 @@ void tst_QMenuBar::pressDragRelease() QTRY_COMPARE(triggeredSpy.size(), 1); } +void tst_QMenuBar::setActiveAction_disablesSloppyTimer() +{ + QMenuBar menuBar; + QMenu *menu = new QMenu(&menuBar); + menuBar.addMenu(menu); + + QAction *item1 = menu->addAction("Item 1"); + QAction *item2 = menu->addAction("Item 2"); + + // Create submenu for first item + QMenu *submenu = new QMenu(&menuBar); + submenu->addAction("Subitem 1"); + submenu->addAction("Subitem 2"); + submenu->addAction("Subitem 3"); + item1->setMenu(submenu); + + using namespace std::chrono_literals; + + QTimer::singleShot(0, [&]() { + menu->show(); + }); + + QTimer::singleShot(100ms, [&]() { + menu->setActiveAction(item1); + QCOMPARE_EQ(menu->activeAction(), item1); + }); + + QTimer::singleShot(200ms, [&] { + menu->setActiveAction(item2); + QCOMPARE_EQ(menu->activeAction(), item2); + }); + + bool done = false; + // QTBUG-138956: sloppy timer should not fire when calling setActiveAction + QTimer::singleShot(2s, [&] { + QCOMPARE_EQ(menu->activeAction(), item2); + done = true; + }); + + QVERIFY(QTest::qWaitFor([&]{ + return done; + })); +} + // QTBUG-56526 void tst_QMenuBar::platformMenu() { |