From 6324873543afd7b76d476bd43e3b85e84ea70c00 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 25 Feb 2020 16:20:42 +0100 Subject: Stabilize task255529_transformationAnchorMouseAndViewportMargins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test doesn't test whether window activation works, so there is no reason to fail the test if it doesn't. Instead, abort the test, so that we can record it as a skipped test. Change-Id: Ia44308ef17f110d40c6455d7ee85d90914face4f Fixes: QTBUG-22455 Reviewed-by: Jan Arve Sæther Reviewed-by: Levon Sargsyan --- tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index e21b1b889a..f02835aa90 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -4553,7 +4553,9 @@ void tst_QGraphicsView::task255529_transformationAnchorMouseAndViewportMargins() view.show(); qApp->setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QVERIFY(QTest::qWaitForWindowActive(&view)); + const bool isActiveWindow = QTest::qWaitForWindowActive(&view); + if (!isActiveWindow) + QSKIP("Window activation failed, skipping test", Abort); // This is highly unstable (observed to pass on Windows and some Linux configurations). #ifndef Q_OS_MAC for (int i = 0; i < 4; ++i) { -- cgit v1.2.3 From 529cfe4e22cc02dc7c29f653e8ff23656aa16ff9 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 21 Feb 2020 09:10:28 +0100 Subject: qwindowswindow: Fix screen changes between different DPI screens for native windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When asynchronous events are used for notifications about screen changes it is possible that we run into a race condition where the scale factor has not yet been updated for the new screen. This results in a wrong geometry being set for the window that is moved between the screens. We do not have that problem with synchronous events. Change-Id: I4eb6d2a7cb49517d271901b479f973e273a0926a Amends: 7eed1e40d4d3b6a066bac52995eed7e75d17de2d Task-number: QTBUG-65580 Fixes: QTBUG-82312 Reviewed-by: Friedemann Kleint Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/windows/qwindowswindow.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 496b18ba1a..a11da598fc 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1943,10 +1943,8 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode) qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ << ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString()) << "\"->\"" << newScreen->name() << '"'; - if (mode == FromGeometryChange) - setFlag(SynchronousGeometryChangeEvent); updateFullFrameMargins(); - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } void QWindowsWindow::handleGeometryChange() -- cgit v1.2.3 From 715468df40e4ce97da04f327b6e34d535ff9b97d Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Thu, 27 Feb 2020 09:53:49 +0100 Subject: Fix flaky QElapsedTimer::elapsed test case Much of this test case was testing that the machine it runs on didn't take more than an expected amount of time, which is an assumption that won't hold in a virtual environment where the hypervisor might decide to not allocate any CPU time to the machine at certain times. Instead, take the samples that we want to compare with once, then use them as reference for further comparisons. Also, split the test in two, with the comparison operators and msecsTo test moved into a separate test function. Change-Id: I7db12b8e02552f4d63af933c1b0fee9d62b591eb Fixes: QTBUG-58713 Reviewed-by: Lars Knoll --- .../kernel/qelapsedtimer/tst_qelapsedtimer.cpp | 47 ++++++++++++++-------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp index 4ee3ca361f..bfc4f2ca36 100644 --- a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp +++ b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp @@ -48,6 +48,7 @@ private Q_SLOTS: void validity(); void basics(); void elapsed(); + void msecsTo(); }; void tst_QElapsedTimer::statics() @@ -108,30 +109,42 @@ void tst_QElapsedTimer::elapsed() t1.start(); QTest::qSleep(2*minResolution); - QElapsedTimer t2; - t2.start(); - - QVERIFY(t1 != t2); - QVERIFY(!(t1 == t2)); - QVERIFY(t1 < t2); - QVERIFY(t1.msecsTo(t2) > 0); - QVERIFY(t1.nsecsElapsed() > 0); - QVERIFY(t1.elapsed() > 0); + auto nsecs = t1.nsecsElapsed(); + auto msecs = t1.elapsed(); + QVERIFY(nsecs > 0); + QVERIFY(msecs > 0); // the number of elapsed nanoseconds and milliseconds should match - QVERIFY(t1.nsecsElapsed() - t1.elapsed() * 1000000 < 1000000); + QVERIFY(nsecs - msecs * 1000000 < 1000000); + + if (msecs > 8 * minResolution) + QSKIP("Sampling timer took too long, aborting test"); + QVERIFY(t1.hasExpired(minResolution)); QVERIFY(!t1.hasExpired(8*minResolution)); - QVERIFY(!t2.hasExpired(minResolution)); - QVERIFY(!t1.hasExpired(-1)); - QVERIFY(!t2.hasExpired(-1)); qint64 elapsed = t1.restart(); - QVERIFY(elapsed > minResolution); - QVERIFY(elapsed < 3*minResolution); - qint64 diff = t2.msecsTo(t1); - QVERIFY(diff < minResolution); + QVERIFY(elapsed >= msecs); + QVERIFY(elapsed < msecs + 3*minResolution); +} + +void tst_QElapsedTimer::msecsTo() +{ + QElapsedTimer t1; + t1.start(); + QTest::qSleep(minResolution); + QElapsedTimer t2; + t2.start(); + + QVERIFY(t1 != t2); + QVERIFY(!(t1 == t2)); + QVERIFY(t1 < t2); + + auto diff = t1.msecsTo(t2); + QVERIFY2(diff > 0, QString("difference t1 and t2 is %1").arg(diff).toLatin1()); + diff = t2.msecsTo(t1); + QVERIFY2(diff < 0, QString("difference t2 and t1 is %1").arg(diff).toLatin1()); } QTEST_MAIN(tst_QElapsedTimer); -- cgit v1.2.3 From de1d51a3fd69a4961816ecfc3982424d5379a00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Tue, 25 Feb 2020 15:59:09 +0100 Subject: uic: handle header tag for python imports Fixes: PYSIDE-1233 Change-Id: Id2b6e2a8b833da6ea4417d06643b2f7b045515a9 Reviewed-by: Friedemann Kleint --- src/tools/uic/python/pythonwriteimports.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp index d33b4c6210..95e039e6f0 100644 --- a/src/tools/uic/python/pythonwriteimports.cpp +++ b/src/tools/uic/python/pythonwriteimports.cpp @@ -131,6 +131,8 @@ void WriteImports::acceptCustomWidget(DomCustomWidget *node) output << "import " << className << '\n'; } else { // When we do have elementHeader, we know it's a relative import. QString modulePath = node->elementHeader()->text(); + // Replace the '/' by '.' + modulePath.replace(QLatin1Char('/'), QLatin1Char('.')); // '.h' is added by default on headers for if (modulePath.endsWith(QLatin1String(".h"))) modulePath.chop(2); -- cgit v1.2.3 From 09c5dfb73271614eb55c6d6c610c873fc9146a2f Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 26 Feb 2020 13:00:42 +0100 Subject: Windows: Enable closing the system tray menu when clicking outside of it In order for the system to close a menu when clicking outside of it or outside of the controlling window for the system tray then it needs to be at the foreground right before the menu is tracked. This makes it act like other system tray menus then. Change-Id: I663670c506cfd1e2ba59cd3e75b12e1f8ba17c33 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowssystemtrayicon.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index ab830e1461..9409d2db4d 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -424,8 +424,12 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result) if (screen) { emit contextMenuRequested(globalPos, screen); emit activated(Context); - if (m_menu) + if (m_menu) { + // Set the foreground window to the controlling window so that clicking outside + // of the menu or window will cause the menu to close + SetForegroundWindow(m_hwnd); m_menu->trackPopupMenu(message.hwnd, globalPos.x(), globalPos.y()); + } } } break; -- cgit v1.2.3 From eaf7f572bfbcb33b106097923f4e0efdd9c683fc Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 20 Jan 2020 13:30:39 +0100 Subject: Android: Don't recurse into directories inside the assets when iterating When iterating, it should only return what is in the specified path and not the contents of the sub-directories inside the given path in addition. Change-Id: Iad56f075c22fdf1c633582e37444e26520c24a73 Reviewed-by: BogDan Vatra --- .../android/qandroidassetsfileenginehandler.cpp | 25 +++++----------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index ca16efe34f..07776a4a76 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -202,9 +202,7 @@ public: const QString &path) : QAbstractFileEngineIterator(filters, nameFilters) { - m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path), true)); - if (m_stack.last()->empty()) - m_stack.pop_back(); + m_currentIterator = FolderIterator::fromCache(cleanedAssetPath(path), true); } QFileInfo currentFileInfo() const override @@ -228,36 +226,23 @@ public: bool hasNext() const override { - if (m_stack.empty()) + if (!m_currentIterator) return false; - if (!m_stack.last()->hasNext()) { - m_stack.pop_back(); - return hasNext(); - } - return true; + return m_currentIterator->hasNext(); } QString next() override { - if (m_stack.empty()) { - m_currentIterator.reset(); + if (!m_currentIterator) return {}; - } - m_currentIterator = m_stack.last(); auto res = m_currentIterator->next(); if (!res) return {}; - if (res->second.type == AssetItem::Type::Folder) { - m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()), true)); - if (m_stack.last()->empty()) - m_stack.pop_back(); - } return res->first; } private: - mutable QSharedPointer m_currentIterator; - mutable QVector> m_stack; + QSharedPointer m_currentIterator; }; class AndroidAbstractFileEngine: public QAbstractFileEngine -- cgit v1.2.3 From 7447e2b337f12b4d04935d0f30fc673e4327d5a0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 24 Feb 2020 16:23:27 +0100 Subject: QTextMarkdownImporter: fix use after free; add fuzz-generated tests It was possible to end up with a dangling pointer in m_listStack. This is now avoided by using QPointer and doing nullptr checks before accessing any QTextList pointer stored there. We have 2 specimens of garbage that caused crashes before; now they don't. But only fuzz20450 triggered the dangling pointer in the list stack. The crash caused by fuzz20580 was fixed by updating md4c from upstream: 4b0fc030777cd541604f5ebaaad47a2b76d61ff9 Change-Id: I8e1eca23b281256a03aea0f55e9ae20f1bdd2a38 Reviewed-by: Robert Loehning --- src/gui/text/qtextmarkdownimporter.cpp | 7 +++++-- src/gui/text/qtextmarkdownimporter_p.h | 2 +- .../text/qtextmarkdownimporter/data/fuzz20450.md | 5 +++++ .../text/qtextmarkdownimporter/data/fuzz20580.md | 1 + .../qtextmarkdownimporter.pro | 2 ++ .../tst_qtextmarkdownimporter.cpp | 24 ++++++++++++++++++++++ 6 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md create mode 100644 tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index 7e18a10895..5e75e7816b 100644 --- a/src/gui/text/qtextmarkdownimporter.cpp +++ b/src/gui/text/qtextmarkdownimporter.cpp @@ -577,7 +577,10 @@ void QTextMarkdownImporter::insertBlock() QTextBlockFormat blockFormat; if (!m_listStack.isEmpty() && !m_needsInsertList && m_listItem) { QTextList *list = m_listStack.top(); - blockFormat = list->item(list->count() - 1).blockFormat(); + if (list) + blockFormat = list->item(list->count() - 1).blockFormat(); + else + qWarning() << "attempted to insert into a list that no longer exists"; } if (m_blockQuoteDepth) { blockFormat.setProperty(QTextFormat::BlockQuoteLevel, m_blockQuoteDepth); @@ -607,7 +610,7 @@ void QTextMarkdownImporter::insertBlock() } if (m_needsInsertList) { m_listStack.push(m_cursor->createList(m_listFormat)); - } else if (!m_listStack.isEmpty() && m_listItem) { + } else if (!m_listStack.isEmpty() && m_listItem && m_listStack.top()) { m_listStack.top()->add(m_cursor->block()); } m_needsInsertList = false; diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h index f450da5eb3..e3b4bcd0f2 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -113,7 +113,7 @@ private: #endif QString m_blockCodeLanguage; QVector m_nonEmptyTableCells; // in the current row - QStack m_listStack; + QStack> m_listStack; QStack m_spanFormatStack; QFont m_monoFont; QPalette m_palette; diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md new file mode 100644 index 0000000000..d7005cb01e --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20450.md @@ -0,0 +1,5 @@ +ÿ +* ÿ + + ÿ +* ÿ \ No newline at end of file diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md new file mode 100644 index 0000000000..22006f5876 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/fuzz20580.md @@ -0,0 +1 @@ +| --:| ("warning"); + QTest::newRow("fuzz20450") << "attempted to insert into a list that no longer exists"; + QTest::newRow("fuzz20580") << ""; +} + +void tst_QTextMarkdownImporter::pathological() // avoid crashing on crazy input +{ + QFETCH(QString, warning); + QString filename = QLatin1String("data/") + QTest::currentDataTag() + QLatin1String(".md"); + QFile f(QFINDTESTDATA(filename)); + QVERIFY(f.open(QFile::ReadOnly)); +#ifdef QT_NO_DEBUG + Q_UNUSED(warning) +#else + if (!warning.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); +#endif + QTextDocument().setMarkdown(f.readAll()); +} + QTEST_MAIN(tst_QTextMarkdownImporter) #include "tst_qtextmarkdownimporter.moc" -- cgit v1.2.3 From 08d5059320334223ff1f9009342324f25c231f0b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 14 Oct 2019 14:54:44 +0200 Subject: Fix geometry handling for native child windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't move the native child window position for native child windows. Initial-patch-by: BÅ‚ażej SzczygieÅ‚ Task-number: QTBUG-82312 Fixes: QTBUG-79166 Change-Id: I117ef08da13c8e90ff60cf034126c9efdc17b836 Reviewed-by: BÅ‚ażej SzczygieÅ‚ Reviewed-by: Morten Johan Sørvig Reviewed-by: Oliver Wolff --- src/gui/kernel/qwindow.cpp | 10 +++++++--- src/gui/kernel/qwindowsysteminterface.cpp | 13 ++++++++++--- src/plugins/platforms/windows/qwindowsintegration.cpp | 4 +++- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 +++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 0a4277c118..9cb851a7a2 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1666,7 +1666,7 @@ void QWindow::setGeometry(const QRect &rect) if (newScreen && isTopLevel()) nativeRect = QHighDpi::toNativePixels(rect, newScreen); else - nativeRect = QHighDpi::toNativePixels(rect, this); + nativeRect = QHighDpi::toNativeLocalPosition(rect, newScreen); d->platformWindow->setGeometry(nativeRect); } else { d->geometry = rect; @@ -1717,8 +1717,12 @@ QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) const QRect QWindow::geometry() const { Q_D(const QWindow); - if (d->platformWindow) - return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this); + if (d->platformWindow) { + const auto nativeGeometry = d->platformWindow->geometry(); + return isTopLevel() + ? QHighDpi::fromNativePixels(nativeGeometry, this) + : QHighDpi::fromNativeLocalPosition(nativeGeometry, this); + } return d->geometry; } diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 8457282bed..8f2927901a 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -296,14 +296,21 @@ QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow , window(window) , newGeometry(newGeometry) { - if (const QPlatformWindow *pw = window->handle()) - requestedGeometry = QHighDpi::fromNativePixels(pw->QPlatformWindow::geometry(), window); + if (const QPlatformWindow *pw = window->handle()) { + const auto nativeGeometry = pw->QPlatformWindow::geometry(); + requestedGeometry = window->isTopLevel() + ? QHighDpi::fromNativePixels(nativeGeometry, window) + : QHighDpi::fromNativeLocalPosition(nativeGeometry, window); + } } QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect) { Q_ASSERT(window); - QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window)); + const auto newRectDi = window->isTopLevel() + ? QHighDpi::fromNativePixels(newRect, window) + : QHighDpi::fromNativeLocalPosition(newRect, window); + auto e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, newRectDi); if (window->handle()) { // Persist the new geometry so that QWindow::geometry() can be queried in the resize event window->handle()->QPlatformWindow::setGeometry(newRect); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 09117f663d..d37b405db8 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -334,7 +334,9 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); + requested.geometry = window->isTopLevel() + ? QHighDpi::toNativePixels(window->geometry(), window) + : QHighDpi::toNativeLocalPosition(window->geometry(), window); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index cfe048d5c4..c9d1cfe50a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -276,7 +276,9 @@ void QXcbWindow::create() QXcbScreen *currentScreen = xcbScreen(); QXcbScreen *platformScreen = parent() ? parentScreen() : initialScreen(); - QRect rect = QHighDpi::toNativePixels(window()->geometry(), platformScreen); + QRect rect = parent() + ? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen) + : QHighDpi::toNativePixels(window()->geometry(), platformScreen); if (type == Qt::Desktop) { m_window = platformScreen->root(); -- cgit v1.2.3 From 4a1de178c9cc891560f38d64d89074799b0fa0e1 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 28 Feb 2020 12:33:35 +0100 Subject: Try again to make QDeadlineTimer test robust against context switches Instead of comparing to absolute values, compare the result from QDeadlineTimer with the reference clock types from std::chrono. Pass the test as long as we are within 10% of that reference. In addition, handle the case where QTest::qSleep sleeps for more than 10% longer or shorter than what is requested, and if so, abort the test. Change-Id: If8b77aea55a8c5c53e96427b2fff2f78281d0f82 Reviewed-by: Lars Knoll --- .../kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp | 50 +++++++++++++++------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp index 35c5e7cb75..db53c3f20c 100644 --- a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp +++ b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp @@ -573,12 +573,32 @@ void tst_QDeadlineTimer::stdchrono() QCOMPARE(deadline.remainingTimeAsDuration(), nanoseconds::zero()); + /* + Call QTest::qSleep, and return true if the time actually slept is + within \a deviationPercent percent of the requested sleep time. + Otherwise, return false, in which case the test should to abort. + */ + auto sleepHelper = [](int ms, int deviationPercent = 10) -> bool { + auto before = steady_clock::now(); + QTest::qSleep(ms); + auto after = steady_clock::now(); + auto diff = duration_cast(after - before).count(); + bool inRange = qAbs(diff - ms) < ms * deviationPercent/100.0; + if (!inRange) + qWarning() << "sleeping" << diff << "instead of" << ms << inRange; + return inRange; + }; + auto steady_before = steady_clock::now(); auto system_before = system_clock::now(); - QTest::qSleep(minResolution); + if (!sleepHelper(minResolution)) + QSKIP("Slept too long"); auto now = QDeadlineTimer::current(timerType); - QTest::qSleep(minResolution); + auto steady_reference = steady_clock::now(); + auto system_reference = system_clock::now(); + if (!sleepHelper(minResolution)) + QSKIP("Slept too long"); auto sampling_start = steady_clock::now(); auto steady_deadline = now.deadline(); @@ -599,35 +619,33 @@ void tst_QDeadlineTimer::stdchrono() } { - auto diff = duration_cast(steady_after - steady_deadline); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); + auto reference = duration_cast(steady_after - steady_reference).count(); + auto diff = duration_cast(steady_after - steady_deadline).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_after(steady_after, timerType); QVERIFY2(now < dt_after, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; after = " + QLocale().toString(dt_after.deadlineNSecs())).toLatin1()); - diff = duration_cast(steady_deadline - steady_before); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); + reference = duration_cast(steady_reference - steady_before).count(); + diff = duration_cast(steady_deadline - steady_before).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_before(steady_before, timerType); QVERIFY2(now > dt_before, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; before = " + QLocale().toString(dt_before.deadlineNSecs())).toLatin1()); } { - auto diff = duration_cast(system_after - system_deadline); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); - QDeadlineTimer dt_after(system_after, timerType); + auto reference = duration_cast(system_after - system_reference).count(); + auto diff = duration_cast(system_after - system_deadline).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_after(system_after, timerType); QVERIFY2(now < dt_after, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; after = " + QLocale().toString(dt_after.deadlineNSecs())).toLatin1()); - diff = duration_cast(system_deadline - system_before); - QVERIFY2(diff.count() > minResolution/2, QByteArray::number(qint64(diff.count()))); - QVERIFY2(diff.count() < 3*minResolution/2, QByteArray::number(qint64(diff.count()))); - QDeadlineTimer dt_before(system_before, timerType); + reference = duration_cast(system_reference - system_before).count(); + diff = duration_cast(steady_deadline - steady_before).count(); + QVERIFY2(diff > reference * 0.9 && diff < reference*1.1, QByteArray::number(qint64(diff))); QDeadlineTimer dt_before(system_before, timerType); QVERIFY2(now > dt_before, ("now = " + QLocale().toString(now.deadlineNSecs()) + "; before = " + QLocale().toString(dt_before.deadlineNSecs())).toLatin1()); -- cgit v1.2.3 From 54413653d5fb12bb08b9cbf1554b732bc0b8d1fb Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 19 Feb 2020 14:08:22 +0100 Subject: Rename the endonym members of the Locale type All other members had camelCase names, but the endonyms had prefix_endonym names, requiring munging where they were emitted to XML. So just do that munging upstream in the attribute name of the Locale objects. Makes no change to the data output by the scripts, not even to the intermediate QLocaleXML file. Task-number: QTBUG-81344 Change-Id: I01c15a822216281dc669b3e7ebda096d18b04f9b Reviewed-by: Lars Knoll Reviewed-by: Cristian Maureira-Fredes --- util/locale_database/cldr2qlocalexml.py | 4 ++-- util/locale_database/localexml.py | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/util/locale_database/cldr2qlocalexml.py b/util/locale_database/cldr2qlocalexml.py index a1df872e01..6a0b6cbe1a 100755 --- a/util/locale_database/cldr2qlocalexml.py +++ b/util/locale_database/cldr2qlocalexml.py @@ -340,8 +340,8 @@ def _generateLocaleInfo(path, language_code, script_code, country_code, variant_ endonym = findEntryDef(path, "localeDisplayNames/languages/language[type=%s_%s]" % (language_code, country_code)) if not endonym: endonym = findEntryDef(path, "localeDisplayNames/languages/language[type=%s]" % (language_code)) - result['language_endonym'] = endonym - result['country_endonym'] = findEntryDef(path, "localeDisplayNames/territories/territory[type=%s]" % (country_code)) + result['languageEndonym'] = endonym + result['countryEndonym'] = findEntryDef(path, "localeDisplayNames/territories/territory[type=%s]" % (country_code)) currency_format = get_number_in_system(path, "numbers/currencyFormats/currencyFormatLength/currencyFormat/pattern", numbering_system) currency_format = parse_number_format(currency_format, result) diff --git a/util/locale_database/localexml.py b/util/locale_database/localexml.py index 9b353f5122..187227886f 100644 --- a/util/locale_database/localexml.py +++ b/util/locale_database/localexml.py @@ -190,7 +190,7 @@ class Locale: ('minus', '-'), ('plus', '+'), ('exp', 'e')): print inner + "<%s>" % key + fixOrdStr(get(key), std) + "" % key - for key in ('language_endonym', 'country_endonym', + for key in ('languageEndonym', 'countryEndonym', 'quotationStart', 'quotationEnd', 'alternateQuotationStart', 'alternateQuotationEnd', 'listPatternPartStart', 'listPatternPartMiddle', @@ -208,8 +208,7 @@ class Locale: '_'.join((k, cal)) for k in self.propsMonthDay('months') for cal in calendars): - ent = camelCase(key.split('_')) if key.endswith('_endonym') else key - print inner + "<%s>%s" % (ent, escape(get(key)).encode('utf-8'), ent) + print inner + "<%s>%s" % (key, escape(get(key)).encode('utf-8'), key) for key in ('currencyDigits', 'currencyRounding'): print inner + "<%s>%d" % (key, get(key), key) @@ -283,9 +282,9 @@ class Locale: quantifiers=('k', 'M', 'G', 'T', 'P', 'E')): """Returns an object representing the C locale.""" return cls(dict(cls.__monthNames(calendars)), - language='C', language_code='0', language_endonym='', + language='C', language_code='0', languageEndonym='', script='AnyScript', script_code='0', - country='AnyCountry', country_code='0', country_endonym='', + country='AnyCountry', country_code='0', countryEndonym='', decimal='.', group=',', list=';', percent='%', zero='0', minus='-', plus='+', exp='e', quotationStart='"', quotationEnd='"', -- cgit v1.2.3 From 84382bde5c90e68f7c0e9c70c747fce0867fc128 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 19 Feb 2020 14:13:27 +0100 Subject: Rename the localexml module to qlocalexml It implements interaction with the QLocaleXML file format type, so rename it to match. Task-number: QTBUG-81344 Change-Id: I46302d4ac1038cdfc5929e73b554b6d793814c56 Reviewed-by: Lars Knoll --- util/locale_database/cldr2qlocalexml.py | 2 +- util/locale_database/localexml.py | 312 -------------------------------- util/locale_database/qlocalexml.py | 312 ++++++++++++++++++++++++++++++++ util/locale_database/qlocalexml2cpp.py | 6 +- 4 files changed, 316 insertions(+), 316 deletions(-) delete mode 100644 util/locale_database/localexml.py create mode 100644 util/locale_database/qlocalexml.py diff --git a/util/locale_database/cldr2qlocalexml.py b/util/locale_database/cldr2qlocalexml.py index 6a0b6cbe1a..ee53381b22 100755 --- a/util/locale_database/cldr2qlocalexml.py +++ b/util/locale_database/cldr2qlocalexml.py @@ -61,7 +61,7 @@ import enumdata import xpathlite from xpathlite import DraftResolution, findAlias, findEntry, findTagsInFile from dateconverter import convert_date -from localexml import Locale +from qlocalexml import Locale # TODO: make calendars a command-line option calendars = ['gregorian', 'persian', 'islamic'] # 'hebrew' diff --git a/util/locale_database/localexml.py b/util/locale_database/localexml.py deleted file mode 100644 index 187227886f..0000000000 --- a/util/locale_database/localexml.py +++ /dev/null @@ -1,312 +0,0 @@ -# coding=utf8 -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the test suite of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# -"""Shared serialization-scanning code for QLocaleXML format. - -The Locale class is written by cldr2qlocalexml.py and read by qlocalexml2cpp.py -""" -from xml.sax.saxutils import escape - -import xpathlite - -# Tools used by Locale: -def camel(seq): - yield seq.next() - for word in seq: - yield word.capitalize() - -def camelCase(words): - return ''.join(camel(iter(words))) - -def ordStr(c): - if len(c) == 1: - return str(ord(c)) - raise xpathlite.Error('Unable to handle value "%s"' % addEscapes(c)) - -# Fix for a problem with QLocale returning a character instead of -# strings for QLocale::exponential() and others. So we fallback to -# default values in these cases. -def fixOrdStr(c, d): - return str(ord(c if len(c) == 1 else d)) - -def startCount(c, text): # strspn - """First index in text where it doesn't have a character in c""" - assert text and text[0] in c - try: - return (j for j, d in enumerate(text) if d not in c).next() - except StopIteration: - return len(text) - -def convertFormat(format): - """Convert date/time format-specier from CLDR to Qt - - Match up (as best we can) the differences between: - * https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table - * QDateTimeParser::parseFormat() and QLocalePrivate::dateTimeToString() - """ - result = "" - i = 0 - while i < len(format): - if format[i] == "'": - result += "'" - i += 1 - while i < len(format) and format[i] != "'": - result += format[i] - i += 1 - if i < len(format): - result += "'" - i += 1 - else: - s = format[i:] - if s.startswith('E'): # week-day - n = startCount('E', s) - if n < 3: - result += 'ddd' - elif n == 4: - result += 'dddd' - else: # 5: narrow, 6 short; but should be name, not number :-( - result += 'd' if n < 6 else 'dd' - i += n - elif s[0] in 'ab': # am/pm - # 'b' should distinguish noon/midnight, too :-( - result += "AP" - i += startCount('ab', s) - elif s.startswith('S'): # fractions of seconds: count('S') == number of decimals to show - result += 'z' - i += startCount('S', s) - elif s.startswith('V'): # long time zone specifiers (and a deprecated short ID) - result += 't' - i += startCount('V', s) - elif s[0] in 'zv': # zone - # Should use full name, e.g. "Central European Time", if 'zzzz' :-( - # 'v' should get generic non-location format, e.g. PT for "Pacific Time", no DST indicator - result += "t" - i += startCount('zv', s) - else: - result += format[i] - i += 1 - - return result - -class Locale: - @staticmethod - def propsMonthDay(scale, lengths=('long', 'short', 'narrow')): - for L in lengths: - yield camelCase((L, scale)) - yield camelCase(('standalone', L, scale)) - - # Expected to be numbers, read with int(): - __asint = ("decimal", "group", "zero", - "list", "percent", "minus", "plus", "exp", - "currencyDigits", "currencyRounding") - # Single character; use the code-point number for each: - __asord = ("quotationStart", "quotationEnd", - "alternateQuotationStart", "alternateQuotationEnd") - # Convert day-name to Qt day-of-week number: - __asdow = ("firstDayOfWeek", "weekendStart", "weekendEnd") - # Convert from CLDR format-strings to QDateTimeParser ones: - __asfmt = ("longDateFormat", "shortDateFormat", "longTimeFormat", "shortTimeFormat") - # Just use the raw text: - __astxt = ("language", "languageEndonym", "script", "country", "countryEndonym", - "listPatternPartStart", "listPatternPartMiddle", - "listPatternPartEnd", "listPatternPartTwo", "am", "pm", - 'byte_unit', 'byte_si_quantified', 'byte_iec_quantified', - "currencyIsoCode", "currencySymbol", "currencyDisplayName", - "currencyFormat", "currencyNegativeFormat") - - # Day-of-Week numbering used by Qt: - __qDoW = {"mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, "sun": 7} - - @classmethod - def fromXmlData(cls, lookup, calendars=('gregorian',)): - """Constructor from the contents of XML elements. - - Single parameter, lookup, is called with the names of XML - elements that should contain the relevant data, within a CLDR - locale element (within a localeList element); these names are - used for the attributes of the object constructed. Attribute - values are obtained by suitably digesting the returned element - texts.\n""" - data = {} - for k in cls.__asint: - data['listDelim' if k == 'list' else k] = int(lookup(k)) - - for k in cls.__asord: - value = lookup(k) - assert len(value) == 1, \ - (k, value, 'value should be exactly one character') - data[k] = ord(value) - - for k in cls.__asdow: - data[k] = cls.__qDoW[lookup(k)] - - for k in cls.__asfmt: - data[k] = convertFormat(lookup(k)) - - for k in cls.__astxt + tuple(cls.propsMonthDay('days')): - data[k] = lookup(k) - - for k in cls.propsMonthDay('months'): - data[k] = dict((cal, lookup('_'.join((k, cal)))) for cal in calendars) - - return cls(data) - - def toXml(self, calendars=('gregorian',), indent=' ', tab=' '): - print indent + '' - inner = indent + tab - get = lambda k: getattr(self, k) - for key in ('language', 'script', 'country'): - print inner + "<%s>" % key + get(key) + "" % key - print inner + "<%scode>" % key + get(key + '_code') + "" % key - - for key in ('decimal', 'group', 'zero'): - print inner + "<%s>" % key + ordStr(get(key)) + "" % key - for key, std in (('list', ';'), ('percent', '%'), - ('minus', '-'), ('plus', '+'), ('exp', 'e')): - print inner + "<%s>" % key + fixOrdStr(get(key), std) + "" % key - - for key in ('languageEndonym', 'countryEndonym', - 'quotationStart', 'quotationEnd', - 'alternateQuotationStart', 'alternateQuotationEnd', - 'listPatternPartStart', 'listPatternPartMiddle', - 'listPatternPartEnd', 'listPatternPartTwo', - 'byte_unit', 'byte_si_quantified', 'byte_iec_quantified', - 'am', 'pm', 'firstDayOfWeek', - 'weekendStart', 'weekendEnd', - 'longDateFormat', 'shortDateFormat', - 'longTimeFormat', 'shortTimeFormat', - 'longDays', 'shortDays', 'narrowDays', - 'standaloneLongDays', 'standaloneShortDays', 'standaloneNarrowDays', - 'currencyIsoCode', 'currencySymbol', 'currencyDisplayName', - 'currencyFormat', 'currencyNegativeFormat' - ) + tuple(self.propsMonthDay('days')) + tuple( - '_'.join((k, cal)) - for k in self.propsMonthDay('months') - for cal in calendars): - print inner + "<%s>%s" % (key, escape(get(key)).encode('utf-8'), key) - - for key in ('currencyDigits', 'currencyRounding'): - print inner + "<%s>%d" % (key, get(key), key) - - print indent + "" - - def __init__(self, data=None, **kw): - if data: self.__dict__.update(data) - if kw: self.__dict__.update(kw) - - # Tools used by __monthNames: - def fullName(i, name): return name - def firstThree(i, name): return name[:3] - def initial(i, name): return name[:1] - def number(i, name): return str(i + 1) - def islamicShort(i, name): - if not name: return name - if name == 'Shawwal': return 'Shaw.' - words = name.split() - if words[0].startswith('Dhu'): - words[0] = words[0][:7] + '.' - elif len(words[0]) > 3: - words[0] = words[0][:3] + '.' - return ' '.join(words) - @staticmethod - def __monthNames(calendars, - known={ # Map calendar to (names, extractors...): - 'gregorian': (('January', 'February', 'March', 'April', 'May', 'June', 'July', - 'August', 'September', 'October', 'November', 'December'), - # Extractor pairs, (plain, standalone) - (fullName, fullName), # long - (firstThree, firstThree), # short - (number, initial)), # narrow - 'persian': (('Farvardin', 'Ordibehesht', 'Khordad', 'Tir', 'Mordad', - 'Shahrivar', 'Mehr', 'Aban', 'Azar', 'Dey', 'Bahman', 'Esfand'), - (fullName, fullName), - (firstThree, firstThree), - (number, initial)), - 'islamic': ((u'Muharram', u'Safar', u'RabiÊ» I', u'RabiÊ» II', u'Jumada I', - u'Jumada II', u'Rajab', u'ShaÊ»ban', u'Ramadan', u'Shawwal', - u'DhuÊ»l-QiÊ»dah', u'DhuÊ»l-Hijjah'), - (fullName, fullName), - (islamicShort, islamicShort), - (number, number)), - 'hebrew': (('Tishri', 'Heshvan', 'Kislev', 'Tevet', 'Shevat', 'Adar I', - 'Adar', 'Nisan', 'Iyar', 'Sivan', 'Tamuz', 'Av'), - (fullName, fullName), - (fullName, fullName), - (number, number)), - }, - sizes=('long', 'short', 'narrow')): - for cal in calendars: - try: - data = known[cal] - except KeyError: # Need to add an entry to known, above. - print 'Unsupported calendar:', cal - raise - names, get = data[0] + ('',), data[1:] - for n, size in enumerate(sizes): - yield ('_'.join((camelCase((size, 'months')), cal)), - ';'.join(get[n][0](i, x) for i, x in enumerate(names))) - yield ('_'.join((camelCase(('standalone', size, 'months')), cal)), - ';'.join(get[n][1](i, x) for i, x in enumerate(names))) - del fullName, firstThree, initial, number, islamicShort - - @classmethod - def C(cls, calendars=('gregorian',), - # Empty entry at end to ensure final separator when join()ed: - days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', - 'Thursday', 'Friday', 'Saturday', ''), - quantifiers=('k', 'M', 'G', 'T', 'P', 'E')): - """Returns an object representing the C locale.""" - return cls(dict(cls.__monthNames(calendars)), - language='C', language_code='0', languageEndonym='', - script='AnyScript', script_code='0', - country='AnyCountry', country_code='0', countryEndonym='', - decimal='.', group=',', list=';', percent='%', - zero='0', minus='-', plus='+', exp='e', - quotationStart='"', quotationEnd='"', - alternateQuotationStart='\'', alternateQuotationEnd='\'', - listPatternPartStart='%1, %2', - listPatternPartMiddle='%1, %2', - listPatternPartEnd='%1, %2', - listPatternPartTwo='%1, %2', - byte_unit='bytes', - byte_si_quantified=';'.join(q + 'B' for q in quantifiers), - byte_iec_quantified=';'.join(q.upper() + 'iB' for q in quantifiers), - am='AM', pm='PM', firstDayOfWeek='mon', - weekendStart='sat', weekendEnd='sun', - longDateFormat='EEEE, d MMMM yyyy', shortDateFormat='d MMM yyyy', - longTimeFormat='HH:mm:ss z', shortTimeFormat='HH:mm:ss', - longDays=';'.join(days), - shortDays=';'.join(d[:3] for d in days), - narrowDays='7;1;2;3;4;5;6;', - standaloneLongDays=';'.join(days), - standaloneShortDays=';'.join(d[:3] for d in days), - standaloneNarrowDays=';'.join(d[:1] for d in days), - currencyIsoCode='', currencySymbol='', - currencyDisplayName=';' * 7, - currencyDigits=2, currencyRounding=1, - currencyFormat='%1%2', currencyNegativeFormat='') diff --git a/util/locale_database/qlocalexml.py b/util/locale_database/qlocalexml.py new file mode 100644 index 0000000000..187227886f --- /dev/null +++ b/util/locale_database/qlocalexml.py @@ -0,0 +1,312 @@ +# coding=utf8 +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# +"""Shared serialization-scanning code for QLocaleXML format. + +The Locale class is written by cldr2qlocalexml.py and read by qlocalexml2cpp.py +""" +from xml.sax.saxutils import escape + +import xpathlite + +# Tools used by Locale: +def camel(seq): + yield seq.next() + for word in seq: + yield word.capitalize() + +def camelCase(words): + return ''.join(camel(iter(words))) + +def ordStr(c): + if len(c) == 1: + return str(ord(c)) + raise xpathlite.Error('Unable to handle value "%s"' % addEscapes(c)) + +# Fix for a problem with QLocale returning a character instead of +# strings for QLocale::exponential() and others. So we fallback to +# default values in these cases. +def fixOrdStr(c, d): + return str(ord(c if len(c) == 1 else d)) + +def startCount(c, text): # strspn + """First index in text where it doesn't have a character in c""" + assert text and text[0] in c + try: + return (j for j, d in enumerate(text) if d not in c).next() + except StopIteration: + return len(text) + +def convertFormat(format): + """Convert date/time format-specier from CLDR to Qt + + Match up (as best we can) the differences between: + * https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table + * QDateTimeParser::parseFormat() and QLocalePrivate::dateTimeToString() + """ + result = "" + i = 0 + while i < len(format): + if format[i] == "'": + result += "'" + i += 1 + while i < len(format) and format[i] != "'": + result += format[i] + i += 1 + if i < len(format): + result += "'" + i += 1 + else: + s = format[i:] + if s.startswith('E'): # week-day + n = startCount('E', s) + if n < 3: + result += 'ddd' + elif n == 4: + result += 'dddd' + else: # 5: narrow, 6 short; but should be name, not number :-( + result += 'd' if n < 6 else 'dd' + i += n + elif s[0] in 'ab': # am/pm + # 'b' should distinguish noon/midnight, too :-( + result += "AP" + i += startCount('ab', s) + elif s.startswith('S'): # fractions of seconds: count('S') == number of decimals to show + result += 'z' + i += startCount('S', s) + elif s.startswith('V'): # long time zone specifiers (and a deprecated short ID) + result += 't' + i += startCount('V', s) + elif s[0] in 'zv': # zone + # Should use full name, e.g. "Central European Time", if 'zzzz' :-( + # 'v' should get generic non-location format, e.g. PT for "Pacific Time", no DST indicator + result += "t" + i += startCount('zv', s) + else: + result += format[i] + i += 1 + + return result + +class Locale: + @staticmethod + def propsMonthDay(scale, lengths=('long', 'short', 'narrow')): + for L in lengths: + yield camelCase((L, scale)) + yield camelCase(('standalone', L, scale)) + + # Expected to be numbers, read with int(): + __asint = ("decimal", "group", "zero", + "list", "percent", "minus", "plus", "exp", + "currencyDigits", "currencyRounding") + # Single character; use the code-point number for each: + __asord = ("quotationStart", "quotationEnd", + "alternateQuotationStart", "alternateQuotationEnd") + # Convert day-name to Qt day-of-week number: + __asdow = ("firstDayOfWeek", "weekendStart", "weekendEnd") + # Convert from CLDR format-strings to QDateTimeParser ones: + __asfmt = ("longDateFormat", "shortDateFormat", "longTimeFormat", "shortTimeFormat") + # Just use the raw text: + __astxt = ("language", "languageEndonym", "script", "country", "countryEndonym", + "listPatternPartStart", "listPatternPartMiddle", + "listPatternPartEnd", "listPatternPartTwo", "am", "pm", + 'byte_unit', 'byte_si_quantified', 'byte_iec_quantified', + "currencyIsoCode", "currencySymbol", "currencyDisplayName", + "currencyFormat", "currencyNegativeFormat") + + # Day-of-Week numbering used by Qt: + __qDoW = {"mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, "sun": 7} + + @classmethod + def fromXmlData(cls, lookup, calendars=('gregorian',)): + """Constructor from the contents of XML elements. + + Single parameter, lookup, is called with the names of XML + elements that should contain the relevant data, within a CLDR + locale element (within a localeList element); these names are + used for the attributes of the object constructed. Attribute + values are obtained by suitably digesting the returned element + texts.\n""" + data = {} + for k in cls.__asint: + data['listDelim' if k == 'list' else k] = int(lookup(k)) + + for k in cls.__asord: + value = lookup(k) + assert len(value) == 1, \ + (k, value, 'value should be exactly one character') + data[k] = ord(value) + + for k in cls.__asdow: + data[k] = cls.__qDoW[lookup(k)] + + for k in cls.__asfmt: + data[k] = convertFormat(lookup(k)) + + for k in cls.__astxt + tuple(cls.propsMonthDay('days')): + data[k] = lookup(k) + + for k in cls.propsMonthDay('months'): + data[k] = dict((cal, lookup('_'.join((k, cal)))) for cal in calendars) + + return cls(data) + + def toXml(self, calendars=('gregorian',), indent=' ', tab=' '): + print indent + '' + inner = indent + tab + get = lambda k: getattr(self, k) + for key in ('language', 'script', 'country'): + print inner + "<%s>" % key + get(key) + "" % key + print inner + "<%scode>" % key + get(key + '_code') + "" % key + + for key in ('decimal', 'group', 'zero'): + print inner + "<%s>" % key + ordStr(get(key)) + "" % key + for key, std in (('list', ';'), ('percent', '%'), + ('minus', '-'), ('plus', '+'), ('exp', 'e')): + print inner + "<%s>" % key + fixOrdStr(get(key), std) + "" % key + + for key in ('languageEndonym', 'countryEndonym', + 'quotationStart', 'quotationEnd', + 'alternateQuotationStart', 'alternateQuotationEnd', + 'listPatternPartStart', 'listPatternPartMiddle', + 'listPatternPartEnd', 'listPatternPartTwo', + 'byte_unit', 'byte_si_quantified', 'byte_iec_quantified', + 'am', 'pm', 'firstDayOfWeek', + 'weekendStart', 'weekendEnd', + 'longDateFormat', 'shortDateFormat', + 'longTimeFormat', 'shortTimeFormat', + 'longDays', 'shortDays', 'narrowDays', + 'standaloneLongDays', 'standaloneShortDays', 'standaloneNarrowDays', + 'currencyIsoCode', 'currencySymbol', 'currencyDisplayName', + 'currencyFormat', 'currencyNegativeFormat' + ) + tuple(self.propsMonthDay('days')) + tuple( + '_'.join((k, cal)) + for k in self.propsMonthDay('months') + for cal in calendars): + print inner + "<%s>%s" % (key, escape(get(key)).encode('utf-8'), key) + + for key in ('currencyDigits', 'currencyRounding'): + print inner + "<%s>%d" % (key, get(key), key) + + print indent + "" + + def __init__(self, data=None, **kw): + if data: self.__dict__.update(data) + if kw: self.__dict__.update(kw) + + # Tools used by __monthNames: + def fullName(i, name): return name + def firstThree(i, name): return name[:3] + def initial(i, name): return name[:1] + def number(i, name): return str(i + 1) + def islamicShort(i, name): + if not name: return name + if name == 'Shawwal': return 'Shaw.' + words = name.split() + if words[0].startswith('Dhu'): + words[0] = words[0][:7] + '.' + elif len(words[0]) > 3: + words[0] = words[0][:3] + '.' + return ' '.join(words) + @staticmethod + def __monthNames(calendars, + known={ # Map calendar to (names, extractors...): + 'gregorian': (('January', 'February', 'March', 'April', 'May', 'June', 'July', + 'August', 'September', 'October', 'November', 'December'), + # Extractor pairs, (plain, standalone) + (fullName, fullName), # long + (firstThree, firstThree), # short + (number, initial)), # narrow + 'persian': (('Farvardin', 'Ordibehesht', 'Khordad', 'Tir', 'Mordad', + 'Shahrivar', 'Mehr', 'Aban', 'Azar', 'Dey', 'Bahman', 'Esfand'), + (fullName, fullName), + (firstThree, firstThree), + (number, initial)), + 'islamic': ((u'Muharram', u'Safar', u'RabiÊ» I', u'RabiÊ» II', u'Jumada I', + u'Jumada II', u'Rajab', u'ShaÊ»ban', u'Ramadan', u'Shawwal', + u'DhuÊ»l-QiÊ»dah', u'DhuÊ»l-Hijjah'), + (fullName, fullName), + (islamicShort, islamicShort), + (number, number)), + 'hebrew': (('Tishri', 'Heshvan', 'Kislev', 'Tevet', 'Shevat', 'Adar I', + 'Adar', 'Nisan', 'Iyar', 'Sivan', 'Tamuz', 'Av'), + (fullName, fullName), + (fullName, fullName), + (number, number)), + }, + sizes=('long', 'short', 'narrow')): + for cal in calendars: + try: + data = known[cal] + except KeyError: # Need to add an entry to known, above. + print 'Unsupported calendar:', cal + raise + names, get = data[0] + ('',), data[1:] + for n, size in enumerate(sizes): + yield ('_'.join((camelCase((size, 'months')), cal)), + ';'.join(get[n][0](i, x) for i, x in enumerate(names))) + yield ('_'.join((camelCase(('standalone', size, 'months')), cal)), + ';'.join(get[n][1](i, x) for i, x in enumerate(names))) + del fullName, firstThree, initial, number, islamicShort + + @classmethod + def C(cls, calendars=('gregorian',), + # Empty entry at end to ensure final separator when join()ed: + days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', + 'Thursday', 'Friday', 'Saturday', ''), + quantifiers=('k', 'M', 'G', 'T', 'P', 'E')): + """Returns an object representing the C locale.""" + return cls(dict(cls.__monthNames(calendars)), + language='C', language_code='0', languageEndonym='', + script='AnyScript', script_code='0', + country='AnyCountry', country_code='0', countryEndonym='', + decimal='.', group=',', list=';', percent='%', + zero='0', minus='-', plus='+', exp='e', + quotationStart='"', quotationEnd='"', + alternateQuotationStart='\'', alternateQuotationEnd='\'', + listPatternPartStart='%1, %2', + listPatternPartMiddle='%1, %2', + listPatternPartEnd='%1, %2', + listPatternPartTwo='%1, %2', + byte_unit='bytes', + byte_si_quantified=';'.join(q + 'B' for q in quantifiers), + byte_iec_quantified=';'.join(q.upper() + 'iB' for q in quantifiers), + am='AM', pm='PM', firstDayOfWeek='mon', + weekendStart='sat', weekendEnd='sun', + longDateFormat='EEEE, d MMMM yyyy', shortDateFormat='d MMM yyyy', + longTimeFormat='HH:mm:ss z', shortTimeFormat='HH:mm:ss', + longDays=';'.join(days), + shortDays=';'.join(d[:3] for d in days), + narrowDays='7;1;2;3;4;5;6;', + standaloneLongDays=';'.join(days), + standaloneShortDays=';'.join(d[:3] for d in days), + standaloneNarrowDays=';'.join(d[:1] for d in days), + currencyIsoCode='', currencySymbol='', + currencyDisplayName=';' * 7, + currencyDigits=2, currencyRounding=1, + currencyFormat='%1%2', currencyNegativeFormat='') diff --git a/util/locale_database/qlocalexml2cpp.py b/util/locale_database/qlocalexml2cpp.py index 52e6331569..7c00980bc4 100755 --- a/util/locale_database/qlocalexml2cpp.py +++ b/util/locale_database/qlocalexml2cpp.py @@ -40,7 +40,7 @@ import datetime import xml.dom.minidom from enumdata import language_aliases, country_aliases, script_aliases -from localexml import Locale +from qlocalexml import Locale # TODO: Make calendars a command-line parameter # map { CLDR name: Qt file name } @@ -353,7 +353,7 @@ def main(): if len(sys.argv) != 3: usage() - localexml = sys.argv[1] + qlocalexml = sys.argv[1] qtsrcdir = sys.argv[2] if not (os.path.isdir(qtsrcdir) @@ -370,7 +370,7 @@ def main(): s = qlocaledata_file.readline() data_temp_file.write(GENERATED_BLOCK_START) - doc = xml.dom.minidom.parse(localexml) + doc = xml.dom.minidom.parse(qlocalexml) language_map = loadMap(doc, 'language') script_map = loadMap(doc, 'script') country_map = loadMap(doc, 'country') -- cgit v1.2.3 From 275401f580abe19c1519e3d05acec20c68fd9fa6 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 27 Feb 2020 18:19:59 +0100 Subject: Warn about Q(Date|Time)+ switching to C locale in Qt 6 Change-Id: I3a3afc3fb4ddca405a75097feb15aee0e72b3b19 Reviewed-by: Thiago Macieira --- src/corelib/time/qdatetime.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index b3a12a4a46..fe3ebca6eb 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1285,6 +1285,10 @@ QT_WARNING_POP If the datetime is invalid, an empty string will be returned. + \note If localized month and day names are desired, please switch to using + QLocale::system().toString() as QDate methods shall change to use English (C + locale) names at Qt 6. + \sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString() */ @@ -1786,6 +1790,10 @@ QT_WARNING_POP \snippet code/src_corelib_tools_qdatetime.cpp 3 + \note If localized month and day names are used, please switch to using + QLocale::system().toDate() as QDate methods shall change to only recognize + English (C locale) names at Qt 6. + \sa toString(), QDateTime::fromString(), QTime::fromString(), QLocale::toDate() */ @@ -2146,6 +2154,10 @@ QT_WARNING_POP If the time is invalid, an empty string will be returned. If \a format is empty, the default format "hh:mm:ss" is used. + \note If localized forms of am or pm (the AP, ap, A or a formats) are + desired, please switch to using QLocale::system().toString() as QTime + methods shall change to use English (C locale) at Qt 6. + \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString() */ QString QTime::toString(QStringView format) const @@ -2543,6 +2555,10 @@ QT_WARNING_POP \snippet code/src_corelib_tools_qdatetime.cpp 8 + \note If localized forms of am or pm (the AP, ap, A or a formats) are used, + please switch to using QLocale::system().toTime() as QTime methods shall + change to only recognize English (C locale) at Qt 6. + \sa toString(), QDateTime::fromString(), QDate::fromString(), QLocale::toTime() */ @@ -4465,6 +4481,10 @@ QT_WARNING_POP If the datetime is invalid, an empty string will be returned. + \note If localized month and day names are desired, please switch to using + QLocale::system().toString() as QDateTime methods shall change to use + English (C locale) names at Qt 6. + \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString() */ QString QDateTime::toString(QStringView format) const @@ -5504,6 +5524,10 @@ QT_WARNING_POP \snippet code/src_corelib_tools_qdatetime.cpp 14 + \note If localized month and day names are used, please switch to using + QLocale::system().toDateTime() as QDateTime methods shall change to only + recognize English (C locale) names at Qt 6. + \sa toString(), QDate::fromString(), QTime::fromString(), QLocale::toDateTime() */ -- cgit v1.2.3 From 873eba3f8bdd1151762fae2dfcee733ebdd7c0be Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Mon, 24 Feb 2020 09:50:51 +0200 Subject: Examples: use QDialog::showMaximaized() for Android Examples that use QDialog as main window should be maximized on Android to avoid a black view on most of the screen. Task-number: QTBUG-80717 Change-Id: I933c1a01d95d53da009c190c37fa32f27be5af5e Reviewed-by: BogDan Vatra --- examples/network/http/main.cpp | 6 +++++- examples/widgets/layouts/basiclayouts/main.cpp | 4 ++++ examples/widgets/layouts/dynamiclayouts/main.cpp | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/network/http/main.cpp b/examples/network/http/main.cpp index 1339f2f693..6c86933fd6 100644 --- a/examples/network/http/main.cpp +++ b/examples/network/http/main.cpp @@ -81,7 +81,11 @@ int main(int argc, char *argv[]) const QRect availableSize = httpWin.screen()->availableGeometry(); httpWin.resize(availableSize.width() / 5, availableSize.height() / 5); httpWin.move((availableSize.width() - httpWin.width()) / 2, (availableSize.height() - httpWin.height()) / 2); - +#ifdef Q_OS_ANDROID + httpWin.showMaximized(); +#else httpWin.show(); +#endif + return app.exec(); } diff --git a/examples/widgets/layouts/basiclayouts/main.cpp b/examples/widgets/layouts/basiclayouts/main.cpp index f59de1d385..cf0ff0a535 100644 --- a/examples/widgets/layouts/basiclayouts/main.cpp +++ b/examples/widgets/layouts/basiclayouts/main.cpp @@ -56,7 +56,11 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); Dialog dialog; +#ifdef Q_OS_ANDROID + dialog.showMaximized(); +#else dialog.show(); +#endif return app.exec(); } diff --git a/examples/widgets/layouts/dynamiclayouts/main.cpp b/examples/widgets/layouts/dynamiclayouts/main.cpp index 9959c472f4..cf0ff0a535 100644 --- a/examples/widgets/layouts/dynamiclayouts/main.cpp +++ b/examples/widgets/layouts/dynamiclayouts/main.cpp @@ -56,6 +56,11 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); Dialog dialog; +#ifdef Q_OS_ANDROID + dialog.showMaximized(); +#else dialog.show(); +#endif + return app.exec(); } -- cgit v1.2.3 From 761f46f8b526147b29a324b65d253077f35867a9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 Mar 2020 14:45:39 +0100 Subject: Remove overrides of QImageIOHandler::name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will remove the virtual base class function in Qt 6. For now, name() returns format(). Change-Id: I1597e823b859e4db148b3e5ac0f1c15350a582eb Reviewed-by: Eirik Aavitsland Reviewed-by: Jan Arve Sæther --- src/gui/image/qbmphandler.cpp | 7 ------- src/gui/image/qbmphandler_p.h | 3 --- src/gui/image/qpnghandler.cpp | 7 ------- src/gui/image/qpnghandler_p.h | 4 ---- src/gui/image/qppmhandler.cpp | 7 ------- src/gui/image/qppmhandler_p.h | 4 ---- src/gui/image/qxbmhandler.cpp | 7 ------- src/gui/image/qxbmhandler_p.h | 4 ---- src/gui/image/qxpmhandler.cpp | 7 ------- src/gui/image/qxpmhandler_p.h | 4 ---- src/plugins/imageformats/gif/qgifhandler.cpp | 7 ------- src/plugins/imageformats/gif/qgifhandler_p.h | 4 ---- src/plugins/imageformats/ico/qicohandler.cpp | 11 ----------- src/plugins/imageformats/ico/qicohandler.h | 4 ---- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 7 ------- src/plugins/imageformats/jpeg/qjpeghandler_p.h | 4 ---- 16 files changed, 91 deletions(-) diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 32b6131309..387c7b7746 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -866,13 +866,6 @@ void QBmpHandler::setOption(ImageOption option, const QVariant &value) Q_UNUSED(value); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QBmpHandler::name() const -{ - return formatName(); -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_BMP diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h index 33b5b9c501..fd044fc442 100644 --- a/src/gui/image/qbmphandler_p.h +++ b/src/gui/image/qbmphandler_p.h @@ -113,9 +113,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 8435e5a0fe..f956f254ee 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -1296,13 +1296,6 @@ void QPngHandler::setOption(ImageOption option, const QVariant &value) d->scaledSize = value.toSize(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QPngHandler::name() const -{ - return "png"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/image/qpnghandler_p.h b/src/gui/image/qpnghandler_p.h index 5d4da97395..9e12d2d081 100644 --- a/src/gui/image/qpnghandler_p.h +++ b/src/gui/image/qpnghandler_p.h @@ -69,10 +69,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - QVariant option(ImageOption option) const override; void setOption(ImageOption option, const QVariant &value) override; bool supportsOption(ImageOption option) const override; diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 13ee2eadd2..728259ba9e 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -576,13 +576,6 @@ void QPpmHandler::setOption(ImageOption option, const QVariant &value) subType = value.toByteArray().toLower(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QPpmHandler::name() const -{ - return subType.isEmpty() ? QByteArray("ppm") : subType; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_PPM diff --git a/src/gui/image/qppmhandler_p.h b/src/gui/image/qppmhandler_p.h index 2f3811b759..f2faf93984 100644 --- a/src/gui/image/qppmhandler_p.h +++ b/src/gui/image/qppmhandler_p.h @@ -67,10 +67,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device, QByteArray *subType = nullptr); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp index 3cd15b3e4d..f06561690c 100644 --- a/src/gui/image/qxbmhandler.cpp +++ b/src/gui/image/qxbmhandler.cpp @@ -357,13 +357,6 @@ void QXbmHandler::setOption(ImageOption option, const QVariant &value) fileName = value.toString(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QXbmHandler::name() const -{ - return "xbm"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_XBM diff --git a/src/gui/image/qxbmhandler_p.h b/src/gui/image/qxbmhandler_p.h index ae590a1944..db5f352d46 100644 --- a/src/gui/image/qxbmhandler_p.h +++ b/src/gui/image/qxbmhandler_p.h @@ -66,10 +66,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index f9424b62bb..07fec929bf 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -1280,13 +1280,6 @@ void QXpmHandler::setOption(ImageOption option, const QVariant &value) fileName = value.toString(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QXpmHandler::name() const -{ - return "xpm"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_XPM diff --git a/src/gui/image/qxpmhandler_p.h b/src/gui/image/qxpmhandler_p.h index a4dd88cd17..646e8df69e 100644 --- a/src/gui/image/qxpmhandler_p.h +++ b/src/gui/image/qxpmhandler_p.h @@ -68,10 +68,6 @@ public: static bool canRead(QIODevice *device); -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - QVariant option(ImageOption option) const override; void setOption(ImageOption option, const QVariant &value) override; bool supportsOption(ImageOption option) const override; diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp index c92cc3ea61..61981b305f 100644 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ b/src/plugins/imageformats/gif/qgifhandler.cpp @@ -1215,11 +1215,4 @@ int QGifHandler::currentImageNumber() const return frameNumber; } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QGifHandler::name() const -{ - return "gif"; -} -#endif - QT_END_NAMESPACE diff --git a/src/plugins/imageformats/gif/qgifhandler_p.h b/src/plugins/imageformats/gif/qgifhandler_p.h index c6592043ce..f19777fa18 100644 --- a/src/plugins/imageformats/gif/qgifhandler_p.h +++ b/src/plugins/imageformats/gif/qgifhandler_p.h @@ -73,10 +73,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index eb50f52bd6..88ff1f8391 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -809,17 +809,6 @@ bool QtIcoHandler::write(const QImage &image) return ICOReader::write(device, imgs); } -#if QT_DEPRECATED_SINCE(5, 13) -/*! - * Return the common identifier of the format. - * For ICO format this will return "ico". - */ -QByteArray QtIcoHandler::name() const -{ - return "ico"; -} -#endif - /*! \reimp */ diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h index 328dfce47e..0d44a67dfc 100644 --- a/src/plugins/imageformats/ico/qicohandler.h +++ b/src/plugins/imageformats/ico/qicohandler.h @@ -54,10 +54,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - int imageCount() const override; bool jumpToImage(int imageNumber) override; bool jumpToNextImage() override; diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index c31e2db3c5..fed585a82e 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -1184,11 +1184,4 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) } } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QJpegHandler::name() const -{ - return "jpeg"; -} -#endif - QT_END_NAMESPACE diff --git a/src/plugins/imageformats/jpeg/qjpeghandler_p.h b/src/plugins/imageformats/jpeg/qjpeghandler_p.h index fafa930c11..43ca17317a 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler_p.h +++ b/src/plugins/imageformats/jpeg/qjpeghandler_p.h @@ -68,10 +68,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; -- cgit v1.2.3 From c3fc9a24d8695447416b0eb40590fabea7287444 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 28 Feb 2020 10:53:15 +0100 Subject: Avoid UB in QList::removeAt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always keep the out of bounds check for backwards compatibility, but warn about it, so that we can remove it in Qt 6. Amends commit ebf695bc779a63a5730df05ab246305c0ab342e4 Change-Id: I3f1e7e8f9f20feb0b0f06ff9083c26682f1c7d3b Reviewed-by: Richard Öhlinger Reviewed-by: Thiago Macieira --- src/corelib/tools/qlist.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 37258cc66f..8a11663c01 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -583,10 +583,13 @@ inline void QList::removeAt(int i) { #if !QT_DEPRECATED_SINCE(5, 15) Q_ASSERT_X(i >= 0 && i < p.size(), "QList::removeAt", "index out of range"); -#elif !defined(QT_NO_DEBUG) - if (i < 0 || i >= p.size()) +#endif + if (i < 0 || i >= p.size()) { +#if !defined(QT_NO_DEBUG) qWarning("QList::removeAt(): Index out of range."); #endif + return; + } detach(); node_destruct(reinterpret_cast(p.at(i))); p.remove(i); } -- cgit v1.2.3 From f4fca8697ffaf64a2e919bbbb96fbd2639c7ac60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 25 Feb 2020 16:41:13 +0100 Subject: Undeprecate QHash::count(Key) For compatibility with std::unordered_map. Spotted in the API review. Change-Id: Ic34600d55baebcbbf115c1090cd555984037c44c Reviewed-by: Lars Knoll --- src/corelib/tools/qhash.cpp | 8 -------- src/corelib/tools/qhash.h | 35 ++++++++++++++--------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 15f731a603..7ebc374d9f 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -1574,7 +1574,6 @@ uint qHash(long double key, uint seed) noexcept */ /*! \fn template int QHash::count(const Key &key) const - \obsolete Returns the number of items associated with the \a key. @@ -2693,13 +2692,6 @@ uint qHash(long double key, uint seed) noexcept \sa QHash::remove() */ -/*! \fn template int QMultiHash::count(const Key &key) const - - Returns the number of items associated with the \a key. - - \sa contains(), insert() -*/ - /*! \fn template int QMultiHash::count(const Key &key, const T &value) const \since 4.3 diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 9144405501..06313d6c79 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -314,8 +314,8 @@ public: #if QT_DEPRECATED_SINCE(5, 15) QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList uniqueKeys() const; QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList values(const Key &key) const; - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") int count(const Key &key) const; #endif + int count(const Key &key) const; class const_iterator; @@ -729,6 +729,19 @@ Q_OUTOFLINE_TEMPLATE QList QHash::values() const return res; } +template +Q_OUTOFLINE_TEMPLATE int QHash::count(const Key &akey) const +{ + int cnt = 0; + Node *node = *findNode(akey); + if (node != e) { + do { + ++cnt; + } while ((node = node->next) != e && node->key == akey); + } + return cnt; +} + template Q_INLINE_TEMPLATE const T QHash::operator[](const Key &akey) const { @@ -1072,7 +1085,6 @@ public: int remove(const Key &key, const T &value); - int count(const Key &key) const; int count(const Key &key, const T &value) const; QList uniqueKeys() const; @@ -1225,12 +1237,6 @@ Q_OUTOFLINE_TEMPLATE QList QHash::values(const Key &akey) const return static_cast *>(this)->values(akey); } -template -Q_OUTOFLINE_TEMPLATE int QHash::count(const Key &akey) const -{ - return static_cast *>(this)->count(akey); -} - template Q_OUTOFLINE_TEMPLATE QList QHash::uniqueKeys() const { @@ -1251,19 +1257,6 @@ Q_OUTOFLINE_TEMPLATE QList QMultiHash::values(const Key &akey) const return res; } -template -Q_OUTOFLINE_TEMPLATE int QMultiHash::count(const Key &akey) const -{ - int cnt = 0; - Node *node = *findNode(akey); - if (node != this->e) { - do { - ++cnt; - } while ((node = node->next) != this->e && node->key == akey); - } - return cnt; -} - #if !defined(QT_NO_JAVA_STYLE_ITERATORS) template class QHashIterator -- cgit v1.2.3 From bac89e2f49c1b7dda063aad8635a5d3cffad2c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 25 Feb 2020 16:50:55 +0100 Subject: QMap/QHash: Use versioned deprecation macro Because then it can be configured Change-Id: Ib4c20dd64bedfe2ebadf13283698c50d4c0bc527 Reviewed-by: Lars Knoll --- src/corelib/tools/qhash.h | 8 ++++---- src/corelib/tools/qmap.h | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 06313d6c79..5078019602 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -312,8 +312,8 @@ public: QList keys(const T &value) const; QList values() const; #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList uniqueKeys() const; - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList values(const Key &key) const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList uniqueKeys() const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList values(const Key &key) const; #endif int count(const Key &key) const; @@ -531,8 +531,8 @@ public: iterator insert(const Key &key, const T &value); void insert(const QHash &hash); #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); - QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QHash &unite(const QHash &other); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QHash &unite(const QHash &other); #endif // STL compatibility diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 427a4ad5a0..21628032c8 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -384,9 +384,9 @@ public: QList keys(const T &value) const; QList values() const; #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QList uniqueKeys() const; - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QList values(const Key &key) const; - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") int count(const Key &key) const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList uniqueKeys() const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList values(const Key &key) const; + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") int count(const Key &key) const; #endif @@ -585,9 +585,9 @@ public: iterator insert(const_iterator pos, const Key &key, const T &value); void insert(const QMap &map); #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const_iterator pos, const Key &akey, const T &avalue); - QT_DEPRECATED_X("Use QMultiMap for maps storing multiple values with the same key.") QMap &unite(const QMap &other); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") iterator insertMulti(const_iterator pos, const Key &akey, const T &avalue); + QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QMap &unite(const QMap &other); #endif // STL compatibility -- cgit v1.2.3 From b30b3248caff5f3221e2de62a35bc16decb93b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 26 Feb 2020 14:53:07 +0100 Subject: QMap: undeprecate QMap::count(Key) For compatibility with std::map Change-Id: Icba536244aadcad97c59dfd4bb22a7fdea881a7b Reviewed-by: Lars Knoll --- src/corelib/tools/qmap.cpp | 8 +------- src/corelib/tools/qmap.h | 43 ++++++++++++++++++------------------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 6d2b8f7a3e..25ea5f25d7 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -814,11 +814,10 @@ void QMapDataBase::freeData(QMapDataBase *d) */ /*! \fn template int QMap::count(const Key &key) const - \obsolete Returns the number of items associated with key \a key. - \sa QMultiMap::count() + \sa contains(), QMultiMap::count() */ /*! \fn template int QMap::count() const @@ -2115,11 +2114,6 @@ void QMapDataBase::freeData(QMapDataBase *d) inserted one. */ -/*! \fn template int QMultiMap::count(const Key &key) const - - Returns the number of items associated with key \a key. -*/ - /*! \fn template QList QMultiMap::uniqueKeys() const \since 4.2 diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 21628032c8..0c69d13295 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -386,8 +386,8 @@ public: #if QT_DEPRECATED_SINCE(5, 15) QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList uniqueKeys() const; QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList values(const Key &key) const; - QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") int count(const Key &key) const; #endif + int count(const Key &key) const; inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); } @@ -680,6 +680,23 @@ Q_INLINE_TEMPLATE T &QMap::operator[](const Key &akey) return n->value; } +template +Q_INLINE_TEMPLATE int QMap::count(const Key &akey) const +{ + Node *firstNode; + Node *lastNode; + d->nodeRange(akey, &firstNode, &lastNode); + + const_iterator ci_first(firstNode); + const const_iterator ci_last(lastNode); + int cnt = 0; + while (ci_first != ci_last) { + ++cnt; + ++ci_first; + } + return cnt; +} + template Q_INLINE_TEMPLATE bool QMap::contains(const Key &akey) const { @@ -1142,7 +1159,6 @@ public: int remove(const Key &key, const T &value); - int count(const Key &key) const; int count(const Key &key, const T &value) const; typename QMap::iterator find(const Key &key, const T &value) { @@ -1315,23 +1331,6 @@ Q_INLINE_TEMPLATE int QMultiMap::remove(const Key &key, const T &value) return n; } -template -Q_INLINE_TEMPLATE int QMultiMap::count(const Key &akey) const -{ - QMultiMap::Node *firstNode; - QMultiMap::Node *lastNode; - this->d->nodeRange(akey, &firstNode, &lastNode); - - typename QMap::const_iterator ci_first(firstNode); - const typename QMap::const_iterator ci_last(lastNode); - int cnt = 0; - while (ci_first != ci_last) { - ++cnt; - ++ci_first; - } - return cnt; -} - template Q_INLINE_TEMPLATE int QMultiMap::count(const Key &key, const T &value) const { @@ -1359,12 +1358,6 @@ QList QMap::values(const Key &key) const return static_cast *>(this)->values(key); } -template -int QMap::count(const Key &key) const -{ - return static_cast *>(this)->count(key); -} - template typename QMap::iterator QMap::insertMulti(const Key &key, const T &value) { -- cgit v1.2.3 From 23fd7bdf01ae81ca6ae0bd741bb4d82784e762d0 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 10:09:48 +0100 Subject: macOS: MoltenVK: Pass in the layer instead of the view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surface creation may be triggered on a thread other than the main thread. To enable this, MoltenVK also accepts the CAMetalLayer instead of the NSView. See https://github.com/KhronosGroup/MoltenVK/pull/258 Task-number: QTBUG-82600 Change-Id: I7b925210d05235baf04441682760f09fe58d8144 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoavulkaninstance.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index 7ce78ee738..94c0a11b84 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -81,7 +81,7 @@ VkSurfaceKHR QCocoaVulkanInstance::createSurface(NSView *view) surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; surfaceInfo.pNext = nullptr; surfaceInfo.flags = 0; - surfaceInfo.pView = view; + surfaceInfo.pView = view.layer; VkSurfaceKHR surface = nullptr; VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); -- cgit v1.2.3 From 7b8616859adcb0c8b38591b0e9c1165c986bad92 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 09:58:50 +0100 Subject: Do not constantly create new surfaces with MoltenVK on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Querying the VkSurfaceKHR for a window is expected to create the surface once and then return the same value afterwards. Task-number: QTBUG-82600 Change-Id: Ib3e99dfca4d940de1a14348eb1909d372a7dde04 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoanativeinterface.mm | 2 +- src/plugins/platforms/cocoa/qcocoavulkaninstance.h | 6 ++++-- src/plugins/platforms/cocoa/qcocoavulkaninstance.mm | 7 +++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index d0e69bdca5..450329f569 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -107,7 +107,7 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS #if QT_CONFIG(vulkan) } else if (resourceString == "vkSurface") { if (QVulkanInstance *instance = window->vulkanInstance()) - return static_cast(instance->handle())->createSurface(window); + return static_cast(instance->handle())->surface(window); #endif } return nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h index 5fe6a612af..2a8d04757e 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h @@ -61,9 +61,11 @@ public: void createOrAdoptInstance() override; - VkSurfaceKHR *createSurface(QWindow *window); - VkSurfaceKHR createSurface(NSView *view); + VkSurfaceKHR *surface(QWindow *window); + private: + VkSurfaceKHR createSurface(NSView *view); + QVulkanInstance *m_instance = nullptr; QLibrary m_lib; VkSurfaceKHR m_nullSurface = nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index 94c0a11b84..9e714859f2 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -57,12 +57,11 @@ void QCocoaVulkanInstance::createOrAdoptInstance() initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface")); } -VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window) +VkSurfaceKHR *QCocoaVulkanInstance::surface(QWindow *window) { QCocoaWindow *cocoaWindow = static_cast(window->handle()); - if (cocoaWindow->m_vulkanSurface) - destroySurface(cocoaWindow->m_vulkanSurface); - cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view); + if (!cocoaWindow->m_vulkanSurface) + cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view); return &cocoaWindow->m_vulkanSurface; } -- cgit v1.2.3 From 753e4d82be966b82ff6ba41a0e7c4452f494790a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sun, 23 Feb 2020 15:05:44 +0100 Subject: rhi: Execute pending host writes on nativeBuffer() query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise it is impossible to write an application that pulls out the VkBuffer for a Dynamic QRhiBuffer, and then uses it with custom Vulkan operations that read from the buffer. More precisely, the problem arises only if the buffer in question is not used in combination with any QRhi operations, because in that case there is nothing that would trigger doing the host writes queued up by a resource batch's updateDynamicBuffer(). Task-number: QTBUG-82435 Change-Id: Ieb54422f1493921bc6d4d029be56130cd3a1362a Reviewed-by: Christian Strømme --- src/gui/rhi/qrhi.cpp | 8 +++----- src/gui/rhi/qrhid3d11.cpp | 12 ++++++++---- src/gui/rhi/qrhid3d11_p_p.h | 2 +- src/gui/rhi/qrhimetal.mm | 23 +++++++++++++++-------- src/gui/rhi/qrhimetal_p_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 25 ++++++++++++++----------- src/gui/rhi/qrhivulkan_p_p.h | 2 +- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 7a0d53e1e4..6243bcda58 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2048,11 +2048,9 @@ QRhiResource::Type QRhiBuffer::resourceType() const UniformBuffer may not even be backed by a native buffer object at all if uniform buffers are not used or supported by a given backend and graphics API. There are also differences to how data is written to the buffer and - the type of backing memory used, and, if host visible memory is involved, - when memory writes become available and visible. Therefore, in general it - is recommended to limit native buffer object access to vertex and index - buffers with types Static or Immutable, because these operate in a - relatively uniform manner with all backends. + the type of backing memory used. For buffers backed by host visible memory, + calling this function guarantees that pending host writes are executed for + all the returned native buffers. \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight */ diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index f7c7f4a9f2..ce39b42cf5 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -608,7 +608,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind { QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWrites(bufD); if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) { srbUpdate = true; @@ -725,7 +725,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWrites(bufD); if (cbD->currentVertexBuffers[inputSlot] != bufD->buffer || cbD->currentVertexOffsets[inputSlot] != bindings[i].second) @@ -757,7 +757,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, QD3D11Buffer *ibufD = QRHI_RES(QD3D11Buffer, indexBuf); Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer)); if (ibufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(ibufD); + executeBufferHostWrites(ibufD); const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; @@ -1920,7 +1920,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.finish(); } -void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD) +void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) { if (!bufD->hasPendingDynamicUpdates) return; @@ -2388,6 +2388,10 @@ bool QD3D11Buffer::build() QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer() { + if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiD3D11); + rhiD->executeBufferHostWrites(this); + } return { { &buffer }, 1 }; } diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 04751397f7..b70f541c68 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -643,7 +643,7 @@ public: int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD); - void executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD); + void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 48a562ef1d..314c58b0b7 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -1827,16 +1827,15 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate } // this handles all types of buffers, not just Dynamic -void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) +void QRhiMetal::executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot) { - const int idx = bufD->d->slotted ? currentFrameSlot : 0; - if (bufD->d->pendingUpdates[idx].isEmpty()) + if (bufD->d->pendingUpdates[slot].isEmpty()) return; - void *p = [bufD->d->buf[idx] contents]; + void *p = [bufD->d->buf[slot] contents]; int changeBegin = -1; int changeEnd = -1; - for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[idx])) { + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[slot])) { Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf)); memcpy(static_cast(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -1846,10 +1845,15 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) } #ifdef Q_OS_MACOS if (changeBegin >= 0 && bufD->d->managed) - [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; + [bufD->d->buf[slot] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; #endif - bufD->d->pendingUpdates[idx].clear(); + bufD->d->pendingUpdates[slot].clear(); +} + +void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) +{ + executeBufferHostWritesForSlot(bufD, bufD->d->slotted ? currentFrameSlot : 0); } void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) @@ -2205,8 +2209,11 @@ QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer() if (d->slotted) { NativeBuffer b; Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QMTL_FRAMES_IN_FLIGHT)); - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) { + QRHI_RES_RHI(QRhiMetal); + rhiD->executeBufferHostWritesForSlot(this, i); b.objects[i] = &d->buf[i]; + } b.slotCount = QMTL_FRAMES_IN_FLIGHT; return b; } diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 212b731b71..a5af5611a6 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -437,6 +437,7 @@ public: int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, qsizetype *curOfs); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); + void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot); void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD); static const int SUPPORTED_STAGES = 3; void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index d378e2a4ad..8f6f118c9b 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2903,7 +2903,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) { QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf); if (bufD->m_type == QRhiBuffer::Dynamic) { - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); void *p = nullptr; VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]); VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p); @@ -3300,14 +3300,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat ud->free(); } -void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) +void QRhiVulkan::executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot) { - if (bufD->pendingDynamicUpdates[currentFrameSlot].isEmpty()) + if (bufD->pendingDynamicUpdates[slot].isEmpty()) return; Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic); void *p = nullptr; - VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]); + VmaAllocation a = toVmaAllocation(bufD->allocations[slot]); // The vmaMap/Unmap are basically a no-op when persistently mapped since it // refcounts; this is great because we don't need to care if the allocation // was created as persistently mapped or not. @@ -3318,7 +3318,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) } int changeBegin = -1; int changeEnd = -1; - for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[currentFrameSlot])) { + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[slot])) { Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf)); memcpy(static_cast(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -3330,7 +3330,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) if (changeBegin >= 0) vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin)); - bufD->pendingDynamicUpdates[currentFrameSlot].clear(); + bufD->pendingDynamicUpdates[slot].clear(); } static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator) @@ -4166,7 +4166,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); bufD->lastActiveFrameSlot = currentFrameSlot; trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0, @@ -4240,7 +4240,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); bufD->lastActiveFrameSlot = currentFrameSlot; QRhiPassResourceTracker::BufferAccess access; @@ -4349,7 +4349,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer)); bufD->lastActiveFrameSlot = currentFrameSlot; if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0]; if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf @@ -4395,7 +4395,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer)); ibufD->lastActiveFrameSlot = currentFrameSlot; if (ibufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(ibufD); + executeBufferHostWritesForSlot(ibufD, currentFrameSlot); const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0; const VkBuffer vkindexbuf = ibufD->buffers[slot]; @@ -5188,10 +5188,13 @@ bool QVkBuffer::build() QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer() { if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiVulkan); NativeBuffer b; Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QVK_FRAMES_IN_FLIGHT)); - for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) + for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) { + rhiD->executeBufferHostWritesForSlot(this, i); b.objects[i] = &buffers[i]; + } b.slotCount = QVK_FRAMES_IN_FLIGHT; return b; } diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 6322882569..0f0a89cbff 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -778,7 +778,7 @@ public: size_t *curOfs, void *mp, BufferImageCopyList *copyInfos); void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates); - void executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD); + void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot); void enqueueTransitionPassResources(QVkCommandBuffer *cbD); void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD); void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, -- cgit v1.2.3 From 5bbc9986f99a5d61c2e43b79fe815ea8ca450fcd Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 26 Feb 2020 15:07:49 +0100 Subject: rhi: d3d: Use native resource binding mapping table when present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer versions of QShaderBaker will now use distinct, zero-based b, t+s, and u register spaces in the generated HLSL source. If this is the case, the native resource binding map (which so far we only used with Metal) contains the SPIR-V binding -> HLSL register binding mappings. This way we won't end up with invalid resource binding attempts (consider that e.g. D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT is only 16), just because, for example, a combined image sampler had a binding of 18 which then got blindly mapped to s18 and t18 in HLSL. Task-number: QTBUG-82472 Change-Id: I8bdcb5378634cf159f6367424582f9e9e5821c8e Reviewed-by: Christian Strømme --- src/gui/rhi/qrhid3d11.cpp | 257 ++++++++++++++++++++++++++++++++++---------- src/gui/rhi/qrhid3d11_p_p.h | 22 +++- 2 files changed, 215 insertions(+), 64 deletions(-) diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index ce39b42cf5..7b583e6fd2 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -580,6 +580,11 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline } } +static const int RBM_SUPPORTED_STAGES = 3; +static const int RBM_VERTEX = 0; +static const int RBM_FRAGMENT = 1; +static const int RBM_COMPUTE = 2; + void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) @@ -667,8 +672,17 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind } } - if (srbUpdate) - updateShaderResourceBindings(srbD); + if (srbUpdate) { + const QShader::NativeResourceBindingMap *resBindMaps[RBM_SUPPORTED_STAGES]; + memset(resBindMaps, 0, sizeof(resBindMaps)); + if (gfxPsD) { + resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap; + resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap; + } else { + resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap; + } + updateShaderResourceBindings(srbD, resBindMaps); + } const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb); const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation; @@ -1774,7 +1788,26 @@ void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z) cbD->commands.append(cmd); } -void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) +static inline QPair mapBinding(int binding, + int stageIndex, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) +{ + const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex]; + if (!map || map->isEmpty()) + return { binding, binding }; // old QShader versions do not have this map, assume 1:1 mapping then + + auto it = map->constFind(binding); + if (it != map->cend()) + return *it; + + // Hitting this path is normal too. It is not given that the resource is + // present in the shaders for all the stages specified by the visibility + // mask in the QRhiShaderResourceBinding. + return { -1, -1 }; +} + +void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) { srbD->vsubufs.clear(); srbD->vsubufoffsets.clear(); @@ -1799,6 +1832,31 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.clear(); + struct Stage { + struct Buffer { + int breg; // b0, b1, ... + ID3D11Buffer *buffer; + uint offsetInConstants; + uint sizeInConstants; + }; + struct Texture { + int treg; // t0, t1, ... + ID3D11ShaderResourceView *srv; + }; + struct Sampler { + int sreg; // s0, s1, ... + ID3D11SamplerState *sampler; + }; + struct Uav { + int ureg; + ID3D11UnorderedAccessView *uav; + }; + QVarLengthArray buffers; + QVarLengthArray textures; + QVarLengthArray samplers; + QVarLengthArray uavs; + } res[RBM_SUPPORTED_STAGES]; + for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); @@ -1818,26 +1876,24 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) // (ByteWidth) is always a multiple of 256. const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - srbD->vsubufs.feed(b->binding, bufD->buffer); - srbD->vsubufoffsets.feed(b->binding, offsetInConstants); - srbD->vsubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_VERTEX].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fsubufs.feed(b->binding, bufD->buffer); - srbD->fsubufoffsets.feed(b->binding, offsetInConstants); - srbD->fsubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_FRAGMENT].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->csubufs.feed(b->binding, bufD->buffer); - srbD->csubufoffsets.feed(b->binding, offsetInConstants); - srbD->csubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_COMPUTE].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } } break; case QRhiShaderResourceBinding::SampledTexture: { - // A sampler with binding N is mapped to a HLSL sampler and texture - // with registers sN and tN by SPIRV-Cross. QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex); QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler); bd.stex.texId = texD->m_id; @@ -1845,16 +1901,25 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.stex.samplerId = samplerD->m_id; bd.stex.samplerGeneration = samplerD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - srbD->vssamplers.feed(b->binding, samplerD->samplerState); - srbD->vsshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fssamplers.feed(b->binding, samplerD->samplerState); - srbD->fsshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->cssamplers.feed(b->binding, samplerD->samplerState); - srbD->csshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } } break; @@ -1866,9 +1931,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.simage.id = texD->m_id; bd.simage.generation = texD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); - if (uav) - srbD->csUAVs.feed(b->binding, uav); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) { + ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); + if (uav) + res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav }); + } } else { qWarning("Unordered access only supported at compute stage"); } @@ -1882,9 +1950,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.sbuf.id = bufD->m_id; bd.sbuf.generation = bufD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); - if (uav) - srbD->csUAVs.feed(b->binding, uav); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) { + ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); + if (uav) + res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav }); + } } else { qWarning("Unordered access only supported at compute stage"); } @@ -1896,27 +1967,75 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) } } + // QRhiBatchedBindings works with the native bindings and expects + // sorted input. The pre-sorted QRhiShaderResourceBinding list (based + // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we + // have to sort here every time. + for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) { + std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) { + return a.breg < b.breg; + }); + std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) { + return a.treg < b.treg; + }); + std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) { + return a.sreg < b.sreg; + }); + std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) { + return a.ureg < b.ureg; + }); + } + + for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) { + srbD->vsubufs.feed(buf.breg, buf.buffer); + srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->vsubufs.finish(); srbD->vsubufoffsets.finish(); srbD->vsubufsizes.finish(); + for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) { + srbD->fsubufs.feed(buf.breg, buf.buffer); + srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->fsubufs.finish(); srbD->fsubufoffsets.finish(); srbD->fsubufsizes.finish(); + for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) { + srbD->csubufs.feed(buf.breg, buf.buffer); + srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->csubufs.finish(); srbD->csubufoffsets.finish(); srbD->csubufsizes.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_VERTEX].textures)) + srbD->vsshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_VERTEX].samplers)) + srbD->vssamplers.feed(s.sreg, s.sampler); srbD->vssamplers.finish(); srbD->vsshaderresources.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_FRAGMENT].textures)) + srbD->fsshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_FRAGMENT].samplers)) + srbD->fssamplers.feed(s.sreg, s.sampler); srbD->fssamplers.finish(); srbD->fsshaderresources.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_COMPUTE].textures)) + srbD->csshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_COMPUTE].samplers)) + srbD->cssamplers.feed(s.sreg, s.sampler); srbD->cssamplers.finish(); srbD->csshaderresources.finish(); + for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs)) + srbD->csUAVs.feed(u.ureg, u.uav); srbD->csUAVs.finish(); } @@ -2205,8 +2324,8 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * case QD3D11CommandBuffer::Command::BindGraphicsPipeline: { QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps; - context->VSSetShader(psD->vs, nullptr, 0); - context->PSSetShader(psD->fs, nullptr, 0); + context->VSSetShader(psD->vs.shader, nullptr, 0); + context->PSSetShader(psD->fs.shader, nullptr, 0); context->IASetPrimitiveTopology(psD->d3dTopology); context->IASetInputLayout(psD->inputLayout); context->OMSetDepthStencilState(psD->dsState, stencilRef); @@ -2281,7 +2400,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * annotations->SetMarker(reinterpret_cast(QString::fromLatin1(cmd.args.debugMark.s).utf16())); break; case QD3D11CommandBuffer::Command::BindComputePipeline: - context->CSSetShader(cmd.args.bindComputePipeline.ps->cs, nullptr, 0); + context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0); break; case QD3D11CommandBuffer::Command::Dispatch: context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z); @@ -3137,6 +3256,7 @@ QD3D11ShaderResourceBindings::~QD3D11ShaderResourceBindings() void QD3D11ShaderResourceBindings::release() { sortedBindings.clear(); + boundResourceData.clear(); } bool QD3D11ShaderResourceBindings::build() @@ -3153,8 +3273,8 @@ bool QD3D11ShaderResourceBindings::build() boundResourceData.resize(sortedBindings.count()); - QRHI_RES_RHI(QRhiD3D11); - rhiD->updateShaderResourceBindings(this); + for (BoundResourceData &bd : boundResourceData) + memset(&bd, 0, sizeof(BoundResourceData)); generation += 1; return true; @@ -3195,15 +3315,17 @@ void QD3D11GraphicsPipeline::release() rastState = nullptr; } - if (vs) { - vs->Release(); - vs = nullptr; + if (vs.shader) { + vs.shader->Release(); + vs.shader = nullptr; } + vs.nativeResourceBindingMap.clear(); - if (fs) { - fs->Release(); - fs = nullptr; + if (fs.shader) { + fs.shader->Release(); + fs.shader = nullptr; } + fs.nativeResourceBindingMap.clear(); rhiD->unregisterResource(this); } @@ -3405,13 +3527,14 @@ static pD3DCompile resolveD3DCompile() return nullptr; } -static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error) +static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey) { QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant }); if (!dxbc.shader().isEmpty()) return dxbc.shader(); - QShaderCode hlslSource = shader.shader({ QShader::HlslShader, 50, shaderVariant }); + const QShaderKey key = { QShader::HlslShader, 50, shaderVariant }; + QShaderCode hlslSource = shader.shader(key); if (hlslSource.shader().isEmpty()) { qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader; return QByteArray(); @@ -3463,6 +3586,9 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian return QByteArray(); } + if (usedShaderKey) + *usedShaderKey = key; + QByteArray result; result.resize(int(bytecode->GetBufferSize())); memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size())); @@ -3554,20 +3680,23 @@ bool QD3D11GraphicsPipeline::build() if (cacheIt != rhiD->m_shaderCache.constEnd()) { switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - vs = static_cast(cacheIt->s); - vs->AddRef(); + vs.shader = static_cast(cacheIt->s); + vs.shader->AddRef(); vsByteCode = cacheIt->bytecode; + vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; case QRhiShaderStage::Fragment: - fs = static_cast(cacheIt->s); - fs->AddRef(); + fs.shader = static_cast(cacheIt->s); + fs.shader->AddRef(); + fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; default: break; } } else { QString error; - const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error); + QShaderKey shaderKey; + const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error, &shaderKey); if (bytecode.isEmpty()) { qWarning("HLSL shader compilation failed: %s", qPrintable(error)); return false; @@ -3580,23 +3709,27 @@ bool QD3D11GraphicsPipeline::build() switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs); + hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader); if (FAILED(hr)) { qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr))); return false; } vsByteCode = bytecode; - rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode)); - vs->AddRef(); + if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey)) + vs.nativeResourceBindingMap = *map; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap)); + vs.shader->AddRef(); break; case QRhiShaderStage::Fragment: - hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs); + hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader); if (FAILED(hr)) { qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr))); return false; } - rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode)); - fs->AddRef(); + if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey)) + fs.nativeResourceBindingMap = *map; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap)); + fs.shader->AddRef(); break; default: break; @@ -3655,46 +3788,52 @@ void QD3D11ComputePipeline::release() { QRHI_RES_RHI(QRhiD3D11); - if (!cs) + if (!cs.shader) return; - cs->Release(); - cs = nullptr; + cs.shader->Release(); + cs.shader = nullptr; + cs.nativeResourceBindingMap.clear(); rhiD->unregisterResource(this); } bool QD3D11ComputePipeline::build() { - if (cs) + if (cs.shader) release(); QRHI_RES_RHI(QRhiD3D11); auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage); if (cacheIt != rhiD->m_shaderCache.constEnd()) { - cs = static_cast(cacheIt->s); + cs.shader = static_cast(cacheIt->s); + cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; } else { QString error; - const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error); + QShaderKey shaderKey; + const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error, &shaderKey); if (bytecode.isEmpty()) { qWarning("HLSL compute shader compilation failed: %s", qPrintable(error)); return false; } - HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs); + HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader); if (FAILED(hr)) { qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); return false; } + if (const QShader::NativeResourceBindingMap *map = m_shaderStage.shader().nativeResourceBindingMap(shaderKey)) + cs.nativeResourceBindingMap = *map; + if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) rhiD->clearShaderCache(); - rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode)); + rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap)); } - cs->AddRef(); + cs.shader->AddRef(); generation += 1; rhiD->registerResource(this); diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index b70f541c68..f749b612b5 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -270,8 +270,14 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline ID3D11DepthStencilState *dsState = nullptr; ID3D11BlendState *blendState = nullptr; - ID3D11VertexShader *vs = nullptr; - ID3D11PixelShader *fs = nullptr; + struct { + ID3D11VertexShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } vs; + struct { + ID3D11PixelShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } fs; ID3D11InputLayout *inputLayout = nullptr; D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; ID3D11RasterizerState *rastState = nullptr; @@ -286,7 +292,10 @@ struct QD3D11ComputePipeline : public QRhiComputePipeline void release() override; bool build() override; - ID3D11ComputeShader *cs = nullptr; + struct { + ID3D11ComputeShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } cs; uint generation = 0; friend class QRhiD3D11; }; @@ -642,7 +651,8 @@ public: void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); - void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD); + void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]); void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, @@ -701,9 +711,11 @@ public: struct Shader { Shader() = default; - Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { } + Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm) + : s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { } IUnknown *s; QByteArray bytecode; + QShader::NativeResourceBindingMap nativeResourceBindingMap; }; QHash m_shaderCache; -- cgit v1.2.3 From bd2b77120e1db8cb991aff23dd1f99cec792fa8e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 15:38:07 +0100 Subject: rhi: vulkan: Sanitize device extension handling Instead of qputenv("QT_VULKAN_DEVICE_EXTENSIONS", "VK_KHR_get_memory_requirements2;VK_NV_ray_tracing"); one can now do params.deviceExtensions = { "VK_KHR_get_memory_requirements2", "VK_NV_ray_tracing" }; on the QRhiVulkanInitParams passed to QRhi::create(). The environment variable stays important for Qt Quick applications, which provide no configurability for the QRhi construction (yet). On the other hand, applications using QRhi directly can now also use the new approach to specify the list of device extensions to enable. In addition, take QVulkanInfoVector into use. There is no reason not to rely on the infrastructure provided by QVulkanInstance. This also implies showing an informative warning for unsupported extensions, instead of merely failing the device creation. (applications will likely not be able to recover of course, but at least the reason for failing is made obvious this way) Task-number: QTBUG-82435 Change-Id: Ib47fd1a10c02be5ceef2c973e61e896c34f92fa3 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhivulkan.cpp | 60 +++++++++++++++++++++++++++++++------------- src/gui/rhi/qrhivulkan_p.h | 1 + src/gui/rhi/qrhivulkan_p_p.h | 1 + 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 8f6f118c9b..60ab15e89d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -149,6 +149,10 @@ QT_BEGIN_NAMESPACE for other windows as well, as long as they all have their QWindow::surfaceType() set to QSurface::VulkanSurface. + To request additional extensions to be enabled on the Vulkan device, list them + in deviceExtensions. This can be relevant when integrating with native Vulkan + rendering code. + \section2 Working with existing Vulkan devices When interoperating with another graphics engine, it may be necessary to @@ -299,6 +303,7 @@ QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *im { inst = params->inst; maybeWindow = params->window; // may be null + requestedDeviceExtensions = params->deviceExtensions; importedDevice = importDevice != nullptr; if (importedDevice) { @@ -463,40 +468,59 @@ bool QRhiVulkan::create(QRhi::Flags flags) if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation")) devLayers.append("VK_LAYER_LUNARG_standard_validation"); + QVulkanInfoVector devExts; uint32_t devExtCount = 0; f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, nullptr); - QVector devExts(devExtCount); - f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, devExts.data()); + if (devExtCount) { + QVector extProps(devExtCount); + f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, extProps.data()); + for (const VkExtensionProperties &p : qAsConst(extProps)) + devExts.append({ p.extensionName, p.specVersion }); + } qCDebug(QRHI_LOG_INFO, "%d device extensions available", devExts.count()); QVector requestedDevExts; requestedDevExts.append("VK_KHR_swapchain"); debugMarkersAvailable = false; + if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { + requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + debugMarkersAvailable = true; + } + vertexAttribDivisorAvailable = false; - for (const VkExtensionProperties &ext : devExts) { - if (!strcmp(ext.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { - requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); - debugMarkersAvailable = true; - } else if (!strcmp(ext.extensionName, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { - if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { - requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); - vertexAttribDivisorAvailable = true; - } + if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { + if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { + requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); + vertexAttribDivisorAvailable = true; } } - QByteArrayList envExtList; - if (qEnvironmentVariableIsSet("QT_VULKAN_DEVICE_EXTENSIONS")) { - envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); - for (auto ext : requestedDevExts) - envExtList.removeAll(ext); - for (const QByteArray &ext : envExtList) { - if (!ext.isEmpty()) + for (const QByteArray &ext : requestedDeviceExtensions) { + if (!ext.isEmpty()) { + if (devExts.contains(ext)) requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); } } + QByteArrayList envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); + for (const QByteArray &ext : envExtList) { + if (!ext.isEmpty() && !requestedDevExts.contains(ext)) { + if (devExts.contains(ext)) + requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); + } + } + + if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) { + qCDebug(QRHI_LOG_INFO, "Enabling device extensions:"); + for (const char *ext : requestedDevExts) + qCDebug(QRHI_LOG_INFO, " %s", ext); + } + VkDeviceCreateInfo devInfo; memset(&devInfo, 0, sizeof(devInfo)); devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index d495919671..f8870dcd77 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -57,6 +57,7 @@ struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams { QVulkanInstance *inst = nullptr; QWindow *window = nullptr; + QByteArrayList deviceExtensions; }; struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 0f0a89cbff..a6bcb7e7b6 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -810,6 +810,7 @@ public: QVulkanInstance *inst = nullptr; QWindow *maybeWindow = nullptr; + QByteArrayList requestedDeviceExtensions; bool importedDevice = false; VkPhysicalDevice physDev = VK_NULL_HANDLE; VkDevice dev = VK_NULL_HANDLE; -- cgit v1.2.3 From 4cff6e102dc65693d4f535079c72b0f8a63e8ebf Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 17:23:28 +0100 Subject: rhi: Include an arrayDims vector in InOutVariable too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the this struct to describe combined image samplers and storage images as well. Especially with the former, it is not unlikely that we will need arrays, so e.g. layout(binding = 1) uniform samplerCube shadowCubes[8]. In this case the '8' is something that must be reported in to the reflection information. The new arrayDims member is expected to work exactly like the similarly named member in BlockVariable. Task-number: QTBUG-82624 Change-Id: I1fb8b0318906ff4c116c1a7ec23a399c6545c730 Reviewed-by: Christian Strømme --- src/gui/rhi/qshaderdescription.cpp | 23 ++++++++++++++++++++++- src/gui/rhi/qshaderdescription_p.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 96c8d082fc..80cda259ec 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -783,6 +783,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var) dbg.nospace() << " imageFormat=" << imageFormatStr(var.imageFormat); if (var.imageFlags) dbg.nospace() << " imageFlags=" << var.imageFlags; + if (!var.arrayDims.isEmpty()) + dbg.nospace() << " array=" << var.arrayDims; dbg.nospace() << ')'; return dbg; } @@ -878,6 +880,12 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v (*obj)[imageFormatKey] = imageFormatStr(v.imageFormat); if (v.imageFlags) (*obj)[imageFlagsKey] = int(v.imageFlags); + if (!v.arrayDims.isEmpty()) { + QJsonArray dimArr; + for (int dim : v.arrayDims) + dimArr.append(dim); + (*obj)[arrayDimsKey] = dimArr; + } } static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v) @@ -887,6 +895,9 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription:: (*stream) << v.descriptorSet; (*stream) << int(v.imageFormat); (*stream) << int(v.imageFlags); + (*stream) << v.arrayDims.count(); + for (int dim : v.arrayDims) + (*stream) << dim; } static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) @@ -1124,6 +1135,11 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj) var.imageFormat = mapImageFormat(obj[imageFormatKey].toString()); if (obj.contains(imageFlagsKey)) var.imageFlags = QShaderDescription::ImageFlags(obj[imageFlagsKey].toInt()); + if (obj.contains(arrayDimsKey)) { + QJsonArray dimArr = obj[arrayDimsKey].toArray(); + for (int i = 0; i < dimArr.count(); ++i) + var.arrayDims.append(dimArr.at(i).toInt()); + } return var; } @@ -1137,6 +1153,10 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); + (*stream) >> f; + v->arrayDims.resize(f); + for (int i = 0; i < f; ++i) + (*stream) >> v->arrayDims[i]; } static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream) @@ -1420,7 +1440,8 @@ bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescr && lhs.binding == rhs.binding && lhs.descriptorSet == rhs.descriptorSet && lhs.imageFormat == rhs.imageFormat - && lhs.imageFlags == rhs.imageFlags; + && lhs.imageFlags == rhs.imageFlags + && lhs.arrayDims == rhs.arrayDims; } /*! diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 108fc32a56..783aa384e1 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -216,6 +216,7 @@ public: int descriptorSet = -1; ImageFormat imageFormat = ImageFormatUnknown; ImageFlags imageFlags; + QVector arrayDims; }; struct BlockVariable { -- cgit v1.2.3 From 0378332bc1a6cf3592a4bf5f7e73fe10963168ca Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 3 Mar 2020 11:19:14 +0100 Subject: rhi: Use versioning in QShaderDescription serialization as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the first time that we add something to QShaderDescription after migrating to the non-JSON based serialization system. This now involves checking the "qsb version" when deserializing. Task-number: QTBUG-82624 Change-Id: I2bd875ef21e461559b878dccc5537cdfa43feaa2 Reviewed-by: Christian Strømme --- src/gui/rhi/qshader.cpp | 3 ++- src/gui/rhi/qshader_p_p.h | 3 ++- src/gui/rhi/qshaderdescription.cpp | 42 ++++++++++++++++-------------- src/gui/rhi/qshaderdescription_p.h | 2 +- src/gui/rhi/qshaderdescription_p_p.h | 2 +- tests/auto/gui/rhi/qshader/tst_qshader.cpp | 4 +-- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 69f4a68215..945f4820c2 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -428,6 +428,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->qsbVersion = intVal; if (d->qsbVersion != QShaderPrivate::QSB_VERSION + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_CBOR && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) @@ -439,7 +440,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->stage = Stage(intVal); if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_CBOR) { - d->desc = QShaderDescription::deserialize(&ds); + d->desc = QShaderDescription::deserialize(&ds, d->qsbVersion); } else if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) { QByteArray descBin; ds >> descBin; diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 66ef18f391..ec9d25971f 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -57,7 +57,8 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QShaderPrivate { - static const int QSB_VERSION = 4; + static const int QSB_VERSION = 5; + static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4; static const int QSB_VERSION_WITH_CBOR = 3; static const int QSB_VERSION_WITH_BINARY_JSON = 2; static const int QSB_VERSION_WITHOUT_BINDINGS = 1; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 80cda259ec..f3ef5edd12 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -35,6 +35,7 @@ ****************************************************************************/ #include "qshaderdescription_p_p.h" +#include "qshader_p_p.h" #include #include #include @@ -402,10 +403,10 @@ QShaderDescription QShaderDescription::fromCbor(const QByteArray &data) return desc; } -QShaderDescription QShaderDescription::deserialize(QDataStream *stream) +QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version) { QShaderDescription desc; - QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream); + QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream, version); return desc; } @@ -1143,7 +1144,7 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj) return var; } -static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v) +static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v) { (*stream) >> v->location; (*stream) >> v->binding; @@ -1153,20 +1154,23 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); - (*stream) >> f; - v->arrayDims.resize(f); - for (int i = 0; i < f; ++i) - (*stream) >> v->arrayDims[i]; + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS) { + (*stream) >> f; + v->arrayDims.resize(f); + for (int i = 0; i < f; ++i) + (*stream) >> v->arrayDims[i]; + } } -static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream) +static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version) { QShaderDescription::InOutVariable var; (*stream) >> var.name; int t; (*stream) >> t; var.type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &var); + deserializeDecorations(stream, version, &var); return var; } @@ -1196,7 +1200,7 @@ static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj) return var; } -static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream) +static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream, int version) { QShaderDescription::BlockVariable var; (*stream) >> var.name; @@ -1216,7 +1220,7 @@ static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream * (*stream) >> count; var.structMembers.resize(count); for (int i = 0; i < count; ++i) - var.structMembers[i] = deserializeBlockMemberVar(stream); + var.structMembers[i] = deserializeBlockMemberVar(stream, version); return var; } @@ -1324,7 +1328,7 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc) } } -void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) +void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) { Q_ASSERT(ref.loadRelaxed() == 1); // must be detached @@ -1332,12 +1336,12 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> count; inVars.resize(count); for (int i = 0; i < count; ++i) - inVars[i] = deserializeInOutVar(stream); + inVars[i] = deserializeInOutVar(stream, version); (*stream) >> count; outVars.resize(count); for (int i = 0; i < count; ++i) - outVars[i] = deserializeInOutVar(stream); + outVars[i] = deserializeInOutVar(stream, version); (*stream) >> count; uniformBlocks.resize(count); @@ -1351,7 +1355,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; uniformBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1363,7 +1367,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; pushConstantBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1378,7 +1382,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; storageBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1388,7 +1392,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) int t; (*stream) >> t; combinedImageSamplers[i].type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &combinedImageSamplers[i]); + deserializeDecorations(stream, version, &combinedImageSamplers[i]); } (*stream) >> count; @@ -1398,7 +1402,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) int t; (*stream) >> t; storageImages[i].type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &storageImages[i]); + deserializeDecorations(stream, version, &storageImages[i]); } for (size_t i = 0; i < 3; ++i) diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 783aa384e1..e5650ed921 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -78,7 +78,7 @@ public: static QShaderDescription fromBinaryJson(const QByteArray &data); #endif static QShaderDescription fromCbor(const QByteArray &data); - static QShaderDescription deserialize(QDataStream *stream); + static QShaderDescription deserialize(QDataStream *stream, int version); enum VariableType { Unknown = 0, diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h index 69b6e811a1..ec2b0b6b4c 100644 --- a/src/gui/rhi/qshaderdescription_p_p.h +++ b/src/gui/rhi/qshaderdescription_p_p.h @@ -82,7 +82,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate QJsonDocument makeDoc(); void writeToStream(QDataStream *stream); void loadDoc(const QJsonDocument &doc); - void loadFromStream(QDataStream *stream); + void loadFromStream(QDataStream *stream, int version); QAtomicInt ref; QVector inVars; diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp index ab7115b74a..378d1e85e7 100644 --- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -368,7 +368,7 @@ void tst_QShader::serializeShaderDesc() QBuffer buf(&data); QDataStream ds(&buf); QVERIFY(buf.open(QIODevice::ReadOnly)); - QShaderDescription desc2 = QShaderDescription::deserialize(&ds); + QShaderDescription desc2 = QShaderDescription::deserialize(&ds, QShaderPrivate::QSB_VERSION); QVERIFY(!desc2.isValid()); } } @@ -400,7 +400,7 @@ void tst_QShader::serializeShaderDesc() QBuffer buf(&data); QDataStream ds(&buf); QVERIFY(buf.open(QIODevice::ReadOnly)); - QShaderDescription desc2 = QShaderDescription::deserialize(&ds); + QShaderDescription desc2 = QShaderDescription::deserialize(&ds, QShaderPrivate::QSB_VERSION); QVERIFY(desc2.isValid()); QCOMPARE(desc, desc2); } -- cgit v1.2.3 From eff6f77c1a38a5a89268b2dfbe9ab03cf9b2d652 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Feb 2020 14:50:38 +0100 Subject: Add since 5.15 to new QVulkanInstance function Change-Id: Ib1fb6186a8c76d6848d5eda1756e7749383dae40 Reviewed-by: Eirik Aavitsland --- src/gui/vulkan/qvulkaninstance.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp index 4b961a6f20..555dee3a9c 100644 --- a/src/gui/vulkan/qvulkaninstance.cpp +++ b/src/gui/vulkan/qvulkaninstance.cpp @@ -781,6 +781,8 @@ bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t system dependent synchronization. For example, on Wayland this will add send a wl_surface.frame request in order to prevent the driver from blocking for minimized windows. + + \since 5.15 */ void QVulkanInstance::presentAboutToBeQueued(QWindow *window) { -- cgit v1.2.3 From bbc52a043da3b38a2d44a5502c8587a1fdc8ad59 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 16:47:55 +0100 Subject: rhi: Add a way to communicate back the native image layout for a QRhiTexture Relevant when doing custom rendering combined with QRhi, and only for APIs like Vulkan, where image layouts are a thing. As shown by demo apps, it is not currently possible to implement a correct application that renders or raytraces into a QRhiTexture's backing VkImage, and then uses that QRhiTexture in a QRhi-based render pass. This is because QRhi has no knowledge of the image layout if it changes due to commands recorded by direct Vulkan calls, and not via QRhi itself. So, except for certain simple cases, one will end up with incorrect image layout transitions in the barriers. (at minimum this will be caught by the validation layer) To remedy this, add a simple function taking the layout as int (we already do the opposite in nativeTexture()). Task-number: QTBUG-82435 Change-Id: Ic9e9c1b820b018f3b236742f99fe99fa6de63d36 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhi.cpp | 25 +++++++++++++++++++++++++ src/gui/rhi/qrhi_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 5 +++++ src/gui/rhi/qrhivulkan_p_p.h | 1 + 4 files changed, 32 insertions(+) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 6243bcda58..c805e23ad0 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2339,6 +2339,31 @@ bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src) return false; } +/*! + With some graphics APIs, such as Vulkan, integrating custom rendering code + that uses the graphics API directly needs special care when it comes to + image layouts. This function allows communicating the expected layout the + image backing the QRhiTexture is in after the native rendering commands. + + For example, consider rendering into a QRhiTexture's VkImage directly with + Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and + QRhiCommandBuffer::endExternal(), followed by using the image for texture + sampling in a QRhi-based render pass. To avoid potentially incorrect image + layout transitions, this function can be used to indicate what the image + layout will be once the commands recorded in said code block complete. + + Calling this function makes sense only after + QRhiCommandBuffer::endExternal() and before a subsequent + QRhiCommandBuffer::beginPass(). + + This function has no effect with QRhi backends where the underlying + graphics API does not expose a concept of image layouts. + */ +void QRhiTexture::setNativeLayout(int layout) +{ + Q_UNUSED(layout); +} + /*! \class QRhiSampler \internal diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 8f53808d34..17c911a5ff 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -791,6 +791,7 @@ public: virtual bool build() = 0; virtual NativeTexture nativeTexture(); virtual bool buildFrom(NativeTexture src); + virtual void setNativeLayout(int layout); protected: QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 60ab15e89d..a92c3e14e9 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -5563,6 +5563,11 @@ QRhiTexture::NativeTexture QVkTexture::nativeTexture() return {&image, usageState.layout}; } +void QVkTexture::setNativeLayout(int layout) +{ + usageState.layout = VkImageLayout(layout); +} + VkImageView QVkTexture::imageViewForLevel(int level) { Q_ASSERT(level >= 0 && level < int(mipLevelCount)); diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index a6bcb7e7b6..fd65417e75 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -123,6 +123,7 @@ struct QVkTexture : public QRhiTexture bool build() override; bool buildFrom(NativeTexture src) override; NativeTexture nativeTexture() override; + void setNativeLayout(int layout) override; bool prepareBuild(QSize *adjustedSize = nullptr); bool finishBuild(); -- cgit v1.2.3 From dd0a197be40bdec1af02e58f50926afb11af9509 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Feb 2020 14:58:10 +0100 Subject: QVulkanWindow: Remove queueCreateInfoModifier getter This is inconsistent with the other similar functions in QVulkanWindow, we do not provide getters for those either. Change-Id: If764b49f4b26ff14a2fa908b8d5b37429047250c Reviewed-by: Paul Olav Tvete --- src/gui/vulkan/qvulkanwindow.cpp | 13 ------------- src/gui/vulkan/qvulkanwindow.h | 1 - 2 files changed, 14 deletions(-) diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index e211863f21..ee49cf0999 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -1595,19 +1595,6 @@ bool QVulkanWindow::event(QEvent *e) \sa setQueueCreateInfoModifier() */ -/*! - Return a previously set queue create info modification function. - - \sa setQueueCreateInfoModifier() - - \since 5.15 - */ -QVulkanWindow::QueueCreateInfoModifier QVulkanWindow::queueCreateInfoModifier() const -{ - Q_D(const QVulkanWindow); - return d->queueCreateInfoModifier; -} - /*! Set a queue create info modification function. diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 530b6c0744..511b9501bd 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -106,7 +106,6 @@ public: typedef std::function &)> QueueCreateInfoModifier; - QueueCreateInfoModifier queueCreateInfoModifier() const; void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier); bool isValid() const; -- cgit v1.2.3 From 8f8eb99991216c0833c23a0f068e036a70e3b060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Sat, 29 Feb 2020 11:39:58 +0100 Subject: QNetworkReply: Deprecate 'error' signal, use 'errorOccurred' instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ChangeLog][Deprecation Notice] QNetworkReply::error() (the signal) is deprecated; superseded by errorOccurred() Change-Id: I4f1ef410fd22d34ddf87e89cc5709cc60703af95 Reviewed-by: MÃ¥rten Nordheim --- examples/xml/rsslisting/rsslisting.cpp | 2 +- src/network/access/qnetworkreply.cpp | 15 ++++++-- src/network/access/qnetworkreply.h | 4 +++ src/network/access/qnetworkreplydataimpl.cpp | 2 +- src/network/access/qnetworkreplyhttpimpl.cpp | 2 +- src/network/access/qnetworkreplyimpl.cpp | 4 +-- tests/auto/network/access/http2/tst_http2.cpp | 2 +- .../tst_qhttpnetworkconnection.cpp | 6 ++-- .../tst_qnetworkaccessmanager.cpp | 2 +- .../access/qnetworkreply/tst_qnetworkreply.cpp | 42 +++++++++++----------- tests/auto/network/access/spdy/tst_spdy.cpp | 2 +- 11 files changed, 48 insertions(+), 35 deletions(-) diff --git a/examples/xml/rsslisting/rsslisting.cpp b/examples/xml/rsslisting/rsslisting.cpp index d1b4373531..143ad6dcba 100644 --- a/examples/xml/rsslisting/rsslisting.cpp +++ b/examples/xml/rsslisting/rsslisting.cpp @@ -131,7 +131,7 @@ void RSSListing::get(const QUrl &url) currentReply = manager.get(request); connect(currentReply, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(currentReply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); - connect(currentReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); + connect(currentReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); } /* diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index fb30bfd4f1..22c522756c 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -91,7 +91,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() content. \note Do not delete the object in the slot connected to the - error() or finished() signal. Use deleteLater(). + errorOccurred() or finished() signal. Use deleteLater(). \sa QNetworkRequest, QNetworkAccessManager */ @@ -219,6 +219,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() the server response was detected \sa error() + \sa errorOccurred() */ /*! @@ -362,6 +363,14 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() /*! \fn void QNetworkReply::error(QNetworkReply::NetworkError code) + \obsolete + + Use errorOccurred() instead. +*/ + +/*! + \fn void QNetworkReply::errorOccurred(QNetworkReply::NetworkError code) + \since 5.15 This signal is emitted when the reply detects an error in processing. The finished() signal will probably follow, indicating @@ -442,7 +451,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() QNetworkAccessManager functions to do that. */ QNetworkReply::QNetworkReply(QObject *parent) - : QIODevice(*new QNetworkReplyPrivate, parent) + : QNetworkReply(*new QNetworkReplyPrivate, parent) { } @@ -452,6 +461,8 @@ QNetworkReply::QNetworkReply(QObject *parent) QNetworkReply::QNetworkReply(QNetworkReplyPrivate &dd, QObject *parent) : QIODevice(dd, parent) { + // Support the deprecated error() signal: + connect(this, &QNetworkReply::errorOccurred, this, QOverload::of(&QNetworkReply::error)); } /*! diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 4a402daa91..82349f9e2a 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -156,7 +156,11 @@ public Q_SLOTS: Q_SIGNALS: void metaDataChanged(); void finished(); +#if QT_DEPRECATED_SINCE(5,15) + QT_DEPRECATED_X("Use QNetworkReply::errorOccurred(QNetworkReply::NetworkError) instead") void error(QNetworkReply::NetworkError); +#endif + void errorOccurred(QNetworkReply::NetworkError); #if QT_CONFIG(ssl) void encrypted(); void sslErrors(const QList &errors); diff --git a/src/network/access/qnetworkreplydataimpl.cpp b/src/network/access/qnetworkreplydataimpl.cpp index 924c905b1a..2f75020446 100644 --- a/src/network/access/qnetworkreplydataimpl.cpp +++ b/src/network/access/qnetworkreplydataimpl.cpp @@ -88,7 +88,7 @@ QNetworkReplyDataImpl::QNetworkReplyDataImpl(QObject *parent, const QNetworkRequ const QString msg = QCoreApplication::translate("QNetworkAccessDataBackend", "Invalid URI: %1").arg(url.toString()); setError(QNetworkReply::ProtocolFailure, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolFailure)); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 12f402cabd..2a9d281256 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -2265,7 +2265,7 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c // note: might not be a good idea, since users could decide to delete us // which would delete the backend too... // maybe we should protect the backend - emit q->error(code); + emit q->errorOccurred(code); } void QNetworkReplyHttpImplPrivate::_q_metaDataChanged() diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 51bb386186..a0b4ace470 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -855,7 +855,7 @@ void QNetworkReplyImplPrivate::error(QNetworkReplyImpl::NetworkError code, const // note: might not be a good idea, since users could decide to delete us // which would delete the backend too... // maybe we should protect the backend - emit q->error(code); + emit q->errorOccurred(code); } void QNetworkReplyImplPrivate::metaDataChanged() @@ -1128,7 +1128,7 @@ QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent, "Network access is disabled."); setError(UnknownNetworkError, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, UnknownNetworkError)); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 6f94692cb1..6a07ae78fb 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -513,7 +513,7 @@ void tst_Http2::goaway() replies[i] = manager->get(request); QCOMPARE(replies[i]->error(), QNetworkReply::NoError); void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = - &QNetworkReply::error; + &QNetworkReply::errorOccurred; connect(replies[i], errorSignal, this, &tst_Http2::replyFinishedWithError); // Since we're using self-signed certificates, ignore SSL errors: replies[i]->ignoreSslErrors(); diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp index 57fa5a613c..e8d4c773f0 100644 --- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp +++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp @@ -1005,10 +1005,8 @@ void tst_QHttpNetworkConnection::overlappingCloseAndWrite() for (int i = 0; i < 10; ++i) { QNetworkRequest request(url); QNetworkReply *reply = accessManager.get(request); - // Not using Qt5 connection syntax here because of overly baroque syntax to discern between - // different error() methods. - QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - &server, SLOT(onReply(QNetworkReply::NetworkError))); + QObject::connect(reply, &QNetworkReply::errorOccurred, + &server, &TestTcpServer::onReply); } QTRY_COMPARE(server.errorCodeReports, 10); diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp index 752655ee94..b5ded86d58 100644 --- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp +++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp @@ -87,7 +87,7 @@ void tst_QNetworkAccessManager::networkAccessible() // When network is not accessible, all requests fail QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://www.example.org"))); QSignalSpy finishedSpy(reply, &QNetworkReply::finished); - QSignalSpy errorSpy(reply, QOverload::of(&QNetworkReply::error)); + QSignalSpy errorSpy(reply, &QNetworkReply::errorOccurred); QVERIFY(finishedSpy.wait()); QCOMPARE(reply->isFinished(), true); QCOMPARE(reply->errorString(), QStringLiteral("Network access is disabled.")); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 65f355ca25..7d065f1248 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -1371,7 +1371,7 @@ QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request, // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below reply->setParent(this); connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); multiPart->setParent(reply.data()); returnCode = Timeout; @@ -1431,7 +1431,7 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, code = Failure; } else { connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); int count = 0; loop = new QEventLoop; @@ -1466,7 +1466,7 @@ QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request, reply.reset(manager.sendCustomRequest(request, verb, data)); reply->setParent(this); connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); returnCode = Timeout; loop = new QEventLoop; @@ -1503,7 +1503,7 @@ int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply) int count = 0; connect(reply, SIGNAL(finished()), SLOT(finished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(gotError())); returnCode = Success; loop = new QEventLoop; QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64))); @@ -1890,7 +1890,7 @@ void tst_QNetworkReply::getFromFtpAfterError() QNetworkRequest invalidRequest(QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/invalid.txt")); QNetworkReplyPtr invalidReply; invalidReply.reset(manager.get(invalidRequest)); - QSignalSpy spy(invalidReply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(invalidReply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QVERIFY(spy.wait()); QCOMPARE(invalidReply->error(), QNetworkReply::ContentNotFoundError); @@ -3911,7 +3911,7 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer() QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); @@ -5447,7 +5447,7 @@ void tst_QNetworkReply::rateControl() QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort())); QNetworkReplyPtr reply(manager.get(request)); reply->setReadBufferSize(32768); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); RateControlledReader reader(sender, reply.data(), rate, 20); @@ -5861,7 +5861,7 @@ void tst_QNetworkReply::nestedEventLoops() QNetworkReplyPtr reply(manager.get(request)); QSignalSpy finishedspy(reply.data(), SIGNAL(finished())); - QSignalSpy errorspy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorspy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot())); QTestEventLoop::instance().enterLoop(20); @@ -6094,7 +6094,7 @@ void tst_QNetworkReply::authorizationError() QCOMPARE(reply->error(), QNetworkReply::NoError); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QSignalSpy finishedSpy(reply.data(), SIGNAL(finished())); // now run the request: QCOMPARE(waitForFinish(reply), int(Failure)); @@ -7050,7 +7050,7 @@ void tst_QNetworkReply::qtbug4121unknownAuthentication() QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*))); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); QTestEventLoop::instance().enterLoop(10); @@ -7371,7 +7371,7 @@ void tst_QNetworkReply::httpWithNoCredentialUsage() request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual); QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); QTestEventLoop::instance().enterLoop(10); @@ -8083,7 +8083,7 @@ void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890 QNetworkRequest request(urls.at(a)); QNetworkReply *reply = manager.get(request); replies.append(reply); - QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); errorSpies.append(errorSpy); QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished())); finishedSpies.append(finishedSpy); @@ -8474,7 +8474,7 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects() QNetworkReplyPtr reply(manager.get(request)); QSignalSpy redSpy(reply.data(), SIGNAL(redirected(QUrl))); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); @@ -8538,7 +8538,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors() QTimer watchDog; watchDog.setSingleShot(true); - reply->connect(reply.data(), QOverload().of(&QNetworkReply::error), + reply->connect(reply.data(), &QNetworkReply::errorOccurred, [&eventLoop](QNetworkReply::NetworkError){ eventLoop.exit(Failure); }); @@ -8704,7 +8704,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors() if (ssl) reply->ignoreSslErrors(); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); QCOMPARE(spy.count(), 1); @@ -9352,7 +9352,7 @@ void tst_QNetworkReply::getWithTimeout() QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Success)); @@ -9363,7 +9363,7 @@ void tst_QNetworkReply::getWithTimeout() server.stopTransfer = true; QNetworkReplyPtr reply2(manager.get(request)); - QSignalSpy spy2(reply2.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply2), int(Failure)); @@ -9374,7 +9374,7 @@ void tst_QNetworkReply::getWithTimeout() manager.setTransferTimeout(1000); QNetworkReplyPtr reply3(manager.get(request)); - QSignalSpy spy3(reply3.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply3), int(Failure)); @@ -9392,7 +9392,7 @@ void tst_QNetworkReply::postWithTimeout() request.setRawHeader("Content-Type", "application/octet-stream"); QByteArray postData("Just some nonsense"); QNetworkReplyPtr reply(manager.post(request, postData)); - QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Success)); @@ -9403,7 +9403,7 @@ void tst_QNetworkReply::postWithTimeout() server.stopTransfer = true; QNetworkReplyPtr reply2(manager.post(request, postData)); - QSignalSpy spy2(reply2.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply2), int(Failure)); @@ -9414,7 +9414,7 @@ void tst_QNetworkReply::postWithTimeout() manager.setTransferTimeout(1000); QNetworkReplyPtr reply3(manager.post(request, postData)); - QSignalSpy spy3(reply3.data(), SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply3), int(Failure)); diff --git a/tests/auto/network/access/spdy/tst_spdy.cpp b/tests/auto/network/access/spdy/tst_spdy.cpp index 5701f4911c..1b0b3aec6b 100644 --- a/tests/auto/network/access/spdy/tst_spdy.cpp +++ b/tests/auto/network/access/spdy/tst_spdy.cpp @@ -581,7 +581,7 @@ void tst_Spdy::errors() if (ignoreSslErrors) reply->ignoreSslErrors(); QSignalSpy finishedSpy(reply, SIGNAL(finished())); - QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy errorSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); -- cgit v1.2.3 From 466d32160a23e6848fe0a42e74085c79071d7dec Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 3 Mar 2020 08:01:05 +0100 Subject: Suppress warnings where QString and its tests use SplitBehavior This is a follow-up to commit 895939c7f91d0c8424a0638c42d05cb42293a142 to fix deprecation warnings it added. Change-Id: I3d86655ec2c84c1bdcac9c70436075fc78f2f781 Reviewed-by: Volker Hilsheimer --- src/corelib/text/qstring.cpp | 3 +++ tests/auto/corelib/text/qstring/tst_qstring.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index a2c603c776..68dec7cfff 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7748,7 +7748,10 @@ static ResultList splitString(const StringSource &source, const QChar *sep, #if QT_DEPRECATED_SINCE(5, 15) Qt::SplitBehavior mapSplitBehavior(QString::SplitBehavior sb) { +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED return sb & QString::SkipEmptyParts ? Qt::SkipEmptyParts : Qt::KeepEmptyParts; +QT_WARNING_POP } #endif diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 7072cb9516..bc2b19125a 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -5824,6 +5824,8 @@ void tst_QString::split(const QString &string, const QString &sep, QStringList r QVERIFY(list == result); } +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED list = str.split(sep, QString::KeepEmptyParts); QVERIFY(list == result); list = str.split(rx, QString::KeepEmptyParts); @@ -5846,6 +5848,7 @@ void tst_QString::split(const QString &string, const QString &sep, QStringList r list = str.split(sep.at(0), QString::SkipEmptyParts); QVERIFY(list == result); } +QT_WARNING_POP } void tst_QString::split() -- cgit v1.2.3 From e5f4e1405947bcecd78f15bd76162ad6b54c2502 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Wed, 12 Feb 2020 17:27:36 +0200 Subject: Examples: enable HighDPI scaling for examples on Android These examples show very tiny UI elements on Android devices, thus enabling HighDPI. Task-number: QTBUG-80717 Change-Id: I813801d5249dc1fcfc6f61a8d146f60dd19901f6 Reviewed-by: BogDan Vatra --- examples/widgets/graphicsview/collidingmice/main.cpp | 3 +++ examples/widgets/graphicsview/diagramscene/main.cpp | 3 +++ examples/widgets/itemviews/addressbook/main.cpp | 3 +++ examples/widgets/itemviews/spreadsheet/main.cpp | 4 ++++ examples/widgets/mainwindows/application/main.cpp | 3 +++ examples/widgets/mainwindows/dockwidgets/main.cpp | 3 +++ examples/widgets/painting/affine/main.cpp | 4 +++- examples/widgets/painting/concentriccircles/main.cpp | 3 +++ examples/widgets/painting/fontsampler/main.cpp | 3 +++ examples/widgets/painting/gradients/main.cpp | 3 +++ examples/widgets/painting/pathstroke/main.cpp | 3 +++ examples/widgets/tools/undo/main.cpp | 3 +++ examples/widgets/widgets/calculator/main.cpp | 3 +++ examples/widgets/widgets/elidedlabel/main.cpp | 3 +++ examples/widgets/widgets/scribble/main.cpp | 3 +++ examples/widgets/widgets/sliders/main.cpp | 3 +++ 16 files changed, 49 insertions(+), 1 deletion(-) diff --git a/examples/widgets/graphicsview/collidingmice/main.cpp b/examples/widgets/graphicsview/collidingmice/main.cpp index ef6d6cca64..c9ad90260f 100644 --- a/examples/widgets/graphicsview/collidingmice/main.cpp +++ b/examples/widgets/graphicsview/collidingmice/main.cpp @@ -58,6 +58,9 @@ static constexpr int MouseCount = 7; //! [0] int main(int argc, char **argv) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); //! [0] diff --git a/examples/widgets/graphicsview/diagramscene/main.cpp b/examples/widgets/graphicsview/diagramscene/main.cpp index eefaa86554..3e321259c5 100644 --- a/examples/widgets/graphicsview/diagramscene/main.cpp +++ b/examples/widgets/graphicsview/diagramscene/main.cpp @@ -55,6 +55,9 @@ int main(int argv, char *args[]) { Q_INIT_RESOURCE(diagramscene); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argv, args); MainWindow mainWindow; diff --git a/examples/widgets/itemviews/addressbook/main.cpp b/examples/widgets/itemviews/addressbook/main.cpp index 0731287cdd..86a11c5850 100644 --- a/examples/widgets/itemviews/addressbook/main.cpp +++ b/examples/widgets/itemviews/addressbook/main.cpp @@ -55,6 +55,9 @@ //! [0] int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); MainWindow mw; mw.show(); diff --git a/examples/widgets/itemviews/spreadsheet/main.cpp b/examples/widgets/itemviews/spreadsheet/main.cpp index 548dc8d604..968312d097 100644 --- a/examples/widgets/itemviews/spreadsheet/main.cpp +++ b/examples/widgets/itemviews/spreadsheet/main.cpp @@ -56,6 +56,10 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(spreadsheet); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif + QApplication app(argc, argv); SpreadSheet sheet(10, 6); sheet.setWindowIcon(QPixmap(":/images/interview.png")); diff --git a/examples/widgets/mainwindows/application/main.cpp b/examples/widgets/mainwindows/application/main.cpp index 78db7134a3..b46e1116dc 100644 --- a/examples/widgets/mainwindows/application/main.cpp +++ b/examples/widgets/mainwindows/application/main.cpp @@ -58,6 +58,9 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(application); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); QCoreApplication::setOrganizationName("QtProject"); diff --git a/examples/widgets/mainwindows/dockwidgets/main.cpp b/examples/widgets/mainwindows/dockwidgets/main.cpp index ff3ba506a8..bf3ad9bcf7 100644 --- a/examples/widgets/mainwindows/dockwidgets/main.cpp +++ b/examples/widgets/mainwindows/dockwidgets/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Q_INIT_RESOURCE(dockwidgets); MainWindow mainWin; diff --git a/examples/widgets/painting/affine/main.cpp b/examples/widgets/painting/affine/main.cpp index 6ce8efe482..641fc5c204 100644 --- a/examples/widgets/painting/affine/main.cpp +++ b/examples/widgets/painting/affine/main.cpp @@ -55,7 +55,9 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(affine); - +#ifdef Q_OS_ANDROID + qputenv("QT_SCALE_FACTOR", "2"); +#endif QApplication app(argc, argv); XFormWidget xformWidget(nullptr); diff --git a/examples/widgets/painting/concentriccircles/main.cpp b/examples/widgets/painting/concentriccircles/main.cpp index d9fa2879c4..00456195d9 100644 --- a/examples/widgets/painting/concentriccircles/main.cpp +++ b/examples/widgets/painting/concentriccircles/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Window window; window.show(); diff --git a/examples/widgets/painting/fontsampler/main.cpp b/examples/widgets/painting/fontsampler/main.cpp index 1bf46b226f..cec6929827 100644 --- a/examples/widgets/painting/fontsampler/main.cpp +++ b/examples/widgets/painting/fontsampler/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); MainWindow window; window.show(); diff --git a/examples/widgets/painting/gradients/main.cpp b/examples/widgets/painting/gradients/main.cpp index 0ddf7a4579..7ffb0326e9 100644 --- a/examples/widgets/painting/gradients/main.cpp +++ b/examples/widgets/painting/gradients/main.cpp @@ -55,6 +55,9 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(gradients); +#ifdef Q_OS_ANDROID + qputenv("QT_SCALE_FACTOR", "2"); +#endif QApplication app(argc, argv); diff --git a/examples/widgets/painting/pathstroke/main.cpp b/examples/widgets/painting/pathstroke/main.cpp index 57c85d73a3..35317480a3 100644 --- a/examples/widgets/painting/pathstroke/main.cpp +++ b/examples/widgets/painting/pathstroke/main.cpp @@ -55,6 +55,9 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(pathstroke); +#ifdef Q_OS_ANDROID + qputenv("QT_SCALE_FACTOR", "2"); +#endif QApplication app(argc, argv); diff --git a/examples/widgets/tools/undo/main.cpp b/examples/widgets/tools/undo/main.cpp index a5ec1b1b83..1a6dcf8c48 100644 --- a/examples/widgets/tools/undo/main.cpp +++ b/examples/widgets/tools/undo/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(undo); +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); diff --git a/examples/widgets/widgets/calculator/main.cpp b/examples/widgets/widgets/calculator/main.cpp index a034bb262e..5f59d00ca6 100644 --- a/examples/widgets/widgets/calculator/main.cpp +++ b/examples/widgets/widgets/calculator/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Calculator calc; calc.show(); diff --git a/examples/widgets/widgets/elidedlabel/main.cpp b/examples/widgets/widgets/elidedlabel/main.cpp index 1c620c1d41..58507766e7 100644 --- a/examples/widgets/widgets/elidedlabel/main.cpp +++ b/examples/widgets/widgets/elidedlabel/main.cpp @@ -55,6 +55,9 @@ //! [0] int main( int argc, char *argv[] ) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication application( argc, argv ); TestWidget w; w.showFullScreen(); diff --git a/examples/widgets/widgets/scribble/main.cpp b/examples/widgets/widgets/scribble/main.cpp index 1bf46b226f..cec6929827 100644 --- a/examples/widgets/widgets/scribble/main.cpp +++ b/examples/widgets/widgets/scribble/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); MainWindow window; window.show(); diff --git a/examples/widgets/widgets/sliders/main.cpp b/examples/widgets/widgets/sliders/main.cpp index 99725195e5..9bf18cb6d4 100644 --- a/examples/widgets/widgets/sliders/main.cpp +++ b/examples/widgets/widgets/sliders/main.cpp @@ -54,6 +54,9 @@ int main(int argc, char *argv[]) { +#ifdef Q_OS_ANDROID + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif QApplication app(argc, argv); Window window; window.show(); -- cgit v1.2.3 From f03202b560e04d032f6485e65bcd430c4641894e Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 27 Feb 2020 19:30:18 +0100 Subject: Fix missing return-type in doc of qfloat16::copySign() Change-Id: I617081fe3335a85191be7882578644621d5ffede Reviewed-by: Thiago Macieira --- src/corelib/global/qfloat16.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index 80a851e4e4..3d82bbe95a 100644 --- a/src/corelib/global/qfloat16.cpp +++ b/src/corelib/global/qfloat16.cpp @@ -147,7 +147,7 @@ QT_BEGIN_NAMESPACE /*! \since 5.15 - \fn qfloat16::copySign(qfloat16 sign) const noexcept + \fn qfloat16 qfloat16::copySign(qfloat16 sign) const noexcept Returns a qfloat16 with the sign of \a sign but the rest of its value taken from this qfloat16. Serves as qfloat16's equivalent of std::copysign(). -- cgit v1.2.3 From 8a6e1de87c32fcbf8d7946f688635a3ca2a78203 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Wed, 12 Feb 2020 17:28:43 +0200 Subject: Examples: update examples list for Android Explicitly set the list of examples that works on Android, as many have issues with layout or other issues. Task-number: QTBUG-80716 Change-Id: If71efc45a48c6236f8775e21e4cab6dc0129f024 Reviewed-by: BogDan Vatra Reviewed-by: Eskil Abrahamsen Blomfeldt --- doc/global/manifest-meta.qdocconf | 175 +++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 78 deletions(-) diff --git a/doc/global/manifest-meta.qdocconf b/doc/global/manifest-meta.qdocconf index 3db67a3131..f5e5dbf8db 100644 --- a/doc/global/manifest-meta.qdocconf +++ b/doc/global/manifest-meta.qdocconf @@ -32,84 +32,103 @@ manifestmeta.filters = highlighted android thumbnail ios manifestmeta.highlighted.attributes = isHighlighted:true -manifestmeta.android.names = "QtQuick/Qt Quick Demo - Calqlatr" \ - "QtWidgets/Application Chooser Example" \ - "QtWidgets/Stickman Example" \ - "QtWidgets/Move Blocks Example" \ - "QtWidgets/Border Layout Example" \ - "QtWidgets/Flow Layout Example" \ - "QtWidgets/Dock Widgets Example" \ - "QtWidgets/Recent Files Example" \ - "QtWidgets/Concentric Circles Example" \ - "QtWidgets/Gradients" \ - "QtWidgets/Font Sampler Example" \ - "QtWidgets/Path Stroking" \ - "QtWidgets/Transformations Example" \ - "QtWidgets/Syntax Highlighter Example" \ - "QtWidgets/Calendar Example" \ - "QtWidgets/Analog Clock Example" \ - "QtWidgets/Calculator Example" \ - "QtWidgets/Mouse Button Tester" \ - "QtWidgets/Character Map Example" \ - "QtWidgets/Digital Clock Example" \ - "QtWidgets/Elided Label Example" \ - "QtWidgets/Sliders Example" \ - "QtWidgets/Tetrix Example" \ - "QtWidgets/Group Box Example" \ - "QtWidgets/Undo Framework" \ - "QtWidgets/Colliding Mice Example" \ - "QtWidgets/Diagram Scene Example" \ - "QtWidgets/Elastic Nodes Example" \ - "QtWidgets/Weather Anchor Layout Example" \ - "QtNetwork/Torrent Example" \ - "QtNetwork/Network Chat Example" \ - "QtSQL/Master Detail Example" \ - "QtLinguist/Arrow Pad Example" \ - "QtGui/Raster Window Example" \ - "QtGui/Analog Clock Window Example" \ - "QtAndroidExtras/Qt Notifier" \ - "QtMultimedia/QML Video Shader Effects Example" \ - "QtMultimedia/QML Video Example" \ - "QtMultimedia/QML Camera Example" \ - "QtSVG/Text Object Example" \ - "QtQML/Qt Quick Examples - XMLHttpRequest" \ - "QtQuick/Qt Quick Particles Examples - *" \ - "QtQuick/Qt Quick Examples - Touch Interaction" \ - "QtQuick/Scene Graph - Custom Geometry" \ - "QtQuick/Scene Graph - Graph" \ - "QtQuick/Scene Graph - OpenGL Under QML" \ - "QtQuick/Scene Graph - Painted Item" \ - "QtQuick/Scene Graph - Rendering FBOs" \ - "QtQuick/Scene Graph - Simple Material" \ - "QtQuick/Qt Quick Examples - Image Elements" \ - "QtQuick/Qt Quick Examples - Key Interaction" \ - "QtQuick/Qt Quick Examples - Text" \ - "QtQuick/Qt Quick Examples - Animation" \ - "QtQuick/Qt Quick Examples - Shader Effects" \ - "QtQuick/Qt Quick Examples - Canvas" \ - "QtQuick/Qt Quick Examples - MouseArea" \ - "QtQuick/Qt Quick Examples - Positioners" \ - "QtQuick/Qt Quick Examples - Right to Left" \ - "QtWidgets/Interview" \ - "QtWidgets/Spreadsheet" \ - "QtWidgets/Pixelator Example" \ - "QtWidgets/Animated Tiles Example" \ - "QtWidgets/Affine Transformations" \ - "QtWidgets/Image Composition Example" \ - "QtWidgets/Basic Drawing Example" \ - "QtWidgets/Vector Deformation" \ - "QtWidgets/Painter Paths Example" \ - "QtWidgets/Style Sheet Example" \ - "QtWidgets/Code Editor Example" \ - "QtWidgets/Scribble Example" \ - "QtWidgets/Line Edits Example" \ - "QtWidgets/Calendar Widget Example" \ - "QtWidgets/Completer Example" \ - "QtWidgets/I18N Example" \ - "QtQML/Extending QML - Grouped Properties Example" \ - "QtQML/Extending QML - Methods Example" \ - "QtQML/Extending QML - Signal Support Example" \ - "QtQML/Extending QML - Attached Properties Example" +manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \ + "Qt3D/Qt 3D: Planets QML Example" \ + "Qt3D/Qt 3D: Simple Custom Material QML Example" \ + "QtAndroidExtras/Qt Notifier" \ + "QtBluetooth/Bluetooth Low Energy Scanner Example" \ + "QtBluetooth/Bluetooth Scanner Example" \ + "QtBluetooth/QML Bluetooth Scanner Example" \ + "QtCharts/*" \ + "QtConcurrent/QtConcurrent Progress Dialog Example" \ + "QtDataVisualization/Audiolevels Example" \ + "QtDataVisualization/Qt Quick 2 Scatter Example" \ + "QtDataVisualization/Qt Quick 2 Surface Multiseries Example" \ + "QtGui/Analog Clock Window Example" \ + "QtGui/OpenGL Window Example" \ + "QtGui/Raster Window Example" \ + "QtLinguist/Arrow Pad Example" \ + "QtLinguistManual/Hello tr() Example" \ + "QtLocation/Map Viewer (QML)" \ + "QtLocation/Places Map (QML)" \ + "QtLocation/Plane Spotter (QML)" \ + "QtMultimedia/AudioEngine Example" \ + "QtMultimedia/Camera Example" \ + "QtMultimedia/QML Camera Example" \ + "QtMultimedia/QML Video Example" \ + "QtMultimedia/QML Video Shader Effects Example" \ + "QtNFC/Annotated URL Example" \ + "QtNFC/QML Poster Example" \ + "QtOpenGL/2D Painting Example" \ + "QtOpenGL/Hello GLES3 Example" \ + "QtOpenGL/Textures Example" \ + "QtPositioning/SatelliteInfo (C++/QML)" \ + "QtPositioning/Weather Info (C++/QML)" \ + "QtPurchasing/Qt Purchasing Examples - QtHangman" \ + "QtQML/Extending QML - Attached Properties Example" \ + "QtQML/Extending QML - Grouped Properties Example" \ + "QtQML/Extending QML - Methods Example" \ + "QtQML/Extending QML - Signal Support Example" \ + "QtQML/Qt Quick Examples - XMLHttpRequest" \ + "QtQml/Qt Quick Examples - XMLHttpRequest" \ + "QtQuick/*" \ + "QtQuickControls/*" \ + "QtQuickControls1/Qt Quick Controls 1 - Calendar Example" \ + "QtQuickControls1/Qt Quick Controls 1 - Gallery" \ + "QtQuickControls1/Qt Quick Controls 1 - Styles Example" \ + "QtQuickControls1/Qt Quick Controls 1 - Table View Example" \ + "QtQuickControls1/Qt Quick Controls 1 - Touch Gallery" \ + "QtQuickDialogs/*" \ + "QtQuickExtras/*" \ + "QtSCXML/Qt SCXML Calculator QML Example" \ + "QtSCXML/Qt SCXML Sudoku Example" \ + "QtSCXML/Qt SCXML Traffic Light Example (Dynamic)" \ + "QtSCXML/Qt SCXML Traffic Light QML Example (Dynamic)" \ + "QtSQL/Master Detail Example" \ + "QtSVG/Text Object Example" \ + "QtUiTools/Text Finder Example" \ + "QtWebView/Qt WebView Examples - Minibrowser" \ + "QtWidgets/Address Book Example" \ + "QtWidgets/Affine Transformations" \ + "QtWidgets/Analog Clock Example" \ + "QtWidgets/Animated Tiles Example" \ + "QtWidgets/Application Chooser Example" \ + "QtWidgets/Basic Layouts Example" \ + "QtWidgets/Border Layout Example" \ + "QtWidgets/Code Editor Example" \ + "QtWidgets/Colliding Mice Example" \ + "QtWidgets/Concentric Circles Example" \ + "QtWidgets/Digital Clock Example" \ + "QtWidgets/Dynamic Layouts Example" \ + "QtWidgets/Easing Curves Example" \ + "QtWidgets/Editable Tree Model Example" \ + "QtWidgets/Elided Label Example" \ + "QtWidgets/Event Transitions Example" \ + "QtWidgets/Fade Message Effect Example" \ + "QtWidgets/Flow Layout Example" \ + "QtWidgets/Font Sampler Example" \ + "QtWidgets/Frozen Column Example" \ + "QtWidgets/Gradients" \ + "QtWidgets/Group Box Example" \ + "QtWidgets/Image Composition Example" \ + "QtWidgets/Line Edits Example" \ + "QtWidgets/Mouse Button Tester" \ + "QtWidgets/Move Blocks Example" \ + "QtWidgets/Painter Paths Example" \ + "QtWidgets/Painter Paths Example" \ + "QtWidgets/Path Stroking" \ + "QtWidgets/Pixelator Example" \ + "QtWidgets/Recent Files Example" \ + "QtWidgets/SDI Example" \ + "QtWidgets/Scribble Example" \ + "QtWidgets/Simple Tree Model Example" \ + "QtWidgets/Sliders Example" \ + "QtWidgets/Spreadsheet" \ + "QtWidgets/Touch Dials Example" \ + "QtWidgets/Transformations Example" \ + "QtWidgets/Undo Framework" \ + "QtWidgets/Vector Deformation" \ + "QtWidgets/Wiggly Example" manifestmeta.android.tags = android -- cgit v1.2.3 From b711ee255515440b923a898f65f6afe13d63916f Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Sun, 23 Feb 2020 23:37:11 +0200 Subject: Examples: add scrollbar to allow viewing all options on Android This fix is most relevant for Android for affine and gradients examples. Currently, if the screen size is small the settings will show cramped and not usable. Thus, adding a scrollbar to fix that. Task-number: QTBUG-80717 Change-Id: Ic25460e5ce37a5c53bbcae48e11b6b787c45e999 Reviewed-by: BogDan Vatra --- examples/widgets/painting/affine/xform.cpp | 22 ++++++++++++++++------ examples/widgets/painting/gradients/gradients.cpp | 23 +++++++++++++++++------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/examples/widgets/painting/affine/xform.cpp b/examples/widgets/painting/affine/xform.cpp index 4e7cb91ce1..d7ed2125d2 100644 --- a/examples/widgets/painting/affine/xform.cpp +++ b/examples/widgets/painting/affine/xform.cpp @@ -787,8 +787,8 @@ XFormWidget::XFormWidget(QWidget *parent) view = new XFormView(this); view->setMinimumSize(200, 200); - QGroupBox *mainGroup = new QGroupBox(this); - mainGroup->setFixedWidth(180); + QWidget *mainContentWidget = new QWidget(); + QGroupBox *mainGroup = new QGroupBox(mainContentWidget); mainGroup->setTitle(tr("Affine Transformations")); QGroupBox *rotateGroup = new QGroupBox(mainGroup); @@ -837,10 +837,6 @@ XFormWidget::XFormWidget(QWidget *parent) whatsThisButton->setText(tr("What's This?")); whatsThisButton->setCheckable(true); - QHBoxLayout *viewLayout = new QHBoxLayout(this); - viewLayout->addWidget(view); - viewLayout->addWidget(mainGroup); - QVBoxLayout *rotateGroupLayout = new QVBoxLayout(rotateGroup); rotateGroupLayout->addWidget(rotateSlider); @@ -871,6 +867,20 @@ XFormWidget::XFormWidget(QWidget *parent) #endif mainGroupLayout->addWidget(whatsThisButton); + mainGroup->setLayout(mainGroupLayout); + + QVBoxLayout *mainContentLayout = new QVBoxLayout(); + mainContentLayout->addWidget(mainGroup); + mainContentWidget->setLayout(mainContentLayout); + + QScrollArea *mainScrollArea = new QScrollArea(); + mainScrollArea->setWidget(mainContentWidget); + mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + + QHBoxLayout *viewLayout = new QHBoxLayout(this); + viewLayout->addWidget(view); + viewLayout->addWidget(mainScrollArea); + connect(rotateSlider, &QSlider::valueChanged, view, &XFormView::changeRotation); connect(shearSlider, &QSlider::valueChanged, view, &XFormView::changeShear); connect(scaleSlider, &QSlider::valueChanged, view, &XFormView::changeScale); diff --git a/examples/widgets/painting/gradients/gradients.cpp b/examples/widgets/painting/gradients/gradients.cpp index d62ae93a15..cb1a0177e9 100644 --- a/examples/widgets/painting/gradients/gradients.cpp +++ b/examples/widgets/painting/gradients/gradients.cpp @@ -282,7 +282,8 @@ GradientWidget::GradientWidget(QWidget *parent) m_renderer = new GradientRenderer(this); - QGroupBox *mainGroup = new QGroupBox(this); + QWidget *mainContentWidget = new QWidget(); + QGroupBox *mainGroup = new QGroupBox(mainContentWidget); mainGroup->setTitle(tr("Gradients")); QGroupBox *editorGroup = new QGroupBox(mainGroup); @@ -327,11 +328,6 @@ GradientWidget::GradientWidget(QWidget *parent) whatsThisButton->setText(tr("What's This?")); whatsThisButton->setCheckable(true); - // Layouts - QHBoxLayout *mainLayout = new QHBoxLayout(this); - mainLayout->addWidget(m_renderer); - mainLayout->addWidget(mainGroup); - mainGroup->setFixedWidth(200); QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup); mainGroupLayout->addWidget(editorGroup); @@ -370,6 +366,21 @@ GradientWidget::GradientWidget(QWidget *parent) defaultsGroupLayout->addWidget(default3Button); editorGroupLayout->addWidget(default4Button); + mainGroup->setLayout(mainGroupLayout); + + QVBoxLayout *mainContentLayout = new QVBoxLayout(); + mainContentLayout->addWidget(mainGroup); + mainContentWidget->setLayout(mainContentLayout); + + QScrollArea *mainScrollArea = new QScrollArea(); + mainScrollArea->setWidget(mainContentWidget); + mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + + // Layouts + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->addWidget(m_renderer); + mainLayout->addWidget(mainScrollArea); + connect(m_editor, &GradientEditor::gradientStopsChanged, m_renderer, &GradientRenderer::setGradientStops); connect(m_linearButton, &QRadioButton::clicked, -- cgit v1.2.3 From 23785face5a01bf63334fd32975718468d5f816e Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Sat, 16 Nov 2019 16:02:29 +0200 Subject: QEventDispatcherWin32: unregister event notifiers on close When QEventDispatcherWin32::closingDown() is called, threadData->eventDispatcher is already nullptr and the application will no longer process the events. Thus, just as it works for socket notifiers and timers, it makes sense to disable all active event notifiers at this point. Otherwise, it seems possible that an object in signalled state can provoke a data race in the notifier's callback on 'edp' pointer, if QWin32EventDispatcher destructor is running simultaneously. Task-number: QTBUG-64152 Task-number: QTBUG-70214 Change-Id: I6e77f3eeca1b0ea639021e73b86798cba0200ebf Reviewed-by: Edward Welbourne Reviewed-by: Volker Hilsheimer --- src/corelib/kernel/qeventdispatcher_win.cpp | 8 ++++++++ src/corelib/kernel/qeventdispatcher_win_p.h | 1 + src/corelib/kernel/qwineventnotifier.cpp | 5 +---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 8616631603..f2216d4113 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -884,7 +884,11 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) return; } #endif + doUnregisterEventNotifier(notifier); +} +void QEventDispatcherWin32::doUnregisterEventNotifier(QWinEventNotifier *notifier) +{ Q_D(QEventDispatcherWin32); int i = d->winEventNotifierList.indexOf(notifier); @@ -996,6 +1000,10 @@ void QEventDispatcherWin32::closingDown() doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj); Q_ASSERT(d->active_fd.isEmpty()); + // clean up any eventnotifiers + while (!d->winEventNotifierList.isEmpty()) + doUnregisterEventNotifier(d->winEventNotifierList.first()); + // clean up any timers for (int i = 0; i < d->timerVec.count(); ++i) d->unregisterTimer(d->timerVec.at(i)); diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index e6620178d8..a482c8b7db 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -110,6 +110,7 @@ protected: QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0); virtual void sendPostedEvents(); void doUnregisterSocketNotifier(QSocketNotifier *notifier); + void doUnregisterEventNotifier(QWinEventNotifier *notifier); private: friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index db5d44b276..0c574e9a4b 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -198,11 +198,8 @@ void QWinEventNotifier::setEnabled(bool enable) d->enabled = enable; QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed(); - if (!eventDispatcher) { // perhaps application is shutting down - if (!enable && d->waitHandle != nullptr) - d->unregisterWaitObject(); + if (!eventDispatcher) // perhaps application is shutting down return; - } if (Q_UNLIKELY(thread() != QThread::currentThread())) { qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread"); return; -- cgit v1.2.3 From b4669b919048c1dbdac2b3e9b2e79f3d023aa078 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 26 Feb 2020 16:59:52 +0100 Subject: QMenu: hide when a QWidgetAction fires the trigged signal QMenu hides regularly when the user interacts with it, and manages the firing of signals based on that. It ignores if a QAction that is added to it fires the triggered() signal programmatically. With QWidgetActions added to the menu, the menu usually doesn't get interacted with directly, as the widget gets the input events. Since the action can be added to multiple menus, neither widget nor action can interact with the menus programmatically. Instead, the menu needs to hide when the widget action triggers. Test included that covers the case where a QWidgetAction is added to multiple menus that are visible. Documentation updated, and removed a redudant paragraph as a drive-by change. [ChangeLog][QtWidgets][QMenu] a popup menu hides when a QWidgetAction added to it fires the triggered signal. Change-Id: I69f378426a45c2e46cebdaa5e6f1b21c8fb03633 Fixes: QTBUG-10427 Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qmenu.cpp | 9 +-- tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp | 79 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index abe4e485c0..0233fa136d 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -1470,6 +1470,9 @@ void QMenuPrivate::_q_actionTriggered() } } activateCausedStack(list, action, QAction::Trigger, false); + // if a widget action fires, we need to hide the menu explicitly + if (qobject_cast(action)) + hideUpToMenuBar(); } } } @@ -1637,10 +1640,8 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) Widgets can be inserted into menus with the QWidgetAction class. Instances of this class are used to hold widgets, and are inserted - into menus with the addAction() overload that takes a QAction. - - Conversely, actions can be added to widgets with the addAction(), - addActions() and insertAction() functions. + into menus with the addAction() overload that takes a QAction. If the + QWidgetAction fires the triggered() signal, the menu will close. \warning To make QMenu visible on the screen, exec() or popup() should be used instead of show(). diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index d7d3a934f8..7e39138473 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -116,6 +116,7 @@ private slots: void QTBUG20403_nested_popup_on_shortcut_trigger(); void QTBUG47515_widgetActionEnterLeave(); void QTBUG8122_widgetActionCrashOnClose(); + void widgetActionTriggerClosesMenu(); void QTBUG_10735_crashWithDialog(); #ifdef Q_OS_MAC @@ -1407,6 +1408,84 @@ void tst_QMenu::QTBUG8122_widgetActionCrashOnClose() QTRY_VERIFY(menu->isHidden()); } +/*! + Test that a QWidgetAction that fires closes the menus that it is in. +*/ +void tst_QMenu::widgetActionTriggerClosesMenu() +{ + class ButtonAction : public QWidgetAction + { + public: + ButtonAction() + : QWidgetAction(nullptr) + {} + + void click() + { + if (pushButton) + pushButton->click(); + } + + protected: + QWidget *createWidget(QWidget *parent) + { + QPushButton *button = new QPushButton(QLatin1String("Button"), parent); + connect(button, &QPushButton::clicked, this, &QAction::trigger); + + if (!pushButton) + pushButton = button; + return button; + } + + private: + QPointer pushButton; + }; + + QMenu menu; + QMenu submenu; + + int menuTriggeredCount = 0; + int menuAboutToHideCount = 0; + QAction *actionTriggered = nullptr; + + connect(&menu, &QMenu::triggered, this, [&](QAction *action){ + ++menuTriggeredCount; + actionTriggered = action; + }); + connect (&menu, &QMenu::aboutToHide, this, [&](){ + ++menuAboutToHideCount; + }); + + QAction regularAction(QLatin1String("Action")); + ButtonAction widgetAction; + + submenu.addAction(®ularAction); + submenu.addAction(&widgetAction); + + menu.addMenu(&submenu); + menu.addAction(®ularAction); + menu.addAction(&widgetAction); + + menu.popup(QPoint(200,200)); + submenu.popup(QPoint(250,250)); + if (!QTest::qWaitForWindowExposed(&menu) || !QTest::qWaitForWindowExposed(&submenu)) + QSKIP("Failed to show menus, aborting test"); + + regularAction.trigger(); + QVERIFY(menu.isVisible()); + QVERIFY(submenu.isVisible()); + QCOMPARE(menuTriggeredCount, 1); + QCOMPARE(actionTriggered, ®ularAction); + menuTriggeredCount = 0; + actionTriggered = nullptr; + + widgetAction.click(); + QVERIFY(!menu.isVisible()); + QVERIFY(!submenu.isVisible()); + QCOMPARE(menuTriggeredCount, 1); + QCOMPARE(menuAboutToHideCount, 1); + QCOMPARE(actionTriggered, &widgetAction); +} class MyMenu : public QMenu { -- cgit v1.2.3 From 065ace2bca656467c3bc2ef760bfff1fd198dbdc Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 3 Mar 2020 11:29:23 +0100 Subject: Generate separate debug info for Qt tools too If Qt was configured with -separate-debug-info, Qt's tools should be separated from their debug information too. Fixes: QTBUG-56482 Change-Id: Ief0130db1787b767496d0052716183fe773460bf Reviewed-by: Ulf Hermann Reviewed-by: Kai Koehne --- mkspecs/features/qt_common.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf index 02460a2e0c..ac24b03b6b 100644 --- a/mkspecs/features/qt_common.prf +++ b/mkspecs/features/qt_common.prf @@ -20,11 +20,11 @@ qtConfig(c++1z): CONFIG += c++1z qtConfig(c++2a): CONFIG += c++2a qtConfig(c99): CONFIG += c99 qtConfig(c11): CONFIG += c11 +qtConfig(separate_debug_info): CONFIG += separate_debug_info qtConfig(stack-protector-strong): CONFIG += stack_protector_strong contains(TEMPLATE, .*lib) { # module and plugins unix:qtConfig(reduce_relocations): CONFIG += bsymbolic_functions - qtConfig(separate_debug_info): CONFIG += separate_debug_info !isEmpty(_QMAKE_SUPER_CACHE_): \ rplbase = $$dirname(_QMAKE_SUPER_CACHE_)/[^/][^/]* -- cgit v1.2.3 From 14420b359b2d14d202df8df841af5e88f16352a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C4=8Cuki=C4=87?= Date: Fri, 10 Jan 2020 18:13:41 +0100 Subject: Add operator-> to the key-value iterator for QHash and QMap This patch adds the arrow operator to the stl-like key-value iterator (QKeyValueIterator) for QMap and QHash. This allows using normal member access syntax it->first and it->second instead of having to use (*it).first and (*it).second. [ChangeLog][QtCore][Containers] Added operator-> to the key-value iterator for QHash/QMap. Change-Id: I9cfa6480784ebce147fcfbf37fec5ad0080e2899 Reviewed-by: Vitaly Fanaskov --- src/corelib/tools/qiterator.h | 26 +++++++++++++++++++++++++- src/corelib/tools/qiterator.qdoc | 13 +++++++++++-- tests/auto/corelib/tools/qhash/tst_qhash.cpp | 6 ++++++ tests/auto/corelib/tools/qmap/tst_qmap.cpp | 6 ++++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h index 84a0e116ca..c4665c7c87 100644 --- a/src/corelib/tools/qiterator.h +++ b/src/corelib/tools/qiterator.h @@ -195,7 +195,6 @@ public: typedef typename Iterator::iterator_category iterator_category; typedef typename Iterator::difference_type difference_type; typedef std::pair value_type; - typedef const value_type *pointer; typedef const value_type &reference; QKeyValueIterator() = default; @@ -206,6 +205,31 @@ public: return std::pair(i.key(), i.value()); } + struct pointer { + pointer(value_type&& r_) + : r(std::move(r_)) + {} + + pointer() = default; + pointer(const pointer &other) = default; + pointer(pointer &&other) = default; + pointer& operator=(const pointer &other) = default; + pointer& operator=(pointer &&other) = default; + + value_type& operator*() const { + return r; + } + + value_type r; + const value_type *operator->() const { + return &r; + } + }; + + pointer operator->() const { + return pointer(std::pair(i.key(), i.value())); + } + friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i == rhs.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 3531fb202c..ed39fe28c3 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -57,7 +57,7 @@ \internal */ -/*! \typedef QKeyValueIterator::pointer +/*! \struct QKeyValueIterator::pointer \internal */ @@ -75,11 +75,20 @@ Constructs a QKeyValueIterator on top of \a o. */ -/*! \fn template const T &QKeyValueIterator::operator*() const +/*! \fn template std::pair QKeyValueIterator::operator*() const Returns the current entry as a pair. */ +/*! \fn template pointer QKeyValueIterator::operator->() const + + Returns the current entry as a pointer-like object to the pair. + + \since 5.15 + + \sa operator*() +*/ + /*! \fn template bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) \relates QKeyValueIterator diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index b98ac38288..134b3ff4c0 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -1144,6 +1144,12 @@ void tst_QHash::keyValueIterator() entry_type pair(it.key(), it.value()); QCOMPARE(*key_value_it, pair); + QCOMPARE(key_value_it->first, pair.first); + QCOMPARE(key_value_it->second, pair.second); + QCOMPARE(&(*key_value_it).first, &it.key()); + QCOMPARE(&key_value_it->first, &it.key()); + QCOMPARE(&(*key_value_it).second, &it.value()); + QCOMPARE(&key_value_it->second, &it.value()); ++key_value_it; ++it; } diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index c3a8a88f0c..ba4b190f06 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -882,6 +882,12 @@ void tst_QMap::keyValueIterator() entry_type pair(it.key(), it.value()); QCOMPARE(*key_value_it, pair); + QCOMPARE(key_value_it->first, pair.first); + QCOMPARE(key_value_it->second, pair.second); + QCOMPARE(&(*key_value_it).first, &it.key()); + QCOMPARE(&key_value_it->first, &it.key()); + QCOMPARE(&(*key_value_it).second, &it.value()); + QCOMPARE(&key_value_it->second, &it.value()); ++key_value_it; ++it; } -- cgit v1.2.3 From 1edf586ed73596e1d53a0d612a77f86ea34a65bf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 28 Feb 2020 08:26:49 -0800 Subject: QMimeXMLProvider: fix another issue with -no-mimetype-database The compiler must emit the destructor for the members of a class in an inline constructor, in case the constructor throws. This won't work in Qt 5.15 due to QList requiring knowing whether QMimeMagicRuleMatcher is trivial or not. Another solution would be to use QVector. Fixes: QTBUG-82547 Change-Id: Ia8b65350cd5d49debca9fffd15f79db872ed7c0c Reviewed-by: David Faure --- src/corelib/mimetypes/qmimeprovider.cpp | 10 +++++++++- src/corelib/mimetypes/qmimeprovider_p.h | 5 +---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 4aee772366..9dba72923a 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -664,7 +664,15 @@ QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnu load(data, size); } -#endif +#else // !QT_CONFIG(mimetype_database) +// never called in release mode, but some debug builds may need +// this to be defined. +QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum) + : QMimeProviderBase(db, QString()) +{ + Q_UNREACHABLE(); +} +#endif // QT_CONFIG(mimetype_database) QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory) : QMimeProviderBase(db, directory) diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h index c4e712b318..9c91903684 100644 --- a/src/corelib/mimetypes/qmimeprovider_p.h +++ b/src/corelib/mimetypes/qmimeprovider_p.h @@ -135,13 +135,10 @@ public: enum InternalDatabaseEnum { InternalDatabase }; #if QT_CONFIG(mimetype_database) enum : bool { InternalDatabaseAvailable = true }; - QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum); #else enum : bool { InternalDatabaseAvailable = false }; - QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum) - : QMimeProviderBase(db, QString()) - { Q_UNREACHABLE(); }; #endif + QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum); QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory); ~QMimeXMLProvider(); -- cgit v1.2.3 From 5d9d3ff3269f92366b022e17485fa4dd98f5ba95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 19:36:26 +0100 Subject: macOS: Reduce save dialog extension filters to their last component NSSavePanel does not deal well with multi-part extensions, to the point where it will fail to open if that's the only acceptable extension. We follow Chromium's lead here and reduce the extension to its last component, which enables selecting and saving files such as 'foo.tar.gz'. To improve the user experience we always show file extensions when we detect a multi-part extension. This makes it clearer what the final extension will be, and avoids confusing macOS about the intention of the user when choosing a file that without the final extension also matches another known extension. Fixes: QTBUG-38303 Fixes: QTBUG-44227 Change-Id: Id0cee84f758c2cd59fcf1b339caa30f7da07dd1e Reviewed-by: Timur Pocheptsov --- .../platforms/cocoa/qcocoafiledialoghelper.mm | 61 +++++++++++++++------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 6aa21d78d1..8b76e45616 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -419,8 +419,7 @@ static QString strippedText(QString s) [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead? if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) { - const QStringList ext = [self acceptableExtensionsForSave]; - [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)]; + [self recomputeAcceptableExtensionsForSave]; } else { [mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel } @@ -457,25 +456,49 @@ static QString strippedText(QString s) } /* - Returns a list of extensions (e.g. "png", "jpg", "gif") - for the current name filter. If a filter do not conform - to the format *.xyz or * or *.*, an empty list - is returned meaning accept everything. + Computes a list of extensions (e.g. "png", "jpg", "gif") + for the current name filter, and updates the save panel. + + If a filter do not conform to the format *.xyz or * or *.*, + all files types are allowed. + + Extensions with more than one part (e.g. "tar.gz") are + reduced to their final part, as NSSavePanel does not deal + well with multi-part extensions. */ -- (QStringList)acceptableExtensionsForSave -{ - QStringList result; - for (int i=0; icount(); ++i) { - const QString &filter = mSelectedNameFilter->at(i); - if (filter.startsWith(QLatin1String("*.")) - && !filter.contains(QLatin1Char('?')) - && filter.count(QLatin1Char('*')) == 1) { - result += filter.mid(2); - } else { - return QStringList(); // Accept everything - } +- (void)recomputeAcceptableExtensionsForSave +{ + QStringList fileTypes; + for (const QString &filter : *mSelectedNameFilter) { + if (!filter.startsWith(QLatin1String("*."))) + continue; + + if (filter.contains(QLatin1Char('?'))) + continue; + + if (filter.count(QLatin1Char('*')) != 1) + continue; + + auto extensions = filter.split('.', Qt::SkipEmptyParts); + fileTypes += extensions.last(); + + // Explicitly show extensions if we detect a filter + // that has a multi-part extension. This prevents + // confusing situations where the user clicks e.g. + // 'foo.tar.gz' and 'foo.tar' is populated in the + // file name box, but when then clicking save macOS + // will warn that the file needs to end in .gz, + // due to thinking the user tried to save the file + // as a 'tar' file instead. Unfortunately this + // property can only be set before the panel is + // shown, so it will not have any effect when + // swithcing filters in an already opened dialog. + if (extensions.size() > 2) + mSavePanel.extensionHidden = NO; } - return result; + + mSavePanel.allowedFileTypes = fileTypes.isEmpty() ? nil + : qt_mac_QStringListToNSMutableArray(fileTypes); } - (QString)removeExtensions:(const QString &)filter -- cgit v1.2.3 From 048f0a00fa7b46f531fbe3ed6d1babae9858e8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 2 Mar 2020 16:08:05 +0100 Subject: macOS: Don't create QMacCGContext when printing We adopt the context of the print session, so the code is not needed, and would just produce a warning since QMacCGContext didn't know what to do about the printer paint device. Change-Id: I9ac079f5cb5d98022045632592d0e375710eecc3 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 00b2267f0d..df71f76644 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -394,16 +394,19 @@ QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev) d->cosmeticPenSize = 1; d->current.clipEnabled = false; d->pixelSize = QPoint(1,1); - QMacCGContext ctx(pdev); - d->hd = CGContextRetain(ctx); - if (d->hd) { - d->saveGraphicsState(); - d->orig_xform = CGContextGetCTM(d->hd); - if (d->shading) { - CGShadingRelease(d->shading); - d->shading = nullptr; + + if (pdev->devType() != QInternal::Printer) { + QMacCGContext ctx(pdev); + d->hd = CGContextRetain(ctx); + if (d->hd) { + d->saveGraphicsState(); + d->orig_xform = CGContextGetCTM(d->hd); + if (d->shading) { + CGShadingRelease(d->shading); + d->shading = nullptr; + } + d->setClip(nullptr); //clear the context's clipping } - d->setClip(nullptr); //clear the context's clipping } setActive(true); -- cgit v1.2.3