diff options
426 files changed, 5631 insertions, 2092 deletions
diff --git a/REUSE.toml b/REUSE.toml index c8812eacc03..4961e1f14bc 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -11,13 +11,13 @@ SPDX-License-Identifier = "BSD-3-Clause" path = ["**tools/**", "util/**", "doc/global/template/scripts/extras.js", "doc/global/template/scripts/main.js"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0" [[annotations]] path = ["tests/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" [[annotations]] @@ -29,43 +29,43 @@ path = ["bin/*", "coin/**","libexec/*","**_clang-format", "**.cmake", "**.conf", "**.cfg", "**/Makefile", "**/CMakeLists.txt", "**.qrc", ".tag"] precedence = "closest" comment = "build system" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] path = ["**PrivacyInfo.xcprivacy"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "CC0-1.0" [[annotations]] path = ["**/.gitattributes", "**.gitignore", "**.gitreview"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] path = ["**/snippets/**", "examples/**", "src/tools/qlalr/examples/**"] comment = "this must be after the build system table because example and snippets take precedence over build system" precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] path = ["tests/manual/examples/**", "**/snippets/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] -path = ["**/README*", "src/plugins/**/README*", "examples/**/README*", "tests/**/README*", +path = ["**/README*", "src/plugins/**/README*", "examples/**/README*",# "tests/**/README*", "src/widgets/doc/snippets/common-table-model/README", "cmake/README.md", "lib/README", "coin/instructions/README.md", "src/3rdparty/README", "**.qdocconf", "**.qdocinc", "config_help.txt", "doc/global/template/style/*", "**/doc/**/images/**"] comment = "documentation" precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" [[annotations]] @@ -78,37 +78,37 @@ SPDX-License-Identifier = "CC0-1.0" path = ["src/gui/doc/snippets/textdocument-images/images.qrc"] precedence = "closest" comment = "falls under **/doc/**/images/**, which is wrong" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] -path = ["src/assets/icons/**.png", "src/assets/icons/**.svg", "src/android/**.xml", +path = ["src/assets/icons/**.png", "src/assets/icons/**.svg", "src/gui/**.xml", "src/assets/icons/index.theme", "src/gui/rhi/test.hlsl", "src/corelib/doc/include/QtCoreDoc", "src/gui/doc/includes/QtGuiDoc", "src/opengl/doc/QtOpenGLDoc"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" [[annotations]] path = ["tests/auto/tools/rcc/data/legal/legal.qrc"] precedence = "override" comment = "license in file not referring to the file itself" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] path = ["**/qt_attribution.json"] precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" [[annotations]] path = ["**.toml", "licenseRule.json"] precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] diff --git a/cmake/3rdparty/extra-cmake-modules/0003-ECMEnableSanitizers.cmake-fix-no-undefined-flag-replacement.patch b/cmake/3rdparty/extra-cmake-modules/0003-ECMEnableSanitizers.cmake-fix-no-undefined-flag-replacement.patch new file mode 100644 index 00000000000..dbbef0c9f9e --- /dev/null +++ b/cmake/3rdparty/extra-cmake-modules/0003-ECMEnableSanitizers.cmake-fix-no-undefined-flag-replacement.patch @@ -0,0 +1,15 @@ +diff --git a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake +index 8d95c69e3ad..5145d2ffd71 100644 +--- a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake ++++ b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake +@@ -179,8 +179,8 @@ if (ECM_ENABLE_SANITIZERS) + link_libraries("${linker_flags}") + endif() + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") +- string(REPLACE "-Wl,--no-undefined" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") +- string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") ++ string(REGEX REPLACE "( |^)-Wl,--no-undefined( |$)" " " CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") ++ string(REGEX REPLACE "( |^)-Wl,--no-undefined( |$)" " " CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") + endif () + endforeach() + else() diff --git a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake index 8d95c69e3ad..5145d2ffd71 100644 --- a/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake +++ b/cmake/3rdparty/extra-cmake-modules/modules/ECMEnableSanitizers.cmake @@ -179,8 +179,8 @@ if (ECM_ENABLE_SANITIZERS) link_libraries("${linker_flags}") endif() if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - string(REPLACE "-Wl,--no-undefined" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") - string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") + string(REGEX REPLACE "( |^)-Wl,--no-undefined( |$)" " " CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REGEX REPLACE "( |^)-Wl,--no-undefined( |$)" " " CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") endif () endforeach() else() diff --git a/cmake/FindBundletool.cmake b/cmake/FindBundletool.cmake new file mode 100644 index 00000000000..f691b27da89 --- /dev/null +++ b/cmake/FindBundletool.cmake @@ -0,0 +1,48 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +#.rst: +# FindBundletool +# --------- +# +# Try to locate the android bundletool. +# If found, this will define the following variables: +# +# ``Bundletool_FOUND`` +# True if the Bundletool is found +# +# ``Bundletool_EXECUTABLE `` +# Path to the Bundletool executable +# +# If ``Bundletool_FOUND`` is TRUE, it will also define the following +# imported target: +# +# ``Bundletool::Bundletool`` +# The Bundletool executable + +if(DEFINED ENV{Bundletool_EXECUTABLE}) + if((NOT Bundletool_EXECUTABLE OR NOT EXISTS "${Bundletool_EXECUTABLE}") + AND EXISTS "$ENV{Bundletool_EXECUTABLE}") + set(_Bundletool_use_force FORCE) + else() + set(_Bundletool_use_force "") + endif() + set(Bundletool_EXECUTABLE "$ENV{Bundletool_EXECUTABLE}" CACHE FILEPATH + "Path to the 'bundletool' executable." ${_Bundletool_use_force}) + unset(_Bundletool_use_force) +endif() + +find_file(Bundletool_EXECUTABLE bundletool bundletool.jar) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Bundletool DEFAULT_MSG Bundletool_EXECUTABLE) + +if(Bundletool_FOUND) + if(NOT TARGET Bundletool::Bundletool) + add_executable(Bundletool::Bundletool IMPORTED) + set_target_properties(Bundletool::Bundletool PROPERTIES + IMPORTED_LOCATION "${Bundletool_EXECUTABLE}") + endif() +endif() + +mark_as_advanced(Bundletool_EXECUTABLE) diff --git a/cmake/QtAndroidHelpers.cmake b/cmake/QtAndroidHelpers.cmake index 64696fff6d4..cb7d4716f12 100644 --- a/cmake/QtAndroidHelpers.cmake +++ b/cmake/QtAndroidHelpers.cmake @@ -473,3 +473,33 @@ function(qt_internal_create_source_jar) add_dependencies(install_android_source_jar_${module} ${jar_target}) add_dependencies(install_android_source_jars install_android_source_jar_${module}) endfunction() + +# The function stores Android permissions that are required by the module target. +# The stored INTERFACE_QT_ANDROID_PERMISSIONS is the transitive property. +function(qt_internal_android_add_interface_permissions target) + get_target_property(permissions ${target} QT_ANDROID_PERMISSIONS) + if(NOT permissions) + return() + endif() + + set(postprocessed_permissions "") + foreach(permission IN LISTS permissions) + # TODO: skip processing extras for now, add them back once internal API + # will cover adding extras using internal function. + list(APPEND postprocessed_permissions "name\;${permission}") + endforeach() + qt_internal_set_module_transitive_properties(${target} TYPE LINK PROPERTIES + INTERFACE_QT_ANDROID_PERMISSIONS "${postprocessed_permissions}") +endfunction() + +# The function stores Android features that are required by the module target. +# The stored INTERFACE_QT_ANDROID_FEATURES is the transitive property. +function(qt_internal_android_add_interface_features target) + get_target_property(features ${target} QT_ANDROID_FEATURES) + if(NOT features) + return() + endif() + + qt_internal_set_module_transitive_properties(${target} TYPE LINK PROPERTIES + INTERFACE_QT_ANDROID_FEATURES "${features}") +endfunction() diff --git a/cmake/QtBaseHelpers.cmake b/cmake/QtBaseHelpers.cmake index b3a4e8c7619..911b6001564 100644 --- a/cmake/QtBaseHelpers.cmake +++ b/cmake/QtBaseHelpers.cmake @@ -237,6 +237,9 @@ macro(qt_internal_qtbase_build_repo) # Needed when building qtbase for android. if(ANDROID) include(src/corelib/Qt6AndroidMacros.cmake) + include(src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake) + include(src/corelib/Qt6AndroidGradleHelpers.cmake) + include(src/corelib/Qt6AndroidPermissionHelpers.cmake) endif() # Needed when building for WebAssembly. diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake index 1b0adccd5b5..c041f9d3ac5 100644 --- a/cmake/QtInternalTargets.cmake +++ b/cmake/QtInternalTargets.cmake @@ -368,6 +368,13 @@ if (MSVC AND NOT CLANG) ) endif() +if (WIN32 AND (CLANG OR MINGW) AND (TEST_architecture_arch STREQUAL x86_64)) + # windows 10 requires cmpxchg16b + target_compile_options(PlatformCommonInternal INTERFACE + -mcx16 + ) +endif() + set(_qt_internal_clang_msvc_frontend False) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake index b480b1c14a6..d56a889d114 100644 --- a/cmake/QtPlatformAndroid.cmake +++ b/cmake/QtPlatformAndroid.cmake @@ -30,6 +30,7 @@ include(UseJava) # Find JDK 8.0 find_package(Java 1.8 COMPONENTS Development REQUIRED) +find_package(Bundletool) # Ensure we are using the shared version of libc++ if(NOT ANDROID_STL STREQUAL c++_shared) @@ -117,13 +118,32 @@ function(qt_internal_android_test_runner_arguments target out_test_runner out_te set(deployment_tool "${host_bin_dir}/androiddeployqt") _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) - set(${out_test_arguments} + _qt_internal_android_get_platform_tools_path(platform_tools) + set(test_arguments "--path" "${android_build_dir}" - "--adb" "${ANDROID_SDK_ROOT}/platform-tools/adb" + "--adb" "${platform_tools}/adb" "--skip-install-root" - "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk" - "--apk" "${android_build_dir}/${target}.apk" "--ndk-stack" "${ANDROID_NDK_ROOT}/ndk-stack" - PARENT_SCOPE ) + + if(QT_USE_ANDROID_MODERN_BUNDLE) + _qt_internal_android_get_target_deployment_dir(target_deployment_dir ${target}) + list(APPEND test_arguments + "--manifest" "${target_deployment_dir}/AndroidManifest.xml") + endif() + + if(EXISTS "${Bundletool_EXECUTABLE}" AND QT_USE_ANDROID_MODERN_BUNDLE) + list(APPEND test_arguments + "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_aab" + "--aab" "${android_build_dir}/${target}.aab" + "--bundletool" "${Bundletool_EXECUTABLE}" + ) + else() + list(APPEND test_arguments + "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk" + "--apk" "${android_build_dir}/${target}.apk" + ) + endif() + + set(${out_test_arguments} "${test_arguments}" PARENT_SCOPE) endfunction() diff --git a/cmake/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake index 9f220f9d78b..07fcdee268b 100644 --- a/cmake/QtPostProcessHelpers.cmake +++ b/cmake/QtPostProcessHelpers.cmake @@ -790,6 +790,8 @@ function(qt_modules_process_android_dependencies) qt_internal_get_qt_repo_known_modules(repo_known_modules) foreach (target ${repo_known_modules}) qt_internal_android_dependencies(${target}) + qt_internal_android_add_interface_permissions(${target}) + qt_internal_android_add_interface_features(${target}) endforeach() endfunction() diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake index ad8a9d65c14..8a0666b0ceb 100644 --- a/cmake/QtTestHelpers.cmake +++ b/cmake/QtTestHelpers.cmake @@ -1176,6 +1176,13 @@ function(qt_internal_collect_command_environment out_path out_plugin_path) set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}${install_prefix}") endforeach() set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}$ENV{PATH}") + if(ANDROID) + # Add android platform tools to path. Required for the correct androidtestrunner work. + _qt_internal_android_get_platform_tools_path(platform_tools) + string(PREPEND test_env_path + "${platform_tools}" "${QT_PATH_SEPARATOR}") + endif() + string(REPLACE ";" "\;" test_env_path "${test_env_path}") set(${out_path} "${test_env_path}" PARENT_SCOPE) diff --git a/coin/instructions/prepare_building_env.yaml b/coin/instructions/prepare_building_env.yaml index 20e7ef7f01c..0330369662d 100644 --- a/coin/instructions/prepare_building_env.yaml +++ b/coin/instructions/prepare_building_env.yaml @@ -7,6 +7,24 @@ instructions: - type: EnvironmentVariable variableName: CMAKE_GENERATOR variableValue: Ninja + - type: Group + instructions: + - type: AppendToEnvironmentVariable + variableName: COMMON_CMAKE_ARGS + variableValue: " -DCMAKE_MAKE_PROGRAM={{.Env.NINJA_EXECUTABLE}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_NON_QTBASE_CMAKE_ARGS + variableValue: " -DCMAKE_MAKE_PROGRAM={{.Env.NINJA_EXECUTABLE}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_TARGET_CMAKE_ARGS + variableValue: " -DCMAKE_MAKE_PROGRAM={{.Env.NINJA_EXECUTABLE}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_NON_QTBASE_TARGET_CMAKE_ARGS + variableValue: " -DCMAKE_MAKE_PROGRAM={{.Env.NINJA_EXECUTABLE}}" + enable_if: + condition: runtime + env_var: NINJA_EXECUTABLE + not_equals_value: null # Set path separator based on host platform. # \ on Windows (double \\ for escaping the backslash) @@ -646,6 +664,26 @@ instructions: property: features contains_value: Sccache + # VCPKG + - type: Group + instructions: + - type: AppendToEnvironmentVariable + variableName: COMMON_NON_QTBASE_CMAKE_ARGS + variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_TEST_CMAKE_ARGS + variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_EXAMPLES_CMAKE_ARGS + variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}" + - type: AppendToEnvironmentVariable + variableName: COMMON_NON_QTBASE_TARGET_CMAKE_ARGS + variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}" + enable_if: + condition: runtime + env_var: USE_VCPKG + equals_value: "ON" + # Specify a custom examples installation directory, so that the built example binaries are not # packaged into the artifact archive together with the Qt libraries. # Also specify that during examples deployment, only a subset of examples should be deployed, to diff --git a/configure.cmake b/configure.cmake index 92fe4dba448..8d96ba7e1f0 100644 --- a/configure.cmake +++ b/configure.cmake @@ -1116,13 +1116,12 @@ qt_feature("network" PRIVATE ) qt_feature("printsupport" PRIVATE LABEL "Qt PrintSupport" - CONDITION QT_FEATURE_widgets AND NOT WASM + CONDITION QT_FEATURE_widgets SECTION "Module" PURPOSE "Provides the Qt PrintSupport module." ) qt_feature("sql" PRIVATE LABEL "Qt Sql" - CONDITION NOT WASM SECTION "Module" PURPOSE "Provides the Sql module." ) diff --git a/dist/REUSE.toml b/dist/REUSE.toml index f14104bf6f4..6e06fc5353f 100644 --- a/dist/REUSE.toml +++ b/dist/REUSE.toml @@ -4,5 +4,5 @@ version = 1 path = ["*"] precedence = "override" comment = "Licensed as documentation." -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" diff --git a/doc/global/includes/cli-build-cmake.qdocinc b/doc/global/includes/cli-build-cmake.qdocinc index b4c6ffccb4b..5f30e8632b7 100644 --- a/doc/global/includes/cli-build-cmake.qdocinc +++ b/doc/global/includes/cli-build-cmake.qdocinc @@ -28,7 +28,7 @@ \badcode \QtVersion md notepad-build cd notepad-build - C:\Qt\\1\msvc2019_64\bin\qt-cmake -GNinja C:\Examples\notepad + C:\Qt\\1\msvc2022_64\bin\qt-cmake -GNinja C:\Examples\notepad ninja \endcode diff --git a/examples/widgets/doc/images/treemodel-structure.png b/examples/widgets/doc/images/treemodel-structure.png Binary files differdeleted file mode 100644 index 778841b6fd8..00000000000 --- a/examples/widgets/doc/images/treemodel-structure.png +++ /dev/null diff --git a/examples/widgets/doc/images/treemodel-structure.svg b/examples/widgets/doc/images/treemodel-structure.svg new file mode 100644 index 00000000000..f8bc24803bf --- /dev/null +++ b/examples/widgets/doc/images/treemodel-structure.svg @@ -0,0 +1,93 @@ +<svg + preserveAspectRatio="none" + width="192" + height="350" + viewBox="-25 -30 153.6 280" + version="1.1" + xmlns="http://www.w3.org/2000/svg"> + +<!-- Root node --> +<g transform="translate(0, 0)"> +<path fill="none" stroke="#333" stroke-dasharray="4" d="M -10 -10 l 20 0 l 0 20 l -20 0 z" /> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="left" dominant-baseline="central" font-weight="bold"> + Root item (empty) +</text> +</g> + +<!-- Root spine vertical line solid part --> +<path fill="none" stroke="#333" d="M 0 10 l 0 190" /> + +<!-- Root spine vertical line dotted continuation --> +<path fill="none" stroke="#333" stroke-dasharray="4" d="M 0 200 l 0 30" /> + +<!-- Horizontal lines from Root spine to children A, E, F --> +<path fill="none" stroke="#333" d="M 0 40 l 20 0" /> +<path fill="none" stroke="#333" d="M 0 160 l 20 0" /> +<path fill="none" stroke="#333" d="M 0 185 l 20 0" /> + +<!-- Node A with label [0] --> +<g transform="translate(30, 40)"> +<path fill="none" stroke="#333" d="M -10 -10 l 20 0 l 0 20 l -20 0 z"/> +<text x="0" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="middle" dominant-baseline="central"> + A +</text> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="start" dominant-baseline="central"> + row = 0 +</text> +</g> + +<!-- Vertical line from A to its children --> +<path fill="none" stroke="#333" d="M 30 50 l 0 80" /> + +<!-- Horizontal lines from A's spine to B, C, D --> +<path fill="none" stroke="#333" d="M 30 70 l 20 0" /> +<path fill="none" stroke="#333" d="M 30 100 l 20 0" /> +<path fill="none" stroke="#333" d="M 30 130 l 20 0" /> + +<!-- Node B --> +<g transform="translate(60, 70)"> +<path fill="none" stroke="#333" d="M -10 -10 l 20 0 l 0 20 l -20 0 z"/> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="start" dominant-baseline="central"> + row = 0 +</text> +</g> + +<!-- Node C --> +<g transform="translate(60, 100)"> +<path fill="none" stroke="#333" d="M -10 -10 l 20 0 l 0 20 l -20 0 z"/> +<text x="0" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="middle" dominant-baseline="central"> + B +</text> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="start" dominant-baseline="central"> + row = 1 +</text> +</g> + +<!-- Node D --> +<g transform="translate(60, 130)"> +<path fill="none" stroke="#333" d="M -10 -10 l 20 0 l 0 20 l -20 0 z"/> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="start" dominant-baseline="central"> + row = 2 +</text> +</g> + +<!-- Node E --> +<g transform="translate(30, 160)"> +<path fill="none" stroke="#333" d="M -10 -10 l 20 0 l 0 20 l -20 0 z"/> +<text x="0" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="middle" dominant-baseline="central"> + C +</text> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="start" dominant-baseline="central"> + row = 1 +</text> +</g> + +<!-- Node F --> +<g transform="translate(30, 185)"> +<path fill="none" stroke="#333" d="M -10 -10 l 20 0 l 0 20 l -20 0 z"/> +<text x="15" y="0" font-size="12" font-family="Arial" fill="#333" text-anchor="start" dominant-baseline="central"> + row = 2 +</text> +</g> + +</svg> diff --git a/examples/widgets/doc/src/shortcuteditor.qdoc b/examples/widgets/doc/src/shortcuteditor.qdoc index 9999a184215..b17835ba168 100644 --- a/examples/widgets/doc/src/shortcuteditor.qdoc +++ b/examples/widgets/doc/src/shortcuteditor.qdoc @@ -30,7 +30,7 @@ two columns of data. \table - \row \li \inlineimage treemodel-structure.png + \row \li \inlineimage treemodel-structure.svg \li \b{Shortcut Editor Structure} The data is stored internally in the model using ShortcutEditorModelItem diff --git a/examples/widgets/doc/src/simpletreemodel.qdoc b/examples/widgets/doc/src/simpletreemodel.qdoc index d8e5a6faa8b..be4889adbe9 100644 --- a/examples/widgets/doc/src/simpletreemodel.qdoc +++ b/examples/widgets/doc/src/simpletreemodel.qdoc @@ -40,7 +40,7 @@ \target SimpleTreeModelStructure \table - \row \li \inlineimage treemodel-structure.png + \row \li \inlineimage treemodel-structure.svg \li \b{Simple Tree Model Structure} The data is stored internally in the model using \c TreeItem objects that diff --git a/mkspecs/REUSE.toml b/mkspecs/REUSE.toml index 7f5d9f5040a..7f452f8794d 100644 --- a/mkspecs/REUSE.toml +++ b/mkspecs/REUSE.toml @@ -8,13 +8,13 @@ path = ["**.plist*", "features/data/configure.json", "features/data/testserver/D "macx-xcode/default.xcscheme"] precedence = "closest" comment = "build system" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] path = ["modules/README"] comment = "documentation" precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" diff --git a/src/3rdparty/freetype/REUSE.toml b/src/3rdparty/freetype/REUSE.toml index f2fc6b3e2bc..6cc074c1947 100644 --- a/src/3rdparty/freetype/REUSE.toml +++ b/src/3rdparty/freetype/REUSE.toml @@ -10,5 +10,5 @@ SPDX-License-Identifier = "FTL OR GPL-2.0-only" path = ["CMakeLists.txt"] precedence = "override" SPDX-FileCopyrightText = ["Copyright (C) 2013-2024 by David Turner, Robert Wilhelm, and Werner Lemberg.", -"Copyright (C) 2024 The Qt Company Ltd."] +"Copyright (C) The Qt Company Ltd."] SPDX-License-Identifier = "FTL OR GPL-2.0-only" diff --git a/src/3rdparty/freetype/docs/REUSE.toml b/src/3rdparty/freetype/docs/REUSE.toml index 873ff919050..84576882473 100644 --- a/src/3rdparty/freetype/docs/REUSE.toml +++ b/src/3rdparty/freetype/docs/REUSE.toml @@ -46,5 +46,5 @@ SPDX-License-Identifier = "GPL-2.0-only" path = "REUSE.toml" comment = "The copyrights inside those files are not related to the file" precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" diff --git a/src/3rdparty/freetype/src/pcf/REUSE.toml b/src/3rdparty/freetype/src/pcf/REUSE.toml index 4eecd7a22bc..52d5b551e34 100644 --- a/src/3rdparty/freetype/src/pcf/REUSE.toml +++ b/src/3rdparty/freetype/src/pcf/REUSE.toml @@ -24,5 +24,5 @@ SPDX-License-Identifier = "FTL OR GPL-2.0-only" path = ["REUSE.toml"] comment = "The copyrights inside those files are not related to the file" precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" diff --git a/src/3rdparty/freetype/src/sdf/REUSE.toml b/src/3rdparty/freetype/src/sdf/REUSE.toml index f25732fce90..ff7ddb872db 100644 --- a/src/3rdparty/freetype/src/sdf/REUSE.toml +++ b/src/3rdparty/freetype/src/sdf/REUSE.toml @@ -11,5 +11,5 @@ SPDX-License-Identifier = "FTL OR GPL-2.0-only" path = "REUSE.toml" comment = "The copyrights inside those files are not related to the file" precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" diff --git a/src/3rdparty/gradle/gradle.properties b/src/3rdparty/gradle/gradle.properties index 4fe1674abd3..3472b396d96 100644 --- a/src/3rdparty/gradle/gradle.properties +++ b/src/3rdparty/gradle/gradle.properties @@ -16,3 +16,6 @@ org.gradle.parallel=true # Allow AndroidX usage android.useAndroidX=true + +# User-defined properties +@EXTRA_PROPERTIES@ diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE index 90c766594e7..516e078082d 100644 --- a/src/3rdparty/libpng/ANNOUNCE +++ b/src/3rdparty/libpng/ANNOUNCE @@ -1,5 +1,5 @@ -libpng 1.6.49 - June 12, 2025 -============================= +libpng 1.6.50 - July 1, 2025 +============================ This is a public release of libpng, intended for use in production code. @@ -9,13 +9,13 @@ Files available for download Source files with LF line endings (for Unix/Linux): - * libpng-1.6.49.tar.xz (LZMA-compressed, recommended) - * libpng-1.6.49.tar.gz (deflate-compressed) + * libpng-1.6.50.tar.xz (LZMA-compressed, recommended) + * libpng-1.6.50.tar.gz (deflate-compressed) Source files with CRLF line endings (for Windows): - * lpng1649.7z (LZMA-compressed, recommended) - * lpng1649.zip (deflate-compressed) + * lpng1650.7z (LZMA-compressed, recommended) + * lpng1650.zip (deflate-compressed) Other information: @@ -25,13 +25,18 @@ Other information: * TRADEMARK.md -Changes from version 1.6.48 to version 1.6.49 +Changes from version 1.6.49 to version 1.6.50 --------------------------------------------- - * Added SIMD-optimized code for the RISC-V Vector Extension (RVV). - (Contributed by Manfred Schlaegl, Dragos Tiselice and Filip Wasil) - * Added various fixes and improvements to the build scripts and to - the sample code. + * Improved the detection of the RVV Extension on the RISC-V platform. + (Contributed by Filip Wasil) + * Replaced inline ASM with C intrinsics in the RVV code. + (Contributed by Filip Wasil) + * Fixed a decoder defect in which unknown chunks trailing IDAT, set + to go through the unknown chunk handler, incorrectly triggered + out-of-place IEND errors. + (Contributed by John Bowler) + * Fixed the CMake file for cross-platform builds that require `libm`. Send comments/corrections/commendations to png-mng-implement at lists.sf.net. diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES index 0c0fa6dc70b..b6499b1f34c 100644 --- a/src/3rdparty/libpng/CHANGES +++ b/src/3rdparty/libpng/CHANGES @@ -6267,6 +6267,17 @@ Version 1.6.49 [June 12, 2025] Added various fixes and improvements to the build scripts and to the sample code. +Version 1.6.50 [July 1, 2025] + Improved the detection of the RVV Extension on the RISC-V platform. + (Contributed by Filip Wasil) + Replaced inline ASM with C intrinsics in the RVV code. + (Contributed by Filip Wasil) + Fixed a decoder defect in which unknown chunks trailing IDAT, set + to go through the unknown chunk handler, incorrectly triggered + out-of-place IEND errors. + (Contributed by John Bowler) + Fixed the CMake file for cross-platform builds that require `libm`. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net. Subscription is required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README index 9f2b2d0ed53..2eb633ac0fb 100644 --- a/src/3rdparty/libpng/README +++ b/src/3rdparty/libpng/README @@ -1,4 +1,4 @@ -README for libpng version 1.6.49 +README for libpng version 1.6.50 ================================ See the note about version numbers near the top of `png.h`. diff --git a/src/3rdparty/libpng/libpng-manual.txt b/src/3rdparty/libpng/libpng-manual.txt index f4e151f0c23..6c07e1022b6 100644 --- a/src/3rdparty/libpng/libpng-manual.txt +++ b/src/3rdparty/libpng/libpng-manual.txt @@ -9,7 +9,7 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng version 1.6.36, December 2018, through 1.6.49 - June 2025 + libpng version 1.6.36, December 2018, through 1.6.50 - July 2025 Updated and distributed by Cosmin Truta Copyright (c) 2018-2025 Cosmin Truta @@ -65,18 +65,22 @@ Libpng was written as a companion to the PNG specification, as a way of reducing the amount of time and effort it takes to support the PNG file format in application programs. -The PNG specification (second edition), November 2003, is available as +The PNG specification (Third Edition), June 2025, is available as +a W3C Recommendation at +<https://www.w3.org/TR/2025/REC-png-3-20250624/>. + +The PNG specification (Second Edition), November 2003, is available as a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at <https://www.w3.org/TR/2003/REC-PNG-20031110/>. The W3C and ISO documents have identical technical content. The PNG-1.2 specification is available at -<https://png-mng.sourceforge.io/pub/png/spec/1.2/>. -It is technically equivalent -to the PNG specification (second edition) but has some additional material. +<https://www.libpng.org/pub/png/spec/1.2/>. +It is technically equivalent to the PNG specification (Second Edition) +but has some additional material. The PNG-1.0 specification is available as RFC 2083 at -<https://png-mng.sourceforge.io/pub/png/spec/1.0/> and as a +<https://www.libpng.org/pub/png/spec/1.0/> and as a W3C Recommendation at <https://www.w3.org/TR/REC-png-961001>. Some additional chunks are described in the special-purpose public chunks diff --git a/src/3rdparty/libpng/png.c b/src/3rdparty/libpng/png.c index 8a77b6db5f2..6e21915c402 100644 --- a/src/3rdparty/libpng/png.c +++ b/src/3rdparty/libpng/png.c @@ -13,7 +13,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_49 Your_png_h_is_not_version_1_6_49; +typedef png_libpng_version_1_6_50 Your_png_h_is_not_version_1_6_50; /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the * corresponding macro definitions. This causes a compile time failure if @@ -815,7 +815,7 @@ png_get_copyright(png_const_structrp png_ptr) return PNG_STRING_COPYRIGHT #else return PNG_STRING_NEWLINE \ - "libpng version 1.6.49" PNG_STRING_NEWLINE \ + "libpng version 1.6.50" PNG_STRING_NEWLINE \ "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h index f43e49c521a..b9985e81680 100644 --- a/src/3rdparty/libpng/png.h +++ b/src/3rdparty/libpng/png.h @@ -1,6 +1,6 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.49 + * libpng version 1.6.50 * * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson @@ -14,7 +14,7 @@ * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.35, July 2018: * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.49, June 2025: + * libpng versions 1.6.36, December 2018, through 1.6.50, July 2025: * Cosmin Truta * See also "Contributing Authors", below. */ @@ -238,7 +238,7 @@ * ... * 1.5.30 15 10530 15.so.15.30[.0] * ... - * 1.6.49 16 10649 16.so.16.49[.0] + * 1.6.50 16 10650 16.so.16.50[.0] * * Henceforth the source version will match the shared-library major and * minor numbers; the shared-library major version number will be used for @@ -274,7 +274,7 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.49" +#define PNG_LIBPNG_VER_STRING "1.6.50" #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n" /* The versions of shared library builds should stay in sync, going forward */ @@ -285,7 +285,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 49 +#define PNG_LIBPNG_VER_RELEASE 50 /* This should be zero for a public release, or non-zero for a * development version. @@ -316,7 +316,7 @@ * From version 1.0.1 it is: * XXYYZZ, where XX=major, YY=minor, ZZ=release */ -#define PNG_LIBPNG_VER 10649 /* 1.6.49 */ +#define PNG_LIBPNG_VER 10650 /* 1.6.50 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -426,7 +426,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_6_49; +typedef char* png_libpng_version_1_6_50; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h index e92a3b1eca4..d1081b54ddd 100644 --- a/src/3rdparty/libpng/pngconf.h +++ b/src/3rdparty/libpng/pngconf.h @@ -1,6 +1,6 @@ /* pngconf.h - machine-configurable file for libpng * - * libpng version 1.6.49 + * libpng version 1.6.50 * * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h index ea61c441ba6..f15fc16dade 100644 --- a/src/3rdparty/libpng/pnglibconf.h +++ b/src/3rdparty/libpng/pnglibconf.h @@ -1,6 +1,6 @@ /* pnglibconf.h - library build configuration */ -/* libpng version 1.6.49 */ +/* libpng version 1.6.50 */ /* Copyright (c) 2018-2025 Cosmin Truta */ /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ diff --git a/src/3rdparty/libpng/pngpread.c b/src/3rdparty/libpng/pngpread.c index 0a3e822cf47..37aa432aeca 100644 --- a/src/3rdparty/libpng/pngpread.c +++ b/src/3rdparty/libpng/pngpread.c @@ -229,6 +229,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) png_benign_error(png_ptr, "Too many IDATs found"); } + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + /* These flags must be set consistently for all non-IDAT chunks, + * including the unknown chunks. + */ + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT; + } + if (chunk_name == png_IHDR) { if (png_ptr->push_length != 13) diff --git a/src/3rdparty/libpng/pngpriv.h b/src/3rdparty/libpng/pngpriv.h index cb44a6aec8a..e3054b90aae 100644 --- a/src/3rdparty/libpng/pngpriv.h +++ b/src/3rdparty/libpng/pngpriv.h @@ -154,11 +154,7 @@ * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS. */ -# if defined(__riscv) && defined(PNG_ALIGNED_MEMORY_SUPPORTED) -# define PNG_RISCV_RVV_OPT 1 -# else -# define PNG_RISCV_RVV_OPT 0 -# endif +# define PNG_RISCV_RVV_OPT 0 #endif #if PNG_ARM_NEON_OPT > 0 diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c index a0dbf2ae208..212afb7d215 100644 --- a/src/3rdparty/libpng/pngread.c +++ b/src/3rdparty/libpng/pngread.c @@ -702,7 +702,12 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) png_uint_32 chunk_name = png_ptr->chunk_name; if (chunk_name != png_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + { + /* These flags must be set consistently for all non-IDAT chunks, + * including the unknown chunks. + */ + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT; + } if (chunk_name == png_IEND) png_handle_chunk(png_ptr, info_ptr, length); diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c index 7d9a00186dc..e7c7bbe48e9 100644 --- a/src/3rdparty/libpng/pngrutil.c +++ b/src/3rdparty/libpng/pngrutil.c @@ -2412,10 +2412,6 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif - /* TODO: this doesn't work and shouldn't be necessary. */ - if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - png_ptr->mode |= PNG_AFTER_IDAT; - buffer = png_read_buffer(png_ptr, length+1); if (buffer == NULL) @@ -2486,10 +2482,6 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif - /* TODO: should not be necessary. */ - if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - png_ptr->mode |= PNG_AFTER_IDAT; - /* Note, "length" is sufficient here; we won't be adding * a null terminator later. The limit check in png_handle_chunk should be * sufficient. @@ -2606,10 +2598,6 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif - /* TODO: should not be necessary. */ - if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - png_ptr->mode |= PNG_AFTER_IDAT; - buffer = png_read_buffer(png_ptr, length+1); if (buffer == NULL) diff --git a/src/3rdparty/libpng/qt_attribution.json b/src/3rdparty/libpng/qt_attribution.json index 49d0b6ca79f..9327dee564c 100644 --- a/src/3rdparty/libpng/qt_attribution.json +++ b/src/3rdparty/libpng/qt_attribution.json @@ -7,8 +7,8 @@ "Description": "libpng is the official PNG reference library.", "Homepage": "http://www.libpng.org/pub/png/libpng.html", - "Version": "1.6.49", - "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.49.tar.xz", + "Version": "1.6.50", + "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.50.tar.xz", "PURL": "pkg:github/pnggroup/libpng@v$<VERSION>", "CPE": "cpe:2.3:a:libpng:libpng:$<VERSION>:*:*:*:*:*:*:*", diff --git a/src/3rdparty/wayland/extensions/REUSE.toml b/src/3rdparty/wayland/extensions/REUSE.toml index 7debc4f4e09..72b4251a911 100644 --- a/src/3rdparty/wayland/extensions/REUSE.toml +++ b/src/3rdparty/wayland/extensions/REUSE.toml @@ -4,5 +4,5 @@ version = 1 path = "qt-text-input-method-unstable-v1.xml" precedence = "closest" comment = "License is in full text in file. Should it be changed?" -SPDX-FileCopyrightText = "Copyright © 2020 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright © The Qt Company Ltd." SPDX-License-Identifier = "MIT" diff --git a/src/android/CMakeLists.txt b/src/android/CMakeLists.txt index 7c99ce7264e..12fbca624b3 100644 --- a/src/android/CMakeLists.txt +++ b/src/android/CMakeLists.txt @@ -9,6 +9,7 @@ if (ANDROID) add_subdirectory(java) add_subdirectory(templates) add_subdirectory(templates_aar) + add_subdirectory(templates_cmake) endif() qt_internal_add_java_documentation(Global) diff --git a/src/android/REUSE.toml b/src/android/REUSE.toml index 7d5a22fd2f7..04b82f125e9 100644 --- a/src/android/REUSE.toml +++ b/src/android/REUSE.toml @@ -1,15 +1,21 @@ version = 1 [[annotations]] -path = ["jar/build.gradle", "jar/settings.gradle", "templates/build.gradle"] +path = ["jar/build.gradle", "jar/settings.gradle", "templates/build.gradle", "templates_cmake/**", "templates_aar/**", "templates/**", "**.xml"] precedence = "closest" comment = "double check" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" [[annotations]] path = ["java/READ-THIS-BEFORE-MANUALLY-ADDING-FILES-TO-PACKAGE.txt"] comment = "documentation" precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" + +[[annotations]] +path = ["**.gitignore"] +precedence = "closest" +SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" diff --git a/src/android/jar/src/org/qtproject/qt/android/QtView.java b/src/android/jar/src/org/qtproject/qt/android/QtView.java index 9d7850cb517..afe4d005402 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtView.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java @@ -1,6 +1,6 @@ // Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -// Qt-Security score:critical reason:executing-external-code +// Qt-Security score:critical reason:execute-external-code package org.qtproject.qt.android; diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle index 6595cb5358f..b6c4797fde7 100644 --- a/src/android/templates/build.gradle +++ b/src/android/templates/build.gradle @@ -70,8 +70,8 @@ android { abortOnError = false } - // Do not compress Qt binary resources file aaptOptions { + // Do not compress Qt binary resources file noCompress 'rcc' } diff --git a/src/android/templates_cmake/CMakeLists.txt b/src/android/templates_cmake/CMakeLists.txt new file mode 100644 index 00000000000..546a4fc50f3 --- /dev/null +++ b/src/android/templates_cmake/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +set(templates_files + "${CMAKE_CURRENT_SOURCE_DIR}/settings.gradle.in" + "${CMAKE_CURRENT_SOURCE_DIR}/gradle.properties.in" +) + +set(app_template_files + "${CMAKE_CURRENT_SOURCE_DIR}/app/gradle.properties.in" + "${CMAKE_CURRENT_SOURCE_DIR}/app/build.gradle.in" + "${CMAKE_CURRENT_SOURCE_DIR}/app/AndroidManifest.xml.in" +) + +set(dynamic_feature_files + "${CMAKE_CURRENT_SOURCE_DIR}/dynamic_feature/AndroidManifest.xml.in" + "${CMAKE_CURRENT_SOURCE_DIR}/dynamic_feature/build.gradle.in" +) + +add_custom_target(Qt6AndroidCMakeTemplates + SOURCES + ${templates_files} +) + +qt_path_join(destination ${QT_INSTALL_DIR} ${INSTALL_DATADIR} "src/android/templates_cmake") + +qt_copy_or_install(FILES ${templates_files} DESTINATION "${destination}") +qt_copy_or_install(FILES ${app_template_files} DESTINATION "${destination}/app") +qt_copy_or_install(FILES ${dynamic_feature_files} DESTINATION "${destination}/dynamic_feature") + +if(NOT QT_WILL_INSTALL) + qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates + FILES ${templates_files} + DESTINATION ${destination} + ) + + qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates + FILES ${app_templates_files} + DESTINATION ${destination}/app + ) + + qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates + FILES ${dynamic_feature_files} + DESTINATION ${destination}/dynamic_feature + ) +endif() diff --git a/src/android/templates_cmake/app/AndroidManifest.xml.in b/src/android/templates_cmake/app/AndroidManifest.xml.in new file mode 100644 index 00000000000..61c33cc7657 --- /dev/null +++ b/src/android/templates_cmake/app/AndroidManifest.xml.in @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:dist="http://schemas.android.com/apk/distribution" + package="@APP_PACKAGE_NAME@" + android:installLocation="auto" + android:versionCode="@APP_VERSION_CODE@" + android:versionName="@APP_VERSION_NAME@"> + @APP_PERMISSIONS@ + @APP_FEATURES@ + <dist:module dist:instant="true"/> + <supports-screens + android:anyDensity="true" + android:largeScreens="true" + android:normalScreens="true" + android:smallScreens="true" /> + <application + android:name="org.qtproject.qt.android.bindings.QtApplication" + android:hardwareAccelerated="true" + android:label="@APP_NAME@" + @APP_ICON@ + android:requestLegacyExternalStorage="true" + android:allowBackup="true" + android:fullBackupOnly="false"> + <activity + android:name="org.qtproject.qt.android.bindings.QtActivity" + android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" + android:launchMode="singleTop" + android:screenOrientation="unspecified" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + + <meta-data + android:name="android.app.lib_name" + android:value="@APP_LIB_NAME@" /> + + <meta-data + android:name="android.app.arguments" + android:value="@APP_ARGUMENTS@" /> + </activity> + + <provider + android:name="androidx.core.content.FileProvider" + android:authorities="${applicationId}.qtprovider" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/qtprovider_paths"/> + </provider> + </application> +</manifest> diff --git a/src/android/templates_cmake/app/build.gradle.in b/src/android/templates_cmake/app/build.gradle.in new file mode 100644 index 00000000000..917f371e46f --- /dev/null +++ b/src/android/templates_cmake/app/build.gradle.in @@ -0,0 +1,53 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.10.1' + } +} + +apply plugin: '@GRADLE_PLUGIN_TYPE@' + +dependencies { + @GRADLE_DEPENDENCIES@ +} + +android { + namespace '@PACKAGE_NAME@' + compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@' + buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@' + ndkVersion '@ANDROID_NDK_REVISION@' + + defaultConfig { + @DEFAULT_CONFIG_VALUES@ + } + + sourceSets { + main { +@SOURCE_SETS@ + } + } + + tasks.withType(JavaCompile) { + options.incremental = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + aaptOptions { + // Do not compress Qt binary resources file + noCompress 'rcc' + } + + @ANDROID_DEPLOYMENT_EXTRAS@ +} diff --git a/src/android/templates_cmake/app/gradle.properties.in b/src/android/templates_cmake/app/gradle.properties.in new file mode 100644 index 00000000000..1136551f3fa --- /dev/null +++ b/src/android/templates_cmake/app/gradle.properties.in @@ -0,0 +1 @@ +# Extend this template with the extra gradle properties applicable for Android app. diff --git a/src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in b/src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in new file mode 100644 index 00000000000..9945ec76f27 --- /dev/null +++ b/src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:dist="http://schemas.android.com/apk/distribution" + split="@APP_TARGET@" + android:isFeatureSplit="true"> + <dist:module + dist:instant="true" + dist:title="@TITLE_VAR@"> + <dist:delivery> + <dist:on-demand /> + </dist:delivery> + <dist:fusing dist:include="false" /> + </dist:module> + <application android:hasCode="false"/> +</manifest> diff --git a/src/android/templates_cmake/dynamic_feature/build.gradle.in b/src/android/templates_cmake/dynamic_feature/build.gradle.in new file mode 100644 index 00000000000..917f371e46f --- /dev/null +++ b/src/android/templates_cmake/dynamic_feature/build.gradle.in @@ -0,0 +1,53 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.10.1' + } +} + +apply plugin: '@GRADLE_PLUGIN_TYPE@' + +dependencies { + @GRADLE_DEPENDENCIES@ +} + +android { + namespace '@PACKAGE_NAME@' + compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@' + buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@' + ndkVersion '@ANDROID_NDK_REVISION@' + + defaultConfig { + @DEFAULT_CONFIG_VALUES@ + } + + sourceSets { + main { +@SOURCE_SETS@ + } + } + + tasks.withType(JavaCompile) { + options.incremental = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + aaptOptions { + // Do not compress Qt binary resources file + noCompress 'rcc' + } + + @ANDROID_DEPLOYMENT_EXTRAS@ +} diff --git a/src/android/templates_cmake/gradle.properties.in b/src/android/templates_cmake/gradle.properties.in new file mode 100644 index 00000000000..b751946190a --- /dev/null +++ b/src/android/templates_cmake/gradle.properties.in @@ -0,0 +1,12 @@ +# Project-wide Gradle settings. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# Enable building projects in parallel +org.gradle.parallel=true + +# Allow AndroidX usage +android.useAndroidX=true diff --git a/src/android/templates_cmake/settings.gradle.in b/src/android/templates_cmake/settings.gradle.in new file mode 100644 index 00000000000..03954ae5f9f --- /dev/null +++ b/src/android/templates_cmake/settings.gradle.in @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "@ROOT_PROJECT_NAME@" +include(":app") +@SUBPROJECTS@ diff --git a/src/assets/CMakeLists.txt b/src/assets/CMakeLists.txt index da9c0c14eea..ab07d27696e 100644 --- a/src/assets/CMakeLists.txt +++ b/src/assets/CMakeLists.txt @@ -1,6 +1,5 @@ # Copyright (C) 2024 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(icons) if (NOT INTEGRITY AND TARGET Qt6::Network AND TARGET Qt6::Concurrent) add_subdirectory(downloader) diff --git a/src/assets/icons/128x128/document-new.png b/src/assets/icons/128x128/document-new.png Binary files differdeleted file mode 100644 index 8d86a4827a7..00000000000 --- a/src/assets/icons/128x128/document-new.png +++ /dev/null diff --git a/src/assets/icons/128x128/document-open.png b/src/assets/icons/128x128/document-open.png Binary files differdeleted file mode 100644 index 2183dbbea64..00000000000 --- a/src/assets/icons/128x128/document-open.png +++ /dev/null diff --git a/src/assets/icons/128x128/document-print.png b/src/assets/icons/128x128/document-print.png Binary files differdeleted file mode 100644 index 9e7378aab2a..00000000000 --- a/src/assets/icons/128x128/document-print.png +++ /dev/null diff --git a/src/assets/icons/128x128/document-save.png b/src/assets/icons/128x128/document-save.png Binary files differdeleted file mode 100644 index e8b28406433..00000000000 --- a/src/assets/icons/128x128/document-save.png +++ /dev/null diff --git a/src/assets/icons/128x128/edit-copy.png b/src/assets/icons/128x128/edit-copy.png Binary files differdeleted file mode 100644 index 7585f4baa0c..00000000000 --- a/src/assets/icons/128x128/edit-copy.png +++ /dev/null diff --git a/src/assets/icons/128x128/edit-cut.png b/src/assets/icons/128x128/edit-cut.png Binary files differdeleted file mode 100644 index 51ede2fe37e..00000000000 --- a/src/assets/icons/128x128/edit-cut.png +++ /dev/null diff --git a/src/assets/icons/128x128/edit-delete.png b/src/assets/icons/128x128/edit-delete.png Binary files differdeleted file mode 100644 index bdf785c8285..00000000000 --- a/src/assets/icons/128x128/edit-delete.png +++ /dev/null diff --git a/src/assets/icons/128x128/edit-paste.png b/src/assets/icons/128x128/edit-paste.png Binary files differdeleted file mode 100644 index 690ffa172d9..00000000000 --- a/src/assets/icons/128x128/edit-paste.png +++ /dev/null diff --git a/src/assets/icons/128x128/edit-redo.png b/src/assets/icons/128x128/edit-redo.png Binary files differdeleted file mode 100644 index f1c97f71c25..00000000000 --- a/src/assets/icons/128x128/edit-redo.png +++ /dev/null diff --git a/src/assets/icons/128x128/edit-undo.png b/src/assets/icons/128x128/edit-undo.png Binary files differdeleted file mode 100644 index e728cbf6e03..00000000000 --- a/src/assets/icons/128x128/edit-undo.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-justify-center.png b/src/assets/icons/128x128/format-justify-center.png Binary files differdeleted file mode 100644 index 44ceb2af4d5..00000000000 --- a/src/assets/icons/128x128/format-justify-center.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-justify-fill.png b/src/assets/icons/128x128/format-justify-fill.png Binary files differdeleted file mode 100644 index b99a8507046..00000000000 --- a/src/assets/icons/128x128/format-justify-fill.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-justify-left.png b/src/assets/icons/128x128/format-justify-left.png Binary files differdeleted file mode 100644 index 2b63887b495..00000000000 --- a/src/assets/icons/128x128/format-justify-left.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-justify-right.png b/src/assets/icons/128x128/format-justify-right.png Binary files differdeleted file mode 100644 index 6c61889d595..00000000000 --- a/src/assets/icons/128x128/format-justify-right.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-text-bold.png b/src/assets/icons/128x128/format-text-bold.png Binary files differdeleted file mode 100644 index 96a5ca88a22..00000000000 --- a/src/assets/icons/128x128/format-text-bold.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-text-italic.png b/src/assets/icons/128x128/format-text-italic.png Binary files differdeleted file mode 100644 index 2bb71b4a4d3..00000000000 --- a/src/assets/icons/128x128/format-text-italic.png +++ /dev/null diff --git a/src/assets/icons/128x128/format-text-underline.png b/src/assets/icons/128x128/format-text-underline.png Binary files differdeleted file mode 100644 index ecf6830c929..00000000000 --- a/src/assets/icons/128x128/format-text-underline.png +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 32776b51a96..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 06e188b93b9..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 644e3c149af..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 16fa70493a2..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index b18bead117f..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index d9454cebf1c..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 4081cdb2ca7..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 3358426818d..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index e28b28542c6..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index fe10f57a398..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index d4ad74b0d07..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index bf0dd84bbb0..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index dde68c8514a..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 8a5e7518bdc..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 665d3ce37b5..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 4b6846a6b98..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected] Binary files differdeleted file mode 100644 index 601f73216a3..00000000000 --- a/src/assets/icons/128x128@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16/document-new.png b/src/assets/icons/16x16/document-new.png Binary files differdeleted file mode 100644 index 893e7e1aec4..00000000000 --- a/src/assets/icons/16x16/document-new.png +++ /dev/null diff --git a/src/assets/icons/16x16/document-open.png b/src/assets/icons/16x16/document-open.png Binary files differdeleted file mode 100644 index b07906f40bd..00000000000 --- a/src/assets/icons/16x16/document-open.png +++ /dev/null diff --git a/src/assets/icons/16x16/document-print.png b/src/assets/icons/16x16/document-print.png Binary files differdeleted file mode 100644 index 9341060076f..00000000000 --- a/src/assets/icons/16x16/document-print.png +++ /dev/null diff --git a/src/assets/icons/16x16/document-save.png b/src/assets/icons/16x16/document-save.png Binary files differdeleted file mode 100644 index 6238718191b..00000000000 --- a/src/assets/icons/16x16/document-save.png +++ /dev/null diff --git a/src/assets/icons/16x16/edit-copy.png b/src/assets/icons/16x16/edit-copy.png Binary files differdeleted file mode 100644 index 585f5bfc8d8..00000000000 --- a/src/assets/icons/16x16/edit-copy.png +++ /dev/null diff --git a/src/assets/icons/16x16/edit-cut.png b/src/assets/icons/16x16/edit-cut.png Binary files differdeleted file mode 100644 index 661ef1ad030..00000000000 --- a/src/assets/icons/16x16/edit-cut.png +++ /dev/null diff --git a/src/assets/icons/16x16/edit-delete.png b/src/assets/icons/16x16/edit-delete.png Binary files differdeleted file mode 100644 index 7b5998df8a4..00000000000 --- a/src/assets/icons/16x16/edit-delete.png +++ /dev/null diff --git a/src/assets/icons/16x16/edit-paste.png b/src/assets/icons/16x16/edit-paste.png Binary files differdeleted file mode 100644 index 6318a22caf3..00000000000 --- a/src/assets/icons/16x16/edit-paste.png +++ /dev/null diff --git a/src/assets/icons/16x16/edit-redo.png b/src/assets/icons/16x16/edit-redo.png Binary files differdeleted file mode 100644 index 7eb10fe899c..00000000000 --- a/src/assets/icons/16x16/edit-redo.png +++ /dev/null diff --git a/src/assets/icons/16x16/edit-undo.png b/src/assets/icons/16x16/edit-undo.png Binary files differdeleted file mode 100644 index 108712547cb..00000000000 --- a/src/assets/icons/16x16/edit-undo.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-justify-center.png b/src/assets/icons/16x16/format-justify-center.png Binary files differdeleted file mode 100644 index 6b0951fa5dd..00000000000 --- a/src/assets/icons/16x16/format-justify-center.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-justify-fill.png b/src/assets/icons/16x16/format-justify-fill.png Binary files differdeleted file mode 100644 index 6e1c10d7c45..00000000000 --- a/src/assets/icons/16x16/format-justify-fill.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-justify-left.png b/src/assets/icons/16x16/format-justify-left.png Binary files differdeleted file mode 100644 index 9dfdc89b68a..00000000000 --- a/src/assets/icons/16x16/format-justify-left.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-justify-right.png b/src/assets/icons/16x16/format-justify-right.png Binary files differdeleted file mode 100644 index 36a52081f18..00000000000 --- a/src/assets/icons/16x16/format-justify-right.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-text-bold.png b/src/assets/icons/16x16/format-text-bold.png Binary files differdeleted file mode 100644 index a079317a947..00000000000 --- a/src/assets/icons/16x16/format-text-bold.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-text-italic.png b/src/assets/icons/16x16/format-text-italic.png Binary files differdeleted file mode 100644 index 04202b2842f..00000000000 --- a/src/assets/icons/16x16/format-text-italic.png +++ /dev/null diff --git a/src/assets/icons/16x16/format-text-underline.png b/src/assets/icons/16x16/format-text-underline.png Binary files differdeleted file mode 100644 index a80368212d8..00000000000 --- a/src/assets/icons/16x16/format-text-underline.png +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 482ae52024e..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 9858b146f44..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 1672ec58971..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index f04de746731..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index bbb34cc4c22..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index d89ef6c0167..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 4c97ee24952..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 299fa776867..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 4f8849c7110..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index b3d366c53f6..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 80c3afd9a6e..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 33589ea25d0..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index ba028211355..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 8e15d0cb44f..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 754efdd9755..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 6db31a4f697..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected] Binary files differdeleted file mode 100644 index 977cde9d974..00000000000 --- a/src/assets/icons/16x16@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256/document-new.png b/src/assets/icons/256x256/document-new.png Binary files differdeleted file mode 100644 index 32776b51a96..00000000000 --- a/src/assets/icons/256x256/document-new.png +++ /dev/null diff --git a/src/assets/icons/256x256/document-open.png b/src/assets/icons/256x256/document-open.png Binary files differdeleted file mode 100644 index 06e188b93b9..00000000000 --- a/src/assets/icons/256x256/document-open.png +++ /dev/null diff --git a/src/assets/icons/256x256/document-print.png b/src/assets/icons/256x256/document-print.png Binary files differdeleted file mode 100644 index 644e3c149af..00000000000 --- a/src/assets/icons/256x256/document-print.png +++ /dev/null diff --git a/src/assets/icons/256x256/document-save.png b/src/assets/icons/256x256/document-save.png Binary files differdeleted file mode 100644 index 16fa70493a2..00000000000 --- a/src/assets/icons/256x256/document-save.png +++ /dev/null diff --git a/src/assets/icons/256x256/edit-copy.png b/src/assets/icons/256x256/edit-copy.png Binary files differdeleted file mode 100644 index b18bead117f..00000000000 --- a/src/assets/icons/256x256/edit-copy.png +++ /dev/null diff --git a/src/assets/icons/256x256/edit-cut.png b/src/assets/icons/256x256/edit-cut.png Binary files differdeleted file mode 100644 index d9454cebf1c..00000000000 --- a/src/assets/icons/256x256/edit-cut.png +++ /dev/null diff --git a/src/assets/icons/256x256/edit-delete.png b/src/assets/icons/256x256/edit-delete.png Binary files differdeleted file mode 100644 index 4081cdb2ca7..00000000000 --- a/src/assets/icons/256x256/edit-delete.png +++ /dev/null diff --git a/src/assets/icons/256x256/edit-paste.png b/src/assets/icons/256x256/edit-paste.png Binary files differdeleted file mode 100644 index 3358426818d..00000000000 --- a/src/assets/icons/256x256/edit-paste.png +++ /dev/null diff --git a/src/assets/icons/256x256/edit-redo.png b/src/assets/icons/256x256/edit-redo.png Binary files differdeleted file mode 100644 index e28b28542c6..00000000000 --- a/src/assets/icons/256x256/edit-redo.png +++ /dev/null diff --git a/src/assets/icons/256x256/edit-undo.png b/src/assets/icons/256x256/edit-undo.png Binary files differdeleted file mode 100644 index fe10f57a398..00000000000 --- a/src/assets/icons/256x256/edit-undo.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-justify-center.png b/src/assets/icons/256x256/format-justify-center.png Binary files differdeleted file mode 100644 index d4ad74b0d07..00000000000 --- a/src/assets/icons/256x256/format-justify-center.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-justify-fill.png b/src/assets/icons/256x256/format-justify-fill.png Binary files differdeleted file mode 100644 index bf0dd84bbb0..00000000000 --- a/src/assets/icons/256x256/format-justify-fill.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-justify-left.png b/src/assets/icons/256x256/format-justify-left.png Binary files differdeleted file mode 100644 index dde68c8514a..00000000000 --- a/src/assets/icons/256x256/format-justify-left.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-justify-right.png b/src/assets/icons/256x256/format-justify-right.png Binary files differdeleted file mode 100644 index 8a5e7518bdc..00000000000 --- a/src/assets/icons/256x256/format-justify-right.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-text-bold.png b/src/assets/icons/256x256/format-text-bold.png Binary files differdeleted file mode 100644 index 665d3ce37b5..00000000000 --- a/src/assets/icons/256x256/format-text-bold.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-text-italic.png b/src/assets/icons/256x256/format-text-italic.png Binary files differdeleted file mode 100644 index 4b6846a6b98..00000000000 --- a/src/assets/icons/256x256/format-text-italic.png +++ /dev/null diff --git a/src/assets/icons/256x256/format-text-underline.png b/src/assets/icons/256x256/format-text-underline.png Binary files differdeleted file mode 100644 index 601f73216a3..00000000000 --- a/src/assets/icons/256x256/format-text-underline.png +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index bfec6d0e6d1..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 630a05f622c..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index c8611c31c49..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 6f460959818..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 2f350041a05..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index e11cf6d2347..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index efe6b90bf59..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 32f54b39598..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 1f6e366535b..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 980ed370621..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index af7044ddee1..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index da14563bd68..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index c1025bf0102..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 3a07e06e0f3..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index b0f4cb09958..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 85f0cfc1d65..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected] Binary files differdeleted file mode 100644 index 51ee0aa7783..00000000000 --- a/src/assets/icons/256x256@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32/document-new.png b/src/assets/icons/32x32/document-new.png Binary files differdeleted file mode 100644 index 482ae52024e..00000000000 --- a/src/assets/icons/32x32/document-new.png +++ /dev/null diff --git a/src/assets/icons/32x32/document-open.png b/src/assets/icons/32x32/document-open.png Binary files differdeleted file mode 100644 index 9858b146f44..00000000000 --- a/src/assets/icons/32x32/document-open.png +++ /dev/null diff --git a/src/assets/icons/32x32/document-print.png b/src/assets/icons/32x32/document-print.png Binary files differdeleted file mode 100644 index 1672ec58971..00000000000 --- a/src/assets/icons/32x32/document-print.png +++ /dev/null diff --git a/src/assets/icons/32x32/document-save.png b/src/assets/icons/32x32/document-save.png Binary files differdeleted file mode 100644 index f04de746731..00000000000 --- a/src/assets/icons/32x32/document-save.png +++ /dev/null diff --git a/src/assets/icons/32x32/edit-copy.png b/src/assets/icons/32x32/edit-copy.png Binary files differdeleted file mode 100644 index bbb34cc4c22..00000000000 --- a/src/assets/icons/32x32/edit-copy.png +++ /dev/null diff --git a/src/assets/icons/32x32/edit-cut.png b/src/assets/icons/32x32/edit-cut.png Binary files differdeleted file mode 100644 index d89ef6c0167..00000000000 --- a/src/assets/icons/32x32/edit-cut.png +++ /dev/null diff --git a/src/assets/icons/32x32/edit-delete.png b/src/assets/icons/32x32/edit-delete.png Binary files differdeleted file mode 100644 index 4c97ee24952..00000000000 --- a/src/assets/icons/32x32/edit-delete.png +++ /dev/null diff --git a/src/assets/icons/32x32/edit-paste.png b/src/assets/icons/32x32/edit-paste.png Binary files differdeleted file mode 100644 index 299fa776867..00000000000 --- a/src/assets/icons/32x32/edit-paste.png +++ /dev/null diff --git a/src/assets/icons/32x32/edit-redo.png b/src/assets/icons/32x32/edit-redo.png Binary files differdeleted file mode 100644 index 4f8849c7110..00000000000 --- a/src/assets/icons/32x32/edit-redo.png +++ /dev/null diff --git a/src/assets/icons/32x32/edit-undo.png b/src/assets/icons/32x32/edit-undo.png Binary files differdeleted file mode 100644 index b3d366c53f6..00000000000 --- a/src/assets/icons/32x32/edit-undo.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-justify-center.png b/src/assets/icons/32x32/format-justify-center.png Binary files differdeleted file mode 100644 index 80c3afd9a6e..00000000000 --- a/src/assets/icons/32x32/format-justify-center.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-justify-fill.png b/src/assets/icons/32x32/format-justify-fill.png Binary files differdeleted file mode 100644 index 33589ea25d0..00000000000 --- a/src/assets/icons/32x32/format-justify-fill.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-justify-left.png b/src/assets/icons/32x32/format-justify-left.png Binary files differdeleted file mode 100644 index ba028211355..00000000000 --- a/src/assets/icons/32x32/format-justify-left.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-justify-right.png b/src/assets/icons/32x32/format-justify-right.png Binary files differdeleted file mode 100644 index 8e15d0cb44f..00000000000 --- a/src/assets/icons/32x32/format-justify-right.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-text-bold.png b/src/assets/icons/32x32/format-text-bold.png Binary files differdeleted file mode 100644 index 754efdd9755..00000000000 --- a/src/assets/icons/32x32/format-text-bold.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-text-italic.png b/src/assets/icons/32x32/format-text-italic.png Binary files differdeleted file mode 100644 index 6db31a4f697..00000000000 --- a/src/assets/icons/32x32/format-text-italic.png +++ /dev/null diff --git a/src/assets/icons/32x32/format-text-underline.png b/src/assets/icons/32x32/format-text-underline.png Binary files differdeleted file mode 100644 index 977cde9d974..00000000000 --- a/src/assets/icons/32x32/format-text-underline.png +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index c9245760612..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 68e75b549a0..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index b7843367393..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index f4cca4b3238..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 9690d6bb041..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 408b0ae19b0..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 58abfc1fa53..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index b8c288f6c70..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 89fcd33c300..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 6f7ad2cb402..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 9b2cc1ed160..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 1212e9f7613..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 8c0eca3037e..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index fb0ed702525..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 0e67ead0b8c..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index f746f8956f8..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected] Binary files differdeleted file mode 100644 index 47d6fced026..00000000000 --- a/src/assets/icons/32x32@2/[email protected] +++ /dev/null diff --git a/src/assets/icons/CMakeLists.txt b/src/assets/icons/CMakeLists.txt deleted file mode 100644 index f5adb229d85..00000000000 --- a/src/assets/icons/CMakeLists.txt +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright (C) 2023 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -qt_internal_add_module(ExampleIconsPrivate - CONFIG_MODULE_NAME example_icons - STATIC - INTERNAL_MODULE - NO_GENERATE_CPP_EXPORTS -) - -set(icons_resource_files - index.theme - 16x16/document-new.png - 16x16/document-open.png - 16x16/document-print.png - 16x16/document-save.png - 16x16/edit-copy.png - 16x16/edit-cut.png - 16x16/edit-delete.png - 16x16/edit-paste.png - 16x16/edit-redo.png - 16x16/edit-undo.png - 16x16/format-justify-center.png - 16x16/format-justify-fill.png - 16x16/format-justify-left.png - 16x16/format-justify-right.png - 16x16/format-text-bold.png - 16x16/format-text-italic.png - 16x16/format-text-underline.png - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 16x16@2/[email protected] - 32x32/document-new.png - 32x32/document-open.png - 32x32/document-print.png - 32x32/document-save.png - 32x32/edit-copy.png - 32x32/edit-cut.png - 32x32/edit-delete.png - 32x32/edit-paste.png - 32x32/edit-redo.png - 32x32/edit-undo.png - 32x32/format-justify-center.png - 32x32/format-justify-fill.png - 32x32/format-justify-left.png - 32x32/format-justify-right.png - 32x32/format-text-bold.png - 32x32/format-text-italic.png - 32x32/format-text-underline.png - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 32x32@2/[email protected] - 128x128/document-new.png - 128x128/document-open.png - 128x128/document-print.png - 128x128/document-save.png - 128x128/edit-copy.png - 128x128/edit-cut.png - 128x128/edit-delete.png - 128x128/edit-paste.png - 128x128/edit-redo.png - 128x128/edit-undo.png - 128x128/format-justify-center.png - 128x128/format-justify-fill.png - 128x128/format-justify-left.png - 128x128/format-justify-right.png - 128x128/format-text-bold.png - 128x128/format-text-italic.png - 128x128/format-text-underline.png - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 128x128@2/[email protected] - 256x256/document-new.png - 256x256/document-open.png - 256x256/document-print.png - 256x256/document-save.png - 256x256/edit-copy.png - 256x256/edit-cut.png - 256x256/edit-delete.png - 256x256/edit-paste.png - 256x256/edit-redo.png - 256x256/edit-undo.png - 256x256/format-justify-center.png - 256x256/format-justify-fill.png - 256x256/format-justify-left.png - 256x256/format-justify-right.png - 256x256/format-text-bold.png - 256x256/format-text-italic.png - 256x256/format-text-underline.png - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - 256x256@2/[email protected] - scalable/document-new.svg - scalable/document-open.svg - scalable/document-print.svg - scalable/document-save.svg - scalable/edit-copy.svg - scalable/edit-cut.svg - scalable/edit-delete.svg - scalable/edit-paste.svg - scalable/edit-redo.svg - scalable/edit-undo.svg - scalable/format-justify-center.svg - scalable/format-justify-fill.svg - scalable/format-justify-left.svg - scalable/format-justify-right.svg - scalable/format-text-bold.svg - scalable/format-text-italic.svg - scalable/format-text-underline.svg -) - -qt_internal_add_resource(ExampleIconsPrivate "example_icons" - PREFIX - "/qt-project.org/icons/example_icons" - FILES - ${icons_resource_files} -) - diff --git a/src/assets/icons/README b/src/assets/icons/README deleted file mode 100644 index 26d94e9ff13..00000000000 --- a/src/assets/icons/README +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (C) 2023 The Qt Company Ltd. -SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -Setting up a project for using Example icon library - -1. Add ExampleIconsPrivate component to your project CMakeList.txt file - ... - find_package(Qt6 - REQUIRED COMPONENTS Core Gui Widgets ExampleIconsPrivate - ) - - target_link_libraries(imageviewer PRIVATE - Qt6::Core - Qt6::Gui - Qt6::Widgets - Qt6::ExampleIconsPrivate - ) - ... - -2. Load the theme - ... - QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() << u":/qt-project.org/icons"_s); - QIcon::setFallbackThemeName(u"example_icons"_s); - ... - -3. Use the icons - ... - const QIcon openIcon = QIcon::fromTheme("document-open"); - ... diff --git a/src/assets/icons/index.theme b/src/assets/icons/index.theme deleted file mode 100644 index e389719e01c..00000000000 --- a/src/assets/icons/index.theme +++ /dev/null @@ -1,46 +0,0 @@ -[Icon Theme] -Name=example_icons - -Directories=16x16,16x16@2,32x32,32x32@2,128x128,128x128@2,256x256,256x256@2,scalable - -[16x16] -Size=16 -Type=Fixed - -[16x16@2] -Size=16 -Scale=2 -Type=Fixed - -[32x32] -Size=32 -Type=Fixed - -[32x32@2] -Size=32 -Scale=2 -Type=Fixed - -[128x128] -Size=128 -Type=Fixed - -[128x128@2] -Size=128 -Scale=2 -Type=Fixed - -[256x256] -Size=256 -Type=Fixed - -[256x256@2] -Size=256 -Scale=2 -Type=Fixed - -[scalable] -Size=512 -Type=Scalable -MinSize=16 -MaxSize=512 diff --git a/src/assets/icons/scalable/document-new.svg b/src/assets/icons/scalable/document-new.svg deleted file mode 100644 index b926a7b0e11..00000000000 --- a/src/assets/icons/scalable/document-new.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_New" d="m15,13c0,.28-.22.5-.5.5h-2v2c0,.28-.22.5-.5.5s-.5-.22-.5-.5v-2h-2c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h2v-2c0-.28.22-.5.5-.5s.5.22.5.5v2h2c.28,0,.5.22.5.5Zm-12,2h5v1H3c-1.1,0-2-.9-2-2V2C1,.9,1.9,0,3,0h7c1.14,1.14,2.93,2.93,4,4v5h-1v-4h-2c-1.1,0-2-.9-2-2V1H3c-.55,0-1,.45-1,1v12c0,.55.45,1,1,1ZM10,1.41v1.59c0,.55.45,1,1,1h1.59l-.82-.82-1.76-1.76Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/document-open.svg b/src/assets/icons/scalable/document-open.svg deleted file mode 100644 index 778c1b7c6e9..00000000000 --- a/src/assets/icons/scalable/document-open.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Open" d="m14.5,5h-1.5v-1c0-1.1-.9-2-2-2h-5L4,0h-2C.9,0,0,.9,0,2v12c0,1.1.9,2,2,2h9s0,0,0,0c.12,0,.25-.01.36-.03.98-.16,1.94-.94,2.24-1.87l2.29-7.19c.33-1.05-.29-1.91-1.39-1.91ZM1,14V2c0-.55.45-1,1-1h1.59l1.71,1.71c.19.19.44.29.71.29h5c.55,0,1,.45,1,1v1h-5.5c-1.1,0-2.27.86-2.61,1.91l-2.29,7.19c-.09.28-.11.54-.07.78-.32-.17-.54-.49-.54-.87Zm13.94-7.4l-2.29,7.19c-.2.63-.99,1.21-1.65,1.21H3c-.2,0-.36-.05-.43-.15-.07-.1-.07-.26-.01-.45l2.29-7.19c.2-.63.99-1.21,1.65-1.21h8c.2,0,.36.05.43.15.07.1.07.26.01.45Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/document-print.svg b/src/assets/icons/scalable/document-print.svg deleted file mode 100644 index fb8436af81a..00000000000 --- a/src/assets/icons/scalable/document-print.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Print" d="m14,4h-2v-2c0-1.1-.9-2-2-2h-4c-1.1,0-2,.9-2,2v2h-2c-1.1,0-2,.9-2,2v4c0,1.1.9,2,2,2h2v2c0,1.1.9,2,2,2h4c1.1,0,2-.9,2-2v-2h2c1.1,0,2-.9,2-2v-4c0-1.1-.9-2-2-2ZM5,2c0-.55.45-1,1-1h4c.55,0,1,.45,1,1v2h-6v-2Zm5,13h-4c-.55,0-1-.45-1-1v-5h6v5c0,.55-.45,1-1,1Zm5-5c0,.55-.45,1-1,1h-2v-2h.5c.28,0,.5-.22.5-.5s-.22-.5-.5-.5h-.5s-8,0-8,0h0s-.5,0-.5,0c-.28,0-.5.22-.5.5s.22.5.5.5h.5v2h-2c-.55,0-1-.45-1-1v-4c0-.55.45-1,1-1h12c.55,0,1,.45,1,1v4Zm-5,1.5c0,.28-.22.5-.5.5h-3c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h3c.28,0,.5.22.5.5Zm0,2c0,.28-.22.5-.5.5h-3c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h3c.28,0,.5.22.5.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/document-save.svg b/src/assets/icons/scalable/document-save.svg deleted file mode 100644 index 03675f4dab0..00000000000 --- a/src/assets/icons/scalable/document-save.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Save" d="m16,11h0V2.29c0-1.26-1.02-2.29-2.29-2.29H2.29C1.02,0,0,1.02,0,2.29v8.71h0v1h0v1.71c0,1.26,1.02,2.29,2.29,2.29h11.43c1.26,0,2.29-1.02,2.29-2.29v-1.71h0v-1ZM5.71,1h5.29v4.5c0,.28-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5V1h.71ZM1,2.29c0-.71.58-1.29,1.29-1.29h1.71v4.5c0,.83.67,1.5,1.5,1.5h5c.83,0,1.5-.67,1.5-1.5V1h1.71c.71,0,1.29.58,1.29,1.29v8.71H1V2.29Zm14,11.43c0,.71-.58,1.29-1.29,1.29H2.29c-.71,0-1.29-.58-1.29-1.29v-1.71h14v1.71Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/edit-copy.svg b/src/assets/icons/scalable/edit-copy.svg deleted file mode 100644 index db53ff11624..00000000000 --- a/src/assets/icons/scalable/edit-copy.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Copy" d="m12,0h-5c-1.1,0-2,.9-2,2h1c0-.55.45-1,1-1h4v2c0,1.1.9,2,2,2h2v6c0,.55-.45,1-1,1h-2v1h2c1.1,0,2-.9,2-2v-7c-1.07-1.07-2.86-2.86-4-4Zm1,4c-.55,0-1-.45-1-1v-1.59l1.29,1.29,1.29,1.29h-1.59Zm-6-1H2c-1.1,0-2,.9-2,2v9c0,1.1.9,2,2,2h7c1.1,0,2-.9,2-2v-7c-1.07-1.07-2.86-2.86-4-4Zm3,6v5c0,.55-.45,1-1,1H2c-.55,0-1-.45-1-1V5c0-.55.45-1,1-1h4v2c0,1.1.9,2,2,2h2v1Zm-2-2c-.55,0-1-.45-1-1v-1.59l1.29,1.29,1.29,1.29h-1.59Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/edit-cut.svg b/src/assets/icons/scalable/edit-cut.svg deleted file mode 100644 index 7f75d0b829d..00000000000 --- a/src/assets/icons/scalable/edit-cut.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Cut" d="m15.22,12.05l-7.39-3.55,7.39-3.55c.25-.12.35-.42.23-.67-.12-.25-.42-.35-.67-.23l-8.12,3.9-2.48-1.19c1.07-.46,1.81-1.52,1.81-2.75,0-1.66-1.34-3-3-3S0,2.34,0,4c0,1.28.81,2.36,1.93,2.8.1.05.22.1.35.15l3.23,1.55-3.23,1.55c-.1.05-.18.09-.26.13-1.18.41-2.02,1.51-2.02,2.82,0,1.66,1.34,3,3,3s3-1.34,3-3c0-1.24-.75-2.29-1.81-2.75l2.48-1.19,8.12,3.9c.07.03.14.05.22.05.19,0,.37-.1.45-.28.12-.25.01-.55-.23-.67ZM3,2c1.1,0,2,.9,2,2s-.9,2-2,2-2-.9-2-2,.9-2,2-2Zm2,11c0,1.1-.9,2-2,2s-2-.9-2-2,.9-2,2-2,2,.9,2,2Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/edit-delete.svg b/src/assets/icons/scalable/edit-delete.svg deleted file mode 100644 index 15d1a9c7fd6..00000000000 --- a/src/assets/icons/scalable/edit-delete.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Delete" d="m8,0C3.58,0,0,3.58,0,8s3.58,8,8,8,8-3.58,8-8S12.42,0,8,0Zm0,15c-3.86,0-7-3.14-7-7S4.14,1,8,1s7,3.14,7,7-3.14,7-7,7Zm2.83-9.12l-2.12,2.12,2.12,2.12c.2.2.2.51,0,.71-.1.1-.23.15-.35.15s-.26-.05-.35-.15l-2.12-2.12-2.12,2.12c-.1.1-.23.15-.35.15s-.26-.05-.35-.15c-.2-.2-.2-.51,0-.71l2.12-2.12-2.12-2.12c-.2-.2-.2-.51,0-.71s.51-.2.71,0l2.12,2.12,2.12-2.12c.2-.2.51-.2.71,0s.2.51,0,.71Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/edit-paste.svg b/src/assets/icons/scalable/edit-paste.svg deleted file mode 100644 index 57e94d917d2..00000000000 --- a/src/assets/icons/scalable/edit-paste.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Paste" d="m14.09,6.09c-.71-.74-1.44-1.5-2.09-2.09h-3.78c-1.23,0-2.22.9-2.22,2v8c0,1.1.99,2,2.22,2h5.56c1.23,0,2.22-.9,2.22-2v-6c-.52-.52-1.21-1.21-1.91-1.91Zm-2.09-.68l1.38,1.38c.41.43.8.83,1.18,1.21h-1.56c-.55,0-1-.45-1-1v-1.59Zm3,5.59v3c0,.55-.55,1-1.22,1h-5.56c-.67,0-1.22-.45-1.22-1V6c0-.55.55-1,1.22-1h2.78v2c0,1.1.9,2,2,2h2v2Zm-6.5,0h5c.28,0,.5.22.5.5s-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5s.22-.5.5-.5ZM5.5,3h1c.83,0,1.5-.67,1.5-1.5v-.5h2c.55,0,1,.45,1,1v1h1v-1C12,.9,11.1,0,10,0h-2s-4,0-4,0h0s-2,0-2,0C.9,0,0,.9,0,2v10c0,1.1.9,2,2,2h3v-1h-3c-.55,0-1-.45-1-1V2c0-.55.45-1,1-1h2v.5c0,.83.67,1.5,1.5,1.5Zm1.5-1.5c0,.28-.22.5-.5.5h-1c-.28,0-.5-.22-.5-.5v-.5h2v.5Zm7,12c0,.28-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h5c.28,0,.5.22.5.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/edit-redo.svg b/src/assets/icons/scalable/edit-redo.svg deleted file mode 100644 index 92d60e1dd8c..00000000000 --- a/src/assets/icons/scalable/edit-redo.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Redo" d="m15.85,4.68l-3.54-3.54c-.2-.2-.51-.2-.71,0s-.2.51,0,.71l2.68,2.68H2.5c-1.38,0-2.5,1.12-2.5,2.5v4c0,1.38,1.12,2.5,2.5,2.5h7c.28,0,.5-.22.5-.5s-.22-.5-.5-.5H2.5c-.83,0-1.5-.67-1.5-1.5v-4c0-.83.67-1.5,1.5-1.5h11.79l-2.68,2.68c-.2.2-.2.51,0,.71.1.1.23.15.35.15s.26-.05.35-.15l3.54-3.54c.2-.2.2-.51,0-.71Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/edit-undo.svg b/src/assets/icons/scalable/edit-undo.svg deleted file mode 100644 index 91731bb86fa..00000000000 --- a/src/assets/icons/scalable/edit-undo.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Undo" d="m13.5,4.54H1.71l2.68-2.68c.2-.2.2-.51,0-.71s-.51-.2-.71,0L.15,4.68c-.2.2-.2.51,0,.71l3.54,3.54c.1.1.23.15.35.15s.26-.05.35-.15c.2-.2.2-.51,0-.71l-2.68-2.68h11.79c.83,0,1.5.67,1.5,1.5v4c0,.83-.67,1.5-1.5,1.5h-7c-.28,0-.5.22-.5.5s.22.5.5.5h7c1.38,0,2.5-1.12,2.5-2.5v-4c0-1.38-1.12-2.5-2.5-2.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-justify-center.svg b/src/assets/icons/scalable/format-justify-center.svg deleted file mode 100644 index 9822c95f2fa..00000000000 --- a/src/assets/icons/scalable/format-justify-center.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignCenter" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm-2,3.5h0c0-.28-.22-.5-.5-.5H3c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm2.5,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm-2.5-12h0c0-.28-.22-.5-.5-.5H3c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-justify-fill.svg b/src/assets/icons/scalable/format-justify-fill.svg deleted file mode 100644 index 2fa7ddfa40d..00000000000 --- a/src/assets/icons/scalable/format-justify-fill.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignJustify" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm.5,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0-12h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-justify-left.svg b/src/assets/icons/scalable/format-justify-left.svg deleted file mode 100644 index 99d666428d9..00000000000 --- a/src/assets/icons/scalable/format-justify-left.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignLeft" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm-4.5,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm5,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5ZM11,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-justify-right.svg b/src/assets/icons/scalable/format-justify-right.svg deleted file mode 100644 index 7041f5e3f88..00000000000 --- a/src/assets/icons/scalable/format-justify-right.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignRight" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm.5,3.5h0c0-.28-.22-.5-.5-.5H5.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm0,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0-12h0c0-.28-.22-.5-.5-.5H5.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-text-bold.svg b/src/assets/icons/scalable/format-text-bold.svg deleted file mode 100644 index c0f43e0a692..00000000000 --- a/src/assets/icons/scalable/format-text-bold.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_Bold" d="m12.06,7.75c.65-.36,1.13-.81,1.44-1.35.3-.55.46-1.29.46-2.24,0-1.45-.4-2.5-1.21-3.16-.81-.66-2.03-.99-3.67-.99H3v16h6.26c3.39,0,5.09-1.51,5.09-4.53,0-1.88-.76-3.12-2.29-3.71ZM5.59,2.24h3.34c1.59,0,2.38.74,2.38,2.22,0,1.57-.76,2.36-2.29,2.36h-3.43V2.24Zm5.45,10.98c-.43.36-1.07.54-1.93.54h-3.53v-4.74h3.48c.75,0,1.37.17,1.87.53.5.35.75.96.75,1.83s-.21,1.49-.64,1.85Z"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-text-italic.svg b/src/assets/icons/scalable/format-text-italic.svg deleted file mode 100644 index 43df7ca54dc..00000000000 --- a/src/assets/icons/scalable/format-text-italic.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon id="iconTextEditor_Italic" points="6.63 0 6.18 2.01 8.18 2.01 5.45 13.99 3.45 13.99 3 16 9.56 16 10.01 13.99 8.01 13.99 10.74 2.01 12.74 2.01 13.19 0 6.63 0"/></svg>
\ No newline at end of file diff --git a/src/assets/icons/scalable/format-text-underline.svg b/src/assets/icons/scalable/format-text-underline.svg deleted file mode 100644 index 62778fc579e..00000000000 --- a/src/assets/icons/scalable/format-text-underline.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_Underline" d="m3.38,11.88c-.92-.75-1.38-1.94-1.38-3.57V0h2.44v8.35c0,1.79,1.02,2.69,3.06,2.69s3.06-.9,3.06-2.69V0h2.44v8.31c0,1.63-.46,2.82-1.39,3.57-.92.75-2.3,1.12-4.13,1.12s-3.2-.37-4.11-1.12Zm10.12,3.12H1.5c-.28,0-.5.22-.5.5s.22.5.5.5h12c.28,0,.5-.22.5-.5s-.22-.5-.5-.5Z"/></svg>
\ No newline at end of file diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 4d83bbf794e..249b9b8c1ee 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -16,7 +16,11 @@ qt_internal_extend_sbom(WrapZLIB::WrapZLIB if(ANDROID) set(corelib_extra_cmake_files - "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake") + "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidDynamicFeatureHelpers.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidGradleHelpers.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidPermissionHelpers.cmake" + ) endif() if(WASM) set(corelib_extra_cmake_files diff --git a/src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake b/src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake new file mode 100644 index 00000000000..e8a81bde1d7 --- /dev/null +++ b/src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake @@ -0,0 +1,152 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause +# Collects the dynamic features for the target + +function(_qt_internal_android_add_dynamic_feature_deployment target) + get_target_property(dynamic_features ${target} _qt_android_dynamic_features) + if(NOT dynamic_features) + return() + endif() + + foreach(dynamic_feature IN LISTS dynamic_features) + get_target_property(is_imported ${dynamic_feature} IMPORTED) + if(is_imported) + message(FATAL_ERROR "Imported target ${dynamic_feature} can not be a" + " 'DYNAMIC_FEATURE'.") + endif() + + get_target_property(type ${dynamic_feature} TYPE) + if(NOT type STREQUAL "SHARED_LIBRARY") + message(FATAL_ERROR "Cannot make ${dynamic_feature} 'DYNAMIC_FEATURE'." + " The target must be the 'SHARED_LIBRARY'.") + endif() + + get_target_property(android_type ${dynamic_feature} _qt_android_target_type) + if(NOT android_type STREQUAL "" AND NOT android_type MATCHES "-NOTFOUND$" + AND NOT android_type STREQUAL "DYNAMIC_FEATURE") + message(FATAL_ERROR "Cannot make ${dynamic_feature} 'DYNAMIC_FEATURE'," + " it's already '${android_type}'. The target must be the plain 'SHARED_LIBRARY'.") + endif() + + # Mark the target as DYNAMIC_FEATURE, since we used it in this role once. + set_target_properties(${dynamic_feature} PROPERTIES _qt_android_target_type DYNAMIC_FEATURE) + _qt_internal_set_android_dynamic_feature_gradle_defaults(${dynamic_feature}) + + _qt_internal_android_get_dynamic_feature_deployment_dir(dynamic_feature_deployment_dir + ${target} ${dynamic_feature}) + _qt_internal_android_generate_target_build_gradle(${dynamic_feature} + DEPLOYMENT_DIR "${dynamic_feature_deployment_dir}") + _qt_internal_android_generate_dynamic_feature_manifest(${target} ${dynamic_feature}) + _qt_internal_android_copy_dynamic_feature(${target} ${dynamic_feature}) + endforeach() +endfunction() + +# Sets the default values of the gradle properties for the Android dynamic feature target. +function(_qt_internal_set_android_dynamic_feature_gradle_defaults target) + _qt_internal_android_java_dir(android_java_dir) + + # TODO: make androidx.core:core versionc configurable. + # Currently, it is hardcoded to 1.16.0. + set(implementation_dependencies "project(':app')" "'androidx.core:core:1.16.0'") + + set_target_properties(${target} PROPERTIES + _qt_android_gradle_java_source_dirs "src;java" + _qt_android_gradle_aidl_source_dirs "src;aidl" + _qt_android_gradle_res_source_dirs "res" + _qt_android_gradle_resources_source_dirs "resources" + _qt_android_gradle_renderscript_source_dirs "src" + _qt_android_gradle_assets_source_dirs "assets" + _qt_android_gradle_jniLibs_source_dirs "libs" + _qt_android_manifest "AndroidManifest.xml" + _qt_android_gradle_implementation_dependencies "${implementation_dependencies}" + ) +endfunction() + +# Copies the dynamic feature library to the respective gradle build tree. +function(_qt_internal_android_copy_dynamic_feature target dynamic_feature) + if(NOT TARGET ${dynamic_feature}) + message(FATAL_ERROR "${dynamic_feature} is not a target.") + endif() + + _qt_internal_android_get_dynamic_feature_deployment_dir(dynamic_feature_deployment_dir + ${target} ${dynamic_feature}) + + set(dynamic_feature_libs_dir "${dynamic_feature_deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}") + get_target_property(output_name ${dynamic_feature} OUTPUT_NAME) + if(NOT output_name) + get_target_property(suffix "${dynamic_feature}" SUFFIX) + set(output_name "lib${dynamic_feature}${suffix}") + endif() + set(output_file_path "${dynamic_feature_libs_dir}/${output_name}") + _qt_internal_copy_file_if_different_command(copy_command + "$<TARGET_FILE:${dynamic_feature}>" + "${output_file_path}" + ) + add_custom_command(OUTPUT ${output_file_path} + COMMAND ${copy_command} + DEPENDS ${dynamic_feature} + COMMENT "Copying ${dynamic_feature} dynamic feature to ${target} deployment directory" + ) + add_custom_target(${target}_deploy_dynamic_features DEPENDS "${output_file_path}") +endfunction() + +# Generates the feature name strings and copy them to the respective deployment directory. +function(_qt_internal_android_generate_dynamic_feature_names target) + get_target_property(dynamic_features ${target} _qt_android_dynamic_features) + if(NOT dynamic_features) + return() + endif() + + # Collect the titles + string(JOIN "\n" content + "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<resources>" + ) + foreach(feature IN LISTS dynamic_features) + string(APPEND content "\n <string name=\"${feature}_title\">${feature}</string>") + endforeach() + string(APPEND content "\n</resources>") + + _qt_internal_android_get_target_deployment_dir(deployment_dir ${target}) + # TODO: androiddeployqt wipes the android build directory. Generate feature_names.xml target + # build dir and copy after androiddeployqt run. We should skip feature_names.xml copying when + # androiddeployqt is not involved into the deployment process anymore. + # + # set(output_file "${deployment_dir}/res/values/feature_names.xml") + set(output_file "$<TARGET_PROPERTY:${target},BINARY_DIR>/res/values/feature_names.xml") + _qt_internal_configure_file(GENERATE OUTPUT "${output_file}" CONTENT "${content}") + set(output_file_in_deployment_dir "${deployment_dir}/res/values/feature_names.xml") + add_custom_command(OUTPUT "${output_file_in_deployment_dir}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${output_file}" + "${output_file_in_deployment_dir}" + DEPENDS "${output_file}" ${target}_android_deploy_aux + VERBATIM + ) + add_custom_target(${target}_copy_feature_names + DEPENDS + "${output_file_in_deployment_dir}" + ) +endfunction() + +# Returns the dynamic feature deployment directory in the target build tree. +function(_qt_internal_android_get_dynamic_feature_deployment_dir out_var target dynamic_feature) + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + set(${out_var} "${android_build_dir}/${dynamic_feature}" PARENT_SCOPE) +endfunction() + +# Generates the AndroidManifest.xml file for the dynamic_feature. +function(_qt_internal_android_generate_dynamic_feature_manifest target dynamic_feature) + set(android_manifest_filename AndroidManifest.xml) + _qt_internal_android_get_dynamic_feature_deployment_dir(dynamic_feature_deployment_dir ${target} + ${dynamic_feature}) + + _qt_internal_android_get_template_path(template_file ${target} + "dynamic_feature/${android_manifest_filename}") + + set(APP_TARGET "${target}") + set(TITLE_VAR "@string/${dynamic_feature}_title") + + set(output_file "${dynamic_feature_deployment_dir}/AndroidManifest.xml") + _qt_internal_configure_file(CONFIGURE OUTPUT "${output_file}" INPUT "${template_file}") +endfunction() diff --git a/src/corelib/Qt6AndroidGradleHelpers.cmake b/src/corelib/Qt6AndroidGradleHelpers.cmake new file mode 100644 index 00000000000..09184c93b69 --- /dev/null +++ b/src/corelib/Qt6AndroidGradleHelpers.cmake @@ -0,0 +1,631 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Returns the path to the template file from either user defined template directory, or +# Qt default template directory. +function(_qt_internal_android_get_template_path out_var target template_name) + if(template_name STREQUAL "") + message(FATAL_ERROR "Template name is empty." + " This is the Qt issue, please report a bug at https://bugreports.qt.io.") + endif() + + _qt_internal_android_template_dir(template_directory) + get_filename_component(template_directory "${template_directory}" ABSOLUTE) + + # The paths are ordered according to their priority, from highest to lowest. + set(possible_paths + "${template_directory}/${template_name}.in" + ) + + get_target_property(android_target_type ${target} _qt_android_target_type) + if(android_target_type STREQUAL "APPLICATION") + _qt_internal_android_get_package_source_dir(user_template_directory ${target}) + get_filename_component(user_template_directory "${user_template_directory}" ABSOLUTE) + + # Add user template with the higher priority + list(PREPEND possible_paths "${user_template_directory}/${template_name}.in") + endif() + + set(template_path "") + foreach(possible_path IN LISTS possible_paths) + if(EXISTS "${possible_path}") + set(template_path "${possible_path}") + break() + endif() + endforeach() + + if(template_path STREQUAL "") + message(FATAL_ERROR "'${template_name}' is not found." + " This is the Qt issue, please report a bug at https://bugreports.qt.io.") + endif() + + set(${out_var} "${template_path}" PARENT_SCOPE) +endfunction() + +# Generates the settings.gradle file for the target. Writes the result to the target android build +# directory. +function(_qt_internal_android_generate_bundle_settings_gradle target) + set(settings_gradle_filename "settings.gradle") + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + set(settings_gradle_file "${android_build_dir}/${settings_gradle_filename}") + + # Skip generating the file if it's already provided by user. + get_target_property(deployment_files ${target} _qt_android_deployment_files) + if("${settings_gradle_file}" IN_LIST deployment_files) + return() + endif() + + _qt_internal_android_get_template_path(template_file ${target} "${settings_gradle_filename}") + + set(android_app_name "$<TARGET_PROPERTY:${target},QT_ANDROID_APP_NAME>") + string(JOIN "" ROOT_PROJECT_NAME + "$<IF:$<BOOL:${android_app_name}>," + "${android_app_name}," + "${target}" + ">" + ) + + set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>") + set(include_prefix "include(\":") + set(include_suffix "\")") + set(include_glue "${include_suffix}\n${include_prefix}") + string(JOIN "" SUBPROJECTS + "$<$<BOOL:${target_dynamic_features}>:" + "${include_prefix}" + "$<JOIN:${target_dynamic_features},${include_glue}>" + "${include_suffix}" + ">" + ) + + _qt_internal_configure_file(GENERATE OUTPUT ${settings_gradle_file} + INPUT "${template_file}") + set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files + "${settings_gradle_file}") +endfunction() + +# Generates the source sets for the target. +function(_qt_internal_android_get_gradle_source_sets out_var target) + set(known_types java aidl res resources renderscript assets jniLibs) + set(source_set "") + set(indent " ") + foreach(type IN LISTS known_types) + set(source_dirs + "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_android_gradle_${type}_source_dirs>>") + string(JOIN "" source_set + "${source_set}" + "$<$<BOOL:${source_dirs}>:" + "${indent}${type}.srcDirs = ['$<JOIN:${source_dirs},'$<COMMA> '>']\n" + ">" + ) + endforeach() + + set(manifest + "$<TARGET_PROPERTY:${target},_qt_android_manifest>") + string(JOIN "" source_set + "${source_set}" + "$<$<BOOL:${manifest}>:" + "${indent}manifest.srcFile '${manifest}'\n" + ">" + ) + set(${out_var} "${source_set}" PARENT_SCOPE) +endfunction() + +# Generates the gradle dependency list for the target. +function(_qt_internal_android_get_gradle_dependencies out_var target) + # Use dependencies from file tree by default + set(known_dependencies + "implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])") + foreach(dep_type implementation api) + string(JOIN "\n " dep_prefix + "\n //noinspection GradleDependency" + "${dep_type} " + ) + set(dep_postfix "") + set(dep_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_android_gradle_${dep_type}_dependencies>>") + string(JOIN "" known_dependencies + "${known_dependencies}" + "$<$<BOOL:${dep_property}>:" + "${dep_prefix}$<JOIN:${dep_property},${dep_postfix}${dep_prefix}>${dep_postfix}" + ">" + ) + endforeach() + set(${out_var} "${known_dependencies}" PARENT_SCOPE) +endfunction() + +# Sets the default values of the gradle properties for the Android executable target. +function(_qt_internal_set_android_application_gradle_defaults target) + _qt_internal_android_java_dir(android_java_dir) + + set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>") + string(JOIN "" implementation_dependencies + "$<$<BOOL:${target_dynamic_features}>:'com.google.android.play:feature-delivery:2.1.0'>" + ) + # TODO: make androidx.core:core version configurable. + # Currently, it is hardcoded to 1.16.0. + list(APPEND implementation_dependencies "'androidx.core:core:1.16.0'") + + set_target_properties(${target} PROPERTIES + _qt_android_gradle_java_source_dirs "${android_java_dir}/src;src;java" + _qt_android_gradle_aidl_source_dirs "${android_java_dir}/src;src;aidl" + _qt_android_gradle_res_source_dirs "${android_java_dir}/res;res" + _qt_android_gradle_resources_source_dirs "resources" + _qt_android_gradle_renderscript_source_dirs "src" + _qt_android_gradle_assets_source_dirs "assets" + _qt_android_gradle_jniLibs_source_dirs "libs" + _qt_android_manifest "AndroidManifest.xml" + _qt_android_gradle_implementation_dependencies "${implementation_dependencies}" + ) +endfunction() + +# Generates the build.gradle file for the target. Writes the result to the target app deployment +# directory. +function(_qt_internal_android_generate_target_build_gradle target) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "") + + if(NOT arg_DEPLOYMENT_DIR) + message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.") + endif() + + set(build_gradle_filename "build.gradle") + set(out_file "${arg_DEPLOYMENT_DIR}/${build_gradle_filename}") + + # Skip generating the file if it's already provided by user. + get_target_property(deployment_files ${target} _qt_android_deployment_files) + if("${out_file}" IN_LIST deployment_files) + return() + endif() + + # TODO: The current build.gradle.in templates hardcodes couple values that needs to be + # configurable in the future. For example the buildscript dependencies, or the use of + # androidx.core:core:1.13.1 and the dependency for all user applications. + + _qt_internal_android_get_gradle_property(PACKAGE_NAME ${target} + QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>") + + _qt_internal_android_get_target_sdk_build_tools_revision(ANDROID_BUILD_TOOLS_VERSION + ${target}) + + _qt_internal_detect_latest_android_platform(ANDROID_COMPILE_SDK_VERSION) + if(NOT ANDROID_COMPILE_SDK_VERSION) + message(FATAL_ERROR "Unable to detect the android platform in ${ANDROID_SDK_ROOT}. " + "Please check your Android SDK installation.") + endif() + + _qt_internal_android_get_gradle_source_sets(SOURCE_SETS ${target}) + _qt_internal_android_get_gradle_dependencies(GRADLE_DEPENDENCIES ${target}) + + _qt_internal_android_get_gradle_property(min_sdk_version ${target} + QT_ANDROID_MIN_SDK_VERSION "28") + + _qt_internal_android_get_gradle_property(target_sdk_version ${target} + QT_ANDROID_TARGET_SDK_VERSION "34") + + set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>") + set(target_abi_list "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>") + + string(JOIN "\n " DEFAULT_CONFIG_VALUES + "resConfig 'en'" + "minSdkVersion ${min_sdk_version}" + "targetSdkVersion ${target_sdk_version}" + "ndk.abiFilters = ['${target_abi_list}']" + ) + + set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>") + set(include_prefix "\":") + set(include_suffix "\"") + set(include_glue "${include_suffix}$<COMMA>${include_prefix}") + string(APPEND ANDROID_DEPLOYMENT_EXTRAS + "$<$<BOOL:${target_dynamic_features}>:dynamicFeatures = [" + "${include_prefix}" + "$<JOIN:${target_dynamic_features},${include_glue}>" + "${include_suffix}]" + ">" + ) + + get_target_property(android_target_type ${target} _qt_android_target_type) + if(android_target_type STREQUAL "APPLICATION") + set(GRADLE_PLUGIN_TYPE "com.android.application") + set(template_subdir "app") + elseif(android_target_type STREQUAL "DYNAMIC_FEATURE") + set(GRADLE_PLUGIN_TYPE "com.android.dynamic-feature") + set(template_subdir "dynamic_feature") + else() + message(FATAL_ERROR "Unsupported target type for android bundle deployment ${target}") + endif() + + _qt_internal_android_get_template_path(template_file ${target} + "${template_subdir}/${build_gradle_filename}") + _qt_internal_configure_file(GENERATE + OUTPUT "${out_file}" + INPUT "${template_file}" + ) + set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}") +endfunction() + +# Prepares the artifacts for the gradle build of the target. +function(_qt_internal_android_prepare_gradle_build target) + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + _qt_internal_android_get_target_deployment_dir(deployment_dir ${target}) + + _qt_internal_android_copy_gradle_files(${target} "${android_build_dir}") + _qt_internal_android_copy_target_package_sources(${target}) + + _qt_internal_android_generate_bundle_gradle_properties(${target}) + _qt_internal_android_generate_bundle_settings_gradle(${target}) + _qt_internal_android_generate_bundle_local_properties(${target}) + _qt_internal_android_generate_target_build_gradle(${target} DEPLOYMENT_DIR "${deployment_dir}") + _qt_internal_android_generate_target_gradle_properties(${target} + DEPLOYMENT_DIR "${deployment_dir}") + _qt_internal_android_generate_target_android_manifest(${target} + DEPLOYMENT_DIR "${deployment_dir}") + + + _qt_internal_android_add_gradle_build(${target} apk) + _qt_internal_android_add_gradle_build(${target} aab) + + # Make global apk, aab, and aar targets depend on the respective targets. + _qt_internal_android_add_global_package_dependencies(${target}) + _qt_internal_create_global_apk_all_target_if_needed() +endfunction() + +# Adds the modern gradle build targets. +# These targets use the settings.gradle based build directory structure. +function(_qt_internal_android_add_gradle_build target type) + _qt_internal_android_get_deployment_type_option(android_deployment_type_option + "assembleRelease" "assembleDebug") + + _qt_internal_android_gradlew_name(gradlew_file_name) + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + set(gradlew "${android_build_dir}/${gradlew_file_name}") + + set(extra_args "") + if(type STREQUAL "aab") + set(extra_args "bundle") + endif() + + set(package_file_path "${android_build_dir}/${target}.${type}") + + _qt_internal_android_package_path(package_build_dir ${target} ${type}) + _qt_internal_android_get_deployment_type_option(deployment_type_suffix + "release" "debug") + set(package_build_file_path + "${package_build_dir}/${deployment_type_suffix}/app-${deployment_type_suffix}.${type}") + + set(extra_deps "") + if(TARGET ${target}_copy_feature_names) + list(APPEND extra_deps ${target}_copy_feature_names) + endif() + + if(TARGET ${target}_deploy_dynamic_features) + list(APPEND extra_deps ${target}_deploy_dynamic_features) + endif() + + set(gradle_scripts "$<TARGET_PROPERTY:${target},_qt_android_deployment_files>") + add_custom_command(OUTPUT "${package_file_path}" + BYPRODUCTS "${package_build_file_path}" + COMMAND + "${gradlew}" ${android_deployment_type_option} ${extra_args} + COMMAND + ${CMAKE_COMMAND} -E copy_if_different + "${package_build_file_path}" "${package_file_path}" + DEPENDS + ${target} + ${gradle_scripts} + ${target}_copy_gradle_files + ${target}_android_deploy_aux + ${extra_deps} + WORKING_DIRECTORY + "${android_build_dir}" + VERBATIM + ) + + add_custom_target(${target}_make_${type} DEPENDS "${package_file_path}") +endfunction() + +# Returns the path to the android executable package either apk or aab. +function(_qt_internal_android_package_path out_var target type) + set(supported_package_types apk aab) + if(NOT type IN_LIST supported_package_types) + message(FATAL_ERROR "Invalid package type, supported types: ${supported_package_types}") + endif() + + # aab packages are located in the bundle directory + if(type STREQUAL "aab") + set(type "bundle") + endif() + + _qt_internal_android_get_target_deployment_dir(deployment_dir ${target}) + + set(${out_var} "${deployment_dir}/build/outputs/${type}" PARENT_SCOPE) +endfunction() + +# Returns the path to the gradle build directory. +function(_qt_internal_android_gradle_template_dir out_var) + if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD) + set(${out_var} "${QtBase_SOURCE_DIR}/src/3rdparty/gradle" PARENT_SCOPE) + else() + set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/3rdparty/gradle" PARENT_SCOPE) + endif() +endfunction() + +# Returns the path to the android java dir. +function(_qt_internal_android_java_dir out_var) + if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD) + set(${out_var} "${QtBase_SOURCE_DIR}/src/android/java" PARENT_SCOPE) + else() + set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/java" PARENT_SCOPE) + endif() +endfunction() + +# Returns the platform-spefic name of the gradlew script. +function(_qt_internal_android_gradlew_name out_var) + if(CMAKE_HOST_WIN32) + set(gradlew_file_name "gradlew.bat") + else() + set(gradlew_file_name "gradlew") + endif() + + set(${out_var} "${gradlew_file_name}" PARENT_SCOPE) +endfunction() + +# Return the path to the gradlew script. +function(_qt_internal_android_gradlew_path out_var target) + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + set(${out_var} "${android_build_dir}/${gradlew_file_name}" PARENT_SCOPE) +endfunction() + +# Returns the generator expression for the gradle_property value. Defaults to the default_value +# argument. +function(_qt_internal_android_get_gradle_property out_var target target_property default_value) + set(target_property_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},${target_property}>>") + string(JOIN "" result + "$<IF:$<BOOL:${target_property_genex}>," + "${target_property_genex}," + "${default_value}" + ">" + ) + set(${out_var} "${result}" PARENT_SCOPE) +endfunction() + +# Generates gradle.properties for the specific target. Usually contains the +# target build type(executable, dynamic feature, library). +function(_qt_internal_android_generate_target_gradle_properties target) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "") + + if(NOT arg_DEPLOYMENT_DIR) + message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.") + endif() + + set(gradle_properties_file_name "gradle.properties") + set(out_file "${arg_DEPLOYMENT_DIR}/${gradle_properties_file_name}") + # Skip generating the file if it's already provided by user. + get_target_property(deployment_files ${target} _qt_android_deployment_files) + if("${out_file}" IN_LIST deployment_files) + return() + endif() + + _qt_internal_android_get_template_path(template_file ${target} + "app/${gradle_properties_file_name}") + _qt_internal_configure_file(CONFIGURE + OUTPUT "${out_file}" + INPUT "${template_file}" + ) + set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}") +endfunction() + +# Constucts generator expression that returns either target property or the default value +function(_qt_internal_android_get_manifest_property out_var target property default) + set(target_property "$<TARGET_PROPERTY:${target},${property}>") + string(JOIN "" out_genex + "$<IF:$<BOOL:${target_property}>," + "${target_property}," + "${default}" + ">" + ) + + set(${out_var} "${out_genex}" PARENT_SCOPE) +endfunction() + +# Generates the target AndroidManifest.xml +function(_qt_internal_android_generate_target_android_manifest target) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "") + + if(NOT arg_DEPLOYMENT_DIR) + message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.") + endif() + + set(android_manifest_filename "AndroidManifest.xml") + set(out_file "${arg_DEPLOYMENT_DIR}/${android_manifest_filename}") + + # Skip generating the file if it's already provided by user. + get_target_property(deployment_files ${target} _qt_android_deployment_files) + if("${out_file}" IN_LIST deployment_files) + return() + endif() + + _qt_internal_android_get_template_path(template_file ${target} + "app/${android_manifest_filename}") + set(temporary_file "${out_file}.tmp") + + # The file cannot be generated at cmake configure time, because androiddeployqt + # will override it at build time. We use this trick with temporary file to override + # it after the aux run of androiddeployqt. + add_custom_command(OUTPUT "${out_file}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${temporary_file}" + "${out_file}" + DEPENDS + "${template_file}" + "${temporary_file}" + ${target}_android_deploy_aux + ) + + _qt_internal_android_get_manifest_property(APP_PACKAGE_NAME ${target} + QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>") + _qt_internal_android_get_manifest_property(APP_NAME ${target} + QT_ANDROID_APP_NAME "${target}") + _qt_internal_android_get_manifest_property(APP_VERSION_CODE ${target} + QT_ANDROID_VERSION_CODE "1") + _qt_internal_android_get_manifest_property(APP_VERSION_NAME ${target} + QT_ANDROID_VERSION_NAME "1") + _qt_internal_android_get_manifest_property(APP_LIB_NAME ${target} OUTPUT_NAME "${target}") + + # For application icon we substitute the whole attribute definition, but not only value + # otherwise it leads to the Manifest processing issue. + set(target_property "$<TARGET_PROPERTY:${target},QT_ANDROID_APP_ICON>") + string(JOIN "" APP_ICON + "$<$<BOOL:${target_property}>:" + "android:icon=\"${target_property}\"" + ">" + ) + + file(READ "${template_file}" manifest_content) + string(REPLACE ">" "$<ANGLE-R>" manifest_content "${manifest_content}") + string(REPLACE ";" "$<SEMICOLON>" manifest_content "${manifest_content}") + string(REPLACE "," "$<COMMA>" manifest_content "${manifest_content}") + + _qt_internal_android_convert_permissions(APP_PERMISSIONS ${target} XML) + + set(feature_prefix "\n <uses-feature android:name=\"") + set(feature_suffix " \" android:required=\"false\" /$<ANGLE-R>") + set(feature_property "$<TARGET_PROPERTY:${target},QT_ANDROID_FEATURES>") + string(JOIN "" APP_FEATURES + "$<$<BOOL:${feature_property}>:" + "${feature_prefix}" + "$<JOIN:${feature_property},${feature_suffix},${feature_prefix}>" + "${feature_suffix}" + ">" + ) + + set(APP_ARGUMENTS "${QT_ANDROID_APPLICATION_ARGUMENTS}") + + _qt_internal_configure_file(GENERATE OUTPUT "${temporary_file}" + CONTENT "${manifest_content}") + + set_property(TARGET ${target} APPEND PROPERTY + _qt_android_deployment_files "${out_file}" "${temporary_file}") +endfunction() + +# Generates the top-level gradle.properties in the android-build directory +# The file contains the information about the versions of the android build +# tools, the list of supported ABIs. +function(_qt_internal_android_generate_bundle_gradle_properties target) + set(EXTRA_PROPERTIES "") + + set(gradle_properties_file_name "gradle.properties") + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + set(out_file "${android_build_dir}/${gradle_properties_file_name}") + + # Skip generating the file if it's already provided by user. + get_target_property(deployment_files ${target} _qt_android_deployment_files) + if("${out_file}" IN_LIST deployment_files) + return() + endif() + + _qt_internal_android_get_template_path(template_file ${target} "${gradle_properties_file_name}") + _qt_internal_configure_file(CONFIGURE + OUTPUT "${out_file}" + INPUT "${template_file}" + ) + set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}") +endfunction() + +# Generates the local.properties for gradle builds. Contains the path to the +# Android SDK root. +function(_qt_internal_android_generate_bundle_local_properties target) + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + set(out_file "${android_build_dir}/local.properties") + + # Skip generating the file if it's already provided by user. + get_target_property(deployment_files ${target} _qt_android_deployment_files) + if("${out_file}" IN_LIST deployment_files) + return() + endif() + + file(TO_CMAKE_PATH "${ANDROID_SDK_ROOT}" ANDROID_SDK_ROOT_NATIVE) + _qt_internal_configure_file(CONFIGURE OUTPUT "${out_file}" + CONTENT "sdk.dir=${ANDROID_SDK_ROOT_NATIVE}\n") +endfunction() + +# Copies the customized Android package sources to the Android build directory +function(_qt_internal_android_copy_target_package_sources target) + _qt_internal_android_get_package_source_dir(package_source_dir ${target}) + + if(NOT package_source_dir) + return() + endif() + get_filename_component(package_source_dir "${package_source_dir}" ABSOLUTE) + + # Collect deployment files from use-defined package source directory + file(GLOB_RECURSE package_files + LIST_DIRECTORIES false + RELATIVE "${package_source_dir}" + "${package_source_dir}/*" + ) + + # Do not copy files that we treat as CMake templates, having '.in' extention. + # + # TODO: If it ever will be an issue we may exclude only templates that are + # known by our build system. + list(FILTER package_files EXCLUDE REGEX ".+\\.in$") + + _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + list(TRANSFORM package_files PREPEND "${android_build_dir}/" OUTPUT_VARIABLE out_package_files) + list(TRANSFORM package_files PREPEND "${package_source_dir}/" OUTPUT_VARIABLE in_package_files) + + if(in_package_files) + # TODO: Add cmake < 3.26 support + if(CMAKE_VERSION VERSION_LESS 3.26) + message(FATAL_ERROR "The use of QT_ANDROID_PACKAGE_SOURCE_DIR property with + the QT_USE_ANDROID_MODERN_BUNDLE option enabled requires CMake version >= 3.26.") + endif() + set(copy_commands COMMAND "${CMAKE_COMMAND}" -E copy_directory_if_different + "${package_source_dir}" "${android_build_dir}") + else() + # We actually have nothing to deploy. + return() + endif() + + add_custom_command(OUTPUT ${out_package_files} + ${copy_commands} + DEPENDS + ${in_package_files} + VERBATIM + ) + + set_target_properties(${target} PROPERTIES _qt_android_deployment_files "${out_package_files}") +endfunction() + +# Copies gradle scripts to a build directory. +function(_qt_internal_android_copy_gradle_files target output_directory) + _qt_internal_android_gradlew_name(gradlew_file_name) + _qt_internal_android_gradle_template_dir(gradle_template_dir) + + set(gradlew_file_src "${gradle_template_dir}/${gradlew_file_name}") + set(gradlew_file_dst "${output_directory}/${gradlew_file_name}") + + add_custom_command(OUTPUT "${gradlew_file_dst}" + COMMAND + ${CMAKE_COMMAND} -E copy_if_different "${gradlew_file_src}" "${gradlew_file_dst}" + DEPENDS "${gradlew_file_src}" + COMMENT "Copying gradlew script for ${target}" + VERBATIM + ) + + # TODO: make a more precise directory copying + set(gradle_dir_src "${gradle_template_dir}/gradle") + set(gradle_dir_dst "${output_directory}/gradle") + add_custom_command(OUTPUT "${gradle_dir_dst}" + COMMAND + ${CMAKE_COMMAND} -E copy_directory "${gradle_dir_src}" "${gradle_dir_dst}" + DEPENDS "${gradle_dir_src}" + COMMENT "Copying gradle support files for ${target}" + VERBATIM + ) + + add_custom_target(${target}_copy_gradle_files + DEPENDS + "${gradlew_file_dst}" + "${gradle_dir_dst}" + ) +endfunction() diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake index aa0e5bfed24..ed97a42c83f 100644 --- a/src/corelib/Qt6AndroidMacros.cmake +++ b/src/corelib/Qt6AndroidMacros.cmake @@ -120,6 +120,29 @@ function(_qt_internal_generate_android_permissions_json out_result target) set(${out_result} "${result}" PARENT_SCOPE) endfunction() +# Add the specific dynamic library as the dynamic feature for the Android application target. +function(qt6_add_android_dynamic_features target) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "FEATURE_TARGETS") + if(NOT QT_USE_ANDROID_MODERN_BUNDLE) + message(FATAL_ERROR "qt6_add_android_dynamic_features is only supported with" + " 'QT_USE_ANDROID_MODERN_BUNDLE' enabled.") + endif() + if(NOT TARGET ${target}) + message(FATAL_ERROR "${target} is not a target. Cannot add the dynamic features.") + endif() + get_target_property(android_type ${target} _qt_android_target_type) + if(NOT android_type STREQUAL "APPLICATION") + message(FATAL_ERROR "${target} is not an android executable target." + " Cannot add the dynamic features.") + endif() + if(arg_FEATURE_TARGETS) + set_property(TARGET ${target} + APPEND PROPERTY _qt_android_dynamic_features ${arg_FEATURE_TARGETS}) + else() + message(WARNING "No dynamic features provided.") + endif() +endfunction() + # Generate the deployment settings json file for a cmake target. function(qt6_android_generate_deployment_settings target) # Information extracted from mkspecs/features/android/android_deployment_settings.prf @@ -324,8 +347,9 @@ function(qt6_android_generate_deployment_settings target) __qt_internal_collect_plugin_library_files_v2("${target}" "${plugin_targets}" plugin_targets) string(APPEND file_contents " \"android-deploy-plugins\":\"${plugin_targets}\",\n") - _qt_internal_generate_android_permissions_json(permissions_json_array "${target}") - string(APPEND file_contents " \"permissions\": ${permissions_json_array},\n") + + _qt_internal_android_convert_permissions(permissions_genex ${target} JSON) + string(APPEND file_contents " \"permissions\": ${permissions_genex},\n") # App binary string(APPEND file_contents @@ -415,44 +439,6 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) endfunction() endif() -function(_qt_internal_add_android_permission target) - if(NOT TARGET ${target}) - message(FATAL_ERROR "Empty or invalid target for adding Android permission: (${target})") - endif() - - cmake_parse_arguments(arg "" "NAME" "ATTRIBUTES" ${ARGN}) - - if(NOT arg_NAME) - message(FATAL_ERROR "NAME for adding Android permission cannot be empty (${target})") - endif() - - set(permission_entry "${arg_NAME}") - - if(arg_ATTRIBUTES) - # Permission with additional attributes - list(LENGTH arg_ATTRIBUTES attributes_len) - math(EXPR attributes_modulus "${attributes_len} % 2") - if(NOT (attributes_len GREATER 1 AND attributes_modulus EQUAL 0)) - message(FATAL_ERROR "Android permission: ${arg_NAME} attributes: ${arg_ATTRIBUTES} must" - " be name-value pairs (for example: minSdkVersion 30)") - endif() - # Combine name-value pairs - set(index 0) - set(attributes "") - while(index LESS attributes_len) - list(GET arg_ATTRIBUTES ${index} name) - math(EXPR index "${index} + 1") - list(GET arg_ATTRIBUTES ${index} value) - string(APPEND attributes "android:${name}=\'${value}\' ") - math(EXPR index "${index} + 1") - endwhile() - set(permission_entry "${permission_entry}\;${attributes}") - endif() - - # Append the permission to the target's property - set_property(TARGET ${target} APPEND PROPERTY QT_ANDROID_PERMISSIONS "${permission_entry}") -endfunction() - function(qt6_add_android_permission target) _qt_internal_add_android_permission(${ARGV}) endfunction() @@ -519,18 +505,6 @@ function(qt6_android_add_apk_target target) ">" ) - # Make global apk and aab targets depend on the current apk target. - if(TARGET aab) - add_dependencies(aab ${target}_make_aab) - endif() - if(TARGET aar) - add_dependencies(aar ${target}_make_aar) - endif() - if(TARGET apk) - add_dependencies(apk ${target}_make_apk) - _qt_internal_create_global_apk_all_target_if_needed() - endif() - _qt_internal_android_get_deployment_tool(deployment_tool) # No need to use genex for the BINARY_DIR since it's read-only. @@ -719,6 +693,10 @@ function(qt6_android_add_apk_target target) ) add_dependencies(${target}_make_aab ${target}_prepare_apk_dir) + # Make global apk, aab, and aar targets depend on the respective targets. + _qt_internal_android_add_global_package_dependencies(${target}) + _qt_internal_create_global_apk_all_target_if_needed() + if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT) # When building per-ABI external projects we only need to copy ABI-specific libraries and # resources to the "main" ABI android build folder. @@ -1661,13 +1639,26 @@ endfunction() # module and is executed implicitly when configuring user projects. function(_qt_internal_android_executable_finalizer target) set_property(TARGET ${target} PROPERTY _qt_android_executable_finalizer_called TRUE) + set_property(TARGET ${target} PROPERTY _qt_android_in_finalizer "EXECUTABLE") _qt_internal_expose_android_package_source_dir_to_ide(${target}) _qt_internal_configure_android_multiabi_target("${target}") qt6_android_generate_deployment_settings("${target}") - qt6_android_add_apk_target("${target}") + if(QT_USE_ANDROID_MODERN_BUNDLE) + _qt_internal_android_generate_dynamic_feature_names("${target}") + _qt_internal_android_add_dynamic_feature_deployment("${target}") + + _qt_internal_android_prepare_gradle_build("${target}") + _qt_internal_android_add_aux_deployment("${target}") + + _qt_internal_collect_apk_dependencies_defer() + _qt_internal_collect_apk_imported_dependencies_defer("${target}") + else() + qt6_android_add_apk_target("${target}") + endif() _qt_internal_android_create_runner_wrapper("${target}") + set_property(TARGET ${target} PROPERTY _qt_android_in_finalizer "") endfunction() # Helper to add the android executable finalizer. @@ -1737,8 +1728,9 @@ function(_qt_internal_android_app_runner_arguments target out_runner_path out_ar set(${out_runner_path} "${runner_dir}/qt-android-runner.py" PARENT_SCOPE) _qt_internal_android_get_target_android_build_dir(android_build_dir ${target}) + _qt_internal_android_get_platform_tools_path(platform_tools) set(${out_arguments} - "--adb" "${ANDROID_SDK_ROOT}/platform-tools/adb" + "--adb" "${platform_tools}/adb" "--build-path" "${android_build_dir}" "--apk" "${android_build_dir}/${target}.apk" PARENT_SCOPE @@ -1754,8 +1746,13 @@ function(_qt_internal_android_get_target_android_build_dir out_build_dir target) endif() endfunction() +function(_qt_internal_android_get_target_deployment_dir out_deploy_dir target) + _qt_internal_android_get_target_android_build_dir(build_dir ${target}) + set(${out_deploy_dir} "${build_dir}/app" PARENT_SCOPE) +endfunction() + function(_qt_internal_expose_android_package_source_dir_to_ide target) - get_target_property(android_package_source_dir ${target} QT_ANDROID_PACKAGE_SOURCE_DIR) + _qt_internal_android_get_package_source_dir(android_package_source_dir ${target}) if(android_package_source_dir) get_target_property(target_source_dir ${target} SOURCE_DIR) if(NOT IS_ABSOLUTE "${android_package_source_dir}") @@ -1778,6 +1775,71 @@ function(_qt_internal_expose_android_package_source_dir_to_ide target) endif() endfunction() +function(_qt_internal_android_add_aux_deployment target) + cmake_parse_arguments(arg "" "OUTPUT_TARGET_NAME;DEPLOYMENT_DIRECTORY" "EXTRA_ARGS" ${ARGN}) + _qt_internal_validate_all_args_are_parsed(arg) + + string(JOIN "" deployment_file + "$<GENEX_EVAL:" + "$<TARGET_PROPERTY:${target},QT_ANDROID_DEPLOYMENT_SETTINGS_FILE>" + ">" + ) + + _qt_internal_android_get_deployment_tool(deployment_tool) + if(arg_DEPLOYMENT_DIRECTORY) + set(deployment_dir "${arg_DEPLOYMENT_DIRECTORY}") + else() + _qt_internal_android_get_target_deployment_dir(deployment_dir ${target}) + endif() + + cmake_policy(PUSH) + if(POLICY CMP0116) + # Without explicitly setting this policy to NEW, we get a warning + # even though we ensure there's actually no problem here. + # See https://gitlab.kitware.com/cmake/cmake/-/issues/21959 + cmake_policy(SET CMP0116 NEW) + set(relative_to_dir ${CMAKE_CURRENT_BINARY_DIR}) + else() + set(relative_to_dir ${CMAKE_BINARY_DIR}) + endif() + + set(target_file_copy_relative_path + "libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>") + _qt_internal_copy_file_if_different_command(copy_command + "$<TARGET_FILE:${target}>" + "${deployment_dir}/${target_file_copy_relative_path}" + ) + + _qt_internal_android_get_use_terminal_for_deployment(uses_terminal) + + # TODO: We use androiddeployqt to collect target depdenencies and produce the lib.xml file + # which autoloads the collected libraries. Should be done using GRE and transitive properties + # in the future. + set(libs_xml "${deployment_dir}/res/values/libs.xml") + add_custom_command(OUTPUT "${libs_xml}" + COMMAND ${copy_command} + COMMAND "${deployment_tool}" + --input "${deployment_file}" + --output "${deployment_dir}" + --builddir "${relative_to_dir}" + --aux-mode + ${arg_EXTRA_ARGS} + #TODO: Support signing + COMMENT "Deploying Android artifacts for ${target}" + DEPENDS "${target}" "${deployment_file}" + VERBATIM + ${uses_terminal} + ) + + if(NOT arg_OUTPUT_TARGET_NAME) + set(arg_OUTPUT_TARGET_NAME ${target}_android_deploy_aux) + endif() + + add_custom_target(${arg_OUTPUT_TARGET_NAME} DEPENDS "${libs_xml}") + + cmake_policy(POP) +endfunction() + # Enables the terminal usage for the add_custom_command calls when verbose deployment is enabled. function(_qt_internal_android_get_use_terminal_for_deployment out_var) if(QT_ENABLE_VERBOSE_DEPLOYMENT) @@ -1822,6 +1884,45 @@ function(_qt_internal_android_get_deployment_type_option out_var release_flag de endif() endfunction() +# Returns the path to the android template directory, that are used by CMake +# deployment procedures. +function(_qt_internal_android_template_dir out_var) + if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD) + set(${out_var} "${QtBase_SOURCE_DIR}/src/android/templates_cmake" PARENT_SCOPE) + else() + set(${out_var} + "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/templates_cmake" PARENT_SCOPE) + endif() +endfunction() + +# Return the path to the target template directory if it's set for the target. +# Then this path is stored in the target QT_ANDROID_PACKAGE_SOURCE_DIR property +# and can only be effectively read in android finalizers. +function(_qt_internal_android_get_package_source_dir out_var target) + get_target_property(in_finalizer ${target} _qt_android_in_finalizer) + if(NOT in_finalizer) + message(FATAL_ERROR "The '_qt_internal_android_get_package_source_dir' function is" + " called outside the Android finalizer." + " This is the Qt issue, please report a bug at https://bugreports.qt.io.") + endif() + get_target_property(package_src_dir ${target} QT_ANDROID_PACKAGE_SOURCE_DIR) + if(NOT package_src_dir) + set(package_src_dir "") + endif() + set(${out_var} "${package_src_dir}" PARENT_SCOPE) +endfunction() + +# Add target_make_<apk|aab> as the depednecy for the respective global apk/aab +# target. +function(_qt_internal_android_add_global_package_dependencies target) + foreach(type apk aab aar) + # Make global apk and aab targets depend on the current apk target. + if(TARGET ${type} AND TARGET ${target}_make_${type}) + add_dependencies(${type} ${target}_make_${type}) + endif() + endforeach() +endfunction() + function(_qt_internal_android_get_target_abis out_abis target) get_target_property(target_abis ${target} QT_ANDROID_ABIS) if(target_abis) @@ -1840,5 +1941,10 @@ function(_qt_internal_android_get_target_abis out_abis target) set(${out_abis} "${android_abis}" PARENT_SCOPE) endfunction() +# Returns the path to the Android platform-tools(adb is located there). +function(_qt_internal_android_get_platform_tools_path out_var) + set(${out_var} "${ANDROID_SDK_ROOT}/platform-tools" PARENT_SCOPE) +endfunction() + set(QT_INTERNAL_ANDROID_TARGET_BUILD_DIR_SUPPORT ON CACHE INTERNAL "Indicates that Qt supports per-target Android build directories") diff --git a/src/corelib/Qt6AndroidPermissionHelpers.cmake b/src/corelib/Qt6AndroidPermissionHelpers.cmake new file mode 100644 index 00000000000..7f851e14667 --- /dev/null +++ b/src/corelib/Qt6AndroidPermissionHelpers.cmake @@ -0,0 +1,126 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Generates the generator expression that converts the 'target' +# QT_ANDROID_PERMISSIONS property to the specific 'type'. +# +# It's expected that each element in QT_ANDROID_PERMISSIONS list has specific +# format: +# <name>\;<permission>\\\;<extra1>\;<value>\\\;<extra2>\;<value> +# +# Synopsis +# _qt_internal_android_convert_permissions(out_var target <JSON|XML>) +# +# Arguments +# +# `out_var` +# The name of the variable where the resulting generator expression is +# stored. +# +# `target` +# The name of the target. +# +# `JSON` +# Generate JSON array known by androiddeployqt. +# +# `XML` +# Generate XML content compatible with AndroidManifest.xml. +function(_qt_internal_android_convert_permissions out_var target type) + set(permissions_property "$<TARGET_PROPERTY:${target},QT_ANDROID_PERMISSIONS>") + set(permissions_genex "$<$<BOOL:${permissions_property}>:") + if(type STREQUAL "JSON") + set(pref "{ \"") + set(post "\" }") + set(indent "\n ") + string(APPEND permissions_genex + "[${indent}$<JOIN:" + "$<JOIN:" + "${pref}$<JOIN:" + "${permissions_property}," + "${post}$<COMMA>${indent}${pref}" + ">${post}," + "\": \"" + ">," + "\"$<COMMA> \"" + ">\n ]" + ) + elseif(type STREQUAL "XML") + set(pref "<uses-permission\n android:") + set(post "' /$<ANGLE-R>\n") + string(APPEND permissions_genex + "$<JOIN:" + "$<JOIN:" + "${pref}$<JOIN:" + "${permissions_property}," + "${post}${pref}" + ">${post}\n," + "='" + ">," + "' android:" + ">" + ) + else() + message(FATAL_ERROR "Invalid type ${type}. Supported types: JSON, XML") + endif() + string(APPEND permissions_genex ">") + + set(${out_var} "${permissions_genex}" PARENT_SCOPE) +endfunction() + +# Add the specific Android permission to the target. The permission is stored +# in the QT_ANDROID_PERMISSIONS property(the property is not a public API) +# and has the following format: +# <name>\;<permission>\\\;<extra1>\;<value>\\\;<extra2>\;<value> +# +# Synopsis +# _qt_internal_add_android_permission(target NAME <permission> +# ATTRIBUTES <extra1> <value1> +# [<extra2> <value2>]... +# ) +# +# Arguments +# +# `target` +# The Android target. +# +# `NAME` +# The permission name. E.g. 'android.permission.CAMERA'. +# +# `ATTRIBUTES` +# Extra permission attribute key-value pairs. +# See https://developer.android.com/guide/topics/manifest/uses-permission-element +# for details. +function(_qt_internal_add_android_permission target) + if(NOT TARGET ${target}) + message(FATAL_ERROR "Empty or invalid target for adding Android permission: (${target})") + endif() + + cmake_parse_arguments(arg "" "NAME" "ATTRIBUTES" ${ARGN}) + + if(NOT arg_NAME) + message(FATAL_ERROR "NAME for adding Android permission cannot be empty (${target})") + endif() + + set(permission_entry "name\;${arg_NAME}") + if(arg_ATTRIBUTES) + # Permission with additional attributes + list(LENGTH arg_ATTRIBUTES attributes_len) + math(EXPR attributes_modulus "${attributes_len} % 2") + if(NOT (attributes_len GREATER 1 AND attributes_modulus EQUAL 0)) + message(FATAL_ERROR "Android permission: ${arg_NAME} attributes: ${arg_ATTRIBUTES}" + " must be name-value pairs (for example: minSdkVersion 30)") + endif() + # Combine name-value pairs + set(index 0) + while(index LESS attributes_len) + list(GET arg_ATTRIBUTES ${index} name) + math(EXPR index "${index} + 1") + list(GET arg_ATTRIBUTES ${index} value) + string(APPEND permission_entry "\\\;${name}\;${value}") + math(EXPR index "${index} + 1") + endwhile() + endif() + + # Append the permission to the target's property + set_property(TARGET ${target} APPEND PROPERTY QT_ANDROID_PERMISSIONS "${permission_entry}") +endfunction() diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in index 15405197a61..8a88d558fa8 100644 --- a/src/corelib/Qt6CoreConfigExtras.cmake.in +++ b/src/corelib/Qt6CoreConfigExtras.cmake.in @@ -30,6 +30,10 @@ _qt_internal_setup_deploy_support() if(ANDROID_PLATFORM) include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]") + include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]") + include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]") + include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]") + _qt_internal_create_global_android_targets() _qt_internal_collect_default_android_abis() if(__qt_Core_targets_file_included) diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 7b522f99abb..5bc85ae7f7a 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -683,6 +683,9 @@ function(_qt_internal_create_executable target) ) qt6_android_apply_arch_suffix("${target}") + if(QT_USE_ANDROID_MODERN_BUNDLE) + _qt_internal_set_android_application_gradle_defaults(${target}) + endif() else() cmake_policy(PUSH) __qt_internal_set_cmp0156() diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index d74894e1e42..4388122b7b9 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default /*! \class QAbstractAnimation diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h index 69a30556a3a..b4b43e64a1d 100644 --- a/src/corelib/animation/qabstractanimation.h +++ b/src/corelib/animation/qabstractanimation.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QABSTRACTANIMATION_H #define QABSTRACTANIMATION_H diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index d6c245f36f0..51c635f1bed 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QABSTRACTANIMATION_P_H #define QABSTRACTANIMATION_P_H diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp index d2572a7462b..ae96069e86f 100644 --- a/src/corelib/animation/qanimationgroup.cpp +++ b/src/corelib/animation/qanimationgroup.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default /*! \class QAnimationGroup diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h index 412e2d442ea..07d24ae1f73 100644 --- a/src/corelib/animation/qanimationgroup.h +++ b/src/corelib/animation/qanimationgroup.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QANIMATIONGROUP_H #define QANIMATIONGROUP_H diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h index 334f780968a..a09bc6ebcc6 100644 --- a/src/corelib/animation/qanimationgroup_p.h +++ b/src/corelib/animation/qanimationgroup_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QANIMATIONGROUP_P_H #define QANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp index 86e9417b595..0b43a73434f 100644 --- a/src/corelib/animation/qparallelanimationgroup.cpp +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default /*! \class QParallelAnimationGroup diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h index 77bc6eabac7..9442f4f7355 100644 --- a/src/corelib/animation/qparallelanimationgroup.h +++ b/src/corelib/animation/qparallelanimationgroup.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPARALLELANIMATIONGROUP_H #define QPARALLELANIMATIONGROUP_H diff --git a/src/corelib/animation/qparallelanimationgroup_p.h b/src/corelib/animation/qparallelanimationgroup_p.h index 62c53d36097..482b9555c7d 100644 --- a/src/corelib/animation/qparallelanimationgroup_p.h +++ b/src/corelib/animation/qparallelanimationgroup_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPARALLELANIMATIONGROUP_P_H #define QPARALLELANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp index 344b21946e3..74e22e2f053 100644 --- a/src/corelib/animation/qpauseanimation.cpp +++ b/src/corelib/animation/qpauseanimation.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default /*! \class QPauseAnimation diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h index f661459f835..bf7863a171c 100644 --- a/src/corelib/animation/qpauseanimation.h +++ b/src/corelib/animation/qpauseanimation.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPAUSEANIMATION_H #define QPAUSEANIMATION_H diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 04f048af753..73ce8ca02c1 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default /*! \class QPropertyAnimation @@ -20,7 +21,12 @@ makes it possible to animate many of Qt's widgets. Let's look at an example: - \snippet code/src_corelib_animation_qpropertyanimation.cpp 0 + \snippet code/src_corelib_animation_qpropertyanimation.cpp includes + \snippet code/src_corelib_animation_qpropertyanimation.cpp class_decl + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl + \snippet code/src_corelib_animation_qpropertyanimation.cpp first_example + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close + \snippet code/src_corelib_animation_qpropertyanimation.cpp main \note You can also control an animation's lifespan by choosing a \l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting the diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h index 038c202b8f3..590a6ddaf15 100644 --- a/src/corelib/animation/qpropertyanimation.h +++ b/src/corelib/animation/qpropertyanimation.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPROPERTYANIMATION_H #define QPROPERTYANIMATION_H diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h index ef5534cd9c3..c1918ae1bf8 100644 --- a/src/corelib/animation/qpropertyanimation_p.h +++ b/src/corelib/animation/qpropertyanimation_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPROPERTYANIMATION_P_H #define QPROPERTYANIMATION_P_H diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 260481dbef5..d11249ca7ed 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default /*! \class QSequentialAnimationGroup diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h index 6786078170d..b7f9c1b17a1 100644 --- a/src/corelib/animation/qsequentialanimationgroup.h +++ b/src/corelib/animation/qsequentialanimationgroup.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QSEQUENTIALANIMATIONGROUP_H #define QSEQUENTIALANIMATIONGROUP_H diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h index cbdf204d0a6..131902b5aa5 100644 --- a/src/corelib/animation/qsequentialanimationgroup_p.h +++ b/src/corelib/animation/qsequentialanimationgroup_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QSEQUENTIALANIMATIONGROUP_P_H #define QSEQUENTIALANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index be5c09519e9..bd12d5dae95 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qvariantanimation.h" #include "qvariantanimation_p.h" diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h index 4bdb9713578..172ee0d6090 100644 --- a/src/corelib/animation/qvariantanimation.h +++ b/src/corelib/animation/qvariantanimation.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QVARIANTANIMATION_H #define QVARIANTANIMATION_H diff --git a/src/corelib/animation/qvariantanimation_p.h b/src/corelib/animation/qvariantanimation_p.h index 0ac238a882b..5fdd9666dba 100644 --- a/src/corelib/animation/qvariantanimation_p.h +++ b/src/corelib/animation/qvariantanimation_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QVARIANTANIMATION_P_H #define QVARIANTANIMATION_P_H diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index 909041cf44b..096dce9e84e 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -591,6 +591,7 @@ qt_config_compile_test(cpp_winrt runtimeobject CODE "// Including winrt/base.h causes an error in some configurations (Windows 10 SDK + c++20) +# include <guiddef.h> // required by clang-cl: https://github.com/microsoft/cppwinrt/issues/1179 # include <winrt/base.h> int main(void) diff --git a/src/corelib/doc/REUSE.toml b/src/corelib/doc/REUSE.toml index 254251a0b6b..969cc0d9938 100644 --- a/src/corelib/doc/REUSE.toml +++ b/src/corelib/doc/REUSE.toml @@ -3,23 +3,23 @@ version = 1 [[annotations]] path = ["snippets/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] path = ["**qdocinc", "**/images/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" [[annotations]] path = ["src/corelib/doc/qtcore.qdocconf"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] path = ["src/corelib/doc/include/QtCoreDoc"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" diff --git a/src/corelib/doc/snippets/CMakeLists.txt b/src/corelib/doc/snippets/CMakeLists.txt index 937433f2e21..78cd4f6b001 100644 --- a/src/corelib/doc/snippets/CMakeLists.txt +++ b/src/corelib/doc/snippets/CMakeLists.txt @@ -39,6 +39,7 @@ qt_internal_extend_target(corelib_snippets CONDITION QT_FEATURE_widgets hellotrmain.cpp fileinfo/main.cpp pointer/pointer.cpp + qsignalmapper/buttonwidget.cpp qsortfilterproxymodel-details/main.cpp qstring/main.cpp qtcast/qtcast.cpp @@ -53,6 +54,8 @@ qt_internal_extend_target(corelib_snippets CONDITION QT_FEATURE_gui qdebug/qdebugsnippet.cpp ) +set_target_properties(corelib_snippets PROPERTIES COMPILE_OPTIONS "-w") + if ("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_23") set_property(TARGET corelib_snippets PROPERTY CXX_STANDARD 23) endif() diff --git a/src/corelib/doc/snippets/code/doc_src_containers.cpp b/src/corelib/doc/snippets/code/doc_src_containers.cpp index b5684624929..167437c0151 100644 --- a/src/corelib/doc/snippets/code/doc_src_containers.cpp +++ b/src/corelib/doc/snippets/code/doc_src_containers.cpp @@ -3,6 +3,8 @@ #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses +#include <QtCore> + //! [0] class Employee { @@ -18,225 +20,225 @@ private: }; //! [0] -//! [range_for] -QList<QString> list = {"A", "B", "C", "D"}; -for (const auto &item : list) { - ... -} -//! [range_for] - -//! [range_for_as_const] -QList<QString> list = {"A", "B", "C", "D"}; -for (const auto &item : std::as_const(list)) { - ... -} -//! [range_for_as_const] - -//! [index] -QList<QString> list = {"A", "B", "C", "D"}; -for (qsizetype i = 0; i < list.size(); ++i) { - const auto &item = list.at(i); - ... -} -//! [index] - -//! [1] -QList<QString> list = {"A", "B", "C", "D"}; - -QListIterator<QString> i(list); -while (i.hasNext()) - QString s = i.next(); -//! [1] - - -//! [2] -QListIterator<QString> i(list); -i.toBack(); -while (i.hasPrevious()) - QString s = i.previous(); -//! [2] - - -//! [3] -QMutableListIterator<int> i(list); -while (i.hasNext()) { - if (i.next() % 2 != 0) - i.remove(); -} -//! [3] - - -//! [4] -QMutableListIterator<int> i(list); -i.toBack(); -while (i.hasPrevious()) { - if (i.previous() % 2 != 0) - i.remove(); -} -//! [4] - - -//! [5] -QMutableListIterator<int> i(list); -while (i.hasNext()) { - if (i.next() > 128) - i.setValue(128); -} -//! [5] - - -//! [6] -QMutableListIterator<int> i(list); -while (i.hasNext()) - i.next() *= 2; -//! [6] - - -//! [7] -QMap<QString, QString> map = { - {"Paris", "France"}, - {"Guatemala City", "Guatemala"}, - {"Mexico City", "Mexico"}, - {"Moscow", "Russia"} -}; -... - -QMutableMapIterator<QString, QString> i(map); -while (i.hasNext()) { - if (i.next().key().endsWith("City")) - i.remove(); -} -//! [7] - - -//! [8] -QMap<int, QWidget *> map; -QHash<int, QWidget *> hash; - -QMapIterator<int, QWidget *> i(map); -while (i.hasNext()) { - i.next(); - hash.insert(i.key(), i.value()); -} -//! [8] - - -//! [9] -QMutableMapIterator<int, QWidget *> i(map); -while (i.findNext(widget)) - i.remove(); -//! [9] +void examles() +{ + { + //! [range_for] + QList<QString> list = {"A", "B", "C", "D"}; + for (const auto &item : list) { + //... + } + //! [range_for] + } + { + //! [range_for_as_const] + QList<QString> list = {"A", "B", "C", "D"}; + for (const auto &item : std::as_const(list)) { + //... + } + //! [range_for_as_const] + } -//! [10] -QList<QString> list = {"A", "B", "C", "D"}; + { + //! [index] + QList<QString> list = {"A", "B", "C", "D"}; + for (qsizetype i = 0; i < list.size(); ++i) { + const auto &item = list.at(i); + //... + } + //! [index] + } -for (auto i = list.begin(), end = list.end(); i != end; ++i) - *i = (*i).toLower(); -//! [10] + { + //! [1] + QList<QString> list = {"A", "B", "C", "D"}; + QListIterator<QString> i(list); + while (i.hasNext()) + QString s = i.next(); + //! [1] + } -//! [11] -QList<QString> list = {"A", "B", "C", "D"}; + { + QList<QString> list = {"A", "B", "C", "D"}; -for (auto i = list.rbegin(), rend = list.rend(); i != rend; ++i) - *i = i->toLower(); -//! [11] + //! [2] + QListIterator<QString> i(list); + i.toBack(); + while (i.hasPrevious()) + QString s = i.previous(); + //! [2] + } + { + QList<int> list = {1, 2, 3, 4}; + { + //! [3] + QMutableListIterator<int> i(list); + while (i.hasNext()) { + if (i.next() % 2 != 0) + i.remove(); + } + //! [3] + } + + { + //! [4] + QMutableListIterator<int> i(list); + i.toBack(); + while (i.hasPrevious()) { + if (i.previous() % 2 != 0) + i.remove(); + } + //! [4] + } + + { + //! [5] + QMutableListIterator<int> i(list); + while (i.hasNext()) { + if (i.next() > 128) + i.setValue(128); + } + //! [5] + } + + { + //! [6] + QMutableListIterator<int> i(list); + while (i.hasNext()) + i.next() *= 2; + //! [6] + } + } -//! [12] -for (auto i = list.cbegin(), end = list.cend(); i != end; ++i) - qDebug() << *i; -//! [12] + { + //! [7] + QMap<QString, QString> map = { + {"Paris", "France"}, + {"Guatemala City", "Guatemala"}, + {"Mexico City", "Mexico"}, + {"Moscow", "Russia"} + }; + //... + + QMutableMapIterator<QString, QString> i(map); + while (i.hasNext()) { + if (i.next().key().endsWith("City")) + i.remove(); + } + //! [7] + } + { + //! [10] + QList<QString> list = {"A", "B", "C", "D"}; -//! [13] -QMap<int, int> map; -... -for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) - qDebug() << i.key() << ':' << i.value(); -//! [13] + for (auto i = list.begin(), end = list.end(); i != end; ++i) + *i = (*i).toLower(); + //! [10] + } + { + //! [11] + QList<QString> list = {"A", "B", "C", "D"}; -//! [14] -// RIGHT -const QList<int> sizes = splitter->sizes(); -for (auto i = sizes.begin(), end = sizes.end(); i != end; ++i) - ... + for (auto i = list.rbegin(), rend = list.rend(); i != rend; ++i) + *i = i->toLower(); + //! [11] -// WRONG -for (auto i = splitter->sizes().begin(); - i != splitter->sizes().end(); ++i) - ... -//! [14] + //! [12] + for (auto i = list.cbegin(), end = list.cend(); i != end; ++i) + qDebug() << *i; + //! [12] -//! [15] -QList<QString> values; -... -QString str; -foreach (str, values) - qDebug() << str; -//! [15] + //! [13] + QMap<int, int> map; + //... + for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) + qDebug() << i.key() << ':' << i.value(); + //! [13] + } -//! [16] -QList<QString> values; -... -QListIterator<QString> i(values); -while (i.hasNext()) { - QString s = i.next(); - qDebug() << s; -} -//! [16] + { + //! [15] + QList<QString> values; + //... + QString str; + foreach (str, values) + qDebug() << str; + //! [15] + } + { + //! [16] + QList<QString> values; + //... + QListIterator<QString> i(values); + while (i.hasNext()) { + QString s = i.next(); + qDebug() << s; + } + //! [16] + } -//! [17] -QList<QString> values; -... -foreach (const QString &str, values) - qDebug() << str; -//! [17] + { + //! [17] + QList<QString> values; + //... + foreach (const QString &str, values) + qDebug() << str; + //! [17] + } + { + //! [18] + QList<QString> values; + //... + foreach (const QString &str, values) { + if (str.isEmpty()) + break; + qDebug() << str; + } + //! [18] + } -//! [18] -QList<QString> values; -... -foreach (const QString &str, values) { - if (str.isEmpty()) - break; - qDebug() << str; -} -//! [18] + { + //! [19] + QMap<QString, int> map; + //... + foreach (const QString &str, map.keys()) + qDebug() << str << ':' << map.value(str); + //! [19] + } + { + //! [20] + QMultiMap<QString, int> map; + //... + foreach (const QString &str, map.uniqueKeys()) { + foreach (int i, map.values(str)) + qDebug() << str << ':' << i; + } + //! [20] + } -//! [19] -QMap<QString, int> map; -... -foreach (const QString &str, map.keys()) - qDebug() << str << ':' << map.value(str); -//! [19] + { + #if 0 + //! [22] + CONFIG += no_keywords + //! [22] -//! [20] -QMultiMap<QString, int> map; -... -foreach (const QString &str, map.uniqueKeys()) { - foreach (int i, map.values(str)) - qDebug() << str << ':' << i; + //! [cmake_no_keywords] + target_compile_definitions(my_app PRIVATE QT_NO_KEYWORDS) + //! [cmake_no_keywords] + #endif + } } -//! [20] - - -//! [22] -CONFIG += no_keywords -//! [22] - - -//! [cmake_no_keywords] -target_compile_definitions(my_app PRIVATE QT_NO_KEYWORDS) -//! [cmake_no_keywords] - //! [23] QString onlyLetters(const QString &in) @@ -250,61 +252,111 @@ QString onlyLetters(const QString &in) } //! [23] -//! [24] -QList<int> a, b; -a.resize(100000); // make a big list filled with 0. - -QList<int>::iterator i = a.begin(); -// WRONG way of using the iterator i: -b = a; -/* - Now we should be careful with iterator i since it will point to shared data - If we do *i = 4 then we would change the shared instance (both vectors) - The behavior differs from STL containers. Avoid doing such things in Qt. -*/ - -a[0] = 5; -/* - Container a is now detached from the shared data, - and even though i was an iterator from the container a, it now works as an iterator in b. - Here the situation is that (*i) == 0. -*/ - -b.clear(); // Now the iterator i is completely invalid. - -int j = *i; // Undefined behavior! -/* - The data from b (which i pointed to) is gone. - This would be well-defined with STL containers (and (*i) == 5), - but with QList this is likely to crash. -*/ -//! [24] - -//! [25] -QList<int> list = {1, 2, 3, 4, 4, 5}; -QSet<int> set(list.cbegin(), list.cend()); -/* - Will generate a QSet containing 1, 2, 3, 4, 5. -*/ -//! [25] - -//! [26] -QList<int> list = {2, 3, 1}; - -std::sort(list.begin(), list.end()); -/* - Sort the list, now contains { 1, 2, 3 } -*/ - -std::reverse(list.begin(), list.end()); -/* - Reverse the list, now contains { 3, 2, 1 } -*/ - -int even_elements = - std::count_if(list.begin(), list.end(), [](int element) { return (element % 2 == 0); }); -/* - Count how many elements that are even numbers, 1 -*/ - -//! [26] +void wrap() +{ + //! [24] + QList<int> a, b; + a.resize(100000); // make a big list filled with 0. + + QList<int>::iterator i = a.begin(); + // WRONG way of using the iterator i: + b = a; + /* + Now we should be careful with iterator i since it will point to shared data + If we do *i = 4 then we would change the shared instance (both vectors) + The behavior differs from STL containers. Avoid doing such things in Qt. + */ + + a[0] = 5; + /* + Container a is now detached from the shared data, + and even though i was an iterator from the container a, it now works as an iterator in b. + Here the situation is that (*i) == 0. + */ + + b.clear(); // Now the iterator i is completely invalid. + + int j = *i; // Undefined behavior! + /* + The data from b (which i pointed to) is gone. + This would be well-defined with STL containers (and (*i) == 5), + but with QList this is likely to crash. + */ + //! [24] + + { + //! [25] + QList<int> list = {1, 2, 3, 4, 4, 5}; + QSet<int> set(list.cbegin(), list.cend()); + /* + Will generate a QSet containing 1, 2, 3, 4, 5. + */ + //! [25] + } + + //! [26] + QList<int> list = {2, 3, 1}; + + std::sort(list.begin(), list.end()); + /* + Sort the list, now contains { 1, 2, 3 } + */ + + std::reverse(list.begin(), list.end()); + /* + Reverse the list, now contains { 3, 2, 1 } + */ + + int even_elements = + std::count_if(list.begin(), list.end(), [](int element) { return (element % 2 == 0); }); + /* + Count how many elements that are even numbers, 1 + */ + //! [26] +} + +#if __has_include(<QWidget>) + +#include <QWidget> +#include <QSplitter> + +void examples_with_widgets() +{ + { + //! [8] + QMap<int, QWidget *> map; + QHash<int, QWidget *> hash; + + QMapIterator<int, QWidget *> i(map); + while (i.hasNext()) { + i.next(); + hash.insert(i.key(), i.value()); + } + //! [8] + } + + { + QMap<int, QWidget *> map; + QWidget* widget; + //! [9] + QMutableMapIterator<int, QWidget *> i(map); + while (i.findNext(widget)) + i.remove(); + //! [9] + } + + QSplitter* splitter; + + //! [14] + // RIGHT + const QList<int> sizes = splitter->sizes(); + for (auto i = sizes.begin(), end = sizes.end(); i != end; ++i) + {/*...*/} + + // WRONG + for (auto i = splitter->sizes().begin(); + i != splitter->sizes().end(); ++i) + {/*...*/} + //! [14] +} +#endif diff --git a/src/corelib/doc/snippets/code/doc_src_groups.cpp b/src/corelib/doc/snippets/code/doc_src_groups.cpp index a0901904db0..2d7c2f96056 100644 --- a/src/corelib/doc/snippets/code/doc_src_groups.cpp +++ b/src/corelib/doc/snippets/code/doc_src_groups.cpp @@ -1,6 +1,15 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QPen> +#include <QPainter> + +class QPenPrivate { +public: + int ref = 1; + Qt::PenStyle style; +}; + //! [0] void QPen::setStyle(Qt::PenStyle style) { @@ -11,19 +20,21 @@ void QPen::setStyle(Qt::PenStyle style) void QPen::detach() { if (d->ref != 1) { - ... // perform a deep copy + //... // perform a deep copy } } //! [0] +void example() +{ + //! [1] + QPixmap p1, p2; + p1.load("image.bmp"); + p2 = p1; // p1 and p2 share data -//! [1] -QPixmap p1, p2; -p1.load("image.bmp"); -p2 = p1; // p1 and p2 share data - -QPainter paint; -paint.begin(&p2); // cuts p2 loose from p1 -paint.drawText(0,50, "Hi"); -paint.end(); -//! [1] + QPainter paint; + paint.begin(&p2); // cuts p2 loose from p1 + paint.drawText(0,50, "Hi"); + paint.end(); + //! [1] +} diff --git a/src/corelib/doc/snippets/code/doc_src_objecttrees.cpp b/src/corelib/doc/snippets/code/doc_src_objecttrees.cpp index b7c71ccb6b0..8b55ad9b157 100644 --- a/src/corelib/doc/snippets/code/doc_src_objecttrees.cpp +++ b/src/corelib/doc/snippets/code/doc_src_objecttrees.cpp @@ -1,23 +1,31 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//![0] +#include <QPushButton> + +//![open] int main() { - QWidget window; - QPushButton quit("Quit", &window); - ... -} -//![0] +//![open] + { + //![example1] + QWidget window; + QPushButton quit("Quit", &window); + //... + //![example1] + } -//![1] -int main() -{ - QPushButton quit("Quit"); - QWidget window; + { + //![example2] + QPushButton quit("Quit"); + QWidget window; + + quit.setParent(&window); + //... + //![example2] + } - quit.setParent(&window); - ... +//![close] } -//![1] +//![close] diff --git a/src/corelib/doc/snippets/code/doc_src_properties.cpp b/src/corelib/doc/snippets/code/doc_src_properties.cpp index 190a8437101..eafa7acda3b 100644 --- a/src/corelib/doc/snippets/code/doc_src_properties.cpp +++ b/src/corelib/doc/snippets/code/doc_src_properties.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#ifdef QPROPERTY_MACRO //! [0] Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | @@ -25,33 +26,40 @@ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor) //! [1] - //! [2] Q_PROPERTY(QDate date READ getDate WRITE setDate) //! [2] +#endif +#if __has_include(<QPushButton>) +#include <QPushButton> +void button_example() +{ + //! [3] + QPushButton *button = new QPushButton; + QObject *object = button; -//! [3] -QPushButton *button = new QPushButton; -QObject *object = button; - -button->setDown(true); -object->setProperty("down", true); -//! [3] - - -//! [4] -QObject *object = ... -const QMetaObject *metaobject = object->metaObject(); -int count = metaobject->propertyCount(); -for (int i=0; i<count; ++i) { - QMetaProperty metaproperty = metaobject->property(i); - const char *name = metaproperty.name(); - QVariant value = object->property(name); - ... + button->setDown(true); + object->setProperty("down", true); + //! [3] } -//! [4] +#endif +#include <QMetaProperty> +void qobject_example() +{ + //! [4] + QObject *object = new QObject; + const QMetaObject *metaobject = object->metaObject(); + int count = metaobject->propertyCount(); + for (int i=0; i<count; ++i) { + QMetaProperty metaproperty = metaobject->property(i); + const char *name = metaproperty.name(); + QVariant value = object->property(name); + //... + } + //! [4] +} //! [5] class MyClass : public QObject @@ -85,16 +93,17 @@ private: }; //! [5] +void example(){ + //! [6] + MyClass *myinstance = new MyClass; + QObject *object = myinstance; -//! [6] -MyClass *myinstance = new MyClass; -QObject *object = myinstance; - -myinstance->setPriority(MyClass::VeryHigh); -object->setProperty("priority", "VeryHigh"); -//! [6] - + myinstance->setPriority(MyClass::VeryHigh); + object->setProperty("priority", "VeryHigh"); + //! [6] +} +#ifdef QPROPERTY_MACRO //! [7] Q_CLASSINFO("DefaultProperty", "content") //! [7] @@ -103,7 +112,7 @@ Q_CLASSINFO("DefaultProperty", "content") Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged) Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged) Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged) - ... + //... signals: void colorChanged(); void spacingChanged(); @@ -114,4 +123,4 @@ private: qreal m_spacing; QString m_text; //! [8] - +#endif diff --git a/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp b/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp index f2b94a74165..9155345508a 100644 --- a/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp @@ -1,11 +1,17 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [1] -QList<Employee *> list; -list.append(new Employee("Blackpool", "Stephen")); -list.append(new Employee("Twist", "Oliver")); +#include <QList> +#include <QColor> -qDeleteAll(list.begin(), list.end()); -list.clear(); -//! [1] +void example() +{ + //! [1] + QList<QColor *> list; + list.append(new QColor(Qt::blue)); + list.append(new QColor(Qt::yellow)); + + qDeleteAll(list.begin(), list.end()); + list.clear(); + //! [1] +} diff --git a/src/corelib/doc/snippets/code/doc_src_qcache.cpp b/src/corelib/doc/snippets/code/doc_src_qcache.cpp index a15a8027600..3157981f3fa 100644 --- a/src/corelib/doc/snippets/code/doc_src_qcache.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qcache.cpp @@ -1,20 +1,34 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] -QCache<int, Employee> cache; -//! [0] +#include <QCache> +struct Employee { + void setId(int id); + int id() const { return 0; } + void setName(const QString &name); +}; -//! [1] -Employee *employee = new Employee; -employee->setId(37); -employee->setName("Richard Schmit"); -... -cache.insert(employee->id(), employee); -//! [1] +struct MyDataStructure { }; +void example() +{ + //! [0] + QCache<int, Employee> cache; + //! [0] -//! [2] -QCache<int, MyDataStructure> cache(5000); -//! [2] + + //! [1] + Employee *employee = new Employee; + employee->setId(37); + employee->setName("Richard Schmit"); + //... + cache.insert(employee->id(), employee); + //! [1] + + { + //! [2] + QCache<int, MyDataStructure> cache(5000); + //! [2] + } +} diff --git a/src/corelib/doc/snippets/code/doc_src_qiterator.cpp b/src/corelib/doc/snippets/code/doc_src_qiterator.cpp index 0d921b87e67..209e98af522 100644 --- a/src/corelib/doc/snippets/code/doc_src_qiterator.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qiterator.cpp @@ -1,278 +1,349 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -//! [0] -QList<float> list; -... -QListIterator<float> i(list); -while (i.hasNext()) - float f = i.next(); -//! [0] - - -//! [1] -QListIterator<float> i(list); -i.toBack(); -while (i.hasPrevious()) - float f = i.previous(); -//! [1] - -//! [6] -QSet<QString> set; -... -QSetIterator<QString> i(set); -while (i.hasNext()) - float f = i.next(); -//! [6] - -//! [8] -QList<float> list; -... -QMutableListIterator<float> i(list); -while (i.hasNext()) - float f = i.next(); -//! [8] - - -//! [9] -QMutableListIterator<float> i(list); -i.toBack(); -while (i.hasPrevious()) - float f = i.previous(); -//! [9] - - -//! [10] -QMutableListIterator<int> i(list); -while (i.hasNext()) { - int val = i.next(); - if (val < 0) { - i.setValue(-val); - } else if (val == 0) { - i.remove(); +#include <QList> +#include <QSet> + +void example() +{ + { + //! [0] + QList<float> list; + //... + QListIterator<float> i(list); + while (i.hasNext()) + float f = i.next(); + //! [0] } -} -//! [10] - -//! [17] -QSet<float> set; -... -QMutableSetIterator<float> i(set); -while (i.hasNext()) - float f = i.next(); -//! [17] -//! [19] -QMutableListIterator<int> i(list); -while (i.hasNext()) { - int val = i.next(); - if (val < -32768 || val > 32767) - i.remove(); -} -//! [19] - -//! [22] -QMutableSetIterator<int> i(set); -while (i.hasNext()) { - int val = i.next(); - if (val < -32768 || val > 32767) - i.remove(); -} -//! [22] - - -//! [23] -QMutableListIterator<double> i(list); -while (i.hasNext()) { - double val = i.next(); - i.setValue(std::sqrt(val)); -} -//! [23] - -//! [26] -QMap<int, QWidget *> map; -... -QMapIterator<int, QWidget *> i(map); -while (i.hasNext()) { - i.next(); - qDebug() << i.key() << ": " << i.value(); -} -//! [26] - - -//! [27] -QMapIterator<int, QWidget *> i(map); -i.toBack(); -while (i.hasPrevious()) { - i.previous(); - qDebug() << i.key() << ": " << i.value(); -} -//! [27] - - -//! [28] -QMapIterator<int, QWidget *> i(map); -while (i.findNext(widget)) { - qDebug() << "Found widget " << widget << " under key " - << i.key(); -} -//! [28] - -//! [26multi] -QMultiMap<int, QWidget *> multimap; -... -QMultiMapIterator<int, QWidget *> i(multimap); -while (i.hasNext()) { - i.next(); - qDebug() << i.key() << ": " << i.value(); -} -//! [26multi] + QList<float> list; + { + //! [1] + QListIterator<float> i(list); + i.toBack(); + while (i.hasPrevious()) + float f = i.previous(); + //! [1] + } -//! [27multi] -QMultiMapIterator<int, QWidget *> i(multimap); -i.toBack(); -while (i.hasPrevious()) { - i.previous(); - qDebug() << i.key() << ": " << i.value(); -} -//! [27multi] + { + //! [6] + QSet<QString> set; + //... + QSetIterator<QString> i(set); + while (i.hasNext()) + QString f = i.next(); + //! [6] + } + { + //! [8] + QList<float> list; + //... + QMutableListIterator<float> i(list); + while (i.hasNext()) + float f = i.next(); + //! [8] + } -//! [28multi] -QMultiMapIterator<int, QWidget *> i(multimap); -while (i.findNext(widget)) { - qDebug() << "Found widget " << widget << " under key " - << i.key(); -} -//! [28multi] + { + //! [9] + QMutableListIterator<float> i(list); + i.toBack(); + while (i.hasPrevious()) + float f = i.previous(); + //! [9] + } + { + QList<int> list = {1, 2, 3, 4, 5}; + //! [10] + QMutableListIterator<int> i(list); + while (i.hasNext()) { + int val = i.next(); + if (val < 0) { + i.setValue(-val); + } else if (val == 0) { + i.remove(); + } + } + //! [10] + } -//! [29] -QHash<int, QWidget *> hash; -... -QHashIterator<int, QWidget *> i(hash); -while (i.hasNext()) { - i.next(); - qDebug() << i.key() << ": " << i.value(); -} -//! [29] + { + //! [17] + QSet<float> set; + //... + QMutableSetIterator<float> i(set); + while (i.hasNext()) + float f = i.next(); + //! [17] + } + { + QList<int> list = {1, 2, 3, 4, 5}; + //! [19] + QMutableListIterator<int> i(list); + while (i.hasNext()) { + int val = i.next(); + if (val < -32768 || val > 32767) + i.remove(); + } + //! [19] + } -//! [31] -QHashIterator<int, QWidget *> i(hash); -while (i.findNext(widget)) { - qDebug() << "Found widget " << widget << " under key " - << i.key(); -} -//! [31] + { + QSet<int> set; + //! [22] + QMutableSetIterator<int> i(set); + while (i.hasNext()) { + int val = i.next(); + if (val < -32768 || val > 32767) + i.remove(); + } + //! [22] + } + { + QList<double> list; + //! [23] + QMutableListIterator<double> i(list); + while (i.hasNext()) { + double val = i.next(); + i.setValue(std::sqrt(val)); + } + //! [23] + } -//! [32] -QMap<int, QWidget *> map; -... -QMutableMapIterator<int, QWidget *> i(map); -while (i.hasNext()) { - i.next(); - qDebug() << i.key() << ": " << i.value(); + { + //! [25] + QList<int> list; + //... + QListIterator<int> i(list); + while (i.hasNext()) + int val = i.next(); + //! [25] + } } -//! [32] - -//! [33] -QMutableMapIterator<int, QWidget *> i(map); -i.toBack(); -while (i.hasPrevious()) { - i.previous(); - qDebug() << i.key() << ": " << i.value(); -} -//! [33] +#if __has_include(<QWidget>) +#include <QWidget> +void example_widgets() +{ + QMap<int, QWidget *> map; + { + //! [26] + QMap<int, QWidget *> map; + //... + QMapIterator<int, QWidget *> i(map); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": " << i.value(); + } + //! [26] + } + { + //! [27] + QMapIterator<int, QWidget *> i(map); + i.toBack(); + while (i.hasPrevious()) { + i.previous(); + qDebug() << i.key() << ": " << i.value(); + } + //! [27] + } -//! [34] -QMutableMapIterator<int, QWidget *> i(map); -while (i.findNext(widget)) { - qDebug() << "Found widget " << widget << " under key " - << i.key(); -} -//! [34] + QWidget *widget; + { + //! [28] + QMapIterator<int, QWidget *> i(map); + while (i.findNext(widget)) { + qDebug() << "Found widget " << widget << " under key " + << i.key(); + } + //! [28] + } + { + //! [26multi] + QMultiMap<int, QWidget *> multimap; + //... + QMultiMapIterator<int, QWidget *> i(multimap); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": " << i.value(); + } + //! [26multi] + } -//! [35] -QMutableMapIterator<QString, QString> i(map); -while (i.hasNext()) { - i.next(); - if (i.key() == i.value()) - i.remove(); -} -//! [35] + QMultiMap<int, QWidget *> multimap; + { + //! [27multi] + QMultiMapIterator<int, QWidget *> i(multimap); + i.toBack(); + while (i.hasPrevious()) { + i.previous(); + qDebug() << i.key() << ": " << i.value(); + } + //! [27multi] + } + { + //! [28multi] + QMultiMapIterator<int, QWidget *> i(multimap); + while (i.findNext(widget)) { + qDebug() << "Found widget " << widget << " under key " + << i.key(); + } + //! [28multi] + } -//! [32multi] -QMultiMap<int, QWidget *> multimap; -... -QMutableMultiMapIterator<int, QWidget *> i(multimap); -while (i.hasNext()) { - i.next(); - qDebug() << i.key() << ": " << i.value(); -} -//! [32multi] + { + //! [29] + QHash<int, QWidget *> hash; + //... + QHashIterator<int, QWidget *> i(hash); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": " << i.value(); + } + //! [29] + } + QHash<int, QWidget *> hash; + { + //! [31] + QHashIterator<int, QWidget *> i(hash); + while (i.findNext(widget)) { + qDebug() << "Found widget " << widget << " under key " + << i.key(); + } + //! [31] + } -//! [33multi] -QMutableMultiMapIterator<int, QWidget *> i(multimap); -i.toBack(); -while (i.hasPrevious()) { - i.previous(); - qDebug() << i.key() << ": " << i.value(); -} -//! [33multi] + { + //! [32] + QMap<int, QWidget *> map; + //... + QMutableMapIterator<int, QWidget *> i(map); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": " << i.value(); + } + //! [32] + } + { + //! [33] + QMutableMapIterator<int, QWidget *> i(map); + i.toBack(); + while (i.hasPrevious()) { + i.previous(); + qDebug() << i.key() << ": " << i.value(); + } + //! [33] + } -//! [34multi] -QMutableMultiMapIterator<int, QWidget *> i(multimap); -while (i.findNext(widget)) { - qDebug() << "Found widget " << widget << " under key " - << i.key(); -} -//! [34multi] + { + //! [34] + QMutableMapIterator<int, QWidget *> i(map); + while (i.findNext(widget)) { + qDebug() << "Found widget " << widget << " under key " + << i.key(); + } + //! [34] + } + { + QMap<QString, QString> map; + //! [35] + QMutableMapIterator<QString, QString> i(map); + while (i.hasNext()) { + i.next(); + if (i.key() == i.value()) + i.remove(); + } + //! [35] + } -//! [35multi] -QMutableMultiMapIterator<QString, QString> i(multimap); -while (i.hasNext()) { - i.next(); - if (i.key() == i.value()) - i.remove(); -} -//! [35multi] + { + //! [32multi] + QMultiMap<int, QWidget *> multimap; + //... + QMutableMultiMapIterator<int, QWidget *> i(multimap); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": " << i.value(); + } + //! [32multi] + } + { + //! [33multi] + QMutableMultiMapIterator<int, QWidget *> i(multimap); + i.toBack(); + while (i.hasPrevious()) { + i.previous(); + qDebug() << i.key() << ": " << i.value(); + } + //! [33multi] + } -//! [36] -QHash<int, QWidget *> hash; -... -QMutableHashIterator<QString, QWidget *> i(hash); -while (i.hasNext()) { - i.next(); - qDebug() << i.key() << ": " << i.value(); -} -//! [36] + { + //! [34multi] + QMutableMultiMapIterator<int, QWidget *> i(multimap); + while (i.findNext(widget)) { + qDebug() << "Found widget " << widget << " under key " + << i.key(); + } + //! [34multi] + } + { + QMultiMap<QString, QString> multimap; + //! [35multi] + QMutableMultiMapIterator<QString, QString> i(multimap); + while (i.hasNext()) { + i.next(); + if (i.key() == i.value()) + i.remove(); + } + //! [35multi] + } -//! [38] -QMutableHashIterator<int, QWidget *> i(hash); -while (i.findNext(widget)) { - qDebug() << "Found widget " << widget << " under key " - << i.key(); -} -//! [38] + { + //! [36] + QHash<int, QWidget *> hash; + //... + QMutableHashIterator<int, QWidget *> i(hash); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": " << i.value(); + } + //! [36] + } + { + //! [38] + QMutableHashIterator<int, QWidget *> i(hash); + while (i.findNext(widget)) { + qDebug() << "Found widget " << widget << " under key " + << i.key(); + } + //! [38] + } -//! [39] -QMutableHashIterator<QString, QString> i(hash); -while (i.hasNext()) { - i.next(); - if (i.key() == i.value()) - i.remove(); + { + QHash<QString, QString> hash; + //! [39] + QMutableHashIterator<QString, QString> i(hash); + while (i.hasNext()) { + i.next(); + if (i.key() == i.value()) + i.remove(); + } + //! [39] + } } -//! [39] +#endif diff --git a/src/corelib/doc/snippets/code/doc_src_qnamespace.cpp b/src/corelib/doc/snippets/code/doc_src_qnamespace.cpp index 10845855840..d753874f0dd 100644 --- a/src/corelib/doc/snippets/code/doc_src_qnamespace.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qnamespace.cpp @@ -1,6 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QEvent> + //! [1] enum CustomEventPriority { diff --git a/src/corelib/doc/snippets/code/doc_src_qplugin.cpp b/src/corelib/doc/snippets/code/doc_src_qplugin.cpp index 3bca27b9661..4382d13838a 100644 --- a/src/corelib/doc/snippets/code/doc_src_qplugin.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qplugin.cpp @@ -1,10 +1,12 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QtPlugin> + //! [0] namespace Foo { - struct MyInterface { ... }; + struct MyInterface { /*...*/ }; } Q_DECLARE_INTERFACE(Foo::MyInterface, "org.examples.MyInterface") diff --git a/src/corelib/doc/snippets/code/doc_src_qset.cpp b/src/corelib/doc/snippets/code/doc_src_qset.cpp index 98a6f336f5a..8342e1d6f98 100644 --- a/src/corelib/doc/snippets/code/doc_src_qset.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qset.cpp @@ -1,107 +1,134 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] -QSet<QString> set; -//! [0] +#include <QtCore> +#include <iostream> +using namespace std; +void snippets_0_3() +{ + //! [0] + QSet<QString> set; + //! [0] -//! [1] -set.insert("one"); -set.insert("three"); -set.insert("seven"); -//! [1] + //! [1] + set.insert("one"); + set.insert("three"); + set.insert("seven"); + //! [1] -//! [2] -set << "twelve" << "fifteen" << "nineteen"; -//! [2] + //! [2] + set << "twelve" << "fifteen" << "nineteen"; + //! [2] -//! [3] -if (!set.contains("ninety-nine")) - ... -//! [3] - -//! [4] -QSetIterator<QWidget *> i(set); -while (i.hasNext()) { - QWidget *w = i.next(); - qDebug() << w; + //! [3] + if (!set.contains("ninety-nine")) + {/*...*/} + //! [3] } -//! [4] - -//! [5] -for (auto i = set.cbegin(), end = set.cend(); i != end; ++i) - qDebug() << *i; -//! [5] +#if __has_include(<QWidget>) +#include <QWidget> -//! [6] -QSet<QString> set; -... -for (const auto &value : set) - qDebug() << value; -//! [6] +void example_widgets() +{ + QSet<QWidget *> set; + //! [4] + QSetIterator<QWidget *> i(set); + while (i.hasNext()) { + QWidget *w = i.next(); + qDebug() << w; + } + //! [4] +} +#endif + +void snippets_5_12() +{ + QSet<QString> set; + + //! [5] + for (auto i = set.cbegin(), end = set.cend(); i != end; ++i) + qDebug() << *i; + //! [5] + + { + //! [6] + QSet<QString> set; + //... + for (const auto &value : set) + qDebug() << value; + //! [6] + } + { + QString values[3]; + //! [7] + QSet<QString> set; + set.reserve(20000); + for (int i = 0; i < 20000; ++i) + set.insert(values[i]); + //! [7] + } -//! [7] -QSet<QString> set; -set.reserve(20000); -for (int i = 0; i < 20000; ++i) - set.insert(values[i]); -//! [7] + { + //! [8] + QSet<QString> set = {"January", "February", /*...*/ "December"}; + // i is a QSet<QString>::iterator + for (auto i = set.begin(), end = set.end(); i != end; ++i) + qDebug() << *i; + //! [8] + } -//! [8] -QSet<QString> set = {"January", "February", ... "December"} + { + //! [9] + QSet<QString> set = {"January", "February", /*...*/ "December"}; + + auto i = set.begin(); + while (i != set.end()) { + if ((*i).startsWith('J')) { + i = set.erase(i); + } else { + ++i; + } + } + //! [9] + } -// i is a QSet<QString>::iterator -for (auto i = set.begin(), end = set.end(); i != end; ++i) - qDebug() << *i; -//! [8] + { + //! [10] + QSet<QString> set; + //... + const auto predicate = [](const QString &s) { return s.compare("Jeanette", Qt::CaseInsensitive) == 0; }; + QSet<QString>::iterator it = std::find_if(set.begin(), set.end(), predicate); + if (it != set.end()) + cout << "Found Jeanette" << endl; + //! [10] + } + { + //! [11] + QSet<QString> set = {"January", "February", /*...*/ "December"}; -//! [9] -QSet<QString> set = {"January", "February", ... "December"}; + // i is QSet<QString>::const_iterator + for (auto i = set.cbegin(), end = set.cend(); i != end; ++i) + qDebug() << *i; + //! [11] + } -auto i = set.begin(); -while (i != set.end()) { - if ((*i).startsWith('J')) { - i = set.erase(i); - } else { - ++i; + { + //! [12] + QSet<QString> set; + //... + const auto predicate = [](const QString &s) { return s.compare("Jeanette", Qt::CaseInsensitive) == 0; }; + QSet<QString>::const_iterator it = std::find_if(set.cbegin(), set.cend(), predicate); + if (it != set.constEnd()) + cout << "Found Jeanette" << endl; + //! [12] } } -//! [9] - - -//! [10] -QSet<QString> set; -... -const auto predicate = [](const QString &s) { return s.compare("Jeanette", Qt::CaseInsensitive) == 0; }; -QSet<QString>::iterator it = std::find_if(set.begin(), set.end(), predicate); -if (it != set.end()) - cout << "Found Jeanette" << endl; -//! [10] - - -//! [11] -QSet<QString> set = {"January", "February", ... "December"}; - -// i is QSet<QString>::const_iterator -for (auto i = set.cbegin(), end = set.cend(); i != end; ++i) - qDebug() << *i; -//! [11] - - -//! [12] -QSet<QString> set; -... -const auto predicate = [](const QString &s) { return s.compare("Jeanette", Qt::CaseInsensitive) == 0; }; -QSet<QString>::const_iterator it = std::find_if(set.cbegin(), set.cend(), predicate); -if (it != set.constEnd()) - cout << "Found Jeanette" << endl; -//! [12] diff --git a/src/corelib/doc/snippets/code/doc_src_qvarlengtharray.cpp b/src/corelib/doc/snippets/code/doc_src_qvarlengtharray.cpp index 080874fc77d..4d2ccc82c2e 100644 --- a/src/corelib/doc/snippets/code/doc_src_qvarlengtharray.cpp +++ b/src/corelib/doc/snippets/code/doc_src_qvarlengtharray.cpp @@ -1,21 +1,24 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QVarLengthArray> + +#if 0 //! [0] -int myfunc(int n) +int myfunc_wrong(int n) { int table[n + 1]; // WRONG - ... + //... return table[n]; } //! [0] - +#endif //! [1] -int myfunc(int n) +int myfunc_correct(int n) { int *table = new int[n + 1]; - ... + //... int ret = table[n]; delete[] table; return ret; @@ -24,18 +27,21 @@ int myfunc(int n) //! [2] -int myfunc(int n) +int myfunc_q(int n) { QVarLengthArray<int, 1024> array(n + 1); - ... + //... return array[n]; } //! [2] -//! [3] -QVarLengthArray<int> array(10); -int *data = array.data(); -for (int i = 0; i < 10; ++i) - data[i] = 2 * i; -//! [3] +void example() +{ + //! [3] + QVarLengthArray<int> array(10); + int *data = array.data(); + for (int i = 0; i < 10; ++i) + data[i] = 2 * i; + //! [3] +} diff --git a/src/corelib/doc/snippets/code/doc_src_resources.cpp b/src/corelib/doc/snippets/code/doc_src_resources.cpp index 04ecf810ec1..9a244b9239d 100644 --- a/src/corelib/doc/snippets/code/doc_src_resources.cpp +++ b/src/corelib/doc/snippets/code/doc_src_resources.cpp @@ -1,10 +1,25 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [4] -QResource::registerResource("/path/to/myresource.rcc"); -//! [4] +#include <QResource> +#include <QFile> +void wrap() +{ + //! [4] + QResource::registerResource("/path/to/myresource.rcc"); + //! [4] +} + +class BaseClass { + public: + BaseClass() {} +}; + +class MyClass : BaseClass { + public: + MyClass(); +}; //! [5] MyClass::MyClass() : BaseClass() @@ -12,6 +27,6 @@ MyClass::MyClass() : BaseClass() Q_INIT_RESOURCE(resources); QFile file(":/myfile.dat"); - ... + //... } //! [5] diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp index 6328cb00119..db3a9ee2dc0 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qparallelanimationgroup.cpp @@ -1,10 +1,15 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -//! [0] - QParallelAnimationGroup *group = new QParallelAnimationGroup; - group->addAnimation(anim1); - group->addAnimation(anim2); +#include <QParallelAnimationGroup> - group->start(); -//! [0] +void example(QAbstractAnimation *anim1, QAbstractAnimation *anim2) +{ + //! [0] + QParallelAnimationGroup *group = new QParallelAnimationGroup; + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + //! [0] +} diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp index 4b77ab607db..7f259e99fb8 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp @@ -1,28 +1,102 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QParallelAnimationGroup> +#include <QSequentialAnimationGroup> -//! [0] +//! [includes] #include <QApplication> #include <QPushButton> #include <QPropertyAnimation> +//![includes] + +//! [class_decl] class MyButtonWidget : public QWidget { public: MyButtonWidget(QWidget *parent = nullptr); }; +//! [class_decl] + +//! [ctor_impl] MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { - QPushButton *button = new QPushButton(tr("Animated Button"), this); - QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); - anim->setDuration(10000); - anim->setStartValue(QPoint(0, 0)); - anim->setEndValue(QPoint(100, 250)); - anim->start(); +//![ctor_impl] + { + //! [first_example] + QPushButton *button = new QPushButton(tr("Animated Button"), this); + QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); + anim->setDuration(10000); + anim->setStartValue(QPoint(0, 0)); + anim->setEndValue(QPoint(100, 250)); + anim->start(); + //! [first_example] + } + + { + //! [easing-curve] + QPushButton *button = new QPushButton(tr("Animated Button"), this); + QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); + anim->setDuration(10000); + anim->setStartValue(QPoint(0, 0)); + anim->setEndValue(QPoint(100, 250)); + anim->setEasingCurve(QEasingCurve::OutBounce); + anim->start(); + //! [easing-curve] + } + + { + //! [animation-group1] + QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); + QPushButton *clyde = new QPushButton(tr("Clyde"), this); + + QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); + anim1->setDuration(3000); + anim1->setStartValue(QPoint(0, 0)); + anim1->setEndValue(QPoint(100, 250)); + + QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); + anim2->setDuration(3000); + anim2->setStartValue(QPoint(100, 250)); + anim2->setEndValue(QPoint(500, 500)); + + QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup; + parallelAnim->addAnimation(anim1); + parallelAnim->addAnimation(anim2); + parallelAnim->start(); + //! [animation-group1] + } + + { + //! [animation-group2] + QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); + QPushButton *clyde = new QPushButton(tr("Clyde"), this); + + QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); + anim1->setDuration(3000); + anim1->setStartValue(QPoint(0, 0)); + anim1->setEndValue(QPoint(100, 250)); + + QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); + anim2->setDuration(3000); + anim2->setStartValue(QPoint(0, 0)); + anim2->setEndValue(QPoint(200, 250)); + + QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup; + sequenceAnim->addAnimation(anim1); + sequenceAnim->addAnimation(anim2); + sequenceAnim->start(); + //! [animation-group2] + } + +//! [ctor_close] } +//! [ctor_close] + +//! [main] int main(int argc, char *argv[]) { QApplication a(argc, argv); @@ -31,65 +105,4 @@ int main(int argc, char *argv[]) buttonAnimWidget.show(); return a.exec(); } -//! [0] - - -//! [easing-curve] -MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) -{ - QPushButton *button = new QPushButton(tr("Animated Button"), this); - QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); - anim->setDuration(10000); - anim->setStartValue(QPoint(0, 0)); - anim->setEndValue(QPoint(100, 250)); - anim->setEasingCurve(QEasingCurve::OutBounce); - anim->start(); -} -//! [easing-curve] - - -//! [animation-group1] -MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) -{ - QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); - QPushButton *clyde = new QPushButton(tr("Clyde"), this); - - QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); - anim1->setDuration(3000); - anim1->setStartValue(QPoint(0, 0)); - anim1->setEndValue(QPoint(100, 250)); - - QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); - anim2->setDuration(3000); - anim2->setStartValue(QPoint(100, 250)); - anim2->setEndValue(QPoint(500, 500)); - - QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup; - parallelAnim->addAnimation(anim1); - parallelAnim->addAnimation(anim2); - parallelAnim->start(); -} -//! [animation-group1] - -//! [animation-group2] -MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) -{ - QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); - QPushButton *clyde = new QPushButton(tr("Clyde"), this); - - QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); - anim1->setDuration(3000); - anim1->setStartValue(QPoint(0, 0)); - anim1->setEndValue(QPoint(100, 250)); - - QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); - anim2->setDuration(3000); - anim2->setStartValue(QPoint(0, 0)); - anim2->setEndValue(QPoint(200, 250)); - - QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup; - sequenceAnim->addAnimation(anim1); - sequenceAnim->addAnimation(anim2); - sequenceAnim->start(); -} -//! [animation-group2] +//! [main] diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp index a429fe20b2d..c00a723a26c 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qsequentialanimationgroup.cpp @@ -1,6 +1,10 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QSequentialAnimationGroup> + +void example(QAbstractAnimation *anim1, QAbstractAnimation *anim2) +{ //! [0] QSequentialAnimationGroup *group = new QSequentialAnimationGroup; @@ -9,3 +13,4 @@ group->start(); //! [0] +} diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp index be7f549f655..be7e51e1b44 100644 --- a/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_animation_qvariantanimation.cpp @@ -1,14 +1,22 @@ // Copyright (C) 2018 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QVariantAnimation> +#include <QColor> + //! [0] - QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress) - { - ... - return QColor(...); - } - ... +QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress) +{ + // ... + return QColor(/*...*/); +} +// ... +void someFunc() +{ + // ... qRegisterAnimationInterpolator<QColor>(myColorInterpolator); + // ... +} //! [0] //! [1] diff --git a/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp index 4cba70e62d4..56a0532ac21 100644 --- a/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp @@ -1,6 +1,10 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QThreadPool> +#include <QRunnable> +#include <QDebug> + //! [0] class HelloWorldTask : public QRunnable { @@ -10,7 +14,12 @@ class HelloWorldTask : public QRunnable } }; -HelloWorldTask *hello = new HelloWorldTask(); -// QThreadPool takes ownership and deletes 'hello' automatically -QThreadPool::globalInstance()->start(hello); +int main() +{ + //... + HelloWorldTask *hello = new HelloWorldTask(); + // QThreadPool takes ownership and deletes 'hello' automatically + QThreadPool::globalInstance()->start(hello); + //... +} //! [0] diff --git a/src/corelib/doc/snippets/eventfilters/CMakeLists.txt b/src/corelib/doc/snippets/eventfilters/CMakeLists.txt index ea381e425a5..7da83cbdf6e 100644 --- a/src/corelib/doc/snippets/eventfilters/CMakeLists.txt +++ b/src/corelib/doc/snippets/eventfilters/CMakeLists.txt @@ -1,17 +1,19 @@ -add_library(snippets_eventfilters OBJECT) +add_library(corelib_snippets_eventfilters OBJECT) -target_link_libraries(snippets_eventfilters PRIVATE +set_target_properties(corelib_snippets_eventfilters PROPERTIES COMPILE_OPTIONS "-w") + +target_link_libraries(corelib_snippets_eventfilters PRIVATE Qt::Core ) -qt_internal_extend_target(snippets_eventfilters CONDITION QT_FEATURE_widgets +qt_internal_extend_target(corelib_snippets_eventfilters CONDITION QT_FEATURE_widgets LIBRARIES Qt::Widgets SOURCE main.cpp ) -qt_internal_extend_target(snippets_eventfilters CONDITION QT_FEATURE_gui +qt_internal_extend_target(corelib_snippets_eventfilters CONDITION QT_FEATURE_gui LIBRARIES Qt::Gui SOURCES diff --git a/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt b/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt index 76bb79951a3..972bf43d9b1 100644 --- a/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt +++ b/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt @@ -2,13 +2,15 @@ if(NOT QT_FEATURE_widgets) return() endif() -add_library(snippets_qmetaobject-invokable OBJECT) +add_library(corelib_snippets_qmetaobject-invokable OBJECT) -target_link_libraries(snippets_qmetaobject-invokable PRIVATE +set_target_properties(corelib_snippets_qmetaobject-invokable PROPERTIES COMPILE_OPTIONS "-w") + +target_link_libraries(corelib_snippets_qmetaobject-invokable PRIVATE Qt::Core ) -qt_internal_extend_target(snippets_qmetaobject-invokable CONDITION QT_FEATURE_widgets +qt_internal_extend_target(corelib_snippets_qmetaobject-invokable CONDITION QT_FEATURE_widgets LIBRARIES Qt::Widgets SOURCES diff --git a/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt b/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt index 0cadf9380b1..369b2e15315 100644 --- a/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt +++ b/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt @@ -2,13 +2,15 @@ if(NOT QT_FEATURE_widgets) return() endif() -add_library(snippets_qmetaobject-revision OBJECT) +add_library(corelib_snippets_qmetaobject-revision OBJECT) -target_link_libraries(snippets_qmetaobject-revision PRIVATE +set_target_properties(corelib_snippets_qmetaobject-revision PROPERTIES COMPILE_OPTIONS "-w") + +target_link_libraries(corelib_snippets_qmetaobject-revision PRIVATE Qt::Core ) -qt_internal_extend_target(snippets_qmetaobject-revision CONDITION QT_FEATURE_widgets +qt_internal_extend_target(corelib_snippets_qmetaobject-revision CONDITION QT_FEATURE_widgets LIBRARIES Qt::Widgets SOURCES diff --git a/src/corelib/doc/snippets/qprocess/CMakeLists.txt b/src/corelib/doc/snippets/qprocess/CMakeLists.txt index 07b66d0b36b..d00e051ed9b 100644 --- a/src/corelib/doc/snippets/qprocess/CMakeLists.txt +++ b/src/corelib/doc/snippets/qprocess/CMakeLists.txt @@ -1,8 +1,12 @@ -add_library(snippets_qprocess OBJECT +set(CMAKE_UNITY_BUILD OFF) + +add_library(corelib_snippets_qprocess OBJECT qprocess-createprocessargumentsmodifier.cpp qprocess-simpleexecution.cpp ) -target_link_libraries(snippets_qprocess PRIVATE +set_target_properties(corelib_snippets_qprocess PROPERTIES COMPILE_OPTIONS "-w") + +target_link_libraries(corelib_snippets_qprocess PRIVATE Qt::Core ) diff --git a/src/corelib/doc/snippets/qsignalmapper/CMakeLists.txt b/src/corelib/doc/snippets/qsignalmapper/CMakeLists.txt deleted file mode 100644 index 086ddbf9c5e..00000000000 --- a/src/corelib/doc/snippets/qsignalmapper/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -if(NOT TARGET Qt::Widgets) - return() -endif() - -add_library(snippets_qsignalmapper OBJECT - buttonwidget.cpp -) - -add_compile_definitions(EXAMPLE_ONE) - -target_link_libraries(snippets_qsignalmapper PRIVATE - Qt::Core -) - -qt_internal_extend_target(snippets_qsignalmapper CONDITION QT_FEATURE_widgets - LIBRARIES - Qt::Widgets -) diff --git a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp index 1f9e53f1385..cdbf83a977d 100644 --- a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp +++ b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp @@ -5,39 +5,40 @@ #include <QtWidgets> -#ifdef EXAMPLE_ONE -//! [0] -ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent) - : QWidget(parent) -{ - signalMapper = new QSignalMapper(this); + //! [OpenCtor] + ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent) + : QWidget(parent) + { + //! [OpenCtor] + { + //![OldNotation] + signalMapper = new QSignalMapper(this); - QGridLayout *gridLayout = new QGridLayout(this); - for (int i = 0; i < texts.size(); ++i) { - QPushButton *button = new QPushButton(texts[i]); - connect(button, &QPushButton::clicked, signalMapper, qOverload<>(&QSignalMapper::map)); -//! [0] //! [1] - signalMapper->setMapping(button, texts[i]); - gridLayout->addWidget(button, i / 3, i % 3); + QGridLayout *gridLayout = new QGridLayout(this); + for (int i = 0; i < texts.size(); ++i) { + QPushButton *button = new QPushButton(texts[i]); + connect(button, &QPushButton::clicked, signalMapper, qOverload<>(&QSignalMapper::map)); + signalMapper->setMapping(button, texts[i]); + gridLayout->addWidget(button, i / 3, i % 3); + } + + connect(signalMapper, &QSignalMapper::mappedString, + this, &ButtonWidget::clicked); + //![OldNotation] + } + + { + //![ModernNotation] + QGridLayout *gridLayout = new QGridLayout(this); + for (int i = 0; i < texts.size(); ++i) { + QString text = texts[i]; + QPushButton *button = new QPushButton(text); + connect(button, &QPushButton::clicked, [this, text] { clicked(text); }); + gridLayout->addWidget(button, i / 3, i % 3); + } + //![ModernNotation] } - connect(signalMapper, &QSignalMapper::mappedString, -//! [1] //! [2] - this, &ButtonWidget::clicked); -} -//! [2] -#else -//! [3] -ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent) - : QWidget(parent) -{ - QGridLayout *gridLayout = new QGridLayout(this); - for (int i = 0; i < texts.size(); ++i) { - QString text = texts[i]; - QPushButton *button = new QPushButton(text); - connect(button, &QPushButton::clicked, [this, text] { clicked(text); }); - gridLayout->addWidget(button, i / 3, i % 3); + //! [CloseBrackets] } -} -//! [3] -#endif + //! [CloseBrackets] diff --git a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.h b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.h index 537c21c9141..cd75628dc2b 100644 --- a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.h +++ b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.h @@ -4,10 +4,8 @@ #ifndef BUTTONWIDGET_H #define BUTTONWIDGET_H -#include <QWidget> +#include <QtWidgets> -class QSignalMapper; -class QString; //! [0] class ButtonWidget : public QWidget diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc index d2e182f4806..ba5976f11eb 100644 --- a/src/corelib/doc/src/animation.qdoc +++ b/src/corelib/doc/src/animation.qdoc @@ -91,7 +91,12 @@ The following example demonstrates how you can animate a QPushButton widget: - \snippet code/src_corelib_animation_qpropertyanimation.cpp 0 + \snippet code/src_corelib_animation_qpropertyanimation.cpp includes + \snippet code/src_corelib_animation_qpropertyanimation.cpp class_decl + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl + \snippet code/src_corelib_animation_qpropertyanimation.cpp first_example + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close + \snippet code/src_corelib_animation_qpropertyanimation.cpp main The example animates the \c pos Qt property of a QPushButton, to move it from the top--left corner of the screen to the end position (250, 250), @@ -174,7 +179,9 @@ path. + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl \snippet code/src_corelib_animation_qpropertyanimation.cpp easing-curve + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close In this example, the animation follows a curve that makes the \c button bounce like a ball. QEasingCurve offers a large collection of curves @@ -199,13 +206,17 @@ The two following examples demonstrate the use of both QSequentialAnimationGroup and QParallelAnimationGroup: + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group1 + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close A parallel group plays more than one animation at the same time. Its \l{QAbstractAnimation::}{start()} function starts all animations that are part of the group. + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group2 + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close As the name suggests, a QSequentialAnimationGroup plays its animations in sequence. It starts the next animation in @@ -225,7 +236,12 @@ independent QPropertyAnimation has the QApplication instance as its parent: - \snippet code/src_corelib_animation_qpropertyanimation.cpp 0 + \snippet code/src_corelib_animation_qpropertyanimation.cpp includes + \snippet code/src_corelib_animation_qpropertyanimation.cpp class_decl + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_impl + \snippet code/src_corelib_animation_qpropertyanimation.cpp first_example + \snippet code/src_corelib_animation_qpropertyanimation.cpp ctor_close + \snippet code/src_corelib_animation_qpropertyanimation.cpp main \note You can also control the animation's lifespan by choosing a \l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting it. diff --git a/src/corelib/doc/src/objectmodel/objecttrees.qdoc b/src/corelib/doc/src/objectmodel/objecttrees.qdoc index 8939a534d40..25245fd5de8 100644 --- a/src/corelib/doc/src/objectmodel/objecttrees.qdoc +++ b/src/corelib/doc/src/objectmodel/objecttrees.qdoc @@ -59,7 +59,9 @@ behavior applies. Normally, the order of destruction still doesn't present a problem. Consider the following snippet: - \snippet code/doc_src_objecttrees.cpp 0 + \snippet code/doc_src_objecttrees.cpp open + \snippet code/doc_src_objecttrees.cpp example1 + \snippet code/doc_src_objecttrees.cpp close The parent, \c window, and the child, \c quit, are both \l {QObject} {QObjects} because QPushButton inherits QWidget, and QWidget inherits @@ -73,7 +75,9 @@ But now consider what happens if we swap the order of construction, as shown in this second snippet: - \snippet code/doc_src_objecttrees.cpp 1 + \snippet code/doc_src_objecttrees.cpp open + \snippet code/doc_src_objecttrees.cpp example2 + \snippet code/doc_src_objecttrees.cpp close In this case, the order of destruction causes a problem. The parent's destructor is called first because it was created last. It then calls diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index c645e57bdb6..8c22483fbfe 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2017 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qplatformdefs.h" #include "qdebug.h" diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index c115a6aee98..11546d87d9c 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QFILE_H #define QFILE_H diff --git a/src/corelib/io/qfile_p.h b/src/corelib/io/qfile_p.h index 126da28b0f9..a50fe575f8e 100644 --- a/src/corelib/io/qfile_p.h +++ b/src/corelib/io/qfile_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QFILE_P_H #define QFILE_P_H diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 6f995fe082e..5a0be1d895e 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -893,6 +893,12 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM { Q_CHECK_FILE_NAME(entry, false); + // Detection of WasDeletedAttribute is imperfect: in general, if we can + // successfully stat() or access() a file, it hasn't been deleted (though + // there are exceptions, like /proc/XXX/fd/ entries on Linux). So we have + // to restore this flag in case we fail to stat() anything. + auto hadBeenDeleted = data.entryFlags & QFileSystemMetaData::WasDeletedAttribute; + #if defined(Q_OS_DARWIN) if (what & (QFileSystemMetaData::BundleType | QFileSystemMetaData::CaseSensitive)) { if (!data.hasFlags(QFileSystemMetaData::DirectoryType)) @@ -1103,6 +1109,11 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM if (entryErrno != 0) { what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink data.clearFlags(what); + + // see comment at the top + data.entryFlags |= hadBeenDeleted; + data.knownFlagsMask |= hadBeenDeleted; + return false; } return true; diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 0886f63b810..9c1bb45dd2d 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -1309,8 +1309,11 @@ QByteArray QIODevice::readAll() The newline character ('\\n') is included in the buffer. If a newline is not encountered before maxSize - 1 bytes are read, a - newline will not be inserted into the buffer. On windows newline - characters are replaced with '\\n'. + newline will not be inserted into the buffer. + + \note Newline translation(e.g., converting \r to \n) is performed + only when the device is opened for reading with QIODevice::Text + flag. Note that on sequential devices, data may not be immediately available, which may result in a partial line being returned. By calling the diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp index 91f168f20f6..a7d101dc124 100644 --- a/src/corelib/io/qsavefile.cpp +++ b/src/corelib/io/qsavefile.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2012 David Faure <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:guaranteed-behavior #include "qsavefile.h" diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h index bf0a91bae74..5e8cffe7c38 100644 --- a/src/corelib/io/qsavefile.h +++ b/src/corelib/io/qsavefile.h @@ -1,5 +1,6 @@ // Copyright (C) 2012 David Faure <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:header-decls-only #ifndef QSAVEFILE_H #define QSAVEFILE_H diff --git a/src/corelib/io/qsavefile_p.h b/src/corelib/io/qsavefile_p.h index 50ecdad2daf..e1dcc0abe23 100644 --- a/src/corelib/io/qsavefile_p.h +++ b/src/corelib/io/qsavefile_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 David Faure <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:header-decls-only #ifndef QSAVEFILE_P_H #define QSAVEFILE_P_H diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index c1f01267949..038db4d857e 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2017 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qtemporaryfile.h" @@ -881,6 +882,11 @@ void QTemporaryFile::setFileTemplate(const QString &name) be used for a similar purpose too, particularly if the destination file is not temporary. + \note Calling rename() does not disable autoRemove. If you want the renamed + file to persist, you must call setAutoRemove and set it to \c false after + calling rename(). Otherwise, the file will be deleted when the QTemporaryFile + object is destroyed. + \sa QSaveFile, QSaveFile::commit(), QFile::rename() */ bool QTemporaryFile::rename(const QString &newName) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 565ce04c6ce..a4fbf69da8b 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3660,17 +3660,29 @@ QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode) */ size_t qHash(const QUrl &url, size_t seed) noexcept { + QtPrivate::QHashCombineWithSeed hasher(seed); + + // non-commutative, we must hash the port first if (!url.d) - return qHash(-1, seed); // the hash of an unset port (-1) - - return qHash(url.d->scheme) ^ - qHash(url.d->userName) ^ - qHash(url.d->password) ^ - qHash(url.d->host) ^ - qHash(url.d->port, seed) ^ - qHash(url.d->path) ^ - qHash(url.d->query) ^ - qHash(url.d->fragment); + return hasher(0, -1); + size_t state = hasher(0, url.d->port); + + if (url.d->hasScheme()) + state = hasher(state, url.d->scheme); + if (url.d->hasUserInfo()) { + // see presentSections(), appendUserName(), etc. + state = hasher(state, url.d->userName); + state = hasher(state, url.d->password); + } + if (url.d->hasHost() || url.d->isLocalFile()) // for XDG compatibility + state = hasher(state, url.d->host); + if (url.d->hasPath()) + state = hasher(state, url.d->path); + if (url.d->hasQuery()) + state = hasher(state, url.d->query); + if (url.d->hasFragment()) + state = hasher(state, url.d->fragment); + return state; } static QUrl adjustFtpPath(QUrl url) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 3b92c5f48f2..1b711ba16bd 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -2552,8 +2552,9 @@ static QStringList winCmdArgs() Otherwise, the arguments() are constructed from the return value of \l{https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getcommandlinea}{GetCommandLine()}. - As a result of this, the string given by arguments().at(0) might not be - the program name on Windows, depending on how the application was started. + As a result of this, the string given by arguments().at(0) + might not be the exact program used to start the application + on Windows. \sa applicationFilePath(), QCommandLineParser */ diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 2356611a5cf..de5f27f9619 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -3149,6 +3149,20 @@ bool QMetaMethod::invokeOnGadget(void *gadget, representation. The scope() function returns the class scope this enumerator was declared in. + To use QMetaEnum functionality, register the enumerator within the meta-object + system using the Q_ENUM macro. + + \code + enum AppleType { + Big, + Small + }; + Q_ENUM(AppleType) + + QMetaEnum metaEnum = QMetaEnum::fromType<ModelApple::AppleType>(); + qDebug() << metaEnum.valueToKey(ModelApple::Big); + \endcode + \sa QMetaObject, QMetaMethod, QMetaProperty */ diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 60bcdedba13..445009ea000 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -2080,6 +2080,17 @@ bool QMetaPropertyBuilder::isBindable() const else return false; } +/*! + Returns \c true if the property is required. + The default is \c false. + */ +bool QMetaPropertyBuilder::isRequired() const +{ + if (auto d = d_func()) + return d->flag(Required); + else + return false; +} /*! Sets this property to readable if \a value is true. @@ -2236,6 +2247,15 @@ void QMetaPropertyBuilder::setBindable(bool value) } /*! + Sets the\c REQUIRED flag on this property to \a value + */ +void QMetaPropertyBuilder::setRequired(bool value) +{ + if (auto d = d_func()) + d->setFlag(Required, value); +} + +/*! Returns the revision of this property. \sa setRevision() diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h index cf64e51c30c..36cd08d908c 100644 --- a/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -216,6 +216,7 @@ public: bool isFinal() const; bool isAlias() const; bool isBindable() const; + bool isRequired() const; void setReadable(bool value); void setWritable(bool value); @@ -230,6 +231,7 @@ public: void setFinal(bool value); void setAlias(bool value); void setBindable(bool value); + void setRequired(bool value); int revision() const; void setRevision(int revision); diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 1242a40f185..45c947004f5 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -981,12 +981,6 @@ void QMetaType::unregisterMetaType(QMetaType type) than the QMetaType \a rhs, otherwise returns \c false. */ -/*! \internal */ -bool QMetaTypeModuleHelper::convert(const void *, int, void *, int) const -{ - return false; -} - static constexpr auto createStaticTypeToIdMap() { #define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \ @@ -1049,8 +1043,8 @@ static bool qIntegerConversionFromFPHelper(From from, To *to) return true; } -// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class -static constexpr struct : QMetaTypeModuleHelper +namespace { +struct QCoreVariantHelper : QMetaTypeModuleHelper { template<typename T, typename LiteralWrapper = std::conditional_t<std::is_same_v<T, QString>, QLatin1StringView, const char *>> @@ -1060,7 +1054,8 @@ static constexpr struct : QMetaTypeModuleHelper return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false")); } - const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { + static const QtPrivate::QMetaTypeInterface *interfaceForType(int type) + { switch (type) { QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_CONVERT_ID_TO_TYPE) QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE) @@ -1072,11 +1067,14 @@ static constexpr struct : QMetaTypeModuleHelper } } -#ifndef QT_BOOTSTRAPPED - bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override + static bool convert(const void *from, int fromTypeId, void *to, int toTypeId) { Q_ASSERT(fromTypeId != toTypeId); +#ifdef QT_BOOTSTRAPPED + Q_UNUSED(from); + Q_UNUSED(to); +#else // canConvert calls with two nullptr bool onlyCheck = (from == nullptr && to == nullptr); @@ -1747,26 +1745,28 @@ QT_WARNING_DISABLE_CLANG("-Wtautological-compare") QT_WARNING_POP } +#endif // !QT_BOOTSTRAPPED return false; } -#endif // !QT_BOOTSTRAPPED -} metatypeHelper = {}; +}; +} // unnamed namespace -Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper = nullptr; -Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper = nullptr; +Q_CONSTINIT Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeGuiHelper = {}; +Q_CONSTINIT Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeWidgetsHelper = {}; -static const QMetaTypeModuleHelper *qModuleHelperForType(int type) +#ifndef QT_BOOTSTRAPPED +static bool tryConvertBuiltinTypes(const void *from, int fromTypeId, void *to, int toTypeId) { + int type = qMax(fromTypeId, toTypeId); if (type <= QMetaType::LastCoreType) - return &metatypeHelper; + return QCoreVariantHelper::convert(from, fromTypeId, to, toTypeId); if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType) - return qMetaTypeGuiHelper; + return qMetaTypeGuiHelper.convert(from, fromTypeId, to, toTypeId); else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType) - return qMetaTypeWidgetsHelper; - return nullptr; + return qMetaTypeWidgetsHelper.convert(from, fromTypeId, to, toTypeId); + return false; } -#ifndef QT_BOOTSTRAPPED template<typename T, typename Key> class QMetaTypeFunctionRegistry { @@ -2471,10 +2471,8 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, int fromTypeId = fromType.id(); int toTypeId = toType.id(); - if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) { - if (moduleHelper->convert(from, fromTypeId, to, toTypeId)) - return true; - } + if (tryConvertBuiltinTypes(from, fromTypeId, to, toTypeId)) + return true; const auto f = customTypesConversionRegistry()->function({fromTypeId, toTypeId}); if (f) return (*f)(from, to); @@ -2676,10 +2674,9 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType) if (fromTypeId == toTypeId) return true; - if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) { - if (moduleHelper->convert(nullptr, fromTypeId, nullptr, toTypeId)) - return true; - } + if (tryConvertBuiltinTypes(nullptr, fromTypeId, nullptr, toTypeId)) + return true; + const ConverterFunction * const f = customTypesConversionRegistry()->function(std::make_pair(fromTypeId, toTypeId)); if (f) @@ -2879,8 +2876,12 @@ void QMetaType::registerNormalizedTypedef(const NS(QByteArray) & normalizedTypeN static const QtPrivate::QMetaTypeInterface *interfaceForStaticType(int typeId) { Q_ASSERT(typeId < QMetaType::User); - if (auto moduleHelper = qModuleHelperForType(typeId)) - return moduleHelper->interfaceForType(typeId); + if (typeId <= QMetaType::LastCoreType) + return QCoreVariantHelper::interfaceForType(typeId); + if (typeId >= QMetaType::FirstGuiType && typeId <= QMetaType::LastGuiType) + return qMetaTypeGuiHelper.interfaceForType(typeId); + if (typeId >= QMetaType::FirstWidgetsType && typeId <= QMetaType::LastWidgetsType) + return qMetaTypeWidgetsHelper.interfaceForType(typeId); return nullptr; } @@ -2909,40 +2910,18 @@ bool QMetaType::isRegistered(int type) return interfaceForTypeNoWarning(type) != nullptr; } -namespace { -enum NormalizeTypeMode { - DontNormalizeType, - TryNormalizeType -}; -} -template <NormalizeTypeMode tryNormalizedType> static inline -const QtPrivate::QMetaTypeInterface *qMetaTypeTypeImpl(QByteArrayView name) +static const QtPrivate::QMetaTypeInterface *findMetaTypeByName(QByteArrayView name) { - if (name.isEmpty()) - return nullptr; - + Q_PRE(!name.isEmpty()); int type = qMetaTypeStaticType(name); if (type != QMetaType::UnknownType) { return interfaceForStaticType(type); #ifndef QT_BOOTSTRAPPED - } else { - QReadLocker locker(&customTypeRegistry()->lock); + } else if (customTypeRegistry.exists()) { + QReadLocker locker(&customTypeRegistry->lock); auto it = customTypeRegistry->aliases.constFind(name); if (it != customTypeRegistry->aliases.constEnd()) return it.value().data(); - -#ifndef QT_NO_QOBJECT - if (tryNormalizedType) { - const char *typeName = name.constData(); - const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); - type = qMetaTypeStaticType(normalizedTypeName); - if (type == QMetaType::UnknownType) { - return customTypeRegistry->aliases.value(normalizedTypeName).data(); - } else { - return interfaceForStaticType(type); - } - } -#endif #endif } return nullptr; @@ -2969,7 +2948,9 @@ const QtPrivate::QMetaTypeInterface *qMetaTypeTypeImpl(QByteArrayView name) */ int qMetaTypeTypeInternal(QByteArrayView name) { - const QtPrivate::QMetaTypeInterface *iface = qMetaTypeTypeImpl<DontNormalizeType>(name); + const QtPrivate::QMetaTypeInterface *iface = nullptr; + if (!name.isEmpty()) + iface = findMetaTypeByName(name); return iface ? iface->typeId.loadRelaxed() : QMetaType::UnknownType; } @@ -3138,7 +3119,20 @@ QMetaType QMetaType::underlyingType() const */ QMetaType QMetaType::fromName(QByteArrayView typeName) { - return QMetaType(qMetaTypeTypeImpl<TryNormalizeType>(typeName)); + if (typeName.isEmpty()) + return QMetaType(); + + const QtPrivate::QMetaTypeInterface *iface = findMetaTypeByName(typeName); + if (iface) + return QMetaType(iface); + +#if !defined(QT_NO_QOBJECT) + const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName.constData()); + if (normalizedTypeName != typeName) + iface = findMetaTypeByName(normalizedTypeName); +#endif + + return QMetaType(iface); } /*! diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index c05bce5fc8f..b39e1de0be2 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -40,25 +40,29 @@ QT_BEGIN_NAMESPACE assign_and_return \ } -class Q_CORE_EXPORT QMetaTypeModuleHelper +struct QMetaTypeModuleHelper { - Q_DISABLE_COPY_MOVE(QMetaTypeModuleHelper) -protected: - QMetaTypeModuleHelper() = default; - ~QMetaTypeModuleHelper() = default; -public: - Q_WEAK_OVERLOAD // prevent it from entering the ABI and rendering constexpr useless static constexpr auto makePair(int from, int to) -> quint64 { return (quint64(from) << 32) + quint64(to); } - virtual const QtPrivate::QMetaTypeInterface *interfaceForType(int) const = 0; - virtual bool convert(const void *, int, void *, int) const; + static const QtPrivate::QMetaTypeInterface *interfaceForType_dummy(int) + { + return nullptr; + } + + static bool convert_dummy(const void *, int, void *, int) + { + return false; + } + + decltype(&interfaceForType_dummy) interfaceForType = &interfaceForType_dummy; + decltype(&convert_dummy) convert = &convert_dummy; }; -extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper; -extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper; +extern Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeGuiHelper; +extern Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeWidgetsHelper; namespace QtMetaTypePrivate { template<typename T> diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp index 65d766db4a9..96e909d1be7 100644 --- a/src/corelib/kernel/qsignalmapper.cpp +++ b/src/corelib/kernel/qsignalmapper.cpp @@ -74,9 +74,9 @@ public: The only function that we need to implement is the constructor: - \snippet qsignalmapper/buttonwidget.cpp 0 - \snippet qsignalmapper/buttonwidget.cpp 1 - \snippet qsignalmapper/buttonwidget.cpp 2 + \snippet qsignalmapper/buttonwidget.cpp OpenCtor + \snippet qsignalmapper/buttonwidget.cpp OldNotation + \snippet qsignalmapper/buttonwidget.cpp CloseBrackets A list of texts is passed to the constructor. A signal mapper is constructed and for each text in the list a QPushButton is @@ -92,7 +92,9 @@ public: slots. The example above can be rewritten simpler without QSignalMapper by connecting to a lambda function. - \snippet qsignalmapper/buttonwidget.cpp 3 + \snippet qsignalmapper/buttonwidget.cpp OpenCtor + \snippet qsignalmapper/buttonwidget.cpp ModernNotation + \snippet qsignalmapper/buttonwidget.cpp CloseBrackets \sa QObject, QButtonGroup, QActionGroup */ diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 6b68cb7a513..c8348aba16a 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -39,6 +39,8 @@ #include <vector> #include <memory> +#include <QtCore/qmutex.h> + QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcTranslator, "qt.core.qtranslator") @@ -259,6 +261,8 @@ class QTranslatorPrivate : public QObjectPrivate public: enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96, Language = 0xa7 }; + mutable QMutex lock; + QTranslatorPrivate() : #if defined(QT_USE_MMAP) used_mmap(0), @@ -463,6 +467,7 @@ bool QTranslator::load(const QString & filename, const QString & directory, const QString & suffix) { Q_D(QTranslator); + QMutexLocker locker(&d->lock); d->clear(); QString prefix; @@ -738,6 +743,7 @@ bool QTranslator::load(const QLocale & locale, const QString & suffix) { Q_D(QTranslator); + QMutexLocker locker(&d->lock); d->clear(); return d->load_translation(locale, filename, prefix, directory, suffix); } @@ -757,6 +763,7 @@ bool QTranslator::load(const QLocale & locale, bool QTranslator::load(const uchar *data, int len, const QString &directory) { Q_D(QTranslator); + QMutexLocker locker(&d->lock); d->clear(); if (!data || len < MagicLength || memcmp(data, magic, MagicLength)) @@ -1065,6 +1072,8 @@ void QTranslatorPrivate::clear() } /*! + \threadsafe + Returns the translation for the key (\a context, \a sourceText, \a disambiguation). If none is found, also tries (\a context, \a sourceText, ""). If that still fails, returns a null string. @@ -1086,7 +1095,14 @@ QString QTranslator::translate(const char *context, const char *sourceText, cons int n) const { Q_D(const QTranslator); - return d->do_translate(context, sourceText, disambiguation, n); + + // Return early to avoid a deadlock in case translate() is called + // from a code path triggered by QTranslator::load() + if (!d->lock.tryLock()) + return QString(); + QString result = d->do_translate(context, sourceText, disambiguation, n); + d->lock.unlock(); + return result; } /*! diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 31f5869c9d9..e9d3ffb9ae3 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -332,7 +332,16 @@ public: inline void swap(QVariant &other) noexcept { std::swap(d, other.d); } int userType() const { return typeId(); } - int typeId() const { return metaType().id(); } + int typeId() const + { + // QVariant types are always registered (see fromMetaType()) + const QtPrivate::QMetaTypeInterface *mt = metaType().iface(); + if (!mt) + return 0; + int id = mt->typeId.loadRelaxed(); + // Q_ASSUME(id > 0); + return id; + } const char *typeName() const; QMetaType metaType() const; diff --git a/src/corelib/platform/windows/qt_winrtbase_p.h b/src/corelib/platform/windows/qt_winrtbase_p.h index fb7366f93de..79c2bdf6b1c 100644 --- a/src/corelib/platform/windows/qt_winrtbase_p.h +++ b/src/corelib/platform/windows/qt_winrtbase_p.h @@ -18,6 +18,7 @@ #include <QtCore/qglobal.h> #if QT_CONFIG(cpp_winrt) +# include <guiddef.h> // required by clang-cl: https://github.com/microsoft/cppwinrt/issues/1179 # include <winrt/base.h> # include <QtCore/private/qfactorycacheregistration_p.h> // Workaround for Windows SDK bug. diff --git a/src/corelib/thread/qatomicwait.cpp b/src/corelib/thread/qatomicwait.cpp index 3d70333ca7b..25ca771643b 100644 --- a/src/corelib/thread/qatomicwait.cpp +++ b/src/corelib/thread/qatomicwait.cpp @@ -4,6 +4,7 @@ #include "qatomicwait_p.h" #include <qendian.h> +#include "qfutex_p.h" #include "qwaitcondition_p.h" #include <array> @@ -96,8 +97,21 @@ struct QAtomicWaitLocks }; } // unnamed namespace +static inline void checkFutexUse() +{ +#if !defined(QATOMICWAIT_USE_FALLBACK) + if (QtFutex::futexAvailable()) { + // This will disable the code and data on systems where futexes are + // always available (currently: FreeBSD, Linux, Windows). + qFatal("Implementation should have used futex!"); + } +#endif +} + static QAtomicWaitLocks &atomicLocks() noexcept { + checkFutexUse(); + static QAtomicWaitLocks global {}; return global; } diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index bd3b269c0b7..832d87332b0 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -120,8 +120,8 @@ void QBasicMutex::destroyInternal(void *ptr) Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it. - Calling this function multiple times on the same mutex from the - same thread will cause a \e dead-lock. + If the mutex was already locked by the current thread, this call will + never return, causing a \e dead-lock. \sa unlock() */ @@ -140,9 +140,6 @@ void QBasicMutex::destroyInternal(void *ptr) If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. - Calling this function multiple times on the same mutex from the - same thread will cause a \e dead-lock. - \sa lock(), unlock() */ @@ -157,9 +154,6 @@ void QBasicMutex::destroyInternal(void *ptr) If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. - Calling this function multiple times on the same mutex from the - same thread will cause a \e dead-lock. - \sa lock(), unlock() */ @@ -172,9 +166,6 @@ void QBasicMutex::destroyInternal(void *ptr) If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. - Calling this function multiple times on the same mutex from the - same thread will cause a \e dead-lock. - \sa lock(), unlock() */ @@ -202,9 +193,6 @@ void QBasicMutex::destroyInternal(void *ptr) If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. - Calling this function multiple times on the same mutex from the - same thread will cause a \e dead-lock. - \sa lock(), unlock() */ @@ -222,9 +210,6 @@ void QBasicMutex::destroyInternal(void *ptr) If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it. - Calling this function multiple times on the same mutex from the - same thread will cause a \e dead-lock. - \sa lock(), unlock() */ diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 71e183e646e..38d1091ac1f 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -39,7 +39,7 @@ struct QArrayData }; Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) - QBasicAtomicInt m_ref; + QBasicAtomicInt ref_; ArrayOptions flags; qsizetype alloc; @@ -56,19 +56,19 @@ struct QArrayData /// Returns true if sharing took place bool ref() noexcept { - m_ref.ref(); + ref_.ref(); return true; } /// Returns false if deallocation is necessary bool deref() noexcept { - return m_ref.deref(); + return ref_.deref(); } bool isShared() const noexcept { - return m_ref.loadRelaxed() != 1; + return ref_.loadRelaxed() != 1; } // Returns true if a detach is necessary before modifying the data @@ -76,7 +76,7 @@ struct QArrayData // detaching is necessary, you should be in a non-const function already bool needsDetach() noexcept { - return m_ref.loadRelaxed() > 1; + return ref_.loadRelaxed() > 1; } qsizetype detachCapacity(qsizetype newSize) const noexcept diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 419585b0260..c20abd12c23 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -82,7 +82,7 @@ public: void destroyAll() noexcept // Call from destructors, ONLY! { Q_ASSERT(this->d); - Q_ASSERT(this->d->m_ref.loadRelaxed() == 0); + Q_ASSERT(this->d->ref_.loadRelaxed() == 0); // As this is to be called only from destructor, it doesn't need to be // exception safe; size not updated. @@ -345,7 +345,7 @@ public: // As this is to be called only from destructor, it doesn't need to be // exception safe; size not updated. - Q_ASSERT(this->d->m_ref.loadRelaxed() == 0); + Q_ASSERT(this->d->ref_.loadRelaxed() == 0); std::destroy(this->begin(), this->end()); } diff --git a/src/corelib/tools/qatomicscopedvaluerollback.h b/src/corelib/tools/qatomicscopedvaluerollback.h index 8f653acba5e..929a2e2d466 100644 --- a/src/corelib/tools/qatomicscopedvaluerollback.h +++ b/src/corelib/tools/qatomicscopedvaluerollback.h @@ -11,6 +11,7 @@ #include <QtCore/qtconfigmacros.h> #include <atomic> +#include <type_traits> QT_BEGIN_NAMESPACE @@ -122,6 +123,33 @@ template <typename T> QAtomicScopedValueRollback(QBasicAtomicPointer<T> &, std::memory_order) -> QAtomicScopedValueRollback<T*>; +template <typename T, typename V, + std::enable_if_t<std::is_convertible_v<V, T>, bool> = true> +QAtomicScopedValueRollback(std::atomic<T>&, V) + -> QAtomicScopedValueRollback<T>; +template <typename T, typename V, + std::enable_if_t<std::is_convertible_v<V, T>, bool> = true> +QAtomicScopedValueRollback(std::atomic<T>&, V, std::memory_order) + -> QAtomicScopedValueRollback<T>; + +template <typename T, typename V, + std::enable_if_t<std::is_convertible_v<V, T>, bool> = true> +QAtomicScopedValueRollback(QBasicAtomicInteger<T>&, V) + -> QAtomicScopedValueRollback<T>; +template <typename T, typename V, + std::enable_if_t<std::is_convertible_v<V, T>, bool> = true> +QAtomicScopedValueRollback(QBasicAtomicInteger<T>&, V, std::memory_order) + -> QAtomicScopedValueRollback<T>; + +template <typename T, typename V, + std::enable_if_t<std::is_convertible_v<V, T*>, bool> = true> +QAtomicScopedValueRollback(QBasicAtomicPointer<T>&, V) + -> QAtomicScopedValueRollback<T*>; +template <typename T, typename V, + std::enable_if_t<std::is_convertible_v<V, T*>, bool> = true> +QAtomicScopedValueRollback(QBasicAtomicPointer<T>&, V, std::memory_order) + -> QAtomicScopedValueRollback<T*>; + QT_END_NAMESPACE #endif // QATOMICASCOPEDVALUEROLLBACK_H diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h index cc12fb9c8d0..ecefd1f55df 100644 --- a/src/corelib/tools/qfreelist_p.h +++ b/src/corelib/tools/qfreelist_p.h @@ -199,27 +199,27 @@ inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, Constant template <typename T, typename ConstantsType> inline int QFreeList<T, ConstantsType>::next() { - int id, newid, at; - ElementType *v; + int newid; + int id = _next.loadAcquire(); do { - id = _next.loadAcquire(); - - at = id & ConstantsType::IndexMask; + int at = id & ConstantsType::IndexMask; const int block = blockfor(at); - v = _v[block].loadAcquire(); + ElementType *v = _v[block].loadAcquire(); if (!v) { - v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]); - if (!_v[block].testAndSetRelease(nullptr, v)) { + ElementType* const alloced = allocate((id & ConstantsType::IndexMask) - at, + ConstantsType::Sizes[block]); + if (_v[block].testAndSetRelease(nullptr, alloced, v)) { + v = alloced; + } else { // race with another thread lost - delete[] v; - v = _v[block].loadAcquire(); + delete[] alloced; Q_ASSERT(v != nullptr); } } newid = v[at].next.loadRelaxed() | (id & ~ConstantsType::IndexMask); - } while (!_next.testAndSetRelease(id, newid)); + } while (!_next.testAndSetOrdered(id, newid, id)); // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", // id & ConstantsType::IndexMask, // newid & ConstantsType::IndexMask, diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index cbe217db11e..3e44f5f3442 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -298,19 +298,32 @@ bool qHashEquals(const T1 &a, const T2 &b) } namespace QtPrivate { -template <typename Mixer> struct QHashCombiner : private Mixer +template <typename Mixer> struct QHashCombinerWithSeed : private Mixer { - using result_type = typename Mixer::result_type ; + using result_type = typename Mixer::result_type; + size_t seed; + constexpr QHashCombinerWithSeed(result_type s) noexcept : seed(s) {} + + template <typename T> + constexpr result_type operator()(result_type result, const T &t) const + noexcept(noexcept(qHash(t, seed))) + { + return Mixer::operator()(result, qHash(t, seed)); + } +}; #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) - // Qt 6.x didn't use to pass the seed; bootstrap has no seed +// Earlier Qt 6.x versions of qHashMulti() failed to pass the seed as the seed +// argument of qHash(), so this class exists for compatibility with user and +// inline code that relies on the old behavior. For Qt 7, we'll replace with +// the above version, except for the bootstrapped tools (which have no seed). +template <typename Mixer> struct QHashCombiner : private Mixer +{ + using result_type = typename Mixer::result_type; + static constexpr size_t seed = 0; constexpr QHashCombiner(result_type) noexcept {} Q_DECL_DEPRECATED_X("pass the seed argument") constexpr QHashCombiner() noexcept {} -#else - size_t seed; - constexpr QHashCombiner(result_type s) : seed(s) noexcept {} -#endif template <typename T> constexpr result_type operator()(result_type result, const T &t) const @@ -319,6 +332,9 @@ template <typename Mixer> struct QHashCombiner : private Mixer return Mixer::operator()(result, qHash(t, seed)); } }; +#else +template <typename Mixer> using QHashCombiner = QHashCombinerWithSeed<Mixer>; +#endif struct QHashCombineMixer { @@ -330,6 +346,7 @@ struct QHashCombineMixer } }; using QHashCombine = QHashCombiner<QHashCombineMixer>; +using QHashCombineWithSeed = QHashCombinerWithSeed<QHashCombineMixer>; struct QHashCombineCommutativeMixer : std::plus<size_t> { @@ -341,6 +358,7 @@ struct QHashCombineCommutativeMixer : std::plus<size_t> typedef size_t result_type; }; using QHashCombineCommutative = QHashCombiner<QHashCombineCommutativeMixer>; +using QHashCombineCommutativeWithSeed = QHashCombinerWithSeed<QHashCombineCommutativeMixer>; template <typename... T> using QHashMultiReturnType = decltype( diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index a9d334e28f3..e0c0110b794 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -592,7 +592,10 @@ class QWeakPointer { typedef QtSharedPointer::ExternalRefCountData Data; template <typename X> - using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type; + using IfCompatible = std::enable_if_t<std::conjunction_v< + std::negation<std::is_same<T, X>>, // don't make accidental copy/move SMFs + std::is_convertible<X*, T*> + >, bool>; template <typename X> using IfVirtualBase = typename std::enable_if<qxp::is_virtual_base_of_v<T, X>, bool>::type; @@ -768,6 +771,11 @@ private: { return *this = QWeakPointer<T>(ptr, true); } #ifndef QT_NO_QOBJECT + Q_NODISCARD_CTOR + QWeakPointer(T *ptr, bool) + : d{ptr ? Data::getAndRef(ptr) : nullptr}, value{ptr} + { } + template <class X, IfCompatible<X> = true> Q_NODISCARD_CTOR inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr) diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index c6462dfed7b..6da0c4d387b 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -52,14 +52,13 @@ QT_BEGIN_NAMESPACE namespace { - -// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class struct QVariantGuiHelper : QMetaTypeModuleHelper { #define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \ QT_METATYPE_INTERFACE_INIT(RealName), - const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { + static const QtPrivate::QMetaTypeInterface *interfaceForType(int type) + { switch (type) { QT_FOR_EACH_STATIC_GUI_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE) default: return nullptr; @@ -67,7 +66,7 @@ struct QVariantGuiHelper : QMetaTypeModuleHelper } #undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES - bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override + static bool convert(const void *from, int fromTypeId, void *to, int toTypeId) { Q_ASSERT(fromTypeId != toTypeId); @@ -133,14 +132,14 @@ struct QVariantGuiHelper : QMetaTypeModuleHelper return false; } }; - -static constexpr QVariantGuiHelper qVariantGuiHelper; - } // namespace used to hide QVariant handler void qRegisterGuiVariant() { - qMetaTypeGuiHelper = &qVariantGuiHelper; + qMetaTypeGuiHelper = QMetaTypeModuleHelper{ + &QVariantGuiHelper::interfaceForType, + &QVariantGuiHelper::convert, + }; } Q_CONSTRUCTOR_FUNCTION(qRegisterGuiVariant) diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index afe6de35305..caf4cb7fe5b 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -34,6 +34,12 @@ QT_BEGIN_NAMESPACE \note Both physical and logical DPI are expressed in device-independent dots. Multiply by QScreen::devicePixelRatio() to get device-dependent density. + To obtain a QScreen object, use QGuiApplication::primaryScreen() for the + primary screen, or QGuiApplication::screens() to get a list of all screens. + + \sa QGuiApplication::primaryScreen() + \sa QGuiApplication::screens() + \inmodule QtGui */ diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp index ca62798ddfd..dfcea928fd8 100644 --- a/src/gui/kernel/qtestsupport_gui.cpp +++ b/src/gui/kernel/qtestsupport_gui.cpp @@ -24,8 +24,19 @@ QT_BEGIN_NAMESPACE /*! \since 5.0 + \overload - Returns \c true, if \a window is active within \a timeout milliseconds. Otherwise returns \c false. + The \a timeout is in milliseconds. +*/ +bool QTest::qWaitForWindowActive(QWindow *window, int timeout) +{ + return qWaitForWindowActive(window, QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer}); +} + +/*! + \since 6.10 + + Returns \c true, if \a window is active within \a timeout. Otherwise returns \c false. The method is useful in tests that call QWindow::show() and rely on the window actually being active (i.e. being visible and having focus) before proceeding. @@ -38,7 +49,7 @@ QT_BEGIN_NAMESPACE \sa qWaitForWindowExposed(), qWaitForWindowFocused(), QWindow::isActive() */ -Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout) +bool QTest::qWaitForWindowActive(QWindow *window, QDeadlineTimer timeout) { if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) { qWarning() << "qWaitForWindowActive was called on a platform that doesn't support window" @@ -52,6 +63,17 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout) } /*! + \since 6.10 + \overload + + This function uses the default timeout of 5 seconds. +*/ +bool QTest::qWaitForWindowActive(QWindow *window) +{ + return qWaitForWindowActive(window, Internal::defaultTryTimeout); +} + +/*! \since 6.7 Returns \c true, if \a window is the focus window within \a timeout. Otherwise returns \c false. @@ -73,9 +95,31 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowFocused(QWindow *window, QDeadlineTimer t } /*! + \since 6.10 + \overload + + This function uses the default timeout of 5 seconds. +*/ +bool QTest::qWaitForWindowFocused(QWindow *window) +{ + return qWaitForWindowFocused(window, Internal::defaultTryTimeout); +} + +/*! \since 5.0 + \overload + + The \a timeout is in milliseconds. +*/ +bool QTest::qWaitForWindowExposed(QWindow *window, int timeout) +{ + return qWaitForWindowExposed(window, std::chrono::milliseconds(timeout)); +} - Returns \c true, if \a window is exposed within \a timeout milliseconds. Otherwise returns \c false. +/*! + \since 6.10 + + Returns \c true, if \a window is exposed within \a timeout. Otherwise returns \c false. The method is useful in tests that call QWindow::show() and rely on the window actually being being visible before proceeding. @@ -86,11 +130,22 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowFocused(QWindow *window, QDeadlineTimer t \sa qWaitForWindowActive(), QWindow::isExposed() */ -Q_GUI_EXPORT bool QTest::qWaitForWindowExposed(QWindow *window, int timeout) +bool QTest::qWaitForWindowExposed(QWindow *window, QDeadlineTimer timeout) { return QTest::qWaitFor([&]() { return window->isExposed(); }, timeout); } +/*! + \since 6.10 + \overload + + This function uses the default timeout of 5 seconds. +*/ +bool QTest::qWaitForWindowExposed(QWindow *window) +{ + return qWaitForWindowExposed(window, Internal::defaultTryTimeout); +} + namespace QTest { QTouchEventSequence::~QTouchEventSequence() diff --git a/src/gui/kernel/qtestsupport_gui.h b/src/gui/kernel/qtestsupport_gui.h index 951d9df1c7c..39278c2f034 100644 --- a/src/gui/kernel/qtestsupport_gui.h +++ b/src/gui/kernel/qtestsupport_gui.h @@ -23,12 +23,16 @@ Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *w, const QPointingDevice *devic namespace QTest { -[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, - int timeout = static_cast<int>(Internal::defaultTryTimeout.count())); -[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *window, - QDeadlineTimer timeout = Internal::defaultTryTimeout); -[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, - int timeout = static_cast<int>(Internal::defaultTryTimeout.count())); +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout); +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, QDeadlineTimer timeout); +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window); + +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *window, QDeadlineTimer timeout); +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *window); + +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout); +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, QDeadlineTimer timeout); +[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window); Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType = QInputDevice::DeviceType::TouchScreen, QInputDevice::Capabilities caps = QInputDevice::Capability::Position); diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp index c1452ca7688..41ab7c97f8c 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor.cpp +++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp @@ -460,11 +460,20 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { if (!rhi) return QPlatformBackingStore::FlushFailed; + // Note, the sourceTransformFactor is different from the sourceDevicePixelRatio, + // as the former may reflect the fact that the region and offset is pre-transformed, + // in which case we don't need to do a full transform here based on the source DPR. + // In the default case where no explicit source transform has been passed, we fall + // back to the source device pixel ratio. + if (!sourceTransformFactor) + sourceTransformFactor = sourceDevicePixelRatio; + Q_ASSERT(textures); // may be empty if there are no render-to-texture widgets at all, but null it cannot be if (!m_rhi) { @@ -508,7 +517,7 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format()); const QSize size = graphicsBuffer->size(); QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format); - toTexture(wrapperImage, rhi, resourceUpdates, scaledRegion(region, sourceDevicePixelRatio, offset), &flags); + toTexture(wrapperImage, rhi, resourceUpdates, scaledRegion(region, sourceTransformFactor, offset), &flags); gotTextureFromGraphicsBuffer = true; graphicsBuffer->unlock(); if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft) @@ -516,7 +525,7 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo } } if (!gotTextureFromGraphicsBuffer) - toTexture(backingStore, rhi, resourceUpdates, scaledRegion(region, sourceDevicePixelRatio, offset), &flags); + toTexture(backingStore, rhi, resourceUpdates, scaledRegion(region, sourceTransformFactor, offset), &flags); ensureResources(resourceUpdates, swapchain->renderPassDescriptor()); @@ -549,7 +558,7 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo // The backingstore is for the entire tlw. In case of native children, offset tells the position // relative to the tlw. The window rect is scaled by the source device pixel ratio to get // the source rect. - const QPoint sourceWindowOffset = scaledOffset(offset, sourceDevicePixelRatio); + const QPoint sourceWindowOffset = scaledOffset(offset, sourceTransformFactor); const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height()); const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin); QMatrix4x4 target; // identity diff --git a/src/gui/painting/qbackingstoredefaultcompositor_p.h b/src/gui/painting/qbackingstoredefaultcompositor_p.h index c5a8ffd328e..cdc9d098099 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor_p.h +++ b/src/gui/painting/qbackingstoredefaultcompositor_p.h @@ -41,7 +41,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground); + bool translucentBackground, + qreal sourceTransformFactor); private: enum UpdateUniformOption { diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index 8bc49f42ab5..72853be6e97 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -35,9 +35,7 @@ BYTE_MUL_AVX2(__m256i &pixelVector, __m256i alphaChannel, __m256i colorMask, __m pixelVectorAG = _mm256_add_epi16(pixelVectorAG, half); pixelVectorRB = _mm256_srli_epi16(pixelVectorRB, 8); - pixelVectorAG = _mm256_andnot_si256(colorMask, pixelVectorAG); - - pixelVector = _mm256_or_si256(pixelVectorAG, pixelVectorRB); + pixelVector = _mm256_blendv_epi8(pixelVectorAG, pixelVectorRB, colorMask); } inline static void Q_DECL_VECTORCALL @@ -55,9 +53,7 @@ BYTE_MUL_RGB64_AVX2(__m256i &pixelVector, __m256i alphaChannel, __m256i colorMas pixelVectorAG = _mm256_add_epi32(pixelVectorAG, half); pixelVectorRB = _mm256_srli_epi32(pixelVectorRB, 16); - pixelVectorAG = _mm256_andnot_si256(colorMask, pixelVectorAG); - - pixelVector = _mm256_or_si256(pixelVectorAG, pixelVectorRB); + pixelVector = _mm256_blendv_epi8(pixelVectorAG, pixelVectorRB, colorMask); } // See INTERPOLATE_PIXEL_255_SSE2 for details. @@ -78,10 +74,9 @@ INTERPOLATE_PIXEL_255_AVX2(__m256i srcVector, __m256i &dstVector, __m256i alphaC finalRB = _mm256_add_epi16(finalRB, _mm256_srli_epi16(finalRB, 8)); finalAG = _mm256_add_epi16(finalAG, half); finalRB = _mm256_add_epi16(finalRB, half); - finalAG = _mm256_andnot_si256(colorMask, finalAG); finalRB = _mm256_srli_epi16(finalRB, 8); - dstVector = _mm256_or_si256(finalAG, finalRB); + dstVector = _mm256_blendv_epi8(finalAG, finalRB, colorMask); } inline static void Q_DECL_VECTORCALL @@ -101,10 +96,8 @@ INTERPOLATE_PIXEL_RGB64_AVX2(__m256i srcVector, __m256i &dstVector, __m256i alph finalRB = _mm256_add_epi32(finalRB, _mm256_srli_epi32(finalRB, 16)); finalAG = _mm256_add_epi32(finalAG, half); finalRB = _mm256_add_epi32(finalRB, half); - finalAG = _mm256_andnot_si256(colorMask, finalAG); finalRB = _mm256_srli_epi32(finalRB, 16); - - dstVector = _mm256_or_si256(finalAG, finalRB); + dstVector = _mm256_blendv_epi8(finalAG, finalRB, colorMask); } // See BLEND_SOURCE_OVER_ARGB32_SSE2 for details. diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 21e89d67fd2..2acc5ef7c52 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -213,14 +213,15 @@ QPlatformBackingStore::FlushResult QPlatformBackingStore::rhiFlush(QWindow *wind const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { auto &surfaceSupport = d_ptr->surfaceSupport[window->surfaceType()]; return surfaceSupport.compositor.flush(this, surfaceSupport.rhiSupport.rhi(), surfaceSupport.rhiSupport.swapChainForWindow(window), window, sourceDevicePixelRatio, region, offset, textures, - translucentBackground); + translucentBackground, sourceTransformFactor); } /*! diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index a6cb43b4e66..86035b98bea 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -151,7 +151,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground); + bool translucentBackground, + qreal sourceTransformFactor = 0); virtual QImage toImage() const; diff --git a/src/gui/painting/qrhibackingstore.cpp b/src/gui/painting/qrhibackingstore.cpp index d59cc2d83c5..3d9932e5ee2 100644 --- a/src/gui/painting/qrhibackingstore.cpp +++ b/src/gui/painting/qrhibackingstore.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qrhibackingstore_p.h" +#include "qpa/qplatformwindow.h" #include <private/qimage_p.h> QT_BEGIN_NAMESPACE @@ -43,10 +44,22 @@ void QRhiBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, cons createRhi(flushedWindow, rhiConfig); } + // The backing store operates on behalf of its window(), even if we're + // flushing a child window, so pull the source DPR from the window(). + const qreal sourceDevicePixelRatio = window()->devicePixelRatio(); + + // QBackingStore::flush will convert the region and offset from device independent + // pixels to native pixels before calling QPlatformBackingStore::flush, which means + // we can't pass on the window's DPR as the sourceTransformFactor, as that will include + // the Qt scale factor, which has already been applied. Instead we ask the platform + // window, which only reflect the remaining scale factor from the OS. + const qreal sourceTransformFactor = flushedWindow->handle()->devicePixelRatio(); + static QPlatformTextureList emptyTextureList; bool translucentBackground = m_image.hasAlphaChannel(); - rhiFlush(flushedWindow, flushedWindow->devicePixelRatio(), - region, offset, &emptyTextureList, translucentBackground); + rhiFlush(flushedWindow, sourceDevicePixelRatio, + region, offset, &emptyTextureList, translucentBackground, + sourceTransformFactor); } QImage::Format QRhiBackingStore::format() const diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 66f1cf2a985..148d40b8361 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -784,7 +784,7 @@ bool QTransform::operator==(const QTransform &o) const */ size_t qHash(const QTransform &key, size_t seed) noexcept { - QtPrivate::QHashCombine hash(seed); + QtPrivate::QHashCombineWithSeed hash(seed); seed = hash(seed, key.m11()); seed = hash(seed, key.m12()); seed = hash(seed, key.m21()); diff --git a/src/gui/painting/shaders/REUSE.toml b/src/gui/painting/shaders/REUSE.toml index ee4e083dc8f..938a9764b6b 100644 --- a/src/gui/painting/shaders/REUSE.toml +++ b/src/gui/painting/shaders/REUSE.toml @@ -3,5 +3,5 @@ version = 1 [[annotations]] path = ["*"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index b9312f6b304..7a3d4974e53 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -6543,7 +6543,7 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept { const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(b); - QtPrivate::QHashCombine hash(seed); + QtPrivate::QHashCombineWithSeed hash(seed); seed = hash(seed, d->binding); seed = hash(seed, d->stage); seed = hash(seed, d->type); diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 5e967c62e40..1234d01b6ec 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -812,7 +812,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) noexcept size_t qHash(const QShader &s, size_t seed) noexcept { if (s.d) { - QtPrivate::QHashCombine hash(seed); + QtPrivate::QHashCombineWithSeed hash(seed); seed = hash(seed, s.stage()); if (!s.d->shaders.isEmpty()) { seed = hash(seed, s.d->shaders.firstKey()); diff --git a/src/gui/text/qfontdatabase_p.h b/src/gui/text/qfontdatabase_p.h index 4cd6996aab8..27fb34aecdd 100644 --- a/src/gui/text/qfontdatabase_p.h +++ b/src/gui/text/qfontdatabase_p.h @@ -51,7 +51,7 @@ inline bool operator!=(const QtFontFallbacksCacheKey &lhs, const QtFontFallbacks inline size_t qHash(const QtFontFallbacksCacheKey &key, size_t seed = 0) noexcept { - QtPrivate::QHashCombine hash(seed); + QtPrivate::QHashCombineWithSeed hash(seed); seed = hash(seed, key.family); seed = hash(seed, int(key.style)); seed = hash(seed, int(key.styleHint)); diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp index e8a6b56ae20..32fee3bcdf7 100644 --- a/src/gui/util/qgridlayoutengine.cpp +++ b/src/gui/util/qgridlayoutengine.cpp @@ -471,6 +471,7 @@ void QGridLayoutRowData::dump(int indent) const qDebug("%*s Multi-cell entry <%d, %d> (stretch %d)", indent, "", it.key().first, it.key().second, it.value().q_stretch); it.value().q_box.dump(indent + 2); + ++it; } } #endif diff --git a/src/network/android/REUSE.toml b/src/network/android/REUSE.toml index e46bfebe93c..8c759f3eee7 100644 --- a/src/network/android/REUSE.toml +++ b/src/network/android/REUSE.toml @@ -4,5 +4,5 @@ version = 1 path = ["jar/build.gradle", "jar/settings.gradle"] precedence = "closest" comment = "double check" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index 4c8b3ebf3f8..ca5fb50f086 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -429,11 +429,14 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb if (socketType == QAbstractSocket::UdpSocket) { // Set the broadcasting flag if it's a UDP socket. - if (!setOption(BroadcastSocketOption, 1)) { - d->setError(QAbstractSocket::UnsupportedSocketOperationError, - QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString); - close(); - return false; + // IPv6 does not support broadcast — only set option for IPv4 + if (protocol == QAbstractSocket::IPv4Protocol) { + if (!setOption(BroadcastSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString); + close(); + return false; + } } // Set some extra flags that are interesting to us, but accept failure diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 6949eec9560..b78d2829704 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -822,6 +822,12 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const recvResult = getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &value, &valuelen); if (recvResult != -1) recvResult = value; +#elif defined(Q_OS_VXWORKS) + // VxWorks: use ioctl(FIONREAD) to query the number of bytes available + int available = 0; + int ioctlResult = ::ioctl(socketDescriptor, FIONREAD, &available); + if (ioctlResult != -1) + recvResult = available; #else // We need to grow the buffer to fit the entire datagram. // We start at 1500 bytes (the MTU for Ethernet V2), which should catch diff --git a/src/opengl/qopenglcompositorbackingstore.cpp b/src/opengl/qopenglcompositorbackingstore.cpp index 20c86fb8adc..95dd1a562a6 100644 --- a/src/opengl/qopenglcompositorbackingstore.cpp +++ b/src/opengl/qopenglcompositorbackingstore.cpp @@ -163,7 +163,8 @@ QPlatformBackingStore::FlushResult QOpenGLCompositorBackingStore::rhiFlush(QWind const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { // QOpenGLWidget/QQuickWidget content provided as textures. The raster content goes on top. @@ -171,6 +172,7 @@ QPlatformBackingStore::FlushResult QOpenGLCompositorBackingStore::rhiFlush(QWind Q_UNUSED(offset); Q_UNUSED(translucentBackground); Q_UNUSED(sourceDevicePixelRatio); + Q_UNUSED(sourceTransformFactor); m_rhi = rhi(window); Q_ASSERT(m_rhi); diff --git a/src/opengl/qopenglcompositorbackingstore_p.h b/src/opengl/qopenglcompositorbackingstore_p.h index 4512e2d589e..b50629000cf 100644 --- a/src/opengl/qopenglcompositorbackingstore_p.h +++ b/src/opengl/qopenglcompositorbackingstore_p.h @@ -48,7 +48,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) override; + bool translucentBackground, + qreal sourceTransformFactor = 0) override; const QPlatformTextureList *textures() const { return m_textures; } diff --git a/src/plugins/REUSE.toml b/src/plugins/REUSE.toml index d017617236d..d58822731c1 100644 --- a/src/plugins/REUSE.toml +++ b/src/plugins/REUSE.toml @@ -6,19 +6,19 @@ path = ["**.json", "**.png", "**.svg", "**.xml", "platforms/ios/module.modulemap", "tracing/metadata_template.txt"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" [[annotations]] path = ["platforms/wasm/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" [[annotations]] path = ["**.qmake.conf", "networkinformation/android/jar/build.gradle", "networkinformation/android/jar/settings.gradle"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index b5113578dd2..03677107d7d 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -518,7 +518,7 @@ QImage ICOReader::iconAt(int index) } } } - img.setText(QLatin1String(icoOrigDepthKey), QString::number(iconEntry.wBitCount)); + img.setText(QLatin1String(icoOrigDepthKey), QString::number(icoAttrib.nbits)); } } } diff --git a/src/plugins/platforminputcontexts/ibus/REUSE.toml b/src/plugins/platforminputcontexts/ibus/REUSE.toml index a16b04598f2..6423551b15d 100644 --- a/src/plugins/platforminputcontexts/ibus/REUSE.toml +++ b/src/plugins/platforminputcontexts/ibus/REUSE.toml @@ -4,5 +4,5 @@ version = 1 path = ["qibusinputcontextproxy.cpp", "qibusinputcontextproxy.h", "qibusproxy.cpp", "qibusproxy.h", "qibusproxyportal.cpp", "qibusproxyportal.h"] precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 71b6015a54d..79aed15a1d0 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -44,7 +44,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) override; + bool translucentBackground, + qreal sourceTransformFactor) override; QImage toImage() const override; QPlatformGraphicsBuffer *graphicsBuffer() const override; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 78d23b01dea..186aeaac44d 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -457,7 +457,8 @@ QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *windo const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { if (!m_buffers.back()) { qCWarning(lcQpaBackingStore) << "Flush requested with no back buffer. Ignoring."; @@ -466,7 +467,8 @@ QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *windo finalizeBackBuffer(); - return QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, textures, translucentBackground); + return QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, + region, offset, textures, translucentBackground, sourceTransformFactor); } QImage QCALayerBackingStore::toImage() const diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.mm b/src/plugins/platforms/cocoa/qcocoaclipboard.mm index 241faadbec0..0b84cae956b 100644 --- a/src/plugins/platforms/cocoa/qcocoaclipboard.mm +++ b/src/plugins/platforms/cocoa/qcocoaclipboard.mm @@ -3,6 +3,7 @@ #include "qcocoaclipboard.h" +#include <QtGui/qguiapplication.h> #include <QtGui/qutimimeconverter.h> #ifndef QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h index 82c03573763..5c8aaeb1fde 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.h +++ b/src/plugins/platforms/cocoa/qcocoacursor.h @@ -4,9 +4,10 @@ #ifndef QWINDOWSCURSOR_H #define QWINDOWSCURSOR_H -#include <QtCore> #include <qpa/qplatformcursor.h> +#include <QtCore/qhash.h> + Q_FORWARD_DECLARE_OBJC_CLASS(NSCursor); QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h index c5c126ecf3e..09ba685078b 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.h +++ b/src/plugins/platforms/cocoa/qcocoadrag.h @@ -4,16 +4,12 @@ #ifndef QCOCOADRAG_H #define QCOCOADRAG_H -#include <QtGui> #include <qpa/qplatformdrag.h> -#include <private/qsimpledrag_p.h> +#include <QtGui/private/qsimpledrag_p.h> +#include <QtGui/private/qinternalmimedata_p.h> #include <QtCore/private/qcore_mac_p.h> -#include <QtGui/private/qdnd_p.h> -#include <QtGui/private/qinternalmimedata_p.h> - -#include <QtCore/qeventloop.h> Q_FORWARD_DECLARE_OBJC_CLASS(NSView); Q_FORWARD_DECLARE_OBJC_CLASS(NSEvent); @@ -21,6 +17,10 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSPasteboard); QT_BEGIN_NAMESPACE +class QDrag; +class QEventLoop; +class QMimeData; + class QCocoaDrag : public QPlatformDrag { public: diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index 64df903edcb..0f9df3f17ab 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -7,8 +7,15 @@ #include "qcocoadrag.h" #include "qmacclipboard.h" #include "qcocoahelpers.h" -#include <QtGui/private/qcoregraphics_p.h> + +#include <QtGui/qfont.h> +#include <QtGui/qfontmetrics.h> +#include <QtGui/qpainter.h> #include <QtGui/qutimimeconverter.h> +#include <QtGui/private/qcoregraphics_p.h> +#include <QtGui/private/qdnd_p.h> + +#include <QtCore/qeventloop.h> #include <QtCore/private/qcore_mac_p.h> #include <vector> diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 36546879ae4..13139dd399d 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -43,6 +43,8 @@ public: QFunctionPointer getProcAddress(const char *procName) override; + bool isSoftwareContext() const; + private: static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format); @@ -54,6 +56,7 @@ private: QSurfaceFormat m_format; QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers; QAtomicInt m_needsUpdate = false; + bool m_isSoftwareContext = false; #ifndef QT_NO_DEBUG_STREAM friend QDebug operator<<(QDebug debug, const QCocoaGLContext *screen); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index bfac716b633..2f0f513dfc1 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -289,6 +289,9 @@ void QCocoaGLContext::updateSurfaceFormat() else m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer); + m_isSoftwareContext = (pixelFormatAttribute(NSOpenGLPFARendererID) + & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID; + // ------------------- Query the context ------------------- auto glContextParameter = [&](NSOpenGLContextParameter parameter) { @@ -512,6 +515,11 @@ bool QCocoaGLContext::isSharing() const return m_shareContext != nil; } +bool QCocoaGLContext::isSoftwareContext() const +{ + return m_isSoftwareContext; +} + NSOpenGLContext *QCocoaGLContext::nativeContext() const { return m_context; diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 7ef958e5d9b..a569ce2ba4d 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -8,8 +8,6 @@ #include "qcocoahelpers.h" #include "qnsview.h" -#include <QtCore> -#include <QtGui> #include <qpa/qplatformscreen.h> #include <private/qguiapplication_p.h> #include <private/qwindow_p.h> diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 8c6dcfd4f60..4c5975af34a 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -232,6 +232,24 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons // layer-backed. return false; case OpenGL: + if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSSonoma) { + // Tahoe has issues with software-backed GL, crashing in common operations + static bool isSoftwareContext = []{ + QOpenGLContext context; + context.create(); + auto *cocoaContext = static_cast<QCocoaGLContext*>(context.handle()); + if (cocoaContext->isSoftwareContext()) { + qWarning() << "Detected software OpenGL backend," + << "which is known to be broken on" + << qUtf8Printable(QSysInfo::prettyProductName()); + return true; + } else { + return false; + } + }(); + return !isSoftwareContext; + } + Q_FALLTHROUGH(); case BufferQueueingOpenGL: #endif case ThreadedPixmaps: diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h index 95267565f2d..dcc300797c9 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.h +++ b/src/plugins/platforms/cocoa/qmacclipboard.h @@ -4,10 +4,10 @@ #ifndef QMACCLIPBOARD_H #define QMACCLIPBOARD_H -#include <QtGui> #include <QtGui/qutimimeconverter.h> #include <QtCore/qpointer.h> +#include <QtCore/qvariant.h> #include <ApplicationServices/ApplicationServices.h> diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index edafa3b6a10..155c4aa826d 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -11,6 +11,7 @@ #include <QtGui/qbitmap.h> #include <QtCore/qdatetime.h> #include <QtCore/qmetatype.h> +#include <QtCore/qmimedata.h> #include <QtCore/qdebug.h> #include <QtCore/private/qcore_mac_p.h> #include <QtGui/qguiapplication.h> diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h index d47d37729f5..63647246589 100644 --- a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h +++ b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h @@ -15,13 +15,12 @@ #ifndef QMULTITOUCH_MAC_P_H #define QMULTITOUCH_MAC_P_H -#include <QtCore/qglobal.h> -#include <qpa/qwindowsysteminterface.h> -#include <qhash.h> -#include <QtCore> +#include <QtCore/qhash.h> +#include <QtCore/private/qcore_mac_p.h> + #include <QtGui/qpointingdevice.h> -#include <QtCore/private/qcore_mac_p.h> +#include <qpa/qwindowsysteminterface.h> Q_FORWARD_DECLARE_OBJC_CLASS(NSTouch); QT_FORWARD_DECLARE_OBJC_ENUM(NSTouchPhase, unsigned long); diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm index b4c82ddc0d8..805cc7d59ea 100644 --- a/src/plugins/platforms/cocoa/qnsview_dragging.mm +++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm @@ -3,6 +3,8 @@ // This file is included from qnsview.mm, and only used to organize the code +#include <QtGui/qdrag.h> + @implementation QNSView (Dragging) -(void)registerDragTypes diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp index 9f19e649f85..59265daa127 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp @@ -10,6 +10,7 @@ #include <private/qeglfskmsintegration_p.h> #include <QtCore/QLoggingCategory> +#include <QtCore/qtimer.h> #include <QtCore/private/qcore_unix_p.h> #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm index 088d48fc9ff..990409f2d17 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -16,19 +16,28 @@ #include <QtCore/QtCore> @interface QIOSWindowSceneDelegate : NSObject<UIWindowSceneDelegate> +@property (nullable, nonatomic, strong) UIWindow *window; @end @implementation QIOSApplicationDelegate - (UISceneConfiguration *)application:(UIApplication *)application - configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession + configurationForConnectingSceneSession:(UISceneSession *)session options:(UISceneConnectionOptions *)options { - qCDebug(lcQpaWindowScene) << "Configuring scene for" << connectingSceneSession - << "with options" << options; + qCDebug(lcQpaWindowScene) << "Configuring scene for" << session << "with options" << options; + + auto *sceneConfig = session.configuration; + + if ([sceneConfig.role hasPrefix:@"CPTemplateApplication"]) { + qCDebug(lcQpaWindowScene) << "Not touching CarPlay scene with role" << sceneConfig.role + << "and existing delegate class" << sceneConfig.delegateClass; + // FIXME: Consider ignoring any scene with an existing sceneClass, delegateClass, or + // storyboard. But for visionOS the default delegate is SwiftUI.AppSceneDelegate. + } else { + sceneConfig.delegateClass = QIOSWindowSceneDelegate.class; + } - auto *sceneConfig = connectingSceneSession.configuration; - sceneConfig.delegateClass = QIOSWindowSceneDelegate.class; return sceneConfig; } @@ -40,27 +49,53 @@ { qCDebug(lcQpaWindowScene) << "Connecting" << scene << "to" << session; - Q_ASSERT([scene isKindOfClass:UIWindowScene.class]); + // Handle URL contexts, even if we return early + const auto handleUrlContexts = qScopeGuard([&]{ + if (connectionOptions.URLContexts.count > 0) + [self scene:scene openURLContexts:connectionOptions.URLContexts]; + }); + +#if defined(Q_OS_VISIONOS) + // CPImmersiveScene is a UIWindowScene, most likely so it can handle its internal + // CPSceneLayerEventWindow and UITextEffectsWindow, but we don't want a QUIWindow + // for these scenes, so bail out early. + if ([scene.session.role isEqualToString:@"CPSceneSessionRoleImmersiveSpaceApplication"]) { + qCDebug(lcQpaWindowScene) << "Skipping UIWindow creation for immersive scene"; + return; + } +#endif + + if (![scene isKindOfClass:UIWindowScene.class]) { + qCWarning(lcQpaWindowScene) << "Unexpectedly encountered non-window scene"; + return; + } + UIWindowScene *windowScene = static_cast<UIWindowScene*>(scene); QUIWindow *window = [[QUIWindow alloc] initWithWindowScene:windowScene]; + window.rootViewController = [[[QIOSViewController alloc] initWithWindow:window] autorelease]; - QIOSScreen *screen = [&]{ - for (auto *screen : qGuiApp->screens()) { - auto *platformScreen = static_cast<QIOSScreen*>(screen->handle()); -#if !defined(Q_OS_VISIONOS) - if (platformScreen->uiScreen() == windowScene.screen) -#endif - return platformScreen; - } - Q_UNREACHABLE(); - }(); + self.window = [window autorelease]; +} - window.rootViewController = [[[QIOSViewController alloc] - initWithWindow:window andScreen:screen] autorelease]; +- (void)windowScene:(UIWindowScene *)windowScene + didUpdateCoordinateSpace:(id<UICoordinateSpace>)previousCoordinateSpace + interfaceOrientation:(UIInterfaceOrientation)previousInterfaceOrientation + traitCollection:(UITraitCollection *)previousTraitCollection +{ + qCDebug(lcQpaWindowScene) << "Scene" << windowScene << "did update properties"; + if (!self.window) + return; - if (connectionOptions.URLContexts.count > 0) - [self scene:scene openURLContexts:connectionOptions.URLContexts]; + Q_ASSERT([self.window isKindOfClass:QUIWindow.class]); + auto *viewController = static_cast<QIOSViewController*>(self.window.rootViewController); + [viewController updatePlatformScreen]; +} + +- (void)sceneDidDisconnect:(UIScene *)scene +{ + qCDebug(lcQpaWindowScene) << "Disconnecting" << scene; + self.window = nil; } - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 9ab490b2970..89a343061ee 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application"); -Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods"); +Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods", QtCriticalMsg); Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); Q_LOGGING_CATEGORY(lcQpaWindowScene, "qt.qpa.window.scene"); diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 5716ad041e0..8544c497d43 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -371,7 +371,8 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification) // with input-accessory-views. The reason for using frameEnd here (the future state), // instead of the current state reflected in frameBegin, is that QInputMethod::isVisible() // is documented to reflect the future state in the case of animated transitions. - m_keyboardState.keyboardVisible = CGRectIntersectsRect(frameEnd, [UIScreen mainScreen].bounds); + m_keyboardState.keyboardVisible = !CGRectIsEmpty(UIScreen.mainScreen.bounds) && + !CGRectIsEmpty(frameEnd) && CGRectIntersectsRect(frameEnd, UIScreen.mainScreen.bounds); // Used for auto-scroller, and will be used for animation-signal in the future m_keyboardState.keyboardEndRect = frameEnd; @@ -639,8 +640,10 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) // focus object. We try to detect code paths that fail this assertion and smooth // over the situation by doing a manual update of the focus object. if (qApp->focusObject() != m_imeState.focusObject && updatedProperties != Qt::ImQueryAll) { - qWarning() << "stale focus object" << static_cast<void *>(m_imeState.focusObject) - << ", doing manual update"; + qCWarning(lcQpaInputMethods).verbosity(0) << "Updating input context" << updatedProperties + << "with last reported focus object" << m_imeState.focusObject + << "but qGuiApp reports" << qApp->focusObject() + << "which means someone failed to call QPlatformInputContext::setFocusObject()"; setFocusObject(qApp->focusObject()); return; } diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h index 1f8da41ba4f..b5ce88d6a33 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.h +++ b/src/plugins/platforms/ios/qiosviewcontroller.h @@ -12,10 +12,12 @@ QT_END_NAMESPACE @interface QIOSViewController : UIViewController -- (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen; -- (void)updateProperties; +- (instancetype)initWithWindow:(UIWindow*)window; +- (void)updateStatusBarProperties; - (NSArray*)keyCommands; - (void)handleShortcut:(UIKeyCommand*)keyCommand; +- (void)updatePlatformScreen; + #ifndef Q_OS_TVOS // UIViewController diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 36ce785e031..169f8ae1754 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -231,11 +231,12 @@ @synthesize preferredStatusBarStyle; #endif -- (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen +- (instancetype)initWithWindow:(UIWindow*)window { if (self = [self init]) { self.window = window; - self.platformScreen = screen; + self.platformScreen = nil; + [self updatePlatformScreen]; self.changingOrientation = NO; #ifndef Q_OS_TVOS @@ -246,7 +247,7 @@ #endif m_focusWindowChangeConnection = QObject::connect(qApp, &QGuiApplication::focusWindowChanged, [self]() { - [self updateProperties]; + [self updateStatusBarProperties]; }); QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState; @@ -314,6 +315,54 @@ // ------------------------------------------------------------------------- +- (void)updatePlatformScreen +{ + auto *windowScene = self.window.windowScene; + + QIOSScreen *newPlatformScreen = [&]{ + for (auto *screen : qGuiApp->screens()) { + auto *platformScreen = static_cast<QIOSScreen*>(screen->handle()); +#if !defined(Q_OS_VISIONOS) + if (platformScreen->uiScreen() == windowScene.screen) +#endif + return platformScreen; + } + Q_UNREACHABLE(); + }(); + + if (newPlatformScreen != self.platformScreen) { + QIOSScreen *oldPlatformScreen = self.platformScreen; + self.platformScreen = newPlatformScreen; + + qCDebug(lcQpaWindow) << "View controller" << self << "moved from" + << oldPlatformScreen << "to" << newPlatformScreen; + + QScreen *newScreen = newPlatformScreen ? newPlatformScreen->screen() : nullptr; + + const bool isPrimaryScene = !qt_apple_sharedApplication().supportsMultipleScenes + && windowScene.session.role == UIWindowSceneSessionRoleApplication; + + if (isPrimaryScene) { + // When we only have a single application-role scene we treat the + // active screen as the primary one, so that windows shown on the + // primary screen end up in our view controller. + QWindowSystemInterface::handlePrimaryScreenChanged(newPlatformScreen); + } + + for (auto *window : qGuiApp->topLevelWindows()) { + // Move window to new screen if it was on the old screen, + // or if we're setting up the primary scene, in which case + // we want to adopt all existing windows to this screen. + if ((window->screen()->handle() == oldPlatformScreen) + || (isPrimaryScene && !oldPlatformScreen)) { + QWindowSystemInterface::handleWindowScreenChanged(window, newScreen); + } + } + } +} + +// ------------------------------------------------------------------------- + - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { self.changingOrientation = YES; @@ -390,7 +439,7 @@ // ------------------------------------------------------------------------- -- (void)updateProperties +- (void)updateStatusBarProperties { if (!isQtApplication()) return; diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 3e2b6b0102a..af1fbb0abaf 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -243,7 +243,7 @@ void QIOSWindow::setWindowState(Qt::WindowStates state) qt_window_private(window())->windowState = state; if (window()->isTopLevel() && window()->isVisible() && window()->isActive()) - [m_view.qtViewController updateProperties]; + [m_view.qtViewController updateStatusBarProperties]; if (state & Qt::WindowMinimized) { applyGeometry(QRect()); diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 9b17eef07b0..86b6ce07518 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -786,6 +786,9 @@ inline ulong getTimeStamp(UIEvent *event) #if QT_CONFIG(tabletevent) - (void)handleHover:(UIHoverGestureRecognizer *)recognizer { + if (!self.platformWindow) + return; + ulong timeStamp = [[NSProcessInfo processInfo] systemUptime] * 1000; CGFloat zOffset = 0; diff --git a/src/plugins/platforms/wayland/qwaylandcursor.cpp b/src/plugins/platforms/wayland/qwaylandcursor.cpp index 4967f9d46f4..a9cff626224 100644 --- a/src/plugins/platforms/wayland/qwaylandcursor.cpp +++ b/src/plugins/platforms/wayland/qwaylandcursor.cpp @@ -331,7 +331,7 @@ void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window) device->setCursor(cursor, bitmapBuffer, qCeil(waylandWindow->devicePixelRatio())); } - mDisplay->flushRequests(); + wl_display_flush(mDisplay->wl_display()); } } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 38b3bdadd35..a407cde2a7c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1156,9 +1156,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::MoveEvent: platformWindow->handleMoved(); return true; - case QtWindows::ResizeEvent: + case QtWindows::ResizeEvent: { + QWindow *window = platformWindow->window(); platformWindow->handleResized(static_cast<int>(wParam), lParam); + if (window->flags().testFlags(Qt::ExpandedClientAreaHint)) + platformWindow->updateCustomTitlebar(); return true; + } case QtWindows::QuerySizeHints: platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam)); return true;// maybe available on some SDKs revisit WM_NCCALCSIZE @@ -1174,8 +1178,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return platformWindow->handleNonClientActivate(result); case QtWindows::GeometryChangingEvent: return platformWindow->handleGeometryChanging(&msg); - case QtWindows::ExposeEvent: + case QtWindows::ExposeEvent: { + QWindow *window = platformWindow->window(); + if (window->flags().testFlags(Qt::ExpandedClientAreaHint)) + platformWindow->updateCustomTitlebar(); return platformWindow->handleWmPaint(hwnd, message, wParam, lParam, result); + } case QtWindows::NonClientMouseEvent: if (!platformWindow->frameStrutEventsEnabled()) break; @@ -1219,6 +1227,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow(). if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) return false; + [[fallthrough]]; case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); return true; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 25c15861ba1..0f66193f47d 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -262,6 +262,11 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; #ifndef QT_NO_OPENGL case OpenGL: +#if !QT_CONFIG(run_opengl_tests) + // Workaround for build configs on WoA that don't have OpenGL installed + // FIXME: Detect at runtime + return false; +#endif return true; case ThreadedOpenGL: if (const QWindowsStaticOpenGLContext *glContext = QWindowsIntegration::staticOpenGLContext()) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 81a3f1d37b7..731673b61db 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -284,40 +284,6 @@ static inline RECT RECTfromQRect(const QRect &rect) return result; } -static LRESULT WINAPI WndProcTitleBar(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND parentHwnd = reinterpret_cast<HWND>(GetWindowLongPtr(hwnd, GWL_HWNDPARENT)); - QWindowsWindow* platformWindow = QWindowsContext::instance()->findPlatformWindow(parentHwnd); - - switch (message) { - case WM_SHOWWINDOW: - ShowWindow(hwnd,SW_HIDE); - if ((BOOL)wParam == TRUE) - platformWindow->transitionAnimatedCustomTitleBar(); - return 0; - case WM_SIZE: { - if (platformWindow) - platformWindow->updateCustomTitlebar(); - break; - } - case WM_NCHITTEST: - return HTTRANSPARENT; - case WM_TIMER: - ShowWindow(hwnd, SW_SHOWNOACTIVATE); - platformWindow->updateCustomTitlebar(); - break; - case WM_PAINT: - { - PAINTSTRUCT ps; - BeginPaint(hwnd, &ps); - EndPaint(hwnd, &ps); - return 0; - } - } - return DefWindowProc(hwnd, message, wParam, lParam); -} - - #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const RECT &r) { @@ -917,7 +883,7 @@ QWindowsWindowData const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr)); const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); - const QString windowTitlebarName = QWindowsContext::instance()->registerWindowClass(QStringLiteral("_q_titlebar"), WndProcTitleBar, CS_VREDRAW|CS_HREDRAW, nullptr, false); + const QString windowTitlebarName = QWindowsContext::instance()->registerWindowClass(QStringLiteral("_q_titlebar"), DefWindowProc, CS_VREDRAW|CS_HREDRAW, nullptr, false); const QScreen *screen{}; const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, @@ -970,15 +936,13 @@ QWindowsWindowData context->frameWidth, context->frameHeight, parentHandle, nullptr, appinst, nullptr); - if (w->flags().testFlags(Qt::ExpandedClientAreaHint)) { - const UINT dpi = ::GetDpiForWindow(result.hwnd); - const int titleBarHeight = getTitleBarHeight_sys(dpi); - result.hwndTitlebar = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, - classTitleBarNameUtf16, classTitleBarNameUtf16, - WS_POPUP, 0, 0, - context->frameWidth, titleBarHeight, - result.hwnd, nullptr, appinst, nullptr); - } + const UINT dpi = ::GetDpiForWindow(result.hwnd); + const int titleBarHeight = getTitleBarHeight_sys(dpi); + result.hwndTitlebar = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE, + classTitleBarNameUtf16, classTitleBarNameUtf16, + 0, 0, 0, + context->frameWidth, titleBarHeight, + nullptr, nullptr, appinst, nullptr); qCDebug(lcQpaWindow).nospace() << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " @@ -1056,6 +1020,9 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang if (flags & Qt::ExpandedClientAreaHint) { // Gives us the rounded corners looks and the frame shadow MARGINS margins = { -1, -1, -1, -1 }; DwmExtendFrameIntoClientArea(hwnd, &margins); + } else { + MARGINS margins = { 0, 0, 0, 0 }; + DwmExtendFrameIntoClientArea(hwnd, &margins); } } else { // child. SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags); @@ -1191,19 +1158,26 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, bool QWindowsGeometryHint::handleCalculateSize(const QWindow *window, const QMargins &customMargins, const MSG &msg, LRESULT *result) { + // Prevent adding any border for frameless window + if (msg.wParam && window->flags() & Qt::FramelessWindowHint) { + *result = 0; + return true; + } + const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window); + // In case the platformwindow was not yet created, use the initial windowflags provided by the user. + const bool clientAreaExpanded = platformWindow != nullptr ? platformWindow->isClientAreaExpanded() : window->flags() & Qt::ExpandedClientAreaHint; // Return 0 to remove the window's border - const bool clientAreaExpanded = window->flags() & Qt::ExpandedClientAreaHint; if (msg.wParam && clientAreaExpanded) { // Prevent content from being cutoff by border for maximized, but not fullscreened windows. - if (IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen) { - auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); - RECT *clientArea = &ncp->rgrc[0]; - const int border = getResizeBorderThickness(QWindowsWindow::windowsWindowOf(window)->savedDpi()); + const bool maximized = IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen; + auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); + RECT *clientArea = &ncp->rgrc[0]; + const int border = getResizeBorderThickness(96); + if (maximized) clientArea->top += border; - clientArea->bottom -= border; - clientArea->left += border; - clientArea->right -= border; - } + clientArea->bottom -= border; + clientArea->left += border; + clientArea->right -= border; *result = 0; return true; } @@ -1623,6 +1597,12 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) #endif { QWindowsContext::instance()->addWindow(m_data.hwnd, this); + + if (aWindow->flags().testFlags(Qt::ExpandedClientAreaHint)) { + SetParent(m_data.hwndTitlebar, m_data.hwnd); + ShowWindow(m_data.hwndTitlebar, SW_SHOW); + } + const Qt::WindowType type = aWindow->type(); if (type == Qt::Desktop) return; // No further handling for Qt::Desktop @@ -1847,21 +1827,6 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) return w; } -// Checks whether the Window is tiled with Aero snap -bool QWindowsWindow::isWindowArranged(HWND hwnd) -{ - typedef BOOL(WINAPI* PIsWindowArranged)(HWND); - static PIsWindowArranged pIsWindowArranged = nullptr; - static bool resolved = false; - if (!resolved) { - resolved = true; - pIsWindowArranged = (PIsWindowArranged)QSystemLibrary::resolve(QLatin1String("user32.dll"), "IsWindowArranged"); - } - if (pIsWindowArranged == nullptr) - return false; - return pIsWindowArranged(hwnd); -} - QWindowsWindowData QWindowsWindowData::create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -1903,13 +1868,6 @@ void QWindowsWindow::setVisible(bool visible) fireExpose(QRegion()); } } - if (m_data.hwndTitlebar) { - if (visible) { - SetWindowPos(m_data.hwndTitlebar, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } else { - ShowWindow(m_data.hwndTitlebar, SW_HIDE); - } - } } bool QWindowsWindow::isVisible() const @@ -2050,10 +2008,6 @@ void QWindowsWindow::show_sys() const setFlag(WithinMaximize); // QTBUG-8361 ShowWindow(m_data.hwnd, sm); - if (m_data.flags.testFlag(Qt::ExpandedClientAreaHint)) { - ShowWindow(m_data.hwndTitlebar, sm); - SetActiveWindow(m_data.hwnd); - } clearFlag(WithinMaximize); @@ -2245,7 +2199,7 @@ QRect QWindowsWindow::normalGeometry() const QMargins QWindowsWindow::safeAreaMargins() const { if (m_data.flags.testFlags(Qt::ExpandedClientAreaHint)) { - const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); + const int titleBarHeight = getTitleBarHeight_sys(96); return QMargins(0, titleBarHeight, 0, 0); } @@ -2457,15 +2411,9 @@ void QWindowsWindow::handleGeometryChange() clearFlag(SynchronousGeometryChangeEvent); qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry; - if (m_data.hwndTitlebar) { - bool arranged = QWindowsWindow::isWindowArranged(m_data.hwnd); - if (arranged || (m_windowWasArranged && !arranged)) - transitionAnimatedCustomTitleBar(); - + if (m_data.flags & Qt::ExpandedClientAreaHint) { const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); - MoveWindow(m_data.hwndTitlebar, m_data.geometry.x(), m_data.geometry.y(), - m_data.geometry.width(), titleBarHeight, true); - m_windowWasArranged = arranged; + MoveWindow(m_data.hwndTitlebar, 0, 0, m_data.geometry.width(), titleBarHeight, true); } } @@ -2627,6 +2575,16 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, creationData.applyWindowFlags(m_data.hwnd); creationData.initialize(window(), m_data.hwnd, true, m_opacity); + if (creationData.flags.testFlag(Qt::ExpandedClientAreaHint)) { + SetParent(m_data.hwndTitlebar, m_data.hwnd); + ShowWindow(m_data.hwndTitlebar, SW_SHOW); + } else { + if (IsWindowVisible(m_data.hwndTitlebar)) { + SetParent(m_data.hwndTitlebar, HWND_MESSAGE); + ShowWindow(m_data.hwndTitlebar, SW_HIDE); + } + } + QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; @@ -2645,7 +2603,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) handleHidden(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now. } else { - transitionAnimatedCustomTitleBar(); + updateCustomTitlebar(); if (state & Qt::WindowMaximized) { WINDOWPLACEMENT windowPlacement{}; windowPlacement.length = sizeof(WINDOWPLACEMENT); @@ -2743,20 +2701,6 @@ void QWindowsWindow::correctWindowPlacement(WINDOWPLACEMENT &windowPlacement) } } -void QWindowsWindow::transitionAnimatedCustomTitleBar() -{ - if (!m_data.hwndTitlebar) - return; - const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Control Panel\Desktop\WindowMetrics)"); - if (registry.isValid() && registry.value(LR"(MinAnimate)") == 1) { - ShowWindow(m_data.hwndTitlebar, SW_HIDE); - SetTimer(m_data.hwndTitlebar, 1, 200, nullptr); - } else { - ShowWindow(m_data.hwndTitlebar, SW_SHOWNOACTIVATE); - updateCustomTitlebar(); - } -} - void QWindowsWindow::updateRestoreGeometry() { m_data.restoreGeometry = normalFrameGeometry(m_data.hwnd); @@ -3078,7 +3022,8 @@ void QWindowsWindow::calculateFullFrameMargins() const auto systemMargins = testFlag(DisableNonClientScaling) ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd) : frameMargins_sys(); - const QMargins actualMargins = systemMargins + customMargins(); + const int extendedClientAreaBorder = window()->flags().testFlag(Qt::ExpandedClientAreaHint) ? qRound(QHighDpiScaling::factor(window())) * 2 : 0; + const QMargins actualMargins = systemMargins + customMargins() - extendedClientAreaBorder; const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); const bool typicalFrame = (actualMargins.left() == actualMargins.right()) @@ -3517,19 +3462,6 @@ bool QWindowsWindow::handleNonClientActivate(LRESULT *result) const return false; } -static void _q_drawCustomTitleBarButton(QPainter& p, const QRectF& r) -{ - QPainterPath path(QPointF(r.x(), r.y())); - QRectF rightCorner(r.x() + r.width() - 2.0, r.y() + 4.0, 2, 2); - QRectF leftCorner(r.x(), r.y() + 4, 2, 2); - path.lineTo(r.x() + r.width() - 5.0f, r.y()); - path.arcTo(rightCorner, 90, -90); - path.lineTo(r.x() + r.width(), r.y() + r.height() - 1); - path.lineTo(r.x(), r.y() + r.height() - 1); - path.closeSubpath(); - p.drawPath(path); -} - void QWindowsWindow::updateCustomTitlebar() { HWND hwnd = m_data.hwndTitlebar; @@ -3545,7 +3477,7 @@ void QWindowsWindow::updateCustomTitlebar() POINT localPos; GetCursorPos(&localPos); - MapWindowPoints(HWND_DESKTOP, hwnd, &localPos, 1); + MapWindowPoints(HWND_DESKTOP, m_data.hwnd, &localPos, 1); const bool isDarkmode = QWindowsIntegration::instance()->darkModeHandling().testFlags(QWindowsApplication::DarkModeWindowFrames) && qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark; @@ -3567,25 +3499,9 @@ void QWindowsWindow::updateCustomTitlebar() p.setPen(Qt::NoPen); if (!wnd->flags().testFlags(Qt::NoTitleBarBackgroundHint)) { QRect titleRect; - titleRect.setX(2); titleRect.setWidth(windowWidth); titleRect.setHeight(titleBarHeight); - - if (isWindows11orAbove) { - QPainterPath path(QPointF(titleRect.x() + 4.0f, titleRect.y())); - QRectF rightCorner(titleRect.x() + titleRect.width() - 4.0, titleRect.y() + 4.0, 2, 2); - QRectF leftCorner(titleRect.x(), titleRect.y() + 4, 2, 2); - path.lineTo(titleRect.x() + titleRect.width() - 7.0f, titleRect.y()); - path.arcTo(rightCorner, 90, -90); - path.lineTo(titleRect.x() + titleRect.width() - 2.0, titleRect.y() + titleRect.height() - 1); - path.lineTo(titleRect.x(), titleRect.y() + titleRect.height() - 1); - path.lineTo(titleRect.x(), titleRect.y() + 4.0f); - path.arcTo(leftCorner, -90, -90); - path.closeSubpath(); - p.drawPath(path); - } else { - p.drawRect(titleRect); - } + p.drawRect(titleRect); } if (wnd->flags().testFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint) || !wnd->flags().testFlag(Qt::CustomizeWindowHint)) { @@ -3631,15 +3547,12 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth - 1); + rect.setWidth(titleButtonWidth); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - if (isWindows11orAbove && buttons == 1) - _q_drawCustomTitleBarButton(p, rect); - else - p.drawRect(rect); + p.drawRect(rect); const QPen closeButtonHoveredPen = QPen(QColor(0xFF, 0xFF, 0xFD, 0xFF)); p.setPen(closeButtonHoveredPen); } else { @@ -3655,15 +3568,12 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth - 1); + rect.setWidth(titleButtonWidth); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - if (isWindows11orAbove && buttons == 1) - _q_drawCustomTitleBarButton(p, rect); - else - p.drawRect(rect); + p.drawRect(rect); } p.setPen(textPen); p.drawText(rect,QStringLiteral("\uE922"), QTextOption(Qt::AlignVCenter | Qt::AlignHCenter)); @@ -3676,15 +3586,12 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth - 1); + rect.setWidth(titleButtonWidth); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - if (isWindows11orAbove && buttons == 1) - _q_drawCustomTitleBarButton(p, rect); - else - p.drawRect(rect); + p.drawRect(rect); } p.setPen(textPen); p.drawText(rect,QStringLiteral("\uE921"), QTextOption(Qt::AlignVCenter | Qt::AlignHCenter)); @@ -3702,7 +3609,7 @@ void QWindowsWindow::updateCustomTitlebar() BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - POINT ptLocation = { windowRect.left, windowRect.top }; + POINT ptLocation = { 0, 0 }; SIZE szWnd = { windowWidth, titleBarHeight }; POINT ptSrc = { 0, 0 }; UpdateLayeredWindow(hwnd, hdc, &ptLocation, &szWnd, memdc, &ptSrc, 0, &blend, ULW_ALPHA); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index b67bd2850b3..a0e150aeb01 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -307,7 +307,6 @@ public: static QWindow *topLevelOf(QWindow *w); static inline void *userDataOf(HWND hwnd); static inline void setUserDataOf(HWND hwnd, void *ud); - static bool isWindowArranged(HWND hwnd); static bool hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags); static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity); @@ -359,12 +358,10 @@ public: int savedDpi() const { return m_savedDpi; } qreal dpiRelativeScale(const UINT dpi) const; - bool isFrameless() const { return m_data.flags.testFlag(Qt::FramelessWindowHint); } + bool isClientAreaExpanded() const { return m_data.flags.testFlag(Qt::ExpandedClientAreaHint); } void requestUpdate() override; - void transitionAnimatedCustomTitleBar(); - private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 8353fac6a92..fda47944d9d 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -870,7 +870,8 @@ QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) + bool translucentBackground, + qreal sourceTransformFactor) { if (!m_image || m_image->size().isEmpty()) return FlushFailed; @@ -878,7 +879,7 @@ QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window, m_image->flushScrolledRegion(true); auto result = QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, - textures, translucentBackground); + textures, translucentBackground, sourceTransformFactor); if (result != FlushSuccess) return result; QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle()); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 674640780eb..5cda9e1ab79 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -27,7 +27,8 @@ public: const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, - bool translucentBackground) override; + bool translucentBackground, + qreal sourceTransformFactor) override; QImage toImage() const override; QPlatformGraphicsBuffer *graphicsBuffer() const override; diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index 82e978862f8..62269a21de1 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -183,30 +183,24 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt QObject *styleObject = option->styleObject; // Can be widget or qquickitem QRectF thumbRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); - auto center = thumbRect.center(); const qreal outerRadius = qMin(8.0, (slider->orientation == Qt::Horizontal ? thumbRect.height() / 2.0 : thumbRect.width() / 2.0) - 1); - - thumbRect.setWidth(outerRadius); - thumbRect.setHeight(outerRadius); - thumbRect.moveCenter(center); - QPointF cursorPos = widget ? widget->mapFromGlobal(QCursor::pos()) : QPointF(); - bool isInsideHandle = thumbRect.contains(cursorPos); + bool isInsideHandle = option->activeSubControls == SC_SliderHandle; bool oldIsInsideHandle = styleObject->property("_q_insidehandle").toBool(); - int oldState = styleObject->property("_q_stylestate").toInt(); - int oldActiveControls = styleObject->property("_q_stylecontrols").toInt(); + State oldState = State(styleObject->property("_q_stylestate").toInt()); + SubControls oldActiveControls = SubControls(styleObject->property("_q_stylecontrols").toInt()); QRectF oldRect = styleObject->property("_q_stylerect").toRect(); styleObject->setProperty("_q_insidehandle", isInsideHandle); - styleObject->setProperty("_q_stylestate", int(option->state)); + styleObject->setProperty("_q_stylestate", int(state)); styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls)); styleObject->setProperty("_q_stylerect", option->rect); if (option->styleObject->property("_q_end_radius").isNull()) option->styleObject->setProperty("_q_end_radius", outerRadius * 0.43); bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken) - || ((oldIsInsideHandle) != (isInsideHandle)) - || oldActiveControls != int(option->activeSubControls)) + || (oldIsInsideHandle != isInsideHandle) + || (oldActiveControls != option->activeSubControls)) && state & State_Enabled); if (oldRect != option->rect) { @@ -242,11 +236,11 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt QCachedPainter cp(painter, QLatin1StringView("win11_spinbox") % HexString<uint8_t>(colorSchemeIndex), sb, sb->rect.size()); if (cp.needsPainting()) { - const auto frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, option->palette.brush(QPalette::Base)); if (sb->frame && (sub & SC_SpinBoxFrame)) - drawLineEditFrame(cp.painter(), option); + drawLineEditFrame(cp.painter(), frameRect, option); const bool isMouseOver = state & State_MouseOver; const bool hasFocus = state & State_HasFocus; @@ -374,31 +368,29 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt } } if (sub & SC_SliderHandle) { - if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { - const QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); - const QPointF center = rect.center(); + const QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); + const QPointF center = rect.center(); - const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject)); + const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject)); - if (animation != nullptr) - option->styleObject->setProperty("_q_inner_radius", animation->currentValue()); - else - option->styleObject->setProperty("_q_inner_radius", option->styleObject->property("_q_end_radius")); - - const qreal outerRadius = qMin(8.0,(slider->orientation == Qt::Horizontal ? rect.height() / 2.0 : rect.width() / 2.0) - 1); - const float innerRadius = option->styleObject->property("_q_inner_radius").toFloat(); - painter->setRenderHint(QPainter::Antialiasing, true); - painter->setPen(Qt::NoPen); - painter->setBrush(WINUI3Colors[colorSchemeIndex][controlFillSolid]); - painter->drawEllipse(center, outerRadius, outerRadius); - painter->setBrush(option->palette.accent()); - painter->drawEllipse(center, innerRadius, innerRadius); - - painter->setPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]); - painter->setBrush(Qt::NoBrush); - painter->drawEllipse(center, outerRadius + 0.5, outerRadius + 0.5); - painter->drawEllipse(center, innerRadius + 0.5, innerRadius + 0.5); - } + float innerRadius = 0; + if (animation != nullptr) + innerRadius = animation->currentValue(); + else + innerRadius = option->styleObject->property("_q_end_radius").toFloat(); + option->styleObject->setProperty("_q_inner_radius", innerRadius); + const qreal outerRadius = qMin(8.0,(slider->orientation == Qt::Horizontal ? rect.height() / 2.0 : rect.width() / 2.0) - 1); + + painter->setPen(Qt::NoPen); + painter->setBrush(winUI3Color(controlFillSolid)); + painter->drawEllipse(center, outerRadius, outerRadius); + painter->setBrush(option->palette.accent()); + painter->drawEllipse(center, innerRadius, innerRadius); + + painter->setPen(winUI3Color(controlStrokeSecondary)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(center, outerRadius + 0.5, outerRadius + 0.5); + painter->drawEllipse(center, innerRadius + 0.5, innerRadius + 0.5); } if (slider->state & State_HasFocus) { QStyleOptionFocusRect fropt; @@ -412,11 +404,11 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt #if QT_CONFIG(combobox) case CC_ComboBox: if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { - const auto frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); drawRoundedRect(painter, frameRect, Qt::NoPen, option->palette.brush(QPalette::Base)); if (combobox->frame) - drawLineEditFrame(painter, option); + drawLineEditFrame(painter, frameRect, option); const bool isMouseOver = state & State_MouseOver; const bool hasFocus = state & State_HasFocus; @@ -668,7 +660,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption t->setStartValue(styleObject->property("_q_inner_radius").toFloat()); t->setEndValue(7.0f); if (option->state & State_Sunken) - t->setEndValue(2.0f); + t->setEndValue(4.0f); else if (option->state & State_MouseOver && !(option->state & State_On)) t->setEndValue(7.0f); else if (option->state & State_MouseOver && (option->state & State_On)) @@ -709,27 +701,19 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption switch (element) { case PE_PanelTipLabel: { - QRectF tipRect = option->rect.marginsRemoved(QMargins(1,1,1,1)); - painter->setPen(Qt::NoPen); - painter->setBrush(option->palette.toolTipBase()); - painter->drawRoundedRect(tipRect, secondLevelRoundingRadius, secondLevelRoundingRadius); - - painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]); - painter->setBrush(Qt::NoBrush); - painter->drawRoundedRect(tipRect.marginsAdded(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius); + const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5)); + const auto pen = highContrastTheme ? option->palette.buttonText().color() + : winUI3Color(frameColorLight); + drawRoundedRect(painter, rect, pen, option->palette.toolTipBase()); break; } case PE_FrameTabWidget: #if QT_CONFIG(tabwidget) if (const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) { - QRectF frameRect = frame->rect.marginsRemoved(QMargins(0,0,0,0)); - painter->setPen(Qt::NoPen); - painter->setBrush(frame->palette.base()); - painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius); - - painter->setPen(highContrastTheme == true ? frame->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]); - painter->setBrush(Qt::NoBrush); - painter->drawRoundedRect(frameRect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius); + const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5)); + const auto pen = highContrastTheme ? frame->palette.buttonText().color() + : winUI3Color(frameColorLight); + drawRoundedRect(painter, rect, pen, frame->palette.base()); } #endif // QT_CONFIG(tabwidget) break; @@ -763,40 +747,41 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption } } break; - case PE_IndicatorCheckBox: - { + case PE_IndicatorCheckBox: { const bool isRtl = option->direction == Qt::RightToLeft; - QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject)); - QFontMetrics fm(d->assetFont); + const bool isOn = option->state & State_On; + const bool isPartial = option->state & State_NoChange; QRectF rect = isRtl ? option->rect.adjusted(0, 0, -2, 0) : option->rect.adjusted(2, 0, 0, 0); - QPointF center = QPointF(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2); + const QPointF center = rect.center(); rect.setWidth(15); rect.setHeight(15); rect.moveCenter(center); - float clipWidth = animation != nullptr ? animation->currentValue() : 1.0f; - QRectF clipRect = fm.boundingRect(QStringLiteral(u"\uE73E")); - clipRect.moveCenter(center); - clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0); - clipRect.setWidth(clipWidth * clipRect.width()); - - painter->setPen(Qt::NoPen); - painter->setBrush(buttonFillBrush(option)); - painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius, Qt::AbsoluteSize); - - painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() - : WINUI3Colors[colorSchemeIndex][frameColorStrong]); - painter->setBrush(Qt::NoBrush); - painter->drawRoundedRect(rect, secondLevelRoundingRadius + 0.5, secondLevelRoundingRadius + 0.5, Qt::AbsoluteSize); + QPen borderPen(Qt::NoPen); + if (!isOn && !isPartial) { + borderPen = highContrastTheme ? option->palette.buttonText().color() + : winUI3Color(frameColorStrong); + } + drawRoundedRect(painter, rect, borderPen, buttonFillBrush(option)); - painter->setFont(d->assetFont); - painter->setPen(option->palette.highlightedText().color()); - painter->setBrush(option->palette.highlightedText()); - if (option->state & State_On) + if (isOn) { + painter->setFont(d->assetFont); + painter->setPen(option->palette.color(QPalette::Window)); + QNumberStyleAnimation *animation = qobject_cast<QNumberStyleAnimation *>( + d->animation(option->styleObject)); + QFontMetrics fm(d->assetFont); + float clipWidth = animation != nullptr ? animation->currentValue() : 1.0f; + QRectF clipRect = fm.boundingRect(QStringLiteral(u"\uE73E")); + clipRect.moveCenter(center); + clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0); + clipRect.setWidth(clipWidth * clipRect.width()); painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, QStringLiteral(u"\uE73E")); - else if (option->state & State_NoChange) - painter->drawText(rect, Qt::AlignVCenter | Qt::AlignHCenter, QStringLiteral(u"\uE73C")); + } else if (isPartial) { + painter->setFont(d->assetFont); + painter->setPen(option->palette.color(QPalette::Window)); + painter->drawText(rect, Qt::AlignCenter, QStringLiteral(u"\uE73C")); + } } break; case PE_IndicatorBranch: { @@ -814,9 +799,9 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption } } break; - case PE_IndicatorRadioButton: - { + case PE_IndicatorRadioButton: { const bool isRtl = option->direction == Qt::RightToLeft; + const bool isOn = option->state & State_On; qreal innerRadius = option->state & State_On ? 4.0f :7.0f; if (option->styleObject) { if (option->styleObject->property("_q_end_radius").isNull()) @@ -826,34 +811,26 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption option->styleObject->setProperty("_q_inner_radius", innerRadius); } - QPainterPath path; QRectF rect = isRtl ? option->rect.adjusted(0, 0, -2, 0) : option->rect.adjusted(2, 0, 0, 0); - QPointF center = QPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2); - rect.setWidth(15); - rect.setHeight(15); - rect.moveCenter(center); - QRectF innerRect = rect; - innerRect.setWidth(8); - innerRect.setHeight(8); - innerRect.moveCenter(center); - - painter->setPen(Qt::NoPen); - painter->setBrush(option->palette.accent()); - path.addEllipse(center,7,7); - path.addEllipse(center,innerRadius,innerRadius); - painter->drawPath(path); - - painter->setPen(WINUI3Colors[colorSchemeIndex][frameColorStrong]); - painter->setBrush(Qt::NoBrush); - painter->drawEllipse(center, 7.5, 7.5); - painter->drawEllipse(center,innerRadius + 0.5, innerRadius + 0.5); + const QPointF center = rect.center(); - painter->setPen(Qt::NoPen); - if (option->state & State_MouseOver && option->state & State_Enabled) - painter->setBrush(option->palette.window().color().darker(107)); - else - painter->setBrush(option->palette.window()); - painter->drawEllipse(center,innerRadius, innerRadius); + if (isOn) { + painter->setPen(Qt::NoPen); + painter->setBrush(buttonFillBrush(option)); + QPainterPath path; + path.addEllipse(center, 7.5, 7.5); + path.addEllipse(center, innerRadius, innerRadius); + painter->drawPath(path); + QColor fillColor = option->palette.window().color(); + if (option->state & State_MouseOver && option->state & State_Enabled) + fillColor = fillColor.darker(107); + painter->setBrush(fillColor); + painter->drawEllipse(center, innerRadius, innerRadius); + } else { + painter->setPen(winUI3Color(frameColorStrong)); + painter->setBrush(buttonFillBrush(option)); + painter->drawEllipse(center, 7.5, 7.5); + } } break; case PE_PanelButtonTool: @@ -910,7 +887,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption } case PE_PanelLineEdit: if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) { - const auto frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); drawRoundedRect(painter, frameRect, Qt::NoPen, option->palette.brush(QPalette::Base)); if (panel->lineWidth > 0) @@ -922,12 +899,14 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption drawRoundedRect(painter, frameRect, Qt::NoPen, winUI3Color(subtleHighlightColor)); } break; - case PE_FrameLineEdit: - drawLineEditFrame(painter, option); + case PE_FrameLineEdit: { + const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); + drawLineEditFrame(painter, frameRect, option); break; + } case PE_Frame: { if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) { - const auto rect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); if (qobject_cast<const QComboBoxPrivateContainer *>(widget)) { QPen pen; if (highContrastTheme) @@ -941,7 +920,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption if (frame->frameShape == QFrame::NoFrame) break; - drawLineEditFrame(painter, option, qobject_cast<const QTextEdit *>(widget) != nullptr); + drawLineEditFrame(painter, rect, option, qobject_cast<const QTextEdit *>(widget) != nullptr); } break; } @@ -1697,18 +1676,13 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op } const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver); if (highlightCurrent) { - const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget); - if (highContrastTheme) + if (highContrastTheme) { painter->setBrush(vopt->palette.highlight()); - else - painter->setBrush(view->alternatingRowColors() ? vopt->palette.highlight() : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]); - QWidget *editorWidget = view ? view->indexWidget(view->currentIndex()) : nullptr; - if (editorWidget) { - QPalette pal = editorWidget->palette(); - QColor editorBgColor = vopt->backgroundBrush == Qt::NoBrush ? vopt->palette.color(widget->backgroundRole()) : vopt->backgroundBrush.color(); - editorBgColor.setAlpha(255); - pal.setColor(editorWidget->backgroundRole(), editorBgColor); - editorWidget->setPalette(pal); + } else { + const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget); + painter->setBrush(view && view->alternatingRowColors() + ? vopt->palette.highlight() + : winUI3Color(subtleHighlightColor)); } } else { painter->setBrush(vopt->backgroundBrush); @@ -2212,8 +2186,9 @@ void QWindows11Style::polish(QWidget* widget) pal.setColor(scrollarea->viewport()->backgroundRole(), Qt::transparent); scrollarea->viewport()->setPalette(pal); scrollarea->viewport()->setProperty("_q_original_background_palette", originalPalette); - if (qobject_cast<QTableView *>(widget)) - widget->setAttribute(Qt::WA_Hover, true); + // QTreeView & QListView are already set in the base windowsvista style + if (auto table = qobject_cast<QTableView *>(widget)) + table->viewport()->setAttribute(Qt::WA_Hover, true); } } @@ -2249,10 +2224,11 @@ static void populateLightSystemBasePalette(QPalette &result) static QString oldStyleSheet; const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet(); - const QColor textColor = QColor(0x00,0x00,0x00,0xE4); - const QColor textDisabled = QColor(0x00,0x00,0x00,0x5C); - const QColor btnFace = QColor(0xFF,0xFF,0xFF,0xB3); - const QColor alternateBase = QColor(0x00,0x00,0x00,0x09); + constexpr QColor textColor = QColor(0x00,0x00,0x00,0xE4); + constexpr QColor textDisabled = QColor(0x00, 0x00, 0x00, 0x5C); + constexpr QColor btnFace = QColor(0xFF, 0xFF, 0xFF, 0xB3); + constexpr QColor base = QColor(0xFF, 0xFF, 0xFF, 0xFF); + constexpr QColor alternateBase = QColor(0x00, 0x00, 0x00, 0x09); const QColor btnHighlight = result.accent().color(); const QColor btnColor = result.button().color(); @@ -2264,7 +2240,7 @@ static void populateLightSystemBasePalette(QPalette &result) SET_IF_UNRESOLVED(QPalette::Active, QPalette::Mid, btnColor.darker(150)); SET_IF_UNRESOLVED(QPalette::Active, QPalette::Text, textColor); SET_IF_UNRESOLVED(QPalette::Active, QPalette::BrightText, btnHighlight); - SET_IF_UNRESOLVED(QPalette::Active, QPalette::Base, btnFace); + SET_IF_UNRESOLVED(QPalette::Active, QPalette::Base, base); SET_IF_UNRESOLVED(QPalette::Active, QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF)); SET_IF_UNRESOLVED(QPalette::Active, QPalette::ButtonText, textColor); SET_IF_UNRESOLVED(QPalette::Active, QPalette::Midlight, btnColor.lighter(125)); @@ -2281,7 +2257,7 @@ static void populateLightSystemBasePalette(QPalette &result) SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Mid, btnColor.darker(150)); SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Text, textColor); SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::BrightText, btnHighlight); - SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Base, btnFace); + SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Base, base); SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF)); SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::ButtonText, textColor); SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Midlight, btnColor.lighter(125)); @@ -2302,7 +2278,7 @@ static void populateDarkSystemBasePalette(QPalette &result) static QString oldStyleSheet; const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet(); - const QColor alternateBase = QColor(0xFF,0xFF,0xFF,0x0F); + constexpr QColor alternateBase = QColor(0xFF, 0xFF, 0xFF, 0x0F); SET_IF_UNRESOLVED(QPalette::Active, QPalette::AlternateBase, alternateBase); @@ -2356,7 +2332,7 @@ QBrush QWindows11Style::buttonFillBrush(const QStyleOption *option) if (!isOn && option->state & QStyle::State_AutoRaise) return Qt::NoBrush; if (option->state & QStyle::State_MouseOver) - brush.setColor(isOn ? brush.color().lighter(107) : brush.color().darker(107)); + brush.setColor(isOn ? brush.color().lighter(115) : brush.color().darker(107)); return brush; } @@ -2376,9 +2352,8 @@ QColor QWindows11Style::buttonLabelColor(const QStyleOption *option, int colorSc : option->palette.buttonText().color(); } -void QWindows11Style::drawLineEditFrame(QPainter *p, const QStyleOption *o, bool isEditable) const +void QWindows11Style::drawLineEditFrame(QPainter *p, const QRectF &rect, const QStyleOption *o, bool isEditable) const { - const auto rect = QRectF(o->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); const bool isHovered = o->state & State_MouseOver; const auto frameCol = highContrastTheme ? o->palette.color(isHovered ? QPalette::Accent diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h index 51514737259..eccedc5bf67 100644 --- a/src/plugins/styles/modernwindows/qwindows11style_p.h +++ b/src/plugins/styles/modernwindows/qwindows11style_p.h @@ -75,7 +75,7 @@ protected: private: static inline QBrush buttonFillBrush(const QStyleOption *option); static inline QColor buttonLabelColor(const QStyleOption *option, int colorSchemeIndex); - void drawLineEditFrame(QPainter *p, const QStyleOption *o, bool isEditable = true) const; + void drawLineEditFrame(QPainter *p, const QRectF &rect, const QStyleOption *o, bool isEditable = true) const; inline QColor winUI3Color(enum WINUI3Color col) const; private: diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp index 0301b770a1e..52a98b0f9bb 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp @@ -2301,6 +2301,14 @@ int QWindowsVistaStyle::styleHint(StyleHint hint, const QStyleOption *option, co ret = 1; break; + case SH_ComboBox_ListMouseTracking_Current: + ret = 0; + break; + + case SH_ComboBox_ListMouseTracking_Active: + ret = 1; + break; + default: ret = QWindowsStyle::styleHint(hint, option, widget, returnData); break; diff --git a/src/printsupport/REUSE.toml b/src/printsupport/REUSE.toml index 8b6274a751a..e9c18925d17 100644 --- a/src/printsupport/REUSE.toml +++ b/src/printsupport/REUSE.toml @@ -3,23 +3,23 @@ version = 1 [[annotations]] path = ["dialogs/*.ui", "widgets/*.ui", "dialogs/images/*.png"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" [[annotations]] path = ["doc/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" [[annotations]] path = ["**.json"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] path = ["doc/snippets/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index 6f4611d9139..d8e10343854 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -561,9 +561,9 @@ QSqlError QSqlQueryModel::lastError() const \sa lastError() */ -void QSqlQueryModel::setLastError(const QSqlError &error) const +void QSqlQueryModel::setLastError(const QSqlError &error) { - Q_D(const QSqlQueryModel); + Q_D(QSqlQueryModel); d->error = error; } diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h index 24877118865..72b9b053f03 100644 --- a/src/sql/models/qsqlquerymodel.h +++ b/src/sql/models/qsqlquerymodel.h @@ -79,7 +79,7 @@ protected: virtual void queryChange(); virtual QModelIndex indexInQuery(const QModelIndex &item) const; - void setLastError(const QSqlError &error) const; + void setLastError(const QSqlError &error); QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = nullptr); }; diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index e93c3038fca..a27c52f5a99 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -1475,10 +1475,23 @@ bool readInputFile(Options *options) for (const QJsonValue &value : permissions) { if (value.isObject()) { QJsonObject permissionObj = value.toObject(); - QString name = permissionObj.value("name"_L1).toString(); + QString name; QString extras; - if (permissionObj.contains("extras"_L1)) - extras = permissionObj.value("extras"_L1).toString().trimmed(); + for (auto it = permissionObj.begin(); it != permissionObj.end(); ++it) { + if (it.key() == "name"_L1) { + name = it.value().toString(); + } else { + extras.append(" android:"_L1) + .append(it.key()) + .append("=\""_L1) + .append(it.value().toString()) + .append("\""_L1); + } + } + if (name.isEmpty()) { + fprintf(stderr, "Missing permission 'name' in permission specification"); + return false; + } options->applicationPermissions.insert(name, extras); } } @@ -1580,8 +1593,11 @@ bool copyAndroidTemplate(const Options &options) if (options.verbose) fprintf(stdout, "Copying Android package template.\n"); - if (!copyGradleTemplate(options)) - return false; + if (!options.auxMode) { + // Gradle is not configured and is not running in aux mode + if (!copyGradleTemplate(options)) + return false; + } if (!copyAndroidTemplate(options, "/src/android/templates"_L1)) return false; diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index eb4c84fbd75..564a332c091 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -40,6 +40,7 @@ struct Options QString buildPath; QString manifestPath; QString adbCommand{"adb"_L1}; + QString bundletoolPath; QString serial; QString makeCommand; QString package; @@ -48,7 +49,7 @@ struct Options QString stdoutFileName; QHash<QString, QString> outFiles; QStringList amStarttestArgs; - QString apkPath; + QString packagePath; QString ndkStackPath; QList<QStringList> preTestRunAdbCommands; bool showLogcatOutput = false; @@ -114,6 +115,24 @@ static bool execAdbCommand(const QStringList &args, QByteArray *output = nullptr return execCommand(g_options.adbCommand, argsWithSerial, output, verbose); } +static bool execBundletoolCommand(const QStringList &args, QByteArray *output = nullptr, + bool verbose = true) +{ + QString java("java"_L1); + QStringList argsFull = QStringList() << "-jar"_L1 << g_options.bundletoolPath << args; + return execCommand(java, argsFull, output, verbose); +} + +static void setPackagePath(const QString &path) +{ + if (!g_options.packagePath.isEmpty()) { + qCritical("Both --aab and --apk options provided. This is not supported."); + g_options.helpRequested = true; + return; + } + g_options.packagePath = path; +} + static bool execCommand(const QString &command, QByteArray *output = nullptr, bool verbose = true) { auto args = QProcess::splitCommand(command); @@ -133,6 +152,11 @@ static bool parseOptions() g_options.helpRequested = true; else g_options.adbCommand = arguments.at(++i); + } else if (argument.compare("--bundletool"_L1, Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + g_options.helpRequested = true; + else + g_options.bundletoolPath = arguments.at(++i); } else if (argument.compare("--path"_L1, Qt::CaseInsensitive) == 0) { if (i + 1 == arguments.size()) g_options.helpRequested = true; @@ -152,7 +176,12 @@ static bool parseOptions() if (i + 1 == arguments.size()) g_options.helpRequested = true; else - g_options.apkPath = arguments.at(++i); + setPackagePath(arguments.at(++i)); + } else if (argument.compare("--aab"_L1, Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + g_options.helpRequested = true; + else + setPackagePath(arguments.at(++i)); } else if (argument.compare("--activity"_L1, Qt::CaseInsensitive) == 0) { if (i + 1 == arguments.size()) g_options.helpRequested = true; @@ -200,7 +229,7 @@ static bool parseOptions() for (;i < arguments.size(); ++i) g_options.testArgsList << arguments.at(i); - if (g_options.helpRequested || g_options.buildPath.isEmpty() || g_options.apkPath.isEmpty()) + if (g_options.helpRequested || g_options.buildPath.isEmpty() || g_options.packagePath.isEmpty()) return false; g_options.serial = qEnvironmentVariable("ANDROID_SERIAL"); @@ -222,52 +251,57 @@ static bool parseOptions() static void printHelp() { - qWarning( "Syntax: %s <options> -- [TESTARGS] \n" - "\n" - " Runs a Qt for Android test on an emulator or a device. Specify a device\n" - " using the environment variables ANDROID_SERIAL or ANDROID_DEVICE_SERIAL.\n" - " Returns the number of failed tests, -1 on test runner deployment related\n" - " failures or zero on success." - "\n" - " Mandatory arguments:\n" - " --path <path>: The path where androiddeployqt builds the android package.\n" - "\n" - " --make <make cmd>: make command to create an APK, for example:\n" - " \"cmake --build <build-dir> --target <target>_make_apk\".\n" - "\n" - " --apk <apk path>: The test apk path. The apk has to exist already, if it\n" - " does not exist the make command must be provided for building the apk.\n" - "\n" - " Optional arguments:\n" - " --adb <adb cmd>: The Android ADB command. If missing the one from\n" - " $PATH will be used.\n" - "\n" - " --activity <acitvity>: The Activity to run. If missing the first\n" - " activity from AndroidManifest.qml file will be used.\n" - "\n" - " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n" - "\n" - " --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n" - "\n" - " --show-logcat: Print Logcat output to stdout. If an ANR occurs during\n" - " the test run, logs from the system_server process are included.\n" - " This argument is implied if a test crashes.\n" - "\n" - " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n" - " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n" - "\n" - " -- Arguments that will be passed to the test application.\n" - "\n" - " --verbose: Prints out information during processing.\n" - "\n" - " --pre-test-adb-command <command>: call the adb <command> after\n" - " installation and before the test run.\n" - "\n" - " --manifest <path>: Custom path to the AndroidManifest.xml.\n" - "\n" - " --help: Displays this information.\n", - qPrintable(QCoreApplication::arguments().at(0)) - ); + qWarning("Syntax: %s <options> -- [TESTARGS] \n" + "\n" + " Runs a Qt for Android test on an emulator or a device. Specify a device\n" + " using the environment variables ANDROID_SERIAL or ANDROID_DEVICE_SERIAL.\n" + " Returns the number of failed tests, -1 on test runner deployment related\n" + " failures or zero on success." + "\n" + " Mandatory arguments:\n" + " --path <path>: The path where androiddeployqt builds the android package.\n" + "\n" + " --make <make cmd>: make command to create an APK, for example:\n" + " \"cmake --build <build-dir> --target <target>_make_apk\".\n" + "\n" + " --apk <apk path>: The test apk path. The apk has to exist already, if it\n" + " does not exist the make command must be provided for building the apk.\n" + "\n" + " --aab <aab path>: The test aab path. The aab has to exist already, if it\n" + " does not exist the make command must be provided for building the aab.\n" + "\n" + " Optional arguments:\n" + " --adb <adb cmd>: The Android ADB command. If missing the one from\n" + " $PATH will be used.\n" + "\n" + " --activity <acitvity>: The Activity to run. If missing the first\n" + " activity from AndroidManifest.qml file will be used.\n" + "\n" + " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n" + "\n" + " --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n" + "\n" + " --show-logcat: Print Logcat output to stdout. If an ANR occurs during\n" + " the test run, logs from the system_server process are included.\n" + " This argument is implied if a test crashes.\n" + "\n" + " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n" + " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n" + "\n" + " -- Arguments that will be passed to the test application.\n" + "\n" + " --verbose: Prints out information during processing.\n" + "\n" + " --pre-test-adb-command <command>: call the adb <command> after\n" + " installation and before the test run.\n" + "\n" + " --manifest <path>: Custom path to the AndroidManifest.xml.\n" + "\n" + " --bundletool <bundletool path>: The path to Android bundletool.\n" + " See https://developer.android.com/tools/bundletool for details.\n" + "\n" + " --help: Displays this information.\n", + qPrintable(QCoreApplication::arguments().at(0))); } static QString packageNameFromAndroidManifest(const QString &androidManifestPath) @@ -850,10 +884,10 @@ int main(int argc, char *argv[]) return EXIT_ERROR; } - if (!QFile::exists(g_options.apkPath)) { + if (!QFile::exists(g_options.packagePath)) { qCritical("No apk \"%s\" found after running the make command. " "Check the provided path and the make command.", - qPrintable(g_options.apkPath)); + qPrintable(g_options.packagePath)); return EXIT_ERROR; } @@ -886,11 +920,22 @@ int main(int argc, char *argv[]) // do not install or run packages while another test is running testRunnerLock.acquire(); - const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.apkPath }; - g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr)); - if (!g_testInfo.isPackageInstalled) - return EXIT_ERROR; + if (g_options.packagePath.endsWith(".apk"_L1)) { + const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.packagePath }; + g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr)); + if (!g_testInfo.isPackageInstalled) + return EXIT_ERROR; + } else if (g_options.packagePath.endsWith(".aab"_L1)) { + QFileInfo aab(g_options.packagePath); + const auto apksFilePath = aab.absoluteDir().absoluteFilePath(aab.baseName() + ".apks"_L1); + if (!execBundletoolCommand({ "build-apks"_L1, "--bundle"_L1, g_options.packagePath, + "--output"_L1, apksFilePath, "--local-testing"_L1, + "--overwrite"_L1 })) + return EXIT_ERROR; + if (!execBundletoolCommand({ "install-apks"_L1, "--apks"_L1, apksFilePath })) + return EXIT_ERROR; + } // Call additional adb command if set after installation and before starting the test for (const auto &command : g_options.preTestRunAdbCommands) { QByteArray output; diff --git a/src/tools/uic/ui4.cpp b/src/tools/uic/ui4.cpp index b6a8f4eb4bf..e26d0260682 100644 --- a/src/tools/uic/ui4.cpp +++ b/src/tools/uic/ui4.cpp @@ -54,6 +54,10 @@ void DomUI::read(QXmlStreamReader &reader) setAttributeIdbasedtr(attribute.value() == u"true"_s); continue; } + if (name == u"label"_s) { + setAttributeLabel(attribute.value().toString()); + continue; + } if (name == u"connectslotsbyname"_s) { setAttributeConnectslotsbyname(attribute.value() == u"true"_s); continue; @@ -192,6 +196,9 @@ void DomUI::write(QXmlStreamWriter &writer, const QString &tagName) const if (hasAttributeIdbasedtr()) writer.writeAttribute(u"idbasedtr"_s, (attributeIdbasedtr() ? u"true"_s : u"false"_s)); + if (hasAttributeLabel()) + writer.writeAttribute(u"label"_s, attributeLabel()); + if (hasAttributeConnectslotsbyname()) writer.writeAttribute(u"connectslotsbyname"_s, (attributeConnectslotsbyname() ? u"true"_s : u"false"_s)); diff --git a/src/tools/uic/ui4.h b/src/tools/uic/ui4.h index 333f7f4e6ad..a46a42c6b73 100644 --- a/src/tools/uic/ui4.h +++ b/src/tools/uic/ui4.h @@ -143,6 +143,11 @@ public: inline void setAttributeIdbasedtr(bool a) { m_attr_idbasedtr = a; m_has_attr_idbasedtr = true; } inline void clearAttributeIdbasedtr() { m_has_attr_idbasedtr = false; } + inline bool hasAttributeLabel() const { return m_has_attr_label; } + inline QString attributeLabel() const { return m_attr_label; } + inline void setAttributeLabel(const QString &a) { m_attr_label = a; m_has_attr_label = true; } + inline void clearAttributeLabel() { m_attr_label.clear(); } + inline bool hasAttributeConnectslotsbyname() const { return m_has_attr_connectslotsbyname; } inline bool attributeConnectslotsbyname() const { return m_attr_connectslotsbyname; } inline void setAttributeConnectslotsbyname(bool a) { m_attr_connectslotsbyname = a; m_has_attr_connectslotsbyname = true; } @@ -264,6 +269,9 @@ private: bool m_attr_idbasedtr = false; bool m_has_attr_idbasedtr = false; + QString m_attr_label; + bool m_has_attr_label = false; + bool m_attr_connectslotsbyname = false; bool m_has_attr_connectslotsbyname = false; diff --git a/src/widgets/REUSE.toml b/src/widgets/REUSE.toml index 98653c588bb..0bfd718750e 100644 --- a/src/widgets/REUSE.toml +++ b/src/widgets/REUSE.toml @@ -3,24 +3,24 @@ version = 1 [[annotations]] path = ["styles/images/*.png", "dialogs/images/*.png", "styles/images/*.svg"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only" [[annotations]] path = ["doc/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" [[annotations]] path = ["doc/snippets/**"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" [[annotations]] path = ["doc/snippets/common-table-model/README"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index f9d58e4d906..acb63c4aa9b 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -562,6 +562,10 @@ void QMessageBoxPrivate::helperClicked(QPlatformDialogHelper::StandardButton hel and \l{QMessageBox::standardButtons} {standard buttons} for accepting a user response. + While the parent parameter is optional, specifying it gives a hint + to the window manager, which can then take care of positioning, and + maintain a proper stacking order of the dialog window. + Two APIs for using QMessageBox are provided, the property-based API, and the static functions. Calling one of the static functions is the simpler approach, but it is less flexible than using the diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp index ebc07025ec0..062e2e5142a 100644 --- a/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp +++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp @@ -12,7 +12,7 @@ int ret = QMessageBox::warning(this, tr("My Application"), //! [2] -QMessageBox msgBox; +QMessageBox msgBox(this); QPushButton *connectButton = msgBox.addButton(tr("Connect"), QMessageBox::ActionRole); QPushButton *abortButton = msgBox.addButton(QMessageBox::Abort); @@ -53,13 +53,13 @@ int main(int argc, char *argv[]) //! [4] //! [5] -QMessageBox msgBox; +QMessageBox msgBox(this); msgBox.setText("The document has been modified."); msgBox.exec(); //! [5] //! [6] -QMessageBox msgBox; +QMessageBox msgBox(this); msgBox.setText("The document has been modified."); msgBox.setInformativeText("Do you want to save your changes?"); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index b2fa08e406f..06912d41582 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -3671,10 +3671,8 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool executePostedLayout(); - if (noSectionMemoryUsage() && - (hasAutoResizeSections() || (useGlobalMode && globalResizeMode != QHeaderView::Fixed))) { + if (noSectionMemoryUsage() && (hasAutoResizeSections() || globalMode != QHeaderView::Fixed)) setHeaderMode(HeaderMode::FlexibleWithSectionMemoryUsage); - } if (sectionCount() == 0 ) return; diff --git a/src/widgets/kernel/qtestsupport_widgets.cpp b/src/widgets/kernel/qtestsupport_widgets.cpp index 5a7200e58aa..ce40ba8c6dd 100644 --- a/src/widgets/kernel/qtestsupport_widgets.cpp +++ b/src/widgets/kernel/qtestsupport_widgets.cpp @@ -31,6 +31,17 @@ static bool qWaitForWidgetWindow(QWidget *w, Predicate predicate, QDeadlineTimer /*! \since 5.0 + \overload + + The \a timeout is in milliseconds. +*/ +bool QTest::qWaitForWindowActive(QWidget *widget, int timeout) +{ + return qWaitForWindowActive(widget, QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer}); +} + +/*! + \since 6.10 Returns \c true if \a widget is active within \a timeout milliseconds. Otherwise returns \c false. @@ -45,7 +56,7 @@ static bool qWaitForWidgetWindow(QWidget *w, Predicate predicate, QDeadlineTimer \sa qWaitForWindowExposed(), QWidget::isActiveWindow() */ -Q_WIDGETS_EXPORT bool QTest::qWaitForWindowActive(QWidget *widget, int timeout) +bool QTest::qWaitForWindowActive(QWidget *widget, QDeadlineTimer timeout) { if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) { qWarning() << "qWaitForWindowActive was called on a platform that doesn't support window" @@ -57,9 +68,19 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowActive(QWidget *widget, int timeout) } return qWaitForWidgetWindow(widget, [&](QWindow *window) { return window->isActive(); }, - QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer}); + timeout); } +/*! + \since 6.10 + \overload + + This function uses the default timeout of 5 seconds. +*/ +bool QTest::qWaitForWindowActive(QWidget *widget) +{ + return qWaitForWindowActive(widget, Internal::defaultTryTimeout); +} /*! \since 6.7 @@ -86,7 +107,30 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowFocused(QWidget *widget, QDeadlineTim } /*! + \since 6.10 + \overload + + This function uses the default timeout of 5 seconds. +*/ +bool QTest::qWaitForWindowFocused(QWidget *widget) +{ + return qWaitForWindowFocused(widget, Internal::defaultTryTimeout); +} + +/*! \since 5.0 + \overload + + The \a timeout is in milliseconds. +*/ +bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout) +{ + return qWaitForWindowExposed(widget, std::chrono::milliseconds(timeout)); +} + + +/*! + \since 6.10 Returns \c true if \a widget is exposed within \a timeout milliseconds. Otherwise returns \c false. @@ -99,11 +143,22 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowFocused(QWidget *widget, QDeadlineTim \sa qWaitForWindowActive(), QWidget::isVisible(), QWindow::isExposed() */ -Q_WIDGETS_EXPORT bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout) +bool QTest::qWaitForWindowExposed(QWidget *widget, QDeadlineTimer timeout) { return qWaitForWidgetWindow(widget, [&](QWindow *window) { return window->isExposed(); }, - QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer}); + timeout); +} + +/*! + \since 6.10 + \overload + + This function uses the default timeout of 5 seconds. +*/ +bool QTest::qWaitForWindowExposed(QWidget *widget) +{ + return qWaitForWindowExposed(widget, Internal::defaultTryTimeout); } namespace QTest { diff --git a/src/widgets/kernel/qtestsupport_widgets.h b/src/widgets/kernel/qtestsupport_widgets.h index b49e68db651..4b5e5ff7772 100644 --- a/src/widgets/kernel/qtestsupport_widgets.h +++ b/src/widgets/kernel/qtestsupport_widgets.h @@ -14,9 +14,16 @@ class QWidget; namespace QTest { -[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, int timeout = 5000); -[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout = std::chrono::seconds{5}); -[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, int timeout = 5000); +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, int timeout); +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, QDeadlineTimer timeout); +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget); + +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout); +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget); + +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, int timeout); +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, QDeadlineTimer timeout); +[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget); class Q_WIDGETS_EXPORT QTouchEventWidgetSequence : public QTouchEventSequence { diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp index 17a19aa780d..c843927d366 100644 --- a/src/widgets/kernel/qwidgetsvariant.cpp +++ b/src/widgets/kernel/qwidgetsvariant.cpp @@ -11,18 +11,16 @@ QT_BEGIN_NAMESPACE namespace { - -// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class -static constexpr struct : QMetaTypeModuleHelper +struct QVariantWidgetsHelper : QMetaTypeModuleHelper { - const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { + static const QtPrivate::QMetaTypeInterface *interfaceForType(int type) + { switch (type) { QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE) default: return nullptr; } } -} qVariantWidgetsHelper; - +}; #undef QT_IMPL_METATYPEINTERFACE_WIDGETS_TYPES @@ -30,7 +28,9 @@ static constexpr struct : QMetaTypeModuleHelper void qRegisterWidgetsVariant() { - qMetaTypeWidgetsHelper = &qVariantWidgetsHelper; + qMetaTypeWidgetsHelper = QMetaTypeModuleHelper{ + &QVariantWidgetsHelper::interfaceForType, + }; } Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 4cf2934a2dc..b85446121bd 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -622,7 +622,21 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) } } QApplicationPrivate::replayMousePress = false; +#ifndef QT_NO_CONTEXTMENU + } else if (event->type() == QGuiApplicationPrivate::contextMenuEventType() + && event->button() == Qt::RightButton) { + QWidget *receiver = activePopupWidget; + if (qt_button_down) + receiver = qt_button_down; + else if (popupChild) + receiver = popupChild; + const QPoint localPos = receiver->mapFromGlobal(event->globalPosition().toPoint()); + QContextMenuEvent e(QContextMenuEvent::Mouse, localPos, event->globalPosition().toPoint(), event->modifiers()); + QApplication::forwardEvent(receiver, &e, event); + } +#else } +#endif if (releaseAfter) { qt_button_down = nullptr; diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index b5972411534..60ec043d094 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -5434,7 +5434,8 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget case SH_Menu_AllowActiveAndDisabled: case SH_Menu_SpaceActivatesItem: case SH_ScrollView_FrameOnlyAroundContents: - case SH_ComboBox_ListMouseTracking: + case SH_ComboBox_ListMouseTracking_Current: + case SH_ComboBox_ListMouseTracking_Active: case SH_Menu_MouseTracking: case SH_MenuBar_MouseTracking: case SH_ItemView_ChangeHighlightOnFocus: diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index e9cc250c517..c341a025115 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -591,7 +591,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) painter->setPen(highlightedOutline); else - painter->setPen(colorScheme() == Qt::ColorScheme::Dark ? outline.lighter(150) + painter->setPen(colorScheme() == Qt::ColorScheme::Dark ? outline.lighter(240) : outline.lighter(110)); painter->drawRect(rect); diff --git a/src/widgets/styles/qfusionstyle_p_p.h b/src/widgets/styles/qfusionstyle_p_p.h index 67abdd74dc8..62641609d59 100644 --- a/src/widgets/styles/qfusionstyle_p_p.h +++ b/src/widgets/styles/qfusionstyle_p_p.h @@ -70,10 +70,7 @@ public: } if (pal.window().style() == Qt::TexturePattern) return QColor(0, 0, 0, 160); - if (colorScheme() == Qt::ColorScheme::Dark) - return pal.window().color().lighter(140); - else - return pal.window().color().darker(140); + return pal.window().color().darker(140); } QColor highlightedOutline(const QPalette &pal) const { diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 6bb0728cfd4..e72e645e69c 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1736,8 +1736,16 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, by pressing Alt, followed by using the arrow keys to select the desired item. - \value SH_ComboBox_ListMouseTracking Mouse tracking in combobox - drop-down lists. + \value SH_ComboBox_ListMouseTracking_Current Mouse tracking in + combobox drop-down lists, the item under the cursor is made + the current item (QStyle::State_Selected). + + \value SH_ComboBox_ListMouseTracking same as + SH_ComboBox_ListMouseTracking_Current + + \value SH_ComboBox_ListMouseTracking_Active Mouse tracking in + combobox drop-down lists, the item under the cursor is not + made the current item, only active (QStyle::State_MouseOver). \value SH_Menu_MouseTracking Mouse tracking in popup menus. diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h index db09eedc70d..d6bccf9f698 100644 --- a/src/widgets/styles/qstyle.h +++ b/src/widgets/styles/qstyle.h @@ -602,6 +602,7 @@ public: SH_ScrollView_FrameOnlyAroundContents, SH_MenuBar_AltKeyNavigation, SH_ComboBox_ListMouseTracking, + SH_ComboBox_ListMouseTracking_Current = SH_ComboBox_ListMouseTracking, SH_Menu_MouseTracking, SH_MenuBar_MouseTracking, SH_ItemView_ChangeHighlightOnFocus, @@ -704,6 +705,7 @@ public: SH_TabBar_AllowWheelScrolling, SH_Table_AlwaysDrawLeftTopGridLines, SH_SpinBox_SelectOnStep, + SH_ComboBox_ListMouseTracking_Active, // Add new style hint values here SH_CustomBase = 0xf0000000 diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 08178e7b685..f4b21d3b70d 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -5269,7 +5269,11 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) { if (rule.baseStyleCanDraw()) { sz = baseStyle()->sizeFromContents(ct, opt, sz, w); - } else if (spinbox->buttonSymbols != QAbstractSpinBox::NoButtons) { + if (rule.hasBox() || !rule.hasNativeBorder()) + sz = rule.boxSize(sz); + return sz; + } + if (spinbox->buttonSymbols != QAbstractSpinBox::NoButtons) { // Add some space for the up/down buttons QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton); if (subRule.hasDrawable()) { diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 907628f224e..d6daa681798 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -461,7 +461,7 @@ int QWindowsStyle::styleHint(StyleHint hint, const QStyleOption *opt, const QWid case SH_MenuBar_AltKeyNavigation: case SH_MenuBar_MouseTracking: case SH_Menu_MouseTracking: - case SH_ComboBox_ListMouseTracking: + case SH_ComboBox_ListMouseTracking_Current: case SH_Slider_StopMouseOverSlider: case SH_MainWindow_SpaceBelowMenuBar: ret = 1; diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index fbec606ae4a..aa58ac8d75d 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -640,8 +640,10 @@ void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView) if (usePopup) view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); #endif - if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) || - usePopup) { + if (usePopup || + combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Current, &opt, combo) || + combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Active, &opt, combo) + ) { view->setMouseTracking(true); } view->setSelectionMode(QAbstractItemView::SingleSelection); @@ -775,10 +777,12 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) QPoint vector = widget->mapToGlobal(m->position().toPoint()) - initialClickPosition; if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive()) blockMouseReleaseTimer.stop(); - QModelIndex indexUnderMouse = view->indexAt(m->position().toPoint()); - if (indexUnderMouse.isValid() - && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { - view->setCurrentIndex(indexUnderMouse); + if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Current, nullptr, combo)) { + QModelIndex indexUnderMouse = view->indexAt(m->position().toPoint()); + if (indexUnderMouse.isValid() + && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { + view->setCurrentIndex(indexUnderMouse); + } } } break; diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp index f5d92094f54..c1ce675d75a 100644 --- a/src/widgets/widgets/qdockarealayout.cpp +++ b/src/widgets/widgets/qdockarealayout.cpp @@ -3327,7 +3327,8 @@ int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &or { int delta = 0; const auto dockPosition = static_cast<QInternal::DockPosition>(separator.last()); - const bool isHorizontal = dockPosition == QInternal::LeftDock || dockPosition == QInternal::TopDock; + const bool isHorizontal = + dockPosition == QInternal::LeftDock || dockPosition == QInternal::RightDock; const bool isLeftOrTop = dockPosition == QInternal::LeftDock || dockPosition == QInternal::TopDock; const bool separatorIsWithinDock = separator.size() > 1; diff --git a/src/widgets/widgets/qscrollbar.cpp b/src/widgets/widgets/qscrollbar.cpp index af7a2e011b8..92ccfe7db9d 100644 --- a/src/widgets/widgets/qscrollbar.cpp +++ b/src/widgets/widgets/qscrollbar.cpp @@ -126,8 +126,8 @@ using namespace Qt::StringLiterals; ScrollBar inherits a comprehensive set of signals from QAbstractSlider: \list \li \l{QAbstractSlider::valueChanged()}{valueChanged()} is emitted when the - scroll bar's value has changed. The tracking() determines whether this - signal is emitted during user interaction. + scroll bar's value has changed. The \l{QAbstractSlider::}{tracking} property + determines whether this signal is emitted during user interaction. \li \l{QAbstractSlider::rangeChanged()}{rangeChanged()} is emitted when the scroll bar's range of values has changed. \li \l{QAbstractSlider::sliderPressed()}{sliderPressed()} is emitted when diff --git a/src/widgets/widgets/qtoolbararealayout.cpp b/src/widgets/widgets/qtoolbararealayout.cpp index 54c21b60387..0d7227eb038 100644 --- a/src/widgets/widgets/qtoolbararealayout.cpp +++ b/src/widgets/widgets/qtoolbararealayout.cpp @@ -564,19 +564,19 @@ int QToolBarAreaLayoutInfo::distance(const QPoint &pos) const { switch (dockPos) { case QInternal::LeftDock: - if (pos.y() < rect.bottom()) + if (pos.y() > 0 && pos.y() < rect.bottom()) return pos.x() - rect.right(); break; case QInternal::RightDock: - if (pos.y() < rect.bottom()) + if (pos.y() > 0 && pos.y() < rect.bottom()) return rect.left() - pos.x(); break; case QInternal::TopDock: - if (pos.x() < rect.right()) + if (pos.x() > 0 && pos.x() < rect.right()) return pos.y() - rect.bottom(); break; case QInternal::BottomDock: - if (pos.x() < rect.right()) + if (pos.x() > 0 && pos.x() < rect.right()) return rect.top() - pos.y(); break; diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 7c4f33cddb6..f4789d115a6 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -70,7 +70,7 @@ enable_testing() # doesn't seem to be the case. # Until this is figured out, disable the tests when cross-compiling to Linux. if(UNIX AND NOT APPLE AND NOT WIN32 AND CMAKE_CROSSCOMPILING AND NOT QT_ENABLE_CMAKE_BOOT2QT_TESTS - AND NOT QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS) + AND NOT QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS AND NOT ANDROID) message(STATUS "Running CMake tests is disabled when cross-compiling to Linux / Boot2Qt.") return() endif() @@ -83,6 +83,12 @@ if(WIN32 AND CMAKE_CROSSCOMPILING) return() endif() +if(TARGET Qt6::Core) + # Tests are built as part of the qtbase build tree. + # Setup paths so that the Qt packages are found, similar to examples. + qt_internal_set_up_build_dir_package_paths() +endif() + set(required_packages Core Network Xml Sql Test TestInternalsPrivate) set(optional_packages DBus Gui Widgets PrintSupport OpenGL Concurrent) @@ -117,53 +123,73 @@ endif() include("${_Qt6CTestMacros}") -# Test only multi-abi specific functionality when QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS is ON. -# Qt::Gui is the prerequisite for all Android tests. -if(QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS AND NOT NO_GUI) - unset(multi_abi_vars) - foreach(abi IN LISTS QT_ANDROID_ABIS) - list(APPEND multi_abi_vars "-DQT_PATH_ANDROID_ABI_${abi}=${QT_PATH_ANDROID_ABI_${abi}}") - endforeach() - if(QT_ANDROID_BUILD_ALL_ABIS) - list(APPEND multi_abi_vars "-DQT_ANDROID_BUILD_ALL_ABIS=${QT_ANDROID_BUILD_ALL_ABIS}") + +if(ANDROID) + # Qt::Gui is the prerequisite for all Android tests. + if(NO_GUI) + return() endif() - list(APPEND multi_abi_vars "-DQT_HOST_PATH=${QT_HOST_PATH}") + set(common_android_vars "-DQT_HOST_PATH=${QT_HOST_PATH}") - set(multi_abi_forward_vars - TEST_SINGLE_VALUE_ARG - TEST_SPACES_VALUE_ARG - TEST_LIST_VALUE_ARG - TEST_ESCAPING_VALUE_ARG + _qt_internal_test_expect_pass(test_android_signing + BUILD_OPTIONS "${common_android_vars}" + BINARY ${CMAKE_CTEST_COMMAND} + BINARY_ARGS -V ) - string(REPLACE ";" "[[;]]" multi_abi_forward_vars "${multi_abi_forward_vars}") - - set(single_value "TestValue") - set(list_value "TestValue[[;]]TestValue2[[;]]TestValue3") - set(escaping_value "TestValue\\\\[[;]]TestValue2\\\\[[;]]TestValue3") - set(spaces_value "TestValue TestValue2 TestValue3") - _qt_internal_test_expect_pass(test_android_multi_abi_forward_vars - BUILD_OPTIONS - ${multi_abi_vars} - "-DQT_ANDROID_MULTI_ABI_FORWARD_VARS=${multi_abi_forward_vars}" - "-DTEST_SINGLE_VALUE_ARG=${single_value}" - "-DTEST_LIST_VALUE_ARG=${list_value}" - "-DTEST_ESCAPING_VALUE_ARG=${escaping_value}" - "-DTEST_SPACES_VALUE_ARG=${spaces_value}" + set_property(TEST test_android_signing APPEND PROPERTY ENVIRONMENT + "QT_ANDROID_KEYSTORE_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_android_signing/qttest.jks" + "QT_ANDROID_KEYSTORE_ALIAS=qttest" + "QT_ANDROID_KEYSTORE_STORE_PASS=qttest" + "QT_ANDROID_KEYSTORE_KEY_PASS=qttest" ) - #Run test_android_aar only if the host is Unix and zipinfo is available - find_program(ZIPINFO_EXECUTABLE zipinfo) - if(CMAKE_HOST_UNIX AND ZIPINFO_EXECUTABLE) - _qt_internal_test_expect_pass(test_android_aar + # Test only multi-abi specific functionality when QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS is + # ON. + if(QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS) + set(multi_abi_vars "${common_android_vars}") + foreach(abi IN LISTS QT_ANDROID_ABIS) + list(APPEND multi_abi_vars "-DQT_PATH_ANDROID_ABI_${abi}=${QT_PATH_ANDROID_ABI_${abi}}") + endforeach() + if(QT_ANDROID_BUILD_ALL_ABIS) + list(APPEND multi_abi_vars "-DQT_ANDROID_BUILD_ALL_ABIS=${QT_ANDROID_BUILD_ALL_ABIS}") + endif() + + set(multi_abi_forward_vars + TEST_SINGLE_VALUE_ARG + TEST_SPACES_VALUE_ARG + TEST_LIST_VALUE_ARG + TEST_ESCAPING_VALUE_ARG + ) + string(REPLACE ";" "[[;]]" multi_abi_forward_vars "${multi_abi_forward_vars}") + + set(single_value "TestValue") + set(list_value "TestValue[[;]]TestValue2[[;]]TestValue3") + set(escaping_value "TestValue\\\\[[;]]TestValue2\\\\[[;]]TestValue3") + set(spaces_value "TestValue TestValue2 TestValue3") + _qt_internal_test_expect_pass(test_android_multi_abi_forward_vars BUILD_OPTIONS ${multi_abi_vars} - --build-target verify_aar + "-DQT_ANDROID_MULTI_ABI_FORWARD_VARS=${multi_abi_forward_vars}" + "-DTEST_SINGLE_VALUE_ARG=${single_value}" + "-DTEST_LIST_VALUE_ARG=${list_value}" + "-DTEST_ESCAPING_VALUE_ARG=${escaping_value}" + "-DTEST_SPACES_VALUE_ARG=${spaces_value}" ) - else() - message(WARNING - "Skipping test_android_aar CMake build test because \ - the host is not Unix or zipinfo is not found") + + #Run test_android_aar only if the host is Unix and zipinfo is available + find_program(ZIPINFO_EXECUTABLE zipinfo) + if(CMAKE_HOST_UNIX AND ZIPINFO_EXECUTABLE) + _qt_internal_test_expect_pass(test_android_aar + BUILD_OPTIONS + ${multi_abi_vars} + --build-target verify_aar + ) + else() + message(WARNING + "Skipping test_android_aar CMake build test because \ + the host is not Unix or zipinfo is not found") + endif() endif() return() diff --git a/tests/auto/cmake/test_android_signing/CMakeLists.txt b/tests/auto/cmake/test_android_signing/CMakeLists.txt new file mode 100644 index 00000000000..b2d67676a69 --- /dev/null +++ b/tests/auto/cmake/test_android_signing/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.20) + +project(test_android_signing) + +enable_testing() + +find_program(keytool NAMES keytool) + +if(NOT keytool) + message("Skipping test_android_signing: keytool not found.") + return() +endif() + +if("$ENV{QT_ANDROID_KEYSTORE_PATH}" STREQUAL "" + OR "$ENV{QT_ANDROID_KEYSTORE_STORE_PASS}" STREQUAL "" + OR "$ENV{QT_ANDROID_KEYSTORE_ALIAS}" STREQUAL "" + OR "$ENV{QT_ANDROID_KEYSTORE_KEY_PASS}" STREQUAL "") + message(FATAL_ERROR "Environment variables QT_ANDROID_KEYSTORE_PATH," + " QT_ANDROID_KEYSTORE_STORE_PASS, QT_ANDROID_KEYSTORE_ALIAS, and" + " QT_ANDROID_KEYSTORE_KEY_PASS must be set to run this test.") +endif() + +find_package(Qt6 COMPONENTS Core Gui REQUIRED) + +set(QT_ANDROID_SIGN_AAB ON) +set(QT_ANDROID_SIGN_APK ON) + +execute_process(COMMAND ${keytool} + -genkey -alias "$ENV{QT_ANDROID_KEYSTORE_ALIAS}" -keyalg RSA + -keystore "$ENV{QT_ANDROID_KEYSTORE_PATH}" + -noprompt + -dname "CN=qttest, OU=ID, O=Qt, L=Qt, S=Test, C=DE" + -storepass "$ENV{QT_ANDROID_KEYSTORE_STORE_PASS}" + -keypass "$ENV{QT_ANDROID_KEYSTORE_KEY_PASS}" + RESULT_VARIABLE keytool_result +) + + +qt6_add_executable(test_android_signing main.cpp) + +target_link_libraries(test_android_signing PRIVATE + Qt6::Core + Qt6::Gui +) + +add_test(NAME test_android_signing_verify_signature + COMMAND "${CMAKE_COMMAND}" "-DKEYTOOL_PATH=${keytool}" + "-DAPK_FILE=${CMAKE_CURRENT_BINARY_DIR}/android-build/test_android_signing.apk" + -P "${CMAKE_CURRENT_SOURCE_DIR}/verify_signature.cmake" +) diff --git a/tests/auto/cmake/test_android_signing/main.cpp b/tests/auto/cmake/test_android_signing/main.cpp new file mode 100644 index 00000000000..2112a0de739 --- /dev/null +++ b/tests/auto/cmake/test_android_signing/main.cpp @@ -0,0 +1,4 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +int main(int, char *[]) { return 0; } diff --git a/tests/auto/cmake/test_android_signing/verify_signature.cmake b/tests/auto/cmake/test_android_signing/verify_signature.cmake new file mode 100644 index 00000000000..d4405a30201 --- /dev/null +++ b/tests/auto/cmake/test_android_signing/verify_signature.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT KEYTOOL_PATH) + message(FATAL_ERROR "KEYTOOL_PATH is missing.") +endif() + +if(NOT APK_FILE) + message(FATAL_ERROR "APK_FILE is missing.") +endif() + +execute_process( + COMMAND ${KEYTOOL_PATH} -printcert -jarfile ${APK_FILE} + RESULT_VARIABLE keytool_result + OUTPUT_VARIABLE keytool_output + ERROR_VARIABLE keytool_error +) + +if(NOT keytool_result EQUAL 0) + message(FATAL_ERROR "Keytool command failed with error: ${keytool_error}") +endif() + +if(NOT keytool_output MATCHES ".+Certificate #1:.+") + message(FATAL_ERROR "APK is not signed.") +endif() diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 781f64a31ab..66c3db2e2f0 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -228,6 +228,7 @@ private slots: void getCharFF(); void remove_and_exists(); void removeOpenFile(); + void removedFileDoesntExist(); void fullDisk(); void writeLargeDataBlock_data(); void writeLargeDataBlock(); @@ -2526,6 +2527,37 @@ void tst_QFile::removeOpenFile() } } +void tst_QFile::removedFileDoesntExist() +{ +#ifdef Q_OS_WIN + QSKIP("Not relevant for Windows - can't remove still-open files"); +#endif + QFile::remove("remove_unclosed.txt"); + QFile f("remove_unclosed.txt"); + QVERIFY(!f.exists()); + bool opened = f.open(QIODevice::ReadWrite | QIODevice::Unbuffered); + QVERIFY(opened); + f.write("blah blah blah"); + + QVERIFY(f.exists()); + + // delete by path, not using f.remove() (that's tested above) + QVERIFY(QFile::remove(f.fileName())); + QVERIFY(!QFile::exists(f.fileName())); + QVERIFY(!f.exists()); + +#ifdef Q_OS_LINUX + QString procPath = u"/proc/self/fd/"_s; + if (QFile::exists(procPath)) { + // reopen the deleted file + procPath += QString::number(f.handle()); + QFile f2(procPath); + QVERIFY(f2.open(QIODevice::ReadOnly)); + QVERIFY(!f2.exists()); + } +#endif +} + void tst_QFile::fullDisk() { QFile file("/dev/full"); diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 761f0552eec..e2190477441 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -141,6 +141,7 @@ private slots: void exists_data(); void exists(); + void deletedFileLinuxProcExists(); void absolutePath_data(); void absolutePath(); @@ -615,6 +616,34 @@ void tst_QFileInfo::exists() QVERIFY(!exists); } +void tst_QFileInfo::deletedFileLinuxProcExists() +{ +#ifdef Q_OS_LINUX + static const char msg[] = "Hello, World\n"; + QFileInfo fi("/proc/self/fd/"); + if (!fi.isDir()) + QSKIP("/proc appears not to be mounted"); + + QFile f("removed_file.txt"); + QVERIFY(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + f.write(msg, strlen(msg)); + + fi.setFile(fi.filePath() + QString::number(f.handle())); + QVERIFY(fi.exists()); + QCOMPARE(fi.size(), strlen(msg)); + + QFile::remove("removed_file.txt"); + fi.refresh(); + QVERIFY(fi.exists()); + + fi.refresh(); + QCOMPARE(fi.size(), strlen(msg)); // this stats, so may change flags + QVERIFY(fi.exists()); +#else + QSKIP("Linux-only test"); +#endif +} + void tst_QFileInfo::absolutePath_data() { QTest::addColumn<QString>("file"); diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 282c7f2e360..71389abc976 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -513,6 +513,7 @@ void tst_QUrl::comparison2() QCOMPARE(url1.toString(), url2.toString()); QCOMPARE(url1, url2); QCOMPARE(qHash(url1), qHash(url2)); + QCOMPARE(qHash(url1, 1), qHash(url2, 1)); } else if (ordering < 0) { QCOMPARE_LT(url1.toString(), url2.toString()); QCOMPARE_NE(url1, url2); @@ -1387,12 +1388,14 @@ void tst_QUrl::toString_constructed() QUrl parsed(asString); QCOMPARE(url, parsed); QCOMPARE(qHash(url), qHash(parsed)); + QCOMPARE(qHash(url, 1), qHash(parsed, 1)); } // clear it and ensure no memory of the previous state remains url.setUrl(QString()); QCOMPARE(url, QUrl()); QCOMPARE(qHash(url), qHash(QUrl())); + QCOMPARE(qHash(url, 1), qHash(QUrl(), 1)); } void tst_QUrl::toDisplayString_PreferLocalFile_data() @@ -4265,6 +4268,7 @@ void tst_QUrl::setComponents() QUrl recreated(toString); QCOMPARE(copy, recreated); QCOMPARE(qHash(copy), qHash(recreated)); + QCOMPARE(qHash(copy, 1), qHash(recreated, 1)); } else { QVERIFY(copy.toString().isEmpty()); } diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index b1e2e8164af..a5f23014b94 100644 --- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -708,6 +708,24 @@ void tst_QMetaObjectBuilder::property() prop2.setEnumOrFlag(false); \ prop2.setConstant(false); \ prop2.setFinal(false); \ + prop2.setBindable(false); \ + prop2.setRequired(false); \ + } while (0) +#define SET_ALL_FLAGS() \ + do { \ + prop2.setReadable(true); \ + prop2.setWritable(true); \ + prop2.setResettable(true); \ + prop2.setDesignable(true); \ + prop2.setScriptable(true); \ + prop2.setStored(true); \ + prop2.setUser(true); \ + prop2.setStdCppSet(true); \ + prop2.setEnumOrFlag(true); \ + prop2.setConstant(true); \ + prop2.setFinal(true); \ + prop2.setBindable(true); \ + prop2.setRequired(true); \ } while (0) #define COUNT_FLAGS() \ ((prop2.isReadable() ? 1 : 0) + \ @@ -720,15 +738,19 @@ void tst_QMetaObjectBuilder::property() (prop2.hasStdCppSet() ? 1 : 0) + \ (prop2.isEnumOrFlag() ? 1 : 0) + \ (prop2.isConstant() ? 1 : 0) + \ - (prop2.isFinal() ? 1 : 0)) + (prop2.isFinal() ? 1 : 0) + \ + (prop2.isBindable() ? 1 : 0) + \ + (prop2.isRequired() ? 1 : 0)) #define CHECK_FLAG(setFunc,isFunc) \ do { \ + ++flagCounter; \ CLEAR_FLAGS(); \ QCOMPARE(COUNT_FLAGS(), 0); \ prop2.setFunc(true); \ QVERIFY(prop2.isFunc()); \ QCOMPARE(COUNT_FLAGS(), 1); \ } while (0) + int flagCounter = 0; CHECK_FLAG(setReadable, isReadable); CHECK_FLAG(setWritable, isWritable); CHECK_FLAG(setResettable, isResettable); @@ -739,7 +761,11 @@ void tst_QMetaObjectBuilder::property() CHECK_FLAG(setStdCppSet, hasStdCppSet); CHECK_FLAG(setEnumOrFlag, isEnumOrFlag); CHECK_FLAG(setConstant, isConstant); + CHECK_FLAG(setBindable, isBindable); CHECK_FLAG(setFinal, isFinal); + CHECK_FLAG(setRequired, isRequired); + SET_ALL_FLAGS(); + QCOMPARE(COUNT_FLAGS(), flagCounter); // Check that nothing else changed. QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties)); diff --git a/tests/auto/corelib/platform/CMakeLists.txt b/tests/auto/corelib/platform/CMakeLists.txt index 3a66ec2eae6..9810947e3c6 100644 --- a/tests/auto/corelib/platform/CMakeLists.txt +++ b/tests/auto/corelib/platform/CMakeLists.txt @@ -5,7 +5,9 @@ if(ANDROID) add_subdirectory(android) add_subdirectory(android_appless) add_subdirectory(androiditemmodel) - add_subdirectory(android_legacy_packaging) + if(NOT QT_USE_ANDROID_MODERN_BUNDLE) + add_subdirectory(android_legacy_packaging) + endif() endif() if(WIN32) add_subdirectory(windows) diff --git a/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle b/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle index cbdd833e2ae..1d796d9b6b9 100644 --- a/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle +++ b/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle @@ -70,8 +70,8 @@ android { abortOnError = false } - // Do not compress Qt binary resources file aaptOptions { + // Do not compress Qt binary resources file noCompress 'rcc' } diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 3756937c94a..bfc6074689b 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -2470,7 +2470,8 @@ void tst_QLocale::formatTimeZone() // Time definitely in Standard Time const QStringList knownCETus = { u"GMT+1"_s, // ICU - u"CET"_s // Standard abbreviation + u"CET"_s, // Standard abbreviation + u"UTC+0100"_s, // used by Emscripten }; const QString cet = enUS.toString(QDate(2013, 1, 1).startOfDay(), u"t"); QVERIFY2(knownCETus.contains(cet), cet.isEmpty() ? "[empty]" : qPrintable(cet)); @@ -2478,7 +2479,8 @@ void tst_QLocale::formatTimeZone() // Time definitely in Daylight Time const QStringList knownCESTus = { u"GMT+2"_s, // ICU - u"CEST"_s // Standard abbreviation + u"CEST"_s, // Standard abbreviation + u"UTC+0200"_s, // used by Emscripten }; const QString cest = enUS.toString(QDate(2013, 6, 1).startOfDay(), u"t"); QVERIFY2(knownCESTus.contains(cest), cest.isEmpty() ? "[empty]" : qPrintable(cest)); diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 87d48d56e6b..5804aeeb1e5 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -73,22 +73,22 @@ void tst_QArrayData::referenceCounting() // Reference counting initialized to 1 (owned) QArrayData array = { Q_BASIC_ATOMIC_INITIALIZER(1), {}, 0 }; - QCOMPARE(array.m_ref.loadRelaxed(), 1); + QCOMPARE(array.ref_.loadRelaxed(), 1); QVERIFY(array.ref()); - QCOMPARE(array.m_ref.loadRelaxed(), 2); + QCOMPARE(array.ref_.loadRelaxed(), 2); QVERIFY(array.deref()); - QCOMPARE(array.m_ref.loadRelaxed(), 1); + QCOMPARE(array.ref_.loadRelaxed(), 1); QVERIFY(array.ref()); - QCOMPARE(array.m_ref.loadRelaxed(), 2); + QCOMPARE(array.ref_.loadRelaxed(), 2); QVERIFY(array.deref()); - QCOMPARE(array.m_ref.loadRelaxed(), 1); + QCOMPARE(array.ref_.loadRelaxed(), 1); QVERIFY(!array.deref()); - QCOMPARE(array.m_ref.loadRelaxed(), 0); + QCOMPARE(array.ref_.loadRelaxed(), 0); // Now would be a good time to free/release allocated data } diff --git a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp index 89bd1d7ff61..b53362b43e9 100644 --- a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp +++ b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp @@ -5,6 +5,10 @@ #include <QTest> +#include <chrono> + +using namespace std::chrono_literals; + class tst_QAtomicScopedValueRollback : public QObject { Q_OBJECT @@ -15,6 +19,7 @@ private Q_SLOTS: void rollbackToPreviousCommit(); void exceptions(); void earlyExitScope(); + void mixedTypes(); private: void earlyExitScope_helper(int exitpoint, std::atomic<int> &member); }; @@ -132,6 +137,90 @@ void tst_QAtomicScopedValueRollback::earlyExitScope() } } +template <typename T> +struct Wrap { +#if __cpp_deduction_guides < 201907L // no CTAD for aggregates + Q_IMPLICIT Wrap(T &t) : t{t} {} + Q_IMPLICIT Wrap(T &&t) : t{std::move(t)} {} +#endif + T t; + Q_IMPLICIT operator T() const { return t; } +}; + +void tst_QAtomicScopedValueRollback::mixedTypes() +{ + const auto relaxed = std::memory_order_relaxed; + { + std::atomic a{10'000ms}; + { + QAtomicScopedValueRollback rb(a, 5s); + QCOMPARE(a.load(relaxed), 5s); + } + QCOMPARE(a.load(relaxed), 10s); + { + QAtomicScopedValueRollback rb(a, 5s, relaxed); + QCOMPARE(a.load(relaxed), 5s); + } + QCOMPARE(a.load(relaxed), 10s); + } + { + QBasicAtomicInteger a{10'000}; + { + QAtomicScopedValueRollback rb(a, Wrap{5'000}); + QCOMPARE(a.loadRelaxed(), 5'000); + } + QCOMPARE(a.loadRelaxed(), 10'000); + { + QAtomicScopedValueRollback rb(a, Wrap{5'000}, relaxed); + QCOMPARE(a.loadRelaxed(), 5'000); + } + QCOMPARE(a.loadRelaxed(), 10'000); + } + { + QAtomicInteger a{10'000}; + { + QAtomicScopedValueRollback rb(a, Wrap{5'000}); + QCOMPARE(a.loadRelaxed(), 5'000); + } + QCOMPARE(a.loadRelaxed(), 10'000); + { + QAtomicScopedValueRollback rb(a, Wrap{5'000}, relaxed); + QCOMPARE(a.loadRelaxed(), 5'000); + } + QCOMPARE(a.loadRelaxed(), 10'000); + } + { + int i = 10'000; + int j = 5'000; + QBasicAtomicPointer a{&i}; + { + QAtomicScopedValueRollback rb(a, Wrap{&j}); + QCOMPARE(a.loadRelaxed(), &j); + } + QCOMPARE(a.loadRelaxed(), &i); + { + QAtomicScopedValueRollback rb(a, Wrap{&j}, relaxed); + QCOMPARE(a.loadRelaxed(), &j); + } + QCOMPARE(a.loadRelaxed(), &i); + } + { + int i = 10'000; + int j = 5'000; + QAtomicPointer a{&i}; + { + QAtomicScopedValueRollback rb(a, Wrap{&j}); + QCOMPARE(a.loadRelaxed(), &j); + } + QCOMPARE(a.loadRelaxed(), &i); + { + QAtomicScopedValueRollback rb(a, Wrap{&j}, relaxed); + QCOMPARE(a.loadRelaxed(), &j); + } + QCOMPARE(a.loadRelaxed(), &i); + } +} + static void operator*=(std::atomic<int> &lhs, int rhs) { int expected = lhs.load(); diff --git a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp index 36cf8ac8fd8..18fe43fbcea 100644 --- a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp +++ b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp @@ -35,6 +35,8 @@ private slots: void write(); void icoMask_data(); void icoMask(); + void origBitDepth_data(); + void origBitDepth(); private: QString m_IconPath; @@ -354,6 +356,40 @@ void tst_QIcoImageFormat::icoMask() QCOMPARE(inImage, outImage); } +void tst_QIcoImageFormat::origBitDepth_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QList<int>>("origBitDepths"); + + QTest::newRow("35FLOPPY") << "35FLOPPY.ICO" << QList<int>{4}; + QTest::newRow("abcardWindow") << "abcardWindow.ico" << QList<int>{8}; + QTest::newRow("AddPerf") << "AddPerfMon.ico" << QList<int>{4}; + QTest::newRow("App") << "App.ico" << QList<int>{4}; + QTest::newRow("Obj_N2_Internal_Mem") << "Obj_N2_Internal_Mem.ico" << QList<int>{4, 8, 32}; + QTest::newRow("Qt") << "Qt.ico" << QList<int>{32}; + QTest::newRow("semitransparent") << "semitransparent.ico" << QList<int>{4}; + QTest::newRow("Status_Play") << "Status_Play.ico" << QList<int>{4, 8, 32}; + QTest::newRow("TIMER01") << "TIMER01.ICO" << QList<int>{4}; + QTest::newRow("trolltechlogo_tiny") << "trolltechlogo_tiny.ico" << QList<int>{8}; + QTest::newRow("WORLD") << "WORLD.ico" << QList<int>{8, 4, 4}; + QTest::newRow("yellow") << "yellow.cur" << QList<int>{32}; +} + +void tst_QIcoImageFormat::origBitDepth() +{ + QFETCH(QString, file); + QFETCH(QList<int>, origBitDepths); + + QImage image; + QImageReader reader(m_IconPath + QLatin1String("/valid/") + file); + + for (int depth : origBitDepths) { + reader.read(&image); + QCOMPARE(image.text("_q_icoOrigDepth").toInt(), depth); + reader.jumpToNextImage(); + } +} + QTEST_MAIN(tst_QIcoImageFormat) #include "tst_qicoimageformat.moc" diff --git a/tests/auto/gui/kernel/qopenglwindow/tst_qopenglwindow.cpp b/tests/auto/gui/kernel/qopenglwindow/tst_qopenglwindow.cpp index 6019261f792..06a1ffb2960 100644 --- a/tests/auto/gui/kernel/qopenglwindow/tst_qopenglwindow.cpp +++ b/tests/auto/gui/kernel/qopenglwindow/tst_qopenglwindow.cpp @@ -26,9 +26,6 @@ private slots: void tst_QOpenGLWindow::initTestCase() { -#if !QT_CONFIG(run_opengl_tests) - QSKIP("Skip test as run-opengl-tests feature is off."); -#endif if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) QSKIP("OpenGL is not supported on this platform."); } diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index a92d89c6123..4f994fb3059 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -25,6 +25,5 @@ android windows-10 windows-11 android -rhel [windowExposedAfterReparent] xcb ubuntu-24.04 # QTBUG-129023 diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 1c8dd14eba4..66bb0fa84d8 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -11,6 +11,7 @@ #include <QtGui/QPainter> #include <QTest> +#include <QtTest/private/qtesthelpers_p.h> #include <QSignalSpy> #include <QEvent> #include <QStyleHints> @@ -1237,6 +1238,7 @@ void tst_QWindow::testInputEvents() window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.showNormal(); QTRY_VERIFY(window.isActive()); + QVERIFY(QTestPrivate::ensurePositionTopLeft(&window)); QTest::keyClick(&window, Qt::Key_A, Qt::NoModifier); QCoreApplication::processEvents(); diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp index b9b4c3aa11c..36ff1d1f2e9 100644 --- a/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -185,9 +185,6 @@ static QSurface *createSurface(int surfaceClass) void tst_QOpenGL::initTestCase() { -#if !QT_CONFIG(run_opengl_tests) - QSKIP("Skip test as run-opengl-tests feature is off."); -#endif if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) QSKIP("OpenGL is not supported on this platform."); } diff --git a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp index f597dac53d7..423f9419daf 100644 --- a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp +++ b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp @@ -139,9 +139,6 @@ static void dumpConfiguration(QTextStream &str) void tst_QOpenGlConfig::initTestCase() { -#if !QT_CONFIG(run_opengl_tests) - QSKIP("Skip test as run-opengl-tests feature is off."); -#endif if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) QSKIP("OpenGL is not supported on this platform."); } diff --git a/tests/auto/gui/text/qfont/BLACKLIST b/tests/auto/gui/text/qfont/BLACKLIST index 2d2440255ae..3f63b678bb5 100644 --- a/tests/auto/gui/text/qfont/BLACKLIST +++ b/tests/auto/gui/text/qfont/BLACKLIST @@ -1,12 +1,9 @@ [defaultFamily:cursive] centos b2qt -rhel [defaultFamily:fantasy] centos b2qt -rhel - # QTBUG-130738 [familyNameWithCommaQuote:weird] vxworks diff --git a/tests/auto/network/kernel/qnetworkinterface/BLACKLIST b/tests/auto/network/kernel/qnetworkinterface/BLACKLIST deleted file mode 100644 index e9f4678e8ef..00000000000 --- a/tests/auto/network/kernel/qnetworkinterface/BLACKLIST +++ /dev/null @@ -1,5 +0,0 @@ -# QTBUG-130070 -[localAddress:enet0-fe80::8f41:f072:e573:3caa%enet0] -vxworks -[localAddress:localhost-ipv6] -vxworks diff --git a/tests/auto/other/android/CMakeLists.txt b/tests/auto/other/android/CMakeLists.txt index bcbf5b657d7..0eb2d00b46a 100644 --- a/tests/auto/other/android/CMakeLists.txt +++ b/tests/auto/other/android/CMakeLists.txt @@ -2,3 +2,11 @@ # SPDX-License-Identifier: BSD-3-Clause add_subdirectory(deployment_settings) +add_subdirectory(permissions) + +if(QT_USE_TARGET_ANDROID_BUILD_DIR) + add_subdirectory(package_source_dir) + if(QT_USE_ANDROID_MODERN_BUNDLE) + add_subdirectory(dynamic_feature) + endif() +endif() diff --git a/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp b/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp index 1687ed9de92..571570e370f 100644 --- a/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp +++ b/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp @@ -83,10 +83,11 @@ void tst_android_deployment_settings::DeploymentSettings_data() << "org.qtproject.android_deployment_settings_test"; QTest::newRow("android-app-name") << "android-app-name" << "Android Deployment Settings Test"; - QTest::newRow("permissions") << "permissions" - << "[{\"name\":\"PERMISSION_WITH_ATTRIBUTES\"," - "\"extras\":\"android:minSdkVersion='32' android:maxSdkVersion='34' \"}," - "{\"name\":\"PERMISSION_WITHOUT_ATTRIBUTES\"}]"; + QTest::newRow("permissions") + << "permissions" + << "[{\"maxSdkVersion\":\"34\",\"minSdkVersion\":\"32\",\"name\":\"PERMISSION_WITH_" + "ATTRIBUTES\"},{\"name\":\"PERMISSION_WITHOUT_ATTRIBUTES\"},{\"name\":\"android." + "permission.INTERNET\"},{\"name\":\"android.permission.WRITE_EXTERNAL_STORAGE\"}]"; } void tst_android_deployment_settings::DeploymentSettings() diff --git a/tests/auto/other/android/dynamic_feature/CMakeLists.txt b/tests/auto/other/android/dynamic_feature/CMakeLists.txt new file mode 100644 index 00000000000..b12c2af4dc7 --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_android_dynamic_feature LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +add_subdirectory(feature) + +qt_internal_add_test(tst_android_dynamic_feature + SOURCES + tst_android_dynamic_feature.cpp + storeloader/storeloader.h + storeloader/storeloader.cpp + INCLUDE_DIRECTORIES + storeloader + LIBRARIES + Qt6::Test + Qt6::Gui + Qt6::CorePrivate +) + +set_property(TARGET tst_android_dynamic_feature PROPERTY + QT_ANDROID_PACKAGE_NAME "org.qtproject.example.android_dynamic_feature") +set_property(TARGET tst_android_dynamic_feature APPEND PROPERTY + _qt_android_gradle_java_source_dirs "${CMAKE_CURRENT_SOURCE_DIR}/storeloader/java") + +qt6_add_android_dynamic_features(tst_android_dynamic_feature FEATURE_TARGETS + tst_android_dynamic_feature_resources) diff --git a/tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt b/tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt new file mode 100644 index 00000000000..bfe29cc0f5e --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.16) + +qt6_add_library(tst_android_dynamic_feature_resources SHARED) +qt6_add_resources(tst_android_dynamic_feature_resources "dynamic_resources" + PREFIX "/dynamic_resources" + FILES "qtlogo.png") + +target_link_libraries(tst_android_dynamic_feature_resources PRIVATE Qt6::Core) diff --git a/tests/auto/other/android/dynamic_feature/feature/qtlogo.png b/tests/auto/other/android/dynamic_feature/feature/qtlogo.png Binary files differnew file mode 100644 index 00000000000..b63f1384b11 --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/feature/qtlogo.png diff --git a/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java new file mode 100644 index 00000000000..5a72351c802 --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java @@ -0,0 +1,175 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +package org.qtproject.example.android_dynamic_feature; + +import com.google.android.play.core.splitcompat.SplitCompat; +import com.google.android.play.core.splitinstall.SplitInstallManager; +import com.google.android.play.core.splitinstall.SplitInstallManagerFactory; +import com.google.android.play.core.splitinstall.SplitInstallRequest; +import com.google.android.play.core.splitinstall.SplitInstallHelper; +import com.google.android.play.core.splitinstall.testing.FakeSplitInstallManagerFactory; +import android.content.pm.PackageManager.NameNotFoundException; + +import java.util.Arrays; +import java.util.HashMap; +import java.io.File; +import android.util.Log; +import android.content.Context; +import android.os.Build; + +/** + * Android implementation of store loader. + */ +public class StoreLoader implements StoreLoaderListenerCallback +{ + private static final String TAG = "StoreLoader"; + private final SplitInstallManager m_splitInstallManager; + private HashMap<String, StoreLoaderListener> m_listeners = + new HashMap(); + private Context m_context; + private String m_moduleName; + + public static native void stateChangedNative(String callId, int state); + public static native void errorOccurredNative(String callId, int errorCode, + String errorMessage); + public static native void userConfirmationRequestedNative(String callId, int errorCode, + String errorMessage); + public static native void downloadProgressChangedNative(String callId, long bytes, long total); + public static native void finishedNative(String callId); + + public StoreLoader(Context context) { + m_context = context; + + SplitCompat.install(context); + + m_splitInstallManager = SplitInstallManagerFactory.create(context); + if (m_splitInstallManager == null) + Log.e(TAG,"Constructor: Did not get splitInstallManager"); + } + + /** + * Loads Feature Delivery module from a play store. + */ + public void installModuleFromStore(String moduleName, String callId) { + Log.d(TAG, "installModuleFromStore: " + moduleName + " " + callId); + m_moduleName = moduleName; + + registerListener(callId); + + SplitInstallRequest request = + SplitInstallRequest.newBuilder().addModule(m_moduleName).build(); + if (request == null) + Log.e(TAG, "Null request"); + + if (m_splitInstallManager == null) + Log.e(TAG, "Null m_splitInstallManager"); + + m_splitInstallManager.startInstall(request) + .addOnSuccessListener(sessionId -> { + Log.d(TAG, "Install start call succesfull"); + StoreLoaderListener listener = m_listeners.get(callId); + if (listener != null) { + if (!listener.isCancelled()) + listener.setSessionId(sessionId); + else + m_splitInstallManager.cancelInstall(sessionId); + } else { + Log.d(TAG, "Listener for callId '" + callId + "' is not found"); + } + }); + } + + public void onStateChanged(String callId, int state) { + stateChangedNative(callId, state); + if (state == StoreLoaderListenerCallback.LOADED || + state == StoreLoaderListenerCallback.CANCELED) { + finished(callId); + } + } + + public void onErrorOccurred(String callId, int errorCode, String errorMessage) { + onStateChanged(callId, ERROR); + + Log.e(TAG, "Error occurred " + errorCode + " " + errorMessage); + errorOccurredNative(callId, errorCode, errorMessage); + finished(callId); + } + + public void onUserConfirmationRequested(String callId, int errorCode, String errorMessage) { + Log.d(TAG, "Requires user confirmation " + errorCode); + userConfirmationRequestedNative(callId, errorCode, errorMessage); + } + + public void onDownloadProgressChanged(String callId, long bytes, long total) { + Log.d(TAG, "Downloading " + bytes + "/" + total); + downloadProgressChangedNative(callId, bytes, total); + } + + public void onLoadLibrary(String callId) { + Log.d(TAG, "Load library for the module " + m_moduleName); + + stateChangedNative(callId, StoreLoaderListenerCallback.LOADING); + // update context. + try { + m_context = m_context.createPackageContext(m_context.getPackageName(), 0); + } catch (NameNotFoundException ignored) { + Log.e(TAG, "Could not get package name"); + } + // install splitcompat for new context. + SplitCompat.install(m_context); + // try to load new library + boolean isLoaded = false; + for (String abi : Build.SUPPORTED_ABIS) { + String fullLibraryName = m_moduleName + "_" + abi; + try { + System.loadLibrary(fullLibraryName); + isLoaded = true; + break; + } catch (Exception e) { + Log.d(TAG, "Exception occurred when loading the library " + fullLibraryName + ":" + + e.getClass().getCanonicalName()); + } + } + + if (isLoaded) + onStateChanged(callId, StoreLoaderListenerCallback.LOADED); + else + onErrorOccurred(callId, -1, "Error loading library. Check logcat for details."); + + } + + public void cancelInstall(String callId) { + StoreLoaderListener listener = m_listeners.get(callId); + if (listener == null) { + Log.e(TAG, "The listener for callId " + callId + " is not found"); + return; + } + + if (listener.getSessionId() < 0) + listener.postponeCancel(); + else + m_splitInstallManager.cancelInstall(listener.getSessionId()); + } + + private void finished(String callId) { + unregisterListener(callId); + finishedNative(callId); + } + + private void registerListener(String callId) { + Log.d(TAG, "registerListener"); + StoreLoaderListener listener = new StoreLoaderListener(this, callId); + if (listener != null) { + m_listeners.put(callId, listener); + m_splitInstallManager.registerListener(listener); + } + } + + private void unregisterListener(String callId) { + Log.d(TAG, "unregisterListener"); + StoreLoaderListener listener = m_listeners.remove(callId); + if (listener != null) + m_splitInstallManager.unregisterListener(listener); + } +} diff --git a/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java new file mode 100644 index 00000000000..3e83a0fa7f9 --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java @@ -0,0 +1,92 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +package org.qtproject.example.android_dynamic_feature; + +import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener; +import com.google.android.play.core.splitinstall.SplitInstallSessionState; +import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus; + +import android.util.Log; + +public class StoreLoaderListener implements SplitInstallStateUpdatedListener { + + private final StoreLoaderListenerCallback m_callback; + private final String m_callId; + private int m_installSessionId = -1; + private static final String TAG = "StoreLoaderListener"; + private int m_currentStatus = SplitInstallSessionStatus.UNKNOWN; + private boolean m_postponeCancel = false; + + public StoreLoaderListener(StoreLoaderListenerCallback callback, String callId) { + m_callback = callback; + m_callId = callId; + } + + public void setSessionId(int sessionId) { m_installSessionId = sessionId; } + public int getSessionId() { return m_installSessionId; } + + public void postponeCancel() { m_postponeCancel = true; } + public boolean isCancelled() { return m_postponeCancel; } + + @Override + public void onStateUpdate(SplitInstallSessionState state) { + Log.d(TAG, + "onStateUpdate, status: " + state.status() + " session id: " + state.sessionId()); + if (state.sessionId() != m_installSessionId) { + // Not mine + return; + } + + switch (state.status()) { + case SplitInstallSessionStatus.DOWNLOADING: + Log.d(TAG, + "SplitInstallSessionState: DOWNLOADING " + state.bytesDownloaded() + "/" + + state.totalBytesToDownload()); + if (m_currentStatus != SplitInstallSessionStatus.DOWNLOADING) + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.DOWNLOADING); + + m_callback.onDownloadProgressChanged(m_callId, state.bytesDownloaded(), + state.totalBytesToDownload()); + break; + case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION: + Log.d(TAG, "SplitInstallSessionState: REQUIRES_USER_CONFIRMATION"); + m_callback.onStateChanged(m_callId, + StoreLoaderListenerCallback.REQUIRES_USER_CONFIRMATION); + + m_callback.onUserConfirmationRequested(m_callId, state.errorCode(), "" /*noop for now*/); + break; + case SplitInstallSessionStatus.INSTALLED: + Log.d(TAG, "SplitInstallSessionState: INSTALLED"); + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.INSTALLED); + m_callback.onLoadLibrary(m_callId); + break; + case SplitInstallSessionStatus.INSTALLING: + Log.d(TAG, "SplitInstallSessionState: INSTALLING"); + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.INSTALLING); + break; + case SplitInstallSessionStatus.FAILED: + Log.d(TAG, + "SplitInstallSessionState: FAILED with error code: " + state.errorCode()); + m_callback.onErrorOccurred(m_callId, state.errorCode(), "" /*noop for now*/); + break; + case SplitInstallSessionStatus.PENDING: + Log.d(TAG, "SplitInstallSessionState: PENDING"); + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.PENDING); + break; + case SplitInstallSessionStatus.DOWNLOADED: + Log.d(TAG, "SplitInstallSessionState: DOWNLOADED"); + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.DOWNLOADED); + break; + case SplitInstallSessionStatus.CANCELED: + Log.d(TAG, "SplitInstallSessionState: CANCELED"); + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.CANCELED); + break; + case SplitInstallSessionStatus.CANCELING: + Log.d(TAG, "SplitInstallSessionState: CANCELING"); + m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.CANCELING); + break; + } + m_currentStatus = state.status(); + } +} diff --git a/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java new file mode 100644 index 00000000000..99c7327e328 --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java @@ -0,0 +1,26 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +package org.qtproject.example.android_dynamic_feature; + +public interface StoreLoaderListenerCallback { + public static final int UNKNOWN = 0; // Unused but native part has and uses one. + public static final int INITIALIZED = 1; + public static final int PENDING = 2; + public static final int DOWNLOADING = 3; + public static final int DOWNLOADED = 4; + public static final int REQUIRES_USER_CONFIRMATION = 5; + public static final int CANCELING = 6; + public static final int CANCELED = 7; + public static final int INSTALLING = 8; + public static final int INSTALLED = 9; + public static final int LOADING = 10; + public static final int LOADED = 11; + public static final int ERROR = 12; + + public void onStateChanged(String callId, int state); + public void onErrorOccurred(String callId, int errorCode, String errorMessage); + public void onUserConfirmationRequested(String callId, int errorCode, String errorMessage); + public void onDownloadProgressChanged(String callId, long bytes, long total); + public void onLoadLibrary(String callId); +} diff --git a/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp new file mode 100644 index 00000000000..7abce59b79e --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp @@ -0,0 +1,227 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include "storeloader.h" + +#include <QtCore/private/qobject_p.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qhash.h> +#include <QtCore/qjniobject.h> +#include <QtCore/qlogging.h> +#include <QtCore/qmutex.h> +#include <QtCore/quuid.h> + +#include <jni.h> + +Q_DECLARE_JNI_CLASS(StoreLoader, + "org/qtproject/example/android_dynamic_feature/StoreLoader"); + +class StoreLoaderHandlerPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(StoreLoaderHandler) +public: + void setState(StoreLoader::State state) + { + if (m_state == state) + return; + Q_Q(StoreLoaderHandler); + m_state = state; + q->stateChanged(m_state); + } + + const QString &callId() const & noexcept { return m_callId; } + +private: + StoreLoader::State m_state = StoreLoader::State::Unknown; + QString m_callId = QUuid::createUuid().toString(); +}; + +namespace QtPrivate { +QString asString(const jstring &s) +{ + return QJniObject(s).toString(); +} +} // namespace QtPrivate + +namespace { + +class StoreLoaderImpl +{ +public: + StoreLoaderImpl(); + bool registerNatives() const; + + void addHandler(StoreLoaderHandler *handler); + StoreLoaderHandler *findHandler(const jstring &callId); + void removeHandler(const jstring &callId); + + QtJniTypes::StoreLoader loader = nullptr; + +private: + QHash<QString, QPointer<StoreLoaderHandler>> m_handlers; + QMutex m_lock; +}; + +Q_GLOBAL_STATIC(StoreLoaderImpl, loaderInstance) + +void stateChangedNative(JNIEnv *, jobject, jstring callId, int state) +{ + qDebug("State changed %s.", qPrintable(callId)); + + if (auto *handler = loaderInstance->findHandler(callId)) + emit handler->stateChanged(static_cast<StoreLoader::State>(state)); +} + +void errorOccurredNative(JNIEnv *, jobject, jstring callId, int errorCode, jstring errorMessage) +{ + qDebug("Error occurred %s %d %s.", qPrintable(callId), errorCode, qPrintable(errorMessage)); + auto *handler = loaderInstance->findHandler(callId); + if (!handler) + return; + + emit handler->errorOccured(errorCode, QJniObject(errorMessage).toString()); +} + +void userConfirmationRequestedNative(JNIEnv *, jobject, jstring callId, int errorCode, + jstring errorMessage) +{ + qDebug("User confirmation requested %s %d %s.", qPrintable(callId), errorCode, + qPrintable(errorMessage)); + auto *handler = loaderInstance->findHandler(callId); + if (!handler) + return; + + emit handler->confirmationRequest(errorCode, QJniObject(errorMessage).toString()); +} + +void downloadProgressChangedNative(JNIEnv *, jobject, jstring callId, long bytes, long total) +{ + qDebug("Download progress changed %ld/%ld.", bytes, total); + auto *handler = loaderInstance->findHandler(callId); + if (!handler) + return; + + emit handler->downloadProgress(bytes, total); +} + +void finishedNative(JNIEnv *, jobject, jstring callId) +{ + auto *handler = loaderInstance->findHandler(callId); + if (!handler) + return; + + emit handler->finished(); +} + +} // namespace + +Q_DECLARE_JNI_NATIVE_METHOD(stateChangedNative) +Q_DECLARE_JNI_NATIVE_METHOD(errorOccurredNative) +Q_DECLARE_JNI_NATIVE_METHOD(userConfirmationRequestedNative) +Q_DECLARE_JNI_NATIVE_METHOD(downloadProgressChangedNative) +Q_DECLARE_JNI_NATIVE_METHOD(finishedNative) + +StoreLoaderImpl::StoreLoaderImpl() +{ + loader = QJniObject::construct<QtJniTypes::StoreLoader, QtJniTypes::Context>( + QNativeInterface::QAndroidApplication::context()); +} + +bool StoreLoaderImpl::registerNatives() const +{ + static bool result = [] { + return QtJniTypes::StoreLoader::registerNativeMethods({ + Q_JNI_NATIVE_METHOD(stateChangedNative), + Q_JNI_NATIVE_METHOD(errorOccurredNative), + Q_JNI_NATIVE_METHOD(userConfirmationRequestedNative), + Q_JNI_NATIVE_METHOD(downloadProgressChangedNative), + Q_JNI_NATIVE_METHOD(finishedNative), + }); + }(); + + if (!result) + qCritical("Unable to register native methods."); + + return result; +} + +void StoreLoaderImpl::addHandler(StoreLoaderHandler *handler) +{ + Q_ASSERT(handler); + + QMutexLocker lock(&m_lock); + const auto &callId = handler->callId(); + Q_ASSERT_X(m_handlers.constFind(callId) != m_handlers.constEnd(), "StoreLoaderImpl::addHandler", + qPrintable(QString("Handler with callId %1 already exists.").arg(callId))); + + m_handlers[callId] = QPointer(handler); +} + + +StoreLoaderHandler *StoreLoaderImpl::findHandler(const jstring &callId) +{ + QMutexLocker lock(&m_lock); + const auto it = m_handlers.constFind(QJniObject(callId).toString()); + if (it == m_handlers.constEnd()) { + qCritical("The handler for the call %s was not found.", qPrintable(callId)); + return nullptr; + } + + if (it.value().isNull()) { + qCritical("The handler for the call %s expired.", qPrintable(callId)); + m_handlers.erase(it); + } + + return it.value().get(); +} + +void StoreLoaderImpl::removeHandler(const jstring &callId) +{ + QMutexLocker lock(&m_lock); + m_handlers.remove(QJniObject(callId).toString()); +} + +std::unique_ptr<StoreLoaderHandler> +StoreLoader::loadModule(const QString &moduleName) +{ + if (moduleName.isEmpty()) + return {}; + + if (!loaderInstance->registerNatives()) + return {}; + + if (!loaderInstance->loader.isValid()) { + qCritical("StoreLoader not constructed"); + return {}; + } + + auto handlerPtr = std::make_unique<StoreLoaderHandler>( + nullptr, StoreLoaderHandler::PrivateConstructor{}); + loaderInstance->addHandler(handlerPtr.get()); + + const auto &callId = handlerPtr->callId(); + qDebug("Loading module %s, callId: %s.", qPrintable(moduleName), qPrintable(callId)); + + loaderInstance->loader.callMethod<void>("installModuleFromStore", moduleName, callId); + return handlerPtr; +} + +StoreLoaderHandler::StoreLoaderHandler(QObject *parent, PrivateConstructor) + : QObject(*new StoreLoaderHandlerPrivate(), parent) +{ +} + +StoreLoaderHandler::~StoreLoaderHandler() = default; + +const QString &StoreLoaderHandler::callId() const & noexcept +{ + Q_D(const StoreLoaderHandler); + return d->callId(); +} + +void StoreLoaderHandler::cancel() +{ + Q_D(StoreLoaderHandler); + loaderInstance->loader.callMethod<void>("cancelInstall", d->callId()); +} + +#include "moc_storeloader.cpp" diff --git a/tests/auto/other/android/dynamic_feature/storeloader/storeloader.h b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.h new file mode 100644 index 00000000000..be4e103207e --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.h @@ -0,0 +1,65 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef STORELOADER_H +#define STORELOADER_H + +#include <QtCore/qtconfigmacros.h> +#include <QtCore/qobject.h> + +#include <memory> + +class StoreLoaderHandler; + +namespace StoreLoader { + Q_NAMESPACE +enum class State { + Unknown, + Initialized, + Pending, + Downloading, + Downloaded, + RequiresUserConfirmation, + Canceling, + Canceled, + Installing, + Installed, + Loading, + Loaded, + Error, +}; +Q_ENUM_NS(State) + +std::unique_ptr<StoreLoaderHandler> loadModule(const QString &moduleName); +}; // namespace StoreLoader + +class StoreLoaderHandlerPrivate; + +class StoreLoaderHandler : public QObject +{ + Q_OBJECT + QT_DEFINE_TAG_STRUCT(PrivateConstructor); + +public: + explicit StoreLoaderHandler(QObject *parent, PrivateConstructor); + ~StoreLoaderHandler() override; + + const QString &callId() const & noexcept; + + void cancel(); +signals: + void stateChanged(StoreLoader::State state); + void downloadProgress(qsizetype bytes, qsizetype total); + void errorOccured(int errorCode, const QString &errorString); + void confirmationRequest(int errorCode, const QString &errorString); + void finished(); + +private: + Q_DISABLE_COPY_MOVE(StoreLoaderHandler) + Q_DECLARE_PRIVATE(StoreLoaderHandler) + + friend std::unique_ptr<StoreLoaderHandler> + StoreLoader::loadModule(const QString &); +}; + +#endif // STORELOADER_H diff --git a/tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp b/tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp new file mode 100644 index 00000000000..739a645c5d5 --- /dev/null +++ b/tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <storeloader.h> + +#include <QtTest/QTest> +#include <QtTest/QSignalSpy> + +#include <QtCore/QVariant> + +using namespace Qt::Literals::StringLiterals; + +class QtDynamicFeatureTest : public QObject +{ + Q_OBJECT +public: + QtDynamicFeatureTest(){} + +private Q_SLOTS: + void loadResourcesFeature(); +}; + +void QtDynamicFeatureTest::loadResourcesFeature() +{ + QVERIFY(!QFile::exists(":/dynamic_resources/qtlogo.png")); + + auto handler = StoreLoader::loadModule("tst_android_dynamic_feature_resources"_L1); + + QSignalSpy spy(handler.get(), &StoreLoaderHandler::finished); + + QVERIFY(spy.wait(20000)); + QVERIFY(QFile::exists(":/dynamic_resources/qtlogo.png")); +} + +QTEST_MAIN(QtDynamicFeatureTest) + +#include "tst_android_dynamic_feature.moc" diff --git a/tests/auto/other/android/package_source_dir/CMakeLists.txt b/tests/auto/other/android/package_source_dir/CMakeLists.txt new file mode 100644 index 00000000000..360aa50d87d --- /dev/null +++ b/tests/auto/other/android/package_source_dir/CMakeLists.txt @@ -0,0 +1,54 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_android_package_source_dir LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +# Package name is generated and written to AndroidManifest.xml +qt_internal_add_test(tst_package_source_dir_not_defined + SOURCES + tst_android_package_source_dir.cpp + DEFINES + EXPECTED_APP_NAME="tst_package_source_dir_not_defined" +) + +# Package name from user-provided AndroidManifest.xml +qt_internal_add_test(tst_package_source_dir_custom_android_manifest + SOURCES + tst_android_package_source_dir.cpp + DEFINES + EXPECTED_APP_NAME="tst_package_source_dir_custom_android_manifest_my" +) + +if(QT_USE_ANDROID_MODERN_BUNDLE) + set_target_properties(tst_package_source_dir_custom_android_manifest + PROPERTIES + QT_ANDROID_PACKAGE_SOURCE_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/custom_android_manifest_bundle" + ) +else() + set_target_properties(tst_package_source_dir_custom_android_manifest + PROPERTIES + QT_ANDROID_PACKAGE_SOURCE_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/custom_android_manifest" + ) +endif() + +if(QT_USE_ANDROID_MODERN_BUNDLE) + # Partial gradle template is only supported by QT_USE_ANDROID_MODERN_BUNDLE + # + # Package name from user-provided gradle.build.in + qt_internal_add_test(tst_package_source_dir_partial_template + SOURCES + tst_android_package_source_dir.cpp + DEFINES + EXPECTED_APP_NAME="tst_package_source_dir_partial_template_my" + ) + set_target_properties(tst_package_source_dir_partial_template + PROPERTIES + QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/partial_template" + ) +endif() diff --git a/tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml b/tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml new file mode 100644 index 00000000000..4f53295e979 --- /dev/null +++ b/tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.qtproject.example.tst_package_source_dir_custom_android_manifest" + android:installLocation="auto" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <supports-screens + android:anyDensity="true" + android:largeScreens="true" + android:normalScreens="true" + android:smallScreens="true" /> + <application + android:name="org.qtproject.qt.android.bindings.QtApplication" + android:hardwareAccelerated="true" + android:label="tst_package_source_dir_custom_android_manifest_my" + android:requestLegacyExternalStorage="true" + android:allowBackup="true" + android:fullBackupOnly="false"> + <activity + android:name="org.qtproject.qt.android.bindings.QtActivity" + android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" + android:launchMode="singleTop" + android:screenOrientation="unspecified" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + + <meta-data + android:name="android.app.lib_name" + android:value="tst_package_source_dir_custom_android_manifest" /> + + <meta-data + android:name="android.app.arguments" + android:value="" /> + </activity> + + <provider + android:name="androidx.core.content.FileProvider" + android:authorities="${applicationId}.qtprovider" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/qtprovider_paths"/> + </provider> + </application> +</manifest> diff --git a/tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml b/tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml new file mode 100644 index 00000000000..4f53295e979 --- /dev/null +++ b/tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.qtproject.example.tst_package_source_dir_custom_android_manifest" + android:installLocation="auto" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <supports-screens + android:anyDensity="true" + android:largeScreens="true" + android:normalScreens="true" + android:smallScreens="true" /> + <application + android:name="org.qtproject.qt.android.bindings.QtApplication" + android:hardwareAccelerated="true" + android:label="tst_package_source_dir_custom_android_manifest_my" + android:requestLegacyExternalStorage="true" + android:allowBackup="true" + android:fullBackupOnly="false"> + <activity + android:name="org.qtproject.qt.android.bindings.QtActivity" + android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" + android:launchMode="singleTop" + android:screenOrientation="unspecified" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + + <meta-data + android:name="android.app.lib_name" + android:value="tst_package_source_dir_custom_android_manifest" /> + + <meta-data + android:name="android.app.arguments" + android:value="" /> + </activity> + + <provider + android:name="androidx.core.content.FileProvider" + android:authorities="${applicationId}.qtprovider" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/qtprovider_paths"/> + </provider> + </application> +</manifest> diff --git a/tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml b/tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml new file mode 100644 index 00000000000..838d239e5f4 --- /dev/null +++ b/tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.qtproject.example.tst_package_source_dir_partial_template" + android:installLocation="auto" + android:versionCode="1" + android:versionName="1.0"> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <supports-screens + android:anyDensity="true" + android:largeScreens="true" + android:normalScreens="true" + android:smallScreens="true" /> + <application + android:name="org.qtproject.qt.android.bindings.QtApplication" + android:hardwareAccelerated="true" + android:label="${appName}" + android:requestLegacyExternalStorage="true" + android:allowBackup="true" + android:fullBackupOnly="false"> + <activity + android:name="org.qtproject.qt.android.bindings.QtActivity" + android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" + android:launchMode="singleTop" + android:screenOrientation="unspecified" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + + <meta-data + android:name="android.app.lib_name" + android:value="tst_package_source_dir_partial_template" /> + + <meta-data + android:name="android.app.arguments" + android:value="" /> + </activity> + + <provider + android:name="androidx.core.content.FileProvider" + android:authorities="${applicationId}.qtprovider" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/qtprovider_paths"/> + </provider> + </application> +</manifest> diff --git a/tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in b/tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in new file mode 100644 index 00000000000..538f1ca6217 --- /dev/null +++ b/tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in @@ -0,0 +1,54 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.6.0' + } +} + +apply plugin: '@GRADLE_PLUGIN_TYPE@' + +dependencies { + @GRADLE_DEPENDENCIES@ +} + +android { + namespace '@PACKAGE_NAME@' + compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@' + buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@' + ndkVersion '@ANDROID_NDK_REVISION@' + + defaultConfig { + @DEFAULT_CONFIG_VALUES@ + manifestPlaceholders = [ appName:"tst_package_source_dir_partial_template_my" ] + } + + sourceSets { + main { +@SOURCE_SETS@ + } + } + + tasks.withType(JavaCompile) { + options.incremental = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + aaptOptions { + // Do not compress Qt binary resources file + noCompress 'rcc' + } + + @ANDROID_DEPLOYMENT_EXTRAS@ +} diff --git a/tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp b/tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp new file mode 100644 index 00000000000..d74d388371f --- /dev/null +++ b/tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QCoreApplication> +#include <QJniObject> +#include <QTest> +#include <QDebug> + +using namespace QNativeInterface; + +Q_DECLARE_JNI_CLASS(ApplicationInfo, "android/content/pm/ApplicationInfo") +Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager") +Q_DECLARE_JNI_CLASS(CharSequence, "java/lang/CharSequence") + +class tst_android_package_source_dir : public QObject +{ + Q_OBJECT + +private slots: + void applicationName(); + +private: +}; + +void tst_android_package_source_dir::applicationName() +{ + QJniObject appCtx = QAndroidApplication::context(); + QVERIFY(appCtx.isValid()); + + const auto appInfo = appCtx.callMethod<QtJniTypes::ApplicationInfo>("getApplicationInfo"); + QVERIFY(appInfo.isValid()); + + const auto packageManager = appCtx.callMethod<QtJniTypes::PackageManager>("getPackageManager"); + QVERIFY(packageManager.isValid()); + + const auto appNameLabel = + appInfo.callMethod<QtJniTypes::CharSequence>("loadLabel", packageManager); + QVERIFY(appNameLabel.isValid()); + + const auto appName = appNameLabel.callMethod<jstring>("toString").toString(); + + QCOMPARE_EQ(appName, QString::fromLatin1(EXPECTED_APP_NAME)); +} + +QTEST_MAIN(tst_android_package_source_dir); + +#include "tst_android_package_source_dir.moc" diff --git a/tests/auto/other/android/permissions/CMakeLists.txt b/tests/auto/other/android/permissions/CMakeLists.txt new file mode 100644 index 00000000000..0424c674e1b --- /dev/null +++ b/tests/auto/other/android/permissions/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_android_permissions LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_android_permissions + SOURCES + tst_android_permissions.cpp +) + +qt_add_android_permission(tst_android_permissions + NAME android.permission.ACCESS_COARSE_LOCATION +) + +qt_add_android_permission(tst_android_permissions + NAME android.permission.ACCESS_FINE_LOCATION + ATTRIBUTES + maxSdkVersion 31 +) diff --git a/tests/auto/other/android/permissions/tst_android_permissions.cpp b/tests/auto/other/android/permissions/tst_android_permissions.cpp new file mode 100644 index 00000000000..5d7a255d3ac --- /dev/null +++ b/tests/auto/other/android/permissions/tst_android_permissions.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QCoreApplication> +#include <QJniObject> +#include <QSet> +#include <QString> +#include <QTest> + +constexpr int GET_PERMISSIONS(0x00001000); + +using namespace QNativeInterface; +using namespace Qt::StringLiterals; + +Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager") +Q_DECLARE_JNI_CLASS(PackageInfo, "android/content/pm/PackageInfo") + +class tst_android_permissions : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void checkExpectedDefaults(); + void checkNonExisting(); + void checkNonDefaultPermissions(); + +private: + QJniArray<QString> m_requestedPermissions; +}; + +void tst_android_permissions::initTestCase() +{ + QJniObject appCtx = QAndroidApplication::context(); + QVERIFY(appCtx.isValid()); + + const auto packageName = appCtx.callMethod<QString>("getPackageName"); + const auto packageManager = appCtx.callMethod<QtJniTypes::PackageManager>("getPackageManager"); + QVERIFY(packageManager.isValid()); + + const auto packageInfo = QJniObject(packageManager.callMethod<QtJniTypes::PackageInfo>( + "getPackageInfo", packageName, jint(GET_PERMISSIONS))); + QVERIFY(packageInfo.isValid()); + + m_requestedPermissions = packageInfo.getField<QJniArray<QString>>("requestedPermissions"); + QVERIFY(m_requestedPermissions.isValid()); +} + +void tst_android_permissions::checkExpectedDefaults() +{ + QSet<QString> expectedDefaults{ { "android.permission.INTERNET"_L1 }, + { "android.permission.WRITE_EXTERNAL_STORAGE"_L1 }, + { "android.permission.READ_EXTERNAL_STORAGE"_L1 } }; + + for (const auto &permission : m_requestedPermissions) + expectedDefaults.remove(permission); + + QVERIFY(expectedDefaults.empty()); +} + +void tst_android_permissions::checkNonExisting() +{ + for (const auto &permission : m_requestedPermissions) + QCOMPARE_NE(permission, "android.permission.BLUETOOTH_SCAN"); +} + +void tst_android_permissions::checkNonDefaultPermissions() +{ + bool hasNonDefaultPermissions = false; + for (const auto &permission : m_requestedPermissions) { + if (permission == "android.permission.ACCESS_COARSE_LOCATION") + hasNonDefaultPermissions = true; + } + + QVERIFY(hasNonDefaultPermissions); +} + +QTEST_MAIN(tst_android_permissions); + +#include "tst_android_permissions.moc" diff --git a/tests/auto/testlib/selftests/mouse/tst_mouse.cpp b/tests/auto/testlib/selftests/mouse/tst_mouse.cpp index 4af55adde91..ae8fa54dcea 100644 --- a/tests/auto/testlib/selftests/mouse/tst_mouse.cpp +++ b/tests/auto/testlib/selftests/mouse/tst_mouse.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> +#include <QtTest/private/qtesthelpers_p.h> #include <QtGui/QWindow> #include <QtGui/QCursor> #include <QtGui/private/qguiapplication_p.h> @@ -256,8 +257,9 @@ void tst_Mouse::doubleClick() { MouseWindow w; w.show(); - w.setGeometry(100, 100, 200, 200); + w.resize(200, 200); QVERIFY(QTest::qWaitForWindowActive(&w)); + QVERIFY(QTestPrivate::ensurePositionTopLeft(&w)); // click QPoint point(10, 10); diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index ab88dd78111..217122100a0 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -7,7 +7,7 @@ https://developercommunity.visualstudio.com/t/Regression:-c-compilation-failure-in-c/10926790 */ #include <QtCore/qcompilerdetection.h> -#if defined(Q_CC_MSVC_ONLY) && (_MSC_FULL_VER >= 194435209) && (_MSC_FULL_VER < 194500000) +#if defined(Q_CC_MSVC_ONLY) && (_MSC_FULL_VER >= 194435208) && (_MSC_FULL_VER < 194500000) # define MSVC_ENUM_BUG #endif diff --git a/tests/auto/tools/qmake/testdata/windows_resources/REUSE.toml b/tests/auto/tools/qmake/testdata/windows_resources/REUSE.toml index 8d05566c678..65bfc74258c 100644 --- a/tests/auto/tools/qmake/testdata/windows_resources/REUSE.toml +++ b/tests/auto/tools/qmake/testdata/windows_resources/REUSE.toml @@ -3,5 +3,5 @@ version = 1 [[annotations]] path = ["version.inc"] precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2019 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" diff --git a/tests/auto/tools/uic/baseline/REUSE.toml b/tests/auto/tools/uic/baseline/REUSE.toml index 30f460c00b0..c147a71dca5 100644 --- a/tests/auto/tools/uic/baseline/REUSE.toml +++ b/tests/auto/tools/uic/baseline/REUSE.toml @@ -3,5 +3,5 @@ version = 1 [[annotations]] path = ["Widget.ui"] precedence = "override" -SPDX-FileCopyrightText = "Copyright (C) 2016 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 3e5ff5ce640..df19ea1568e 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -657,9 +657,6 @@ void tst_QGraphicsView::viewport() #if QT_CONFIG(opengl) void tst_QGraphicsView::openGLViewport() { -#if !QT_CONFIG(run_opengl_tests) - QSKIP("Skip test as run-opengl-tests feature is off."); -#endif if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) QSKIP("QOpenGL is not supported on this platform."); if (isPlatformEGLFS()) diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 03be7aa0fe9..b651668cabd 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -213,6 +213,7 @@ private slots: void storeRestoreLowMemoryMode(); void setSectionResizeModeWithSectionWillTakeMemory(); void setModelWithAutoSizeWillSwitchToMemoryMode(); + void tableViewResizeSectionsWillSwitchToMemoryMode(); void setDefaultSectionSizeRespectsColumnWidth(); @@ -3559,12 +3560,17 @@ struct TableViewWithBasicModel : public QTableView emptyState = verticalHeader()->saveState(); setModel(&m); header = verticalHeader(); + horizontal_header = horizontalHeader(); } bool hasLowMemoryUsage() const { return emptyState.size() == header->saveState().size(); } + bool horizontalLowMememorUsage() const { + return emptyState.size() == horizontal_header->saveState().size(); + } + bool hasHigherMemoryUsage() const { const int delta = 1000; return header->saveState().size() > delta + emptyState.size(); @@ -3572,6 +3578,7 @@ struct TableViewWithBasicModel : public QTableView BasicModel m; QHeaderView *header; + QHeaderView *horizontal_header; QByteArray emptyState; }; @@ -3770,6 +3777,15 @@ void tst_QHeaderView::setModelWithAutoSizeWillSwitchToMemoryMode() QCOMPARE_GT(nonEmptyState.size(), emptyState.size() + delta); } +void tst_QHeaderView::tableViewResizeSectionsWillSwitchToMemoryMode() +{ + TableViewWithBasicModel tv; + QVERIFY(tv.horizontalLowMememorUsage()); + tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); + tv.resizeColumnsToContents(); + QVERIFY(!tv.horizontalLowMememorUsage()); +} + void tst_QHeaderView::setDefaultSectionSizeRespectsColumnWidth() { QTreeWidget tree; diff --git a/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp b/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp index c460eb1db8c..f418d5ead14 100644 --- a/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp +++ b/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp @@ -655,121 +655,122 @@ void tst_QWidgetRepaintManager::evaluateRhi() #if QT_CONFIG(opengl) -#if QT_CONFIG(run_opengl_tests) - { - // Non-native child RHI widget enables RHI for top level regular widget - QWidget topLevel; - RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); - topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); - // Only the native widget that actually flushes will report usesRhiFlush - QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); - // But it should have an RHI it can use - QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); - } - - { - // Native child RHI widget does not enable RHI for top level - QWidget topLevel; - RhiWidget nativeRhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); - nativeRhiWidget.setAttribute(Qt::WA_NativeWindow); - topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - QCOMPARE(nativeRhiWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->rhi()); - QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); - QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); - - if (!usesRhiBackingStore) - QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); - } - - { - // Non-native RHI child of native child enables RHI for native child, - // but not top level. - QWidget topLevel; - QWidget nativeChild(&topLevel); - nativeChild.setAttribute(Qt::WA_NativeWindow); - RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &nativeChild); - topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - - QCOMPARE(nativeChild.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&nativeChild)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&nativeChild)->rhi()); - QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); - QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); - QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); - if (!usesRhiBackingStore) - QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); - } - - { - // Native child RHI widget does not prevent RHI for top level - // if non-native RHI child widget is also present. - QWidget topLevel; - RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); - RhiWidget nativeRhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); - nativeRhiWidget.setAttribute(Qt::WA_NativeWindow); - topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { - QCOMPARE(nativeRhiWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->rhi()); - QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); - QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); - } + { + // Non-native child RHI widget enables RHI for top level regular widget + QWidget topLevel; + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + // Only the native widget that actually flushes will report usesRhiFlush + QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + // But it should have an RHI it can use + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + } - { - // Reparenting into a window that already matches the required - // surface type should still mark the parent as flushing with RHI. - QWidget topLevel; + { + // Native child RHI widget does not enable RHI for top level + QWidget topLevel; + RhiWidget nativeRhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + nativeRhiWidget.setAttribute(Qt::WA_NativeWindow); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(nativeRhiWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); + QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); + + if (!usesRhiBackingStore) + QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); + } - RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::Null); - rhiWidget.show(); - QVERIFY(QTest::qWaitForWindowExposed(&rhiWidget)); - QVERIFY(QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + { + // Non-native RHI child of native child enables RHI for native child, + // but not top level. + QWidget topLevel; + QWidget nativeChild(&topLevel); + nativeChild.setAttribute(Qt::WA_NativeWindow); + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &nativeChild); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(nativeChild.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeChild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeChild)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); + QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); + if (!usesRhiBackingStore) + QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); + } - topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - rhiWidget.setParent(&topLevel); - QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); - } + { + // Native child RHI widget does not prevent RHI for top level + // if non-native RHI child widget is also present. + QWidget topLevel; + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + RhiWidget nativeRhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + nativeRhiWidget.setAttribute(Qt::WA_NativeWindow); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(nativeRhiWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + } - { - // Non-native RHI child of native child enables RHI for native child, - // but does not prevent top level from flushing with RHI. - QWidget topLevel; - QWidget nativeChild(&topLevel); - nativeChild.setAttribute(Qt::WA_NativeWindow); - RhiWidget rhiGranchild(QPlatformBackingStoreRhiConfig::OpenGL, &nativeChild); - RhiWidget rhiChild(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); - topLevel.show(); - QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + { + // Reparenting into a window that already matches the required + // surface type should still mark the parent as flushing with RHI. + QWidget topLevel; + + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::Null); + rhiWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&rhiWidget)); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + rhiWidget.setParent(&topLevel); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + } - QCOMPARE(nativeChild.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&nativeChild)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&nativeChild)->rhi()); - QVERIFY(!QWidgetPrivate::get(&rhiGranchild)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&rhiGranchild)->rhi()); - QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); - QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); - QVERIFY(!QWidgetPrivate::get(&rhiChild)->usesRhiFlush); - QVERIFY(QWidgetPrivate::get(&rhiChild)->rhi()); + { + // Non-native RHI child of native child enables RHI for native child, + // but does not prevent top level from flushing with RHI. + QWidget topLevel; + QWidget nativeChild(&topLevel); + nativeChild.setAttribute(Qt::WA_NativeWindow); + RhiWidget rhiGranchild(QPlatformBackingStoreRhiConfig::OpenGL, &nativeChild); + RhiWidget rhiChild(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(nativeChild.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeChild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeChild)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiGranchild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiGranchild)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiChild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiChild)->rhi()); + } } -#endif // QT_CONFIG(run_opengl_tests) #if QT_CONFIG(metal) QRhiMetalInitParams metalParams; @@ -805,10 +806,6 @@ void tst_QWidgetRepaintManager::evaluateRhi() void tst_QWidgetRepaintManager::rhiRecreateMaintainsWindowProperties() { -#if !QT_CONFIG(run_opengl_tests) - QSKIP("Skip test as run-opengl-tests feature is off."); -#endif - const auto *integration = QGuiApplicationPrivate::platformIntegration(); if (!integration->hasCapability(QPlatformIntegration::RhiBasedRendering)) QSKIP("Platform does not support RHI based rendering"); @@ -817,6 +814,9 @@ void tst_QWidgetRepaintManager::rhiRecreateMaintainsWindowProperties() QSKIP("Platform does not support OpenGL RHI based rendering"); #endif + if (!integration->hasCapability(QPlatformIntegration::OpenGL)) + QSKIP("OpenGL is not supported on this platform."); + // Reparenting Rhi widget into a window causes the window to be // recreated, but after recreation the window properties such as // window position must remain the same diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index 1b3afa0a4dc..cbe554f997f 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -8,10 +8,12 @@ #include <QPushButton> #include <QMainWindow> #include <QMenuBar> +#include <QPlainTextEdit> #include <QToolBar> #include <QToolButton> #include <QStatusBar> #include <QListWidget> +#include <QVBoxLayout> #include <QWidgetAction> #include <QScreen> #include <QSpinBox> @@ -96,6 +98,8 @@ private slots: void QTBUG_89082_actionTipsHide(); void QTBUG8122_widgetActionCrashOnClose(); void widgetActionTriggerClosesMenu(); + void widgetActionContextMenu(); + void transientParent(); void QTBUG_10735_crashWithDialog(); @@ -1590,6 +1594,36 @@ void tst_QMenu::widgetActionTriggerClosesMenu() QCOMPARE(actionTriggered, &widgetAction); } +void tst_QMenu::widgetActionContextMenu() // QTBUG-134757 +{ + QPushButton openButton("open"); + QMenu *menu = new QMenu(&openButton); + QVBoxLayout *layout = new QVBoxLayout; + QWidgetAction widgetAction(menu); + QWidget menuWidget(menu); + QPlainTextEdit edit; + openButton.setMenu(menu); + menuWidget.setLayout(layout); + widgetAction.setDefaultWidget(&menuWidget); + menu->addAction(&widgetAction); + layout->addWidget(&edit); + + openButton.show(); + QVERIFY(QTest::qWaitForWindowExposed(&openButton)); + + // Click the QPushButton to open its menu + QTest::mouseClick(&openButton, Qt::LeftButton); + QVERIFY(QTest::qWaitForWindowExposed(&menuWidget)); + QWindow *popupWindow = edit.window()->windowHandle(); + QVERIFY(popupWindow); + QCOMPARE(QApplication::activePopupWidget(), menu); + + // Right-click the QPlainTextEdit to open its context menu + QTest::mouseClick(popupWindow, Qt::RightButton); + QVERIFY(qobject_cast<QMenu *>(QApplication::activePopupWidget())); + QCOMPARE_NE(QApplication::activePopupWidget(), menu); +} + void tst_QMenu::transientParent() { QMainWindow window; diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 609a0847862..f4baf6b1714 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -1233,12 +1233,41 @@ void tst_QMenuBar::taskQTBUG4965_escapeEaten() } #endif +#ifdef Q_OS_LINUX +class ResizeCounter : public QObject +{ +public: + explicit ResizeCounter(QMenuBar *bar) + { + Q_ASSERT(bar); + bar->installEventFilter(this); + } + + int resizeCount() const { return m_resizeCount; } + +protected: + bool eventFilter(QObject *o, QEvent *event) override + { + Q_UNUSED(o); + if (event->type() == QEvent::Resize) + ++m_resizeCount; + return false; + } + +private: + int m_resizeCount = 0; +}; +#endif + void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions() { if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); QMenuBar menubar; +#ifdef Q_OS_LINUX + ResizeCounter counter(&menubar); +#endif menubar.setNativeMenuBar(false); //we can't check the geometry of native menubars QAction * m = menubar.addAction( "&m" ); @@ -1247,6 +1276,12 @@ void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions() centerOnScreen(&menubar); menubar.show(); QVERIFY(QTest::qWaitForWindowActive(&menubar)); + +#ifdef Q_OS_LINUX + if (QSysInfo::productType().contains("opensuse")) + QVERIFY(QTest::qWaitFor([&]{ return counter.resizeCount() == 2;})); +#endif + menubar.setActiveAction(m); QCOMPARE(menubar.activeAction(), m); QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Right); diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index b2cdd6b72c2..c5df30dd7d1 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -63,12 +63,12 @@ private slots: void tst_QOpenGLWidget::initTestCase() { -#if !QT_CONFIG(run_opengl_tests) - QSKIP("Skip test as run-opengl-tests feature is off."); -#endif // See QOpenGLWidget constructor if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)) QSKIP("QOpenGLWidget is not supported on this platform."); + + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + QSKIP("OpenGL is not supported on this platform."); } void tst_QOpenGLWidget::create() diff --git a/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp b/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp index da4fee72f65..457df2159b1 100644 --- a/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp +++ b/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp @@ -64,7 +64,7 @@ void tst_QRhiWidget::testData() QTest::newRow("Null") << QRhiWidget::Api::Null; #endif -#if QT_CONFIG(opengl) && QT_CONFIG(run_opengl_tests) +#if QT_CONFIG(opengl) if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) QTest::newRow("OpenGL") << QRhiWidget::Api::OpenGL; #endif diff --git a/util/lexgen/REUSE.toml b/util/lexgen/REUSE.toml index a5081d017ce..422b63a9d3d 100644 --- a/util/lexgen/REUSE.toml +++ b/util/lexgen/REUSE.toml @@ -4,11 +4,11 @@ version = 1 path = ["tests/testdata/**", "test.lexgen"] comment = "test data" precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" [[annotations]] path = ["lexgen.lexgen", "css3-simplified.lexgen"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0" diff --git a/util/x86simdgen/REUSE.toml b/util/x86simdgen/REUSE.toml index b9311d13368..3d41d1e40b4 100644 --- a/util/x86simdgen/REUSE.toml +++ b/util/x86simdgen/REUSE.toml @@ -10,11 +10,11 @@ SPDX-License-Identifier = "Apache-2.0" [[annotations]] path = ["Makefile"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] path = ["README.md"] precedence = "closest" -SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd." +SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" |