diff options
129 files changed, 2274 insertions, 644 deletions
diff --git a/cmake/FindWrapOpenSSL.cmake b/cmake/FindWrapOpenSSL.cmake index a4341271fee..7f3b9db4c7b 100644 --- a/cmake/FindWrapOpenSSL.cmake +++ b/cmake/FindWrapOpenSSL.cmake @@ -11,7 +11,7 @@ endif() set(WrapOpenSSL_FOUND OFF) # Reuse logic from the headers find script. -find_package(WrapOpenSSLHeaders ${WrapOpenSSL_FIND_VERSION}) +find_package(WrapOpenSSLHeaders ${WrapOpenSSL_FIND_VERSION} MODULE) if(TARGET OpenSSL::SSL) if(WIN32) diff --git a/configure.cmake b/configure.cmake index 6230629fe4c..9a4657f843f 100644 --- a/configure.cmake +++ b/configure.cmake @@ -7,7 +7,8 @@ #### Libraries -qt_find_package(WrapSystemZLIB 1.0.8 PROVIDED_TARGETS WrapSystemZLIB::WrapSystemZLIB MODULE_NAME global QMAKE_LIB zlib) +qt_find_package(WrapSystemZLIB 1.0.8 MODULE + PROVIDED_TARGETS WrapSystemZLIB::WrapSystemZLIB MODULE_NAME global QMAKE_LIB zlib) # Work around global target promotion failure when WrapZLIB is used on APPLE platforms. # What ends up happening is that the ZLIB::ZLIB target is not promoted to global by qt_find_package, # then qt_find_package(WrapSystemPNG) tries to find its dependency ZLIB::ZLIB, sees it's not global @@ -21,8 +22,9 @@ endif() # Look for Threads in the same scope as OpenSSL package, because OpenSSL sometimes depends on # Threads (for static OpenSSL builds) and we want to promote the target to global in the same # directory scope. -qt_find_package(Threads PROVIDED_TARGETS Threads::Threads) -qt_find_package(WrapOpenSSLHeaders PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders MODULE_NAME core) +qt_find_package(Threads MODULE PROVIDED_TARGETS Threads::Threads) +qt_find_package(WrapOpenSSLHeaders MODULE + PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders MODULE_NAME core) # openssl_headers # OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1 qt_config_compile_test(opensslv11_headers @@ -47,7 +49,8 @@ int main(void) } ") -qt_find_package(WrapOpenSSL PROVIDED_TARGETS WrapOpenSSL::WrapOpenSSL MODULE_NAME core QMAKE_LIB openssl) +qt_find_package(WrapOpenSSL MODULE + PROVIDED_TARGETS WrapOpenSSL::WrapOpenSSL MODULE_NAME core QMAKE_LIB openssl) # openssl # OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1 qt_config_compile_test(opensslv11 @@ -113,7 +116,7 @@ SSL_free(SSL_new(0)); } ") -qt_find_package(WrapZSTD 1.3 +qt_find_package(WrapZSTD 1.3 MODULE PROVIDED_TARGETS WrapZSTD::WrapZSTD zstd::libzstd @@ -122,9 +125,10 @@ qt_find_package(WrapZSTD 1.3 MODULE_NAME global QMAKE_LIB zstd ) -qt_find_package(WrapDBus1 1.2 PROVIDED_TARGETS dbus-1 MODULE_NAME global QMAKE_LIB dbus) -qt_find_package(Libudev PROVIDED_TARGETS PkgConfig::Libudev MODULE_NAME global QMAKE_LIB libudev) -qt_find_package(LTTngUST PROVIDED_TARGETS LTTng::UST MODULE_NAME core QMAKE_LIB lttng-ust) +qt_find_package(WrapDBus1 1.2 MODULE PROVIDED_TARGETS dbus-1 MODULE_NAME global QMAKE_LIB dbus) +qt_find_package(Libudev MODULE + PROVIDED_TARGETS PkgConfig::Libudev MODULE_NAME global QMAKE_LIB libudev) +qt_find_package(LTTngUST MODULE PROVIDED_TARGETS LTTng::UST MODULE_NAME core QMAKE_LIB lttng-ust) qt_add_qmake_lib_dependency(lttng-ust libdl) diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt index fd26ef89778..03ea3b31e6f 100644 --- a/src/3rdparty/CMakeLists.txt +++ b/src/3rdparty/CMakeLists.txt @@ -11,7 +11,7 @@ endif() qt_install_3rdparty_library_wrap_config_extra_file(BundledLibjpeg) # Needed for freetype, because it links against WrapPNG -qt_find_package(WrapPNG PROVIDED_TARGETS WrapPNG::WrapPNG) +qt_find_package(WrapPNG MODULE PROVIDED_TARGETS WrapPNG::WrapPNG) if(QT_FEATURE_gui AND QT_FEATURE_freetype AND NOT QT_FEATURE_system_freetype) add_subdirectory(freetype) endif() diff --git a/src/3rdparty/double-conversion/qt_attribution.json b/src/3rdparty/double-conversion/qt_attribution.json index df4770561bf..acc47f989e0 100644 --- a/src/3rdparty/double-conversion/qt_attribution.json +++ b/src/3rdparty/double-conversion/qt_attribution.json @@ -5,8 +5,8 @@ "QtUsage": "Used in Qt Core. Configure with -system-doubleconversion or -no-doubleconversion to avoid.", "Homepage": "https://github.com/google/double-conversion", - "Version": "3.3.0", - "DownloadLocation": "https://github.com/google/double-conversion/releases/tag/v3.3.0", + "Version": "3.3.1", + "DownloadLocation": "https://github.com/google/double-conversion/releases/tag/v3.3.1", "PURL": "pkg:github/google/double-conversion@v$<VERSION>", "CPE": "cpe:2.3:a:google:double-conversion:$<VERSION>:*:*:*:*:*:*:*", "License": "BSD 3-clause \"New\" or \"Revised\" License", diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 6075d6e4d29..e8118e94db6 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -1,13 +1,13 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(WrapPCRE2 PROVIDED_TARGETS WrapPCRE2::WrapPCRE2) +qt_find_package(WrapPCRE2 MODULE PROVIDED_TARGETS WrapPCRE2::WrapPCRE2) qt_internal_extend_sbom(WrapPCRE2::WrapPCRE2 CPE_VENDOR "pcre" CPE_PRODUCT "pcre2" DOWNLOAD_LOCATION "https://github.com/PCRE2Project/pcre2" ) -qt_find_package(WrapZLIB PROVIDED_TARGETS WrapZLIB::WrapZLIB) +qt_find_package(WrapZLIB MODULE PROVIDED_TARGETS WrapZLIB::WrapZLIB) qt_internal_extend_sbom(WrapZLIB::WrapZLIB CPE_VENDOR "zlib" CPE_PRODUCT "zlib" diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index d15b5767a85..909041cf44b 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -20,12 +20,13 @@ set_property(CACHE INPUT_libb2 PROPERTY STRINGS undefined no qt system) if((UNIX AND NOT QNX) OR QT_FIND_ALL_PACKAGES_ALWAYS) # QNX's libbacktrace has an API wholly different from all the other Unix # offerings - qt_find_package(WrapBacktrace PROVIDED_TARGETS WrapBacktrace::WrapBacktrace MODULE_NAME core QMAKE_LIB backtrace) + qt_find_package(WrapBacktrace MODULE + PROVIDED_TARGETS WrapBacktrace::WrapBacktrace MODULE_NAME core QMAKE_LIB backtrace) endif() -qt_find_package(WrapSystemDoubleConversion +qt_find_package(WrapSystemDoubleConversion MODULE PROVIDED_TARGETS WrapSystemDoubleConversion::WrapSystemDoubleConversion MODULE_NAME core QMAKE_LIB doubleconversion) -qt_find_package(GLIB2 PROVIDED_TARGETS GLIB2::GLIB2 MODULE_NAME core QMAKE_LIB glib) +qt_find_package(GLIB2 MODULE PROVIDED_TARGETS GLIB2::GLIB2 MODULE_NAME core QMAKE_LIB glib) qt_find_package_extend_sbom(TARGETS GLIB2::GLIB2 LICENSE_EXPRESSION "LGPL-2.1-or-later" ) @@ -35,20 +36,25 @@ qt_find_package(ICU 50.1 COMPONENTS i18n uc data PROVIDED_TARGETS ICU::i18n ICU: if(QT_FEATURE_dlopen) qt_add_qmake_lib_dependency(icu libdl) endif() -qt_find_package(JeMalloc PROVIDED_TARGETS PkgConfig::JeMalloc MODULE_NAME core QMAKE_LIB jemalloc) -qt_find_package(Libsystemd PROVIDED_TARGETS PkgConfig::Libsystemd MODULE_NAME core QMAKE_LIB journald) -qt_find_package(WrapAtomic PROVIDED_TARGETS WrapAtomic::WrapAtomic MODULE_NAME core QMAKE_LIB libatomic) -qt_find_package(Libb2 PROVIDED_TARGETS Libb2::Libb2 MODULE_NAME core QMAKE_LIB libb2) +qt_find_package(JeMalloc MODULE + PROVIDED_TARGETS PkgConfig::JeMalloc MODULE_NAME core QMAKE_LIB jemalloc) +qt_find_package(Libsystemd MODULE + PROVIDED_TARGETS PkgConfig::Libsystemd MODULE_NAME core QMAKE_LIB journald) +qt_find_package(WrapAtomic MODULE + PROVIDED_TARGETS WrapAtomic::WrapAtomic MODULE_NAME core QMAKE_LIB libatomic) +qt_find_package(Libb2 MODULE PROVIDED_TARGETS Libb2::Libb2 MODULE_NAME core QMAKE_LIB libb2) qt_find_package_extend_sbom(TARGETS Libb2::Libb2 LICENSE_EXPRESSION "CC0-1.0" ) -qt_find_package(WrapRt PROVIDED_TARGETS WrapRt::WrapRt MODULE_NAME core QMAKE_LIB librt) -qt_find_package(WrapSystemPCRE2 10.20 PROVIDED_TARGETS WrapSystemPCRE2::WrapSystemPCRE2 MODULE_NAME core QMAKE_LIB pcre2) +qt_find_package(WrapRt MODULE + PROVIDED_TARGETS WrapRt::WrapRt MODULE_NAME core QMAKE_LIB librt) +qt_find_package(WrapSystemPCRE2 10.20 MODULE + PROVIDED_TARGETS WrapSystemPCRE2::WrapSystemPCRE2 MODULE_NAME core QMAKE_LIB pcre2) set_package_properties(WrapPCRE2 PROPERTIES TYPE REQUIRED) if((QNX) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(PPS PROVIDED_TARGETS PPS::PPS MODULE_NAME core QMAKE_LIB pps) + qt_find_package(PPS MODULE PROVIDED_TARGETS PPS::PPS MODULE_NAME core QMAKE_LIB pps) endif() -qt_find_package(Slog2 PROVIDED_TARGETS Slog2::Slog2 MODULE_NAME core QMAKE_LIB slog2) +qt_find_package(Slog2 MODULE PROVIDED_TARGETS Slog2::Slog2 MODULE_NAME core QMAKE_LIB slog2) #### Tests diff --git a/src/corelib/doc/snippets/code/src_corelib_serialization_qjsonobject.cpp b/src/corelib/doc/snippets/code/src_corelib_serialization_qjsonobject.cpp new file mode 100644 index 00000000000..a6a1cba7322 --- /dev/null +++ b/src/corelib/doc/snippets/code/src_corelib_serialization_qjsonobject.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +//! [1] +QJsonObject obj{ + { "something", "is" }, + { "in", "this" }, + { "object", 42 }, +}; + +for (auto [key, value] : obj.asKeyValueRange()) { + qDebug() << key << "->" << value; + if (key == "object") + value = "!"; // modify the object at this key +} +qDebug() << obj["object"]; // QJsonValue(string, "!") +//! [1] diff --git a/src/corelib/doc/snippets/customtype/customtypeexample.cpp b/src/corelib/doc/snippets/customtype/customtypeexample.cpp index afa2c4b2688..43f7ac7c3ae 100644 --- a/src/corelib/doc/snippets/customtype/customtypeexample.cpp +++ b/src/corelib/doc/snippets/customtype/customtypeexample.cpp @@ -39,6 +39,7 @@ QDebug operator<<(QDebug dbg, const Message &message); //! [custom type streaming operator] QDebug operator<<(QDebug dbg, const Message &message) { + QDebugStateSaver saver(dbg); const QList<QStringView> pieces = message.body().split(u"\r\n", Qt::SkipEmptyParts); if (pieces.isEmpty()) dbg.nospace() << "Message()"; diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 47edc9573f9..fe0f8e1ab68 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -248,7 +248,7 @@ convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true) if (*value == Tmax) { // no double can have an exact value of quint64(-1), but they can // quint32(-1), so we need to compare for that - if (TypeIsLarger || _mm_ucomieq_sd(mv, _mm_set_sd(Tmax))) + if (TypeIsLarger || _mm_ucomieq_sd(mv, _mm_set_sd(double(Tmax)))) return false; } diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 4945d2b66ff..caf8dac464b 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qplatformdefs.h" #include "qdir.h" diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp index c2b274f8b56..0c549a689b3 100644 --- a/src/corelib/io/qipaddress.cpp +++ b/src/corelib/io/qipaddress.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qipaddress_p.h" #include "private/qlocale_tools_p.h" diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 9ae22f68b8e..3e4f5cc27cd 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:execute-external-code //#define QPROCESS_DEBUG diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 68352281667..cdcd68cab2c 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2023 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:execute-external-code #ifndef QPROCESS_H #define QPROCESS_H diff --git a/src/corelib/io/qprocess_darwin.mm b/src/corelib/io/qprocess_darwin.mm index 29b6c6f25d7..aec976e3873 100644 --- a/src/corelib/io/qprocess_darwin.mm +++ b/src/corelib/io/qprocess_darwin.mm @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:execute-external-code #include <private/qprocess_p.h> diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 77ebe5ac2b0..e9634c13dca 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:execute-external-code #ifndef QPROCESS_P_H #define QPROCESS_P_H diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index d78f3461a1b..a6131f117ff 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2022 Intel Corporation. // Copyright (C) 2021 Alex Trotsenko. // 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:execute-external-code //#define QPROCESS_DEBUG #include "qdebug.h" diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 1222322c16e..0995482396b 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2017 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:execute-external-code //#define QPROCESS_DEBUG #include <qdebug.h> diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index ab0e15b3d99..565ce04c6ce 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -537,6 +537,23 @@ public: template <typename String> void setQuery(String &&value, QUrl::ParsingMode mode); template <typename String> void setFragment(String &&value, QUrl::ParsingMode mode); + uint presentSections() const noexcept + { + uint s = sectionIsPresent; + + // We have to ignore the host-is-present flag for local files (the + // "file" protocol), due to the requirements of the XDG file URI + // specification. + if (isLocalFile()) + s &= ~Host; + + // If the password was set, we must have a username too + if (s & Password) + s |= UserName; + + return s; + } + inline bool hasScheme() const { return sectionIsPresent & Scheme; } inline bool hasAuthority() const { return sectionIsPresent & Authority; } inline bool hasUserInfo() const { return sectionIsPresent & UserInfo; } @@ -560,6 +577,15 @@ public: } QString mergePaths(const QString &relativePath) const; + void clear() + { + clearError(); + scheme = userName = password = host = path = query = fragment = QString(); + port = -1; + sectionIsPresent = 0; + flags = 0; + } + QAtomicInt ref; int port; @@ -915,6 +941,8 @@ inline void QUrlPrivate::appendUserName(QString &appendTo, QUrl::FormattingOptio // only called from QUrl::userName() appendToUser(appendTo, userName, options, options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation); + if (appendTo.isNull() && hasPassword()) + appendTo.detach(); // the presence of password implies presence of username } inline void QUrlPrivate::appendPassword(QString &appendTo, QUrl::FormattingOptions options) const @@ -1399,9 +1427,8 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode Q_ASSERT_X(parsingMode != QUrl::DecodedMode, "parse", "This function should only be called when parsing encoded URLs"); - sectionIsPresent = 0; - flags = 0; - clearError(); + Q_ASSERT(sectionIsPresent == 0); + Q_ASSERT(!error); // find the important delimiters qsizetype colon = -1; @@ -1457,10 +1484,10 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode pathStart = authorityEnd; setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode); } else { - userName.clear(); - password.clear(); - host.clear(); - port = -1; + Q_ASSERT(userName.isNull()); + Q_ASSERT(password.isNull()); + Q_ASSERT(host.isNull()); + Q_ASSERT(port == -1); pathStart = hierStart; if (hierStart < hierEnd) @@ -1469,10 +1496,12 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode path.clear(); } + Q_ASSERT(query.isNull()); if (size_t(question) < size_t(hash)) setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1), parsingMode); + Q_ASSERT(fragment.isNull()); if (hash != -1) setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode); @@ -1897,7 +1926,7 @@ void QUrl::setUrl(const QString &url, ParsingMode parsingMode) if (parsingMode == DecodedMode) { qWarning("QUrl: QUrl::DecodedMode is not permitted when parsing a full URL"); } else { - detach(); + detachToClear(); d->parse(url, parsingMode); } } @@ -3090,14 +3119,7 @@ bool comparesEqual(const QUrl &lhs, const QUrl &rhs) if (!rhs.d) return lhs.d->isEmpty(); - // First, compare which sections are present, since it speeds up the - // processing considerably. We just have to ignore the host-is-present flag - // for local files (the "file" protocol), due to the requirements of the - // XDG file URI specification. - int mask = QUrlPrivate::FullUrl; - if (lhs.isLocalFile()) - mask &= ~QUrlPrivate::Host; - return (lhs.d->sectionIsPresent & mask) == (rhs.d->sectionIsPresent & mask) && + return (lhs.d->presentSections() == rhs.d->presentSections()) && lhs.d->scheme == rhs.d->scheme && lhs.d->userName == rhs.d->userName && lhs.d->password == rhs.d->password && @@ -3127,13 +3149,7 @@ bool QUrl::matches(const QUrl &url, FormattingOptions options) const if (!url.d) return d->isEmpty(); - // First, compare which sections are present, since it speeds up the - // processing considerably. We just have to ignore the host-is-present flag - // for local files (the "file" protocol), due to the requirements of the - // XDG file URI specification. - int mask = QUrlPrivate::FullUrl; - if (isLocalFile()) - mask &= ~QUrlPrivate::Host; + uint mask = d->presentSections(); if (options.testFlag(QUrl::RemoveScheme)) mask &= ~QUrlPrivate::Scheme; @@ -3217,12 +3233,9 @@ QUrl &QUrl::operator =(const QUrl &url) noexcept */ QUrl &QUrl::operator =(const QString &url) { - if (url.isEmpty()) { - clear(); - } else { - detach(); + detachToClear(); + if (!url.isEmpty()) d->parse(url, TolerantMode); - } return *this; } @@ -3247,6 +3260,22 @@ void QUrl::detach() /*! \internal + + Forces a detach resulting in a clear state. +*/ +void QUrl::detachToClear() +{ + if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) { + // we had the only copy + d->ref.storeRelaxed(1); + d->clear(); + } else { + d = new QUrlPrivate; + } +} + +/*! + \internal */ bool QUrl::isDetached() const { diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index e9b97cb9bac..d7adedbb8fa 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -276,6 +276,8 @@ private: compareThreeWay(const QUrl &lhs, const QUrl &rhs); Q_DECLARE_WEAKLY_ORDERED_NON_NOEXCEPT(QUrl) + void detachToClear(); + QUrlPrivate *d; friend class QUrlQuery; diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp index dfbe72b2891..98144fad893 100644 --- a/src/corelib/itemmodels/qstringlistmodel.cpp +++ b/src/corelib/itemmodels/qstringlistmodel.cpp @@ -281,13 +281,18 @@ bool QStringListModel::moveRows(const QModelIndex &sourceParent, int sourceRow, if (!beginMoveRows(QModelIndex(), sourceRow, sourceRow + count - 1, QModelIndex(), destinationChild)) return false; - int fromRow = sourceRow; - if (destinationChild < sourceRow) - fromRow += count - 1; - else - destinationChild--; - while (count--) - lst.move(fromRow, destinationChild); + // move [sourceRow, count) into destinationChild: + if (sourceRow < destinationChild) { + auto beg = lst.begin() + sourceRow; + auto end = beg + count; + auto to = lst.begin() + destinationChild; + std::rotate(beg, end, to); + } else { + auto to = lst.begin() + destinationChild; + auto beg = lst.begin() + sourceRow; + auto end = beg + count; + std::rotate(to, beg, end); + } endMoveRows(); return true; } diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index c28149bdc59..236a49544be 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -841,6 +841,11 @@ public: return QtJniTypes::Traits<Class>::className().data(); } + static bool isClassAvailable() + { + return QJniObject::isClassAvailable(QtJniTypes::Traits<Class>::className().data()); + } + private: friend bool comparesEqual(const JObject &lhs, const JObject &rhs) { return lhs.m_object == rhs.m_object; } diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h index c7bec5c1946..935388311a5 100644 --- a/src/corelib/kernel/qjnitypes.h +++ b/src/corelib/kernel/qjnitypes.h @@ -4,6 +4,8 @@ #ifndef QJNITYPES_H #define QJNITYPES_H +#include <QtCore/qglobal.h> + #if defined(Q_QDOC) || defined(Q_OS_ANDROID) #include <QtCore/qjnitypes_impl.h> diff --git a/src/corelib/kernel/qmetacontainer.cpp b/src/corelib/kernel/qmetacontainer.cpp index c70afe163bb..0ac4a79db38 100644 --- a/src/corelib/kernel/qmetacontainer.cpp +++ b/src/corelib/kernel/qmetacontainer.cpp @@ -44,6 +44,16 @@ QT_BEGIN_NAMESPACE \brief The QMetaContainer class provides common functionality for sequential and associative containers. + QMetaContainer is part of Qt's meta-type system that allows type-erased access + to container-like types at runtime. + + It serves as a common base for accessing properties of containers in a generic + way, such as size, iteration, and clearing operations, without knowing the actual + container type. + + Derived classes, such as QMetaSequence, provide specialized interfaces for + sequential containers. + \ingroup objectmodel \compares equality diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index a723d22ced1..85bc3424244 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -97,6 +97,13 @@ struct QMetaTypeDeleter namespace { struct QMetaTypeCustomRegistry { + // HasTypedefs is used as a pointer tag to optimize unregistering of metatypes. + // The entry in aliases for the main/official name has the tag on whether + // there are other typedefs for this type. If there are, we need to search all + // aliases in order to purge them when unregistering a metatype. + enum class HasTypedefs : bool { No, Yes }; + using Alias = QTaggedPointer<const QtPrivate::QMetaTypeInterface, HasTypedefs>; + #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) QMetaTypeCustomRegistry() { @@ -106,13 +113,14 @@ struct QMetaTypeCustomRegistry will get the correct built-in type-id (the interface pointers might still not match, but we already deal with that case. */ - aliases.insert("qfloat16", QtPrivate::qMetaTypeInterfaceForType<qfloat16>()); + aliases.insert( + "qfloat16", Alias(QtPrivate::qMetaTypeInterfaceForType<qfloat16>(), HasTypedefs::No)); } #endif QReadWriteLock lock; QList<const QtPrivate::QMetaTypeInterface *> registry; - QHash<QByteArray, const QtPrivate::QMetaTypeInterface *> aliases; + QHash<QByteArray, Alias> aliases; // index of first empty (unregistered) type in registry, if any. int firstEmpty = 0; @@ -135,7 +143,7 @@ struct QMetaTypeCustomRegistry ti->typeId.storeRelaxed(id); return id; } - aliases[name] = ti; + aliases[name] = Alias(ti, HasTypedefs::No); int size = registry.size(); while (firstEmpty < size && registry[firstEmpty]) ++firstEmpty; @@ -163,7 +171,17 @@ struct QMetaTypeCustomRegistry auto &ti = registry[idx]; // We must unregister all names. - aliases.removeIf([ti] (const auto &kv) { return kv.value() == ti; }); + auto it = aliases.find(ti->name); + if (it->data() == ti) { + switch (it->tag()) { + case HasTypedefs::Yes: + aliases.removeIf([ti] (const auto &kv) { return kv->data() == ti; }); + break; + case HasTypedefs::No: + aliases.erase(it); + break; + } + } ti = nullptr; @@ -194,7 +212,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte auto it = r->aliases.constBegin(); auto end = r->aliases.constEnd(); for ( ; it != end; ++it) { - if (it.value() != type_d) + if (it->data() != type_d) continue; if (it.key() == officialName) continue; // skip the official name @@ -206,7 +224,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte #ifndef QT_NO_DEBUG QByteArrayList otherNames; for ( ; it != end; ++it) { - if (it.value() == type_d && it.key() != officialName) + if (it->data() == type_d && it.key() != officialName) otherNames << it.key(); } l.unlock(); @@ -2849,7 +2867,10 @@ void QMetaType::registerNormalizedTypedef(const NS(QByteArray) & normalizedTypeN auto &al = reg->aliases[normalizedTypeName]; if (al) return; - al = metaType.d_ptr; + + al = QMetaTypeCustomRegistry::Alias( + metaType.d_ptr, QMetaTypeCustomRegistry::HasTypedefs::Yes); + reg->aliases[metaType.name()].setTag(QMetaTypeCustomRegistry::HasTypedefs::Yes); } } #endif // !QT_BOOTSTRAPPED diff --git a/src/corelib/serialization/qcbormap.cpp b/src/corelib/serialization/qcbormap.cpp index bf4d7cbe559..6166775c8ce 100644 --- a/src/corelib/serialization/qcbormap.cpp +++ b/src/corelib/serialization/qcbormap.cpp @@ -165,6 +165,98 @@ using namespace QtCbor; \sa begin(), constBegin(), find(), constFind() */ +/*! \typedef QCborMap::const_key_value_iterator + \inmodule QtCore + \since 6.10 + \brief The QCborMap::const_key_value_iterator typedef provides an STL-style iterator for + QCborMap. + + QCborMap::const_key_value_iterator is essentially the same as QCborMap::const_iterator + but provided for symmetry with other containers like QJsonObject. + + \sa QKeyValueIterator + */ + +/*! \typedef QCborMap::key_value_iterator + \inmodule QtCore + \since 6.10 + \brief The QCborMap::key_value_iterator typedef provides an STL-style iterator for QCborMap. + + QCborMap::key_value_iterator is essentially the same as QCborMap::iterator + but provided for symmetry with other containers like QJsonObject. + + \sa QKeyValueIterator + */ + +/*! \fn QCborMap::key_value_iterator QCborMap::keyValueBegin() + \since 6.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the map. + + \sa keyValueEnd() + */ + +/*! \fn QCborMap::key_value_iterator QCborMap::keyValueEnd() + \since 6.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the map. + + \sa keyValueBegin() +*/ + +/*! \fn QCborMap::const_key_value_iterator QCborMap::keyValueBegin() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the map. + + \sa keyValueEnd() + */ + +/*! \fn QCborMap::const_key_value_iterator QCborMap::constKeyValueBegin() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the map. + + \sa keyValueBegin() + */ + +/*! \fn QCborMap::const_key_value_iterator QCborMap::keyValueEnd() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the map. + + \sa keyValueBegin() + */ + +/*! \fn QCborMap::const_key_value_iterator QCborMap::constKeyValueEnd() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the map. + + \sa constKeyValueBegin() + */ + +/*! \fn auto QCborMap::asKeyValueRange() & + \fn auto QCborMap::asKeyValueRange() const & + \fn auto QCborMap::asKeyValueRange() && + \fn auto QCborMap::asKeyValueRange() const && + \since 6.10 + + Returns a range object that allows iteration over this map as + key/value pairs. + + Note that the values obtained this way are references into the one in the + map. Specifically, mutating the value will modify the map itself. + + \sa QKeyValueIterator + */ + /*! Constructs an empty CBOR Map object. diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h index 1fa93b85157..a5dc0925370 100644 --- a/src/corelib/serialization/qcbormap.h +++ b/src/corelib/serialization/qcbormap.h @@ -16,6 +16,19 @@ class QDataStream; namespace QJsonPrivate { class Variant; } +namespace QtPrivate { + +template <typename T, typename Iterator> +struct QCborMapKeyValues +{ + static QCborValueConstRef key(const Iterator &it) { return it.keyRef(); } + static QCborValueConstRef key(Iterator &it) { return it.keyRef(); } + static T value(const Iterator &it) { return it.value(); } + static T value(Iterator &it) { return it.value(); } +}; + +} // namespace QtPrivate + class QCborContainerPrivate; class Q_CORE_EXPORT QCborMap { @@ -59,6 +72,7 @@ public: QCborValue #endif key() const { return QCborValueRef(item.d, item.i - 1); } + QCborValueConstRef keyRef() const { return QCborValueRef(item.d, item.i - 1); } QCborValueRef value() const { return item; } #if QT_CORE_REMOVED_SINCE(6, 8) @@ -169,6 +183,7 @@ public: QCborValue #endif key() const { return QCborValueRef(item.d, item.i - 1); } + QCborValueConstRef keyRef() const { return QCborValueRef(item.d, item.i - 1); } QCborValueConstRef value() const { return item; } #if QT_CORE_REMOVED_SINCE(6, 8) @@ -325,6 +340,31 @@ public: QCborValue extract(const_iterator it) { return extract(iterator{ it.item.d, it.item.i }); } bool empty() const { return isEmpty(); } + typedef QKeyValueIterator<QCborValueConstRef, QCborValueConstRef, const_iterator, + QtPrivate::QCborMapKeyValues<QCborValueConstRef, ConstIterator>> + const_key_value_iterator; + typedef QKeyValueIterator<QCborValueConstRef, QCborValueRef, iterator, + QtPrivate::QCborMapKeyValues<QCborValueRef, Iterator>> + key_value_iterator; + + key_value_iterator keyValueBegin() { return key_value_iterator(begin()); } + key_value_iterator keyValueEnd() { return key_value_iterator(end()); } + const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); } + const_key_value_iterator constKeyValueBegin() const + { + return const_key_value_iterator(begin()); + } + const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); } + const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); } + + auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QCborMap &>(*this); } + auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QCborMap &>(*this); } + auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QCborMap>(std::move(*this)); } + auto asKeyValueRange() const && + { + return QtPrivate::QKeyValueRange<QCborMap>(std::move(*this)); + } + iterator find(qint64 key); iterator find(QLatin1StringView key); iterator find(const QString & key); diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp index 8377cba4ec8..d51ba037aa7 100644 --- a/src/corelib/serialization/qdatastream.cpp +++ b/src/corelib/serialization/qdatastream.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #include "qdatastream.h" @@ -1412,6 +1413,13 @@ QDataStream &operator<<(QDataStream &out, QChar chr) } /*! + \fn QDataStream::operator bool() const + \since 6.10 + + Returns whether this stream has no errors (status() == \l{OK}). +*/ + +/*! Writes the length specifier \a len and the buffer \a s to the stream and returns a reference to the stream. diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index 6be4b17f092..55632a0f148 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -1,5 +1,6 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser #ifndef QDATASTREAM_H #define QDATASTREAM_H @@ -198,6 +199,8 @@ public: QDataStream &operator<<(char16_t c); QDataStream &operator<<(char32_t c); + explicit operator bool() const noexcept { return status() == Ok; } + #if QT_DEPRECATED_SINCE(6, 11) QT_DEPRECATED_VERSION_X_6_11("Use an overload that takes qint64 length.") QDataStream &readBytes(char *&, uint &len); @@ -309,8 +312,7 @@ QDataStream &readArrayBasedContainer(QDataStream &s, Container &c) c.reserve(n); for (qsizetype i = 0; i < n; ++i) { typename Container::value_type t; - s >> t; - if (s.status() != QDataStream::Ok) { + if (!(s >> t)) { c.clear(); break; } @@ -334,8 +336,7 @@ QDataStream &readListBasedContainer(QDataStream &s, Container &c) } for (qsizetype i = 0; i < n; ++i) { typename Container::value_type t; - s >> t; - if (s.status() != QDataStream::Ok) { + if (!(s >> t)) { c.clear(); break; } @@ -360,8 +361,7 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c) for (qsizetype i = 0; i < n; ++i) { typename Container::key_type k; typename Container::mapped_type t; - s >> k >> t; - if (s.status() != QDataStream::Ok) { + if (!(s >> k >> t)) { c.clear(); break; } diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp index 3e0857dc954..60b2cb3bd0f 100644 --- a/src/corelib/serialization/qjsonobject.cpp +++ b/src/corelib/serialization/qjsonobject.cpp @@ -831,6 +831,107 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const returning \c false. */ +/*! \typedef QJsonObject::const_key_value_iterator + \inmodule QtCore + \since 6.10 + \brief The QJsonObject::const_key_value_iterator typedef provides an STL-style iterator for + QJsonObject. + + QJsonObject::const_key_value_iterator is essentially the same as QJsonObject::const_iterator + with the difference that operator*() returns a key/value pair instead of a + value. + + \sa QKeyValueIterator +*/ + +/*! \typedef QJsonObject::key_value_iterator + \inmodule QtCore + \since 6.10 + \brief The QJsonObject::key_value_iterator typedef provides an STL-style iterator for + QJsonObject. + + QJsonObject::key_value_iterator is essentially the same as QJsonObject::iterator + with the difference that operator*() returns a key/value pair instead of a + value. + + \sa QKeyValueIterator +*/ + +/*! \fn QJsonObject::key_value_iterator QJsonObject::keyValueBegin() + \since 6.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the object. + + \sa keyValueEnd() +*/ + +/*! \fn QJsonObject::key_value_iterator QJsonObject::keyValueEnd() + \since 6.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the object. + + \sa keyValueBegin() +*/ + +/*! \fn QJsonObject::const_key_value_iterator QJsonObject::keyValueBegin() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the object. + + \sa keyValueEnd() +*/ + +/*! \fn QJsonObject::const_key_value_iterator QJsonObject::constKeyValueBegin() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the object. + + \sa keyValueBegin() +*/ + +/*! \fn QJsonObject::const_key_value_iterator QJsonObject::keyValueEnd() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the object. + + \sa keyValueBegin() +*/ + +/*! \fn QJsonObject::const_key_value_iterator QJsonObject::constKeyValueEnd() const + \since 6.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary + entry after the last entry in the ibject. + + \sa constKeyValueBegin() +*/ + +/*! \fn auto QJsonObject::asKeyValueRange() & + \fn auto QJsonObject::asKeyValueRange() const & + \fn auto QJsonObject::asKeyValueRange() && + \fn auto QJsonObject::asKeyValueRange() const && + \since 6.10 + + Returns a range object that allows iteration over this object as + key/value pairs. For instance, this range object can be used in a + range-based for loop, in combination with a structured binding declaration: + + \snippet code/src_corelib_serialization_qjsonobject.cpp 1 + + Note that the value obtained this way is a reference into the one in the + object. Specifically, mutating the value will modify the object itself. + + When calling this method on rvalues (e.g. on a temporary created in the + inializer of a ranged for-loop), the object will be captured in this range. + + \sa QKeyValueIterator +*/ + /*! \class QJsonObject::iterator \inmodule QtCore \ingroup json diff --git a/src/corelib/serialization/qjsonobject.h b/src/corelib/serialization/qjsonobject.h index 41428325b7f..8ad13b3c409 100644 --- a/src/corelib/serialization/qjsonobject.h +++ b/src/corelib/serialization/qjsonobject.h @@ -16,6 +16,19 @@ class QDebug; class QCborContainerPrivate; +namespace QtPrivate { + +template <typename T, typename Iterator> +struct QJsonObjectKeyValues +{ + static QAnyStringView key(const Iterator &it) { return it.keyView(); } + static QAnyStringView key(Iterator &it) { return it.keyView(); } + static T value(const Iterator &it) { return it.value(); } + static T value(Iterator &it) { return it.value(); } +}; + +} // namespace QtPrivate + class Q_CORE_EXPORT QJsonObject { public: @@ -281,6 +294,13 @@ public: }; friend class const_iterator; + typedef QKeyValueIterator<QAnyStringView, QJsonValueConstRef, const_iterator, + QtPrivate::QJsonObjectKeyValues<QJsonValueConstRef, const_iterator>> + const_key_value_iterator; + typedef QKeyValueIterator<QAnyStringView, QJsonValueRef, iterator, + QtPrivate::QJsonObjectKeyValues<QJsonValueRef, iterator>> + key_value_iterator; + // STL style inline iterator begin() { detach(); return iterator(this, 0); } inline const_iterator begin() const { return const_iterator(this, 0); } @@ -288,8 +308,25 @@ public: inline iterator end() { detach(); return iterator(this, size()); } inline const_iterator end() const { return const_iterator(this, size()); } inline const_iterator constEnd() const { return const_iterator(this, size()); } + key_value_iterator keyValueBegin() { return key_value_iterator(begin()); } + key_value_iterator keyValueEnd() { return key_value_iterator(end()); } + const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); } + const_key_value_iterator constKeyValueBegin() const + { + return const_key_value_iterator(begin()); + } + const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); } + const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); } iterator erase(iterator it); + auto asKeyValueRange() & { return QtPrivate::QKeyValueRange<QJsonObject &>(*this); } + auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange<const QJsonObject &>(*this); } + auto asKeyValueRange() && { return QtPrivate::QKeyValueRange<QJsonObject>(std::move(*this)); } + auto asKeyValueRange() const && + { + return QtPrivate::QKeyValueRange<QJsonObject>(std::move(*this)); + } + // more Qt typedef iterator Iterator; typedef const_iterator ConstIterator; diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index fe5c2de3bf6..ad9e1089bfe 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -3199,6 +3199,7 @@ void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode) errorString = QXmlStream::tr("An error occurred while writing"); break; case QXmlStreamWriter::Error::None: + errorString.clear(); break; } } diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 7a8623dc254..e62e5e89db6 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -1870,6 +1870,11 @@ QByteArray::QByteArray(qsizetype size, char ch) /*! Constructs a byte array of size \a size with uninitialized contents. + + For example: + \code + QByteArray buffer(123, Qt::Uninitialized); + \endcode */ QByteArray::QByteArray(qsizetype size, Qt::Initialization) @@ -2014,7 +2019,6 @@ void QByteArray::expand(qsizetype i) } /*! - \fn QByteArray &QByteArray::nullTerminate() \since 6.10 If this byte array's data isn't null-terminated, this method will make @@ -2027,9 +2031,17 @@ void QByteArray::expand(qsizetype i) \sa nullTerminated(), fromRawData(), setRawData() */ +QByteArray &QByteArray::nullTerminate() +{ + // Ensure \0-termination for fromRawData() byte arrays + if (!d.isMutable()) + *this = QByteArray{constData(), size()}; + return *this; +} /*! \fn QByteArray QByteArray::nullTerminated() const & + \fn QByteArray QByteArray::nullTerminated() && \since 6.10 Returns a copy of this byte array that is always null-terminated. @@ -2037,6 +2049,19 @@ void QByteArray::expand(qsizetype i) \sa nullTerminate(), fromRawData(), setRawData() */ +QByteArray QByteArray::nullTerminated() const & +{ + // Ensure \0-termination for fromRawData() byte arrays + if (!d.isMutable()) + return QByteArray{constData(), size()}; + return *this; +} + +QByteArray QByteArray::nullTerminated() && +{ + nullTerminate(); + return std::move(*this); +} /*! \fn QByteArray &QByteArray::prepend(QByteArrayView ba) diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 683e6dcca67..b35984d747e 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -531,29 +531,9 @@ public: #endif explicit inline QByteArray(DataPointer &&dd) : d(std::move(dd)) {} - [[nodiscard]] QByteArray nullTerminated() const & - { - // Ensure \0-termination for fromRawData() byte arrays - if (!d.isMutable()) - return QByteArray{constData(), size()}; - return *this; - } - - [[nodiscard]] QByteArray nullTerminated() && - { - // Ensure \0-termination for fromRawData() byte arrays - if (!d.isMutable()) - return QByteArray{constData(), size()}; - return std::move(*this); - } - - QByteArray &nullTerminate() - { - // Ensure \0-termination for fromRawData() byte arrays - if (!d.isMutable()) - *this = QByteArray{constData(), size()}; - return *this; - } + [[nodiscard]] QByteArray nullTerminated() const &; + [[nodiscard]] QByteArray nullTerminated() &&; + QByteArray &nullTerminate(); private: friend bool comparesEqual(const QByteArray &lhs, const QByteArrayView &rhs) noexcept diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index b2f4919c7c4..abba4b12fb2 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7077,9 +7077,17 @@ const ushort *QString::utf16() const \sa nullTerminated(), fromRawData(), setRawData() */ +QString &QString::nullTerminate() +{ + // ensure '\0'-termination for ::fromRawData strings + if (!d->isMutable()) + *this = QString{constData(), size()}; + return *this; +} /*! \fn QString QString::nullTerminated() const & + \fn QString QString::nullTerminated() && \since 6.10 Returns a copy of this string that is always null-terminated. @@ -7087,6 +7095,19 @@ const ushort *QString::utf16() const \sa nullTerminated(), fromRawData(), setRawData() */ +QString QString::nullTerminated() const & +{ + // ensure '\0'-termination for ::fromRawData strings + if (!d->isMutable()) + return QString{constData(), size()}; + return *this; +} + +QString QString::nullTerminated() && +{ + nullTerminate(); + return std::move(*this); +} /*! Returns a string of size \a width that contains this string diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index a89104dbc8e..09cfbdfe94d 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -707,29 +707,9 @@ public: [[nodiscard]] QString repeated(qsizetype times) const; const ushort *utf16() const; // ### Qt 7 char16_t - [[nodiscard]] QString nullTerminated() const & - { - // ensure '\0'-termination for ::fromRawData strings - if (!d->isMutable()) - return QString{constData(), size()}; - return *this; - } - - [[nodiscard]] QString nullTerminated() && - { - // ensure '\0'-termination for ::fromRawData strings - if (!d->isMutable()) - return QString{constData(), size()}; - return std::move(*this); - } - - QString &nullTerminate() - { - // ensure '\0'-termination for ::fromRawData strings - if (!d->isMutable()) - *this = QString{constData(), size()}; - return *this; - } + [[nodiscard]] QString nullTerminated() const &; + [[nodiscard]] QString nullTerminated() &&; + QString &nullTerminate(); #if !defined(Q_QDOC) [[nodiscard]] QByteArray toLatin1() const & diff --git a/src/corelib/thread/qfuturewatcher.cpp b/src/corelib/thread/qfuturewatcher.cpp index 2cffadfa5be..cb3c5b72bc7 100644 --- a/src/corelib/thread/qfuturewatcher.cpp +++ b/src/corelib/thread/qfuturewatcher.cpp @@ -651,7 +651,7 @@ QT_WARNING_POP no more running computations. After receiving this signal no more result ready or progress reporting signals are expected. - \sa setSuspended(), suspend(), suspended() + \sa setSuspended(), suspend() */ /*! \fn template <typename T> void QFutureWatcher<T>::resumed() diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h index 30b54951a55..885905e7a58 100644 --- a/src/corelib/tools/qiterator.h +++ b/src/corelib/tools/qiterator.h @@ -241,7 +241,21 @@ public: \ #define Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(C) #endif // QT_NO_JAVA_STYLE_ITERATORS -template<typename Key, typename T, class Iterator> +namespace QtPrivate { + +template <typename Key, typename T, typename Iterator> +struct QDefaultKeyValues +{ + static Key key(const Iterator &it) { return it.key(); } + static Key key(Iterator &it) { return it.key(); } + static T value(const Iterator &it) { return it.value(); } + static T value(Iterator &it) { return it.value(); } +}; + +} // namespace QtPrivate + +template <typename Key, typename T, class Iterator, + class Traits = QtPrivate::QDefaultKeyValues<Key, T, Iterator>> class QKeyValueIterator { public: @@ -255,13 +269,13 @@ public: : i(std::move(o)) {} std::pair<Key, T> operator*() const { - return std::pair<Key, T>(i.key(), i.value()); + return std::pair<Key, T>(Traits::key(i), Traits::value(i)); } using pointer = QtPrivate::ArrowProxy<value_type>; pointer operator->() const { - return pointer{std::pair<Key, T>(i.key(), i.value())}; + return pointer{ std::pair<Key, T>(Traits::key(i), Traits::value(i)) }; } friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i == rhs.i; } diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc index 041fb0701d2..99c1c22620b 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -41,22 +41,22 @@ \internal */ -/*! \fn template<typename Key, typename T, class Iterator> QKeyValueIterator<Key, T, Iterator>::QKeyValueIterator() +/*! \fn template<typename Key, typename T, class Iterator, class Traits> QKeyValueIterator<Key, T, Iterator, Traits>::QKeyValueIterator() Constructs a default QKeyValueIterator. */ -/*! \fn template<typename Key, typename T, class Iterator> QKeyValueIterator<Key, T, Iterator>::QKeyValueIterator(Iterator o) +/*! \fn template<typename Key, typename T, class Iterator, class Traits> QKeyValueIterator<Key, T, Iterator, Traits>::QKeyValueIterator(Iterator o) Constructs a QKeyValueIterator on top of \a o. */ -/*! \fn template<typename Key, typename T, class Iterator> std::pair<Key, T> QKeyValueIterator<Key, T, Iterator>::operator*() const +/*! \fn template<typename Key, typename T, class Iterator, class Traits> std::pair<Key, T> QKeyValueIterator<Key, T, Iterator, Traits>::operator*() const Returns the current entry as a pair. */ -/*! \fn template<typename Key, typename T, class Iterator> pointer QKeyValueIterator<Key, T, Iterator>::operator->() const +/*! \fn template<typename Key, typename T, class Iterator, class Traits> pointer QKeyValueIterator<Key, T, Iterator,Traits>::operator->() const Returns the current entry as a pointer-like object to the pair. @@ -65,7 +65,7 @@ \sa operator*() */ -/*! \fn template<typename Key, typename T, class Iterator> bool QKeyValueIterator<Key, T, Iterator>::operator==(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs) +/*! \fn template<typename Key, typename T, class Iterator, class Traits> bool QKeyValueIterator<Key, T, Iterator, Traits>::operator==(QKeyValueIterator<Key, T, Iterator, Traits> lhs, QKeyValueIterator<Key, T, Iterator, Traits> rhs) Returns \c true if \a rhs points to the same item as \a lhs otherwise returns \c false. @@ -73,7 +73,7 @@ \sa operator!=() */ -/*! \fn template<typename Key, typename T, class Iterator> bool QKeyValueIterator<Key, T, Iterator>::operator!=(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs) +/*! \fn template<typename Key, typename T, class Iterator, class Traits> bool QKeyValueIterator<Key, T, Iterator, Traits>::operator!=(QKeyValueIterator<Key, T, Iterator, Traits> lhs, QKeyValueIterator<Key, T, Iterator, Traits> rhs) Returns \c true if \a rhs points to a different item than \a lhs otherwise returns \c false. @@ -82,7 +82,7 @@ */ /*! - \fn template<typename Key, typename T, class Iterator> QKeyValueIterator &QKeyValueIterator<Key, T, Iterator>::operator++() + \fn template<typename Key, typename T, class Iterator, class Traits> QKeyValueIterator &QKeyValueIterator<Key, T, Iterator, Traits>::operator++() The prefix \c{++} operator (\c{++i}) advances the iterator to the next item in the container and returns the iterator. @@ -93,7 +93,7 @@ \sa operator--() */ -/*! \fn template<typename Key, typename T, class Iterator> QKeyValueIterator QKeyValueIterator<Key, T, Iterator>::operator++(int) +/*! \fn template<typename Key, typename T, class Iterator, class Traits> QKeyValueIterator QKeyValueIterator<Key, T, Iterator, Traits>::operator++(int) \overload @@ -104,7 +104,7 @@ undefined behavior. */ -/*! \fn template<typename Key, typename T, class Iterator> QKeyValueIterator &QKeyValueIterator<Key, T, Iterator>::operator--() +/*! \fn template<typename Key, typename T, class Iterator, class Traits> QKeyValueIterator &QKeyValueIterator<Key, T, Iterator, Traits>::operator--() The prefix c{--} operator (\c{--i}) backs the iterator up to the previous item in the container and returns the iterator. @@ -115,7 +115,7 @@ \sa operator++() */ -/*! \fn template<typename Key, typename T, class Iterator> QKeyValueIterator QKeyValueIterator<Key, T, Iterator>::operator--(int) +/*! \fn template<typename Key, typename T, class Iterator, class Traits> QKeyValueIterator QKeyValueIterator<Key, T, Iterator, Traits>::operator--(int) \overload @@ -126,7 +126,7 @@ undefined behavior. */ -/*! \fn template<typename Key, typename T, class Iterator> Iterator QKeyValueIterator<Key, T, Iterator>::base() const +/*! \fn template<typename Key, typename T, class Iterator, class Traits> Iterator QKeyValueIterator<Key, T, Iterator, Traits>::base() const Returns the underlying iterator this QKeyValueIterator is based on. */ diff --git a/src/corelib/tools/qscopeguard.h b/src/corelib/tools/qscopeguard.h index ca7aa864780..627a9250bdc 100644 --- a/src/corelib/tools/qscopeguard.h +++ b/src/corelib/tools/qscopeguard.h @@ -5,6 +5,7 @@ #ifndef QSCOPEGUARD_H #define QSCOPEGUARD_H +#include <QtCore/qassert.h> #include <QtCore/qtclasshelpermacros.h> #include <QtCore/qcompilerdetection.h> #include <QtCore/qtconfigmacros.h> @@ -12,6 +13,8 @@ #include <type_traits> #include <utility> +class tst_QScopeGuard; + QT_BEGIN_NAMESPACE template <typename F> @@ -48,8 +51,16 @@ public: m_invoke = false; } + void commit() noexcept(std::is_nothrow_invocable_v<F>) + { + Q_ASSERT(m_invoke); + m_invoke = false; // do it before we may throw from calling m_func() + m_func(); + } + private: Q_DISABLE_COPY(QScopeGuard) + friend class ::tst_QScopeGuard; F m_func; bool m_invoke = true; diff --git a/src/corelib/tools/qscopeguard.qdoc b/src/corelib/tools/qscopeguard.qdoc index 4c49220755b..ecfb1c79812 100644 --- a/src/corelib/tools/qscopeguard.qdoc +++ b/src/corelib/tools/qscopeguard.qdoc @@ -19,7 +19,7 @@ QT_BEGIN_NAMESPACE exited early by a return statement, or exited by an exception. A scope guard can be disabled using dismiss(), in which case the function - is not run at all. + is not run at all, or executed ahead of destruction, using commit(). \note Exceptions are not supported. The callable shouldn't throw when executed, copied or moved. @@ -45,6 +45,18 @@ QT_BEGIN_NAMESPACE Disarms the scope guard, so that the function \e F will not be called at the end of the scope. + + \sa commit() +*/ + +/*! + \since 6.11 + \fn template <typename F> void QScopeGuard<F>::commit() + + Calls the function \e F and then disarms the scope guard. The guard must be + armed (not been \l{dismiss()}ed) when calling this function. + + \sa dismiss() */ /*! diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index 4cb0bcdd975..82e12aa2dde 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -213,7 +213,7 @@ public: friend QSet operator-(const QSet &lhs, const QSet &rhs) { return QSet(lhs) -= rhs; } friend QSet operator-(QSet &&lhs, const QSet &rhs) { lhs -= rhs; return std::move(lhs); } - QList<T> values() const; + inline QList<T> values() const; private: static inline QSet intersected_helper(const QSet &lhs, const QSet &rhs); @@ -384,7 +384,7 @@ Q_INLINE_TEMPLATE bool QSet<T>::contains(const QSet<T> &other) const } template <typename T> -Q_OUTOFLINE_TEMPLATE QList<T> QSet<T>::values() const +QList<T> QSet<T>::values() const { QList<T> result; result.reserve(size()); diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index 0db433cb623..a56888b302f 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -261,6 +261,12 @@ protected: void assign_impl(qsizetype prealloc, void *array, qsizetype n, const T &t); template <typename Iterator> + void assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last, + std::forward_iterator_tag); + template <typename Iterator> + void assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last, + std::input_iterator_tag); + template <typename Iterator> void assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last); bool isValidIterator(const const_iterator &i) const @@ -824,18 +830,47 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *arr template <class T> template <typename Iterator> -Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last) +Q_OUTOFLINE_TEMPLATE +void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last, + std::forward_iterator_tag) { // This function only provides the basic exception guarantee. - constexpr bool IsFwdIt = - std::is_convertible_v<typename std::iterator_traits<Iterator>::iterator_category, - std::forward_iterator_tag>; - if constexpr (IsFwdIt) { - const qsizetype n = std::distance(first, last); - if (n > capacity()) - reallocate_impl(prealloc, array, 0, n); // clear & reserve n + const qsizetype n = std::distance(first, last); + if (n > capacity()) + reallocate_impl(prealloc, array, 0, n); // clear & reserve n + + auto dst = begin(); + + if constexpr (!QTypeInfo<T>::isComplex) { + // For non-complex types, we prefer a single std::copy() -> memcpy() + // call. We can do that because either the default constructor is + // trivial (so the lifetime has started) or the copy constructor is + // (and won't care what the stored value is). Note that in some cases + // dst > end() after this. + dst = std::copy(first, last, dst); + } else if (n > this->s) { + // overwrite existing elements and create new + for (qsizetype i = 0; i < this->s; ++i) { + *dst = *first; + ++first; + ++dst; + } + std::uninitialized_copy_n(first, n - this->s, dst); + } else { + // overwrite existing elements and destroy tail + dst = std::copy(first, last, dst); + std::destroy(dst, end()); } + this->s = n; +} +template <class T> +template <typename Iterator> +Q_OUTOFLINE_TEMPLATE +void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last, + std::input_iterator_tag) +{ + // This function only provides the basic exception guarantee. auto dst = begin(); const auto dend = end(); while (true) { @@ -844,15 +879,10 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *arr break; } if (dst == dend) { // ran out of existing elements to overwrite - if constexpr (IsFwdIt) { - dst = std::uninitialized_copy(first, last, dst); - break; - } else { do { emplace_back_impl(prealloc, array, *first); } while (++first != last); return; // size() is already correct (and dst invalidated)! - } } *dst = *first; // overwrite existing element ++dst; @@ -862,6 +892,15 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *arr } template <class T> +template <typename Iterator> +Q_OUTOFLINE_TEMPLATE +void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last) +{ + using Cat = typename std::iterator_traits<Iterator>::iterator_category; + assign_impl(prealloc, array, first, last, Cat{}); +} + +template <class T> Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc) { Q_ASSERT(aalloc >= asize); diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index 9f91d4ed4e1..b10266ac8b7 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -520,6 +520,15 @@ QDBusMessage::QDBusMessage() } /*! + \fn QDBusMessage::QDBusMessage(QDBusMessage &&other) + \since 6.11 + + Moves \a other into this object. + + \include qdbusmessage.cpp partially-formed +*/ + +/*! Constructs a copy of the object given by \a other. Note: QDBusMessage objects are shared. Modifications made to the @@ -537,11 +546,23 @@ QDBusMessage::QDBusMessage(const QDBusMessage &other) */ QDBusMessage::~QDBusMessage() { - if (!d_ptr->ref.deref()) + if (d_ptr && !d_ptr->ref.deref()) delete d_ptr; } /*! + \fn QDBusMessage &QDBusMessage::operator=(QDBusMessage &&other) + + Move-assigns \a other into this object. + +//! [partially-formed] + \note The moved-from object \a other is placed in a partially-formed state, + in which the only valid operations are destruction and assignment of a new + value. +//! [partially-formed] +*/ + +/*! Copies the contents of the object given by \a other. Note: QDBusMessage objects are shared. Modifications made to the @@ -550,7 +571,8 @@ QDBusMessage::~QDBusMessage() */ QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other) { - qAtomicAssign(d_ptr, other.d_ptr); + QDBusMessage copy(other); + swap(copy); return *this; } diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h index f6db3bc21e6..608b9779d22 100644 --- a/src/dbus/qdbusmessage.h +++ b/src/dbus/qdbusmessage.h @@ -31,6 +31,7 @@ public: QDBusMessage(); QDBusMessage(const QDBusMessage &other); + QDBusMessage(QDBusMessage &&other) noexcept : d_ptr(std::exchange(other.d_ptr, nullptr)) {} QDBusMessage &operator=(QDBusMessage &&other) noexcept { swap(other); return *this; } QDBusMessage &operator=(const QDBusMessage &other); ~QDBusMessage(); diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index 225b05ed1e2..cd222c9ffa5 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -227,6 +227,15 @@ void QDBusPendingCallPrivate::waitForFinishedWithGui() } /*! + \fn QDBusPendingCall::QDBusPendingCall(QDBusPendingCall &&other) + \since 6.11 + + Moves \a other into this object. + + \include qdbuspendingcall.cpp partially-formed +*/ + +/*! Creates a copy of the \a other pending asynchronous call. Note that both objects will refer to the same pending call. */ @@ -258,6 +267,19 @@ QDBusPendingCall::~QDBusPendingCall() // d deleted by QExplicitlySharedDataPointer } +QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDBusPendingCallPrivate) + +/*! + \fn QDBusPendingCall &QDBusPendingCall::operator=(QDBusPendingCall &&other) + + Move-assigns \a other into this QDBusPendingCall. + +//! [partially-formed] + \note The moved-from object \a other is placed in a partially-formed state, + in which the only valid operations are destruction and assignment of a new + value. +//! [partially-formed] +*/ /*! Creates a copy of the \a other pending asynchronous call and drops diff --git a/src/dbus/qdbuspendingcall.h b/src/dbus/qdbuspendingcall.h index c2763762239..0db6667e5ec 100644 --- a/src/dbus/qdbuspendingcall.h +++ b/src/dbus/qdbuspendingcall.h @@ -19,10 +19,14 @@ class QDBusError; class QDBusPendingCallWatcher; class QDBusPendingCallPrivate; + +QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QDBusPendingCallPrivate) + class Q_DBUS_EXPORT QDBusPendingCall { public: QDBusPendingCall(const QDBusPendingCall &other); + QDBusPendingCall(QDBusPendingCall &&other) noexcept = default; ~QDBusPendingCall(); QDBusPendingCall &operator=(QDBusPendingCall &&other) noexcept { swap(other); return *this; } QDBusPendingCall &operator=(const QDBusPendingCall &other); diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1b210e1f420..4f236c9faca 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,10 +1,10 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(X11_XCB) -qt_find_package(WrapHarfbuzz PROVIDED_TARGETS WrapHarfbuzz::WrapHarfbuzz) -qt_find_package(WrapPNG PROVIDED_TARGETS WrapPNG::WrapPNG) -qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype) +qt_find_package(X11_XCB MODULE) +qt_find_package(WrapHarfbuzz MODULE PROVIDED_TARGETS WrapHarfbuzz::WrapHarfbuzz) +qt_find_package(WrapPNG MODULE PROVIDED_TARGETS WrapPNG::WrapPNG) +qt_find_package(WrapFreetype MODULE PROVIDED_TARGETS WrapFreetype::WrapFreetype) if (QT_FEATURE_gui) if(QT_QPA_PLATFORMS) @@ -427,6 +427,7 @@ qt_internal_extend_target(Gui CONDITION APPLE platform/darwin/qmacmimeregistry.mm platform/darwin/qmacmimeregistry_p.h platform/darwin/qutimimeconverter.mm platform/darwin/qutimimeconverter.h platform/darwin/qapplekeymapper.mm platform/darwin/qapplekeymapper_p.h + platform/darwin/qapplefileiconengine.mm platform/darwin/qapplefileiconengine_p.h platform/darwin/qappleiconengine.mm platform/darwin/qappleiconengine_p.h text/coretext/qcoretextfontdatabase.mm text/coretext/qcoretextfontdatabase_p.h text/coretext/qfontengine_coretext.mm text/coretext/qfontengine_coretext_p.h @@ -517,7 +518,7 @@ if(QT_FEATURE_graphicsframecapture) endif() if(QT_FEATURE_egl) - qt_find_package(EGL) + qt_find_package(EGL MODULE) endif() qt_internal_extend_target(Gui CONDITION QT_FEATURE_egl diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake index e04c25bc112..72c17ec62a5 100644 --- a/src/gui/configure.cmake +++ b/src/gui/configure.cmake @@ -30,23 +30,26 @@ set_property(CACHE INPUT_libpng PROPERTY STRINGS undefined no qt system) #### Libraries qt_set01(X11_SUPPORTED LINUX OR HPUX OR FREEBSD OR NETBSD OR OPENBSD OR SOLARIS OR HURD) -qt_find_package(ATSPI2 PROVIDED_TARGETS PkgConfig::ATSPI2 MODULE_NAME gui QMAKE_LIB atspi) +qt_find_package(ATSPI2 MODULE PROVIDED_TARGETS PkgConfig::ATSPI2 MODULE_NAME gui QMAKE_LIB atspi) qt_find_package(DirectFB PROVIDED_TARGETS PkgConfig::DirectFB MODULE_NAME gui QMAKE_LIB directfb) -qt_find_package(Libdrm PROVIDED_TARGETS Libdrm::Libdrm MODULE_NAME gui QMAKE_LIB drm) +qt_find_package(Libdrm MODULE PROVIDED_TARGETS Libdrm::Libdrm MODULE_NAME gui QMAKE_LIB drm) qt_find_package(PlatformGraphics PROVIDED_TARGETS PlatformGraphics::PlatformGraphics MODULE_NAME gui QMAKE_LIB platform_graphics) -qt_find_package(EGL PROVIDED_TARGETS EGL::EGL MODULE_NAME gui QMAKE_LIB egl) +qt_find_package(EGL MODULE PROVIDED_TARGETS EGL::EGL MODULE_NAME gui QMAKE_LIB egl) -qt_find_package(WrapSystemFreetype 2.2.0 PROVIDED_TARGETS WrapSystemFreetype::WrapSystemFreetype MODULE_NAME gui QMAKE_LIB freetype) +qt_find_package(WrapSystemFreetype 2.2.0 MODULE + PROVIDED_TARGETS WrapSystemFreetype::WrapSystemFreetype MODULE_NAME gui QMAKE_LIB freetype) if(QT_FEATURE_system_zlib) qt_add_qmake_lib_dependency(freetype zlib) endif() qt_find_package(Fontconfig PROVIDED_TARGETS Fontconfig::Fontconfig MODULE_NAME gui QMAKE_LIB fontconfig) qt_add_qmake_lib_dependency(fontconfig freetype) -qt_find_package(gbm PROVIDED_TARGETS gbm::gbm MODULE_NAME gui QMAKE_LIB gbm) -qt_find_package(WrapSystemHarfbuzz 2.6.0 PROVIDED_TARGETS WrapSystemHarfbuzz::WrapSystemHarfbuzz MODULE_NAME gui QMAKE_LIB harfbuzz) -qt_find_package(Libinput PROVIDED_TARGETS Libinput::Libinput MODULE_NAME gui QMAKE_LIB libinput) +qt_find_package(gbm MODULE PROVIDED_TARGETS gbm::gbm MODULE_NAME gui QMAKE_LIB gbm) +qt_find_package(WrapSystemHarfbuzz 2.6.0 MODULE + PROVIDED_TARGETS WrapSystemHarfbuzz::WrapSystemHarfbuzz MODULE_NAME gui QMAKE_LIB harfbuzz) +qt_find_package(Libinput MODULE + PROVIDED_TARGETS Libinput::Libinput MODULE_NAME gui QMAKE_LIB libinput) qt_find_package_extend_sbom(TARGETS Libinput::Libinput COPYRIGHTS "Copyright © 2006-2009 Simon Thum" @@ -57,113 +60,134 @@ qt_find_package_extend_sbom(TARGETS Libinput::Libinput "Copyright © 2013-2014 Jonas Ã…dahl" "Copyright © 2013-2015 Red Hat, Inc." ) -qt_find_package(WrapSystemJpeg PROVIDED_TARGETS WrapSystemJpeg::WrapSystemJpeg MODULE_NAME gui QMAKE_LIB libjpeg) -qt_find_package(WrapSystemMd4c PROVIDED_TARGETS WrapSystemMd4c::WrapSystemMd4c MODULE_NAME gui QMAKE_LIB libmd4c) -qt_find_package(WrapSystemPNG PROVIDED_TARGETS WrapSystemPNG::WrapSystemPNG MODULE_NAME gui QMAKE_LIB libpng) +qt_find_package(WrapSystemJpeg MODULE + PROVIDED_TARGETS WrapSystemJpeg::WrapSystemJpeg MODULE_NAME gui QMAKE_LIB libjpeg) +qt_find_package(WrapSystemMd4c MODULE + PROVIDED_TARGETS WrapSystemMd4c::WrapSystemMd4c MODULE_NAME gui QMAKE_LIB libmd4c) +qt_find_package(WrapSystemPNG MODULE + PROVIDED_TARGETS WrapSystemPNG::WrapSystemPNG MODULE_NAME gui QMAKE_LIB libpng) if(QT_FEATURE_system_zlib) qt_add_qmake_lib_dependency(libpng zlib) endif() -qt_find_package(Mtdev PROVIDED_TARGETS PkgConfig::Mtdev MODULE_NAME gui QMAKE_LIB mtdev) -qt_find_package(WrapOpenGL PROVIDED_TARGETS WrapOpenGL::WrapOpenGL MODULE_NAME gui QMAKE_LIB opengl) -qt_find_package(GLESv2 PROVIDED_TARGETS GLESv2::GLESv2 MODULE_NAME gui QMAKE_LIB opengl_es2) -qt_find_package(Tslib PROVIDED_TARGETS PkgConfig::Tslib MODULE_NAME gui QMAKE_LIB tslib) -qt_find_package(WrapVulkanHeaders PROVIDED_TARGETS WrapVulkanHeaders::WrapVulkanHeaders +qt_find_package(Mtdev MODULE PROVIDED_TARGETS PkgConfig::Mtdev MODULE_NAME gui QMAKE_LIB mtdev) +qt_find_package(WrapOpenGL MODULE PROVIDED_TARGETS WrapOpenGL::WrapOpenGL MODULE_NAME gui QMAKE_LIB opengl) +qt_find_package(GLESv2 MODULE + PROVIDED_TARGETS GLESv2::GLESv2 MODULE_NAME gui QMAKE_LIB opengl_es2) +qt_find_package(Tslib MODULE PROVIDED_TARGETS PkgConfig::Tslib MODULE_NAME gui QMAKE_LIB tslib) +qt_find_package(WrapVulkanHeaders MODULE PROVIDED_TARGETS WrapVulkanHeaders::WrapVulkanHeaders MODULE_NAME gui QMAKE_LIB vulkan MARK_OPTIONAL) if(LINUX OR FREEBSD OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(Wayland PROVIDED_TARGETS Wayland::Server + qt_find_package(Wayland MODULE PROVIDED_TARGETS Wayland::Server MODULE_NAME gui QMAKE_LIB wayland_server) - qt_find_package(Wayland PROVIDED_TARGETS Wayland::Client + qt_find_package(Wayland MODULE PROVIDED_TARGETS Wayland::Client MODULE_NAME gui QMAKE_LIB wayland_client) # Gui doesn't use these, but the wayland qpa plugin does, and we # need to list the rest of the provided targets here, so they are # promoted to global, and can be accessed by the SBOM at the root # project level. That's not possible to do in the wayland qpa subdir, # due to different cmake directory scopes. - qt_find_package(Wayland PROVIDED_TARGETS Wayland::Cursor + qt_find_package(Wayland MODULE PROVIDED_TARGETS Wayland::Cursor MODULE_NAME gui QMAKE_LIB wayland_cursor) - qt_find_package(Wayland PROVIDED_TARGETS Wayland::Egl + qt_find_package(Wayland MODULE PROVIDED_TARGETS Wayland::Egl MODULE_NAME gui QMAKE_LIB wayland_egl) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(X11 PROVIDED_TARGETS X11::X11 MODULE_NAME gui QMAKE_LIB xlib) + qt_find_package(X11 MODULE PROVIDED_TARGETS X11::X11 MODULE_NAME gui QMAKE_LIB xlib) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(X11 PROVIDED_TARGETS X11::SM X11::ICE MODULE_NAME gui QMAKE_LIB x11sm) + qt_find_package(X11 MODULE PROVIDED_TARGETS X11::SM X11::ICE MODULE_NAME gui QMAKE_LIB x11sm) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 1.11 PROVIDED_TARGETS XCB::XCB MODULE_NAME gui QMAKE_LIB xcb) + qt_find_package(XCB 1.11 MODULE PROVIDED_TARGETS XCB::XCB MODULE_NAME gui QMAKE_LIB xcb) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 0.1.1 COMPONENTS CURSOR PROVIDED_TARGETS XCB::CURSOR MODULE_NAME gui QMAKE_LIB xcb_cursor) + qt_find_package(XCB 0.1.1 MODULE + COMPONENTS CURSOR PROVIDED_TARGETS XCB::CURSOR MODULE_NAME gui QMAKE_LIB xcb_cursor) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 0.3.9 COMPONENTS ICCCM PROVIDED_TARGETS XCB::ICCCM MODULE_NAME gui QMAKE_LIB xcb_icccm) + qt_find_package(XCB 0.3.9 MODULE + COMPONENTS ICCCM PROVIDED_TARGETS XCB::ICCCM MODULE_NAME gui QMAKE_LIB xcb_icccm) endif() qt_add_qmake_lib_dependency(xcb_icccm xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 0.3.8 COMPONENTS UTIL PROVIDED_TARGETS XCB::UTIL MODULE_NAME gui QMAKE_LIB xcb_util) + qt_find_package(XCB 0.3.8 MODULE + COMPONENTS UTIL PROVIDED_TARGETS XCB::UTIL MODULE_NAME gui QMAKE_LIB xcb_util) endif() qt_add_qmake_lib_dependency(xcb_util xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 0.3.9 COMPONENTS IMAGE PROVIDED_TARGETS XCB::IMAGE MODULE_NAME gui QMAKE_LIB xcb_image) + qt_find_package(XCB 0.3.9 MODULE + COMPONENTS IMAGE PROVIDED_TARGETS XCB::IMAGE MODULE_NAME gui QMAKE_LIB xcb_image) endif() qt_add_qmake_lib_dependency(xcb_image xcb_shm xcb_util xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 0.3.9 COMPONENTS KEYSYMS PROVIDED_TARGETS XCB::KEYSYMS MODULE_NAME gui QMAKE_LIB xcb_keysyms) + qt_find_package(XCB 0.3.9 MODULE + COMPONENTS KEYSYMS PROVIDED_TARGETS XCB::KEYSYMS MODULE_NAME gui QMAKE_LIB xcb_keysyms) endif() qt_add_qmake_lib_dependency(xcb_keysyms xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 0.3.9 COMPONENTS RENDERUTIL PROVIDED_TARGETS XCB::RENDERUTIL MODULE_NAME gui QMAKE_LIB xcb_renderutil) + qt_find_package(XCB 0.3.9 MODULE + COMPONENTS RENDERUTIL PROVIDED_TARGETS XCB::RENDERUTIL MODULE_NAME gui QMAKE_LIB xcb_renderutil) endif() qt_add_qmake_lib_dependency(xcb_renderutil xcb xcb_render) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS RANDR PROVIDED_TARGETS XCB::RANDR MODULE_NAME gui QMAKE_LIB xcb_randr) + qt_find_package(XCB MODULE + COMPONENTS RANDR PROVIDED_TARGETS XCB::RANDR MODULE_NAME gui QMAKE_LIB xcb_randr) endif() qt_add_qmake_lib_dependency(xcb_randr xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS SHAPE PROVIDED_TARGETS XCB::SHAPE MODULE_NAME gui QMAKE_LIB xcb_shape) + qt_find_package(XCB MODULE + COMPONENTS SHAPE PROVIDED_TARGETS XCB::SHAPE MODULE_NAME gui QMAKE_LIB xcb_shape) endif() qt_add_qmake_lib_dependency(xcb_shape xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS SHM PROVIDED_TARGETS XCB::SHM MODULE_NAME gui QMAKE_LIB xcb_shm) + qt_find_package(XCB MODULE + COMPONENTS SHM PROVIDED_TARGETS XCB::SHM MODULE_NAME gui QMAKE_LIB xcb_shm) endif() qt_add_qmake_lib_dependency(xcb_shm xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS SYNC PROVIDED_TARGETS XCB::SYNC MODULE_NAME gui QMAKE_LIB xcb_sync) + qt_find_package(XCB MODULE + COMPONENTS SYNC PROVIDED_TARGETS XCB::SYNC MODULE_NAME gui QMAKE_LIB xcb_sync) endif() qt_add_qmake_lib_dependency(xcb_sync xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS XFIXES PROVIDED_TARGETS XCB::XFIXES MODULE_NAME gui QMAKE_LIB xcb_xfixes) + qt_find_package(XCB MODULE + COMPONENTS XFIXES PROVIDED_TARGETS XCB::XFIXES MODULE_NAME gui QMAKE_LIB xcb_xfixes) endif() qt_add_qmake_lib_dependency(xcb_xfixes xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(X11_XCB PROVIDED_TARGETS X11::XCB MODULE_NAME gui QMAKE_LIB xcb_xlib) + qt_find_package(X11_XCB MODULE PROVIDED_TARGETS X11::XCB MODULE_NAME gui QMAKE_LIB xcb_xlib) endif() qt_add_qmake_lib_dependency(xcb_xlib xcb xlib) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS XKB PROVIDED_TARGETS XCB::XKB MODULE_NAME gui QMAKE_LIB xcb_xkb) + qt_find_package(XCB MODULE + COMPONENTS XKB PROVIDED_TARGETS XCB::XKB MODULE_NAME gui QMAKE_LIB xcb_xkb) endif() qt_add_qmake_lib_dependency(xcb_xkb xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS RENDER PROVIDED_TARGETS XCB::RENDER MODULE_NAME gui QMAKE_LIB xcb_render) + qt_find_package(XCB MODULE + COMPONENTS RENDER PROVIDED_TARGETS XCB::RENDER MODULE_NAME gui QMAKE_LIB xcb_render) endif() qt_add_qmake_lib_dependency(xcb_render xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB COMPONENTS GLX PROVIDED_TARGETS XCB::GLX MODULE_NAME gui QMAKE_LIB xcb_glx) + qt_find_package(XCB MODULE + COMPONENTS GLX PROVIDED_TARGETS XCB::GLX MODULE_NAME gui QMAKE_LIB xcb_glx) endif() qt_add_qmake_lib_dependency(xcb_glx xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XCB 1.12 COMPONENTS XINPUT PROVIDED_TARGETS XCB::XINPUT MODULE_NAME gui QMAKE_LIB xcb_xinput) + qt_find_package(XCB 1.12 MODULE + COMPONENTS XINPUT PROVIDED_TARGETS XCB::XINPUT MODULE_NAME gui QMAKE_LIB xcb_xinput) endif() qt_add_qmake_lib_dependency(xcb_xinput xcb) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XKB 0.5.0 PROVIDED_TARGETS XKB::XKB MODULE_NAME gui QMAKE_LIB xkbcommon) + qt_find_package(XKB 0.5.0 MODULE PROVIDED_TARGETS XKB::XKB MODULE_NAME gui QMAKE_LIB xkbcommon) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XKB_COMMON_X11 0.5.0 PROVIDED_TARGETS PkgConfig::XKB_COMMON_X11 MODULE_NAME gui QMAKE_LIB xkbcommon_x11) + qt_find_package(XKB_COMMON_X11 0.5.0 MODULE + PROVIDED_TARGETS PkgConfig::XKB_COMMON_X11 MODULE_NAME gui QMAKE_LIB xkbcommon_x11) endif() if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(XRender 0.6 PROVIDED_TARGETS PkgConfig::XRender MODULE_NAME gui QMAKE_LIB xrender) + qt_find_package(XRender 0.6 MODULE + PROVIDED_TARGETS PkgConfig::XRender MODULE_NAME gui QMAKE_LIB xrender) endif() qt_add_qmake_lib_dependency(xrender xlib) @@ -171,11 +195,12 @@ qt_add_qmake_lib_dependency(xrender xlib) if(LINUX OR FREEBSD OR QT_FIND_ALL_PACKAGES_ALWAYS) # EGL if(NOT TARGET EGL::EGL) - qt_find_package(EGL PROVIDED_TARGETS EGL::EGL MODULE_NAME gui QMAKE_LIB egl MARK_OPTIONAL) + qt_find_package(EGL MODULE + PROVIDED_TARGETS EGL::EGL MODULE_NAME gui QMAKE_LIB egl MARK_OPTIONAL) endif() # and Libdrm if(NOT TARGET Libdrm::Libdrm) - qt_find_package(Libdrm + qt_find_package(Libdrm MODULE PROVIDED_TARGETS Libdrm::Libdrm MODULE_NAME gui QMAKE_LIB drm @@ -183,10 +208,10 @@ if(LINUX OR FREEBSD OR QT_FIND_ALL_PACKAGES_ALWAYS) endif() endif() -qt_find_package(Wayland 1.15) -qt_find_package(WaylandScanner PROVIDED_TARGETS Wayland::Scanner) +qt_find_package(Wayland 1.15 MODULE) +qt_find_package(WaylandScanner MODULE PROVIDED_TARGETS Wayland::Scanner) -qt_find_package(RenderDoc PROVIDED_TARGETS RenderDoc::RenderDoc) +qt_find_package(RenderDoc MODULE PROVIDED_TARGETS RenderDoc::RenderDoc) #### Tests @@ -1545,7 +1570,7 @@ qt_feature("wayland-dmabuf-server-buffer" PRIVATE ) qt_feature("wayland-shm-emulation-server-buffer" PRIVATE LABEL "Shm emulation server buffer" - CONDITION (QT_FEATURE_wayland_client OR QT_FEATURE_wayland_server) AND QT_FEATURE_opengl + CONDITION (QT_FEATURE_wayland_client OR QT_FEATURE_wayland_server) AND QT_FEATURE_opengl AND QT_FEATURE_sharedmemory ) qt_feature("wayland-vulkan-server-buffer" PRIVATE LABEL "Vulkan-based server buffer" diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 62f397ef229..647d33f6c70 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -175,8 +175,7 @@ static inline uint apply_scale(uint value, uint scale) static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf) { // read BMP file header - s >> bf; - if (s.status() != QDataStream::Ok) + if (!(s >> bf)) return false; // check header @@ -188,8 +187,7 @@ static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf) static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi) { - s >> bi; // read BMP info header - if (s.status() != QDataStream::Ok) + if (!(s >> bi)) // read BMP info header return false; int nbits = bi.biBitCount; @@ -602,8 +600,7 @@ bool qt_write_dib(QDataStream &s, const QImage &image, int bpl, int bpl_bmp, int bi.biYPelsPerMeter = image.dotsPerMeterY() ? image.dotsPerMeterY() : 2834; bi.biClrUsed = image.colorCount(); bi.biClrImportant = image.colorCount(); - s << bi; // write info header - if (s.status() != QDataStream::Ok) + if (!(s << bi)) // write info header return false; if (image.depth() != 32) { // write color table diff --git a/src/gui/platform/darwin/qapplefileiconengine.mm b/src/gui/platform/darwin/qapplefileiconengine.mm new file mode 100644 index 00000000000..f1ba6319d0a --- /dev/null +++ b/src/gui/platform/darwin/qapplefileiconengine.mm @@ -0,0 +1,69 @@ +// 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 "qapplefileiconengine_p.h" +#include "qappleiconengine_p.h" + +#if defined(Q_OS_MACOS) +# include <AppKit/AppKit.h> +#elif defined(QT_PLATFORM_UIKIT) +# include <UIKit/UIKit.h> +#endif + +#include <QtGui/private/qcoregraphics_p.h> + +QT_BEGIN_NAMESPACE + +using namespace Qt::StringLiterals; + +QAppleFileIconEngine::QAppleFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts) + : QAbstractFileIconEngine(info, opts) +{ +#if defined(Q_OS_MACOS) + m_image = [[NSWorkspace sharedWorkspace] iconForFile:fileInfo().canonicalFilePath().toNSString()]; +#elif defined(QT_PLATFORM_UIKIT) + const QUrl url = QUrl::fromLocalFile(fileInfo().canonicalFilePath()); + const auto controller = [UIDocumentInteractionController interactionControllerWithURL:url.toNSURL()]; + const auto allIcons = controller.icons; + m_image = allIcons.count > 0 ? [allIcons firstObject] : nil; +#endif + if (m_image) + [m_image retain]; +} + +QAppleFileIconEngine::~QAppleFileIconEngine() +{ + if (m_image) + [m_image release]; +} + +QList<QSize> QAppleFileIconEngine::availableSizes(QIcon::Mode, QIcon::State) +{ + return QAppleIconEngine::availableIconSizes(); +} + +bool QAppleFileIconEngine::isNull() +{ + return m_image == nil; +} + +QPixmap QAppleFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon::State) +{ + if (!m_image) + return QPixmap(); + + const QSize preferredSize = QSize(m_image.size.width, + m_image.size.height).scaled(size, Qt::KeepAspectRatio); + + if (m_pixmap.size() == preferredSize) + return m_pixmap; + +#if defined(Q_OS_MACOS) + m_pixmap = qt_mac_toQPixmap(m_image, preferredSize); +#elif defined(QT_PLATFORM_UIKIT) + m_pixmap = QPixmap::fromImage(qt_mac_toQImage(m_image, preferredSize)); +#endif + return m_pixmap; +} + +QT_END_NAMESPACE diff --git a/src/gui/platform/darwin/qapplefileiconengine_p.h b/src/gui/platform/darwin/qapplefileiconengine_p.h new file mode 100644 index 00000000000..b4d6130393f --- /dev/null +++ b/src/gui/platform/darwin/qapplefileiconengine_p.h @@ -0,0 +1,51 @@ +// 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 + +#ifndef QAPPLEFILEICONENGINE_P_H +#define QAPPLEFILEICONENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qabstractfileiconengine_p.h> +#include <QtCore/private/qcore_mac_p.h> + +Q_FORWARD_DECLARE_OBJC_CLASS(UIImage); +Q_FORWARD_DECLARE_OBJC_CLASS(NSImage); + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QAppleFileIconEngine : public QAbstractFileIconEngine +{ +public: + explicit QAppleFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts); + ~QAppleFileIconEngine() override; + + bool isNull() override; + QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) override; + +protected: + QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override; + +private: +#if defined(Q_OS_MACOS) + NSImage *m_image = nil; +#elif defined(QT_PLATFORM_UIKIT) + UIImage *m_image = nil; +#endif + + QPixmap m_pixmap; +}; + + +QT_END_NAMESPACE + +#endif // QAPPLEFILEICONENGINE_P_H diff --git a/src/gui/platform/darwin/qappleiconengine.mm b/src/gui/platform/darwin/qappleiconengine.mm index 84e9ff4ea39..7745cfb6ce5 100644 --- a/src/gui/platform/darwin/qappleiconengine.mm +++ b/src/gui/platform/darwin/qappleiconengine.mm @@ -187,6 +187,7 @@ auto *loadImage(const QString &iconName) {"multimedia-player"_L1, @"play.rectangle"}, {"network-wired"_L1, @"app.connected.to.app.below.fill"}, {"network-wireless"_L1, @"wifi"}, + {"network-workgroup"_L1, @"network"}, //{"pda"_L1, @""}, {"phone"_L1, @"iphone"}, {"printer"_L1, @"printer"}, @@ -205,13 +206,13 @@ auto *loadImage(const QString &iconName) {"emblem-synchronized"_L1, @"arrow.triangle.2.circlepath.circle"}, {"emblem-system"_L1, @"gear"}, //{"emblem-unreadable"_L1, @""}, + {"text-x-generic"_L1, @"doc"}, // until iOS 18/macOS 15; @"document" after that {"folder"_L1, @"folder"}, //{"folder-remote"_L1, @""}, {"network-server"_L1, @"server.rack"}, - //{"network-workgroup"_L1, @""}, //{"start-here"_L1, @""}, {"user-bookmarks"_L1, @"bookmark.circle"}, - {"user-desktop"_L1, @"desktopcomputer"}, //"computer" also using this one + {"user-desktop"_L1, @"menubar.dock.rectangle"}, // used by finder {"user-home"_L1, @"house"}, //"go-home" also using this one {"user-trash"_L1, @"trash"}, {"appointment-missed"_L1, @"calendar.badge.exclamationmark"}, diff --git a/src/gui/platform/darwin/qappleiconengine_p.h b/src/gui/platform/darwin/qappleiconengine_p.h index d99c60ffc54..7d20896517b 100644 --- a/src/gui/platform/darwin/qappleiconengine_p.h +++ b/src/gui/platform/darwin/qappleiconengine_p.h @@ -72,7 +72,6 @@ private: mutable QHash<CacheKey, QPixmap> m_cache; }; - QT_END_NAMESPACE #endif // QAPPLEICONENGINE_P_H diff --git a/src/network/access/qhstsstore.cpp b/src/network/access/qhstsstore.cpp index a972a90ee7e..4497ba365a7 100644 --- a/src/network/access/qhstsstore.cpp +++ b/src/network/access/qhstsstore.cpp @@ -128,12 +128,10 @@ bool QHstsStore::deserializePolicy(const QString &key, QHstsPolicy &policy) const QByteArray serializedData(data.toByteArray()); QDataStream streamer(serializedData); qint64 expiryInMS = 0; - streamer >> expiryInMS; - if (streamer.status() != QDataStream::Ok) + if (!(streamer >> expiryInMS)) return false; bool includesSubDomains = false; - streamer >> includesSubDomains; - if (streamer.status() != QDataStream::Ok) + if (!(streamer >> includesSubDomains)) return false; policy.setExpiry(QDateTime::fromMSecsSinceEpoch(expiryInMS)); diff --git a/src/network/configure.cmake b/src/network/configure.cmake index 4d4db9d256c..980f097e7e8 100644 --- a/src/network/configure.cmake +++ b/src/network/configure.cmake @@ -7,12 +7,17 @@ #### Libraries -qt_find_package(WrapBrotli PROVIDED_TARGETS WrapBrotli::WrapBrotliDec MODULE_NAME network QMAKE_LIB brotli) -qt_find_package(Libproxy PROVIDED_TARGETS PkgConfig::Libproxy MODULE_NAME network QMAKE_LIB libproxy) -qt_find_package(GSSAPI PROVIDED_TARGETS GSSAPI::GSSAPI MODULE_NAME network QMAKE_LIB gssapi) -qt_find_package(GLIB2 OPTIONAL_COMPONENTS GOBJECT PROVIDED_TARGETS GLIB2::GOBJECT MODULE_NAME core QMAKE_LIB gobject) -qt_find_package(GLIB2 OPTIONAL_COMPONENTS GIO PROVIDED_TARGETS GLIB2::GIO MODULE_NAME core QMAKE_LIB gio) -qt_find_package(WrapResolv PROVIDED_TARGETS WrapResolv::WrapResolv MODULE_NAME network QMAKE_LIB libresolv) +qt_find_package(WrapBrotli MODULE + PROVIDED_TARGETS WrapBrotli::WrapBrotliDec MODULE_NAME network QMAKE_LIB brotli) +qt_find_package(Libproxy MODULE + PROVIDED_TARGETS PkgConfig::Libproxy MODULE_NAME network QMAKE_LIB libproxy) +qt_find_package(GSSAPI MODULE PROVIDED_TARGETS GSSAPI::GSSAPI MODULE_NAME network QMAKE_LIB gssapi) +qt_find_package(GLIB2 MODULE + OPTIONAL_COMPONENTS GOBJECT PROVIDED_TARGETS GLIB2::GOBJECT MODULE_NAME core QMAKE_LIB gobject) +qt_find_package(GLIB2 MODULE + OPTIONAL_COMPONENTS GIO PROVIDED_TARGETS GLIB2::GIO MODULE_NAME core QMAKE_LIB gio) +qt_find_package(WrapResolv MODULE + PROVIDED_TARGETS WrapResolv::WrapResolv MODULE_NAME network QMAKE_LIB libresolv) #### Tests diff --git a/src/platformsupport/input/CMakeLists.txt b/src/platformsupport/input/CMakeLists.txt index 0c58bb5c308..15e71300e30 100644 --- a/src/platformsupport/input/CMakeLists.txt +++ b/src/platformsupport/input/CMakeLists.txt @@ -1,10 +1,10 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(Libinput) -qt_find_package(XKB) -qt_find_package(Tslib) -qt_find_package(Mtdev) +qt_find_package(Libinput MODULE) +qt_find_package(XKB MODULE) +qt_find_package(Tslib MODULE) +qt_find_package(Mtdev MODULE) ##################################################################### ## InputSupportPrivate Module: diff --git a/src/platformsupport/kmsconvenience/CMakeLists.txt b/src/platformsupport/kmsconvenience/CMakeLists.txt index 9cd4eb1d33f..fb0957c68c0 100644 --- a/src/platformsupport/kmsconvenience/CMakeLists.txt +++ b/src/platformsupport/kmsconvenience/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(Libdrm) +qt_find_package(Libdrm MODULE) ##################################################################### ## KmsSupportPrivate Module: diff --git a/src/plugins/generic/tslib/CMakeLists.txt b/src/plugins/generic/tslib/CMakeLists.txt index 85121337993..94fefbbacdb 100644 --- a/src/plugins/generic/tslib/CMakeLists.txt +++ b/src/plugins/generic/tslib/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(Tslib) +qt_find_package(Tslib MODULE) ##################################################################### ## QTsLibPlugin Plugin: diff --git a/src/plugins/imageformats/jpeg/CMakeLists.txt b/src/plugins/imageformats/jpeg/CMakeLists.txt index 6b077a76476..27d4255de3c 100644 --- a/src/plugins/imageformats/jpeg/CMakeLists.txt +++ b/src/plugins/imageformats/jpeg/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(WrapJpeg PROVIDED_TARGETS WrapJpeg::WrapJpeg) +qt_find_package(WrapJpeg MODULE PROVIDED_TARGETS WrapJpeg::WrapJpeg) ##################################################################### ## QJpegPlugin Plugin: diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 9325afed110..a78408c2a7f 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -910,8 +910,7 @@ static int getExifOrientation(QByteArray &exifData) } // read offset to next IFD - stream >> offset; - if (stream.status() != QDataStream::Ok) + if (!(stream >> offset)) return -1; if (offset == 0) // this is the last IFD return 0; // No Exif orientation was found diff --git a/src/plugins/platforminputcontexts/compose/CMakeLists.txt b/src/plugins/platforminputcontexts/compose/CMakeLists.txt index 9e71a7a07c5..9b7cf1434f9 100644 --- a/src/plugins/platforminputcontexts/compose/CMakeLists.txt +++ b/src/plugins/platforminputcontexts/compose/CMakeLists.txt @@ -5,7 +5,7 @@ ## QComposePlatformInputContextPlugin Plugin: ##################################################################### -qt_find_package(XKB) +qt_find_package(XKB MODULE) pkg_get_variable(PKG_X11_PREFIX x11 prefix) qt_internal_add_plugin(QComposePlatformInputContextPlugin diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt index b42f84a6107..0160e12c26c 100644 --- a/src/plugins/platforms/android/CMakeLists.txt +++ b/src/plugins/platforms/android/CMakeLists.txt @@ -4,7 +4,7 @@ ##################################################################### ## QAndroidIntegrationPlugin Plugin: ##################################################################### -qt_find_package(EGL) +qt_find_package(EGL MODULE) qt_internal_add_plugin(QAndroidIntegrationPlugin OUTPUT_NAME qtforandroid @@ -25,6 +25,7 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h qandroidplatformfontdatabase.cpp qandroidplatformfontdatabase.h qandroidplatformforeignwindow.cpp qandroidplatformforeignwindow.h + qandroidplatformfileiconengine.cpp qandroidplatformfileiconengine.h qandroidplatformiconengine.cpp qandroidplatformiconengine.h qandroidplatformintegration.cpp qandroidplatformintegration.h qandroidplatformmenu.cpp qandroidplatformmenu.h diff --git a/src/plugins/platforms/android/qandroidplatformfileiconengine.cpp b/src/plugins/platforms/android/qandroidplatformfileiconengine.cpp new file mode 100644 index 00000000000..1bc285cbb62 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformfileiconengine.cpp @@ -0,0 +1,113 @@ +// 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 "qandroidplatformfileiconengine.h" + +#ifndef QT_NO_ICON + +#include "androidjnimain.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qjniobject.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qscopeguard.h> + +#include <android/bitmap.h> + +QT_BEGIN_NAMESPACE + +Q_STATIC_LOGGING_CATEGORY(lcAndroidFileIconEngine, "qt.qpa.theme.fileiconengine") + +using namespace Qt::StringLiterals; +using namespace QtJniTypes; + +Q_DECLARE_JNI_CLASS(CharSequence, "java/lang/CharSequence") +Q_DECLARE_JNI_CLASS(Icon, "android/graphics/drawable/Icon") +Q_DECLARE_JNI_CLASS(Bitmap, "android/graphics/Bitmap") +Q_DECLARE_JNI_CLASS(Canvas, "android/graphics/Canvas") +Q_DECLARE_JNI_CLASS(MimeTypeMap, "android/webkit/MimeTypeMap") +Q_DECLARE_JNI_CLASS(MimeTypeInfo, "android/content/ContentResolver$MimeTypeInfo") + +QAndroidPlatformFileIconEngine::QAndroidPlatformFileIconEngine(const QFileInfo &fileInfo, + QPlatformTheme::IconOptions opts) + : QAbstractFileIconEngine(fileInfo, opts) +{ + // MimeTypeInfo requires API level 29 + static bool hasMimeTypeInfo = []{ + if (!MimeTypeInfo::isClassAvailable()) { + qCWarning(lcAndroidFileIconEngine) << "MimeTypeInfo not available, requires API level 29"; + return false; + } + return true; + }(); + if (!hasMimeTypeInfo) + return; + + const auto context = QtAndroidPrivate::context(); + if (!context.isValid()) { + qCWarning(lcAndroidFileIconEngine) << "Couldn't get context"; + return; + } + const auto contentResolver = context.callMethod<ContentResolver>("getContentResolver"); + if (!contentResolver.isValid()) { + qCWarning(lcAndroidFileIconEngine) << "Couldn't get content resolver"; + return; + } + + const auto mimeTypeMap = MimeTypeMap::callStaticMethod<MimeTypeMap>("getSingleton"); + const QString mimeType = mimeTypeMap.callMethod<QString>("getMimeTypeFromExtension", + fileInfo.suffix()); + + const auto mimeTypeInfo = contentResolver.callMethod<MimeTypeInfo>("getTypeInfo", mimeType); + qCDebug(lcAndroidFileIconEngine) << "MimeTypeInfo" << mimeType + << mimeTypeInfo.callMethod<CharSequence>("getLabel").toString() + << mimeTypeInfo.callMethod<CharSequence>("getContentDescription").toString(); + const auto icon = mimeTypeInfo.callMethod<Icon>("getIcon"); + if (!icon.isValid()) { + qCDebug(lcAndroidFileIconEngine) << "No valid icon in type info"; + return; + } + m_drawable = icon.callMethod<Drawable>("loadDrawable", context); + if (!m_drawable || !m_drawable->isValid()) + qCWarning(lcAndroidFileIconEngine) << "Failed to load drawable for icon"; +} + +QAndroidPlatformFileIconEngine::~QAndroidPlatformFileIconEngine() = default; + +bool QAndroidPlatformFileIconEngine::isNull() +{ + return !m_drawable || !m_drawable->isValid(); +} + +QPixmap QAndroidPlatformFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon::State) +{ + if (m_pixmap.size() == size) + return m_pixmap; + if (isNull()) + return QPixmap(); + + JNIEnv *jniEnv = QJniEnvironment::getJniEnv(); + // createBitmap doesn't support ARGB32, but it doesn't matter here + Bitmap bitmap = QtAndroid::createBitmap(size.width(), size.height(), + QImage::Format_RGBA8888, jniEnv); + Canvas canvas(bitmap); + m_drawable->callMethod("setBounds", 0, 0, size.width(), size.height()); + m_drawable->callMethod("draw", canvas); + + void *pixels = nullptr; + if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_lockPixels(jniEnv, bitmap.object(), &pixels)) { + qCWarning(lcAndroidFileIconEngine) << "Failed to lock bitmap pixels"; + return QPixmap(); + } + + // this makes a deep copy of the pixel data + m_pixmap = QPixmap::fromImage(QImage(reinterpret_cast<const uchar *>(pixels), + size.width(), size.height(), QImage::Format_RGBA8888)); + if (ANDROID_BITMAP_RESULT_SUCCESS != AndroidBitmap_unlockPixels(jniEnv, bitmap.object())) + qCWarning(lcAndroidFileIconEngine) << "Failed to unlock bitmap pixels"; + return m_pixmap; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ICON diff --git a/src/plugins/platforms/android/qandroidplatformfileiconengine.h b/src/plugins/platforms/android/qandroidplatformfileiconengine.h new file mode 100644 index 00000000000..bd9be21e252 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformfileiconengine.h @@ -0,0 +1,42 @@ +// 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 + +#ifndef QANDROIDPLATFORMFILEICONENGINE_H +#define QANDROIDPLATFORMFILEICONENGINE_H + +#include <QtCore/qjnitypes.h> + +#include <QtGui/qpixmap.h> +#include <QtGui/private/qabstractfileiconengine_p.h> +#include "qandroidplatformiconengine.h" + +#ifndef QT_NO_ICON + +QT_BEGIN_NAMESPACE + +Q_DECLARE_JNI_CLASS(Drawable, "android/graphics/drawable/Drawable") + +class QAndroidPlatformFileIconEngine : public QAbstractFileIconEngine +{ +public: + explicit QAndroidPlatformFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts); + ~QAndroidPlatformFileIconEngine(); + + QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) override + { return {{16, 16}, {24, 24}, {48, 48}, {128, 128}}; } + + bool isNull() override; + +protected: + QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override; + +private: + std::optional<QtJniTypes::Drawable> m_drawable; + QPixmap m_pixmap; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ICON + +#endif // QANDROIDPLATFORMFILEICONENGINE_H diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 58543cecb38..7a432d10a5b 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -4,6 +4,7 @@ #include "androidjnimain.h" #include "androidjnimenu.h" #include "qandroidplatformtheme.h" +#include "qandroidplatformfileiconengine.h" #include "qandroidplatformiconengine.h" #include "qandroidplatformmenubar.h" #include "qandroidplatformmenu.h" @@ -509,6 +510,23 @@ QIconEngine *QAndroidPlatformTheme::createIconEngine(const QString &iconName) co return new QAndroidPlatformIconEngine(iconName); } +QIcon QAndroidPlatformTheme::fileIcon(const QFileInfo &fileInfo, + QPlatformTheme::IconOptions options) const +{ +#ifndef QT_NO_ICON + std::unique_ptr<QIconEngine> iconEngine(new QAndroidPlatformFileIconEngine(fileInfo, options)); + if (iconEngine->isNull()) { + // If we didn't get an icon for the file type, return a generic file + // icon. Assuming the Material Symbols font, this is the "draft" icon + // with code point e66d. + iconEngine.reset(new QAndroidPlatformIconEngine(u"\ue66d"_s)); + } + return QIcon(iconEngine.release()); +#else + return {}; +#endif +} + QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const { switch (hint) { diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h index 1b4ab5664de..57a7d4db4b4 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.h +++ b/src/plugins/platforms/android/qandroidplatformtheme.h @@ -52,6 +52,7 @@ public: static QAndroidPlatformTheme *instance( QAndroidPlatformNativeInterface * androidPlatformNativeInterface = nullptr); + QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const override; private: QAndroidPlatformTheme(QAndroidPlatformNativeInterface * androidPlatformNativeInterface); diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index e3ff518b4e1..e3dd05a0976 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -21,6 +21,7 @@ #include <QtGui/qpainter.h> #include <QtGui/qtextformat.h> #include <QtGui/private/qcoretextfontdatabase_p.h> +#include <QtGui/private/qapplefileiconengine_p.h> #include <QtGui/private/qappleiconengine_p.h> #include <QtGui/private/qfontengine_coretext_p.h> #include <QtGui/private/qabstractfileiconengine_p.h> @@ -406,31 +407,9 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const return QPlatformTheme::standardPixmap(sp, size); } -class QCocoaFileIconEngine : public QAbstractFileIconEngine -{ -public: - explicit QCocoaFileIconEngine(const QFileInfo &info, - QPlatformTheme::IconOptions opts) : - QAbstractFileIconEngine(info, opts) {} - - QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) override - { return QAppleIconEngine::availableIconSizes(); } - -protected: - QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override - { - QMacAutoReleasePool pool; - - NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:fileInfo().canonicalFilePath().toNSString()]; - if (!iconImage) - return QPixmap(); - return qt_mac_toQPixmap(iconImage, size); - } -}; - QIcon QCocoaTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const { - return QIcon(new QCocoaFileIconEngine(fileInfo, iconOptions)); + return QIcon(new QAppleFileIconEngine(fileInfo, iconOptions)); } QIconEngine *QCocoaTheme::createIconEngine(const QString &iconName) const diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index c7a5d55344a..f378c8aba03 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -19,6 +19,7 @@ #include <MoltenVK/mvk_vulkan.h> #endif +#include <QtCore/qhash.h> #include <QtCore/private/qflatmap_p.h> Q_FORWARD_DECLARE_OBJC_CLASS(NSWindow); diff --git a/src/plugins/platforms/directfb/CMakeLists.txt b/src/plugins/platforms/directfb/CMakeLists.txt index 7222168a376..60c68a8ef74 100644 --- a/src/plugins/platforms/directfb/CMakeLists.txt +++ b/src/plugins/platforms/directfb/CMakeLists.txt @@ -1,8 +1,8 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(DirectFB) -qt_find_package(EGL) +qt_find_package(DirectFB MODULE) +qt_find_package(EGL MODULE) ##################################################################### ## QDirectFbIntegrationPlugin Plugin: diff --git a/src/plugins/platforms/eglfs/CMakeLists.txt b/src/plugins/platforms/eglfs/CMakeLists.txt index 7c53dae667c..e0ed34e377b 100644 --- a/src/plugins/platforms/eglfs/CMakeLists.txt +++ b/src/plugins/platforms/eglfs/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(EGL) +qt_find_package(EGL MODULE) if(QT_FEATURE_eglfs_gbm) set(_device_integration "eglfs_kms") diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h index 70e2c37ff1f..241156e0b6c 100644 --- a/src/plugins/platforms/ios/qiostheme.h +++ b/src/plugins/platforms/ios/qiostheme.h @@ -36,6 +36,7 @@ public: const QFont *font(Font type = SystemFont) const override; QIconEngine *createIconEngine(const QString &iconName) const override; + QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = {}) const override; static const char *name; diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm index afee9824d6d..a265ec0a824 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -11,6 +11,7 @@ #include <QtGui/private/qcoregraphics_p.h> #include <QtGui/private/qcoretextfontdatabase_p.h> +#include <QtGui/private/qapplefileiconengine_p.h> #include <QtGui/private/qappleiconengine_p.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -220,4 +221,10 @@ QIconEngine *QIOSTheme::createIconEngine(const QString &iconName) const return new QAppleIconEngine(iconName); } +QIcon QIOSTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const +{ + return QIcon(new QAppleFileIconEngine(fileInfo, iconOptions)); +} + + QT_END_NAMESPACE diff --git a/src/plugins/platforms/minimal/CMakeLists.txt b/src/plugins/platforms/minimal/CMakeLists.txt index 18d8828134a..06bf34129d0 100644 --- a/src/plugins/platforms/minimal/CMakeLists.txt +++ b/src/plugins/platforms/minimal/CMakeLists.txt @@ -5,7 +5,7 @@ ## QMinimalIntegrationPlugin Plugin: ##################################################################### -qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype) +qt_find_package(WrapFreetype MODULE PROVIDED_TARGETS WrapFreetype::WrapFreetype) qt_internal_add_plugin(QMinimalIntegrationPlugin OUTPUT_NAME qminimal diff --git a/src/plugins/platforms/minimalegl/CMakeLists.txt b/src/plugins/platforms/minimalegl/CMakeLists.txt index b93f325b8fc..cb4f2cabd1d 100644 --- a/src/plugins/platforms/minimalegl/CMakeLists.txt +++ b/src/plugins/platforms/minimalegl/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(EGL) +qt_find_package(EGL MODULE) ##################################################################### ## QMinimalEglIntegrationPlugin Plugin: diff --git a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt index 406487f1e99..dfbca92ccc0 100644 --- a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt +++ b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype) +qt_find_package(WrapFreetype MODULE PROVIDED_TARGETS WrapFreetype::WrapFreetype) qt_internal_add_plugin(QVkKhrDisplayIntegrationPlugin OUTPUT_NAME qvkkhrdisplay diff --git a/src/plugins/platforms/wayland/plugins/hardwareintegration/wayland-egl/CMakeLists.txt b/src/plugins/platforms/wayland/plugins/hardwareintegration/wayland-egl/CMakeLists.txt index 68388d570c4..ff93adfa52b 100644 --- a/src/plugins/platforms/wayland/plugins/hardwareintegration/wayland-egl/CMakeLists.txt +++ b/src/plugins/platforms/wayland/plugins/hardwareintegration/wayland-egl/CMakeLists.txt @@ -6,7 +6,7 @@ ##################################################################### ## QWaylandEglClientBufferPlugin Plugin: ##################################################################### -qt_find_package(EGL) # special case +qt_find_package(EGL MODULE) qt_internal_add_plugin(QWaylandEglClientBufferPlugin OUTPUT_NAME qt-plugin-wayland-egl diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index 170e80f806c..0a67169dd28 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -371,20 +371,6 @@ QWaylandInputDevice::~QWaylandInputDevice() void QWaylandInputDevice::seat_capabilities(uint32_t caps) { mCaps = caps; - maybeRegisterInputDevices(); -} - -void QWaylandInputDevice::seat_name(const QString &name) -{ - mSeatName = name; - mSeatNameKnown = true; - maybeRegisterInputDevices(); -} - -void QWaylandInputDevice::maybeRegisterInputDevices() -{ - if (!mSeatNameKnown) - return; // too early if (mCaps & WL_SEAT_CAPABILITY_KEYBOARD && !mKeyboard) { mKeyboard.reset(createKeyboard(this)); @@ -430,6 +416,11 @@ void QWaylandInputDevice::maybeRegisterInputDevices() } } +void QWaylandInputDevice::seat_name(const QString &name) +{ + mSeatName = name; +} + QWaylandInputDevice::Keyboard *QWaylandInputDevice::createKeyboard(QWaylandInputDevice *device) { return new Keyboard(device); diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h index bcaf025840d..c3c4c05d4f8 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h +++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h @@ -158,7 +158,6 @@ protected: uint32_t mId = -1; uint32_t mCaps = 0; QString mSeatName; - bool mSeatNameKnown = false; #if QT_CONFIG(cursor) struct CursorState { @@ -200,7 +199,6 @@ protected: void seat_capabilities(uint32_t caps) override; void seat_name(const QString &name) override; - void maybeRegisterInputDevices(); void handleTouchPoint(int id, QEventPoint::State state, const QPointF &surfacePosition = QPoint()); QPointingDevice *mTouchDevice = nullptr; diff --git a/src/plugins/platforms/wayland/qwaylandtextinputv3.cpp b/src/plugins/platforms/wayland/qwaylandtextinputv3.cpp index fbb40c2e216..42ee5cde2ff 100644 --- a/src/plugins/platforms/wayland/qwaylandtextinputv3.cpp +++ b/src/plugins/platforms/wayland/qwaylandtextinputv3.cpp @@ -309,7 +309,8 @@ void QWaylandTextInputv3::updateState(Qt::InputMethodQueries queries, uint32_t f // The worst case will be supposed here. const int MAX_MESSAGE_SIZE = 4000; - const int textSize = text.toUtf8().size(); + const QByteArray utf8 = text.toUtf8(); + const int textSize = utf8.size(); if (textSize > MAX_MESSAGE_SIZE) { qCDebug(qLcQpaWaylandTextInput) << "SurroundText size is over " << MAX_MESSAGE_SIZE @@ -317,18 +318,19 @@ void QWaylandTextInputv3::updateState(Qt::InputMethodQueries queries, uint32_t f const int selectionStart = qMin(cursor, anchor); const int selectionEnd = qMax(cursor, anchor); const int selectionLength = selectionEnd - selectionStart; - const int selectionSize = QStringView{text}.sliced(selectionStart, selectionLength).toUtf8().size(); + QByteArray selection = QStringView{text}.sliced(selectionStart, selectionLength).toUtf8(); + const int selectionSize = selection.size(); // If selection is bigger than 4000 byte, it is fixed to 4000 byte. // anchor will be moved in the 4000 byte boundary. if (selectionSize > MAX_MESSAGE_SIZE) { if (anchor > cursor) { cursor = 0; anchor = MAX_MESSAGE_SIZE; - text = text.sliced(selectionStart, selectionLength); + text = QString::fromUtf8(QByteArrayView{selection}.sliced(0, MAX_MESSAGE_SIZE)); } else { anchor = 0; cursor = MAX_MESSAGE_SIZE; - text = text.sliced(selectionEnd - selectionLength, selectionLength); + text = QString::fromUtf8(QByteArrayView{selection}.sliced(selectionSize - MAX_MESSAGE_SIZE, MAX_MESSAGE_SIZE)); } } else { // This is not optimal in some cases. @@ -340,10 +342,10 @@ void QWaylandTextInputv3::updateState(Qt::InputMethodQueries queries, uint32_t f cursor = QWaylandInputMethodEventBuilder::indexToWayland(text, cursor); anchor = QWaylandInputMethodEventBuilder::indexToWayland(text, anchor); if (selEndSize < MAX_MESSAGE_SIZE) { - text = QString::fromUtf8(QByteArrayView{text.toUtf8()}.first(MAX_MESSAGE_SIZE)); + text = QString::fromUtf8(QByteArrayView{utf8}.first(MAX_MESSAGE_SIZE)); } else { const int startOffset = selEndSize - MAX_MESSAGE_SIZE; - text = QString::fromUtf8(QByteArrayView{text.toUtf8()}.sliced(startOffset, MAX_MESSAGE_SIZE)); + text = QString::fromUtf8(QByteArrayView{utf8}.sliced(startOffset, MAX_MESSAGE_SIZE)); cursor -= startOffset; anchor -= startOffset; } diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index aaf2cc21b4b..73d90b6c321 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -53,6 +53,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display) , mDisplay(display) , mSurfaceLock(QReadWriteLock::Recursive) , mShellIntegration(display->shellIntegration()) + , mSurfaceFormat(window->requestedFormat()) { { bool ok; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 87e77a551cd..c484d97479a 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1153,13 +1153,9 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::MoveEvent: platformWindow->handleMoved(); return true; - case QtWindows::ResizeEvent: { - QWindow *window = platformWindow->window(); + case QtWindows::ResizeEvent: platformWindow->handleResized(static_cast<int>(wParam), lParam); - if (window->flags().testFlags(Qt::ExpandedClientAreaHint)) - platformWindow->updateCustomTitlebar(); return true; - } case QtWindows::QuerySizeHints: platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam)); return true;// maybe available on some SDKs revisit WM_NCCALCSIZE @@ -1175,12 +1171,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return platformWindow->handleNonClientActivate(result); case QtWindows::GeometryChangingEvent: return platformWindow->handleGeometryChanging(&msg); - case QtWindows::ExposeEvent: { - QWindow *window = platformWindow->window(); - if (window->flags().testFlags(Qt::ExpandedClientAreaHint)) - platformWindow->updateCustomTitlebar(); + case QtWindows::ExposeEvent: return platformWindow->handleWmPaint(hwnd, message, wParam, lParam, result); - } case QtWindows::NonClientMouseEvent: if (!platformWindow->frameStrutEventsEnabled()) break; diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index ddc1114485e..57b833b299b 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -762,6 +762,28 @@ static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen) w->setGeometry(geometry); } +void QWindowsScreenManager::addScreen(const QWindowsScreenData &screenData) +{ + auto *newScreen = new QWindowsScreen(screenData); + m_screens.push_back(newScreen); + QWindowSystemInterface::handleScreenAdded(newScreen, + screenData.flags & QWindowsScreenData::PrimaryScreen); + qCDebug(lcQpaScreen) << "New Monitor: " << screenData; + + // When a new screen is attached Window might move windows to the new screen + // automatically, in which case they will get a WM_DPICHANGED event. But at + // that point we have not received WM_DISPLAYCHANGE yet, so we fail to reflect + // the new screen's DPI. To account for this we explicitly check for screen + // change here, now that we are processing the WM_DISPLAYCHANGE. + const auto allWindows = QGuiApplication::allWindows(); + for (QWindow *w : allWindows) { + if (w->isVisible() && w->handle() && w->type() != Qt::Desktop) { + if (QWindowsWindow *window = QWindowsWindow::windowsWindowOf(w)) + window->checkForScreenChanged(QWindowsWindow::ScreenChangeMode::FromScreenAdded); + } + } +} + void QWindowsScreenManager::removeScreen(int index) { qCDebug(lcQpaScreen) << "Removing Monitor:" << m_screens.at(index)->data(); @@ -784,7 +806,7 @@ void QWindowsScreenManager::removeScreen(int index) && (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) { moveToVirtualScreen(w, primaryScreen); } else { - QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); + QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, primaryScreen); } ++movedWindowCount; } @@ -813,11 +835,7 @@ bool QWindowsScreenManager::handleScreenChanges() if (existingIndex == 0) primaryScreenChanged = true; } else { - auto *newScreen = new QWindowsScreen(newData); - m_screens.push_back(newScreen); - QWindowSystemInterface::handleScreenAdded(newScreen, - newData.flags & QWindowsScreenData::PrimaryScreen); - qCDebug(lcQpaScreen) << "New Monitor: " << newData; + addScreen(newData); } // exists } // for new screens. // Remove deleted ones but keep main monitors if we get only the diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index ea6a29efe38..8d555998388 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -119,6 +119,7 @@ public: static bool isSingleScreen(); private: + void addScreen(const QWindowsScreenData &screenData); void removeScreen(int index); HWND m_displayChangeObserver = nullptr; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 8567e42129c..81a3f1d37b7 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -284,6 +284,40 @@ static inline RECT RECTfromQRect(const QRect &rect) return result; } +static LRESULT WINAPI WndProcTitleBar(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND parentHwnd = reinterpret_cast<HWND>(GetWindowLongPtr(hwnd, GWL_HWNDPARENT)); + QWindowsWindow* platformWindow = QWindowsContext::instance()->findPlatformWindow(parentHwnd); + + switch (message) { + case WM_SHOWWINDOW: + ShowWindow(hwnd,SW_HIDE); + if ((BOOL)wParam == TRUE) + platformWindow->transitionAnimatedCustomTitleBar(); + return 0; + case WM_SIZE: { + if (platformWindow) + platformWindow->updateCustomTitlebar(); + break; + } + case WM_NCHITTEST: + return HTTRANSPARENT; + case WM_TIMER: + ShowWindow(hwnd, SW_SHOWNOACTIVATE); + platformWindow->updateCustomTitlebar(); + break; + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + return 0; + } + } + return DefWindowProc(hwnd, message, wParam, lParam); +} + + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const RECT &r) { @@ -883,7 +917,7 @@ QWindowsWindowData const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr)); const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); - const QString windowTitlebarName = QWindowsContext::instance()->registerWindowClass(QStringLiteral("_q_titlebar"), DefWindowProc, CS_VREDRAW|CS_HREDRAW, nullptr, false); + const QString windowTitlebarName = QWindowsContext::instance()->registerWindowClass(QStringLiteral("_q_titlebar"), WndProcTitleBar, CS_VREDRAW|CS_HREDRAW, nullptr, false); const QScreen *screen{}; const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, @@ -936,16 +970,14 @@ QWindowsWindowData context->frameWidth, context->frameHeight, parentHandle, nullptr, appinst, nullptr); - const UINT dpi = ::GetDpiForWindow(result.hwnd); - const int titleBarHeight = getTitleBarHeight_sys(dpi); - result.hwndTitlebar = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE, - classTitleBarNameUtf16, classTitleBarNameUtf16, - 0, 0, 0, - context->frameWidth, titleBarHeight, - nullptr, nullptr, appinst, nullptr); if (w->flags().testFlags(Qt::ExpandedClientAreaHint)) { - SetParent(result.hwndTitlebar, result.hwnd); - ShowWindow(result.hwndTitlebar, SW_SHOW); + const UINT dpi = ::GetDpiForWindow(result.hwnd); + const int titleBarHeight = getTitleBarHeight_sys(dpi); + result.hwndTitlebar = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, + classTitleBarNameUtf16, classTitleBarNameUtf16, + WS_POPUP, 0, 0, + context->frameWidth, titleBarHeight, + result.hwnd, nullptr, appinst, nullptr); } qCDebug(lcQpaWindow).nospace() @@ -1024,9 +1056,6 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang if (flags & Qt::ExpandedClientAreaHint) { // Gives us the rounded corners looks and the frame shadow MARGINS margins = { -1, -1, -1, -1 }; DwmExtendFrameIntoClientArea(hwnd, &margins); - } else { - MARGINS margins = { 0, 0, 0, 0 }; - DwmExtendFrameIntoClientArea(hwnd, &margins); } } else { // child. SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags); @@ -1162,22 +1191,19 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, bool QWindowsGeometryHint::handleCalculateSize(const QWindow *window, const QMargins &customMargins, const MSG &msg, LRESULT *result) { - const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window); - // In case the platformwindow was not yet created, use the initial windowflags provided by the user. - const bool clientAreaExpanded = platformWindow != nullptr ? platformWindow->isClientAreaExpanded() : window->flags() & Qt::ExpandedClientAreaHint; // Return 0 to remove the window's border + const bool clientAreaExpanded = window->flags() & Qt::ExpandedClientAreaHint; if (msg.wParam && clientAreaExpanded) { // Prevent content from being cutoff by border for maximized, but not fullscreened windows. - //if (IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen) { - const bool maximized = IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen; - auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); - RECT *clientArea = &ncp->rgrc[0]; - const int border = getResizeBorderThickness(96); - if (maximized) + if (IsZoomed(msg.hwnd) && window->visibility() != QWindow::FullScreen) { + auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); + RECT *clientArea = &ncp->rgrc[0]; + const int border = getResizeBorderThickness(QWindowsWindow::windowsWindowOf(window)->savedDpi()); clientArea->top += border; - clientArea->bottom -= border; - clientArea->left += border; - clientArea->right -= border; + clientArea->bottom -= border; + clientArea->left += border; + clientArea->right -= border; + } *result = 0; return true; } @@ -1821,6 +1847,21 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) return w; } +// Checks whether the Window is tiled with Aero snap +bool QWindowsWindow::isWindowArranged(HWND hwnd) +{ + typedef BOOL(WINAPI* PIsWindowArranged)(HWND); + static PIsWindowArranged pIsWindowArranged = nullptr; + static bool resolved = false; + if (!resolved) { + resolved = true; + pIsWindowArranged = (PIsWindowArranged)QSystemLibrary::resolve(QLatin1String("user32.dll"), "IsWindowArranged"); + } + if (pIsWindowArranged == nullptr) + return false; + return pIsWindowArranged(hwnd); +} + QWindowsWindowData QWindowsWindowData::create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -1862,6 +1903,13 @@ void QWindowsWindow::setVisible(bool visible) fireExpose(QRegion()); } } + if (m_data.hwndTitlebar) { + if (visible) { + SetWindowPos(m_data.hwndTitlebar, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } else { + ShowWindow(m_data.hwndTitlebar, SW_HIDE); + } + } } bool QWindowsWindow::isVisible() const @@ -2002,6 +2050,10 @@ void QWindowsWindow::show_sys() const setFlag(WithinMaximize); // QTBUG-8361 ShowWindow(m_data.hwnd, sm); + if (m_data.flags.testFlag(Qt::ExpandedClientAreaHint)) { + ShowWindow(m_data.hwndTitlebar, sm); + SetActiveWindow(m_data.hwnd); + } clearFlag(WithinMaximize); @@ -2193,7 +2245,7 @@ QRect QWindowsWindow::normalGeometry() const QMargins QWindowsWindow::safeAreaMargins() const { if (m_data.flags.testFlags(Qt::ExpandedClientAreaHint)) { - const int titleBarHeight = getTitleBarHeight_sys(96); + const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); return QMargins(0, titleBarHeight, 0, 0); } @@ -2405,9 +2457,15 @@ void QWindowsWindow::handleGeometryChange() clearFlag(SynchronousGeometryChangeEvent); qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry; - if (m_data.flags & Qt::ExpandedClientAreaHint) { + if (m_data.hwndTitlebar) { + bool arranged = QWindowsWindow::isWindowArranged(m_data.hwnd); + if (arranged || (m_windowWasArranged && !arranged)) + transitionAnimatedCustomTitleBar(); + const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); - MoveWindow(m_data.hwndTitlebar, 0, 0, m_data.geometry.width(), titleBarHeight, true); + MoveWindow(m_data.hwndTitlebar, m_data.geometry.x(), m_data.geometry.y(), + m_data.geometry.width(), titleBarHeight, true); + m_windowWasArranged = arranged; } } @@ -2569,16 +2627,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, creationData.applyWindowFlags(m_data.hwnd); creationData.initialize(window(), m_data.hwnd, true, m_opacity); - if (creationData.flags.testFlag(Qt::ExpandedClientAreaHint)) { - SetParent(m_data.hwndTitlebar, m_data.hwnd); - ShowWindow(m_data.hwndTitlebar, SW_SHOW); - } else { - if (IsWindowVisible(m_data.hwndTitlebar)) { - SetParent(m_data.hwndTitlebar, HWND_MESSAGE); - ShowWindow(m_data.hwndTitlebar, SW_HIDE); - } - } - QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; @@ -2597,7 +2645,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) handleHidden(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now. } else { - updateCustomTitlebar(); + transitionAnimatedCustomTitleBar(); if (state & Qt::WindowMaximized) { WINDOWPLACEMENT windowPlacement{}; windowPlacement.length = sizeof(WINDOWPLACEMENT); @@ -2695,6 +2743,20 @@ void QWindowsWindow::correctWindowPlacement(WINDOWPLACEMENT &windowPlacement) } } +void QWindowsWindow::transitionAnimatedCustomTitleBar() +{ + if (!m_data.hwndTitlebar) + return; + const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Control Panel\Desktop\WindowMetrics)"); + if (registry.isValid() && registry.value(LR"(MinAnimate)") == 1) { + ShowWindow(m_data.hwndTitlebar, SW_HIDE); + SetTimer(m_data.hwndTitlebar, 1, 200, nullptr); + } else { + ShowWindow(m_data.hwndTitlebar, SW_SHOWNOACTIVATE); + updateCustomTitlebar(); + } +} + void QWindowsWindow::updateRestoreGeometry() { m_data.restoreGeometry = normalFrameGeometry(m_data.hwnd); @@ -3016,8 +3078,7 @@ void QWindowsWindow::calculateFullFrameMargins() const auto systemMargins = testFlag(DisableNonClientScaling) ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd) : frameMargins_sys(); - const int extendedClientAreaBorder = window()->flags().testFlag(Qt::ExpandedClientAreaHint) ? qRound(QHighDpiScaling::factor(window())) * 2 : 0; - const QMargins actualMargins = systemMargins + customMargins() - extendedClientAreaBorder; + const QMargins actualMargins = systemMargins + customMargins(); const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); const bool typicalFrame = (actualMargins.left() == actualMargins.right()) @@ -3456,6 +3517,19 @@ bool QWindowsWindow::handleNonClientActivate(LRESULT *result) const return false; } +static void _q_drawCustomTitleBarButton(QPainter& p, const QRectF& r) +{ + QPainterPath path(QPointF(r.x(), r.y())); + QRectF rightCorner(r.x() + r.width() - 2.0, r.y() + 4.0, 2, 2); + QRectF leftCorner(r.x(), r.y() + 4, 2, 2); + path.lineTo(r.x() + r.width() - 5.0f, r.y()); + path.arcTo(rightCorner, 90, -90); + path.lineTo(r.x() + r.width(), r.y() + r.height() - 1); + path.lineTo(r.x(), r.y() + r.height() - 1); + path.closeSubpath(); + p.drawPath(path); +} + void QWindowsWindow::updateCustomTitlebar() { HWND hwnd = m_data.hwndTitlebar; @@ -3471,7 +3545,7 @@ void QWindowsWindow::updateCustomTitlebar() POINT localPos; GetCursorPos(&localPos); - MapWindowPoints(HWND_DESKTOP, m_data.hwnd, &localPos, 1); + MapWindowPoints(HWND_DESKTOP, hwnd, &localPos, 1); const bool isDarkmode = QWindowsIntegration::instance()->darkModeHandling().testFlags(QWindowsApplication::DarkModeWindowFrames) && qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark; @@ -3493,9 +3567,25 @@ void QWindowsWindow::updateCustomTitlebar() p.setPen(Qt::NoPen); if (!wnd->flags().testFlags(Qt::NoTitleBarBackgroundHint)) { QRect titleRect; + titleRect.setX(2); titleRect.setWidth(windowWidth); titleRect.setHeight(titleBarHeight); - p.drawRect(titleRect); + + if (isWindows11orAbove) { + QPainterPath path(QPointF(titleRect.x() + 4.0f, titleRect.y())); + QRectF rightCorner(titleRect.x() + titleRect.width() - 4.0, titleRect.y() + 4.0, 2, 2); + QRectF leftCorner(titleRect.x(), titleRect.y() + 4, 2, 2); + path.lineTo(titleRect.x() + titleRect.width() - 7.0f, titleRect.y()); + path.arcTo(rightCorner, 90, -90); + path.lineTo(titleRect.x() + titleRect.width() - 2.0, titleRect.y() + titleRect.height() - 1); + path.lineTo(titleRect.x(), titleRect.y() + titleRect.height() - 1); + path.lineTo(titleRect.x(), titleRect.y() + 4.0f); + path.arcTo(leftCorner, -90, -90); + path.closeSubpath(); + p.drawPath(path); + } else { + p.drawRect(titleRect); + } } if (wnd->flags().testFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint) || !wnd->flags().testFlag(Qt::CustomizeWindowHint)) { @@ -3541,12 +3631,15 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth); + rect.setWidth(titleButtonWidth - 1); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - p.drawRect(rect); + if (isWindows11orAbove && buttons == 1) + _q_drawCustomTitleBarButton(p, rect); + else + p.drawRect(rect); const QPen closeButtonHoveredPen = QPen(QColor(0xFF, 0xFF, 0xFD, 0xFF)); p.setPen(closeButtonHoveredPen); } else { @@ -3562,12 +3655,15 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth); + rect.setWidth(titleButtonWidth - 1); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - p.drawRect(rect); + if (isWindows11orAbove && buttons == 1) + _q_drawCustomTitleBarButton(p, rect); + else + p.drawRect(rect); } p.setPen(textPen); p.drawText(rect,QStringLiteral("\uE922"), QTextOption(Qt::AlignVCenter | Qt::AlignHCenter)); @@ -3580,12 +3676,15 @@ void QWindowsWindow::updateCustomTitlebar() QRectF rect; rect.setY(1); rect.setX(windowWidth - titleButtonWidth * buttons); - rect.setWidth(titleButtonWidth); + rect.setWidth(titleButtonWidth - 1); rect.setHeight(titleBarHeight); if (localPos.x > (windowWidth - buttons * titleButtonWidth) && localPos.x < (windowWidth - (buttons - 1) * titleButtonWidth) && localPos.y > rect.y() && localPos.y < rect.y() + rect.height()) { - p.drawRect(rect); + if (isWindows11orAbove && buttons == 1) + _q_drawCustomTitleBarButton(p, rect); + else + p.drawRect(rect); } p.setPen(textPen); p.drawText(rect,QStringLiteral("\uE921"), QTextOption(Qt::AlignVCenter | Qt::AlignHCenter)); @@ -3603,7 +3702,7 @@ void QWindowsWindow::updateCustomTitlebar() BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - POINT ptLocation = { 0, 0 }; + POINT ptLocation = { windowRect.left, windowRect.top }; SIZE szWnd = { windowWidth, titleBarHeight }; POINT ptSrc = { 0, 0 }; UpdateLayeredWindow(hwnd, hdc, &ptLocation, &szWnd, memdc, &ptSrc, 0, &blend, ULW_ALPHA); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index e8d0984e322..b67bd2850b3 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -307,6 +307,7 @@ public: static QWindow *topLevelOf(QWindow *w); static inline void *userDataOf(HWND hwnd); static inline void setUserDataOf(HWND hwnd, void *ud); + static bool isWindowArranged(HWND hwnd); static bool hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags); static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity); @@ -341,7 +342,7 @@ public: void alertWindow(int durationMs = 0); void stopAlertWindow(); - enum ScreenChangeMode { FromGeometryChange, FromDpiChange }; + enum ScreenChangeMode { FromGeometryChange, FromDpiChange, FromScreenAdded }; void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange); void registerTouchWindow(); @@ -358,10 +359,12 @@ public: int savedDpi() const { return m_savedDpi; } qreal dpiRelativeScale(const UINT dpi) const; - bool isClientAreaExpanded() const { return m_data.flags.testFlag(Qt::ExpandedClientAreaHint); } + bool isFrameless() const { return m_data.flags.testFlag(Qt::FramelessWindowHint); } void requestUpdate() override; + void transitionAnimatedCustomTitleBar(); + private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt index 12938c159a9..921cdd667fa 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt @@ -5,7 +5,7 @@ ## QXcbEglIntegrationPlugin Plugin: ##################################################################### -qt_find_package(EGL) +qt_find_package(EGL MODULE) qt_internal_add_plugin(QXcbEglIntegrationPlugin OUTPUT_NAME qxcb-egl-integration diff --git a/src/plugins/platformthemes/gtk3/CMakeLists.txt b/src/plugins/platformthemes/gtk3/CMakeLists.txt index 6b0613b42fb..362f1a8b7e1 100644 --- a/src/plugins/platformthemes/gtk3/CMakeLists.txt +++ b/src/plugins/platformthemes/gtk3/CMakeLists.txt @@ -1,10 +1,10 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(GTK3) +qt_find_package(GTK3 MODULE) if(QT_FEATURE_xlib) - qt_find_package(X11) + qt_find_package(X11 MODULE) endif() ##################################################################### diff --git a/src/plugins/sqldrivers/configure.cmake b/src/plugins/sqldrivers/configure.cmake index f3aaf83bda7..d96c220d70a 100644 --- a/src/plugins/sqldrivers/configure.cmake +++ b/src/plugins/sqldrivers/configure.cmake @@ -13,14 +13,15 @@ set_property(CACHE INPUT_sqlite PROPERTY STRINGS undefined qt system) #### Libraries -qt_find_package(DB2 PROVIDED_TARGETS DB2::DB2 MODULE_NAME sqldrivers QMAKE_LIB db2) -qt_find_package(MySQL PROVIDED_TARGETS MySQL::MySQL MODULE_NAME sqldrivers QMAKE_LIB mysql) -qt_find_package(PostgreSQL PROVIDED_TARGETS PostgreSQL::PostgreSQL MODULE_NAME sqldrivers QMAKE_LIB psql) -qt_find_package(Oracle PROVIDED_TARGETS Oracle::OCI MODULE_NAME sqldrivers QMAKE_LIB oci) +qt_find_package(DB2 MODULE PROVIDED_TARGETS DB2::DB2 MODULE_NAME sqldrivers QMAKE_LIB db2) +qt_find_package(MySQL MODULE PROVIDED_TARGETS MySQL::MySQL MODULE_NAME sqldrivers QMAKE_LIB mysql) +qt_find_package(PostgreSQL MODULE PROVIDED_TARGETS PostgreSQL::PostgreSQL MODULE_NAME sqldrivers QMAKE_LIB psql) +qt_find_package(Oracle MODULE PROVIDED_TARGETS Oracle::OCI MODULE_NAME sqldrivers QMAKE_LIB oci) qt_find_package(ODBC PROVIDED_TARGETS ODBC::ODBC MODULE_NAME sqldrivers QMAKE_LIB odbc) qt_find_package(SQLite3 PROVIDED_TARGETS SQLite::SQLite3 MODULE_NAME sqldrivers QMAKE_LIB sqlite3) -qt_find_package(Interbase PROVIDED_TARGETS Interbase::Interbase MODULE_NAME sqldrivers QMAKE_LIB ibase) # special case -qt_find_package(Mimer PROVIDED_TARGETS MimerSQL::MimerSQL MODULE_NAME sqldrivers QMAKE_LIB mimer) +qt_find_package(Interbase MODULE + PROVIDED_TARGETS Interbase::Interbase MODULE_NAME sqldrivers QMAKE_LIB ibase) # special case +qt_find_package(Mimer MODULE PROVIDED_TARGETS MimerSQL::MimerSQL MODULE_NAME sqldrivers QMAKE_LIB mimer) if(NOT WIN32 AND QT_FEATURE_system_zlib) qt_add_qmake_lib_dependency(sqlite3 zlib) endif() diff --git a/src/plugins/sqldrivers/psql/CMakeLists.txt b/src/plugins/sqldrivers/psql/CMakeLists.txt index 2f55ab49500..9c0bc6df18c 100644 --- a/src/plugins/sqldrivers/psql/CMakeLists.txt +++ b/src/plugins/sqldrivers/psql/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(PostgreSQL) +qt_find_package(PostgreSQL MODULE) ##################################################################### ## QPSQLDriverPlugin Plugin: diff --git a/src/tools/configure.cmake b/src/tools/configure.cmake index 7ab1509a89f..6a9c1b8e3f3 100644 --- a/src/tools/configure.cmake +++ b/src/tools/configure.cmake @@ -2,7 +2,7 @@ # SPDX-License-Identifier: BSD-3-Clause if(LINUX OR QT_FIND_ALL_PACKAGES_ALWAYS) - qt_find_package(WaylandScanner PROVIDED_TARGETS Wayland::Scanner) + qt_find_package(WaylandScanner MODULE PROVIDED_TARGETS Wayland::Scanner) endif() qt_feature("androiddeployqt" PRIVATE diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index b60b65d5fb5..3d2d5da1e62 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -628,11 +628,11 @@ void Generator::addFunctions(const QList<FunctionDef> &list, const char *functyp if (f.isConstructor) fprintf(out, "Constructor("); else - fprintf(out, "%s(", f.type.name.constData()); // return type + fprintf(out, "%s(", disambiguatedTypeName(f.type.name).constData()); // return type const char *comma = ""; for (const auto &argument : f.arguments) { - fprintf(out, "%s%s", comma, argument.type.name.constData()); + fprintf(out, "%s%s", comma, disambiguatedTypeName(argument.type.name).constData()); comma = ", "; } @@ -725,7 +725,9 @@ void Generator::addProperties() for (const PropertyDef &p : std::as_const(cdef->propertyList)) { fprintf(out, " // property '%s'\n" " QtMocHelpers::PropertyData<%s%s>(%d, ", - p.name.constData(), cxxTypeTag(p.typeTag), p.type.constData(), stridx(p.name)); + p.name.constData(), cxxTypeTag(p.typeTag), + disambiguatedTypeName(p.type, p.typeTag).constData(), + stridx(p.name)); generateTypeInfo(p.type); fputc(',', out); @@ -810,7 +812,7 @@ void Generator::addEnums() fprintf(out, " // %s '%s'\n" " QtMocHelpers::EnumData<%s>(%d, %d,", e.flags & EnumIsFlag ? "flag" : "enum", e.name.constData(), - e.name.constData(), stridx(e.name), stridx(typeName)); + disambiguatedTypeName(e.name).constData(), stridx(e.name), stridx(typeName)); if (e.flags) { const char *separator = ""; @@ -959,7 +961,7 @@ void Generator::generateStaticMetacall() if (it != begin) fprintf(out, ","); fprintf(out, "(*reinterpret_cast<%s>(_a[%d]))", - a.typeNameForCast.constData(), offset++); + disambiguatedTypeNameForCast(a.normalizedType).constData(), offset++); } }; @@ -1006,7 +1008,7 @@ void Generator::generateStaticMetacall() Q_ASSERT(!f.normalizedType.isEmpty()); fprintf(out, " case %d: ", methodindex); if (f.normalizedType != "void") - fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData()); + fprintf(out, "{ %s _r = ", disambiguatedTypeName(noRef(f.normalizedType)).constData()); fprintf(out, "_t->"); if (f.inPrivateClass.size()) fprintf(out, "%s->", f.inPrivateClass.constData()); @@ -1023,7 +1025,7 @@ void Generator::generateStaticMetacall() const ArgumentDef &a = *it; if (it != begin) fprintf(out, ","); - fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++); + fprintf(out, "(*reinterpret_cast<%s>(_a[%d]))", disambiguatedTypeNameForCast(a.normalizedType).constData(), offset++); usedArgs |= UsedA; } if (f.isPrivateSignal) { @@ -1034,8 +1036,8 @@ void Generator::generateStaticMetacall() } fprintf(out, ");"); if (f.normalizedType != "void") { - fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = std::move(_r); } ", - noRef(f.normalizedType).constData()); + fprintf(out, "\n if (_a[0]) *reinterpret_cast<%s*>(_a[0]) = std::move(_r); } ", + disambiguatedTypeName(noRef(f.normalizedType)).constData()); usedArgs |= UsedA; } fprintf(out, " break;\n"); @@ -1169,19 +1171,19 @@ void Generator::generateStaticMetacall() #if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) else if (auto eflags = cdef->enumDeclarations.value(p.type); eflags & EnumIsFlag) fprintf(out, " case %d: QtMocHelpers::assignFlags<%s>(_v, %s%s()); break;\n", - propindex, p.type.constData(), prefix.constData(), p.read.constData()); + propindex, disambiguatedTypeName(p.type, p.typeTag).constData(), prefix.constData(), p.read.constData()); #endif else if (p.read == "default") fprintf(out, " case %d: *reinterpret_cast<%s%s*>(_v) = %s%s().value(); break;\n", - propindex, cxxTypeTag(p.typeTag), p.type.constData(), + propindex, cxxTypeTag(p.typeTag), disambiguatedTypeName(p.type, p.typeTag).constData(), prefix.constData(), p.bind.constData()); else if (!p.read.isEmpty()) fprintf(out, " case %d: *reinterpret_cast<%s%s*>(_v) = %s%s(); break;\n", - propindex, cxxTypeTag(p.typeTag), p.type.constData(), + propindex, cxxTypeTag(p.typeTag), disambiguatedTypeName(p.type, p.typeTag).constData(), prefix.constData(), p.read.constData()); else fprintf(out, " case %d: *reinterpret_cast<%s%s*>(_v) = %s%s; break;\n", - propindex, cxxTypeTag(p.typeTag), p.type.constData(), + propindex, cxxTypeTag(p.typeTag), disambiguatedTypeName(p.type, p.typeTag).constData(), prefix.constData(), p.member.constData()); } fprintf(out, " default: break;\n"); @@ -1206,21 +1208,24 @@ void Generator::generateStaticMetacall() if (p.write == "default") { fprintf(out, " case %d: {\n", propindex); fprintf(out, " %s%s().setValue(*reinterpret_cast<%s%s*>(_v));\n", - prefix.constData(), p.bind.constData(), cxxTypeTag(p.typeTag), p.type.constData()); + prefix.constData(), p.bind.constData(), cxxTypeTag(p.typeTag), + disambiguatedTypeName(p.type, p.typeTag).constData()); fprintf(out, " break;\n"); fprintf(out, " }\n"); } else if (!p.write.isEmpty()) { fprintf(out, " case %d: %s%s(*reinterpret_cast<%s%s*>(_v)); break;\n", propindex, prefix.constData(), p.write.constData(), - cxxTypeTag(p.typeTag), p.type.constData()); + cxxTypeTag(p.typeTag), disambiguatedTypeName(p.type, p.typeTag).constData()); } else { fprintf(out, " case %d:", propindex); if (p.notify.isEmpty()) { fprintf(out, " QtMocHelpers::setProperty(%s%s, *reinterpret_cast<%s%s*>(_v)); break;\n", - prefix.constData(), p.member.constData(), cxxTypeTag(p.typeTag), p.type.constData()); + prefix.constData(), p.member.constData(), cxxTypeTag(p.typeTag), + disambiguatedTypeName(p.type, p.typeTag).constData()); } else { fprintf(out, "\n if (QtMocHelpers::setProperty(%s%s, *reinterpret_cast<%s%s*>(_v)))\n", - prefix.constData(), p.member.constData(), cxxTypeTag(p.typeTag), p.type.constData()); + prefix.constData(), p.member.constData(), cxxTypeTag(p.typeTag), + disambiguatedTypeName(p.type, p.typeTag).constData()); fprintf(out, " Q_EMIT _t->%s(", p.notify.constData()); if (p.notifyId > -1) { const FunctionDef &f = cdef->signalList.at(p.notifyId); @@ -1483,6 +1488,27 @@ void Generator::generatePluginMetaData() fputs("\n", out); } +QByteArray Generator::disambiguatedTypeName(const QByteArray &name) +{ + if (cdef->allEnumNames.contains(name)) + return "enum " + name; + return name; +} + +// in contexts where we already print the type tag, we don't want to do the +// disambiguation +QByteArray Generator::disambiguatedTypeName(const QByteArray &name, TypeTags tag) +{ + if (tag == TypeTag::None) + return disambiguatedTypeName(name); + return name; +} + +QByteArray Generator::disambiguatedTypeNameForCast(const QByteArray &name) +{ + return QByteArray("std::add_pointer_t<"+ disambiguatedTypeName(name) +">"); +} + QT_WARNING_DISABLE_GCC("-Wunused-function") QT_WARNING_DISABLE_CLANG("-Wunused-function") QT_WARNING_DISABLE_CLANG("-Wundefined-internal") diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h index 0ee2ad23919..45df0783c2b 100644 --- a/src/tools/moc/generator.h +++ b/src/tools/moc/generator.h @@ -40,6 +40,9 @@ private: void generateStaticMetacall(); void generateSignal(const FunctionDef *def, int index); void generatePluginMetaData(); + QByteArray disambiguatedTypeName(const QByteArray &name); + QByteArray disambiguatedTypeName(const QByteArray &name, TypeTags tag); + QByteArray disambiguatedTypeNameForCast(const QByteArray &name); QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper(); QMap<int, QMultiMap<QByteArray, int>> methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList); diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index da0096ebfe1..14280712154 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -243,7 +243,7 @@ enum class IncludeState { NoInclude, }; -bool Moc::parseEnum(EnumDef *def) +bool Moc::parseEnum(EnumDef *def, ClassDef *containingClass) { bool isTypdefEnum = false; // typedef enum { ... } Foo; @@ -252,6 +252,8 @@ bool Moc::parseEnum(EnumDef *def) if (test(IDENTIFIER)) { def->name = lexem(); + if (containingClass) + containingClass->allEnumNames.insert(def->name); } else { if (lookup(-1) != TYPEDEF) return false; // anonymous enum @@ -294,6 +296,8 @@ bool Moc::parseEnum(EnumDef *def) if (!test(IDENTIFIER)) return false; def->name = lexem(); + // used as the name for our enum, but we don't track it, + // because we only care about types that might conflict with members } return true; } @@ -316,7 +320,6 @@ void Moc::parseFunctionArguments(FunctionDef *def) arg.rightType += lexem(); } arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType)); - arg.typeNameForCast = QByteArray("std::add_pointer_t<"+arg.normalizedType+">"); if (test(EQ)) arg.isDefault = true; def->arguments += arg; @@ -772,7 +775,7 @@ void Moc::parse() break; case ENUM: { EnumDef enumDef; - if (parseEnum(&enumDef)) + if (parseEnum(&enumDef, nullptr)) def.enumList += enumDef; } break; case CLASS: @@ -979,7 +982,7 @@ void Moc::parse() break; case ENUM: { EnumDef enumDef; - if (parseEnum(&enumDef)) + if (parseEnum(&enumDef, &def)) def.enumList += enumDef; } break; case SEMIC: diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 6ee48b83df1..f08edb3f0d2 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -66,7 +66,6 @@ struct ArgumentDef ArgumentDef() : isDefault(false) {} Type type; QByteArray rightType, normalizedType, name; - QByteArray typeNameForCast; // type name to be used in cast from void * in metacall bool isDefault; QJsonObject toJson() const; @@ -198,6 +197,7 @@ struct ClassDef : BaseDef { QList<FunctionDef> signalList, slotList, methodList, publicList; QList<QByteArray> nonClassSignalList; QList<PropertyDef> propertyList; + QSet<QByteArray> allEnumNames; int revisionedMethods = 0; bool hasQObject = false; @@ -260,7 +260,7 @@ public: Type parseType(); - bool parseEnum(EnumDef *def); + bool parseEnum(EnumDef *def, ClassDef *containingClass); bool parseFunction(FunctionDef *def, bool inMacro = false); bool parseMaybeFunction(const ClassDef *cdef, FunctionDef *def); diff --git a/src/widgets/configure.cmake b/src/widgets/configure.cmake index 745f2d11524..ea9e0ec86df 100644 --- a/src/widgets/configure.cmake +++ b/src/widgets/configure.cmake @@ -9,7 +9,8 @@ #### Libraries -qt_find_package(GTK3 3.6 PROVIDED_TARGETS PkgConfig::GTK3 MODULE_NAME widgets QMAKE_LIB gtk3) +qt_find_package(GTK3 3.6 MODULE + PROVIDED_TARGETS PkgConfig::GTK3 MODULE_NAME widgets QMAKE_LIB gtk3) #### Tests diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index b6eefed149f..8a926b73002 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -4356,13 +4356,11 @@ bool QHeaderViewPrivate::read(QDataStream &in) recalcSectionStartPos(); int tmpint; - in >> tmpint; - if (in.status() == QDataStream::Ok) // we haven't read past end + if (in >> tmpint) // we haven't read past end resizeContentsPrecision = tmpint; bool tmpbool; - in >> tmpbool; - if (in.status() == QDataStream::Ok) { // we haven't read past end + if (in >> tmpbool) { // we haven't read past end customDefaultSectionSize = tmpbool; if (!customDefaultSectionSize) updateDefaultSectionSizeFromStyle(); @@ -4370,8 +4368,7 @@ bool QHeaderViewPrivate::read(QDataStream &in) lastSectionSize = -1; int inLastSectionSize; - in >> inLastSectionSize; - if (in.status() == QDataStream::Ok) + if (in >> inLastSectionSize) lastSectionSize = inLastSectionSize; lastSectionLogicalIdx = -1; @@ -4381,16 +4378,14 @@ bool QHeaderViewPrivate::read(QDataStream &in) } int inSortIndicatorClearable; - in >> inSortIndicatorClearable; - if (in.status() == QDataStream::Ok) // we haven't read past end + if (in >> inSortIndicatorClearable) // we haven't read past end sortIndicatorClearable = inSortIndicatorClearable; in >> countInNoSectionItemsMode; int iHeaderMode; - in >> iHeaderMode; + if (!(in >> iHeaderMode)) { // On any failure (especially reading past end) we consider mode to be normal by default. - if (in.status() != QDataStream::Ok) { iHeaderMode = static_cast<int>(HeaderMode::FlexibleWithSectionMemoryUsage); } diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 03dbb730c5c..4a24f4f484d 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -1768,8 +1768,6 @@ void QMainWindowLayout::setDocumentMode(bool enabled) // Update the document mode for all tab bars for (QTabBar *bar : std::as_const(usedTabBars)) bar->setDocumentMode(_documentMode); - for (QTabBar *bar : std::as_const(unusedTabBars)) - bar->setDocumentMode(_documentMode); } void QMainWindowLayout::setVerticalTabsEnabled(bool enabled) @@ -1894,7 +1892,7 @@ void QMainWindowLayout::keepSize(QDockWidget *w) class QMainWindowTabBar : public QTabBar { Q_OBJECT - QMainWindow *mainWindow; + QPointer<QMainWindow> mainWindow; QPointer<QDockWidget> draggingDock; // Currently dragging (detached) dock widget public: QMainWindowTabBar(QMainWindow *parent); @@ -1909,6 +1907,22 @@ protected: }; +QDebug operator<<(QDebug debug, const QMainWindowTabBar *bar) +{ + if (!bar) + return debug << "QMainWindowTabBar(0x0)"; + QDebugStateSaver saver(debug); + debug.nospace().noquote() << "QMainWindowTabBar(" << static_cast<const void *>(bar) << ", "; + debug.nospace().noquote() << "ParentWidget=(" << bar->parentWidget() << "), "; + const auto dockWidgets = bar->dockWidgets(); + if (dockWidgets.isEmpty()) + debug.nospace().noquote() << "No QDockWidgets"; + else + debug.nospace().noquote() << "DockWidgets(" << dockWidgets << ")"; + debug.nospace().noquote() << ")"; + return debug; +} + QMainWindowTabBar *QMainWindowLayout::findTabBar(const QDockWidget *dockWidget) const { for (auto *bar : usedTabBars) { @@ -1954,7 +1968,7 @@ QDockWidget *QMainWindowTabBar::dockAt(int index) const { QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this); QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow); - QDockAreaLayoutInfo *info = mlayout->dockInfo(that); + QDockAreaLayoutInfo *info = mlayout ? mlayout->dockInfo(that) : nullptr; if (!info) return nullptr; @@ -2049,7 +2063,6 @@ QMainWindowTabBar::~QMainWindowTabBar() auto *mwLayout = qt_mainwindow_layout(mainWindow); if (!mwLayout) return; - mwLayout->unusedTabBars.removeOne(this); mwLayout->usedTabBars.remove(this); } @@ -2105,6 +2118,12 @@ bool QMainWindowLayout::isDockWidgetTabbed(const QDockWidget *dockWidget) const return bar && bar->count() > 1; } +void QMainWindowLayout::unuseTabBar(QTabBar *bar) +{ + Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar)); + delete bar; +} + QTabBar *QMainWindowLayout::getTabBar() { if (!usedTabBars.isEmpty() && !isInRestoreState) { @@ -2116,21 +2135,16 @@ QTabBar *QMainWindowLayout::getTabBar() activate(); } - QTabBar *result = nullptr; - if (!unusedTabBars.isEmpty()) { - result = unusedTabBars.takeLast(); - } else { - result = new QMainWindowTabBar(static_cast<QMainWindow *>(parentWidget())); - result->setDrawBase(true); - result->setElideMode(Qt::ElideRight); - result->setDocumentMode(_documentMode); - result->setMovable(true); - connect(result, SIGNAL(currentChanged(int)), this, SLOT(tabChanged())); - connect(result, &QTabBar::tabMoved, this, &QMainWindowLayout::tabMoved); - } + QTabBar *bar = new QMainWindowTabBar(static_cast<QMainWindow *>(parentWidget())); + bar->setDrawBase(true); + bar->setElideMode(Qt::ElideRight); + bar->setDocumentMode(_documentMode); + bar->setMovable(true); + connect(bar, SIGNAL(currentChanged(int)), this, SLOT(tabChanged())); + connect(bar, &QTabBar::tabMoved, this, &QMainWindowLayout::tabMoved); - usedTabBars.insert(result); - return result; + usedTabBars.insert(bar); + return bar; } // Allocates a new separator widget if needed @@ -2731,14 +2745,6 @@ QMainWindowLayout::~QMainWindowLayout() layoutState.deleteCentralWidgetItem(); delete statusbar; - -#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) - // unusedTabBars contains unparented tab bars, which need to be removed manually. - // ~QMainWindowTabBar() attempts to remove the bar from unusedTabBars - // => move it out of the way first. - const auto bars = std::move(unusedTabBars); - qDeleteAll(bars); -#endif // QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) } void QMainWindowLayout::setDockOptions(QMainWindow::DockOptions opts) @@ -3213,10 +3219,7 @@ void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animat const QSet<QTabBar*> retired = usedTabBars - used; usedTabBars = used; for (QTabBar *tab_bar : retired) { - tab_bar->hide(); - while (tab_bar->count() > 0) - tab_bar->removeTab(0); - unusedTabBars.append(tab_bar); + unuseTabBar(tab_bar); } if (sep == 1) { diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h index 3cc62c7d917..49b40d2599e 100644 --- a/src/widgets/widgets/qmainwindowlayout_p.h +++ b/src/widgets/widgets/qmainwindowlayout_p.h @@ -550,8 +550,8 @@ public: void setDocumentMode(bool enabled); QTabBar *getTabBar(); + void unuseTabBar(QTabBar *bar); QSet<QTabBar*> usedTabBars; - QList<QTabBar*> unusedTabBars; bool verticalTabsEnabled; QWidget *getSeparatorWidget(); diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index b44046969f5..a8d42e556fd 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -622,6 +622,13 @@ void QMenuPrivate::hideMenu(QMenu *menu) QWindow *QMenuPrivate::transientParentWindow() const { Q_Q(const QMenu); + if (causedPopup.widget) { + if (const QWidget *w = causedPopup.widget.data()) { + if (const QWidget *ww = w->window()) + return ww->windowHandle(); + } + } + if (const QWidget *parent = q->nativeParentWidget()) { if (parent->windowHandle()) return parent->windowHandle(); @@ -632,13 +639,6 @@ QWindow *QMenuPrivate::transientParentWindow() const return w->transientParent(); } - if (causedPopup.widget) { - if (const QWidget *w = causedPopup.widget.data()) { - if (const QWidget *ww = w->window()) - return ww->windowHandle(); - } - } - return nullptr; } @@ -3037,7 +3037,7 @@ bool QMenu::event(QEvent *e) d->sloppyState.reset(); if (d->currentAction) d->popupAction(d->currentAction, 0, false); - if (isWindow() && window() && window()->windowHandle() && !window()->windowHandle()->transientParent()) + if (isWindow() && window() && window()->windowHandle()) window()->windowHandle()->setTransientParent(d->transientParentWindow()); break; #if QT_CONFIG(tooltip) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 78192ce6ff2..968cbfa58e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,9 +14,9 @@ if(QT_BUILD_STANDALONE_TESTS) # are handled by qt_enable_cmake_languages(). qt_internal_set_up_config_optimizations_like_in_qmake() - qt_find_package(WrapDBus1 PROVIDED_TARGETS dbus-1) + qt_find_package(WrapDBus1 MODULE PROVIDED_TARGETS dbus-1) qt_find_package(ICU 50.1 COMPONENTS i18n uc data PROVIDED_TARGETS ICU::i18n ICU::uc ICU::data) - qt_find_package(WrapOpenSSL PROVIDED_TARGETS WrapOpenSSL::WrapOpenSSL) - qt_find_package(WrapOpenSSLHeaders PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders) + qt_find_package(WrapOpenSSL MODULE PROVIDED_TARGETS WrapOpenSSL::WrapOpenSSL) + qt_find_package(WrapOpenSSLHeaders MODULE PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders) endif() qt_build_tests() diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index 99232c852b6..1e423f21bec 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -209,6 +209,7 @@ private slots: private: QSharedPointer<QTemporaryDir> m_dataDir; QString m_dataPath; + bool uncServerAvailable = false; constexpr static const std::array m_testDirs = { "entrylist"_L1, @@ -285,6 +286,12 @@ void tst_QDir::initTestCase() #endif QVERIFY2(!m_dataPath.isEmpty(), "test data not found"); + +#ifdef Q_OS_WIN + // "When used with directories, _access determines only whether the specified directory exists" + if (_waccess(qUtf16Printable("//" + QTest::uncServerName() + "/testshare"), 0) == 0) + uncServerAvailable = true; +#endif } void tst_QDir::cleanupTestCase() @@ -688,10 +695,10 @@ void tst_QDir::exists_data() const QString uncRoot = QStringLiteral("//") + QTest::uncServerName(); QTest::newRow("unc 1") << uncRoot << true; QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << true; - QTest::newRow("unc 3") << uncRoot + "/testshare" << true; - QTest::newRow("unc 4") << uncRoot + "/testshare/" << true; - QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << true; - QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << true; + QTest::newRow("unc 3") << uncRoot + "/testshare" << uncServerAvailable; + QTest::newRow("unc 4") << uncRoot + "/testshare/" << uncServerAvailable; + QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << uncServerAvailable; + QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << uncServerAvailable; QTest::newRow("unc 7") << uncRoot + "/testshare/adirthatshouldnotexist" << false; QTest::newRow("unc 8") << uncRoot + "/asharethatshouldnotexist" << false; QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << false; @@ -1082,12 +1089,14 @@ void tst_QDir::entryListSimple_data() #if defined(Q_OS_WIN) const QString uncRoot = QStringLiteral("//") + QTest::uncServerName(); - QTest::newRow("unc 1") << uncRoot << 2; - QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << 2; - QTest::newRow("unc 3") << uncRoot + "/testshare" << 2; - QTest::newRow("unc 4") << uncRoot + "/testshare/" << 2; - QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << 2; - QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << 2; + if (uncServerAvailable) { + QTest::newRow("unc 1") << uncRoot << 2; + QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << 2; + QTest::newRow("unc 3") << uncRoot + "/testshare" << 2; + QTest::newRow("unc 4") << uncRoot + "/testshare/" << 2; + QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << 2; + QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << 2; + } QTest::newRow("unc 7") << uncRoot + "/testshare/adirthatshouldnotexist" << 0; QTest::newRow("unc 8") << uncRoot + "/asharethatshouldnotexist" << 0; QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << 0; @@ -2481,8 +2490,9 @@ void tst_QDir::cdBelowRoot_data() << systemDrive << systemRoot.mid(3) << QDir::cleanPath(systemRoot); const QString uncRoot = QStringLiteral("//") + QTest::uncServerName(); const QString testDirectory = QStringLiteral("testshare"); - QTest::newRow("windows-share") - << uncRoot << testDirectory << QDir::cleanPath(uncRoot + QLatin1Char('/') + testDirectory); + if (uncServerAvailable) + QTest::newRow("windows-share") + << uncRoot << testDirectory << QDir::cleanPath(uncRoot + QLatin1Char('/') + testDirectory); #endif // Windows } diff --git a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp index d4ae8c16118..929c80ae8dc 100644 --- a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp +++ b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp @@ -32,6 +32,8 @@ class tst_QDirIterator : public QObject { Q_OBJECT + bool uncServerAvailable = false; + private: // convenience functions QStringList createdDirectories; QStringList createdFiles; @@ -165,7 +167,11 @@ void tst_QDirIterator::initTestCase() # endif #endif -#if !defined(Q_OS_WIN) +#ifdef Q_OS_WIN + // "When used with directories, _access determines only whether the specified directory exists" + if (_waccess(qUtf16Printable("//" + QTest::uncServerName() + "/testshare"), 0) == 0) + uncServerAvailable = true; +#else createDirectory("hiddenDirs_hiddenFiles"); createFile("hiddenDirs_hiddenFiles/normalFile"); createFile("hiddenDirs_hiddenFiles/.hiddenFile"); @@ -589,6 +595,9 @@ void tst_QDirIterator::relativePaths() #if defined(Q_OS_WIN) void tst_QDirIterator::uncPaths_data() { + if (!uncServerAvailable) + QSKIP("UNC server not available"); + QTest::addColumn<QString>("dirName"); QTest::newRow("uncserver") <<QString("//" + QTest::uncServerName()); diff --git a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp index 50540a65276..0410d070e8d 100644 --- a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp +++ b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp @@ -35,6 +35,8 @@ class tst_QDirListing : public QObject { Q_OBJECT + bool uncServerAvailable = false; + private: // convenience functions QStringList createdDirectories; QStringList createdFiles; @@ -168,7 +170,11 @@ void tst_QDirListing::initTestCase() # endif #endif -#if !defined(Q_OS_WIN) +#ifdef Q_OS_WIN + // "When used with directories, _access determines only whether the specified directory exists" + if (_waccess(qUtf16Printable("//" + QTest::uncServerName() + "/testshare"), 0) == 0) + uncServerAvailable = true; +#else createDirectory("hiddenDirs_hiddenFiles"); createFile("hiddenDirs_hiddenFiles/normalFile"); createFile("hiddenDirs_hiddenFiles/.hiddenFile"); @@ -674,6 +680,9 @@ void tst_QDirListing::relativePaths() #if defined(Q_OS_WIN) void tst_QDirListing::uncPaths_data() { + if (!uncServerAvailable) + QSKIP("UNC server not available"); + QTest::addColumn<QString>("dirName"); QTest::newRow("uncserver") <<QString("//" + QTest::uncServerName()); diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 43a60ddeb23..781f64a31ab 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -388,6 +388,7 @@ private: } int fd_; + bool uncServerAvailable = false; FILE *stream_; QTemporaryDir m_temporaryDir; @@ -531,6 +532,13 @@ void tst_QFile::initTestCase() #else QVERIFY2(file.open(QFile::WriteOnly), msgOpenFailed(file).constData()); #endif + +#ifdef Q_OS_WIN + // "When used with directories, _access determines only whether the specified directory exists" + if (_waccess(qUtf16Printable("//" + QTest::uncServerName() + "/TESTSHAREWRITABLE"), 0) == 0 + && _waccess(qUtf16Printable("//" + QTest::uncServerName() + "/testshare"), 0) == 0) + uncServerAvailable = true; +#endif } void tst_QFile::cleanupTestCase() @@ -576,7 +584,8 @@ void tst_QFile::exists() #if defined(Q_OS_WIN) const QString uncPath = "//" + QTest::uncServerName() + "/testshare/readme.txt"; QFile unc(uncPath); - QVERIFY2(unc.exists(), msgFileDoesNotExist(uncPath).constData()); + if (uncServerAvailable) + QVERIFY2(unc.exists(), msgFileDoesNotExist(uncPath).constData()); #endif QTest::ignoreMessage(QtWarningMsg, "Broken filename passed to function"); @@ -641,7 +650,7 @@ void tst_QFile::open_data() << false << QFile::OpenError; } QTest::newRow("uncFile") << "//" + QTest::uncServerName() + "/testshare/test.pri" << int(QIODevice::ReadOnly) - << true << QFile::NoError; + << uncServerAvailable << QFile::NoError; #endif } @@ -713,8 +722,9 @@ void tst_QFile::size_data() QTest::newRow( "exist01" ) << m_testFile << (qint64)245; #if defined(Q_OS_WIN) - // Only test UNC on Windows./ - QTest::newRow("unc") << "//" + QString(QTest::uncServerName() + "/testshare/test.pri") << (qint64)34; + // Only test UNC on Windows. + if (uncServerAvailable) + QTest::newRow("unc") << "//" + QString(QTest::uncServerName() + "/testshare/test.pri") << (qint64)34; #endif } @@ -1831,6 +1841,9 @@ void tst_QFile::largeUncFileSupport() // test server architecture where the server is no longer shared. QSKIP("Multiple instances of running this test at the same time fail due to QTQAINFRA-1727"); + if (!uncServerAvailable) + QSKIP("UNC server not available"); + qint64 size = Q_INT64_C(8589934592); qint64 dataOffset = Q_INT64_C(8589914592); QByteArray knownData("LargeFile content at offset 8589914592"); @@ -2563,10 +2576,11 @@ void tst_QFile::writeLargeDataBlock_data() #if defined(Q_OS_WIN) && !defined(QT_NO_NETWORK) // Some semi-randomness to avoid collisions. - QTest::newRow("unc file") - << QString("//" + QTest::uncServerName() + "/TESTSHAREWRITABLE/largefile-%1-%2.txt") - .arg(QHostInfo::localHostName()) - .arg(QTime::currentTime().msec()) << (int)OpenQFile; + if (uncServerAvailable) + QTest::newRow("unc file") + << QString("//" + QTest::uncServerName() + "/TESTSHAREWRITABLE/largefile-%1-%2.txt") + .arg(QHostInfo::localHostName()) + .arg(QTime::currentTime().msec()) << (int)OpenQFile; #endif } @@ -3108,6 +3122,9 @@ void tst_QFile::appendAndRead() void tst_QFile::miscWithUncPathAsCurrentDir() { #if defined(Q_OS_WIN) + if (!uncServerAvailable) + QSKIP("UNC server not available"); + QString current = QDir::currentPath(); const QString path = QLatin1String("//") + QTest::uncServerName() + QLatin1String("/testshare"); diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 6ee8841d435..761f0552eec 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -262,6 +262,7 @@ private: QTemporaryDir m_dir; QSharedPointer<QTemporaryDir> m_dataDir; QTemporaryDir m_tempSubDir; + bool uncServerAvailable = false; }; void tst_QFileInfo::initTestCase() @@ -278,6 +279,12 @@ void tst_QFileInfo::initTestCase() QVERIFY2(m_dir.isValid(), ("Failed to create temporary dir: " + m_dir.errorString()).toUtf8()); QVERIFY(QDir::setCurrent(m_dir.path())); + +#ifdef Q_OS_WIN + // "When used with directories, _access determines only whether the specified directory exists" + if (_waccess(qUtf16Printable("//" + QTest::uncServerName() + "/testshare"), 0) == 0) + uncServerAvailable = true; +#endif } void tst_QFileInfo::cleanupTestCase() @@ -396,10 +403,10 @@ void tst_QFileInfo::isDir_data() const QString uncRoot = QStringLiteral("//") + QTest::uncServerName(); QTest::newRow("unc 1") << uncRoot << true; QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << true; - QTest::newRow("unc 3") << uncRoot + "/testshare" << true; - QTest::newRow("unc 4") << uncRoot + "/testshare/" << true; - QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << true; - QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << true; + QTest::newRow("unc 3") << uncRoot + "/testshare" << uncServerAvailable; + QTest::newRow("unc 4") << uncRoot + "/testshare/" << uncServerAvailable; + QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << uncServerAvailable; + QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << uncServerAvailable; QTest::newRow("unc 7") << uncRoot + "/testshare/adirthatshouldnotexist" << false; #endif } @@ -584,10 +591,10 @@ void tst_QFileInfo::exists_data() const QString uncRoot = QStringLiteral("//") + QTest::uncServerName(); QTest::newRow("unc 1") << uncRoot << true; QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << true; - QTest::newRow("unc 3") << uncRoot + "/testshare" << true; - QTest::newRow("unc 4") << uncRoot + "/testshare/" << true; - QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << true; - QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << true; + QTest::newRow("unc 3") << uncRoot + "/testshare" << uncServerAvailable; + QTest::newRow("unc 4") << uncRoot + "/testshare/" << uncServerAvailable; + QTest::newRow("unc 5") << uncRoot + "/testshare/tmp" << uncServerAvailable; + QTest::newRow("unc 6") << uncRoot + "/testshare/tmp/" << uncServerAvailable; QTest::newRow("unc 7") << uncRoot + "/testshare/adirthatshouldnotexist" << false; QTest::newRow("unc 8") << uncRoot + "/asharethatshouldnotexist" << false; QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << false; @@ -1882,7 +1889,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() << NtfsTestResource(NtfsTestResource::SymLink, relToRelSymlink, relToRelTarget) << relToRelSymlink << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); } - { + if (uncServerAvailable) { // Symlink to UNC share pwd.mkdir("unc"); QString uncTarget = QStringLiteral("//") + QTest::uncServerName() + "/testshare"; diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index ba56edc5d54..282c7f2e360 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -352,6 +352,15 @@ void tst_QUrl::comparison() QCOMPARE(urlSetPathDecoded, urlPathSetDecoded); QCOMPARE(urlSetPathDecoded, urlSetPathEncodedWithPercent); QCOMPARE(urlSetPathDecoded, urlSetPathEncodedWithLiterals); + QCOMPARE(qHash(urlSetPathEncodedWithPercent), qHash(urlPathSetEncoded)); + QCOMPARE(qHash(urlSetPathEncodedWithPercent), qHash(urlPathSetDecoded)); + QCOMPARE(qHash(urlSetPathEncodedWithLiterals), qHash(urlPathSetEncoded)); + QCOMPARE(qHash(urlSetPathEncodedWithLiterals), qHash(urlPathSetDecoded)); + QCOMPARE(qHash(urlSetPathEncodedWithLiterals), qHash(urlSetPathEncodedWithPercent)); + QCOMPARE(qHash(urlSetPathDecoded), qHash(urlPathSetEncoded)); + QCOMPARE(qHash(urlSetPathDecoded), qHash(urlPathSetDecoded)); + QCOMPARE(qHash(urlSetPathDecoded), qHash(urlSetPathEncodedWithPercent)); + QCOMPARE(qHash(urlSetPathDecoded), qHash(urlSetPathEncodedWithLiterals)); // 6.2.2.1 Make sure hexdecimal characters in percent encoding are // treated case-insensitively @@ -457,6 +466,33 @@ void tst_QUrl::comparison2_data() QTest::newRow("fragment-scheme") << QUrl("#foo") << QUrl("x:") << -1; QTest::newRow("noport-zeroport") << QUrl("http://example.com") << QUrl("http://example.com:0") << -1; + + // check that nothing is remembered + auto addEmptiedUrl = [](const char *label, const QUrl &url) { + QUrl copy = url; + copy.setUrl(QString()); + QTest::addRow("null-latent-%s", label) << QUrl() << copy << 0; + + QString nonempty = u"https://www.qt-project.org"_s; + copy = url; + copy.setUrl(nonempty); + QTest::addRow("nonnull-latent-%s", label) << QUrl(nonempty) << copy << 0; + }; + addEmptiedUrl("scheme", QUrl("x:")); + addEmptiedUrl("username", QUrl("//user@")); + addEmptiedUrl("password", QUrl("//:pass@")); + addEmptiedUrl("userinfo", QUrl("//user:pass@")); + addEmptiedUrl("host", QUrl("//foo")); + addEmptiedUrl("username-host", QUrl("//user@bar")); + addEmptiedUrl("password-host", QUrl("//:pass@bar")); + addEmptiedUrl("userinfo-host", QUrl("//user:pass@bar")); + addEmptiedUrl("host-port", QUrl("//bar:1")); + addEmptiedUrl("abpath", QUrl("/")); + addEmptiedUrl("relpath", QUrl("hello")); + addEmptiedUrl("abpath-local", QUrl("file:/")); + addEmptiedUrl("relpath-local", QUrl("file:hello")); + addEmptiedUrl("query", QUrl("?boop")); + addEmptiedUrl("fragment", QUrl("#meep")); } void tst_QUrl::comparison2() @@ -473,10 +509,20 @@ void tst_QUrl::comparison2() return Qt::weak_ordering::equivalent; }(); - QCOMPARE(url1.toString() == url2.toString(), ordering == 0); - QT_TEST_ALL_COMPARISON_OPS(url1, url2, expectedOrdering); - if (ordering == 0) + if (ordering == 0) { + QCOMPARE(url1.toString(), url2.toString()); + QCOMPARE(url1, url2); QCOMPARE(qHash(url1), qHash(url2)); + } else if (ordering < 0) { + QCOMPARE_LT(url1.toString(), url2.toString()); + QCOMPARE_NE(url1, url2); + QCOMPARE_LT(url1, url2); + } else { + QCOMPARE_GT(url1.toString(), url2.toString()); + QCOMPARE_NE(url1, url2); + QCOMPARE_GT(url1, url2); + } + QT_TEST_ALL_COMPARISON_OPS(url1, url2, expectedOrdering); // redundant checks (the above should catch these) QCOMPARE(url1 < url2 || url2 < url1, ordering != 0); @@ -1336,6 +1382,17 @@ void tst_QUrl::toString_constructed() QCOMPARE(url.toString(formattingOptions), asString); QCOMPARE(QString::fromLatin1(url.toEncoded(formattingOptions)), QString::fromLatin1(asEncoded)); // readable in case of differences QCOMPARE(url.toEncoded(formattingOptions), asEncoded); + + if (options == QUrl::UrlFormattingOption::None) { + QUrl parsed(asString); + QCOMPARE(url, parsed); + QCOMPARE(qHash(url), qHash(parsed)); + } + + // clear it and ensure no memory of the previous state remains + url.setUrl(QString()); + QCOMPARE(url, QUrl()); + QCOMPARE(qHash(url), qHash(QUrl())); } void tst_QUrl::toDisplayString_PreferLocalFile_data() @@ -4203,6 +4260,11 @@ void tst_QUrl::setComponents() QCOMPARE(copy.toString(), toString); // Check round-tripping QCOMPARE(QUrl(copy.toString()).toString(), toString); + + // check comparisons + QUrl recreated(toString); + QCOMPARE(copy, recreated); + QCOMPARE(qHash(copy), qHash(recreated)); } else { QVERIFY(copy.toString().isEmpty()); } diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp index d945b184849..1c2630b37f4 100644 --- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp +++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp @@ -27,7 +27,6 @@ #include <QSignalSpy> #include <atomic> -#include <optional> #include <thread> using namespace std::chrono_literals; @@ -618,7 +617,7 @@ void tst_QEventLoop::canUseQThreadQuitToExitEventLoopInStdThread() }); QObject obj; - std::optional joiner = qScopeGuard([&] { t.join(); }); // CTAD + auto joiner = qScopeGuard([&] { t.join(); }); #ifdef __cpp_lib_atomic_wait adopted.wait(nullptr); // no timed version exists :( QVERIFY(adopted.load()); @@ -632,7 +631,7 @@ void tst_QEventLoop::canUseQThreadQuitToExitEventLoopInStdThread() called.store(true); QThread::currentThread()->quit(); }, Qt::QueuedConnection)); - joiner.reset(); // joins + joiner.commit(); QVERIFY(!timedOut.load()); QVERIFY(called.load()); } diff --git a/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp b/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp index 8b6939483a6..f66bea72828 100644 --- a/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp +++ b/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp @@ -14,6 +14,8 @@ #include <QWidget> #endif +using namespace std::chrono_literals; + class tst_QPointer : public QObject { Q_OBJECT @@ -540,11 +542,10 @@ void tst_QPointer::raceCondition() QObject targetObject; - std::vector<std::unique_ptr<QThread>> threads; - threads.reserve(NUM_THREADS); + std::array<std::unique_ptr<QThread>, NUM_THREADS> threads; - for (int i = 0; i < NUM_THREADS; ++i) { - QThread *thread = + for (auto &thread : threads) { + thread.reset( QThread::create([&] { startSemaphore.acquire(); @@ -552,18 +553,19 @@ void tst_QPointer::raceCondition() QPointer<QObject> pointer(&targetObject); Q_UNUSED(pointer); } - }); + })); - threads.emplace_back(thread); thread->start(); } - QTest::qWait(100); - startSemaphore.release(NUM_THREADS); + QTest::qWait(100ms); + startSemaphore.release(threads.size()); + bool allJoined = true; for (const auto &thread : threads) { - QVERIFY(thread->wait(30000)); + allJoined = thread->wait(30s) && allJoined; } + QVERIFY(allJoined); } void tst_QPointer::qvariantCast() diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp index 8232a752f81..127c8228616 100644 --- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp +++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp @@ -15,6 +15,7 @@ QT_WARNING_DISABLE_DEPRECATED #include "qjsondocument.h" #include "qregularexpression.h" #include "private/qnumeric_p.h" +#include "private/qjson_p.h" #include <limits> #define INVALID_UNICODE "\xCE\xBA\xE1" @@ -169,6 +170,8 @@ private Q_SLOTS: void noLeakOnNameClash_data(); void noLeakOnNameClash(); + void objectItemsRange(); + private: QString testDataDir; }; @@ -4411,5 +4414,112 @@ void tst_QtJson::noLeakOnNameClash() // In particular it should not forget to deref the container for the inner objects. } +template <typename T> +using ItemsRangeType = decltype(std::declval<T>().asKeyValueRange()); + +void tst_QtJson::objectItemsRange() +{ + auto makeObj = [] { + return QJsonObject{ + { "a", 1 }, + { "b", true }, + { "c", QJsonValue::Null }, + { "d", QJsonValue::Undefined }, + { "e", "ee" }, + { QLatin1String("f"), QLatin1String("g") }, + { "h", QJsonObject{ { "h1", false } } }, + { "i", QJsonArray{ 1, 2, false } }, + }; + }; + QJsonObject obj = makeObj(); + QJsonObject dummy; + + for (auto &&[key, value] : obj.asKeyValueRange()) { + static_assert(std::is_same_v<std::remove_reference_t<decltype(value)>, QJsonValueRef>); + QVERIFY(key.size() == 1); + + auto resolved = key.visit([&](auto &&key) { + if constexpr (std::is_same_v<std::remove_reference_t<decltype(key)>, QUtf8StringView>) { + return dummy["?"]; + } else { + return obj[key]; + } + }); + QVERIFY(QJsonPrivate::Value::container(resolved) == QJsonPrivate::Value::container(value)); + QVERIFY(QJsonPrivate::Value::indexHelper(resolved) + == QJsonPrivate::Value::indexHelper(value)); + } + for (auto &&[key, value] : std::as_const(obj).asKeyValueRange()) { + static_assert(std::is_same_v<std::remove_reference_t<decltype(value)>, QJsonValueConstRef>); + QVERIFY(key.size() == 1); + } + for (auto &&[key, value] : makeObj().asKeyValueRange()) { + static_assert(std::is_same_v<std::remove_reference_t<decltype(value)>, QJsonValueRef>); + QVERIFY(key.size() == 1); + } + + for (auto &&[key, value] : + QJsonObject{ { "a", "a" }, { "b", "b" }, { "c", "c" } }.asKeyValueRange()) { + QVERIFY(key == value.toStringView()); + } + + QJsonObject modify = makeObj(); + for (auto &&[key, value] : modify.asKeyValueRange()) { + if (key == "a") { + value = "modified"; + } + } + QVERIFY(modify["a"] == "modified"); + +#if defined(__cpp_lib_ranges) && __cpp_lib_ranges > 202110L // P2415R2 + static_assert(std::ranges::viewable_range<ItemsRangeType<QJsonObject>>); + static_assert(std::ranges::viewable_range<ItemsRangeType<QJsonObject &>>); + static_assert(std::ranges::viewable_range<ItemsRangeType<const QJsonObject>>); + static_assert(std::ranges::viewable_range<ItemsRangeType<const QJsonObject &>>); + + static_assert(!std::ranges::view<ItemsRangeType<QJsonObject>>); + static_assert(std::ranges::view<ItemsRangeType<QJsonObject &>>); + static_assert(!std::ranges::view<ItemsRangeType<const QJsonObject>>); + static_assert(std::ranges::view<ItemsRangeType<const QJsonObject &>>); + + const auto keyValueTest = [](auto &&pair) { return pair.first == pair.second.toStringView(); }; + { + auto range = obj.asKeyValueRange(); + static_assert(std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } + + { + auto range = std::as_const(obj).asKeyValueRange(); + static_assert(std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } + + { + auto range = makeObj().asKeyValueRange(); + static_assert(!std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } + + { + auto range = const_cast<const QJsonObject &&>(makeObj()).asKeyValueRange(); + static_assert(!std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } +#endif +} + QTEST_MAIN(tst_QtJson) #include "tst_qtjson.moc" diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 90b9679309c..6cd327ada62 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -86,6 +86,7 @@ private slots: void mapComplexKeys_data() { basics_data(); } void mapComplexKeys(); void mapNested(); + void mapItemsRange(); void sorting_data(); void sorting(); @@ -1924,6 +1925,112 @@ void tst_QCborValue::mapNested() } } +template <typename T> +using ItemsRangeType = decltype(std::declval<T>().asKeyValueRange()); + +void tst_QCborValue::mapItemsRange() +{ + auto makeMap = [] { + return QCborMap{ + { "a", 1 }, + { "b", true }, + { "c", QCborValue::Null }, + { "d", QCborValue::Undefined }, + { "e", "ee" }, + { QLatin1String("f"), QLatin1String("g") }, + { "h", QCborMap{ { "h1", false } } }, + { "i", QCborArray{ 1, 2, false } }, + { true, 1 }, + { QCborMap{ { 1, 1 }, { 2, 4 } }, true }, + }; + }; + QCborMap obj = makeMap(); + + for (auto &&[key, value] : obj.asKeyValueRange()) { + static_assert(std::is_same_v<std::remove_reference_t<decltype(value)>, QCborValueRef>); + + if (key.isString()) { + QVERIFY(key.toStringView().length() == 1); + } else if (key.isMap()) { + QVERIFY(key.toMap().size() == 2); + } else { + QVERIFY(key.isBool()); + } + } + for (auto &&[key, value] : std::as_const(obj).asKeyValueRange()) { + static_assert(std::is_same_v<std::remove_reference_t<decltype(value)>, QCborValueConstRef>); + QVERIFY(obj.contains(key)); + } + for (auto &&[key, value] : makeMap().asKeyValueRange()) { + static_assert(std::is_same_v<std::remove_reference_t<decltype(value)>, QCborValueRef>); + QVERIFY(obj.contains(key)); + } + + for (auto &&[key, value] : + QCborMap{ { "a", "a" }, { "b", "b" }, { "c", "c" } }.asKeyValueRange()) { + QVERIFY(key.toStringView() == value.toStringView()); + } + + QCborMap modify = makeMap(); + for (auto &&[key, value] : modify.asKeyValueRange()) { + if (key == "a") { + value = "modified"; + } + } + QVERIFY(modify[QLatin1String("a")] == "modified"); + +#if defined(__cpp_lib_ranges) && __cpp_lib_ranges > 202110L // P2415R2 + static_assert(std::ranges::viewable_range<ItemsRangeType<QCborMap>>); + static_assert(std::ranges::viewable_range<ItemsRangeType<QCborMap &>>); + static_assert(std::ranges::viewable_range<ItemsRangeType<const QCborMap>>); + static_assert(std::ranges::viewable_range<ItemsRangeType<const QCborMap &>>); + + static_assert(!std::ranges::view<ItemsRangeType<QCborMap>>); + static_assert(std::ranges::view<ItemsRangeType<QCborMap &>>); + static_assert(!std::ranges::view<ItemsRangeType<const QCborMap>>); + static_assert(std::ranges::view<ItemsRangeType<const QCborMap &>>); + + const auto keyValueTest = [](auto &&pair) { + return pair.first.toStringView("default key") == pair.second.toStringView(); + }; + { + auto range = obj.asKeyValueRange(); + static_assert(std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } + + { + auto range = std::as_const(obj).asKeyValueRange(); + static_assert(std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } + + { + auto range = makeMap().asKeyValueRange(); + static_assert(!std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } + + { + auto range = const_cast<const QCborMap &&>(makeMap()).asKeyValueRange(); + static_assert(!std::ranges::view<decltype(range)>); + QCOMPARE(std::ranges::distance(range), obj.size()); + const bool ok = + std::ranges::none_of(range | std::views::transform(keyValueTest), std::identity{}); + QVERIFY(ok); + } +#endif +} + void tst_QCborValue::sorting_data() { // CBOR data comparisons are done as if we were comparing their canonically diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp index 1abd2939c43..4c12680b23e 100644 --- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp @@ -1266,14 +1266,14 @@ void tst_QDataStream::stream_QDate() void tst_QDataStream::writeQDate(QDataStream *s) { QDate d6(qDateData(dataIndex(QTest::currentDataTag()))); - *s << d6; + QVERIFY(*s << d6); } void tst_QDataStream::readQDate(QDataStream *s) { QDate test(qDateData(dataIndex(QTest::currentDataTag()))); QDate d6; - *s >> d6; + QVERIFY(*s >> d6); QCOMPARE(d6, test); } @@ -2215,21 +2215,21 @@ void tst_QDataStream::stream_QByteArray2() QByteArray ba; { QDataStream s(&ba, QIODevice::WriteOnly); - s << QByteArray("hallo"); - s << QByteArray(""); - s << QByteArray(); + QVERIFY(s << QByteArray("hallo")); + QVERIFY(s << QByteArray("")); + QVERIFY(s << QByteArray()); } { QDataStream s(&ba, QIODevice::ReadOnly); QByteArray res; - s >> res; + QVERIFY(s >> res); QCOMPARE(res, QByteArray("hallo")); - s >> res; + QVERIFY(s >> res); QCOMPARE(res, QByteArray("")); QVERIFY(res.isEmpty()); QVERIFY(!res.isNull()); - s >> res; + QVERIFY(s >> res); QCOMPARE(res, QByteArray()); QVERIFY(res.isEmpty()); QVERIFY(res.isNull()); @@ -2241,10 +2241,10 @@ void tst_QDataStream::stream_QJsonDocument() QByteArray buffer; { QDataStream save(&buffer, QIODevice::WriteOnly); - save << QByteArrayLiteral("invalidJson"); + QVERIFY(save << QByteArrayLiteral("invalidJson")); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonDocument doc; - load >> doc; + QVERIFY(!(load >> doc)); QVERIFY(doc.isEmpty()); QVERIFY(load.status() != QDataStream::Ok); QCOMPARE(load.status(), QDataStream::ReadCorruptData); @@ -2252,10 +2252,10 @@ void tst_QDataStream::stream_QJsonDocument() { QDataStream save(&buffer, QIODevice::WriteOnly); QJsonDocument docSave(QJsonArray{1,2,3}); - save << docSave; + QVERIFY(save << docSave); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonDocument docLoad; - load >> docLoad; + QVERIFY(load >> docLoad); QCOMPARE(docLoad, docSave); } } @@ -2265,10 +2265,10 @@ void tst_QDataStream::stream_QJsonArray() QByteArray buffer; { QDataStream save(&buffer, QIODevice::WriteOnly); - save << QByteArrayLiteral("invalidJson"); + QVERIFY(save << QByteArrayLiteral("invalidJson")); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonArray array; - load >> array; + QVERIFY(!(load >> array)); QVERIFY(array.isEmpty()); QVERIFY(load.status() != QDataStream::Ok); QCOMPARE(load.status(), QDataStream::ReadCorruptData); @@ -2276,10 +2276,10 @@ void tst_QDataStream::stream_QJsonArray() { QDataStream save(&buffer, QIODevice::WriteOnly); QJsonArray arraySave(QJsonArray{1,2,3}); - save << arraySave; + QVERIFY(save << arraySave); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonArray arrayLoad; - load >> arrayLoad; + QVERIFY(load >> arrayLoad); QCOMPARE(arrayLoad, arraySave); } } @@ -2289,10 +2289,10 @@ void tst_QDataStream::stream_QJsonObject() QByteArray buffer; { QDataStream save(&buffer, QIODevice::WriteOnly); - save << QByteArrayLiteral("invalidJson"); + QVERIFY(save << QByteArrayLiteral("invalidJson")); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonObject object; - load >> object; + QVERIFY(!(load >> object)); QVERIFY(object.isEmpty()); QVERIFY(load.status() != QDataStream::Ok); QCOMPARE(load.status(), QDataStream::ReadCorruptData); @@ -2300,10 +2300,10 @@ void tst_QDataStream::stream_QJsonObject() { QDataStream save(&buffer, QIODevice::WriteOnly); QJsonObject objSave{{"foo", 1}, {"bar", 2}}; - save << objSave; + QVERIFY(save << objSave); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonObject objLoad; - load >> objLoad; + QVERIFY(load >> objLoad); QCOMPARE(objLoad, objSave); } } @@ -2313,10 +2313,10 @@ void tst_QDataStream::stream_QJsonValue() QByteArray buffer; { QDataStream save(&buffer, QIODevice::WriteOnly); - save << quint8(42); + QVERIFY(save << quint8(42)); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonValue value; - load >> value; + QVERIFY(!(load >> value)); QVERIFY(value.isUndefined()); QVERIFY(load.status() != QDataStream::Ok); QCOMPARE(load.status(), QDataStream::ReadCorruptData); @@ -2324,10 +2324,10 @@ void tst_QDataStream::stream_QJsonValue() { QDataStream save(&buffer, QIODevice::WriteOnly); QJsonValue valueSave{42}; - save << valueSave; + QVERIFY(save << valueSave); QDataStream load(&buffer, QIODevice::ReadOnly); QJsonValue valueLoad; - load >> valueLoad; + QVERIFY(load >> valueLoad); QCOMPARE(valueLoad, valueSave); } } @@ -2338,10 +2338,10 @@ void tst_QDataStream::stream_QCborArray() QByteArray buffer; QDataStream save(&buffer, QIODevice::WriteOnly); QCborArray arraySave({1, 2, 3}); - save << arraySave; + QVERIFY(save << arraySave); QDataStream load(&buffer, QIODevice::ReadOnly); QCborArray arrayLoad; - load >> arrayLoad; + QVERIFY(load >> arrayLoad); QCOMPARE(arrayLoad, arraySave); } @@ -2350,10 +2350,10 @@ void tst_QDataStream::stream_QCborMap() QByteArray buffer; QDataStream save(&buffer, QIODevice::WriteOnly); QCborMap objSave{{"foo", 1}, {"bar", 2}}; - save << objSave; + QVERIFY(save << objSave); QDataStream load(&buffer, QIODevice::ReadOnly); QCborMap objLoad; - load >> objLoad; + QVERIFY(load >> objLoad); QCOMPARE(objLoad, objSave); } @@ -2362,10 +2362,10 @@ void tst_QDataStream::stream_QCborValue() QByteArray buffer; QDataStream save(&buffer, QIODevice::WriteOnly); QCborValue valueSave{42}; - save << valueSave; + QVERIFY(save << valueSave); QDataStream load(&buffer, QIODevice::ReadOnly); QCborValue valueLoad; - load >> valueLoad; + QVERIFY(load >> valueLoad); QCOMPARE(valueLoad, valueSave); } #endif @@ -2392,15 +2392,15 @@ void tst_QDataStream::setVersion() { QDataStream out(&ba1, QIODevice::WriteOnly); out.setVersion(vers); - out << QKeySequence(Qt::Key_A) << QKeySequence(Qt::Key_B, Qt::Key_C) - << (quint32)0xDEADBEEF; + QVERIFY(out << QKeySequence(Qt::Key_A) << QKeySequence(Qt::Key_B, Qt::Key_C) + << (quint32)0xDEADBEEF); } { QKeySequence keyseq1, keyseq2; quint32 deadbeef; QDataStream in(&ba1, QIODevice::ReadOnly); in.setVersion(vers); - in >> keyseq1 >> keyseq2 >> deadbeef; + QVERIFY(in >> keyseq1 >> keyseq2 >> deadbeef); QCOMPARE(keyseq1, QKeySequence(Qt::Key_A)); if (vers >= 5) { QVERIFY(keyseq2 == QKeySequence(Qt::Key_B, Qt::Key_C)); @@ -2434,15 +2434,15 @@ void tst_QDataStream::setVersion() { QDataStream out(&ba2, QIODevice::WriteOnly); out.setVersion(vers); - out << pal1 << pal2 << (quint32)0xCAFEBABE; + QVERIFY(out << pal1 << pal2 << (quint32)0xCAFEBABE); } { QPalette inPal1, inPal2; quint32 cafebabe; QDataStream in(&ba2, QIODevice::ReadOnly); in.setVersion(vers); - in >> inPal1 >> inPal2; - in >> cafebabe; + QVERIFY(in >> inPal1 >> inPal2); + QVERIFY(in >> cafebabe); QCOMPARE(cafebabe, 0xCAFEBABE); @@ -2830,7 +2830,7 @@ void tst_QDataStream::status_charptr_QByteArray() { QDataStream stream(&data, QIODevice::ReadOnly); char *buf; - stream >> buf; + QCOMPARE(static_cast<bool>(stream >> buf), (expectedStatus == (int) QDataStream::Ok)); QCOMPARE((int)qstrlen(buf), expectedString.size()); QCOMPARE(QByteArray(buf), expectedString); @@ -2869,7 +2869,7 @@ QT_WARNING_POP { QDataStream stream(&data, QIODevice::ReadOnly); QByteArray buf = "Content to be overwritten"; - stream >> buf; + QCOMPARE(static_cast<bool>(stream >> buf), (expectedStatus == (int) QDataStream::Ok)); if (data.startsWith("\xff\xff\xff\xff")) { // QByteArray, unlike 'char *', supports the null/empty distinction @@ -2961,7 +2961,7 @@ void tst_QDataStream::status_QString() QDataStream stream(&data, QIODevice::ReadOnly); QString str = "Content to be overwritten"; - stream >> str; + QCOMPARE(static_cast<bool>(stream >> str), (expectedStatus == (int) QDataStream::Ok)); QCOMPARE(str.size(), expectedString.size()); QCOMPARE(str, expectedString); @@ -3056,7 +3056,7 @@ void tst_QDataStream::status_QBitArray() QDataStream stream(&data, QIODevice::ReadOnly); stream.setVersion(version); QBitArray str(255, true); - stream >> str; + QCOMPARE(static_cast<bool>(stream >> str), (expectedStatus == (int) QDataStream::Ok)); if (sizeof(qsizetype) == sizeof(int)) QEXPECT_FAIL("new badsize 0x10000", "size > INT_MAX fails on 32bit system (QTBUG-87660)", @@ -3075,7 +3075,7 @@ void tst_QDataStream::status_QBitArray() if (inTransaction) \ stream.startTransaction(); \ stream.setStatus(initialStatus); \ - stream >> hash; \ + QCOMPARE(static_cast<bool>(stream >> hash), (expectedStatus == (int) QDataStream::Ok)); \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ if (!inTransaction || stream.commitTransaction()) { \ QCOMPARE(hash.size(), expectedHash.size()); \ @@ -3094,7 +3094,7 @@ void tst_QDataStream::status_QBitArray() if (inTransaction) \ stream.startTransaction(); \ stream.setStatus(initialStatus); \ - stream >> map; \ + QCOMPARE(static_cast<bool>(stream >> map), (expectedStatus == (int) QDataStream::Ok)); \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ if (!inTransaction || stream.commitTransaction()) { \ QCOMPARE(map.size(), expectedMap.size()); \ @@ -3158,7 +3158,7 @@ void tst_QDataStream::status_QHash_QMap() if (inTransaction) \ stream.startTransaction(); \ stream.setStatus(initialStatus); \ - stream >> list; \ + QCOMPARE(static_cast<bool>(stream >> list), (expectedStatus == (int) QDataStream::Ok)); \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ if (!inTransaction || stream.commitTransaction()) { \ QCOMPARE(list.size(), expectedList.size()); \ @@ -3176,7 +3176,7 @@ void tst_QDataStream::status_QHash_QMap() if (inTransaction) \ stream.startTransaction(); \ stream.setStatus(initialStatus); \ - stream >> vector; \ + QCOMPARE(static_cast<bool>(stream >> vector), (expectedStatus == (int) QDataStream::Ok)); \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ if (!inTransaction || stream.commitTransaction()) { \ QCOMPARE(vector.size(), expectedVector.size()); \ @@ -3251,8 +3251,8 @@ void tst_QDataStream::streamToAndFromQByteArray() quint32 x = 0xdeadbeef; quint32 y; - in << x; - out >> y; + QVERIFY(in << x); + QVERIFY(out >> y); QCOMPARE(y, x); } @@ -3302,17 +3302,17 @@ void tst_QDataStream::streamRealDataTypes() QVERIFY(file.open(QIODevice::WriteOnly)); QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_2); - stream << qreal(0) << qreal(1.0) << qreal(1.1) << qreal(3.14) << qreal(-3.14) << qreal(-1); - stream << QPointF(3, 5) << QRectF(-1, -2, 3, 4) << (QPolygonF() << QPointF(0, 0) << QPointF(1, 2)); - stream << QTransform().rotate(90).scale(2, 2).asAffineMatrix(); - stream << path; + QVERIFY(stream << qreal(0) << qreal(1.0) << qreal(1.1) << qreal(3.14) << qreal(-3.14) << qreal(-1)); + QVERIFY(stream << QPointF(3, 5) << QRectF(-1, -2, 3, 4) << (QPolygonF() << QPointF(0, 0) << QPointF(1, 2))); + QVERIFY(stream << QTransform().rotate(90).scale(2, 2).asAffineMatrix()); + QVERIFY(stream << path); #ifndef QT_NO_PICTURE - stream << picture; + QVERIFY(stream << picture); #endif - stream << QTextLength(QTextLength::VariableLength, 1.5); - stream << color; - stream << radialBrush << conicalBrush; - stream << QPen(QBrush(Qt::red), 1.5); + QVERIFY(stream << QTextLength(QTextLength::VariableLength, 1.5)); + QVERIFY(stream << color); + QVERIFY(stream << radialBrush << conicalBrush); + QVERIFY(stream << QPen(QBrush(Qt::red), 1.5)); file.close(); } @@ -3339,47 +3339,47 @@ void tst_QDataStream::streamRealDataTypes() // the reference stream for 4.2 contains doubles, // so we must read them out as doubles! double a, b, c, d, e, f; - stream >> a; + QVERIFY(stream >> a); QCOMPARE(a, 0.0); - stream >> b; + QVERIFY(stream >> b); QCOMPARE(b, 1.0); - stream >> c; + QVERIFY(stream >> c); QCOMPARE(c, 1.1); - stream >> d; + QVERIFY(stream >> d); QCOMPARE(d, 3.14); - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, -3.14); - stream >> f; + QVERIFY(stream >> f); QCOMPARE(f, -1.0); } else { qreal a, b, c, d, e, f; - stream >> a; + QVERIFY(stream >> a); QCOMPARE(a, qreal(0)); - stream >> b; + QVERIFY(stream >> b); QCOMPARE(b, qreal(1.0)); - stream >> c; + QVERIFY(stream >> c); QCOMPARE(c, qreal(1.1)); - stream >> d; + QVERIFY(stream >> d); QCOMPARE(d, qreal(3.14)); - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, qreal(-3.14)); - stream >> f; + QVERIFY(stream >> f); QCOMPARE(f, qreal(-1)); } - stream >> point; + QVERIFY(stream >> point); QCOMPARE(point, QPointF(3, 5)); - stream >> rect; + QVERIFY(stream >> rect); QCOMPARE(rect, QRectF(-1, -2, 3, 4)); - stream >> polygon; + QVERIFY(stream >> polygon); QCOMPARE((QList<QPointF> &)polygon, (QPolygonF() << QPointF(0, 0) << QPointF(1, 2))); auto matrix = transform.asAffineMatrix(); - stream >> matrix; + QVERIFY(stream >> matrix); QCOMPARE(transform, QTransform().rotate(90).scale(2, 2)); - stream >> p; + QVERIFY(stream >> p); QCOMPARE(p, path); #ifndef QT_NO_PICTURE if (i == 1) { - stream >> pict; + QVERIFY(stream >> pict); QByteArray pictA, pictB; QBuffer bufA, bufB; @@ -3392,11 +3392,11 @@ void tst_QDataStream::streamRealDataTypes() QCOMPARE(pictA, pictB); } #endif - stream >> textLength; + QVERIFY(stream >> textLength); QCOMPARE(textLength, QTextLength(QTextLength::VariableLength, 1.5)); - stream >> col; + QVERIFY(stream >> col); QCOMPARE(col, color); - stream >> rGrad; + QVERIFY(stream >> rGrad); QCOMPARE(rGrad.style(), radialBrush.style()); QCOMPARE(rGrad.transform(), radialBrush.transform()); QCOMPARE(rGrad.gradient()->type(), radialBrush.gradient()->type()); @@ -3405,7 +3405,7 @@ void tst_QDataStream::streamRealDataTypes() QCOMPARE(((QRadialGradient *)rGrad.gradient())->center(), ((QRadialGradient *)radialBrush.gradient())->center()); QCOMPARE(((QRadialGradient *)rGrad.gradient())->focalPoint(), ((QRadialGradient *)radialBrush.gradient())->focalPoint()); QCOMPARE(((QRadialGradient *)rGrad.gradient())->radius(), ((QRadialGradient *)radialBrush.gradient())->radius()); - stream >> cGrad; + QVERIFY(stream >> cGrad); QCOMPARE(cGrad.style(), conicalBrush.style()); QCOMPARE(cGrad.transform(), conicalBrush.transform()); QCOMPARE(cGrad.gradient()->type(), conicalBrush.gradient()->type()); @@ -3415,7 +3415,7 @@ void tst_QDataStream::streamRealDataTypes() QCOMPARE(((QConicalGradient *)cGrad.gradient())->angle(), ((QConicalGradient *)conicalBrush.gradient())->angle()); QCOMPARE(cGrad, conicalBrush); - stream >> pen; + QVERIFY(stream >> pen); QCOMPARE(pen.widthF(), qreal(1.5)); QCOMPARE(stream.status(), QDataStream::Ok); @@ -3437,16 +3437,16 @@ void tst_QDataStream::compatibility_Qt5() { QDataStream out(&stream, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_7); - out << palette; - out << brush; + QVERIFY(out << palette); + QVERIFY(out << brush); } QBrush in_brush; QPalette in_palette; { QDataStream in(stream); in.setVersion(QDataStream::Qt_5_7); - in >> in_palette; - in >> in_brush; + QVERIFY(in >> in_palette); + QVERIFY(in >> in_brush); } QCOMPARE(in_brush.style(), Qt::LinearGradientPattern); QCOMPARE(in_palette.brush(QPalette::Button).style(), Qt::LinearGradientPattern); @@ -3462,33 +3462,33 @@ void tst_QDataStream::compatibility_Qt3() { QDataStream out(&stream, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_3_3); - out << var; - out << QColor(); - out << QColor(Qt::darkYellow); - out << QColor(Qt::darkCyan); - out << invalidColor; + QVERIFY(out << var); + QVERIFY(out << QColor()); + QVERIFY(out << QColor(Qt::darkYellow)); + QVERIFY(out << QColor(Qt::darkCyan)); + QVERIFY(out << invalidColor); } { QDataStream in(stream); in.setVersion(QDataStream::Qt_3_3); quint32 type; - in >> type; + QVERIFY(in >> type); //29 is the type of a QByteArray in Qt3 QCOMPARE(type, quint32(29)); QByteArray ba2; - in >> ba2; + QVERIFY(in >> ba2); QCOMPARE(ba2, ba); quint32 color; - in >> color; + QVERIFY(in >> color); QCOMPARE(color, invalidColor); - in >> color; + QVERIFY(in >> color); QCOMPARE(color, QColor(Qt::darkYellow).rgb()); QColor col; - in >> col; + QVERIFY(in >> col); QCOMPARE(col, QColor(Qt::darkCyan)); - in >> col; + QVERIFY(in >> col); QVERIFY(!col.isValid()); } { @@ -3505,16 +3505,16 @@ void tst_QDataStream::compatibility_Qt3() { QDataStream out(&stream, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_3_3); - out << palette; - out << brush; + QVERIFY(out << palette); + QVERIFY(out << brush); } QBrush in_brush; QPalette in_palette; { QDataStream in(stream); in.setVersion(QDataStream::Qt_3_3); - in >> in_palette; - in >> in_brush; + QVERIFY(in >> in_palette); + QVERIFY(in >> in_brush); } QCOMPARE(in_brush.style(), Qt::NoBrush); QCOMPARE(in_palette.brush(QPalette::Button).style(), Qt::NoBrush); @@ -3527,20 +3527,20 @@ void tst_QDataStream::compatibility_Qt3() { QDataStream out(&stream, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_3_3); - out << QTime(); + QVERIFY(out << QTime()); } QTime in_time; { QDataStream in(stream); in.setVersion(QDataStream::Qt_3_3); - in >> in_time; + QVERIFY(in >> in_time); } QVERIFY(in_time.isNull()); quint32 rawValue; QDataStream in(stream); in.setVersion(QDataStream::Qt_3_3); - in >> rawValue; + QVERIFY(in >> rawValue); QCOMPARE(rawValue, quint32(0)); } @@ -3561,16 +3561,16 @@ void tst_QDataStream::compatibility_Qt2() { QDataStream out(&stream, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_2_1); - out << palette; - out << brush; + QVERIFY(out << palette); + QVERIFY(out << brush); } QBrush in_brush; QPalette in_palette; { QDataStream in(stream); in.setVersion(QDataStream::Qt_2_1); - in >> in_palette; - in >> in_brush; + QVERIFY(in >> in_palette); + QVERIFY(in >> in_brush); } QCOMPARE(in_brush.style(), Qt::NoBrush); QCOMPARE(in_palette.brush(QPalette::Button).style(), Qt::NoBrush); @@ -3603,8 +3603,8 @@ void tst_QDataStream::floatingPointNaN() QDataStream stream(&ba, QIODevice::WriteOnly); stream.setByteOrder(bo); stream.setFloatingPointPrecision(QDataStream::SinglePrecision); - stream << xs[0].f; - stream << xs[1].f; + QVERIFY(stream << xs[0].f); + QVERIFY(stream << xs[1].f); } { @@ -3612,9 +3612,9 @@ void tst_QDataStream::floatingPointNaN() stream.setByteOrder(bo); stream.setFloatingPointPrecision(QDataStream::SinglePrecision); float fr = 0.0f; - stream >> fr; + QVERIFY(stream >> fr); QCOMPARE(fr, xs[0].f); - stream >> fr; + QVERIFY(stream >> fr); QCOMPARE(fr, xs[1].f); } } @@ -3631,13 +3631,13 @@ void tst_QDataStream::enumTest() }; { QDataStream stream(&ba, QIODevice::WriteOnly); - stream << E1::A; + QVERIFY(stream << E1::A); QCOMPARE(ba.size(), int(sizeof(E1))); } { QDataStream stream(ba); E1 e; - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, E1::A); } ba.clear(); @@ -3650,13 +3650,13 @@ void tst_QDataStream::enumTest() }; { QDataStream stream(&ba, QIODevice::WriteOnly); - stream << E2::B; + QVERIFY(stream << E2::B); QCOMPARE(ba.size(), int(sizeof(E2))); } { QDataStream stream(ba); E2 e; - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, E2::B); } ba.clear(); @@ -3669,13 +3669,13 @@ void tst_QDataStream::enumTest() }; { QDataStream stream(&ba, QIODevice::WriteOnly); - stream << E4::C; + QVERIFY(stream << E4::C); QCOMPARE(ba.size(), int(sizeof(E4))); } { QDataStream stream(ba); E4 e; - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, E4::C); } ba.clear(); @@ -3690,13 +3690,13 @@ void tst_QDataStream::enumTest() }; { QDataStream stream(&ba, QIODevice::WriteOnly); - stream << E::D; + QVERIFY(stream << E::D); QCOMPARE(ba.size(), 4); } { QDataStream stream(ba); E e; - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, E::D); } ba.clear(); @@ -3709,13 +3709,13 @@ void tst_QDataStream::enumTest() }; { QDataStream stream(&ba, QIODevice::WriteOnly); - stream << E5::C; + QVERIFY(stream << E5::C); QCOMPARE(ba.size(), int(sizeof(E5))); } { QDataStream stream(ba); E5 e; - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, E5::C); } ba.clear(); @@ -3726,13 +3726,13 @@ void tst_QDataStream::enumTest() enum class ELong : long { A, B, C }; { QDataStream stream(&ba, QIODevice::WriteOnly); - stream << ELong::A; + QVERIFY(stream << ELong::A); QCOMPARE(ba.size(), sizeof(long)); } { QDataStream stream(ba); ELong e; - stream >> e; + QVERIFY(stream >> e); QCOMPARE(e, ELong::A); } ba.clear(); @@ -3746,21 +3746,21 @@ void tst_QDataStream::floatingPointPrecision() QCOMPARE(QDataStream::DoublePrecision, stream.floatingPointPrecision()); float f = 123.0f; - stream << f; + QVERIFY(stream << f); QCOMPARE(ba.size(), int(sizeof(double))); double d = 234.0; - stream << d; + QVERIFY(stream << d); QCOMPARE(ba.size(), int(sizeof(double)*2)); stream.setFloatingPointPrecision(QDataStream::SinglePrecision); f = 123.0f; - stream << f; + QVERIFY(stream << f); QCOMPARE(ba.size(), int(sizeof(double)*2 + sizeof(float))); d = 234.0; - stream << d; + QVERIFY(stream << d); QCOMPARE(ba.size(), int(sizeof(double)*2 + sizeof(float)*2)); } @@ -3768,20 +3768,20 @@ void tst_QDataStream::floatingPointPrecision() QDataStream stream(ba); float f = 0.0f; - stream >> f; + QVERIFY(stream >> f); QCOMPARE(123.0f, f); double d = 0.0; - stream >> d; + QVERIFY(stream >> d); QCOMPARE(234.0, d); f = 0.0f; stream.setFloatingPointPrecision(QDataStream::SinglePrecision); - stream >> f; + QVERIFY(stream >> f); QCOMPARE(123.0f, f); d = 0.0; - stream >> d; + QVERIFY(stream >> d); QCOMPARE(234.0, d); } @@ -3831,8 +3831,8 @@ void tst_QDataStream::transaction() { QDataStream stream(&testBuffer, QIODevice::WriteOnly); - stream << i8Data << i16Data << i32Data << i64Data - << bData << fData << dData << imgData << strData.constData(); + QVERIFY(stream << i8Data << i16Data << i32Data << i64Data + << bData << fData << dData << imgData << strData.constData()); stream.writeRawData(rawData.constData(), rawData.size()); } @@ -3933,7 +3933,7 @@ void tst_QDataStream::nestedTransactionsResult() stream.startTransaction(); stream.startTransaction(); - stream >> c; + QVERIFY(stream >> c); if (commitFirst) QVERIFY(stream.commitTransaction()); @@ -3976,7 +3976,7 @@ void tst_QDataStream::typedefQt5Compat() QDataStream stream(&in); stream.setVersion(QDataStream::Qt_5_15); QVariant var; - stream >> var; + QVERIFY(stream >> var); QCOMPARE(stream.status(), QDataStream::Ok); CustomPair p = var.value<CustomPair>(); QCOMPARE(p.first, 42); @@ -3991,7 +3991,7 @@ void tst_QDataStream::typedefQt5Compat() QDataStream stream(&file); stream.setVersion(QDataStream::Qt_5_15); CustomPair p {42, 100}; - stream << QVariant::fromValue(p); + QVERIFY(stream << QVariant::fromValue(p)); file.close(); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(file.readAll(), qt5Data); diff --git a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp index b7c2b952e2d..1dadbb9efea 100644 --- a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp +++ b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp @@ -19,6 +19,7 @@ class tst_QScopeGuard : public QObject Q_OBJECT private Q_SLOTS: + void commit(); void construction(); void constructionFromLvalue(); void constructionFromRvalue(); @@ -70,6 +71,20 @@ int Callable::moved = 0; static int s_globalState = 0; +void tst_QScopeGuard::commit() +{ + int i = 0; + auto lambda = [&] { ++i; }; + { + auto sg = qScopeGuard(lambda); + QVERIFY(sg.m_invoke); + sg.commit(); + QVERIFY(!sg.m_invoke); + QCOMPARE(i, 1); + } + QCOMPARE(i, 1); // dtor skipped execution +} + void tst_QScopeGuard::construction() { QScopeGuard fromLambda([] { }); diff --git a/tests/auto/dbus/CMakeLists.txt b/tests/auto/dbus/CMakeLists.txt index d67877a0b36..8b9671d6344 100644 --- a/tests/auto/dbus/CMakeLists.txt +++ b/tests/auto/dbus/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(qdbusconnection_signalorder) add_subdirectory(qdbusconnection_spyhook) add_subdirectory(qdbuscontext) add_subdirectory(qdbuslocalcalls) +add_subdirectory(qdbusmessage) add_subdirectory(qdbusmetaobject) add_subdirectory(qdbusmetatype) add_subdirectory(qdbuspendingcall) diff --git a/tests/auto/dbus/qdbusmessage/CMakeLists.txt b/tests/auto/dbus/qdbusmessage/CMakeLists.txt new file mode 100644 index 00000000000..eb4dab17224 --- /dev/null +++ b/tests/auto/dbus/qdbusmessage/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qdbusmessage Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdbusmessage LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qdbusmessage + SOURCES + tst_qdbusmessage.cpp + LIBRARIES + Qt::Core + Qt::DBus +) diff --git a/tests/auto/dbus/qdbusmessage/tst_qdbusmessage.cpp b/tests/auto/dbus/qdbusmessage/tst_qdbusmessage.cpp new file mode 100644 index 00000000000..bc2e28e7d24 --- /dev/null +++ b/tests/auto/dbus/qdbusmessage/tst_qdbusmessage.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QDBusMessage> + +using namespace Qt::StringLiterals; + +// incomplete, but enough for the test +#define COMPARE_MESSAGES(lhs, rhs) \ + do { \ + QCOMPARE_EQ(lhs.service(), rhs.service()); \ + QCOMPARE_EQ(lhs.path(), rhs.path()); \ + QCOMPARE_EQ(lhs.interface(), rhs.interface()); \ + QCOMPARE_EQ(lhs.member(), rhs.member()); \ + QCOMPARE_EQ(lhs.type(), rhs.type()); \ + QCOMPARE_EQ(lhs.signature(), rhs.signature()); \ + QCOMPARE_EQ(lhs.arguments(), rhs.arguments()); \ + } while (false) + +class tst_QDBusMessage : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void moveAssign(); + void moveConstruct(); +}; + +void tst_QDBusMessage::moveAssign() +{ + QDBusMessage referenceMessage = + QDBusMessage::createMethodCall("org.kde.selftest"_L1, "/org/kde/selftest"_L1, + "org.kde.selftest"_L1, "Ping"_L1); + referenceMessage << "ping"_L1; + + { + QDBusMessage copy = referenceMessage; + + // move-assign into another message + QDBusMessage other; + other = std::move(copy); + COMPARE_MESSAGES(other, referenceMessage); + + // modify + other << "other_arg"_L1; // also affects referenceMessage + + // and move-assign back + copy = std::move(other); + COMPARE_MESSAGES(copy, referenceMessage); + } +} + +void tst_QDBusMessage::moveConstruct() +{ + QDBusMessage referenceMessage = + QDBusMessage::createMethodCall("org.kde.selftest"_L1, "/org/kde/selftest"_L1, + "org.kde.selftest"_L1, "Ping"_L1); + referenceMessage << "ping"_L1; + + // moved-from object can be destroyed... + { + QDBusMessage copy = referenceMessage; + QDBusMessage other = std::move(copy); + COMPARE_MESSAGES(other, referenceMessage); + } + // ... or assigned-to + { + QDBusMessage copy = referenceMessage; + QDBusMessage other = std::move(copy); + COMPARE_MESSAGES(other, referenceMessage); + other << "other_arg"_L1; // also affects referenceMessage + copy = other; + COMPARE_MESSAGES(copy, other); + COMPARE_MESSAGES(copy, referenceMessage); + } +} + +#undef COMPARE_MESSAGES + +QTEST_MAIN(tst_QDBusMessage) + +#include "tst_qdbusmessage.moc" diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index cf03f9616ac..790cf31b93a 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -695,6 +695,9 @@ void tst_QWindow::framePositioningStableAfterDestroy() void tst_QWindow::geometryAfterWmUpdateAndDestroyCreate() { + if (isPlatformWayland()) + QSKIP("A window can't be moved programmatically on Wayland"); + QWindow window; window.setFlag(Qt::FramelessWindowHint); window.show(); @@ -963,6 +966,9 @@ void tst_QWindow::isActive() QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QVERIFY(window.isActive()); + if (isPlatformWayland()) + QSKIP("A nested window or a subsurface in wayland terms can't get focus."); + Window child; child.setParent(&window); child.setGeometry(10, 10, 20, 20); diff --git a/tests/auto/tools/moc/CMakeLists.txt b/tests/auto/tools/moc/CMakeLists.txt index 11dbc52411e..c8344dad081 100644 --- a/tests/auto/tools/moc/CMakeLists.txt +++ b/tests/auto/tools/moc/CMakeLists.txt @@ -28,6 +28,7 @@ set(JSON_HEADERS gadgetwithnoenums.h grand-parent-gadget-class.h moc_include.h + name_collision.h namespace.h namespaced-flags.h namespaced-base-class.h diff --git a/tests/auto/tools/moc/allmocs_baseline_in.json b/tests/auto/tools/moc/allmocs_baseline_in.json index c3425c6d15f..28feba8dba9 100644 --- a/tests/auto/tools/moc/allmocs_baseline_in.json +++ b/tests/auto/tools/moc/allmocs_baseline_in.json @@ -1380,6 +1380,73 @@ { "classes": [ { + "className": "NameCollision", + "lineNumber": 11, + "object": true, + "properties": [ + { + "constant": false, + "designable": true, + "final": false, + "index": 0, + "name": "Status", + "read": "Status", + "required": false, + "scriptable": true, + "stored": true, + "type": "Status", + "user": false, + "write": "setStatus" + }, + { + "constant": false, + "designable": true, + "final": false, + "index": 1, + "member": "m_decorationMode", + "name": "decorationMode", + "required": false, + "scriptable": true, + "stored": true, + "type": "DecorationMode", + "user": false + } + + ], + "qualifiedClassName": "myns::NameCollision", + "slots": [ + { + "access": "public", + "arguments": [ + { + "type": "Status" + } + ], + "index": 0, + "name": "setStatus", + "returnType": "void" + }, + { + "access": "public", + "index": 1, + "name": "Status", + "returnType": "Status" + } + ], + "superClasses": [ + { + "access": "public", + "name": "QObject" + } + ] + } + ], + "inputFile": "name_collision.h", + "outputRevision": 69 + }, + { + "classes": [ + { "className": "FooNamespace", "enums": [ { diff --git a/tests/auto/tools/moc/name_collision.h b/tests/auto/tools/moc/name_collision.h new file mode 100644 index 00000000000..7124de6bf7b --- /dev/null +++ b/tests/auto/tools/moc/name_collision.h @@ -0,0 +1,40 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef NAME_COLLISION_H +#define NAME_COLLISION_H + +#include <QObject> + +namespace myns { + +class NameCollision : public QObject +{ + Q_OBJECT + + // intentionally not fully qualified + Q_PROPERTY(Status Status READ Status WRITE setStatus) + + Q_PROPERTY(enum DecorationMode decorationMode MEMBER m_decorationMode) + + int m_status = 0; + +public: + enum Status {}; + enum DecorationMode { + ClientSideDecoration = 1, + ServerSideDecoration = 2, + }; + + void statusChanged(Status status); + enum DecorationMode m_decorationMode; + +public Q_SLOTS: + void setStatus(Status ) {} + Status Status() { return {}; } +}; + +} + + +#endif // TECH_PREVIEW_H diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 9c345093854..9a428e59f06 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -67,6 +67,8 @@ #include "tech-preview.h" +#include "name_collision.h" + using namespace Qt::StringLiterals; #ifdef Q_MOC_RUN @@ -987,6 +989,7 @@ void tst_Moc::initTestCase() QVERIFY(QmlMacro::staticMetaObject.className()); QVERIFY(SignalWithDefaultArg::staticMetaObject.className()); QVERIFY(TestPointeeCanBeIncomplete::staticMetaObject.className()); + QVERIFY(myns::NameCollision::staticMetaObject.className()); } void tst_Moc::hasIncludeSupport() diff --git a/tests/auto/wayland/shared/coreprotocol.h b/tests/auto/wayland/shared/coreprotocol.h index 127ff0964b2..0facac0c607 100644 --- a/tests/auto/wayland/shared/coreprotocol.h +++ b/tests/auto/wayland/shared/coreprotocol.h @@ -348,8 +348,8 @@ public: protected: void seat_bind_resource(Resource *resource) override { + wl_seat::send_name(resource->handle, m_seatName); wl_seat::send_capabilities(resource->handle, m_capabilities); - wl_seat::send_name(resource->handle, m_seatName); // in any normal world this is would be set before capabilities. Weston does it after } void seat_get_pointer(Resource *resource, uint32_t id) override; diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp index 03fe51aa0a0..a79d3454724 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp @@ -119,6 +119,7 @@ private: void cleanupSettingsFile(); QTemporaryDir tempDir; + bool uncServerAvailable = false; }; tst_QFileDialog2::tst_QFileDialog2() @@ -143,7 +144,13 @@ void tst_QFileDialog2::initTestCase() { QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); QStandardPaths::setTestModeEnabled(true); - cleanupSettingsFile(); + +#ifdef Q_OS_WIN + // "When used with directories, _access determines only whether the specified directory exists" + if (_waccess(qUtf16Printable("//" + QTest::uncServerName() + "/TESTSHAREWRITABLE"), 0) == 0 + && _waccess(qUtf16Printable("//" + QTest::uncServerName() + "/testshare"), 0) == 0) + uncServerAvailable = true; +#endif } void tst_QFileDialog2::init() @@ -261,16 +268,16 @@ void tst_QFileDialog2::showNameFilterDetails() void tst_QFileDialog2::unc() { #if defined(Q_OS_WIN) - // Only test UNC on Windows./ + // Only test UNC on Windows. + if (!uncServerAvailable) + QSKIP("UNC server not available"); QString dir("\\\\" + QTest::uncServerName() + "\\testsharewritable"); -#else - QString dir(QDir::currentPath()); -#endif QVERIFY2(QFile::exists(dir), msgDoesNotExist(dir).constData()); QFileDialog fd(0, QString(), dir); QFileSystemModel *model = fd.findChild<QFileSystemModel*>("qt_filesystem_model"); QVERIFY(model); QCOMPARE(model->index(fd.directory().absolutePath()), model->index(dir)); +#endif } void tst_QFileDialog2::emptyUncPath() diff --git a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp index 3a94e1833a0..317bc3f6ca6 100644 --- a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp +++ b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp @@ -158,6 +158,7 @@ private slots: void shortcutToFocusProxy(); void deleteLater(); void keys(); + void modifierOnly(); protected: static Qt::KeyboardModifiers toButtons( int key ); @@ -1356,5 +1357,42 @@ void tst_QShortcut::keys() QTRY_COMPARE(spy.size(), 2); } +void tst_QShortcut::modifierOnly() +{ + MainWindow mainW; + const QString name = QLatin1String(QTest::currentTestFunction()); + mainW.setWindowTitle(name); + mainW.show(); + mainW.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&mainW)); + + const QKeyCombination altModifier(Qt::AltModifier); + const QKeyCombination altKey(Qt::Key_Alt); + const QKeyCombination altModifierPlusK(Qt::AltModifier | Qt::Key_K); + + QShortcut *altModifierShortcut = setupShortcut(&mainW, name, altModifier); + QSignalSpy altModifierActivated(altModifierShortcut, &QShortcut::activated); + QShortcut *altModifierPlusKShortcut = setupShortcut(&mainW, name, altModifierPlusK); + QSignalSpy altModifierPlusKActivated(altModifierPlusKShortcut, &QShortcut::activated); + QShortcut *altKeyShortcut = setupShortcut(&mainW, name, altKey); + QSignalSpy altKeyActivated(altKeyShortcut, &QShortcut::activated); + + // modifier only shortcuts are unsupported + sendKeyEvents(&mainW, altModifier); + QCOMPARE(altModifierActivated.size(), 0); + QCOMPARE(altKeyActivated.size(), 0); + QCOMPARE(altModifierPlusKActivated.size(), 0); + + sendKeyEvents(&mainW, altKey); + QCOMPARE(altModifierActivated.size(), 0); + QCOMPARE(altKeyActivated.size(), 0); + QCOMPARE(altModifierPlusKActivated.size(), 0); + + sendKeyEvents(&mainW, altModifierPlusK); + QCOMPARE(altModifierActivated.size(), 0); + QCOMPARE(altKeyActivated.size(), 0); + QCOMPARE(altModifierPlusKActivated.size(), 1); +} + QTEST_MAIN(tst_QShortcut) #include "tst_qshortcut.moc" diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index 7edbda70c0d..1b3afa0a4dc 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -1610,31 +1610,64 @@ void tst_QMenu::transientParent() menuBar->addMenu(editMenu); window.setMenuBar(menuBar); - // On Mac, we need to create native key events to test menu - // action activation, so skip this part of the test. -#if QT_CONFIG(shortcut) && !defined(Q_OS_DARWIN) + QMenu *bookmarksMenu = new QMenu(&window); + bookmarksMenu->addAction("This is KDE!"); + + QMenu *contextMenu = new QMenu(&window); + QAction *bookmarksAction = contextMenu->addAction("&Bookmarks"); + bookmarksAction->setMenu(bookmarksMenu); + window.show(); QVERIFY(QTest::qWaitForWindowActive(&window)); QWindow *topLevel = window.windowHandle(); QVERIFY(topLevel); + // Show the standalone bookmarks menu. It should be a child of the main window. + bookmarksMenu->popup(window.geometry().center()); + QTRY_VERIFY(QTest::qWaitForWindowExposed(bookmarksMenu)); + QVERIFY(bookmarksMenu->windowHandle()); + QCOMPARE(bookmarksMenu->windowHandle()->transientParent(), topLevel); + bookmarksMenu->close(); + + // Show the bookmarks menu attached to the context menu. Even though the bookmarks menu is + // a child of the main window, its transient parent will be the context menu. + contextMenu->popup(window.geometry().center()); + QTRY_VERIFY(QTest::qWaitForWindowExposed(contextMenu)); + QVERIFY(contextMenu->windowHandle()); + QCOMPARE(contextMenu->windowHandle()->transientParent(), topLevel); + + contextMenu->setActiveAction(bookmarksAction); + QTRY_VERIFY(QTest::qWaitForWindowExposed(bookmarksMenu)); + QVERIFY(bookmarksMenu->windowHandle()); + QCOMPARE(bookmarksMenu->windowHandle()->transientParent(), contextMenu->windowHandle()); + contextMenu->close(); + + // Show the standalone bookmarks menu. Its transient parent will be the main window again. + bookmarksMenu->popup(window.geometry().center()); + QTRY_VERIFY(QTest::qWaitForWindowExposed(bookmarksMenu)); + QVERIFY(bookmarksMenu->windowHandle()); + QCOMPARE(bookmarksMenu->windowHandle()->transientParent(), topLevel); + bookmarksMenu->close(); + + // On Mac, we need to create native key events to test menu + // action activation, so skip this part of the test. +#if QT_CONFIG(shortcut) && !defined(Q_OS_DARWIN) window.setFocus(); QVERIFY(QTest::qWaitForWindowFocused(&window)); QVERIFY(window.hasFocus()); QTest::keyPress(&window, Qt::Key_F, Qt::AltModifier); QTRY_VERIFY(QTest::qWaitForWindowExposed(fileMenu)); - if (fileMenu->isWindow() && fileMenu->window() && fileMenu->window()->windowHandle()) - QVERIFY(fileMenu->window()->windowHandle()->transientParent()); + QVERIFY(fileMenu->windowHandle()); + QCOMPARE(fileMenu->windowHandle()->transientParent(), topLevel); QTest::keyRelease(fileMenu, Qt::Key_F, Qt::AltModifier); QTest::keyPress(fileMenu, Qt::Key_E, Qt::AltModifier); QTRY_VERIFY(QTest::qWaitForWindowExposed(editMenu)); - if (editMenu->isWindow() && editMenu->window() && editMenu->window()->windowHandle()) - QVERIFY(editMenu->window()->windowHandle()->transientParent()); + QVERIFY(editMenu->windowHandle()); + QCOMPARE(editMenu->windowHandle()->transientParent(), topLevel); QTest::keyRelease(editMenu, Qt::Key_E, Qt::AltModifier); #endif // QT_CONFIG(shortcut) && !Q_OS_DARWIN - } class MyMenu : public QMenu diff --git a/tests/manual/iconbrowser/main.cpp b/tests/manual/iconbrowser/main.cpp index 11968d86eb7..a3f8fb281a1 100644 --- a/tests/manual/iconbrowser/main.cpp +++ b/tests/manual/iconbrowser/main.cpp @@ -324,19 +324,31 @@ class IconModel : public QAbstractItemModel u"weather-storm"_s, }; - const QStringList fileIconTypes = { + QStringList fileIconTypes = { u"Computer"_s, u"Desktop"_s, u"Trashcan"_s, u"Network"_s, u"Drive"_s, u"Folder"_s, - u"File"_s + u"File"_s, }; QAbstractFileIconProvider m_fileIconProvider; + public: - using QAbstractItemModel::QAbstractItemModel; + IconModel() + { + for (const auto &ext : {u"txt"_s, u"pdf"_s, u"png"_s}) { + QTemporaryFile *tempFile = new QTemporaryFile(u"XXXXXX.%1"_s.arg(ext), this); + if (!tempFile->open()) { + qWarning() << "Couldn't create temporary file" << ext; + fileIconTypes << u"file.%1"_s.arg(ext); + } else { + fileIconTypes << QFileInfo(*tempFile).absoluteFilePath(); + } + } + } enum Columns { Name, @@ -422,7 +434,9 @@ public: case File: if (row >= fileIconTypes.size()) break; - return m_fileIconProvider.icon(QAbstractFileIconProvider::IconType(row)); + if (row <= QAbstractFileIconProvider::File) + return m_fileIconProvider.icon(QAbstractFileIconProvider::IconType(row)); + return m_fileIconProvider.icon(QFileInfo(fileIconTypes.at(row))); } break; default: diff --git a/tests/manual/permissions/CMakeLists.txt b/tests/manual/permissions/CMakeLists.txt index fd732ecada4..45c83d77112 100644 --- a/tests/manual/permissions/CMakeLists.txt +++ b/tests/manual/permissions/CMakeLists.txt @@ -61,6 +61,6 @@ elseif(APPLE) if(NOT CMAKE_GENERATOR STREQUAL "Xcode") add_custom_command(TARGET tst_qpermissions_app_with_usage_descriptions - POST_BUILD COMMAND codesign -s - tst_qpermissions_app_with_usage_descriptions.app) + POST_BUILD COMMAND codesign -f -s - tst_qpermissions_app_with_usage_descriptions.app) endif() endif() diff --git a/tests/manual/rhi/stereo/window.cpp b/tests/manual/rhi/stereo/window.cpp index 18e1ecc4097..214a894340a 100644 --- a/tests/manual/rhi/stereo/window.cpp +++ b/tests/manual/rhi/stereo/window.cpp @@ -16,12 +16,14 @@ Window::Window(QRhi::Implementation graphicsApi) case QRhi::OpenGLES2: setSurfaceType(OpenGLSurface); break; +#if QT_CONFIG(vulkan) case QRhi::Vulkan: instance.setLayers({ "VK_LAYER_KHRONOS_validation" }); instance.create(); setVulkanInstance(&instance); setSurfaceType(VulkanSurface); break; +#endif case QRhi::D3D11: case QRhi::D3D12: setSurfaceType(Direct3DSurface); @@ -74,6 +76,7 @@ void Window::init() QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers; switch (m_graphicsApi) { +#if QT_CONFIG(vulkan) case QRhi::Vulkan: { QRhiVulkanInitParams params; @@ -82,6 +85,7 @@ void Window::init() m_rhi.reset(QRhi::create(QRhi::Vulkan, ¶ms, rhiFlags)); break; } +#endif case QRhi::Null: case QRhi::Metal: case QRhi::OpenGLES2: diff --git a/tests/manual/rhi/stereo/window.h b/tests/manual/rhi/stereo/window.h index 0a175e31a03..00f776cc1c6 100644 --- a/tests/manual/rhi/stereo/window.h +++ b/tests/manual/rhi/stereo/window.h @@ -16,7 +16,9 @@ public: void releaseSwapChain(); protected: +#if QT_CONFIG(vulkan) QVulkanInstance instance; +#endif std::unique_ptr<QOffscreenSurface> m_fallbackSurface; std::unique_ptr<QRhi> m_rhi; std::unique_ptr<QRhiSwapChain> m_sc; diff --git a/tests/manual/xembed/gtk-container/CMakeLists.txt b/tests/manual/xembed/gtk-container/CMakeLists.txt index 34a802c1426..88373d99cd5 100644 --- a/tests/manual/xembed/gtk-container/CMakeLists.txt +++ b/tests/manual/xembed/gtk-container/CMakeLists.txt @@ -1,8 +1,8 @@ # Copyright (C) 2024 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -qt_find_package(GTK3) -qt_find_package(X11) +qt_find_package(GTK3 MODULE) +qt_find_package(X11 MODULE) ##################################################################### ## gtk-container Binary: |