diff options
87 files changed, 1503 insertions, 772 deletions
diff --git a/cmake/QtAndroidHelpers.cmake b/cmake/QtAndroidHelpers.cmake index b473c2c331b..59a469b1683 100644 --- a/cmake/QtAndroidHelpers.cmake +++ b/cmake/QtAndroidHelpers.cmake @@ -442,8 +442,9 @@ function(qt_internal_create_source_jar) add_dependencies(android_source_jars ${jar_target}) if(QT_WILL_INSTALL) + qt_path_join(destination "${INSTALL_DATADIR}" "android" "${module}") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${jar_name}-${PROJECT_VERSION}.jar" - DESTINATION "${INSTALL_DATADIR}/android/${module}" + DESTINATION "${destination}" COMPONENT _install_android_source_jar_${module} EXCLUDE_FROM_ALL ) diff --git a/cmake/QtPublicCMakeVersionHelpers.cmake b/cmake/QtPublicCMakeVersionHelpers.cmake index 292d97c84e7..0207c087e1a 100644 --- a/cmake/QtPublicCMakeVersionHelpers.cmake +++ b/cmake/QtPublicCMakeVersionHelpers.cmake @@ -107,10 +107,9 @@ endfunction() # Handle force-assignment of CMP0156 policy when using CMake 3.29+. # # For Apple-platforms we set it to NEW, to avoid duplicate linker issues when using -ObjC flag. +# For Emscripten / WebAssembly we also set it to NEW, to avoid duplicate linker issues. # -# For non-Apple platforms we set it to OLD, because we haven't done the necessary testing to -# see which platforms / linkers can handle the new deduplication behavior, without breaking the -# various linking techniques that Qt uses for object library propagation. +# For other platforms, we leave the policy value as-is, without showing any warnings. function(__qt_internal_set_cmp0156) # Exit early if not using CMake 3.29+ if(NOT POLICY CMP0156) @@ -164,29 +163,32 @@ function(__qt_internal_set_cmp0156) set(default_policy_value NEW) set(unsupported_policy_value OLD) else() - # For non-Apple linkers, we keep the previous behavior of not deduplicating libraries, - # because we haven't done the necessary testing to identify on which platforms - # it is safe to deduplicate. - set(default_policy_value OLD) - set(unsupported_policy_value NEW) + # For other platforms we don't enforce any policy values and keep them as-is. + set(default_policy_value "") + set(unsupported_policy_value "") endif() # Force set the default policy value for the given platform, even if the policy value is # the same or empty. That's because in the calling function scope, the value can be empty # due to the cmake_minimum_required call in Qt6Config.cmake resetting the policy value. - get_cmake_property(debug_message_shown _qt_internal_cmp0156_debug_message_shown) - if(NOT debug_message_shown) - message(DEBUG "Force setting the CMP0156 policy to '${default_policy_value}' " - "for platform '${CMAKE_SYSTEM_NAME}'.") - set_property(GLOBAL PROPERTY _qt_internal_cmp0156_debug_message_shown TRUE) - endif() + if(default_policy_value) + get_cmake_property(debug_message_shown _qt_internal_cmp0156_debug_message_shown) + if(NOT debug_message_shown) + message(DEBUG "Force setting the CMP0156 policy to '${default_policy_value}' " + "for platform '${CMAKE_SYSTEM_NAME}'.") + set_property(GLOBAL PROPERTY _qt_internal_cmp0156_debug_message_shown TRUE) + endif() - cmake_policy(SET CMP0156 "${default_policy_value}") + cmake_policy(SET CMP0156 "${default_policy_value}") + endif() - # If the policy is explicitly set to a value other than the default, issue a warning. + # If the policy is explicitly set to a value other than the (non-empty) default, issue a + # warning. # Don't show the warning if the policy is unset, which would be the default for most # projects, because it's too much noise. Also don't show it for Qt builds. - if("${policy_value}" STREQUAL "${unsupported_policy_value}" AND NOT QT_BUILDING_QT) + if(unsupported_policy_value + AND "${policy_value}" STREQUAL "${unsupported_policy_value}" + AND NOT QT_BUILDING_QT) message(WARNING "CMP0156 is set to '${policy_value}'. Qt forces the '${default_policy_value}'" " behavior of this policy for the '${CMAKE_SYSTEM_NAME}' platform by default." diff --git a/coin/instructions/cmake_regular_test_instructions.yaml b/coin/instructions/cmake_regular_test_instructions.yaml index 91593df6b4f..60fbd2e8e20 100644 --- a/coin/instructions/cmake_regular_test_instructions.yaml +++ b/coin/instructions/cmake_regular_test_instructions.yaml @@ -33,7 +33,7 @@ instructions: conditions: - condition: property property: id - contains_value: "macos-15" + equals_value: "macos-26-arm64-tests" - condition: runtime env_var: COIN_CTEST_FORCE_IGNORE_EXIT_CODE equals_value: null diff --git a/coin/instructions/vxworks_testrunner.yaml b/coin/instructions/vxworks_testrunner.yaml index 6979b6807da..e348290d6d4 100644 --- a/coin/instructions/vxworks_testrunner.yaml +++ b/coin/instructions/vxworks_testrunner.yaml @@ -5,8 +5,39 @@ instructions: fileMode: 493 fileContents: | #!/bin/bash + + # Seconds of serial silence before triggering an SSH probe; also the cadence for repeated probes + EMPTY_READ_GRACE=20 + + # Maximum time (s) with no output while waiting; exceeding this triggers a timeout failure + MAX_WAIT_TIME=700 + quoted_args=`python3 -c 'import sys, shlex; print(shlex.join(sys.argv[2:]))' "$@"` + ssh_cmd() { + LD_LIBRARY_PATH=/usr/lib ssh -n -q \ + -o BatchMode=yes -o ConnectTimeout=1 -o HostKeyAlgorithms=+ssh-rsa \ + ${VXWORKS_SSH} "$@" </dev/null + } + + ssh_probe_status() { + # Returns one of: FINISHED | RUNNING | UNRESPONSIVE + local out + out="$(ssh_cmd 'cmd rtp list; exit' 2>&1 || true)" + # If we don't see the normal SSH epilogue ("Au revoir!"), treat as UNRESPONSIVE + # (system is probably under a heavy load) + if ! printf '%s\n' "$out" | /usr/bin/grep -q 'Au revoir!'; then + echo "UNRESPONSIVE" + return 0 + fi + # Determine if our RTP is present; currently we match by 'tests' substring in 'rtp list' output + if printf '%s\n' "$out" | /usr/bin/grep -Fq "tests"; then + echo "RUNNING" + else + echo "FINISHED" + fi + } + testdir="$(dirname $1)" testexecutable="$1" echo RUNNING via serial: "$quoted_args" @@ -33,8 +64,16 @@ instructions: read -t 1 testline</tmp/guest.out fi - if [[ -z "$testline" ]]; then - echo "Restarting stuck emulator" + probe0="$(ssh_probe_status)" + + if [[ -z "$testline" || "$probe0" != "FINISHED" ]]; then + if [[ "$probe0" == "UNRESPONSIVE" ]]; then + echo "Restarting stuck emulator (SSH down)" + elif [[ "$probe0" == "RUNNING" ]]; then + echo "Restarting stuck emulator (RTP still running)" + else + echo "Restarting stuck emulator (serial down)" + fi pkill qemu-system rm /tmp/guest.in /tmp/guest.out mkfifo /tmp/guest.in /tmp/guest.out @@ -43,37 +82,79 @@ instructions: /bin/bash /home/qt/work/coin_vxworks_vars.sh sleep 1 else - echo "Emulator responding" + echo "VxWorks is functional" fi - # Empty output + # Empty out any pending serial output to start clean while read -t 1 line; do echo $line done < /tmp/guest.out echo "cmd cd $testdir" > /tmp/guest.in sleep 1 + + # Empty line before result of cd + read -t 1 line_cmd </tmp/guest.out + + if read -t 5 cdline </tmp/guest.out; then + cdline_clean=$(printf '%s' "$cdline" | tr -d '\r') + if printf '%s' "$cdline_clean" | /usr/bin/grep -Eq 'error\s*='; then + printf 'entering %s: %s\n' "$testdir" "$cdline_clean" + exit 1 + fi + fi + echo "</home/qt/work/vx.sh" > /tmp/guest.in - while read -t 600 line; do + silent_seconds=0 + last_probe_result="NONE" + + while true; do + if ! read -t $EMPTY_READ_GRACE line; then + silent_seconds=$((silent_seconds + EMPTY_READ_GRACE)) + + probe="$(ssh_probe_status)" + last_probe_result="$probe" + if [[ "$probe" == "UNRESPONSIVE" ]]; then + echo "system is under heavy load after ${silent_seconds}s of silence (SSH unresponsive)" + elif [[ "$probe" == "FINISHED" ]]; then + echo "RTP finished after ${silent_seconds}s of silence, ending" + exit 0 + fi + # RUNNING or UNRESPONSIVE - keep waiting + if (( silent_seconds >= MAX_WAIT_TIME )); then + echo "Timeout: no output for ${MAX_WAIT_TIME}s (last SSH probe: ${last_probe_result})" + exit 1 + fi + continue + fi + + # We received serial output + silent_seconds=0 + echo "$line" + if echo "$line" | /usr/bin/grep -q "qtest_in_vxworks_complete" then read -t 1 line</tmp/guest.out echo "$line" exitcode=$(echo "$line" | sed -nr 's/qtest_in_vxworks_complete: (-?[0-9]+)/\1/gp' | tr -d '\r') + probe="$(ssh_probe_status)" + if [[ "$probe" != "FINISHED" ]]; then + echo "final SSH probe: ${probe}" + fi exit $exitcode fi # Handle crashes if echo "$line" | /usr/bin/grep -qE "(SIGSEGV)|(SIGABRT)|(S_rtpLib_[A-Z_]+)" then - # Empty output pipe + # Drain the pipe for context, mark as crashed, and restart emulator next run. while read -t 1 line; do echo $line done < /tmp/guest.out echo "Test crashed" - pkill qemu-system # Kill emulator to force restart on next test start + pkill qemu-system exit 1 fi done < /tmp/guest.out diff --git a/examples/widgets/doc/src/draggableicons.qdoc b/examples/widgets/doc/src/draggableicons.qdoc index 0f1feacb7fb..3cf9b9b7266 100644 --- a/examples/widgets/doc/src/draggableicons.qdoc +++ b/examples/widgets/doc/src/draggableicons.qdoc @@ -4,6 +4,7 @@ /*! \example draganddrop/draggableicons \title Draggable Icons Example + \ingroup examples-user-input \examplecategory {User Interface Components} \brief The Draggable Icons example shows how to drag and drop image data between widgets diff --git a/examples/widgets/doc/src/draggabletext.qdoc b/examples/widgets/doc/src/draggabletext.qdoc index 3609ed5a1a1..f34e166ed89 100644 --- a/examples/widgets/doc/src/draggabletext.qdoc +++ b/examples/widgets/doc/src/draggabletext.qdoc @@ -4,6 +4,7 @@ /*! \example draganddrop/draggabletext \title Draggable Text Example + \ingroup examples-user-input \examplecategory {User Interface Components} \brief Illustrates how to drag and drop text between widgets. diff --git a/examples/widgets/doc/src/dropsite.qdoc b/examples/widgets/doc/src/dropsite.qdoc index 4c38ffc50d3..baa7b22fa8a 100644 --- a/examples/widgets/doc/src/dropsite.qdoc +++ b/examples/widgets/doc/src/dropsite.qdoc @@ -4,6 +4,7 @@ /*! \example draganddrop/dropsite \title Drop Site Example + \ingroup examples-user-input \examplecategory {User Interface Components} \brief The example shows how to distinguish the various MIME formats available diff --git a/examples/widgets/doc/src/tablet.qdoc b/examples/widgets/doc/src/tablet.qdoc index a18eb3249e7..f1238238df9 100644 --- a/examples/widgets/doc/src/tablet.qdoc +++ b/examples/widgets/doc/src/tablet.qdoc @@ -5,7 +5,7 @@ \example widgets/tablet \title Tablet Example \examplecategory {User Interface Components} - \ingroup examples-widgets + \ingroup examples-user-input \brief This example shows how to use a Wacom tablet in Qt applications. \image tabletexample.png {Application displaying a drawing area} diff --git a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc index 03b31edabc5..63ca14787b6 100644 --- a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc +++ b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc @@ -5,6 +5,7 @@ \example gestures/imagegestures \title Image Gestures Example \examplecategory {User Interface Components} + \ingroup examples-user-input \brief Demonstrates the use of simple gestures in a widget. This example shows how to enable gestures for a widget and use gesture input diff --git a/examples/widgets/touch/knobs/doc/src/touch-knobs.qdoc b/examples/widgets/touch/knobs/doc/src/touch-knobs.qdoc index d229f54f5c7..38bd2016cab 100644 --- a/examples/widgets/touch/knobs/doc/src/touch-knobs.qdoc +++ b/examples/widgets/touch/knobs/doc/src/touch-knobs.qdoc @@ -6,6 +6,7 @@ \title Touch Knobs Example \examplecategory {User Interface Components} \ingroup touchinputexamples + \ingroup examples-user-input \brief Shows how to create custom controls that accept touch input. The Touch Knobs example shows how to create custom controls that 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 b60c58013f5..e245f731ce8 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtView.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java @@ -25,11 +25,11 @@ abstract class QtView extends ViewGroup implements QtNative.AppStateDetailsListe void onQtWindowLoaded(); } - protected QtWindow m_window; - protected long m_windowReference; - protected long m_parentWindowReference; - protected QtWindowListener m_windowListener; - protected final QtEmbeddedViewInterface m_viewInterface; + private QtWindow m_window; + private long m_windowReference; + private long m_parentWindowReference; + private QtWindowListener m_windowListener; + private final QtEmbeddedViewInterface m_viewInterface; // Implement in subclass to handle the creation of the QWindow and its parent container. // TODO could we take care of the parent window creation and parenting outside of the // window creation method to simplify things if user would extend this? Preferably without @@ -164,10 +164,43 @@ abstract class QtView extends ViewGroup implements QtNative.AppStateDetailsListe m_windowReference = windowReference; } - long windowReference() { + long getWindowReference() { return m_windowReference; } + void setQtWindow(QtWindow qtWindow) { + m_window = qtWindow; + } + + QtWindow getQtWindow() { + return m_window; + } + + long getParentWindowReference() + { + return m_parentWindowReference; + } + + void setParentWindowReference(long reference) + { + m_parentWindowReference = reference; + } + + QtWindowListener getWindowListener() + { + return m_windowListener; + } + + void setWindowListener(QtWindowListener listner) + { + m_windowListener = listner; + } + + QtEmbeddedViewInterface getViewInterface() + { + return m_viewInterface; + } + // Set the visibility of the underlying QWindow. If visible is true, showNormal() is called. // If false, the window is hidden. void setWindowVisible(boolean visible) { @@ -203,10 +236,6 @@ abstract class QtView extends ViewGroup implements QtNative.AppStateDetailsListe setWindowReference(0L); } - QtWindow getQtWindow() { - return m_window; - } - @Override public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) { if (!details.isStarted) { diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index d8743a1c976..337703bda3a 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -175,10 +175,12 @@ qt_internal_add_module(Core kernel/qfunctions_p.h kernel/qiterable.cpp kernel/qiterable.h kernel/qiterable_impl.h kernel/qmath.cpp kernel/qmath.h + kernel/qmetaassociation.cpp kernel/qmetacontainer.cpp kernel/qmetacontainer.h kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h kernel/qmetaobject_moc_p.h kernel/qmetaobjectbuilder.cpp kernel/qmetaobjectbuilder_p.h + kernel/qmetasequence.cpp kernel/qmetatype.cpp kernel/qmetatype.h kernel/qmetatype_p.h kernel/qmimedata.cpp kernel/qmimedata.h kernel/qtmetamacros.h kernel/qtmocconstants.h kernel/qtmochelpers.h diff --git a/src/corelib/doc/src/qtcore.qdoc b/src/corelib/doc/src/qtcore.qdoc index ea65d68da58..ec5fa564639 100644 --- a/src/corelib/doc/src/qtcore.qdoc +++ b/src/corelib/doc/src/qtcore.qdoc @@ -19,8 +19,7 @@ \module QtCorePrivate \title Qt Core Private C++ Classes \qtvariable core-private - \qtcmakepackage Core - \qtcmaketargetitem CorePrivate + \qtcmakepackage CorePrivate \preliminary \brief Provides private core functionality. @@ -28,7 +27,7 @@ private Qt Core APIs: \badcode - find_package(Qt6 REQUIRED COMPONENTS Core) + find_package(Qt6 REQUIRED COMPONENTS CorePrivate) target_link_libraries(mytarget PRIVATE Qt6::CorePrivate) \endcode */ diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h index 01106abf34d..cb8514105a0 100644 --- a/src/corelib/global/qfloat16.h +++ b/src/corelib/global/qfloat16.h @@ -354,15 +354,15 @@ inline int qIntCast(qfloat16 f) noexcept { return int(static_cast<qfloat16::NearestFloat>(f)); } #if !defined(Q_QDOC) && !QFLOAT16_IS_NATIVE -QT_WARNING_PUSH -QT_WARNING_DISABLE_CLANG("-Wc99-extensions") -QT_WARNING_DISABLE_GCC("-Wold-style-cast") inline qfloat16::qfloat16(float f) noexcept { #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__) __m128 packsingle = _mm_set_ss(f); + QT_WARNING_PUSH + QT_WARNING_DISABLE_GCC("-Wold-style-cast") // _mm_cvtps_ph() may be a macro using C-style casts __m128i packhalf = _mm_cvtps_ph(packsingle, 0); - b16 = _mm_extract_epi16(packhalf, 0); + QT_WARNING_POP + b16 = quint16(_mm_extract_epi16(packhalf, 0)); #elif defined (__ARM_FP16_FORMAT_IEEE) __fp16 f16 = __fp16(f); memcpy(&b16, &f16, sizeof(quint16)); @@ -393,7 +393,6 @@ inline qfloat16::qfloat16(float f) noexcept b16 = quint16(base + (mantissa >> shift)); #endif } -QT_WARNING_POP inline qfloat16::operator float() const noexcept { diff --git a/src/corelib/kernel/qmetaassociation.cpp b/src/corelib/kernel/qmetaassociation.cpp new file mode 100644 index 00000000000..dc239424e6d --- /dev/null +++ b/src/corelib/kernel/qmetaassociation.cpp @@ -0,0 +1,299 @@ +// Copyright (C) 2025 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 + +#include <QtCore/qmetacontainer.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMetaAssociation + \inmodule QtCore + \since 6.0 + \brief The QMetaAssociation class allows type erased access to associative containers. + + \ingroup objectmodel + + \compares equality + + The class provides a number of primitive container operations, using void* + as operands. This way, you can manipulate a generic container retrieved from + a Variant without knowing its type. + + QMetaAssociation covers both, containers with mapped values such as QMap or + QHash, and containers that only hold keys such as QSet. + + The void* arguments to the various methods are typically created by using + a \l QVariant of the respective container or value type, and calling + its \l QVariant::data() or \l QVariant::constData() methods. However, you + can also pass plain pointers to objects of the container or value type. + + Iterator invalidation follows the rules given by the underlying containers + and is not expressed in the API. Therefore, for a truly generic container, + any iterators should be considered invalid after any write operation. + + \sa QMetaContainer, QMetaSequence, QIterable, QIterator +*/ + +/*! + \fn template<typename C> QMetaAssociation QMetaAssociation::fromContainer() + \since 6.0 + + Returns the QMetaAssociation corresponding to the type given as template parameter. +*/ + +/*! + Returns the meta type for keys in the container. + */ +QMetaType QMetaAssociation::keyMetaType() const +{ + if (auto iface = d()) + return QMetaType(iface->keyMetaType); + return QMetaType(); +} + +/*! + Returns the meta type for mapped values in the container. + */ +QMetaType QMetaAssociation::mappedMetaType() const +{ + if (auto iface = d()) + return QMetaType(iface->mappedMetaType); + return QMetaType(); +} + +/*! + \fn bool QMetaAssociation::canInsertKey() const + + Returns \c true if keys can be added to the container using \l insertKey(), + otherwise returns \c false. + + \sa insertKey() + */ + +/*! + \fn void QMetaAssociation::insertKey(void *container, const void *key) const + + Inserts the \a key into the \a container if possible. If the container has + mapped values a default-create mapped value is associated with the \a key. + + \sa canInsertKey() + */ + +/*! + \fn bool QMetaAssociation::canRemoveKey() const + + Returns \c true if keys can be removed from the container using + \l removeKey(), otherwise returns \c false. + + \sa removeKey() + */ + +/*! + \fn void QMetaAssociation::removeKey(void *container, const void *key) const + + Removes the \a key and its associated mapped value from the \a container if + possible. + + \sa canRemoveKey() + */ + +/*! + \fn bool QMetaAssociation::canContainsKey() const + + Returns \c true if the container can be queried for keys using + \l containsKey(), otherwise returns \c false. + */ + +/*! + \fn bool QMetaAssociation::containsKey(const void *container, const void *key) const + + Returns \c true if the \a container can be queried for keys and contains the + \a key, otherwise returns \c false. + + \sa canContainsKey() + */ + +/*! + \fn bool QMetaAssociation::canGetMappedAtKey() const + + Returns \c true if the container can be queried for values using + \l mappedAtKey(), otherwise returns \c false. + */ + +/*! + \fn void QMetaAssociation::mappedAtKey(const void *container, const void *key, void *mapped) const + + Retrieves the mapped value associated with the \a key in the \a container + and places it in the memory location pointed to by \a mapped, if that is + possible. + + \sa canGetMappedAtKey() + */ + +/*! + \fn bool QMetaAssociation::canSetMappedAtKey() const + + Returns \c true if mapped values can be modified in the container using + \l setMappedAtKey(), otherwise returns \c false. + + \sa setMappedAtKey() + */ + +/*! + \fn void QMetaAssociation::setMappedAtKey(void *container, const void *key, const void *mapped) const + + Overwrites the value associated with the \a key in the \a container using + the \a mapped value passed as argument if that is possible. + + \sa canSetMappedAtKey() + */ + +/*! + \fn bool QMetaAssociation::canGetKeyAtIterator() const + + Returns \c true if a key can be retrieved from a non-const iterator using + \l keyAtIterator(), otherwise returns \c false. + + \sa keyAtIterator() + */ + +/*! + \fn void QMetaAssociation::keyAtIterator(const void *iterator, void *key) const + + Retrieves the key pointed to by the non-const \a iterator and stores it + in the memory location pointed to by \a key, if possible. + + \sa canGetKeyAtIterator(), begin(), end(), createIteratorAtKey() + */ + +/*! + \fn bool QMetaAssociation::canGetKeyAtConstIterator() const + + Returns \c true if a key can be retrieved from a const iterator using + \l keyAtConstIterator(), otherwise returns \c false. + + \sa keyAtConstIterator() + */ + +/*! + \fn void QMetaAssociation::keyAtConstIterator(const void *iterator, void *key) const + + Retrieves the key pointed to by the const \a iterator and stores it + in the memory location pointed to by \a key, if possible. + + \sa canGetKeyAtConstIterator(), constBegin(), constEnd(), createConstIteratorAtKey() + */ + +/*! + \fn bool QMetaAssociation::canGetMappedAtIterator() const + + Returns \c true if a mapped value can be retrieved from a non-const + iterator using \l mappedAtIterator(), otherwise returns \c false. + + \sa mappedAtIterator() + */ + +/*! + \fn void QMetaAssociation::mappedAtIterator(const void *iterator, void *mapped) const + + Retrieves the mapped value pointed to by the non-const \a iterator and + stores it in the memory location pointed to by \a mapped, if possible. + + \sa canGetMappedAtIterator(), begin(), end(), createIteratorAtKey() + */ + +/*! + \fn bool QMetaAssociation::canGetMappedAtConstIterator() const + + Returns \c true if a mapped value can be retrieved from a const iterator + using \l mappedAtConstIterator(), otherwise returns \c false. + + \sa mappedAtConstIterator() + */ + +/*! + \fn void QMetaAssociation::mappedAtConstIterator(const void *iterator, void *mapped) const + + Retrieves the mapped value pointed to by the const \a iterator and + stores it in the memory location pointed to by \a mapped, if possible. + + \sa canGetMappedAtConstIterator(), constBegin(), constEnd(), createConstIteratorAtKey() + */ + +/*! + \fn bool QMetaAssociation::canSetMappedAtIterator() const + + Returns \c true if a mapped value can be set via a non-const iterator using + \l setMappedAtIterator(), otherwise returns \c false. + + \sa setMappedAtIterator() + */ + +/*! + \fn void QMetaAssociation::setMappedAtIterator(const void *iterator, const void *mapped) const + + Writes the \a mapped value to the container location pointed to by the + non-const \a iterator, if possible. + + \sa canSetMappedAtIterator(), begin(), end(), createIteratorAtKey() + */ + +/*! + \fn bool QMetaAssociation::canCreateIteratorAtKey() const + + Returns \c true if an iterator pointing to an entry in the container can be + created using \l createIteratorAtKey(), otherwise returns false. + + \sa createIteratorAtKey() + */ + +/*! + \fn void *QMetaAssociation::createIteratorAtKey(void *container, const void *key) const + + Returns a non-const iterator pointing to the entry of \a key in the + \a container, if possible. If the entry doesn't exist, creates a non-const + iterator pointing to the end of the \a container. If no non-const iterator + can be created, returns \c nullptr. + + The non-const iterator has to be destroyed using destroyIterator(). + + \sa canCreateIteratorAtKey(), begin(), end(), destroyIterator() + */ + +/*! + \fn bool QMetaAssociation::canCreateConstIteratorAtKey() const + + Returns \c true if a const iterator pointing to an entry in the container + can be created using \l createConstIteratorAtKey(), otherwise returns false. + */ + +/*! + \fn void *QMetaAssociation::createConstIteratorAtKey(const void *container, const void *key) const + + Returns a const iterator pointing to the entry of \a key in the + \a container, if possible. If the entry doesn't exist, creates a const + iterator pointing to the end of the \a container. If no const iterator can + be created, returns \c nullptr. + + The const iterator has to be destroyed using destroyConstIterator(). + + \sa canCreateConstIteratorAtKey(), constBegin(), constEnd(), destroyConstIterator() + */ + +/*! + \fn bool QMetaAssociation::operator==(const QMetaAssociation &lhs, const QMetaAssociation &rhs) + + Returns \c true if the QMetaAssociation \a lhs represents the same container type + as the QMetaAssociation \a rhs, otherwise returns \c false. +*/ + +/*! + \fn bool QMetaAssociation::operator!=(const QMetaAssociation &lhs, const QMetaAssociation &rhs) + + Returns \c true if the QMetaAssociation \a lhs represents a different container + type than the QMetaAssociation \a rhs, otherwise returns \c false. +*/ + + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetacontainer.cpp b/src/corelib/kernel/qmetacontainer.cpp index 3a1a33a478a..4b4ea06d8b9 100644 --- a/src/corelib/kernel/qmetacontainer.cpp +++ b/src/corelib/kernel/qmetacontainer.cpp @@ -7,37 +7,6 @@ QT_BEGIN_NAMESPACE /*! - \class QMetaSequence - \inmodule QtCore - \since 6.0 - \brief The QMetaSequence class allows type erased access to sequential containers. - - \ingroup objectmodel - - \compares equality - - The class provides a number of primitive container operations, using void* - as operands. This way, you can manipulate a generic container retrieved from - a Variant without knowing its type. - - The void* arguments to the various methods are typically created by using - a \l QVariant of the respective container or value type, and calling - its \l QVariant::data() or \l QVariant::constData() methods. However, you - can also pass plain pointers to objects of the container or value type. - - Iterator invalidation follows the rules given by the underlying containers - and is not expressed in the API. Therefore, for a truly generic container, - any iterators should be considered invalid after any write operation. -*/ - -/*! - \fn template<typename C> QMetaSequence QMetaSequence::fromContainer() - \since 6.0 - - Returns the QMetaSequence corresponding to the type given as template parameter. -*/ - -/*! \class QMetaContainer \inmodule QtCore \since 6.0 @@ -66,7 +35,7 @@ QT_BEGIN_NAMESPACE specializations of input iterators. This method will also return \c true if the container provides one of those. - QMetaSequence assumes that const and non-const iterators for the same + QMetaContainer assumes that const and non-const iterators for the same container have the same iterator traits. */ bool QMetaContainer::hasInputIterator() const @@ -83,7 +52,7 @@ bool QMetaContainer::hasInputIterator() const specializations of forward iterators. This method will also return \c true if the container provides one of those. - QMetaSequence assumes that const and non-const iterators for the same + QMetaContainer assumes that const and non-const iterators for the same container have the same iterator traits. */ bool QMetaContainer::hasForwardIterator() const @@ -99,7 +68,7 @@ bool QMetaContainer::hasForwardIterator() const std::bidirectional_iterator_tag and std::random_access_iterator_tag, respectively. Otherwise returns \c false. - QMetaSequence assumes that const and non-const iterators for the same + QMetaContainer assumes that const and non-const iterators for the same container have the same iterator traits. */ bool QMetaContainer::hasBidirectionalIterator() const @@ -114,7 +83,7 @@ bool QMetaContainer::hasBidirectionalIterator() const iterator as defined by std::random_access_iterator_tag, otherwise returns \c false. - QMetaSequence assumes that const and non-const iterators for the same + QMetaContainer assumes that const and non-const iterators for the same container have the same iterator traits. */ bool QMetaContainer::hasRandomAccessIterator() const @@ -125,147 +94,6 @@ bool QMetaContainer::hasRandomAccessIterator() const } /*! - Returns the meta type for values stored in the container. - */ -QMetaType QMetaSequence::valueMetaType() const -{ - if (auto iface = d()) - return QMetaType(iface->valueMetaType); - return QMetaType(); -} - -/*! - Returns \c true if the underlying container is sortable, otherwise returns - \c false. A container is considered sortable if values added to it are - placed in a defined location. Inserting into or adding to a sortable - container will always succeed. Inserting into or adding to an unsortable - container may not succeed, for example if the container is a QSet that - already contains the value being inserted. - - \sa addValue(), insertValueAtIterator(), canAddValueAtBegin(), - canAddValueAtEnd(), canRemoveValueAtBegin(), canRemoveValueAtEnd() - */ -bool QMetaSequence::isSortable() const -{ - if (auto iface = d()) { - return (iface->addRemoveCapabilities - & (QtMetaContainerPrivate::CanAddAtBegin | QtMetaContainerPrivate::CanAddAtEnd)) - && (iface->addRemoveCapabilities - & (QtMetaContainerPrivate::CanRemoveAtBegin - | QtMetaContainerPrivate::CanRemoveAtEnd)); - } - return false; -} - -/*! - Returns \c true if values added using \l addValue() can be placed at the - beginning of the container, otherwise returns \c false. - - \sa addValueAtBegin(), canAddValueAtEnd() - */ -bool QMetaSequence::canAddValueAtBegin() const -{ - if (auto iface = d()) { - return iface->addValueFn - && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanAddAtBegin; - } - return false; -} - -/*! - Adds \a value to the beginning of \a container if possible. If - \l canAddValueAtBegin() returns \c false, the \a value is not added. - - \sa canAddValueAtBegin(), isSortable(), removeValueAtBegin() - */ -void QMetaSequence::addValueAtBegin(void *container, const void *value) const -{ - if (canAddValueAtBegin()) - d()->addValueFn(container, value, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin); -} - -/*! - Returns \c true if values can be removed from the beginning of the container - using \l removeValue(), otherwise returns \c false. - - \sa removeValueAtBegin(), canRemoveValueAtEnd() - */ -bool QMetaSequence::canRemoveValueAtBegin() const -{ - if (auto iface = d()) { - return iface->removeValueFn - && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanRemoveAtBegin; - } - return false; -} - -/*! - Removes a value from the beginning of \a container if possible. If - \l canRemoveValueAtBegin() returns \c false, the value is not removed. - - \sa canRemoveValueAtBegin(), isSortable(), addValueAtBegin() - */ -void QMetaSequence::removeValueAtBegin(void *container) const -{ - if (canRemoveValueAtBegin()) - d()->removeValueFn(container, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin); -} - -/*! - Returns \c true if values added using \l addValue() can be placed at the - end of the container, otherwise returns \c false. - - \sa addValueAtEnd(), canAddValueAtBegin() - */ -bool QMetaSequence::canAddValueAtEnd() const -{ - if (auto iface = d()) { - return iface->addValueFn - && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanAddAtEnd; - } - return false; -} - -/*! - Adds \a value to the end of \a container if possible. If - \l canAddValueAtEnd() returns \c false, the \a value is not added. - - \sa canAddValueAtEnd(), isSortable(), removeValueAtEnd() - */ -void QMetaSequence::addValueAtEnd(void *container, const void *value) const -{ - if (canAddValueAtEnd()) - d()->addValueFn(container, value, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd); -} - -/*! - Returns \c true if values can be removed from the end of the container - using \l removeValue(), otherwise returns \c false. - - \sa removeValueAtEnd(), canRemoveValueAtBegin() - */ -bool QMetaSequence::canRemoveValueAtEnd() const -{ - if (auto iface = d()) { - return iface->removeValueFn - && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanRemoveAtEnd; - } - return false; -} - -/*! - Removes a value from the end of \a container if possible. If - \l canRemoveValueAtEnd() returns \c false, the value is not removed. - - \sa canRemoveValueAtEnd(), isSortable(), addValueAtEnd() - */ -void QMetaSequence::removeValueAtEnd(void *container) const -{ - if (canRemoveValueAtEnd()) - d()->removeValueFn(container, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd); -} - -/*! Returns \c true if the container can be queried for its size, \c false otherwise. @@ -309,122 +137,6 @@ void QMetaContainer::clear(void *container) const } /*! - Returns \c true if values can be retrieved from the container by index, - otherwise \c false. - - \sa valueAtIndex() - */ -bool QMetaSequence::canGetValueAtIndex() const -{ - if (auto iface = d()) - return iface->valueAtIndexFn; - return false; -} - -/*! - Retrieves the value at \a index in the \a container and places it in the - memory location pointed to by \a result, if that is possible. - - \sa canGetValueAtIndex() - */ -void QMetaSequence::valueAtIndex(const void *container, qsizetype index, void *result) const -{ - if (canGetValueAtIndex()) - d()->valueAtIndexFn(container, index, result); -} - -/*! - Returns \c true if a value can be written to the container by index, - otherwise \c false. - - \sa setValueAtIndex() -*/ -bool QMetaSequence::canSetValueAtIndex() const -{ - if (auto iface = d()) - return iface->setValueAtIndexFn; - return false; -} - -/*! - Overwrites the value at \a index in the \a container using the \a value - passed as parameter if that is possible. - - \sa canSetValueAtIndex() - */ -void QMetaSequence::setValueAtIndex(void *container, qsizetype index, const void *value) const -{ - if (canSetValueAtIndex()) - d()->setValueAtIndexFn(container, index, value); -} - -/*! - Returns \c true if values can be added to the container, \c false - otherwise. - - \sa addValue(), isSortable() - */ -bool QMetaSequence::canAddValue() const -{ - if (auto iface = d()) - return iface->addValueFn; - return false; -} - -/*! - Adds \a value to the \a container if possible. If \l canAddValue() - returns \c false, the \a value is not added. Else, if - \l canAddValueAtEnd() returns \c true, the \a value is added - to the end of the \a container. Else, if - \l canAddValueAtBegin() returns \c true, the \a value is added to - the beginning of the container. Else, the value is added in an unspecified - place or not at all. The latter is the case for adding values to an - unordered container, for example \l QSet. - - \sa canAddValue(), canAddValueAtBegin(), - canAddValueAtEnd(), isSortable(), removeValue() - */ -void QMetaSequence::addValue(void *container, const void *value) const -{ - if (canAddValue()) { - d()->addValueFn(container, value, - QtMetaContainerPrivate::QMetaSequenceInterface::Unspecified); - } -} - -/*! - Returns \c true if values can be removed from the container, \c false - otherwise. - - \sa removeValue(), isSortable() - */ -bool QMetaSequence::canRemoveValue() const -{ - if (auto iface = d()) - return iface->removeValueFn; - return false; -} - -/*! - Removes a value from the \a container if possible. If - \l canRemoveValue() returns \c false, no value is removed. Else, if - \l canRemoveValueAtEnd() returns \c true, the last value in - the \a container is removed. Else, if \l canRemoveValueAtBegin() - returns \c true, the first value in the \a container is removed. Else, - an unspecified value or nothing is removed. - - \sa canRemoveValue(), canRemoveValueAtBegin(), - canRemoveValueAtEnd(), isSortable(), addValue() - */ -void QMetaSequence::removeValue(void *container) const -{ - if (canRemoveValue()) { - d()->removeValueFn(container, - QtMetaContainerPrivate::QMetaSequenceInterface::Unspecified); - } -} - -/*! Returns \c true if the underlying container offers a non-const iterator, \c false otherwise. @@ -456,7 +168,7 @@ void *QMetaContainer::begin(void *container) const { return hasIterator() ? d_ptr->createIteratorFn( - container, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin) + container, QtMetaContainerPrivate::QMetaContainerInterface::AtBegin) : nullptr; } @@ -473,7 +185,7 @@ void *QMetaContainer::end(void *container) const { return hasIterator() ? d_ptr->createIteratorFn( - container, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd) + container, QtMetaContainerPrivate::QMetaContainerInterface::AtEnd) : nullptr; } @@ -541,137 +253,6 @@ qsizetype QMetaContainer::diffIterator(const void *i, const void *j) const } /*! - Returns \c true if the underlying container can retrieve the value pointed - to by a non-const iterator, \c false otherwise. - - \sa hasIterator(), valueAtIterator() - */ -bool QMetaSequence::canGetValueAtIterator() const -{ - if (auto iface = d()) - return iface->valueAtIteratorFn; - return false; -} - -/*! - Retrieves the value pointed to by the non-const \a iterator and stores it - in the memory location pointed to by \a result, if possible. - - \sa canGetValueAtIterator(), begin(), end() - */ -void QMetaSequence::valueAtIterator(const void *iterator, void *result) const -{ - if (canGetValueAtIterator()) - d()->valueAtIteratorFn(iterator, result); -} - -/*! - Returns \c true if the underlying container can write to the value pointed - to by a non-const iterator, \c false otherwise. - - \sa hasIterator(), setValueAtIterator() - */ -bool QMetaSequence::canSetValueAtIterator() const -{ - if (auto iface = d()) - return iface->setValueAtIteratorFn; - return false; -} - -/*! - Writes \a value to the value pointed to by the non-const \a iterator, if - possible. - - \sa canSetValueAtIterator(), begin(), end() - */ -void QMetaSequence::setValueAtIterator(const void *iterator, const void *value) const -{ - if (canSetValueAtIterator()) - d()->setValueAtIteratorFn(iterator, value); -} - -/*! - Returns \c true if the underlying container can insert a new value, taking - the location pointed to by a non-const iterator into account. - - \sa hasIterator(), insertValueAtIterator() - */ -bool QMetaSequence::canInsertValueAtIterator() const -{ - if (auto iface = d()) - return iface->insertValueAtIteratorFn; - return false; -} - -/*! - Inserts \a value into the \a container, if possible, taking the non-const - \a iterator into account. If \l canInsertValueAtIterator() returns - \c false, the \a value is not inserted. Else if \l isSortable() returns - \c true, the value is inserted before the value pointed to by - \a iterator. Else, the \a value is inserted at an unspecified place or not - at all. In the latter case, the \a iterator is taken as a hint. If it points - to the correct place for the \a value, the operation may be faster than a - \l addValue() without iterator. - - \sa canInsertValueAtIterator(), isSortable(), begin(), end() - */ -void QMetaSequence::insertValueAtIterator(void *container, const void *iterator, - const void *value) const -{ - if (canInsertValueAtIterator()) - d()->insertValueAtIteratorFn(container, iterator, value); -} - -/*! - Returns \c true if the value pointed to by a non-const iterator can be - erased, \c false otherwise. - - \sa hasIterator(), eraseValueAtIterator() - */ -bool QMetaSequence::canEraseValueAtIterator() const -{ - if (auto iface = d()) - return iface->eraseValueAtIteratorFn; - return false; -} - -/*! - Erases the value pointed to by the non-const \a iterator from the - \a container, if possible. - - \sa canEraseValueAtIterator(), begin(), end() - */ -void QMetaSequence::eraseValueAtIterator(void *container, const void *iterator) const -{ - if (canEraseValueAtIterator()) - d()->eraseValueAtIteratorFn(container, iterator); -} - -/*! - Returns \c true if a range between two iterators can be erased from the - container, \c false otherwise. - */ -bool QMetaSequence::canEraseRangeAtIterator() const -{ - if (auto iface = d()) - return iface->eraseRangeAtIteratorFn; - return false; -} - -/*! - Erases the range of values between the iterators \a iterator1 and - \a iterator2 from the \a container, if possible. - - \sa canEraseValueAtIterator(), begin(), end() - */ -void QMetaSequence::eraseRangeAtIterator(void *container, const void *iterator1, - const void *iterator2) const -{ - if (canEraseRangeAtIterator()) - d()->eraseRangeAtIteratorFn(container, iterator1, iterator2); -} - -/*! Returns \c true if the underlying container offers a const iterator, \c false otherwise. @@ -704,7 +285,7 @@ void *QMetaContainer::constBegin(const void *container) const { return hasConstIterator() ? d_ptr->createConstIteratorFn( - container, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin) + container, QtMetaContainerPrivate::QMetaContainerInterface::AtBegin) : nullptr; } @@ -721,7 +302,7 @@ void *QMetaContainer::constEnd(const void *container) const { return hasConstIterator() ? d_ptr->createConstIteratorFn( - container, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd) + container, QtMetaContainerPrivate::QMetaContainerInterface::AtEnd) : nullptr; } @@ -788,68 +369,4 @@ qsizetype QMetaContainer::diffConstIterator(const void *i, const void *j) const return hasConstIterator() ? d_ptr->diffConstIteratorFn(i, j) : 0; } -/*! - Returns \c true if the underlying container can retrieve the value pointed - to by a const iterator, \c false otherwise. - - \sa hasConstIterator(), valueAtConstIterator() - */ -bool QMetaSequence::canGetValueAtConstIterator() const -{ - if (auto iface = d()) - return iface->valueAtConstIteratorFn; - return false; -} - -/*! - Retrieves the value pointed to by the const \a iterator and stores it - in the memory location pointed to by \a result, if possible. - - \sa canGetValueAtConstIterator(), constBegin(), constEnd() - */ -void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) const -{ - if (canGetValueAtConstIterator()) - d()->valueAtConstIteratorFn(iterator, result); -} - -/*! - \fn bool QMetaSequence::operator==(const QMetaSequence &lhs, const QMetaSequence &rhs) - \since 6.0 - - Returns \c true if the QMetaSequence \a lhs represents the same container type - as the QMetaSequence \a rhs, otherwise returns \c false. -*/ - -/*! - \fn bool QMetaSequence::operator!=(const QMetaSequence &lhs, const QMetaSequence &rhs) - \since 6.0 - - Returns \c true if the QMetaSequence \a lhs represents a different container - type than the QMetaSequence \a rhs, otherwise returns \c false. -*/ - - -/*! - \internal - Returns the meta type for keys in the container. - */ -QMetaType QMetaAssociation::keyMetaType() const -{ - if (auto iface = d()) - return QMetaType(iface->keyMetaType); - return QMetaType(); -} - -/*! - \internal - Returns the meta type for mapped values in the container. - */ -QMetaType QMetaAssociation::mappedMetaType() const -{ - if (auto iface = d()) - return QMetaType(iface->mappedMetaType); - return QMetaType(); -} - QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetasequence.cpp b/src/corelib/kernel/qmetasequence.cpp new file mode 100644 index 00000000000..1d3f3dfd080 --- /dev/null +++ b/src/corelib/kernel/qmetasequence.cpp @@ -0,0 +1,471 @@ +// Copyright (C) 2025 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 + +#include "qmetacontainer.h" +#include "qmetatype.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMetaSequence + \inmodule QtCore + \since 6.0 + \brief The QMetaSequence class allows type erased access to sequential containers. + + \ingroup objectmodel + + \compares equality + + The class provides a number of primitive container operations, using void* + as operands. This way, you can manipulate a generic container retrieved from + a Variant without knowing its type. + + The void* arguments to the various methods are typically created by using + a \l QVariant of the respective container or value type, and calling + its \l QVariant::data() or \l QVariant::constData() methods. However, you + can also pass plain pointers to objects of the container or value type. + + Iterator invalidation follows the rules given by the underlying containers + and is not expressed in the API. Therefore, for a truly generic container, + any iterators should be considered invalid after any write operation. +*/ + +/*! + \fn template<typename C> QMetaSequence QMetaSequence::fromContainer() + \since 6.0 + + Returns the QMetaSequence corresponding to the type given as template parameter. +*/ + +/*! + Returns the meta type for values stored in the container. + */ +QMetaType QMetaSequence::valueMetaType() const +{ + if (auto iface = d()) + return QMetaType(iface->valueMetaType); + return QMetaType(); +} + +/*! + Returns \c true if the underlying container is sortable, otherwise returns + \c false. A container is considered sortable if values added to it are + placed in a defined location. Inserting into or adding to a sortable + container will always succeed. Inserting into or adding to an unsortable + container may not succeed, for example if the container is a QSet that + already contains the value being inserted. + + \sa addValue(), insertValueAtIterator(), canAddValueAtBegin(), + canAddValueAtEnd(), canRemoveValueAtBegin(), canRemoveValueAtEnd() + */ +bool QMetaSequence::isSortable() const +{ + if (auto iface = d()) { + return (iface->addRemoveCapabilities + & (QtMetaContainerPrivate::CanAddAtBegin | QtMetaContainerPrivate::CanAddAtEnd)) + && (iface->addRemoveCapabilities + & (QtMetaContainerPrivate::CanRemoveAtBegin + | QtMetaContainerPrivate::CanRemoveAtEnd)); + } + return false; +} + +/*! + Returns \c true if values added using \l addValue() can be placed at the + beginning of the container, otherwise returns \c false. + + \sa addValueAtBegin(), canAddValueAtEnd() + */ +bool QMetaSequence::canAddValueAtBegin() const +{ + if (auto iface = d()) { + return iface->addValueFn + && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanAddAtBegin; + } + return false; +} + +/*! + Adds \a value to the beginning of \a container if possible. If + \l canAddValueAtBegin() returns \c false, the \a value is not added. + + \sa canAddValueAtBegin(), isSortable(), removeValueAtBegin() + */ +void QMetaSequence::addValueAtBegin(void *container, const void *value) const +{ + if (canAddValueAtBegin()) + d()->addValueFn(container, value, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin); +} + +/*! + Returns \c true if values can be removed from the beginning of the container + using \l removeValue(), otherwise returns \c false. + + \sa removeValueAtBegin(), canRemoveValueAtEnd() + */ +bool QMetaSequence::canRemoveValueAtBegin() const +{ + if (auto iface = d()) { + return iface->removeValueFn + && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanRemoveAtBegin; + } + return false; +} + +/*! + Removes a value from the beginning of \a container if possible. If + \l canRemoveValueAtBegin() returns \c false, the value is not removed. + + \sa canRemoveValueAtBegin(), isSortable(), addValueAtBegin() + */ +void QMetaSequence::removeValueAtBegin(void *container) const +{ + if (canRemoveValueAtBegin()) + d()->removeValueFn(container, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin); +} + +/*! + Returns \c true if values added using \l addValue() can be placed at the + end of the container, otherwise returns \c false. + + \sa addValueAtEnd(), canAddValueAtBegin() + */ +bool QMetaSequence::canAddValueAtEnd() const +{ + if (auto iface = d()) { + return iface->addValueFn + && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanAddAtEnd; + } + return false; +} + +/*! + Adds \a value to the end of \a container if possible. If + \l canAddValueAtEnd() returns \c false, the \a value is not added. + + \sa canAddValueAtEnd(), isSortable(), removeValueAtEnd() + */ +void QMetaSequence::addValueAtEnd(void *container, const void *value) const +{ + if (canAddValueAtEnd()) + d()->addValueFn(container, value, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd); +} + +/*! + Returns \c true if values can be removed from the end of the container + using \l removeValue(), otherwise returns \c false. + + \sa removeValueAtEnd(), canRemoveValueAtBegin() + */ +bool QMetaSequence::canRemoveValueAtEnd() const +{ + if (auto iface = d()) { + return iface->removeValueFn + && iface->addRemoveCapabilities & QtMetaContainerPrivate::CanRemoveAtEnd; + } + return false; +} + +/*! + Removes a value from the end of \a container if possible. If + \l canRemoveValueAtEnd() returns \c false, the value is not removed. + + \sa canRemoveValueAtEnd(), isSortable(), addValueAtEnd() + */ +void QMetaSequence::removeValueAtEnd(void *container) const +{ + if (canRemoveValueAtEnd()) + d()->removeValueFn(container, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd); +} + +/*! + Returns \c true if values can be retrieved from the container by index, + otherwise \c false. + + \sa valueAtIndex() + */ +bool QMetaSequence::canGetValueAtIndex() const +{ + if (auto iface = d()) + return iface->valueAtIndexFn; + return false; +} + +/*! + Retrieves the value at \a index in the \a container and places it in the + memory location pointed to by \a result, if that is possible. + + \sa canGetValueAtIndex() + */ +void QMetaSequence::valueAtIndex(const void *container, qsizetype index, void *result) const +{ + if (canGetValueAtIndex()) + d()->valueAtIndexFn(container, index, result); +} + +/*! + Returns \c true if a value can be written to the container by index, + otherwise \c false. + + \sa setValueAtIndex() +*/ +bool QMetaSequence::canSetValueAtIndex() const +{ + if (auto iface = d()) + return iface->setValueAtIndexFn; + return false; +} + +/*! + Overwrites the value at \a index in the \a container using the \a value + passed as parameter if that is possible. + + \sa canSetValueAtIndex() + */ +void QMetaSequence::setValueAtIndex(void *container, qsizetype index, const void *value) const +{ + if (canSetValueAtIndex()) + d()->setValueAtIndexFn(container, index, value); +} + +/*! + Returns \c true if values can be added to the container, \c false + otherwise. + + \sa addValue(), isSortable() + */ +bool QMetaSequence::canAddValue() const +{ + if (auto iface = d()) + return iface->addValueFn; + return false; +} + +/*! + Adds \a value to the \a container if possible. If \l canAddValue() + returns \c false, the \a value is not added. Else, if + \l canAddValueAtEnd() returns \c true, the \a value is added + to the end of the \a container. Else, if + \l canAddValueAtBegin() returns \c true, the \a value is added to + the beginning of the container. Else, the value is added in an unspecified + place or not at all. The latter is the case for adding values to an + unordered container, for example \l QSet. + + \sa canAddValue(), canAddValueAtBegin(), + canAddValueAtEnd(), isSortable(), removeValue() + */ +void QMetaSequence::addValue(void *container, const void *value) const +{ + if (canAddValue()) { + d()->addValueFn(container, value, + QtMetaContainerPrivate::QMetaSequenceInterface::Unspecified); + } +} + +/*! + Returns \c true if values can be removed from the container, \c false + otherwise. + + \sa removeValue(), isSortable() + */ +bool QMetaSequence::canRemoveValue() const +{ + if (auto iface = d()) + return iface->removeValueFn; + return false; +} + +/*! + Removes a value from the \a container if possible. If + \l canRemoveValue() returns \c false, no value is removed. Else, if + \l canRemoveValueAtEnd() returns \c true, the last value in + the \a container is removed. Else, if \l canRemoveValueAtBegin() + returns \c true, the first value in the \a container is removed. Else, + an unspecified value or nothing is removed. + + \sa canRemoveValue(), canRemoveValueAtBegin(), + canRemoveValueAtEnd(), isSortable(), addValue() + */ +void QMetaSequence::removeValue(void *container) const +{ + if (canRemoveValue()) { + d()->removeValueFn(container, + QtMetaContainerPrivate::QMetaSequenceInterface::Unspecified); + } +} + + +/*! + Returns \c true if the underlying container can retrieve the value pointed + to by a non-const iterator, \c false otherwise. + + \sa hasIterator(), valueAtIterator() + */ +bool QMetaSequence::canGetValueAtIterator() const +{ + if (auto iface = d()) + return iface->valueAtIteratorFn; + return false; +} + +/*! + Retrieves the value pointed to by the non-const \a iterator and stores it + in the memory location pointed to by \a result, if possible. + + \sa canGetValueAtIterator(), begin(), end() + */ +void QMetaSequence::valueAtIterator(const void *iterator, void *result) const +{ + if (canGetValueAtIterator()) + d()->valueAtIteratorFn(iterator, result); +} + +/*! + Returns \c true if the underlying container can write to the value pointed + to by a non-const iterator, \c false otherwise. + + \sa hasIterator(), setValueAtIterator() + */ +bool QMetaSequence::canSetValueAtIterator() const +{ + if (auto iface = d()) + return iface->setValueAtIteratorFn; + return false; +} + +/*! + Writes \a value to the value pointed to by the non-const \a iterator, if + possible. + + \sa canSetValueAtIterator(), begin(), end() + */ +void QMetaSequence::setValueAtIterator(const void *iterator, const void *value) const +{ + if (canSetValueAtIterator()) + d()->setValueAtIteratorFn(iterator, value); +} + +/*! + Returns \c true if the underlying container can insert a new value, taking + the location pointed to by a non-const iterator into account. + + \sa hasIterator(), insertValueAtIterator() + */ +bool QMetaSequence::canInsertValueAtIterator() const +{ + if (auto iface = d()) + return iface->insertValueAtIteratorFn; + return false; +} + +/*! + Inserts \a value into the \a container, if possible, taking the non-const + \a iterator into account. If \l canInsertValueAtIterator() returns + \c false, the \a value is not inserted. Else if \l isSortable() returns + \c true, the value is inserted before the value pointed to by + \a iterator. Else, the \a value is inserted at an unspecified place or not + at all. In the latter case, the \a iterator is taken as a hint. If it points + to the correct place for the \a value, the operation may be faster than a + \l addValue() without iterator. + + \sa canInsertValueAtIterator(), isSortable(), begin(), end() + */ +void QMetaSequence::insertValueAtIterator(void *container, const void *iterator, + const void *value) const +{ + if (canInsertValueAtIterator()) + d()->insertValueAtIteratorFn(container, iterator, value); +} + +/*! + Returns \c true if the value pointed to by a non-const iterator can be + erased, \c false otherwise. + + \sa hasIterator(), eraseValueAtIterator() + */ +bool QMetaSequence::canEraseValueAtIterator() const +{ + if (auto iface = d()) + return iface->eraseValueAtIteratorFn; + return false; +} + +/*! + Erases the value pointed to by the non-const \a iterator from the + \a container, if possible. + + \sa canEraseValueAtIterator(), begin(), end() + */ +void QMetaSequence::eraseValueAtIterator(void *container, const void *iterator) const +{ + if (canEraseValueAtIterator()) + d()->eraseValueAtIteratorFn(container, iterator); +} + +/*! + Returns \c true if a range between two iterators can be erased from the + container, \c false otherwise. + */ +bool QMetaSequence::canEraseRangeAtIterator() const +{ + if (auto iface = d()) + return iface->eraseRangeAtIteratorFn; + return false; +} + +/*! + Erases the range of values between the iterators \a iterator1 and + \a iterator2 from the \a container, if possible. + + \sa canEraseValueAtIterator(), begin(), end() + */ +void QMetaSequence::eraseRangeAtIterator(void *container, const void *iterator1, + const void *iterator2) const +{ + if (canEraseRangeAtIterator()) + d()->eraseRangeAtIteratorFn(container, iterator1, iterator2); +} + + +/*! + Returns \c true if the underlying container can retrieve the value pointed + to by a const iterator, \c false otherwise. + + \sa hasConstIterator(), valueAtConstIterator() + */ +bool QMetaSequence::canGetValueAtConstIterator() const +{ + if (auto iface = d()) + return iface->valueAtConstIteratorFn; + return false; +} + +/*! + Retrieves the value pointed to by the const \a iterator and stores it + in the memory location pointed to by \a result, if possible. + + \sa canGetValueAtConstIterator(), constBegin(), constEnd() + */ +void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) const +{ + if (canGetValueAtConstIterator()) + d()->valueAtConstIteratorFn(iterator, result); +} + +/*! + \fn bool QMetaSequence::operator==(const QMetaSequence &lhs, const QMetaSequence &rhs) + \since 6.0 + + Returns \c true if the QMetaSequence \a lhs represents the same container type + as the QMetaSequence \a rhs, otherwise returns \c false. +*/ + +/*! + \fn bool QMetaSequence::operator!=(const QMetaSequence &lhs, const QMetaSequence &rhs) + \since 6.0 + + Returns \c true if the QMetaSequence \a lhs represents a different container + type than the QMetaSequence \a rhs, otherwise returns \c false. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index fe510898429..560a8c7d789 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1894,8 +1894,8 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) A timer event will occur every \a interval until killTimer() is called. If \a interval is equal to \c{std::chrono::duration::zero()}, - then the timer event occurs once every time there are no more window - system events to process. + then the timer event occurs once every time control returns to the event + loop, that is, there are no more native window system events to process. \include timers-common.qdocinc negative-intervals-not-allowed diff --git a/src/corelib/kernel/qwinregistry.cpp b/src/corelib/kernel/qwinregistry.cpp index fb315cacb7e..37bf3f99ae1 100644 --- a/src/corelib/kernel/qwinregistry.cpp +++ b/src/corelib/kernel/qwinregistry.cpp @@ -191,7 +191,9 @@ QVariant QWinRegistryKey::value(const QString &subKey) const // Otherwise, the resulting string (which may be empty) is returned. QString QWinRegistryKey::stringValue(const wchar_t *subKey) const { - return value<QString>(subKey).value_or(QString()); + if (auto v = value<QString>(subKey)) + return std::move(*v); + return QString(); } QString QWinRegistryKey::stringValue(const QString &subKey) const diff --git a/src/corelib/serialization/.gitignore b/src/corelib/serialization/.gitignore index 89f9ac04aac..8261c031991 100644 --- a/src/corelib/serialization/.gitignore +++ b/src/corelib/serialization/.gitignore @@ -1 +1,2 @@ +# Qt-Security score:insignificant reason:gitignore out/ diff --git a/src/corelib/serialization/make-xml-parser.sh b/src/corelib/serialization/make-xml-parser.sh index 18898337003..4174949154c 100755 --- a/src/corelib/serialization/make-xml-parser.sh +++ b/src/corelib/serialization/make-xml-parser.sh @@ -1,6 +1,7 @@ #!/bin/sh # Copyright (C) 2016 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +# Qt-Security score:insignificant reason:build-tool-containing-no-compiled-source me=$(dirname $0) mkdir -p $me/out diff --git a/src/corelib/serialization/qcborstream.h b/src/corelib/serialization/qcborstream.h index 7850d266639..e51296f3cca 100644 --- a/src/corelib/serialization/qcborstream.h +++ b/src/corelib/serialization/qcborstream.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2018 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:header-decls-only #ifndef QCBORSTREAM_H #define QCBORSTREAM_H diff --git a/src/corelib/serialization/qjsonparseerror.h b/src/corelib/serialization/qjsonparseerror.h index 803b04c53b6..d8fc94448e6 100644 --- a/src/corelib/serialization/qjsonparseerror.h +++ b/src/corelib/serialization/qjsonparseerror.h @@ -7,6 +7,7 @@ #include <QtCore/qtconfigmacros.h> #include <QtCore/qtcoreexports.h> +#include <QtCore/qtypes.h> QT_BEGIN_NAMESPACE @@ -34,7 +35,8 @@ struct Q_CORE_EXPORT QJsonParseError QString errorString() const; - int offset = -1; + std::conditional_t<QT_VERSION_MAJOR < 7, int, qint64> + offset = -1; ParseError error = NoError; }; diff --git a/src/corelib/serialization/qjsonparser.cpp b/src/corelib/serialization/qjsonparser.cpp index df266a76c79..779287adb1d 100644 --- a/src/corelib/serialization/qjsonparser.cpp +++ b/src/corelib/serialization/qjsonparser.cpp @@ -321,7 +321,9 @@ QCborValue Parser::parse(QJsonParseError *error) error: container.reset(); if (error) { - error->offset = json - head; + using OffType = decltype(error->offset); + error->offset = OffType(json - head); + Q_ASSERT(error->offset == json - head); error->error = lastError; } return QCborValue(); diff --git a/src/corelib/serialization/qjsonparser_p.h b/src/corelib/serialization/qjsonparser_p.h index 6b70af38152..8951bb3129b 100644 --- a/src/corelib/serialization/qjsonparser_p.h +++ b/src/corelib/serialization/qjsonparser_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:header-decls-only #ifndef QJSONPARSER_P_H #define QJSONPARSER_P_H diff --git a/src/corelib/serialization/qjsonwriter_p.h b/src/corelib/serialization/qjsonwriter_p.h index 446ed906e21..10b89f3c106 100644 --- a/src/corelib/serialization/qjsonwriter_p.h +++ b/src/corelib/serialization/qjsonwriter_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:header-decls-only #ifndef QJSONWRITER_P_H #define QJSONWRITER_P_H diff --git a/src/corelib/text/qcollator.cpp b/src/corelib/text/qcollator.cpp index 9ead847843b..6609d17adf4 100644 --- a/src/corelib/text/qcollator.cpp +++ b/src/corelib/text/qcollator.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2013 Aleix Pol Gonzalez <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qcollator_p.h" #include "qstringlist.h" diff --git a/src/corelib/text/qcollator.h b/src/corelib/text/qcollator.h index 870811fc48e..2b1e3963b0d 100644 --- a/src/corelib/text/qcollator.h +++ b/src/corelib/text/qcollator.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2013 Aleix Pol Gonzalez <[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:trivial-impl-only #ifndef QCOLLATOR_H #define QCOLLATOR_H diff --git a/src/corelib/text/qcollator_icu.cpp b/src/corelib/text/qcollator_icu.cpp index 84f9c515374..e13e96285ef 100644 --- a/src/corelib/text/qcollator_icu.cpp +++ b/src/corelib/text/qcollator_icu.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2013 Aleix Pol Gonzalez <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qcollator_p.h" #include "qlocale_p.h" diff --git a/src/corelib/text/qcollator_macx.cpp b/src/corelib/text/qcollator_macx.cpp index 23c23bd53a2..c0561877dd1 100644 --- a/src/corelib/text/qcollator_macx.cpp +++ b/src/corelib/text/qcollator_macx.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 Aleix Pol Gonzalez <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qcollator_p.h" #include "qlocale_p.h" diff --git a/src/corelib/text/qcollator_p.h b/src/corelib/text/qcollator_p.h index b96cdbaa32a..400cafc0c8a 100644 --- a/src/corelib/text/qcollator_p.h +++ b/src/corelib/text/qcollator_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2013 Aleix Pol Gonzalez <[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:trivial-impl-only #ifndef QCOLLATOR_P_H #define QCOLLATOR_P_H diff --git a/src/corelib/text/qcollator_posix.cpp b/src/corelib/text/qcollator_posix.cpp index 5ed80c1b8ea..2712133521c 100644 --- a/src/corelib/text/qcollator_posix.cpp +++ b/src/corelib/text/qcollator_posix.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2013 Aleix Pol Gonzalez <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qcollator_p.h" #include "qstringlist.h" diff --git a/src/corelib/text/qcollator_win.cpp b/src/corelib/text/qcollator_win.cpp index b588f5ff46a..54228b79b31 100644 --- a/src/corelib/text/qcollator_win.cpp +++ b/src/corelib/text/qcollator_win.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 Aleix Pol Gonzalez <[email protected]> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qcollator_p.h" #include "qlocale_p.h" diff --git a/src/corelib/text/qlocale.qdoc b/src/corelib/text/qlocale.qdoc index 3980e9d9a6d..bc88b27477d 100644 --- a/src/corelib/text/qlocale.qdoc +++ b/src/corelib/text/qlocale.qdoc @@ -1,5 +1,6 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only +// Qt-Security score:insignificant reason:docs /*! \class QLocale diff --git a/src/corelib/text/qtliterals.qdoc b/src/corelib/text/qtliterals.qdoc index c4671415ee4..8be03a02236 100644 --- a/src/corelib/text/qtliterals.qdoc +++ b/src/corelib/text/qtliterals.qdoc @@ -1,5 +1,6 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only +// Qt-Security score:insignificant reason:docs /*! \namespace QtLiterals @@ -43,4 +44,8 @@ // in the Qt namespace using namespace Qt; \endcode + + The latter is discouraged, because it doesn't allow you to pick which literal + operators you want in case Qt adds conflicting operators in different + namespaces within Qt::Literals. */ diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index ccd944a0824..3e08df2b5ac 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -1291,6 +1291,9 @@ bool QThread::event(QEvent *event) This function does not stop any event loop running on the thread and does not terminate it in any way. + This function has no effect on the main thread, and does nothing if the thread + is not currently running. + \sa isInterruptionRequested() */ diff --git a/src/gui/doc/images/plaintext-layout.png b/src/gui/doc/images/plaintext-layout.png Binary files differdeleted file mode 100644 index 9172d7a044d..00000000000 --- a/src/gui/doc/images/plaintext-layout.png +++ /dev/null diff --git a/src/gui/doc/images/plaintext-layout.webp b/src/gui/doc/images/plaintext-layout.webp Binary files differnew file mode 100644 index 00000000000..b8266ec5a8c --- /dev/null +++ b/src/gui/doc/images/plaintext-layout.webp diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc index dca2f10bf26..f5d60699deb 100644 --- a/src/gui/doc/src/qtgui.qdoc +++ b/src/gui/doc/src/qtgui.qdoc @@ -17,8 +17,7 @@ /*! \module QtGuiPrivate \title Qt GUI Private C++ Classes - \qtcmakepackage Gui - \qtcmaketargetitem GuiPrivate + \qtcmakepackage GuiPrivate \qtvariable gui-private \brief Provides access to private GUI functionality. @@ -27,7 +26,7 @@ private Qt GUI APIs: \badcode - find_package(Qt6 REQUIRED COMPONENTS Gui) + find_package(Qt6 REQUIRED COMPONENTS GuiPrivate) target_link_libraries(mytarget PRIVATE Qt6::GuiPrivate) \endcode */ diff --git a/src/gui/doc/src/richtext.qdoc b/src/gui/doc/src/richtext.qdoc index 429233ec8f1..2fa49a31e03 100644 --- a/src/gui/doc/src/richtext.qdoc +++ b/src/gui/doc/src/richtext.qdoc @@ -650,7 +650,7 @@ the QTextLayout class, to help developers perform word-wrapping and layout tasks without the need to create a document first. - \image plaintext-layout.png {Screenshot of a text that flows around a + \image plaintext-layout.webp {Screenshot of a text that flows around a circle.} Formatting and drawing a paragraph of plain text is straightforward. diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index c7b6e4ebff3..bb71f8fb6fc 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -1298,7 +1298,10 @@ QString QKeySequencePrivate::keyName(Qt::Key key, QKeySequence::SequenceFormat f bool nativeText = (format == QKeySequence::NativeText); QString p; - if (key && key < Qt::Key_Escape && key != Qt::Key_Space) { + if (nativeText && (key > 0x00 && key <= 0x1f)) { + // Map C0 control codes to the corresponding Control Pictures + p = QChar::fromUcs2(0x2400 + key); + } else if (key && key < Qt::Key_Escape && key != Qt::Key_Space) { if (!QChar::requiresSurrogates(key)) { p = QChar::fromUcs2(key).toUpper(); } else { diff --git a/src/gui/kernel/qplatformwindow_p.h b/src/gui/kernel/qplatformwindow_p.h index c446ac760c0..24c0fd7c431 100644 --- a/src/gui/kernel/qplatformwindow_p.h +++ b/src/gui/kernel/qplatformwindow_p.h @@ -125,6 +125,14 @@ struct Q_GUI_EXPORT QWaylandWindow : public QObject public: QT_DECLARE_NATIVE_INTERFACE(QWaylandWindow, 1, QWindow) + enum WindowType { + Default, + ToolTip, + ComboBox, + Menu, + SubMenu, + }; + virtual wl_surface *surface() const = 0; virtual void setCustomMargins(const QMargins &margins) = 0; virtual void requestXdgActivationToken(uint serial) = 0; @@ -136,6 +144,10 @@ public: return role ? *role : nullptr; } virtual void setSessionRestoreId(const QString &role) = 0; + + virtual void setExtendedWindowType(WindowType windowType) = 0; + virtual void setParentControlGeometry(const QRect &parentAnchor) = 0; + Q_SIGNALS: void surfaceCreated(); void surfaceDestroyed(); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 3b64a8ecf73..a3f9f069b69 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1527,14 +1527,14 @@ void QPainterPrivate::initFrom(const QPaintDevice *device) Q_Q(QPainter); device->initPainter(q); +} - if (extended) { - extended->penChanged(); - } else if (engine) { - engine->setDirty(QPaintEngine::DirtyPen); - engine->setDirty(QPaintEngine::DirtyBrush); - engine->setDirty(QPaintEngine::DirtyFont); - } +void QPainterPrivate::setEngineDirtyFlags(QSpan<const QPaintEngine::DirtyFlags> flags) +{ + if (!engine) + return; + for (const QPaintEngine::DirtyFlags f : flags) + engine->setDirty(f); } /*! @@ -1801,14 +1801,16 @@ bool QPainter::begin(QPaintDevice *pd) d->engine->setActive(begun); } - // Copy painter properties from original paint device, - // required for QPixmap::grabWidget() - if (d->original_device->devType() == QInternal::Widget) { + switch (d->original_device->devType()) { + case QInternal::Widget: d->initFrom(d->original_device); - } else { + break; + + default: d->state->layoutDirection = Qt::LayoutDirectionAuto; // make sure we have a font compatible with the paintdevice d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device()); + break; } QRect systemRect = d->engine->systemRect(); @@ -1834,6 +1836,15 @@ bool QPainter::begin(QPaintDevice *pd) d->state->emulationSpecifier = 0; + switch (d->original_device->devType()) { + case QInternal::Widget: + // for widgets we've aleady initialized the painter above + break; + default: + d->initFrom(d->original_device); + break; + } + return true; } diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index dd4653a5788..a6f93134ca0 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -15,6 +15,7 @@ // We mean it. // +#include <QtCore/qspan.h> #include <QtCore/qvarlengtharray.h> #include <QtGui/private/qtguiglobal_p.h> #include "QtGui/qbrush.h" @@ -242,6 +243,8 @@ public: std::unique_ptr<QEmulationPaintEngine> emulationEngine; QPaintEngineEx *extended = nullptr; QBrush colorBrush; // for fill with solid color + + Q_GUI_EXPORT void setEngineDirtyFlags(QSpan<const QPaintEngine::DirtyFlags>); }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 79799ca2ece..0d435c95048 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -1154,7 +1154,8 @@ void QDashStroker::processCurrentSubpath() elen -= std::floor(elen * invSumLength) * sumLength; // Update dash offset. while (!done) { - qreal dpos = pos + dashes[idash] - doffset - estart; + // parentheses to avoid float rounding issues: qreal(4) + 0.1 - 0.1 - 4 < 0 + qreal dpos = (pos + dashes[idash]) - (doffset + estart); Q_ASSERT(dpos >= 0); @@ -1189,7 +1190,8 @@ void QDashStroker::processCurrentSubpath() bool has_offset = doffset > 0; bool evenDash = (idash & 1) == 0; - qreal dpos = pos + dashes[idash] - doffset - estart; + // parentheses to avoid float rounding issues: qreal(4) + 0.1 - 0.1 - 4 < 0 + qreal dpos = (pos + dashes[idash]) - (doffset + estart); Q_ASSERT(dpos >= 0); diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index 1b6e76c2017..5797d1a68b4 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -16,6 +16,7 @@ #include <qbytearray.h> #include <qdatastream.h> #include <qdatetime.h> +#include <QtCore/private/qstringiterator_p.h> QT_BEGIN_NAMESPACE @@ -582,8 +583,11 @@ bool QTextHtmlImporter::appendNodeText() QString textToInsert; textToInsert.reserve(text.size()); - for (QChar ch : text) { - if (ch.isSpace() + QStringIterator it(text); + while (it.hasNext()) { + char32_t ch = it.next(); + + if (QChar::isSpace(ch) && ch != QChar::Nbsp && ch != QChar::ParagraphSeparator) { @@ -646,12 +650,12 @@ bool QTextHtmlImporter::appendNodeText() format.setAnchor(true); format.setAnchorNames(namedAnchors); - cursor.insertText(ch, format); + cursor.insertText(QString::fromUcs4(&ch, 1), format); namedAnchors.clear(); format.clearProperty(QTextFormat::IsAnchor); format.clearProperty(QTextFormat::AnchorName); } else { - textToInsert += ch; + textToInsert += QChar::fromUcs4(ch); } } } diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 53a984306c6..d722bceb289 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -657,8 +657,8 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextTableCellFormat & \value FontStyleName \value FontPointSize \value FontPixelSize - \value FontSizeAdjustment Specifies the change in size given to the fontsize already set using - FontPointSize or FontPixelSize. + \value FontSizeAdjustment Specifies an integer adjustment added to the base font size set using + \c FontPointSize or \c FontPixelSize. \value FontFixedPitch \omitvalue FontSizeIncrement \value FontWeight diff --git a/src/gui/util/qundostack.cpp b/src/gui/util/qundostack.cpp index 3d1d8a2b788..27b131cd733 100644 --- a/src/gui/util/qundostack.cpp +++ b/src/gui/util/qundostack.cpp @@ -425,16 +425,16 @@ void QUndoStackPrivate::setIndex(int idx, bool clean) emit q->indexChanged(index); } - const ActionState newUndoState{q->canUndo(), q->undoText()}; - if (indexChanged || newUndoState != undoActionState) { - undoActionState = newUndoState; + if (ActionState newUndoState{q->canUndo(), q->undoText()}; + indexChanged || newUndoState != undoActionState) { + undoActionState = std::move(newUndoState); emit q->canUndoChanged(undoActionState.enabled); emit q->undoTextChanged(undoActionState.text); } - const ActionState newRedoState{q->canRedo(), q->redoText()}; - if (indexChanged || newRedoState != redoActionState) { - redoActionState = newRedoState; + if (ActionState newRedoState{q->canRedo(), q->redoText()}; + indexChanged || newRedoState != redoActionState) { + redoActionState = std::move(newRedoState); emit q->canRedoChanged(redoActionState.enabled); emit q->redoTextChanged(redoActionState.text); } diff --git a/src/gui/util/qundostack_p.h b/src/gui/util/qundostack_p.h index fea201ce62d..6bdcf5fb20b 100644 --- a/src/gui/util/qundostack_p.h +++ b/src/gui/util/qundostack_p.h @@ -59,10 +59,17 @@ public: bool enabled = false; QString text; - bool operator!=(const ActionState &other) const noexcept - { - return enabled != other.enabled || text != other.text; - } + friend bool operator==(const ActionState &lhs, const ActionState &rhs) noexcept +#ifdef __cpp_impl_three_way_comparison + = default; +#else + { return lhs.enabled == rhs.enabled && lhs.text == rhs.text; } + friend bool operator!=(const ActionState &lhs, const ActionState &rhs) noexcept + { return !(lhs == rhs); } +#endif + // some compiler's reject seed = 0) = delete, overload instead: + friend void qHash(const ActionState &key, size_t seed) = delete; + friend void qHash(const ActionState &key) = delete; }; QList<QUndoCommand*> command_list; diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index c8555cdc659..f64742ff133 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -291,7 +291,7 @@ void QAndroidPlatformScreen::topVisibleWindowChanged() if (w && w->handle()) { QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle()); if (platformWindow) { - platformWindow->updateSystemUiVisibility(); + platformWindow->updateSystemUiVisibility(w->windowStates(), w->flags()); platformWindow->updateFocusedEditText(); } } diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 96c4bfa06f1..c4245998772 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -56,15 +56,12 @@ void QAndroidPlatformWindow::initialize() isForeignWindow(), m_nativeParentQtWindow, listener); m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId"); - m_windowFlags = Qt::Widget; - m_windowState = Qt::WindowNoState; // the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save // the fact that it's a raster window for now m_isRaster = window->surfaceType() == QSurface::RasterSurface; - setWindowState(window->windowStates()); // the following is in relation to the virtual geometry - const bool forceMaximize = m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen); + const bool forceMaximize = window->windowStates() & (Qt::WindowMaximized | Qt::WindowFullScreen); const QRect nativeScreenGeometry = platformScreen()->availableGeometry(); if (forceMaximize) { setGeometry(nativeScreenGeometry); @@ -123,7 +120,7 @@ void QAndroidPlatformWindow::raise() QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason); return; } - updateSystemUiVisibility(); + updateSystemUiVisibility(window()->windowStates(), window()->flags()); platformScreen()->raise(this); } @@ -167,13 +164,13 @@ void QAndroidPlatformWindow::setVisible(bool visible) if (!visible && window() == qGuiApp->focusWindow()) { platformScreen()->topVisibleWindowChanged(); } else { - updateSystemUiVisibility(); - if ((m_windowState & Qt::WindowFullScreen) - || (window()->flags() & Qt::ExpandedClientAreaHint)) { + const Qt::WindowStates states = window()->windowStates(); + const Qt::WindowFlags flags = window()->flags(); + updateSystemUiVisibility(states, flags); + if (states & Qt::WindowFullScreen || flags & Qt::ExpandedClientAreaHint) setGeometry(platformScreen()->geometry()); - } else if (m_windowState & Qt::WindowMaximized) { + else if (states & Qt::WindowMaximized) setGeometry(platformScreen()->availableGeometry()); - } requestActivateWindow(); } } @@ -188,27 +185,18 @@ void QAndroidPlatformWindow::setVisible(bool visible) void QAndroidPlatformWindow::setWindowState(Qt::WindowStates state) { - if (m_windowState == state) - return; - QPlatformWindow::setWindowState(state); - m_windowState = state; if (window()->isVisible()) - updateSystemUiVisibility(); + updateSystemUiVisibility(state, window()->flags()); } void QAndroidPlatformWindow::setWindowFlags(Qt::WindowFlags flags) { - if (m_windowFlags == flags) - return; + QPlatformWindow::setWindowFlags(flags); - m_windowFlags = flags; -} - -Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const -{ - return m_windowFlags; + if (window()->isVisible()) + updateSystemUiVisibility(window()->windowStates(), flags); } void QAndroidPlatformWindow::setParent(const QPlatformWindow *window) @@ -256,16 +244,15 @@ void QAndroidPlatformWindow::requestActivateWindow() raise(); } -void QAndroidPlatformWindow::updateSystemUiVisibility() +void QAndroidPlatformWindow::updateSystemUiVisibility(Qt::WindowStates states, Qt::WindowFlags flags) { - const int flags = window()->flags(); const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window; if (!isNonRegularWindow) { auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>(); iface->runOnAndroidMainThread([=]() { using namespace QtJniTypes; auto activity = iface->context().object<Activity>(); - if (m_windowState & Qt::WindowFullScreen) + if (states & Qt::WindowFullScreen) QtWindowInsetsController::callStaticMethod("showFullScreen", activity); else if (flags & Qt::ExpandedClientAreaHint) QtWindowInsetsController::callStaticMethod("showExpanded", activity); diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 07f4e12b35c..826a8d30ade 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -43,7 +43,6 @@ public: void setWindowState(Qt::WindowStates state) override; void setWindowFlags(Qt::WindowFlags flags) override; - Qt::WindowFlags windowFlags() const; void setParent(const QPlatformWindow *window) override; WId winId() const override; @@ -58,7 +57,7 @@ public: void propagateSizeHints() override; void requestActivateWindow() override; - void updateSystemUiVisibility(); + void updateSystemUiVisibility(Qt::WindowStates states, Qt::WindowFlags flags); void updateFocusedEditText(); inline bool isRaster() const { return m_isRaster; } bool isExposed() const override; @@ -82,8 +81,6 @@ protected: bool isEmbeddingContainer() const; virtual void clearSurface() {} - Qt::WindowFlags m_windowFlags; - Qt::WindowStates m_windowState; bool m_isRaster; int m_nativeViewId = -1; diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h index 60b9bc8fc02..8fdcf88293e 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h @@ -2,6 +2,9 @@ // 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 QIOSIMAGEPICKERCONTROLLER_H +#define QIOSIMAGEPICKERCONTROLLER_H + #import <UIKit/UIKit.h> #include "../../qiosfiledialog.h" @@ -9,3 +12,5 @@ @interface QIOSImagePickerController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> - (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog; @end + +#endif // QIOSIMAGEPICKERCONTROLLER_H diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.h b/src/plugins/platforms/ios/qiosdocumentpickercontroller.h index 289c3ee3258..a227312c5b0 100644 --- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.h +++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.h @@ -2,6 +2,9 @@ // 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 QIOSDOCUMENTPICKERCONTROLLER_H +#define QIOSDOCUMENTPICKERCONTROLLER_H + #import <UIKit/UIKit.h> #import <UniformTypeIdentifiers/UniformTypeIdentifiers.h> @@ -12,3 +15,5 @@ UIAdaptivePresentationControllerDelegate> - (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog; @end + +#endif // QIOSDOCUMENTPICKERCONTROLLER_H diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.h b/src/plugins/platforms/ios/qiosplatformaccessibility.h index 04cddf00f4e..1ccc5bd089a 100644 --- a/src/plugins/platforms/ios/qiosplatformaccessibility.h +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.h @@ -23,7 +23,7 @@ public: private: QMacNotificationObserver m_focusObserver; - QMacAccessibilityElement *m_focusElement; + QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *m_focusElement; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm index 26f48468c45..a63c75757e4 100644 --- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -12,6 +12,8 @@ #include "qioswindow.h" #include "quiaccessibilityelement.h" +QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); + QIOSPlatformAccessibility::QIOSPlatformAccessibility() { m_focusObserver = QMacNotificationObserver( diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h index addfae3d748..7d73ed9821a 100644 --- a/src/plugins/platforms/ios/qiostextresponder.h +++ b/src/plugins/platforms/ios/qiostextresponder.h @@ -2,6 +2,9 @@ // 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 QIOSTEXTRESPONDER_H +#define QIOSTEXTRESPONDER_H + #import <UIKit/UIKit.h> #include <QtCore/qstring.h> @@ -50,3 +53,5 @@ QT_END_NAMESPACE @property(nonatomic, assign) id<UITextInputDelegate> inputDelegate; @end + +#endif // QIOSTEXTRESPONDER_H diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 23a4c506c24..5024013ba77 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -10,9 +10,6 @@ #import <UIKit/UIKit.h> -class QIOSContext; -class QIOSWindow; - @class QUIView; QT_BEGIN_NAMESPACE @@ -84,7 +81,7 @@ private: QDebug operator<<(QDebug debug, const QIOSWindow *window); #endif -QT_MANGLE_NAMESPACE(QUIView) *quiview_cast(UIView *view); +QUIView *quiview_cast(UIView *view); QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 84726216021..12ae3646ad9 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -2,6 +2,9 @@ // 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 QUIVIEW_H +#define QUIVIEW_H + #import <UIKit/UIKit.h> #include <qhash.h> @@ -39,3 +42,5 @@ QT_END_NAMESPACE @interface QUIMetalView : QUIView @end #endif + +#endif // QUIVIEW_H diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index 8386b65bdce..17422bd606d 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -697,108 +697,135 @@ void QWaylandXdgSurface::setWindowPosition(const QPoint &position) window()->updateExposure(); } +static QtWayland::xdg_positioner::gravity gravityFromEdge(Qt::Edges edges) +{ + switch (edges) { + case Qt::Edges(): + return QtWayland::xdg_positioner::gravity_none; + case Qt::TopEdge: + return QtWayland::xdg_positioner::gravity_top; + case Qt::TopEdge | Qt::RightEdge: + return QtWayland::xdg_positioner::gravity_top_right; + case Qt::RightEdge: + return QtWayland::xdg_positioner::gravity_right; + case Qt::BottomEdge | Qt::RightEdge: + return QtWayland::xdg_positioner::gravity_bottom_right; + case Qt::BottomEdge: + return QtWayland::xdg_positioner::gravity_bottom; + case Qt::BottomEdge | Qt::LeftEdge: + return QtWayland::xdg_positioner::gravity_bottom_left; + case Qt::LeftEdge: + return QtWayland::xdg_positioner::gravity_left; + case Qt::TopEdge | Qt::LeftEdge: + return QtWayland::xdg_positioner::gravity_top_left; + } + qCWarning(lcQpaWayland) << "Cannot map positioner gravity " << edges; + return QtWayland::xdg_positioner::gravity_none; +} + +static QtWayland::xdg_positioner::anchor anchorFromEdge(Qt::Edges edges) +{ + switch (edges) { + case Qt::Edges(): + return QtWayland::xdg_positioner::anchor_none; + case Qt::TopEdge: + return QtWayland::xdg_positioner::anchor_top; + case Qt::TopEdge | Qt::RightEdge: + return QtWayland::xdg_positioner::anchor_top_right; + case Qt::RightEdge: + return QtWayland::xdg_positioner::anchor_right; + case Qt::BottomEdge | Qt::RightEdge: + return QtWayland::xdg_positioner::anchor_bottom_right; + case Qt::BottomEdge: + return QtWayland::xdg_positioner::anchor_bottom; + case Qt::BottomEdge | Qt::LeftEdge: + return QtWayland::xdg_positioner::anchor_bottom_left; + case Qt::LeftEdge: + return QtWayland::xdg_positioner::anchor_left; + case Qt::TopEdge | Qt::LeftEdge: + return QtWayland::xdg_positioner::anchor_top_left; + } + qCWarning(lcQpaWayland) << "Cannot map positioner anchor" << edges; + return QtWayland::xdg_positioner::anchor_none; +} + std::unique_ptr<QWaylandXdgSurface::Positioner> QWaylandXdgSurface::createPositioner(QWaylandWindow *parent) { std::unique_ptr<Positioner> positioner(new Positioner(m_shell)); - // set_popup expects a position relative to the parent - QRect windowGeometry = m_window->windowContentGeometry(); - QMargins windowMargins = m_window->windowContentMargins() - m_window->clientSideMargins(); - QMargins parentMargins = parent->windowContentMargins() - parent->clientSideMargins(); - // These property overrides may be removed when public API becomes available - QRect placementAnchor = m_window->window()->property("_q_waylandPopupAnchorRect").toRect(); - if (!placementAnchor.isValid()) { - placementAnchor = QRect(m_window->geometry().topLeft() - parent->geometry().topLeft(), QSize(1,1)); - } - placementAnchor.translate(windowMargins.left(), windowMargins.top()); - placementAnchor.translate(-parentMargins.left(), -parentMargins.top()); + // Default case, map the guessed global position to a relative position + QRect placementAnchor = QRect(m_window->geometry().topLeft() - parent->geometry().topLeft(), QSize(1,1)); + Qt::Edges anchor = Qt::TopEdge | Qt::RightEdge; + Qt::Edges gravity = Qt::BottomEdge | Qt::RightEdge; + uint32_t constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x | QtWayland::xdg_positioner::constraint_adjustment_slide_y; - uint32_t anchor = QtWayland::xdg_positioner::anchor_top_left; + // Override from window type + if (m_window->parentControlGeometry().isValid()) + placementAnchor = m_window->parentControlGeometry(); + + switch (m_window->extendedWindowType()) { + case QNativeInterface::Private::QWaylandWindow::Menu: + case QNativeInterface::Private::QWaylandWindow::WindowType::ComboBox: + anchor = Qt::BottomEdge | Qt::LeftEdge; + gravity = Qt::BottomEdge | Qt::RightEdge; + constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x | + QtWayland::xdg_positioner::constraint_adjustment_flip_y | QtWayland::xdg_positioner::constraint_adjustment_slide_y; + break; + case QNativeInterface::Private::QWaylandWindow::SubMenu: + anchor = Qt::TopEdge | Qt::RightEdge; + gravity = Qt::BottomEdge | Qt::RightEdge; + constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_flip_x | + QtWayland::xdg_positioner::constraint_adjustment_slide_y; + break; + case QNativeInterface::Private::QWaylandWindow::ToolTip: + anchor = Qt::BottomEdge | Qt::RightEdge; + gravity = Qt::BottomEdge | Qt::RightEdge; + constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_flip_x | QtWayland::xdg_positioner::constraint_adjustment_slide_x | + QtWayland::xdg_positioner::constraint_adjustment_flip_y | QtWayland::xdg_positioner::constraint_adjustment_slide_y; + break; + default: + break; + } + + if (qApp->layoutDirection() == Qt::RightToLeft) { + if (anchor & (Qt::RightEdge | Qt::LeftEdge)) + anchor ^= (Qt::RightEdge | Qt::LeftEdge); + if (gravity & (Qt::RightEdge | Qt::LeftEdge)) + gravity ^= (Qt::RightEdge | Qt::LeftEdge); + } + + // Override with properties fauxAPI + const QVariant placementAnchorVariant = m_window->window()->property("_q_waylandPopupAnchorRect"); + if (placementAnchorVariant.isValid()) + placementAnchor = placementAnchorVariant.toRect(); const QVariant anchorVariant = m_window->window()->property("_q_waylandPopupAnchor"); - if (anchorVariant.isValid()) { - switch (anchorVariant.value<Qt::Edges>()) { - case Qt::Edges(): - anchor = QtWayland::xdg_positioner::anchor_none; - break; - case Qt::TopEdge: - anchor = QtWayland::xdg_positioner::anchor_top; - break; - case Qt::TopEdge | Qt::RightEdge: - anchor = QtWayland::xdg_positioner::anchor_top_right; - break; - case Qt::RightEdge: - anchor = QtWayland::xdg_positioner::anchor_right; - break; - case Qt::BottomEdge | Qt::RightEdge: - anchor = QtWayland::xdg_positioner::anchor_bottom_right; - break; - case Qt::BottomEdge: - anchor = QtWayland::xdg_positioner::anchor_bottom; - break; - case Qt::BottomEdge | Qt::LeftEdge: - anchor = QtWayland::xdg_positioner::anchor_bottom_left; - break; - case Qt::LeftEdge: - anchor = QtWayland::xdg_positioner::anchor_left; - break; - case Qt::TopEdge | Qt::LeftEdge: - anchor = QtWayland::xdg_positioner::anchor_top_left; - break; - } - } - - uint32_t gravity = QtWayland::xdg_positioner::gravity_bottom_right; + if (anchorVariant.isValid()) + anchor = anchorVariant.value<Qt::Edges>(); const QVariant popupGravityVariant = m_window->window()->property("_q_waylandPopupGravity"); - if (popupGravityVariant.isValid()) { - switch (popupGravityVariant.value<Qt::Edges>()) { - case Qt::Edges(): - gravity = QtWayland::xdg_positioner::gravity_none; - break; - case Qt::TopEdge: - gravity = QtWayland::xdg_positioner::gravity_top; - break; - case Qt::TopEdge | Qt::RightEdge: - gravity = QtWayland::xdg_positioner::gravity_top_right; - break; - case Qt::RightEdge: - gravity = QtWayland::xdg_positioner::gravity_right; - break; - case Qt::BottomEdge | Qt::RightEdge: - gravity = QtWayland::xdg_positioner::gravity_bottom_right; - break; - case Qt::BottomEdge: - gravity = QtWayland::xdg_positioner::gravity_bottom; - break; - case Qt::BottomEdge | Qt::LeftEdge: - gravity = QtWayland::xdg_positioner::gravity_bottom_left; - break; - case Qt::LeftEdge: - gravity = QtWayland::xdg_positioner::gravity_left; - break; - case Qt::TopEdge | Qt::LeftEdge: - gravity = QtWayland::xdg_positioner::gravity_top_left; - break; - } - } - - uint32_t constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x | QtWayland::xdg_positioner::constraint_adjustment_slide_y; + if (popupGravityVariant.isValid()) + gravity = popupGravityVariant.value<Qt::Edges>(); const QVariant constraintAdjustmentVariant = m_window->window()->property("_q_waylandPopupConstraintAdjustment"); - if (constraintAdjustmentVariant.isValid()) { + if (constraintAdjustmentVariant.isValid()) constraintAdjustment = constraintAdjustmentVariant.toUInt(); - } + + // set_popup expects a position relative to the parent + QRect windowGeometry = m_window->windowContentGeometry(); + QMargins windowMargins = m_window->windowContentMargins() - m_window->clientSideMargins(); + QMargins parentMargins = parent->windowContentMargins() - parent->clientSideMargins(); + placementAnchor.translate(windowMargins.left(), windowMargins.top()); + placementAnchor.translate(-parentMargins.left(), -parentMargins.top()); positioner->set_anchor_rect(placementAnchor.x(), placementAnchor.y(), placementAnchor.width(), placementAnchor.height()); - positioner->set_anchor(anchor); - positioner->set_gravity(gravity); + positioner->set_anchor(anchorFromEdge(anchor)); + positioner->set_gravity(gravityFromEdge(gravity)); positioner->set_size(windowGeometry.width(), windowGeometry.height()); positioner->set_constraint_adjustment(constraintAdjustment); return positioner; } - void QWaylandXdgSurface::setIcon(const QIcon &icon) { if (!m_shell->m_topLevelIconManager || !m_toplevel) diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 7c300843518..be527b08f4d 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -481,8 +481,9 @@ void QWaylandWindow::setGeometry(const QRect &r) if (mShellSurface && !mInResizeFromApplyConfigure) { const QRect frameGeometry = r.marginsAdded(clientSideMargins()).marginsRemoved(windowContentMargins()); - if (qt_window_private(window())->positionAutomatic) + if (qt_window_private(window())->positionAutomatic || m_popupInfo.parentControlGeometry.isValid()) mShellSurface->setWindowSize(frameGeometry.size()); + else mShellSurface->setWindowGeometry(frameGeometry); } @@ -1945,6 +1946,27 @@ QString QWaylandWindow::sessionRestoreId() const return mSessionRestoreId; } +void QWaylandWindow::setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::WindowType windowType) { + m_popupInfo.extendedWindowType = windowType; +} + +QNativeInterface::Private::QWaylandWindow::WindowType QWaylandWindow::extendedWindowType() const +{ + return m_popupInfo.extendedWindowType; +} + +void QWaylandWindow::setParentControlGeometry(const QRect &parentControlGeometry) { + m_popupInfo.parentControlGeometry = parentControlGeometry; + if (mExposed) { + mShellSurface->setWindowPosition(window()->position()); + } +} + +QRect QWaylandWindow::parentControlGeometry() const +{ + return m_popupInfo.parentControlGeometry; +} + } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h index 854724daf82..d6b24d0569f 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow_p.h +++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h @@ -255,6 +255,11 @@ public: void setSessionRestoreId(const QString &role) override; QString sessionRestoreId() const; + void setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::WindowType) override; + QNativeInterface::Private::QWaylandWindow::WindowType extendedWindowType() const; + void setParentControlGeometry(const QRect &parentAnchor) override; + QRect parentControlGeometry() const; + public Q_SLOTS: void applyConfigure(); @@ -397,6 +402,11 @@ private: void handleFrameCallback(struct ::wl_callback* callback); const QPlatformWindow *lastParent = nullptr; + struct { + QRect parentControlGeometry; + QNativeInterface::Private::QWaylandWindow::WindowType extendedWindowType = QNativeInterface::Private::QWaylandWindow::Default; + } m_popupInfo; + static QWaylandWindow *mMouseGrab; static QWaylandWindow *mTopPopup; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 82a86d6ff3a..01716fba60c 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -4019,9 +4019,11 @@ void QWindowsWindow::requestUpdate() // request or we are waiting for the event loop to process // the Posted event on the GUI thread. if (m_vsyncUpdatePending.testAndSetAcquire(UpdateState::Requested, UpdateState::Posted)) { - QMetaObject::invokeMethod(w, [w] { + QWindowsWindow *oldSelf = this; + QMetaObject::invokeMethod(w, [w, oldSelf] { + // 'oldSelf' is only used for comparison, don't access it directly! auto *self = static_cast<QWindowsWindow *>(w->handle()); - if (self) { + if (self && self == oldSelf) { // The platform window is still alive self->m_vsyncUpdatePending.storeRelease(UpdateState::Ready); self->deliverUpdateRequest(); diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 5ba6f3e1649..0b05a31ca5c 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -5849,6 +5849,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget); const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize); NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw)); + const auto controlSize = cell.controlSize; + if (qt_apple_runningWithLiquidGlass()) + cell.controlSize = NSControlSizeMini; cell.enabled = (sb->state & State_Enabled); const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()]; @@ -5869,6 +5872,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO]; d->restoreNSGraphicsContext(cg); + if (qt_apple_runningWithLiquidGlass()) + cell.controlSize = controlSize; } } break; diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index 28b12bd81f9..25142612c4f 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -1331,11 +1331,12 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op } } break; - case QStyle::CE_ProgressBarGroove:{ - if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) { - QRect rect = subElementRect(SE_ProgressBarContents, progbaropt, widget); +#if QT_CONFIG(progressbar) + case CE_ProgressBarGroove: + if (const auto baropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) { + QRect rect = option->rect; QPointF center = rect.center(); - if (progbaropt->state & QStyle::State_Horizontal) { + if (baropt->state & QStyle::State_Horizontal) { rect.setHeight(1); rect.moveTop(center.y()); } else { @@ -1347,11 +1348,10 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op painter->drawRect(rect); } break; - } - case QStyle::CE_ProgressBarContents: + case CE_ProgressBarContents: if (const auto baropt = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { QPainterStateGuard psg(painter); - QRectF rect = subElementRect(SE_ProgressBarContents, baropt, widget); + QRectF rect = option->rect; painter->translate(rect.topLeft()); rect.translate(-rect.topLeft()); @@ -1411,16 +1411,17 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent()); } break; - case QStyle::CE_ProgressBarLabel: - if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) { - const bool vertical = !(progbaropt->state & QStyle::State_Horizontal); + case CE_ProgressBarLabel: + if (const auto baropt = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { + const bool vertical = !(baropt->state & QStyle::State_Horizontal); if (!vertical) { - QRect rect = subElementRect(SE_ProgressBarLabel, progbaropt, widget); - painter->setPen(progbaropt->palette.text().color()); - painter->drawText(rect, progbaropt->text, progbaropt->textAlignment); + proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine, + baropt->palette, baropt->state & State_Enabled, baropt->text, + QPalette::Text); } } break; +#endif // QT_CONFIG(progressbar) case CE_PushButtonLabel: if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { QRect textRect = btn->rect; @@ -1914,15 +1915,18 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp ret = QWindowsVistaStyle::subElementRect(element, option, widget); } break; - case QStyle::SE_ProgressBarLabel: - if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { - if (pb->textAlignment.testFlags(Qt::AlignVCenter)) { - ret = option->rect.adjusted(0, 6, 0, 0); - } else { - ret = QWindowsVistaStyle::subElementRect(element, option, widget); - } +#if QT_CONFIG(progressbar) + case SE_ProgressBarGroove: + case SE_ProgressBarContents: + case SE_ProgressBarLabel: + if (const auto *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { + QStyleOptionProgressBar optCopy(*pb); + // we only support label right from content + optCopy.textAlignment = Qt::AlignRight; + return QWindowsVistaStyle::subElementRect(element, &optCopy, widget); } break; +#endif // QT_CONFIG(progressbar) case QStyle::SE_HeaderLabel: case QStyle::SE_HeaderArrow: ret = QCommonStyle::subElementRect(element, option, widget); diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp index 12c2625f39d..667f2d8a6c3 100644 --- a/src/plugins/tls/schannel/qtls_schannel.cpp +++ b/src/plugins/tls/schannel/qtls_schannel.cpp @@ -1238,9 +1238,10 @@ bool TlsCryptographSchannel::createContext() }; #endif + const QString encodedTargetName = QUrl::fromUserInput(targetName()).host(QUrl::EncodeUnicode); auto status = InitializeSecurityContext(&credentialHandle, // phCredential nullptr, // phContext - const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName + const_reinterpret_cast<SEC_WCHAR *>(encodedTargetName.utf16()), // pszTargetName contextReq, // fContextReq 0, // Reserved1 0, // TargetDataRep (unused) diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index 0e04d10e692..b517d85c5fb 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -328,6 +328,53 @@ static bool processAndroidManifest() return true; } +static QStringList queryDangerousPermissions() +{ + QByteArray output; + const QStringList args({ "shell"_L1, "dumpsys"_L1, "package"_L1, "permissions"_L1 }); + if (!execAdbCommand(args, &output, false)) { + qWarning("Failed to query permissions via dumpsys"); + return {}; + } + + /* + * Permissions section from this command look like: + * + * Permission [android.permission.INTERNET] (c8cafdc): + * sourcePackage=android + * uid=1000 gids=[3003] type=0 prot=normal|instant + * perm=PermissionInfo{5f5bfbb android.permission.INTERNET} + * flags=0x0 + */ + const static QRegularExpression regex("^\\s*Permission\\s+\\[([^\\]]+)\\]\\s+\\(([^)]+)\\):"_L1); + QStringList dangerousPermissions; + QString currentPerm; + + const QStringList lines = QString::fromUtf8(output).split(u'\n'); + for (const QString &line : lines) { + QRegularExpressionMatch match = regex.match(line); + if (match.hasMatch()) { + currentPerm = match.captured(1); + continue; + } + + if (currentPerm.isEmpty()) + continue; + + int protIndex = line.indexOf("prot="_L1); + if (protIndex == -1) + continue; + + QString protectionTypes = line.mid(protIndex + 5).trimmed(); + if (protectionTypes.contains("dangerous"_L1, Qt::CaseInsensitive)) { + dangerousPermissions.append(currentPerm); + currentPerm.clear(); + } + } + + return dangerousPermissions; +} + static void setOutputFile(QString file, QString format) { if (format.isEmpty()) @@ -938,7 +985,11 @@ int main(int argc, char *argv[]) return EXIT_ERROR; } + const QStringList dangerousPermisisons = queryDangerousPermissions(); for (const auto &permission : g_options.permissions) { + if (!dangerousPermisisons.contains(permission)) + continue; + if (!execAdbCommand({ "shell"_L1, "pm"_L1, "grant"_L1, g_options.package, permission }, nullptr)) { qWarning("Unable to grant '%s' to '%s'. Probably the Android version mismatch.", diff --git a/src/widgets/doc/src/qtwidgets-examples.qdoc b/src/widgets/doc/src/qtwidgets-examples.qdoc index 45677c471ba..364c985b310 100644 --- a/src/widgets/doc/src/qtwidgets-examples.qdoc +++ b/src/widgets/doc/src/qtwidgets-examples.qdoc @@ -164,3 +164,15 @@ regular expressions for the Widget-based applications. */ +/*! + \group examples-user-input + \ingroup all-examples + \title User Input Examples + \brief Using user input in Qt Widgets applications. + + \image imagegestures-example.png {Application handling touch gestures} + + Qt provides the functionality for handling user input and drag-and-drop in + widget-based applications. + +*/ diff --git a/src/widgets/doc/src/qtwidgets-toc.qdoc b/src/widgets/doc/src/qtwidgets-toc.qdoc index bc447b8bd58..beddf853a22 100644 --- a/src/widgets/doc/src/qtwidgets-toc.qdoc +++ b/src/widgets/doc/src/qtwidgets-toc.qdoc @@ -53,6 +53,7 @@ \li \l{Rich Text Examples} \li \l{Graphics View Examples} \li \l{Widget Tools Examples} + \li \l{User Input Examples} \endlist \endlist diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index e4159ad2cf0..51aea4079a1 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3298,7 +3298,8 @@ void QAbstractItemView::closePersistentEditor(const QModelIndex &index) bool QAbstractItemView::isPersistentEditorOpen(const QModelIndex &index) const { Q_D(const QAbstractItemView); - return d->editorForIndex(index).widget; + QWidget *editor = d->editorForIndex(index).widget; + return editor && d->persistent.contains(editor); } /*! diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index 9e6aaf4b95f..d989feb7f91 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -20,6 +20,8 @@ #if QT_CONFIG(style_stylesheet) #include <private/qstylesheetstyle_p.h> #endif +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> #include <qlabel.h> #include <QtWidgets/private/qlabel_p.h> @@ -386,6 +388,17 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w) p += offset; +#if QT_CONFIG(wayland) + create(); + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(windowHandle()->handle())) { + // based on the existing code below, by default position at 'p' stored at the bottom right of our rect + // then flip to the other arbitrary 4x24 space if constrained + const QRect controlGeometry(QRect(p.x() - 4, p.y() - 24, 4, 24)); + waylandWindow->setParentControlGeometry(controlGeometry); + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ToolTip); + } +#endif + QRect screenRect = screen->geometry(); if (p.x() + this->width() > screenRect.x() + screenRect.width()) p.rx() -= 4 + this->width(); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 36446c3e5c4..9499c88af12 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -13144,11 +13144,22 @@ int QWidget::metric(PaintDeviceMetric m) const void QWidget::initPainter(QPainter *painter) const { const QPalette &pal = palette(); - painter->d_func()->state->pen = QPen(pal.brush(foregroundRole()), 1); - painter->d_func()->state->bgBrush = pal.brush(backgroundRole()); + QPainterPrivate *painterPrivate = QPainterPrivate::get(painter); + + painterPrivate->state->pen = QPen(pal.brush(foregroundRole()), 1); + painterPrivate->state->bgBrush = pal.brush(backgroundRole()); QFont f(font(), this); - painter->d_func()->state->deviceFont = f; - painter->d_func()->state->font = f; + painterPrivate->state->deviceFont = f; + painterPrivate->state->font = f; + + painterPrivate->setEngineDirtyFlags({ + QPaintEngine::DirtyPen, + QPaintEngine::DirtyBrush, + QPaintEngine::DirtyFont, + }); + + if (painterPrivate->extended) + painterPrivate->extended->penChanged(); } /*! diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp index 220f600ea41..735b574d293 100644 --- a/src/widgets/util/qcompleter.cpp +++ b/src/widgets/util/qcompleter.cpp @@ -122,6 +122,8 @@ #include "QtGui/qevent.h" #include <private/qapplication_p.h> #include <private/qwidget_p.h> +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> #if QT_CONFIG(lineedit) #include "QtWidgets/qlineedit.h" #endif @@ -925,10 +927,15 @@ void QCompleterPrivate::showPopup(const QRect& rect) popup->setGeometry(pos.x(), pos.y(), w, h); if (!popup->isVisible()) { - // Make sure popup has a transient parent set, Wayland needs it. QTBUG-130474 - popup->winId(); // force creation of windowHandle - popup->windowHandle()->setTransientParent(widget->window()->windowHandle()); - +#if QT_CONFIG(wayland) + popup->createWinId(); + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(popup->windowHandle()->handle())) { + popup->windowHandle()->setTransientParent(widget->window()->windowHandle()); + const QRect controlGeometry = QRect(widget->mapTo(widget->topLevelWidget(), QPoint(0,0)), widget->size()); + waylandWindow->setParentControlGeometry(controlGeometry); + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ComboBox); + } +#endif popup->show(); } } diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 6f25b8bde67..2f51b83a49d 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -7,6 +7,9 @@ #include <qstylepainter.h> #include <qpa/qplatformtheme.h> #include <qpa/qplatformmenu.h> +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> + #include <qlineedit.h> #include <qapplication.h> #include <qlistview.h> @@ -2868,6 +2871,17 @@ void QComboBox::showPopup() container->hide(); } } + +#if QT_CONFIG(wayland) + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(container->windowHandle()->handle())) { + const QRect popup(style->subControlRect(QStyle::CC_ComboBox, &opt, + QStyle::SC_ComboBoxListBoxPopup, this)); + const QRect controlGeometry = QRect(mapTo(window(), popup.topLeft()), popup.size()); + waylandWindow->setParentControlGeometry(controlGeometry); + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ComboBox); + } +#endif + container->show(); if (!neededHorizontalScrollBar && needHorizontalScrollBar()) { listRect.adjust(0, 0, 0, sb->height()); diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 5cda8f33f4c..3177ed5c2d4 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -40,6 +40,8 @@ #include <private/qaction_p.h> #include <private/qguiapplication_p.h> #include <qpa/qplatformtheme.h> +#include <qpa/qplatformwindow.h> +#include <qpa/qplatformwindow_p.h> #include <private/qstyle_p.h> QT_BEGIN_NAMESPACE @@ -2535,6 +2537,23 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po } popupScreen = QGuiApplication::screenAt(pos); q->setGeometry(QRect(pos, size)); + +#if QT_CONFIG(wayland) + q->create(); + if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(q->windowHandle()->handle())) { + if (causedButton) { + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::Menu); + waylandWindow->setParentControlGeometry(causedButton->geometry()); + } else if (caused) { + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::SubMenu); + waylandWindow->setParentControlGeometry(caused->d_func()->actionRect(caused->d_func()->currentAction)); + } else if (auto menubar = qobject_cast<QMenuBar*>(causedPopup.widget)) { + waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::Menu); + waylandWindow->setParentControlGeometry(menubar->actionGeometry(causedPopup.action)); + } + } +#endif + #if QT_CONFIG(effects) int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; int vGuess = QEffects::DownScroll; @@ -2952,7 +2971,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e) #endif d->activateAction(action, QAction::Trigger); } - } else if (!action || action->isEnabled()) { + } else if ((!action || action->isEnabled()) && !action->isSeparator()) { d->hideUpToMenuBar(); } } diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index b9e239af31d..fde06d2edd9 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -2411,7 +2411,7 @@ void tst_QDateTime::springForward_data() QTest::newRow("PT from day after") << pacific << QDate(2015, 3, 8) << QTime(2, 30) << -1 << -420; } - if (const QTimeZone eastern("America/Ottawa"); eastern.isValid()) { + if (const QTimeZone eastern("America/Toronto"); eastern.isValid()) { QTest::newRow("ET from day before") << eastern << QDate(2015, 3, 8) << QTime(2, 30) << 1 << -300; QTest::newRow("ET from day after") @@ -3500,11 +3500,11 @@ void tst_QDateTime::fromStringStringFormat_localTimeZone_data() QTest::newRow("local-timezone-ttt-with-zone:Etc/GMT+3") << "GMT"_ba << u"2008-10-13 Etc/GMT+3 11.50"_s << u"yyyy-MM-dd ttt hh.mm"_s << 1900 << QDateTime(); // Zone name not valid when offset expected - QTimeZone gmtWithOffset("GMT-2"); + QTimeZone gmtWithOffset("GMT-0"); if (gmtWithOffset.isValid()) { lacksRows = false; - QTest::newRow("local-timezone-with-offset:GMT-2") - << "GMT"_ba << u"2008-10-13 GMT-2 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900 + QTest::newRow("local-timezone-with-offset:GMT-0") + << "GMT"_ba << u"2008-10-13 GMT-0 11.50"_s << u"yyyy-MM-dd t hh.mm"_s << 1900 << QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmtWithOffset); } QTimeZone gmt("GMT"); diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp index 3b66ad76a2f..6a72b5ddf38 100644 --- a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp @@ -1887,12 +1887,14 @@ void tst_QTimeZone::roundtripDisplayNames_data() "UTC"_ba, // Those named overtly in tst_QDateTime - special cases first: "UTC-02:00"_ba, "UTC+02:00"_ba, "UTC+12:00"_ba, - "Etc/GMT+3"_ba, "GMT-2"_ba, "GMT"_ba, + "Etc/GMT+3"_ba, "GMT-0"_ba, "GMT"_ba, // ... then ordinary names in alphabetic order: - "America/New_York"_ba, "America/Sao_Paulo"_ba, "America/Vancouver"_ba, - "Asia/Kathmandu"_ba, "Asia/Singapore"_ba, + "America/Anchorage"_ba, "America/Metlakatla"_ba, "America/New_York"_ba, + "America/Sao_Paulo"_ba, "America/Toronto"_ba, "America/Vancouver"_ba, + "Asia/Kathmandu"_ba, "Asia/Manila"_ba, "Asia/Singapore"_ba, "Australia/Brisbane"_ba, "Australia/Eucla"_ba, "Australia/Sydney"_ba, - "Europe/Berlin"_ba, "Europe/Helsinki"_ba, "Europe/Rome"_ba, "Europe/Oslo"_ba, + "Europe/Berlin"_ba, "Europe/Helsinki"_ba, "Europe/Lisbon"_ba, "Europe/Oslo"_ba, + "Europe/Rome"_ba, "Pacific/Apia"_ba, "Pacific/Auckland"_ba, "Pacific/Kiritimati"_ba, "Vulcan/ShiKahr"_ba // Invalid: also worth testing. }; diff --git a/tests/auto/gui/kernel/qsurfaceformat/tst_qsurfaceformat.cpp b/tests/auto/gui/kernel/qsurfaceformat/tst_qsurfaceformat.cpp index 3f655bd905d..28085e1405f 100644 --- a/tests/auto/gui/kernel/qsurfaceformat/tst_qsurfaceformat.cpp +++ b/tests/auto/gui/kernel/qsurfaceformat/tst_qsurfaceformat.cpp @@ -54,10 +54,10 @@ void tst_QSurfaceFormat::versionCheck() format.setMinorVersion(formatMinor); format.setMajorVersion(formatMajor); - QCOMPARE(format.version() >= qMakePair(compareMajor, compareMinor), expected); + QCOMPARE(format.version() >= std::pair(compareMajor, compareMinor), expected); format.setVersion(formatMajor, formatMinor); - QCOMPARE(format.version() >= qMakePair(compareMajor, compareMinor), expected); + QCOMPARE(format.version() >= std::pair(compareMajor, compareMinor), expected); } #include <tst_qsurfaceformat.moc> diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index 64add80907a..7dac778d5ff 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -292,6 +292,8 @@ private slots: void alphaBlitToNonAlphaFormats_data(); void alphaBlitToNonAlphaFormats(); + void floatRounding(); + private: void fillData(); void setPenColor(QPainter& p); @@ -3843,26 +3845,23 @@ void tst_QPainter::linearGradientSymmetry_data() QTest::addColumn<QGradientStops>("stops"); if (sizeof(qreal) != sizeof(float)) { - QGradientStops stops; - stops << qMakePair(qreal(0.0), QColor(Qt::blue)); - stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0)); - stops << qMakePair(qreal(0.6), QColor(Qt::red)); - stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255)); - stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QGradientStops stops = {{qreal(0.0), QColor(Qt::blue)}, + {qreal(0.2), QColor(220, 220, 220, 0)}, + {qreal(0.6), QColor(Qt::red)}, + {qreal(0.9), QColor(220, 220, 220, 255)}, + {qreal(1.0), QColor(Qt::black)}}; QTest::newRow("multiple stops") << stops; } { - QGradientStops stops; - stops << qMakePair(qreal(0.0), QColor(Qt::blue)); - stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QGradientStops stops = {{qreal(0.0), QColor(Qt::blue)}, + {qreal(1.0), QColor(Qt::black)}}; QTest::newRow("two stops") << stops; } if (sizeof(qreal) != sizeof(float)) { - QGradientStops stops; - stops << qMakePair(qreal(0.3), QColor(Qt::blue)); - stops << qMakePair(qreal(0.6), QColor(Qt::black)); + QGradientStops stops = {{qreal(0.3), QColor(Qt::blue)}, + {qreal(0.6), QColor(Qt::black)}}; QTest::newRow("two stops 2") << stops; } } @@ -3913,12 +3912,10 @@ void tst_QPainter::gradientPixelFormat() QImage a(8, 64, QImage::Format_ARGB32_Premultiplied); QImage b(8, 64, format); - - QGradientStops stops; - stops << qMakePair(qreal(0.0), QColor(Qt::blue)); - stops << qMakePair(qreal(0.3), QColor(Qt::red)); - stops << qMakePair(qreal(0.6), QColor(Qt::green)); - stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QGradientStops stops = {{qreal(0.0), QColor(Qt::blue)}, + {qreal(0.3), QColor(Qt::red)}, + {qreal(0.6), QColor(Qt::green)}, + {qreal(1.0), QColor(Qt::black)}}; a.fill(0); b.fill(0); @@ -5751,6 +5748,30 @@ void tst_QPainter::alphaBlitToNonAlphaFormats() } } +void tst_QPainter::floatRounding() +{ + // oss-fuzz issue 429123947 + // The following triggered an assert in QDashStroker::processCurrentSubpath(): "dpos >= 0" + // when it expected the calculation's result to be zero but it was actually smaller: + // qreal(4) + qreal(0.1) - qreal(0.1) - qreal(4) + // actual result: -4.440892098500626e-16 + QImage img(5, 5, QImage::Format_RGB888); + QPainter p(&img); + + QList<qreal> pattern {0.1, 0.3, 0.1, 0.1, 0.3, 0.1}; + QPainterPathStroker stroker; + stroker.setDashPattern(pattern); + + QPainterPath pp; + pp.moveTo(4.0, 0.0); + pp.lineTo(0.1, 0.0); + pp.lineTo(0.0, 0.0); + pp.lineTo(0.0, 5.0); + + QPolygonF poly = stroker.createStroke(pp).toFillPolygon(); + p.drawPolygon(poly); +} + QTEST_MAIN(tst_QPainter) #include "tst_qpainter.moc" diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index ab0e8693644..511007e0ae4 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -3525,7 +3525,7 @@ void tst_QRhi::renderToTextureMultipleUniformBuffersAndDynamicOffset() // "see" an all zero matrix and zero opacity, thus leading to different // rendering output. This way we can verify if using dynamic offsets, and // more than one at the same time, is functional. - QVarLengthArray<QPair<int, quint32>, 2> dynamicOffset = { + QVarLengthArray<std::pair<int, quint32>, 2> dynamicOffset = { { 0, quint32(ubufElemSize * 2) }, { 1, quint32(ubuf2ElemSize * 3) }, }; diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp index 9e179c95c35..371da0d800c 100644 --- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -279,7 +279,7 @@ void tst_QShader::mslResourceMapping() QCOMPARE(resMap.size(), 2); QCOMPARE(resMap.value(0).first, 0); // mapped to native buffer index 0 - QCOMPARE(resMap.value(1), qMakePair(0, 0)); // mapped to native texture index 0 and sampler index 0 + QCOMPARE(resMap.value(1), std::pair(0, 0)); // mapped to native texture index 0 and sampler index 0 } void tst_QShader::serializeShaderDesc() @@ -667,7 +667,8 @@ void tst_QShader::loadV7() QCOMPARE(tese.description().inputBuiltinVariables()[3].type, QShaderDescription::TessCoordBuiltin); QCOMPARE(tese.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))).size(), 1); - QCOMPARE(tese.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))).value(0), qMakePair(0, -1)); + QCOMPARE(tese.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))).value(0), + std::pair(0, -1)); QShader frag = getShader(QLatin1String(":/data/metal_enabled_tessellation_v7.frag.qsb")); QVERIFY(frag.isValid()); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index fa1d70a942b..fdc2dde7921 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -781,7 +781,7 @@ private: void parseContentLength() { - int index = receivedData.indexOf("content-length:"); + int index = receivedData.toLower().indexOf("content-length:"); if (index == -1) return; @@ -3620,7 +3620,7 @@ void tst_QNetworkReply::connectToIPv6Address() QByteArray content = reply->readAll(); //qDebug() << server.receivedData; QByteArray hostinfo = "\r\nhost: " + hostfield + ':' + QByteArray::number(server.serverPort()) + "\r\n"; - QVERIFY(server.receivedData.contains(hostinfo)); + QVERIFY(server.receivedData.toLower().contains(hostinfo)); QCOMPARE(content, dataToSend); QCOMPARE(reply->url(), request.url()); QCOMPARE(reply->error(), error); @@ -8793,7 +8793,11 @@ void tst_QNetworkReply::httpUserAgent() QVERIFY(reply->isFinished()); QCOMPARE(reply->error(), QNetworkReply::NoError); - QVERIFY(server.receivedData.contains("\r\nuser-agent: abcDEFghi\r\n")); + const char userAgentSearch[] = "\r\nuser-agent: "; + qsizetype userAgentIndex = server.receivedData.toLower().indexOf(userAgentSearch); + QCOMPARE_NE(userAgentIndex, -1); + userAgentIndex += sizeof(userAgentSearch) - 1; + QVERIFY(server.receivedData.slice(userAgentIndex).startsWith("abcDEFghi\r\n")); } void tst_QNetworkReply::synchronousAuthenticationCache() @@ -8813,7 +8817,7 @@ void tst_QNetworkReply::synchronousAuthenticationCache() "content-type: text/plain\r\n" "\r\n" "auth"; - QRegularExpression rx("authorization: Basic ([^\r\n]*)\r\n"); + QRegularExpression rx("[Aa]uthorization: Basic ([^\r\n]*)\r\n"); QRegularExpressionMatch match = rx.match(receivedData); if (match.hasMatch()) { if (QByteArray::fromBase64(match.captured(1).toLatin1()) == "login:password") { @@ -9526,7 +9530,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect() manager.setRedirectPolicy(oldRedirectPolicy); QVERIFY(waitForFinish(reply) == Success); - QVERIFY(target.receivedData.contains("\r\ncookie: hello=world\r\n")); + QVERIFY(target.receivedData.toLower().contains("\r\ncookie: hello=world\r\n")); QVERIFY(validateRedirectedResponseHeaders(reply)); } @@ -10439,7 +10443,7 @@ void tst_QNetworkReply::contentEncoding() { // Check that we included the content encoding method in our Accept-Encoding header const QByteArray &receivedData = server.receivedData; - int start = receivedData.indexOf("accept-encoding"); + int start = receivedData.toLower().indexOf("accept-encoding"); QVERIFY(start != -1); int end = receivedData.indexOf("\r\n", start); QVERIFY(end != -1); diff --git a/tests/auto/network/access/qnetworkreply_local/minihttpserver.h b/tests/auto/network/access/qnetworkreply_local/minihttpserver.h index daad88cdbcc..ae1069d7a7d 100644 --- a/tests/auto/network/access/qnetworkreply_local/minihttpserver.h +++ b/tests/auto/network/access/qnetworkreply_local/minihttpserver.h @@ -152,7 +152,7 @@ private: void parseContentLength(State &st, QByteArrayView header) { - qsizetype index = header.indexOf("\r\ncontent-length:"); + qsizetype index = header.toByteArray().toLower().indexOf("\r\ncontent-length:"); if (index == -1) return; st.foundContentLength = true; diff --git a/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp b/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp index 8bed904c230..977a047c58e 100644 --- a/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp +++ b/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp @@ -270,7 +270,7 @@ void tst_QNetworkReply_local::fullServerName() QVERIFY(receivedData.startsWith(expectedGet)); const QByteArray expectedHost = "host: " % url.host().toUtf8() % "\r\n"; - QVERIFY(receivedData.contains(expectedHost)); + QVERIFY(receivedData.toLower().contains(expectedHost)); } #endif diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 805fa046a07..3e5c65cf0be 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -156,6 +156,7 @@ private slots: void removeIndexWhileEditing(); void focusNextOnHide(); void shiftSelectionAfterModelSetCurrentIndex(); + void QTBUG72333_isPersistentEditorOpen(); private: static QAbstractItemView *viewFromString(const QByteArray &viewType, QWidget *parent = nullptr) @@ -3604,5 +3605,29 @@ void tst_QAbstractItemView::shiftSelectionAfterModelSetCurrentIndex() QCOMPARE(selection.first().bottom(), 2); } +void tst_QAbstractItemView::QTBUG72333_isPersistentEditorOpen() +{ + QStandardItemModel model(1, 1); + model.setData(model.index(0, 0), QStringLiteral("Test")); + + QTableView view; + view.setModel(&model); + view.show(); + + const QModelIndex index = model.index(0, 0); + + view.edit(index); + QVERIFY(view.state() == QAbstractItemView::EditingState); + QVERIFY(!view.isPersistentEditorOpen(index)); + + view.closeEditor(view.indexWidget(index), QAbstractItemDelegate::RevertModelCache); + + view.openPersistentEditor(index); + QVERIFY(view.isPersistentEditorOpen(index)); + + view.closePersistentEditor(index); + QVERIFY(!view.isPersistentEditorOpen(index)); +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 72f5ada4889..8e46876934d 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -11280,7 +11280,7 @@ void tst_QWidget::destroyBackingStore() #endif // QT_BUILD_INTERNAL // Helper function -QWidgetRepaintManager* repaintManager(QWidget &widget) +QWidgetRepaintManager* repaintManager([[maybe_unused]] QWidget &widget) { QWidgetRepaintManager *repaintManager = nullptr; #ifdef QT_BUILD_INTERNAL diff --git a/tests/benchmarks/corelib/time/qtimezone/tst_bench_qtimezone.cpp b/tests/benchmarks/corelib/time/qtimezone/tst_bench_qtimezone.cpp index 3b58b6927ae..fbcce88fe81 100644 --- a/tests/benchmarks/corelib/time/qtimezone/tst_bench_qtimezone.cpp +++ b/tests/benchmarks/corelib/time/qtimezone/tst_bench_qtimezone.cpp @@ -41,15 +41,17 @@ static QList<QByteArray> enoughZones() QByteArray("UTC"), // Those named overtly in tst_QDateTime - special cases first: QByteArray("UTC-02:00"), QByteArray("UTC+02:00"), QByteArray("UTC+12:00"), - QByteArray("Etc/GMT+3"), QByteArray("GMT-2"), QByteArray("GMT"), + QByteArray("Etc/GMT+3"), QByteArray("GMT-0"), QByteArray("GMT"), // ... then ordinary names in alphabetic order: + QByteArray("America/Anchorage"), QByteArray("America/Metlakatla"), QByteArray("America/New_York"), QByteArray("America/Sao_Paulo"), - QByteArray("America/Vancouver"), - QByteArray("Asia/Kathmandu"), QByteArray("Asia/Singapore"), + QByteArray("America/Toronto"), QByteArray("America/Vancouver"), + QByteArray("Asia/Kathmandu"), QByteArray("Asia/Manila"), QByteArray("Asia/Singapore"), QByteArray("Australia/Brisbane"), QByteArray("Australia/Eucla"), QByteArray("Australia/Sydney"), QByteArray("Europe/Berlin"), QByteArray("Europe/Helsinki"), - QByteArray("Europe/Rome"), QByteArray("Europe/Oslo"), + QByteArray("Europe/Lisbon"), QByteArray("Europe/Oslo"), + QByteArray("Europe/Rome"), QByteArray("Pacific/Apia"), QByteArray("Pacific/Auckland"), QByteArray("Pacific/Kiritimati") }; |