From 6ebef2eb9a6a3630f9142fb040c3f87ba8eeac8e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 1 May 2020 10:35:02 +0200 Subject: [PATCH 01/12] Fix 32bit integer overflow in ICC parsing Change-Id: I98c413374374a6143733860aa9bab1a957cd3b2d Reviewed-by: Thiago Macieira Reviewed-by: Marc Mutz --- src/gui/painting/qicc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp index 2b5cd58fb18..b7c8e8f824d 100644 --- a/src/gui/painting/qicc.cpp +++ b/src/gui/painting/qicc.cpp @@ -225,7 +225,7 @@ static bool isValidIccProfile(const ICCProfileHeader &header) } // Don't overflow 32bit integers: - if (header.tagCount >= INT32_MAX / sizeof(TagTableEntry)) { + if (header.tagCount >= (INT32_MAX - sizeof(ICCProfileHeader)) / sizeof(TagTableEntry)) { qCWarning(lcIcc, "Failed tag count sanity"); return false; } @@ -629,6 +629,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) // Read tag index const TagTableEntry *tagTable = (const TagTableEntry *)(data.constData() + sizeof(ICCProfileHeader)); const qsizetype offsetToData = sizeof(ICCProfileHeader) + header->tagCount * sizeof(TagTableEntry); + Q_ASSERT(offsetToData > 0); if (offsetToData > data.size()) { qCWarning(lcIcc) << "fromIccProfile: failed index size sanity"; return false; From 66908badaca7bd258c00103bc388f0ce3bcf7322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 5 May 2020 10:07:29 +0200 Subject: [PATCH 02/12] Add more deprecation notices to QtNetwork release notes And move the ones that was already there under the QtNetwork point. Change-Id: I4f9641f78c624b1846699292e053ee148178df4a Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- dist/changes-5.15.0 | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dist/changes-5.15.0 b/dist/changes-5.15.0 index f8e23303115..c42ff4b84de 100644 --- a/dist/changes-5.15.0 +++ b/dist/changes-5.15.0 @@ -46,23 +46,21 @@ information about a particular change. - QtNetwork: * QNetworkConfigurationManager, QNetworkConfiguration and QNetworkSession are deprecated, to be removed in Qt 6. + * QNetworkAccessManager::activeConfiguration, configuration and + setConfiguration are deprecated, to be removed in Qt 6. + * QNetworkAccessManager::networkAccessible, setNetworkAccessible and + the NetworkAccessibility enum are deprecated, to be removed in Qt 6. + * QLocalSocket::error() (the signal) is deprecated; superseded by + errorOccurred() + * QAbstractSocket::error() (the signal) is deprecated; superseded by + errorOccurred() + * QNetworkReply::error() (the signal) is deprecated; superseded by + errorOccurred() + * [QTBUG-80369] QSslSocket::sslErrors() (the getter) was deprecated and + superseded by sslHandshakeErrors() - - [REVERTED] [QTBUG-80369] QAbstractSocket::error() (the getter) is - deprecated; superseded by socketError(). - - [REVERTED] [QTBUG-80369] QLocalSocket::error() (the getter) is - deprecated; superseded by socketError(). - - [QTBUG-80369] QSslSocket::sslErrors() (the getter) was deprecated and - superseded by sslHandshakeErrors() - - [REVERTED] [QTBUG-80369] QNetworkReply::error() (the getter) was - deprecated; superseded by networkError(). - [QTBUG-81630][QTBUG-80312] QLinkedList is deprecated and will be moved to Qt5Compat in Qt 6. It is recommended to use std::list instead. - - QLocalSocket::error() (the signal) is deprecated; superseded by - errorOccurred() - - QAbstractSocket::error() (the signal) is deprecated; superseded by - errorOccurred() - - QNetworkReply::error() (the signal) is deprecated; superseded by - errorOccurred() See also the various sections below, which include many more deprecations. From 798492ccee75a841dfec0e669a409515f3462350 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 5 May 2020 11:59:52 -0700 Subject: [PATCH 03/12] QCborValue: catch overflow in QByteArray when decoding chunked strings We checked against integer overflow, but not against overflowing the QByteArray size limit. That caused a std::bad_alloc to be thrown, which is bad when decoding unknown data. QCborStreamReader wasn't affected, since it doesn't merge chunks. Change-Id: I99ab0f318b1c43b89888fffd160c36f495fada87 Reviewed-by: Volker Hilsheimer --- src/corelib/serialization/qcborvalue.cpp | 2 +- .../serialization/cborlargedatavalidation.cpp | 20 +++++++++++++++---- .../qcborvalue/tst_qcborvalue.cpp | 15 +++++++++++++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index 3bca15d5625..89a928d3480 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -1636,7 +1636,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) if (len == rawlen) { auto oldSize = data.size(); auto newSize = oldSize; - if (!add_overflow(newSize, len, &newSize)) { + if (!add_overflow(newSize, len, &newSize) && newSize < MaxByteArraySize) { if (newSize != oldSize) data.resize(newSize); diff --git a/tests/auto/corelib/serialization/cborlargedatavalidation.cpp b/tests/auto/corelib/serialization/cborlargedatavalidation.cpp index 9abfe0f575c..f3b68939579 100644 --- a/tests/auto/corelib/serialization/cborlargedatavalidation.cpp +++ b/tests/auto/corelib/serialization/cborlargedatavalidation.cpp @@ -81,19 +81,31 @@ qint64 LargeIODevice::readData(char *data, qint64 maxlen) void addValidationLargeData(qsizetype minInvalid, qsizetype maxInvalid) { - char toolong[2 + sizeof(qsizetype)] = { char(0x81) }; + char toolong[1 + sizeof(qsizetype)]; for (qsizetype v = maxInvalid; v >= minInvalid; --v) { // 0x5a for 32-bit, 0x5b for 64-bit - toolong[1] = sizeof(v) > 4 ? 0x5b : 0x5a; - qToBigEndian(v, toolong + 2); + toolong[0] = sizeof(v) > 4 ? 0x5b : 0x5a; + qToBigEndian(v, toolong + 1); QTest::addRow("bytearray-too-big-for-qbytearray-%llx", v) << QByteArray(toolong, sizeof(toolong)) << 0 << CborErrorDataTooLarge; - toolong[1] |= 0x20; + QTest::addRow("bytearray-chunked-too-big-for-qbytearray-%llx", v) + << ('\x5f' + QByteArray(toolong, sizeof(toolong)) + '\xff') + << 0 << CborErrorDataTooLarge; + QTest::addRow("bytearray-2chunked-too-big-for-qbytearray-%llx", v) + << ("\x5f\x40" + QByteArray(toolong, sizeof(toolong)) + '\xff') + << 0 << CborErrorDataTooLarge; + toolong[0] |= 0x20; // QCborStreamReader::readString copies to a QByteArray first QTest::addRow("string-too-big-for-qbytearray-%llx", v) << QByteArray(toolong, sizeof(toolong)) << 0 << CborErrorDataTooLarge; + QTest::addRow("string-chunked-too-big-for-qbytearray-%llx", v) + << ('\x7f' + QByteArray(toolong, sizeof(toolong)) + '\xff') + << 0 << CborErrorDataTooLarge; + QTest::addRow("string-2chunked-too-big-for-qbytearray-%llx", v) + << ("\x7f\x60" + QByteArray(toolong, sizeof(toolong)) + '\xff') + << 0 << CborErrorDataTooLarge; } } diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 9c1341e252d..1379cc348da 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -1926,11 +1926,24 @@ void tst_QCborValue::validation_data() // Add QCborStreamReader-specific limitations due to use of QByteArray and // QString, which are allocated by QArrayData::allocate(). const qsizetype MaxInvalid = std::numeric_limits::max(); - const qsizetype MinInvalid = MaxByteArraySize + 1; + const qsizetype MinInvalid = MaxByteArraySize + 1 - sizeof(QByteArray::size_type); addValidationColumns(); addValidationData(MinInvalid); addValidationLargeData(MinInvalid, MaxInvalid); + // Chunked strings whose total overflows the limit, but each individual + // chunk doesn't. 0x5a for 32-bit, 0x5b for 64-bit. + char toolong[1 + sizeof(qsizetype)]; + toolong[0] = sizeof(MinInvalid) > 4 ? 0x5b : 0x5a; + qToBigEndian(MinInvalid - 1, toolong + 1); + QTest::addRow("bytearray-2chunked+1-too-big-for-qbytearray-%llx", MinInvalid) + << ("\x5f\x41z" + QByteArray(toolong, sizeof(toolong)) + '\xff') + << 0 << CborErrorDataTooLarge; + toolong[0] |= 0x20; + QTest::addRow("string-2chunked+1-too-big-for-qbytearray-%llx", MinInvalid) + << ("\x7f\x61z" + QByteArray(toolong, sizeof(toolong)) + '\xff') + << 0 << CborErrorDataTooLarge; + // These tests say we have arrays and maps with very large item counts. // They are meant to ensure we don't pre-allocate a lot of memory // unnecessarily and possibly crash the application. The actual number of From a8b373d678f44a9d7006a412cabc75e7586b2c43 Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Tue, 5 May 2020 13:59:27 +0200 Subject: [PATCH 04/12] qstandardpaths_win.cpp: Fix GetCurrentProcessToken() for Win7 The GetCurrentProcessToken() was made an inline function for Windows 8. Expand it to ensure builds work independent of WINVER and disable low integrity support for Windows 7. Fixes: QTBUG-83941 Task-number: QTBUG-83453 Change-Id: Ic989f16621cd80cbc70c6b62779afab8a12714df Reviewed-by: Fredrik Orderud Reviewed-by: Volker Hilsheimer Reviewed-by: Thiago Macieira --- src/corelib/io/qstandardpaths_win.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index 5055f4020ca..cbe4ccd0b23 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -47,6 +47,7 @@ #include #endif +#include #include #include #include @@ -99,7 +100,11 @@ static bool isProcessLowIntegrity() { // Disable function until Qt CI is updated return false; #else - HANDLE process_token = GetCurrentProcessToken(); // non-leaking pseudo-handle + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) + return false; + // non-leaking pseudo-handle. Expanded inline function GetCurrentProcessToken() + // (was made an inline function in Windows 8). + const auto process_token = HANDLE(quintptr(-4)); QVarLengthArray token_info_buf(256); auto* token_info = reinterpret_cast(token_info_buf.data()); From ba3b53cb501a77144aa6259e48a8e0edc3d1481d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 11 May 2020 10:15:08 +0200 Subject: [PATCH 05/12] Fix scanned resources in static builds Fixes: QTBUG-81621 Change-Id: Ica23e99054c7b2498bdb1e256c256c8b430938b4 Reviewed-by: Oliver Wolff --- mkspecs/features/qt.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 6fe0059bf73..99b7fe6562c 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -293,7 +293,7 @@ contains(all_qt_module_deps, qml): \ !isEmpty(SCANNERRESOURCES) { IMPORTPATHS += -qrcFiles - for (RESOURCE, SCANNERRESOURCES) + for (RESOURCE, SCANNERRESOURCES): \ IMPORTPATHS += $$absolute_path($$system_quote($$RESOURCE), $$_PRO_FILE_PWD_) } From 8191472bc806280a02088f1e662c200b17dd8645 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 5 May 2020 15:24:57 +0300 Subject: [PATCH 06/12] Revert "note QFileDialog::setNameFilters() is not supported on Android" This reverts commit 9802b93cc76de8a033a9806383c1631f36225931. The commit dbaf62033af3fdd7998c108246d0d96416595605 allows using nameFilters on Android platforms. Task-number: QTBUG-83089 Change-Id: I7b57cd0423c41e7527ce7a650626b602ea9b587d Reviewed-by: Ville Voutilainen --- src/widgets/dialogs/qfiledialog.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index b406333fefa..625bff52852 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1370,8 +1370,8 @@ QStringList qt_make_filter_list(const QString &filter) \snippet code/src_gui_dialogs_qfiledialog.cpp 6 - \note This is not supported on Android's native file dialog. Use - \l{setMimeTypeFilters()} instead. + \note With Android's native file dialog, the mime type matching the given + name filter is used because only mime types are supported. \sa setMimeTypeFilters(), setNameFilters() */ @@ -1444,9 +1444,6 @@ QStringList qt_strip_filters(const QStringList &filters) filters for each file type. For example, JPEG images have three possible extensions; if your application can open such files, selecting the \c image/jpeg mime type as a filter will allow you to open all of them. - - \note This is not supported on Android's native file dialog. Use - \l{setMimeTypeFilters()} instead. */ void QFileDialog::setNameFilters(const QStringList &filters) { From 5a4b275a201bfc653a99e8b6ab546573553b79ad Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 28 Jan 2020 15:55:07 +0100 Subject: [PATCH 07/12] Fix QRunnable::ref use in QThreadPool The reference counter could only ever be -1, 0 or 1, as an autoDeleted QRunnable can only be in a single thread pool. This commits keeps the reference counting for now, but asserts sanity, simplifies locking and fixes a leak. Pick-To: 5.15 Fixes: QTBUG-20251 Fixes: QTBUG-65486 Change-Id: I4de44e9a4e3710225971d1eab8f2e332513f75ad Reviewed-by: Sona Kurazyan (cherry picked from commit 891b60bbc84ddde077072df3426539c716d47459) --- src/corelib/thread/qrunnable.h | 2 +- src/corelib/thread/qthreadpool.cpp | 66 +++++++++++++++++++----------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/corelib/thread/qrunnable.h b/src/corelib/thread/qrunnable.h index 26b6b991ac6..47ea00bdb0f 100644 --- a/src/corelib/thread/qrunnable.h +++ b/src/corelib/thread/qrunnable.h @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QRunnable { - int ref; + int ref; // Qt6: Make this a bool, or make autoDelete() virtual. friend class QThreadPool; friend class QThreadPoolPrivate; diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index 44cdf071df2..1f99bad2478 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -88,7 +88,8 @@ void QThreadPoolThread::run() do { if (r) { - const bool autoDelete = r->autoDelete(); + const bool del = r->autoDelete(); + Q_ASSERT(!del || r->ref == 1); // run the task @@ -106,10 +107,10 @@ void QThreadPoolThread::run() throw; } #endif - locker.relock(); - if (autoDelete && !--r->ref) + if (del) delete r; + locker.relock(); } // if too many threads are active, expire this thread @@ -193,8 +194,6 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task) ++activeThreads; - if (task->autoDelete()) - ++task->ref; thread->runnable = task; thread->start(); return true; @@ -213,9 +212,6 @@ inline bool comparePriority(int priority, const QueuePage *p) void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) { Q_ASSERT(runnable != nullptr); - if (runnable->autoDelete()) - ++runnable->ref; - for (QueuePage *page : qAsConst(queue)) { if (page->priority() == priority && !page->isFull()) { page->push(runnable); @@ -269,8 +265,6 @@ void QThreadPoolPrivate::startThread(QRunnable *runnable) allThreads.insert(thread.data()); ++activeThreads; - if (runnable->autoDelete()) - ++runnable->ref; thread->runnable = runnable; thread.take()->start(); } @@ -334,8 +328,12 @@ void QThreadPoolPrivate::clear() for (QueuePage *page : qAsConst(queue)) { while (!page->isFinished()) { QRunnable *r = page->pop(); - if (r && r->autoDelete() && !--r->ref) + if (r && r->autoDelete()) { + Q_ASSERT(r->ref == 1); + locker.unlock(); delete r; + locker.relock(); + } } } qDeleteAll(queue); @@ -365,19 +363,19 @@ bool QThreadPool::tryTake(QRunnable *runnable) if (runnable == nullptr) return false; - { - QMutexLocker locker(&d->mutex); - for (QueuePage *page : qAsConst(d->queue)) { - if (page->tryTake(runnable)) { - if (page->isFinished()) { - d->queue.removeOne(page); - delete page; - } - if (runnable->autoDelete()) - --runnable->ref; // undo ++ref in start() - return true; + QMutexLocker locker(&d->mutex); + for (QueuePage *page : qAsConst(d->queue)) { + if (page->tryTake(runnable)) { + if (page->isFinished()) { + d->queue.removeOne(page); + delete page; } + if (runnable->autoDelete()) { + Q_ASSERT(runnable->ref == 1); + --runnable->ref; // undo ++ref in start() + } + return true; } } @@ -395,11 +393,12 @@ void QThreadPoolPrivate::stealAndRunRunnable(QRunnable *runnable) Q_Q(QThreadPool); if (!q->tryTake(runnable)) return; - const bool del = runnable->autoDelete() && !runnable->ref; // tryTake already deref'ed + const bool del = runnable->autoDelete(); runnable->run(); if (del) { + Q_ASSERT(runnable->ref == 0); // tryTake already deref'ed delete runnable; } } @@ -503,6 +502,11 @@ void QThreadPool::start(QRunnable *runnable, int priority) Q_D(QThreadPool); QMutexLocker locker(&d->mutex); + if (runnable->autoDelete()) { + Q_ASSERT(runnable->ref == 0); + ++runnable->ref; + } + if (!d->tryStart(runnable)) { d->enqueueTask(runnable, priority); @@ -548,9 +552,23 @@ bool QThreadPool::tryStart(QRunnable *runnable) if (!runnable) return false; + if (runnable->autoDelete()) { + Q_ASSERT(runnable->ref == 0); + ++runnable->ref; + } + Q_D(QThreadPool); QMutexLocker locker(&d->mutex); - return d->tryStart(runnable); + if (d->tryStart(runnable)) + return true; + + // Undo the reference above as we did not start the runnable and + // take over ownership. + if (runnable->autoDelete()) { + --runnable->ref; + Q_ASSERT(runnable->ref == 0); + } + return false; } /*! From 17367462289d73404257967e3af81b1a0f953af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Mon, 11 May 2020 09:21:51 +0000 Subject: [PATCH 08/12] Blacklist imageAtRightAlignedTab in SLES Task-number: QTBUG-46206 Change-Id: I8da530eedcef937f5dea6c7507be74cbe26186a1 Reviewed-by: Heikki Halmet --- tests/auto/gui/text/qtextdocumentlayout/BLACKLIST | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST index 5c81e74aa0e..e646d71144e 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST +++ b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST @@ -2,3 +2,4 @@ rhel-6.6 rhel-7.4 rhel-7.6 +sles From 844967d297327dc72a1aa67644c1b2fa3fe6839c Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Tue, 21 Apr 2020 21:42:51 +0200 Subject: [PATCH 09/12] Support opening directories over portal Recent version of xdg-desktop-portal got support for opening directories through the portal, which means we no longer need to rely on opening the dialog inside sandbox, hoping we have permissions to user directories. [ChangeLog][Linux] QFileDialog will open directories through the portal if required version of xdg-desktop-portal is running on the system. Change-Id: Ifc9035e268f1cc8d9d6a93480e651e0d9e1e9929 Reviewed-by: Thiago Macieira --- .../qxdgdesktopportalfiledialog.cpp | 5 ++++ .../qxdgdesktopportaltheme.cpp | 26 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp index 13c39436ba6..4b37367ad01 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp @@ -107,6 +107,7 @@ public: { } WId winId = 0; + bool directoryMode = false; bool modal = false; bool multipleFiles = false; bool saveFile = false; @@ -145,6 +146,9 @@ void QXdgDesktopPortalFileDialog::initializeDialog() if (options()->fileMode() == QFileDialogOptions::ExistingFiles) d->multipleFiles = true; + if (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly) + d->directoryMode = true; + if (options()->isLabelExplicitlySet(QFileDialogOptions::Accept)) d->acceptLabel = options()->labelText(QFileDialogOptions::Accept); @@ -179,6 +183,7 @@ void QXdgDesktopPortalFileDialog::openPortal() options.insert(QLatin1String("modal"), d->modal); options.insert(QLatin1String("multiple"), d->multipleFiles); + options.insert(QLatin1String("directory"), d->directoryMode); if (d->saveFile) { if (!d->directory.isEmpty()) diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp index fb65f6d9096..30c43b67dc6 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp @@ -45,6 +45,12 @@ #include #include +#include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE class QXdgDesktopPortalThemePrivate : public QPlatformThemePrivate @@ -60,6 +66,7 @@ public: } QPlatformTheme *baseTheme; + uint fileChooserPortalVersion = 0; }; QXdgDesktopPortalTheme::QXdgDesktopPortalTheme() @@ -90,6 +97,21 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme() // 3) Fall back on the built-in "null" platform theme. if (!d->baseTheme) d->baseTheme = new QPlatformTheme; + + // Get information about portal version + QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"), + QLatin1String("/org/freedesktop/portal/desktop"), + QLatin1String("org.freedesktop.DBus.Properties"), + QLatin1String("Get")); + message << QLatin1String("org.freedesktop.portal.FileChooser") << QLatin1String("version"); + QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [d] (QDBusPendingCallWatcher *watcher) { + QDBusPendingReply reply = *watcher; + if (reply.isValid()) { + d->fileChooserPortalVersion = reply.value().toUInt(); + } + }); } QPlatformMenuItem* QXdgDesktopPortalTheme::createPlatformMenuItem() const @@ -131,7 +153,9 @@ QPlatformDialogHelper* QXdgDesktopPortalTheme::createPlatformDialogHelper(Dialog Q_D(const QXdgDesktopPortalTheme); if (type == FileDialog) { - if (d->baseTheme->usePlatformNativeDialog(type)) + // Older versions of FileChooser portal don't support opening directories, therefore we fallback + // to native file dialog opened inside the sandbox to open a directory. + if (d->fileChooserPortalVersion < 3 && d->baseTheme->usePlatformNativeDialog(type)) return new QXdgDesktopPortalFileDialog(static_cast(d->baseTheme->createPlatformDialogHelper(type))); return new QXdgDesktopPortalFileDialog; From 09ee4282e5eedf5b44245e8b28b223339f87ddfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20L=C3=B6ffler?= Date: Sun, 26 Apr 2020 12:03:28 +0200 Subject: [PATCH 10/12] Fix invalid text layout data when a full layout run is interrupted When a QTextDocument is laid out, this is done in "chunks" to keep programs responsive. During the layout process, blocks are split into lines. When a full (re)layout is interrupted (e.g. because a QHighlighter changes some formats before the layout for all chunks is completed), later chunks are skipped. This results in invalid data (e.g., blocks not split into lines). This change ensures that full layout runs of the root frame are completed even after interruptions. Fixes: QTBUG-20354 Change-Id: I041c73a532a5abe74d577ca49810191b5594dca2 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextdocumentlayout.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 9d708735903..a2b3c8dc767 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -105,13 +105,14 @@ public: bool sizeDirty; bool layoutDirty; + bool fullLayoutCompleted; QVector > floats; }; QTextFrameData::QTextFrameData() : maximumWidth(QFIXED_MAX), - currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true) + currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true), fullLayoutCompleted(false) { } @@ -2943,7 +2944,7 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in QTextFrameData *fd = data(f); QFixed newContentsWidth; - bool fullLayout = false; + bool fullLayout = (f == document->rootFrame() && !fd->fullLayoutCompleted); { QTextFrameFormat fformat = f->frameFormat(); // set sizes of this frame from the format @@ -3397,6 +3398,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout cp.contentsWidth = layoutStruct->contentsWidth; checkPoints.append(cp); checkPoints.reserve(checkPoints.size()); + fd->fullLayoutCompleted = true; } else { currentLazyLayoutPosition = checkPoints.constLast().positionInFrame; // ####### @@ -3808,6 +3810,7 @@ void QTextDocumentLayout::documentChanged(int from, int oldLength, int length) d->contentHasAlignment = false; d->currentLazyLayoutPosition = 0; d->checkPoints.clear(); + data(d->docPrivate->rootFrame())->fullLayoutCompleted = false; d->layoutStep(); } else { d->ensureLayoutedByPosition(from); From d68f3a81c9073c64e4492dfca33eeafccb460c6f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 12 May 2020 22:04:16 +0200 Subject: [PATCH 11/12] Small fixes for the Q*Ref deprecation stuff - don't force the deprecation sentence into a separate memory location (gives the compiler more leeway in how to lay stuff out) - split the switch (will be useful when extending) - fix a spelling mistake in one of the messages Change-Id: Ied137dc8eee7047177983660e1a6776a0bf46bde Reviewed-by: Lars Knoll --- src/corelib/text/qbytearray.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index f0c903737f9..3da643dc8bc 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -5097,20 +5097,28 @@ namespace QtPrivate { namespace DeprecatedRefClassBehavior { void warn(WarningType w, EmittingClass c) { - static const char deprecatedBehaviorString[] = + const char *deprecatedBehaviorString = "The corresponding behavior is deprecated, and will be changed" " in a future version of Qt."; const char *emittingClassName = nullptr; - const char *containerClassName = nullptr; switch (c) { case EmittingClass::QByteRef: emittingClassName = "QByteRef"; - containerClassName = "QByteArray"; break; case EmittingClass::QCharRef: emittingClassName = "QCharRef"; + break; + } + + const char *containerClassName = nullptr; + + switch (c) { + case EmittingClass::QByteRef: + containerClassName = "QByteArray"; + break; + case EmittingClass::QCharRef: containerClassName = "QString"; break; } @@ -5121,7 +5129,7 @@ void warn(WarningType w, EmittingClass c) emittingClassName, containerClassName, deprecatedBehaviorString); break; case WarningType::DelayedDetach: - qWarning("Using %s with on a %s that is not already detached. %s", + qWarning("Using %s on a %s that is not already detached. %s", emittingClassName, containerClassName, deprecatedBehaviorString); break; } From 786ae0141a524c66e01e652aed0e6ed4c97d08bc Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 30 Apr 2020 06:13:03 +0200 Subject: [PATCH 12/12] CMake: Don't hard-code the sysroot in Qt5XXXConfigExtras.cmake Instead of writing the hard-coded sysroot into the .cmake file, write the variable ${CMAKE_SYSROOT}. This makes it possible to relocate the build to a machine where the sysroot is different from the build machine. Fixes: QTBUG-83335 Change-Id: Iaa69feb9a140b050f6b5547929cc940ee0f039ce Reviewed-by: Rolf Eike Beer Reviewed-by: Alexandru Croitor --- mkspecs/features/cmake_functions.prf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/cmake_functions.prf b/mkspecs/features/cmake_functions.prf index 1e6b05c78e9..0c62b46af3b 100644 --- a/mkspecs/features/cmake_functions.prf +++ b/mkspecs/features/cmake_functions.prf @@ -42,10 +42,17 @@ defineReplace(cmakeTargetPaths) { } defineReplace(cmakePortablePaths) { + SYSR = $$[QT_SYSROOT] + !isEmpty(SYSR): SYSR = ${CMAKE_SYSROOT} variable = $$1 out = for(v, variable) { - out += $$[QT_SYSROOT]$$cmakeTargetPath($$v) + path = $$cmakeTargetPath($$v) + contains(path, /.*): \ + sysroot_prefix = $$SYSR + else: \ + sysroot_prefix = $$SYSR/ + out += $${sysroot_prefix}$${path} } return ($$join(out, ";")) }