From 8957cb2682d874403c3ee08c98bfd544a60c6da4 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 3 Apr 2019 14:18:20 +0200 Subject: [PATCH 01/52] Windows QPA: Fix mouse button reported in non-client events The current mouse buttons state was being retrieved from WPARAM for all mouse messages. However, for non-client messages this parameter contains unrelated information, which resulted in non-client events reporting incorrect button state. Changing it to retrieve state using GetAsyncKeyState() for non-client messages, like in the legacy mouse handler implementation. Fixes: QTBUG-74649 Change-Id: Ia246164208707072e584dd521697e9d31d3e65ad Reviewed-by: Friedemann Kleint --- .../windows/qwindowspointerhandler.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index f1960f15857..2673c04c488 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -250,6 +250,23 @@ static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) return result; } +static Qt::MouseButtons queryMouseButtons() +{ + Qt::MouseButtons result = Qt::NoButton; + const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON); + if (GetAsyncKeyState(VK_LBUTTON) < 0) + result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton; + if (GetAsyncKeyState(VK_RBUTTON) < 0) + result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton; + if (GetAsyncKeyState(VK_MBUTTON) < 0) + result |= Qt::MidButton; + if (GetAsyncKeyState(VK_XBUTTON1) < 0) + result |= Qt::XButton1; + if (GetAsyncKeyState(VK_XBUTTON2) < 0) + result |= Qt::XButton2; + return result; +} + static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); @@ -681,7 +698,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); if (et == QtWindows::MouseWheelEvent) @@ -709,7 +725,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, const MouseEvent mouseEvent = eventFromMsg(msg); if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { - QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, + const Qt::MouseButtons nonclientButtons = queryMouseButtons(); + QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, nonclientButtons, mouseEvent.button, mouseEvent.type, keyModifiers, source); return false; // Allow further event processing } @@ -725,6 +742,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, return true; } + const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); handleEnterLeave(window, currentWindowUnderPointer, globalPos); From 4451c86dfd134f35795383bf632f161629a720e4 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 27 Mar 2019 19:30:58 +0000 Subject: [PATCH 02/52] Doc-fixes in QRandomGenerator::bounded(int...) They return int, not quint32. Change-Id: I9879b58cccf9ea324ea1fc0c567a9d30b82fa44d Reviewed-by: Thiago Macieira (cherry picked from commit 6ed2ea86db63c72a38a60543da5a95d3543d39b1) --- src/corelib/global/qrandom.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 6195c324e72..90df8653a73 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -930,7 +930,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel */ /*! - \fn quint32 QRandomGenerator::bounded(int highest) + \fn int QRandomGenerator::bounded(int highest) \overload Generates one random 32-bit quantity in the range between 0 (inclusive) and @@ -957,7 +957,6 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel \snippet code/src_corelib_global_qrandom.cpp 14 - Note that this function cannot be used to obtain values in the full 32-bit range of quint32. Instead, use generate(). @@ -965,7 +964,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel */ /*! - \fn quint32 QRandomGenerator::bounded(int lowest, int highest) + \fn int QRandomGenerator::bounded(int lowest, int highest) \overload Generates one random 32-bit quantity in the range between \a lowest From f5da03ae78d1ae5f6cbd997c69711b9b7f13aab1 Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Mon, 1 Apr 2019 13:35:31 +0300 Subject: [PATCH 03/52] Add changes file for Qt 5.12.3 Edited-By: Thiago Macieira Change-Id: I26354551e7d3a6573bad0aa3851055f482a9a242 Reviewed-by: Thiago Macieira Reviewed-by: Lars Knoll --- dist/changes-5.12.3 | 82 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 dist/changes-5.12.3 diff --git a/dist/changes-5.12.3 b/dist/changes-5.12.3 new file mode 100644 index 00000000000..e6636fc1538 --- /dev/null +++ b/dist/changes-5.12.3 @@ -0,0 +1,82 @@ +Qt 5.12.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Third-Party Code * +**************************************************************************** + + - Changed classification of the wintab license from Public Domain to + Custom. + +**************************************************************************** +* QtCore * +**************************************************************************** + + - Event system: + * [QTBUG-72438] Fixed a possible race condition on Windows that would + cause an interrupted event loop to be stuck until more events were + posted. + + - Logging system: + * [QTBUG-74359] Fixed the compilation of qCDebug("", ...) when debug + output was disabled. + + - QCollator: + * [QTBUG-74209] Fixed a bug that caused QCompare to incorrect return a + sorting order on Windows if the Win32 API failed. + + - QDateTime / QTimeZone: + * [QTBUG-74614] Fixed handling of timezones that contain no DST + transitions. + + - QProcess: + * [QTBUG-73778] Fixed a crash when calling closeWriteChannel() on Windows. + +**************************************************************************** +* QtSql * +**************************************************************************** + + - When cross-compiling pg_config, mysql_config are not looked up in PATH + anymore. Pass -psql_config path/to/pg_config or -mysql_config + path/to/mysql_config to explicitly enable PSQL or MySQL in this setup. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + + - Android: + * Text fields with ImhNoPredictiveText set are no longer working around + keyboards that disregard this setting. To enforce the workaround, the + environment variable + QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT should be set. + + * [QTBUG-74029] Added entries in the AndroidManifest.xml for specific + portrait and landscape splash screens. If one is present for the current + orientation, it will be preferred over the generic one. + + - Linux: + * [QTBUG-74526] Changed the way we use the statx() system call to use a + fallback mechanism provided by the GNU C library. This should allow Qt + applications that are compiled with glibc >= 2.28 to run even on kernels + older than 4.11. + + - Windows: + * [QTBUG-74062] Fixed QToolTip pop-ups and QComboBox animation pop-ups + being off by a few pixels on Windows 10. + From 534df5a33bd6a3d0d00194212cf868a9ef57bd53 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Thu, 28 Mar 2019 18:33:44 +0300 Subject: [PATCH 04/52] Fix QTabletEvent::uniqueId() when Qt uses WinInk A new 'pointerId' is assigned to the stylus every time it enters tablet's proximity. But applications expect this ID be constant, at least during one application run. Therefore, it needs to use 'sourceDevice' instead. Basically, WinInk doesn't have an ability to distinguich two different styluses connected to the same tablet. We cannot do anything about it, it is supported only in WinTab. Task-number: QTBUG-74700 Change-Id: I8328f1e5102b037b370082e69e965ab68b487882 Reviewed-by: Andre de la Rocha --- .../platforms/windows/qwindowspointerhandler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 2673c04c488..9a8b5d51215 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -548,7 +548,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) return false; - const quint32 pointerId = penInfo->pointerInfo.pointerId; + const qint64 sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice; const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y); const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left) @@ -564,7 +564,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase - << __FUNCTION__ << " pointerId=" << pointerId + << __FUNCTION__ << " sourceDevice=" << sourceDevice << " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos << " message=" << hex << msg.message << " flags=" << hex << penInfo->pointerInfo.pointerFlags; @@ -587,7 +587,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin switch (msg.message) { case WM_POINTERENTER: { - QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, pointerId); + QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, sourceDevice); m_windowUnderPointer = window; // The local coordinates may fall outside the window. // Wait until the next update to send the enter event. @@ -600,12 +600,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin m_windowUnderPointer = nullptr; m_currentWindow = nullptr; } - QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, pointerId); + QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, sourceDevice); break; case WM_POINTERDOWN: case WM_POINTERUP: case WM_POINTERUPDATE: { - QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(pointerId).target; // Pass to window that grabbed it. + QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(sourceDevice).target; // Pass to window that grabbed it. if (!target && m_windowUnderPointer) target = m_windowUnderPointer; if (!target) @@ -624,7 +624,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, pressure, xTilt, yTilt, tangentialPressure, rotation, z, - pointerId, keyModifiers); + sourceDevice, keyModifiers); return false; // Allow mouse messages to be generated. } } From 1d1dcd8d6c64a35b94b351f72cc447771834df49 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 11 Mar 2019 14:27:04 +0100 Subject: [PATCH 05/52] Fix context loss in QOpenGLWidget upon tlw change with AA_ShareOpenGLContexts The logic introduced in 2ea90c56 has an issue: it resets (destroy the context and co.) upong TLW change even when AA_ShareOpenGLContexts is set, and that is just wrong and goes against what the docs claim. Fixes: QTBUG-74307 Change-Id: Ib519045c1d9842664cbe602d4e6425660cf638b5 Reviewed-by: Allan Sandfeld Jensen --- src/widgets/kernel/qopenglwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 89f860150f2..7aef74c507e 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -1448,7 +1448,8 @@ bool QOpenGLWidget::event(QEvent *e) { // Special case: did grabFramebuffer() for a hidden widget that then became visible. // Recreate all resources since the context now needs to share with the TLW's. - d->reset(); + if (!qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) + d->reset(); } if (!d->initialized && !size().isEmpty() && window()->windowHandle()) { d->initialize(); From b1709bdc723ee62d13cdb11d77e4fbe03a0c44bf Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 8 Apr 2019 15:51:04 +0200 Subject: [PATCH 06/52] Windows QPA: Fix Drag and Drop of images onto MS PowerPoint Use the PNG format only for transparent images. Fixes: QTBUG-64322 Change-Id: I5e02132ca446876e20fcf46f2ef8daa599e85e71 Reviewed-by: Andre de la Rocha --- src/plugins/platforms/windows/qwindowsmime.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 96e34fb44c7..030d8d1e0f1 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -1087,7 +1087,10 @@ bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMi const QImage image = qvariant_cast(mimeData->imageData()); if (image.isNull()) return false; - return cf == CF_DIBV5 || (cf == CF_DIB) || cf == int(CF_PNG); + // QTBUG-64322: Use PNG only for transparent images as otherwise MS PowerPoint + // cannot handle it. + return cf == CF_DIBV5 || cf == CF_DIB + || (cf == int(CF_PNG) && image.hasAlphaChannel()); } bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const From bafa676d080509fcef3e1189ddc8fe06730dcac9 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 9 Apr 2019 16:16:06 +0200 Subject: [PATCH 07/52] QEglConfigChooser: Silence warning about fallthrough Add Q_FALLTHROUGH, fixing: qeglconvenience.cpp:267:9: warning: this statement may fall through [-Wimplicit-fallthrough=] Change-Id: I764a5821f98982bc94ce5dc6a4efa81a431fd369 Reviewed-by: Laszlo Agocs --- src/platformsupport/eglconvenience/qeglconvenience.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index 020d035bf7a..5ee4773b709 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -268,7 +268,7 @@ EGLConfig QEglConfigChooser::chooseConfig() configureAttributes.append(EGL_OPENGL_ES_BIT); break; } - // fall through + Q_FALLTHROUGH(); default: needsES2Plus = true; break; From 3f17029aa12eafd3f8ddd5e0b246a6bf22eabfe3 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 4 Feb 2019 17:10:22 +0100 Subject: [PATCH 08/52] Fix resolving NTFS symbolic links that point to UNC shares Without this change, the target of a symbolic link that points to a UNC share would include UNC in the target path, and not be correctly made absolute. Add a relevant test case, and use the opportunity to factor out the helper code that creates NTFS symlinks into a function that takes care of error handling. The file created with the new test case only gets cleaned up correctly when passing the file path into QDir::rmdir, which is either way the right thing to do. [ChangeLog][QtCore][QFileInfo] Fixed resolving of symbolic links to UNC shares on NTFS file systems. Change-Id: I9ba75d627aedf7c4cc289f0cb71088d795d30d8a Fixes: QTBUG-73688 Task-number: QTBUG-63970 Task-number: QTBUG-30401 Task-number: QTBUG-20791 Reviewed-by: Thiago Macieira --- src/corelib/io/qfilesystemengine_win.cpp | 13 +++- .../corelib/io/qfileinfo/tst_qfileinfo.cpp | 68 ++++++++++++------- 2 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 2020e34f93d..279918b812b 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -310,9 +310,18 @@ static QString readSymLink(const QFileSystemEntry &link) const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset]; result = QString::fromWCharArray(PathBuffer, length); } - // cut-off "//?/" and "/??/" - if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) + // cut-off "\\?\" and "\??\" + if (result.size() > 4 + && result.at(0) == QLatin1Char('\\') + && result.at(2) == QLatin1Char('?') + && result.at(3) == QLatin1Char('\\')) { result = result.mid(4); + // cut off UNC in addition when the link points at a UNC share + // in which case we need to prepend another backslash to get \\server\share + if (result.leftRef(3) == QLatin1String("UNC")) { + result.replace(0, 3, QLatin1Char('\\')); + } + } } free(rdb); CloseHandle(handle); diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 017eebe153c..baf78f6a04f 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -95,6 +95,33 @@ inline bool qIsLikelyToBeNfs(const QString &path) #endif } +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +enum NtfsTargetType { + NtfsTargetFile = 0x0, + NtfsTargetDir = 0x1 +}; + +static bool createNtfsSymLinkHelper(const QString &path, const QString &target, NtfsTargetType targetType) +{ + DWORD dwFlags = targetType; + DWORD err = ERROR_SUCCESS; + + SetLastError(0); + const bool result = CreateSymbolicLink(reinterpret_cast(path.utf16()), + reinterpret_cast(target.utf16()), dwFlags); + err = GetLastError(); + + // CreateSymbolicLink can return TRUE & still fail to create the link, + // the error code in that case might be ERROR_PRIVILEGE_NOT_HELD (1314) + if (!result || err != ERROR_SUCCESS) { + qWarning() << "Error creating NTFS-symlink from:" << path << "to" << target << ":" << qt_error_string(err); + + return false; + } + return true; +} +#endif + static QString seedAndTemplate() { QString base; @@ -704,18 +731,12 @@ void tst_QFileInfo::canonicalFilePath() #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) { - // CreateSymbolicLink can return TRUE & still fail to create the link, - // the error code in that case is ERROR_PRIVILEGE_NOT_HELD (1314) - SetLastError(0); const QString linkTarget = QStringLiteral("res"); - BOOL ret = CreateSymbolicLink((wchar_t*)linkTarget.utf16(), (wchar_t*)m_resourcesDir.utf16(), 1); - DWORD dwErr = GetLastError(); + BOOL ret = createNtfsSymLinkHelper(linkTarget, m_resourcesDir, NtfsTargetDir); if (!ret) QSKIP("Symbolic links aren't supported by FS"); QString currentPath = QDir::currentPath(); bool is_res_Current = QDir::setCurrent(linkTarget); - if (!is_res_Current && dwErr == 1314) - QSKIP("Not enough privilages to create Symbolic links"); QCOMPARE(is_res_Current, true); const QString actualCanonicalPath = QFileInfo("file1").canonicalFilePath(); QVERIFY(QDir::setCurrent(currentPath)); @@ -1482,19 +1503,12 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() file.open(QIODevice::ReadWrite); file.close(); - DWORD err = ERROR_SUCCESS ; + bool result = true; if (!pwd.exists("abs_symlink")) - if (!CreateSymbolicLink((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)) - err = GetLastError(); - if (err == ERROR_SUCCESS && !pwd.exists(relSymlink)) - if (!CreateSymbolicLink((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)) - err = GetLastError(); - if (err != ERROR_SUCCESS) { - wchar_t errstr[0x100]; - DWORD count = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, - 0, err, 0, errstr, 0x100, 0); - QString error(QString::fromWCharArray(errstr, count)); - qWarning() << error; + result = createNtfsSymLinkHelper(absSymlink, absTarget, NtfsTargetDir); + if (result && !pwd.exists(relSymlink)) + result = createNtfsSymLinkHelper(relSymlink, relTarget, NtfsTargetDir); + if (!result) { //we need at least one data set for the test not to assert fail when skipping _data function QDir target("target"); QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath(); @@ -1517,13 +1531,21 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() QString relSymlink = "rel_symlink.cpp"; QString relToRelTarget = QDir::toNativeSeparators(relativeDir.relativeFilePath(target.absoluteFilePath())); QString relToRelSymlink = "relative/rel_symlink"; - QVERIFY(pwd.exists("abs_symlink.cpp") || CreateSymbolicLink((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x0)); - QVERIFY(pwd.exists(relSymlink) || CreateSymbolicLink((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x0)); - QVERIFY(pwd.exists(relToRelSymlink) || CreateSymbolicLink((wchar_t*)relToRelSymlink.utf16(), (wchar_t*)relToRelTarget.utf16(),0x0)); + QVERIFY(pwd.exists("abs_symlink.cpp") || createNtfsSymLinkHelper(absSymlink, absTarget, NtfsTargetFile)); + QVERIFY(pwd.exists(relSymlink) || createNtfsSymLinkHelper(relSymlink, relTarget, NtfsTargetFile)); + QVERIFY(pwd.exists(relToRelSymlink) || createNtfsSymLinkHelper(relToRelSymlink, relToRelTarget, NtfsTargetFile)); QTest::newRow("absolute file symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); QTest::newRow("relative file symlink") << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); QTest::newRow("relative to relative file symlink") << relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); } + { + // Symlink to UNC share + pwd.mkdir("unc"); + QString uncTarget = QStringLiteral("//") + QtNetworkSettings::winServerName() + "/testshare"; + QString uncSymlink = QDir::toNativeSeparators(pwd.absolutePath().append("\\unc\\link_to_unc")); + QVERIFY(pwd.exists("link_to_unc") || createNtfsSymLinkHelper(uncSymlink, uncTarget, NtfsTargetDir)); + QTest::newRow("UNC symlink") << uncSymlink << true << uncTarget << uncTarget; + } //Junctions QString target = "target"; @@ -1570,7 +1592,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks() // Ensure that junctions, mountpoints are removed. If this fails, do not remove // temporary directory to prevent it from trashing the system. if (fi.isDir()) { - if (!QDir().rmdir(fi.fileName())) { + if (!QDir().rmdir(fi.filePath())) { qWarning("Unable to remove NTFS junction '%s'', keeping '%s'.", qPrintable(fi.fileName()), qPrintable(QDir::toNativeSeparators(m_dir.path()))); m_dir.setAutoRemove(false); From 605634a88a05f175de77e1c7af59fd2a2e0cbc41 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 25 Mar 2019 14:44:14 +0100 Subject: [PATCH 09/52] Doc: Note Q[Plain]TextEdit keeping formatting in some cases Fixes: QTBUG-72427 Change-Id: Ifddabb175c480b64282bd8c8fdb9edab4c7ecf44 Reviewed-by: Venugopal Shivashankar --- src/widgets/widgets/qplaintextedit.cpp | 16 ++++++++++++++-- src/widgets/widgets/qtextedit.cpp | 23 +++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index 57f2dec8f7c..0b5e69b6c3b 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -1239,6 +1239,8 @@ void QPlainTextEditPrivate::ensureViewportLayouted() This property gets and sets the plain text editor's contents. The previous contents are removed and undo/redo history is reset when this property is set. + currentCharFormat() is also reset, unless textCursor() is already at the + beginning of the document. By default, for an editor with no contents, this property contains an empty string. */ @@ -1518,7 +1520,12 @@ void QPlainTextEdit::paste() /*! Deletes all the text in the text edit. - Note that the undo/redo history is cleared by this function. + Notes: + \list + \li The undo/redo history is also cleared. + \li currentCharFormat() is reset, unless textCursor() + is already at the beginning of the document. + \endlist \sa cut(), setPlainText() */ @@ -1651,7 +1658,12 @@ void QPlainTextEdit::timerEvent(QTimerEvent *e) \a text is interpreted as plain text. - Note that the undo/redo history is cleared by this function. + Notes: + \list + \li The undo/redo history is also cleared. + \li currentCharFormat() is reset, unless textCursor() + is already at the beginning of the document. + \endlist \sa toPlainText() */ diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index e3a45680efc..ab636660d71 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -548,7 +548,8 @@ void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect) This property gets and sets the text editor's contents as plain text. Previous contents are removed and undo/redo history is reset - when the property is set. + when the property is set. currentCharFormat() is also reset, unless + textCursor() is already at the beginning of the document. If the text edit has another content type, it will not be replaced by plain text if you call toPlainText(). The only exception to this @@ -1026,7 +1027,12 @@ void QTextEdit::paste() /*! Deletes all the text in the text edit. - Note that the undo/redo history is cleared by this function. + Notes: + \list + \li The undo/redo history is also cleared. + \li currentCharFormat() is reset, unless textCursor() + is already at the beginning of the document. + \endlist \sa cut(), setPlainText(), setHtml() */ @@ -1131,9 +1137,13 @@ void QTextEdit::timerEvent(QTimerEvent *e) Changes the text of the text edit to the string \a text. Any previous text is removed. - \a text is interpreted as plain text. - - Note that the undo/redo history is cleared by this function. + Notes: + \list + \li \a text is interpreted as plain text. + \li The undo/redo history is also cleared. + \li currentCharFormat() is reset, unless textCursor() + is already at the beginning of the document. + \endlist \sa toPlainText() */ @@ -1167,7 +1177,8 @@ QString QTextEdit::toPlainText() const setHtml() changes the text of the text edit. Any previous text is removed and the undo/redo history is cleared. The input text is - interpreted as rich text in html format. + interpreted as rich text in html format. currentCharFormat() is also + reset, unless textCursor() is already at the beginning of the document. \note It is the responsibility of the caller to make sure that the text is correctly decoded when a QString containing HTML is created From 53d62b8fcbb639bd625777c8f1c01764445fb1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 9 Apr 2019 15:02:38 +0200 Subject: [PATCH 10/52] macOS: set layer.delegate when setting a layer Fixes flicker with Qt 5.12.2 on macOS 10.14.4. Change-Id: Ibb866d4339ecafae5fb573a653a2fb0f6238d704 Reviewed-by: Andy Shaw --- src/plugins/platforms/cocoa/qnsview_drawing.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index 490dbe8c4cb..3690d6ebb4e 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -154,6 +154,7 @@ << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS"); [super setLayer:layer]; + layer.delegate = self; } - (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy From 7c74048e94257c5cdc367c3144dc0e26adf06a56 Mon Sep 17 00:00:00 2001 From: wdl Date: Fri, 29 Mar 2019 18:09:13 +0800 Subject: [PATCH 11/52] xcb_egl: Correctly select OpenGL ES render type if user requested Fixes: QTBUG-74736 Change-Id: I8f01857c81e7a831da659102052ca73c101818cd Reviewed-by: Laszlo Agocs --- .../eglconvenience/qeglplatformcontext.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 9d8bf07af84..e44918823b7 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -134,7 +134,7 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share) { - m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig); + m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig, format); // m_format now has the renderableType() resolved (it cannot be Default anymore) // but does not yet contain version, profile, options. m_shareContext = share ? static_cast(share)->m_eglContext : 0; @@ -248,6 +248,12 @@ void QEGLPlatformContext::adopt(const QVariant &nativeHandle, QPlatformOpenGLCon value = 0; eglQueryContext(m_eglDisplay, context, EGL_CONTEXT_CLIENT_TYPE, &value); if (value == EGL_OPENGL_API || value == EGL_OPENGL_ES_API) { + // if EGL config supports both OpenGL and OpenGL ES render type, + // q_glFormatFromConfig() with the default "referenceFormat" parameter + // will always figure it out as OpenGL render type. + // We can override it to match user's real render type. + if (value == EGL_OPENGL_ES_API) + m_format.setRenderableType(QSurfaceFormat::OpenGLES); m_api = value; eglBindAPI(m_api); } else { From 60181f13a35b05bce664ba5f6cfa7a9d6ae2dc7d Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 29 Mar 2019 10:54:43 +0100 Subject: [PATCH 12/52] QShaderGenerator: fix substitution for attributes on GL2/ES2 GL2/ES2 expect it to be attribute and not in like later versions of OpenGL. Task-number: QTBUG-74829 Change-Id: Iddd22386ed315d6e6843d8225e49a4b73b6ad9ba Reviewed-by: Sean Harmer --- src/gui/util/qshaderformat.cpp | 17 +- src/gui/util/qshaderformat_p.h | 13 ++ src/gui/util/qshadergenerator.cpp | 5 +- src/gui/util/qshadernodesloader.cpp | 11 + .../qshadergenerator/tst_qshadergenerator.cpp | 213 ++++++++++++------ 5 files changed, 189 insertions(+), 70 deletions(-) diff --git a/src/gui/util/qshaderformat.cpp b/src/gui/util/qshaderformat.cpp index 373bfb9e7ec..e4e37181992 100644 --- a/src/gui/util/qshaderformat.cpp +++ b/src/gui/util/qshaderformat.cpp @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE QShaderFormat::QShaderFormat() Q_DECL_NOTHROW : m_api(NoApi) + , m_shaderType(Fragment) { } @@ -106,6 +107,9 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW if (m_version < other.m_version) return false; + if (m_shaderType != other.m_shaderType) + return false; + const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(), m_extensions.constEnd(), other.m_extensions.constBegin(), @@ -119,12 +123,23 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW return true; } +QShaderFormat::ShaderType QShaderFormat::shaderType() const Q_DECL_NOTHROW +{ + return m_shaderType; +} + +void QShaderFormat::setShaderType(QShaderFormat::ShaderType shaderType) Q_DECL_NOTHROW +{ + m_shaderType = shaderType; +} + bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW { return lhs.api() == rhs.api() && lhs.version() == rhs.version() && lhs.extensions() == rhs.extensions() - && lhs.vendor() == rhs.vendor(); + && lhs.vendor() == rhs.vendor() + && lhs.shaderType() == rhs.shaderType(); } QT_END_NAMESPACE diff --git a/src/gui/util/qshaderformat_p.h b/src/gui/util/qshaderformat_p.h index 064c2364a79..8d5e83bd223 100644 --- a/src/gui/util/qshaderformat_p.h +++ b/src/gui/util/qshaderformat_p.h @@ -69,6 +69,15 @@ public: OpenGLES }; + enum ShaderType : int { + Vertex = 0, + TessellationControl, + TessellationEvaluation, + Geometry, + Fragment, + Compute + }; + Q_GUI_EXPORT QShaderFormat() Q_DECL_NOTHROW; Q_GUI_EXPORT Api api() const Q_DECL_NOTHROW; @@ -86,11 +95,15 @@ public: Q_GUI_EXPORT bool isValid() const Q_DECL_NOTHROW; Q_GUI_EXPORT bool supports(const QShaderFormat &other) const Q_DECL_NOTHROW; + Q_GUI_EXPORT ShaderType shaderType() const Q_DECL_NOTHROW; + Q_GUI_EXPORT void setShaderType(ShaderType shaderType) Q_DECL_NOTHROW; + private: Api m_api; QVersionNumber m_version; QStringList m_extensions; QString m_vendor; + ShaderType m_shaderType; }; Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW; diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 60cf5a2fc53..9d2cc387e0b 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -56,7 +56,10 @@ namespace case QShaderLanguage::Const: return "const"; case QShaderLanguage::Input: - return "varying"; + if (format.shaderType() == QShaderFormat::Vertex) + return "attribute"; + else + return "varying"; case QShaderLanguage::Output: return ""; // Although fragment shaders for <=2 only have fixed outputs case QShaderLanguage::Uniform: diff --git a/src/gui/util/qshadernodesloader.cpp b/src/gui/util/qshadernodesloader.cpp index 9badbb94df7..5369e8bd4c5 100644 --- a/src/gui/util/qshadernodesloader.cpp +++ b/src/gui/util/qshadernodesloader.cpp @@ -251,6 +251,17 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) break; } + // We default out to a Fragment ShaderType if nothing is specified + // as that was the initial behavior we introduced + const QString shaderType = formatObject.value(QStringLiteral("shaderType")).toString(); + format.setShaderType(shaderType == QStringLiteral("Fragment") ? QShaderFormat::Fragment + : shaderType == QStringLiteral("Vertex") ? QShaderFormat::Vertex + : shaderType == QStringLiteral("TessellationControl") ? QShaderFormat::TessellationControl + : shaderType == QStringLiteral("TessellationEvaluation") ? QShaderFormat::TessellationEvaluation + : shaderType == QStringLiteral("Geometry") ? QShaderFormat::Geometry + : shaderType == QStringLiteral("Compute") ? QShaderFormat::Compute + : QShaderFormat::Fragment); + const QByteArray substitution = substitutionValue.toString().toUtf8(); const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets")); diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 82197f815ef..c873aebef7c 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -35,11 +35,13 @@ namespace { - QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion) + QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion, + QShaderFormat::ShaderType shaderType= QShaderFormat::Fragment) { auto format = QShaderFormat(); format.setApi(api); format.setVersion(QVersionNumber(majorVersion, minorVersion)); + format.setShaderType(shaderType); return format; } @@ -74,7 +76,7 @@ namespace return edge; } - QShaderGraph createGraph() + QShaderGraph createFragmentShaderGraph() { const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0); const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); @@ -213,7 +215,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() QTest::addColumn("format"); QTest::addColumn("expectedCode"); - const auto graph = createGraph(); + const auto graph = createFragmentShaderGraph(); const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0); const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); @@ -580,120 +582,195 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() QTest::addColumn("format"); QTest::addColumn("expectedCode"); - const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0); - const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0); - const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0); - const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); - const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + { + const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0); + const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0); + const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0); + const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); - const auto qualifierEnum = QMetaEnum::fromType(); - const auto typeEnum = QMetaEnum::fromType(); + const auto qualifierEnum = QMetaEnum::fromType(); + const auto typeEnum = QMetaEnum::fromType(); - for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { - const auto qualifierName = qualifierEnum.key(qualifierIndex); - const auto qualifierValue = static_cast(qualifierEnum.value(qualifierIndex)); + for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { + const auto qualifierName = qualifierEnum.key(qualifierIndex); + const auto qualifierValue = static_cast(qualifierEnum.value(qualifierIndex)); - for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { - const auto typeName = typeEnum.key(typeIndex); - const auto typeValue = static_cast(typeEnum.value(typeIndex)); + for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { + const auto typeName = typeEnum.key(typeIndex); + const auto typeValue = static_cast(typeEnum.value(typeIndex)); + + auto graph = QShaderGraph(); + + auto worldPosition = createNode({ + createPort(QShaderNodePort::Output, "value") + }); + worldPosition.setParameter("name", "worldPosition"); + worldPosition.setParameter("qualifier", QVariant::fromValue(qualifierValue)); + worldPosition.setParameter("type", QVariant::fromValue(typeValue)); + worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;", + QByteArrayList() << "$qualifier highp $type $name;")); + worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", + QByteArrayList() << "$qualifier $type $name;")); + worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", + QByteArrayList() << "$qualifier $type $name;")); + + auto fragColor = createNode({ + createPort(QShaderNodePort::Input, "fragColor") + }); + fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;")); + fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;")); + fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;", + QByteArrayList() << "out vec4 fragColor;")); + + graph.addNode(worldPosition); + graph.addNode(fragColor); + + graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor")); + + const auto gl2Code = (QByteArrayList() << "#version 110" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " gl_fragColor = v0;" + << "}" + << "").join("\n"); + const auto gl3Code = (QByteArrayList() << "#version 130" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " fragColor = v0;" + << "}" + << "").join("\n"); + const auto gl4Code = (QByteArrayList() << "#version 400 core" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " fragColor = v0;" + << "}" + << "").join("\n"); + const auto es2Code = (QByteArrayList() << "#version 100" + << "" + << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " gl_fragColor = v0;" + << "}" + << "").join("\n"); + const auto es3Code = (QByteArrayList() << "#version 300 es" + << "" + << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " gl_fragColor = v0;" + << "}" + << "").join("\n"); + + QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; + QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; + QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; + QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; + QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; + } + } + } + + { + const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0, QShaderFormat::Vertex); + const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0, QShaderFormat::Vertex); + const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0, QShaderFormat::Vertex); + const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, QShaderFormat::Vertex); + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0, QShaderFormat::Vertex); auto graph = QShaderGraph(); - auto worldPosition = createNode({ + auto vertexPosition = createNode({ createPort(QShaderNodePort::Output, "value") }); - worldPosition.setParameter("name", "worldPosition"); - worldPosition.setParameter("qualifier", QVariant::fromValue(qualifierValue)); - worldPosition.setParameter("type", QVariant::fromValue(typeValue)); - worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;", + vertexPosition.setParameter("name", "vertexPosition"); + vertexPosition.setParameter("qualifier", QVariant::fromValue(QShaderLanguage::Input)); + vertexPosition.setParameter("type", QVariant::fromValue(QShaderLanguage::Vec4)); + + vertexPosition.addRule(es2, QShaderNode::Rule("", QByteArrayList() << "$qualifier highp $type $name;")); - worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", + vertexPosition.addRule(gl2, QShaderNode::Rule("", QByteArrayList() << "$qualifier $type $name;")); - worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", + vertexPosition.addRule(gl3, QShaderNode::Rule("", QByteArrayList() << "$qualifier $type $name;")); - auto fragColor = createNode({ - createPort(QShaderNodePort::Input, "fragColor") - }); - fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;")); - fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;")); - fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;", - QByteArrayList() << "out vec4 fragColor;")); - - graph.addNode(worldPosition); - graph.addNode(fragColor); - - graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor")); + graph.addNode(vertexPosition); const auto gl2Code = (QByteArrayList() << "#version 110" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "attribute vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); const auto gl3Code = (QByteArrayList() << "#version 130" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) - .arg(toGlsl(typeValue)) - .toUtf8() - << "out vec4 fragColor;" + << "in vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" << "}" << "").join("\n"); const auto gl4Code = (QByteArrayList() << "#version 400 core" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) - .arg(toGlsl(typeValue)) - .toUtf8() - << "out vec4 fragColor;" + << "in vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" << "}" << "").join("\n"); const auto es2Code = (QByteArrayList() << "#version 100" << "" - << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "attribute highp vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); const auto es3Code = (QByteArrayList() << "#version 300 es" << "" - << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "in highp vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); - QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; - QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; - QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; - QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; - QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; - } + QTest::addRow("Attribute header substitution ES2") << graph << es2 << es2Code; + QTest::addRow("Attribute header substitution ES3") << graph << es3 << es3Code; + QTest::addRow("Attribute header substitution GL2") << graph << gl2 << gl2Code; + QTest::addRow("Attribute header substitution GL3") << graph << gl3 << gl3Code; + QTest::addRow("Attribute header substitution GL4") << graph << gl4 << gl4Code; } } From a552864c3bd138ae6f09bf0d14d416a18498875c Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 1 Apr 2019 16:27:39 +0200 Subject: [PATCH 13/52] QShaderGenerator: don't generate temporary variables for global inputs Up until now, the QShaderGenerator would create temporary variables for uniform, attributes, const. This change makes it use the global inputs directly rather than relying on the intermediate properties. Change-Id: Ia9497367d61e536969fe87536606f309c286dbb2 Reviewed-by: Sean Harmer --- src/gui/util/qshadergenerator.cpp | 62 +++++- .../qshadergenerator/tst_qshadergenerator.cpp | 186 ++++++++++++++---- 2 files changed, 206 insertions(+), 42 deletions(-) diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 9d2cc387e0b..205118f41c3 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -40,6 +40,7 @@ #include "qshadergenerator_p.h" #include "qshaderlanguage_p.h" +#include QT_BEGIN_NAMESPACE @@ -317,12 +318,22 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) [enabledLayers] (const QString &s) { return enabledLayers.contains(s); }); }; + QVector globalInputVariables; + const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$")); + const QVector nodes = graph.nodes(); for (const QShaderNode &node : nodes) { if (intersectsEnabledLayers(node.layers())) { const QByteArrayList headerSnippets = node.rule(format).headerSnippets; for (const QByteArray &snippet : headerSnippets) { code << replaceParameters(snippet, node, format); + + // If node is an input, record the variable name into the globalInputVariables vector + if (node.type() == QShaderNode::Input) { + const QRegularExpressionMatch match = globalInputExtractRegExp.match(QString::fromUtf8(code.last())); + if (match.hasMatch()) + globalInputVariables.push_back(match.captured(1)); + } } } } @@ -331,6 +342,14 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); + // Table to store temporary variables that should be replaced by global + // variables. This avoids having vec3 v56 = vertexPosition; when we could + // just use vertexPosition directly. + // The added benefit is when having arrays, we don't try to create + // mat4 v38 = skinningPalelette[100] which would be invalid + QHash localReferencesToGlobalInputs; + const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*(\\w+).*;$")); + for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) { const QShaderNode node = statement.node; QByteArray line = node.rule(format).substitution; @@ -341,6 +360,9 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const bool isInput = port.direction == QShaderNodePort::Input; const int portIndex = statement.portIndex(portDirection, portName); + + Q_ASSERT(portIndex >= 0); + const int variableIndex = isInput ? statement.inputs.at(portIndex) : statement.outputs.at(portIndex); if (variableIndex < 0) @@ -348,15 +370,51 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8()); const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex)); + line.replace(placeholder, variable); } - code << QByteArrayLiteral(" ") + replaceParameters(line, node, format); + const QByteArray substitutionedLine = replaceParameters(line, node, format); + + // Record name of temporary variable that possibly references a global input + // We will replace the temporary variables by the matching global variables later + bool isAGlobalInputVariable = false; + if (node.type() == QShaderNode::Input) { + const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine)); + if (match.hasMatch()) { + const QString globalVariable = match.captured(2); + if (globalInputVariables.contains(globalVariable)) { + const QString localVariable = match.captured(1); + // TO DO: Clean globalVariable (remove brackets ...) + localReferencesToGlobalInputs.insert(localVariable, globalVariable); + isAGlobalInputVariable = true; + } + } + } + + // Only insert content for lines aren't inputs or have not matching + // globalVariables for now + if (!isAGlobalInputVariable) + code << QByteArrayLiteral(" ") + substitutionedLine; } code << QByteArrayLiteral("}"); code << QByteArray(); - return code.join('\n'); + + // Replace occurrences of local variables which reference a global variable + // by the global variables directly + auto it = localReferencesToGlobalInputs.cbegin(); + const auto end = localReferencesToGlobalInputs.cend(); + QString codeString = QString::fromUtf8(code.join('\n')); + + while (it != end) { + const QRegularExpression r(QStringLiteral("\\b(%1)([\\b|\\.|;|\\)|\\[|\\s|\\*|\\+|\\/|\\-|,])").arg(it.key()), + QRegularExpression::MultilineOption); + codeString.replace(r, QStringLiteral("%1\\2").arg(it.value())); + ++it; + } + + return codeString.toUtf8(); } QT_END_NAMESPACE diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index c873aebef7c..f8bb0c38515 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -196,6 +196,7 @@ private slots: void shouldProcessLanguageQualifierAndTypeEnums_data(); void shouldProcessLanguageQualifierAndTypeEnums(); void shouldGenerateDifferentCodeDependingOnActiveLayers(); + void shouldUseGlobalVariableRatherThanTemporaries(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -236,14 +237,9 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() << "" << "void main()" << "{" - << " highp vec2 v2 = texCoord;" - << " sampler2D v1 = texture;" - << " highp float v3 = lightIntensity;" - << " highp vec4 v5 = texture2D(v1, v2);" - << " highp vec3 v0 = worldPosition;" - << " highp float v4 = exposure;" - << " highp vec4 v6 = lightModel(v5, v0, v3);" - << " highp vec4 v7 = v6 * pow(2.0, v4);" + << " highp vec4 v5 = texture2D(texture, texCoord);" + << " highp vec4 v6 = lightModel(v5, worldPosition, lightIntensity);" + << " highp vec4 v7 = v6 * pow(2.0, exposure);" << " gl_fragColor = v7;" << "}" << ""; @@ -258,14 +254,9 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() << "" << "void main()" << "{" - << " vec2 v2 = texCoord;" - << " sampler2D v1 = texture;" - << " float v3 = lightIntensity;" - << " vec4 v5 = texture2D(v1, v2);" - << " vec3 v0 = worldPosition;" - << " float v4 = exposure;" - << " vec4 v6 = lightModel(v5, v0, v3);" - << " vec4 v7 = v6 * pow(2.0, v4);" + << " vec4 v5 = texture2D(texture, texCoord);" + << " vec4 v6 = lightModel(v5, worldPosition, lightIntensity);" + << " vec4 v7 = v6 * pow(2.0, exposure);" << " fragColor = v7;" << "}" << ""; @@ -636,8 +627,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" + << " gl_fragColor = worldPosition;" << "}" << "").join("\n"); const auto gl3Code = (QByteArrayList() << "#version 130" @@ -649,8 +639,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" + << " fragColor = worldPosition;" << "}" << "").join("\n"); const auto gl4Code = (QByteArrayList() << "#version 400 core" @@ -662,8 +651,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" + << " fragColor = worldPosition;" << "}" << "").join("\n"); const auto es2Code = (QByteArrayList() << "#version 100" @@ -674,8 +662,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" + << " gl_fragColor = worldPosition;" << "}" << "").join("\n"); const auto es3Code = (QByteArrayList() << "#version 300 es" @@ -686,8 +673,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" + << " gl_fragColor = worldPosition;" << "}" << "").join("\n"); @@ -883,9 +869,7 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec3 v1 = normalUniform;" - << " vec4 v0 = diffuseUniform;" - << " vec4 v2 = lightModel(v0, v1);" + << " vec4 v2 = lightModel(diffuseUniform, normalUniform);" << " fragColor = v2;" << "}" << ""; @@ -908,10 +892,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec2 v0 = texCoord;" - << " vec3 v2 = texture2D(normalTexture, v0).rgb;" - << " vec4 v1 = diffuseUniform;" - << " vec4 v3 = lightModel(v1, v2);" + << " vec3 v2 = texture2D(normalTexture, texCoord).rgb;" + << " vec4 v3 = lightModel(diffuseUniform, v2);" << " fragColor = v3;" << "}" << ""; @@ -934,10 +916,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec2 v0 = texCoord;" - << " vec3 v2 = normalUniform;" - << " vec4 v1 = texture2D(diffuseTexture, v0);" - << " vec4 v3 = lightModel(v1, v2);" + << " vec4 v1 = texture2D(diffuseTexture, texCoord);" + << " vec4 v3 = lightModel(v1, normalUniform);" << " fragColor = v3;" << "}" << ""; @@ -960,9 +940,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec2 v0 = texCoord;" - << " vec3 v2 = texture2D(normalTexture, v0).rgb;" - << " vec4 v1 = texture2D(diffuseTexture, v0);" + << " vec3 v2 = texture2D(normalTexture, texCoord).rgb;" + << " vec4 v1 = texture2D(diffuseTexture, texCoord);" << " vec4 v3 = lightModel(v1, v2);" << " fragColor = v3;" << "}" @@ -971,6 +950,133 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() } } +void tst_QShaderGenerator::shouldUseGlobalVariableRatherThanTemporaries() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + { + // WHEN + auto vertexPosition = createNode({ + createPort(QShaderNodePort::Output, "vertexPosition") + }); + vertexPosition.addRule(gl4, QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;", + QByteArrayList() << "in vec4 vertexPosition;")); + + auto fakeMultiPlyNoSpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeMultiPlyNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName*v11;")); + + auto fakeMultiPlySpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeMultiPlySpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName * v11;")); + + auto fakeJoinNoSpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeJoinNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz,$varName.w);")); + + auto fakeJoinSpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeJoinSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz, $varName.w);")); + + auto fakeAdd = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeAdd.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw + $varName;")); + + auto fakeSub = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeSub.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw - $varName;")); + + auto fakeDiv = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeDiv.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName / v0;")); + + auto fragColor = createNode({ + createPort(QShaderNodePort::Input, "input1"), + createPort(QShaderNodePort::Input, "input2"), + createPort(QShaderNodePort::Input, "input3"), + createPort(QShaderNodePort::Input, "input4"), + createPort(QShaderNodePort::Input, "input5"), + createPort(QShaderNodePort::Input, "input6"), + createPort(QShaderNodePort::Input, "input7") + }); + fragColor.addRule(gl4, QShaderNode::Rule("fragColor = $input1 + $input2 + $input3 + $input4 + $input5 + $input6 + $input7;", + QByteArrayList() << "out vec4 fragColor;")); + + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(vertexPosition); + res.addNode(fakeMultiPlyNoSpace); + res.addNode(fakeMultiPlySpace); + res.addNode(fakeJoinNoSpace); + res.addNode(fakeJoinSpace); + res.addNode(fakeAdd); + res.addNode(fakeSub); + res.addNode(fakeDiv); + res.addNode(fragColor); + + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlyNoSpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlySpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinNoSpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinSpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeAdd.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeSub.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeDiv.uuid(), "varName")); + res.addEdge(createEdge(fakeMultiPlyNoSpace.uuid(), "out", fragColor.uuid(), "input1")); + res.addEdge(createEdge(fakeMultiPlySpace.uuid(), "out", fragColor.uuid(), "input2")); + res.addEdge(createEdge(fakeJoinNoSpace.uuid(), "out", fragColor.uuid(), "input3")); + res.addEdge(createEdge(fakeJoinSpace.uuid(), "out", fragColor.uuid(), "input4")); + res.addEdge(createEdge(fakeAdd.uuid(), "out", fragColor.uuid(), "input5")); + res.addEdge(createEdge(fakeSub.uuid(), "out", fragColor.uuid(), "input6")); + res.addEdge(createEdge(fakeDiv.uuid(), "out", fragColor.uuid(), "input7")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode({"diffuseUniform", "normalUniform"}); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 vertexPosition;" + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << " vec4 v7 = vertexPosition / vertexPosition;" + << " vec4 v6 = vertexPosition.xyzw - vertexPosition;" + << " vec4 v5 = vertexPosition.xyzw + vertexPosition;" + << " vec4 v4 = vec4(vertexPosition.xyz, vertexPosition.w);" + << " vec4 v3 = vec4(vertexPosition.xyz,vertexPosition.w);" + << " vec4 v2 = vertexPosition * v11;" + << " vec4 v1 = vertexPosition*v11;" + << " fragColor = v1 + v2 + v3 + v4 + v5 + v6 + v7;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); + } +} + QTEST_MAIN(tst_QShaderGenerator) #include "tst_qshadergenerator.moc" From 73698cb3401b9445ba0ad6b0a6cc3e125e50a745 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 2 Apr 2019 19:36:29 +0300 Subject: [PATCH 14/52] Fix effects for highdpi graphical items Create a highdpi pixmap as a source for graphical effects. Fixes: QTBUG-74963 Change-Id: Ie144df3dbe61421fb28e639e640857aca6e6320f Reviewed-by: Friedemann Kleint --- src/widgets/graphicsview/qgraphicsitem.cpp | 11 +++++++---- src/widgets/graphicsview/qgraphicsitem_p.h | 2 +- src/widgets/graphicsview/qgraphicsscene.cpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 86f3d6a2f08..30b35ad92f7 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -11334,7 +11334,7 @@ void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter) } // sourceRect must be in the given coordinate system -QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const +QRectF QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const { QRectF effectRectF; @@ -11362,7 +11362,7 @@ QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem sy *unpadded = true; } - return effectRectF.toAlignedRect(); + return effectRectF; } QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset, @@ -11380,7 +11380,8 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP bool unpadded; const QRectF sourceRect = boundingRect(system); - QRect effectRect = paddedEffectRect(system, mode, sourceRect, &unpadded); + QRectF effectRectF = paddedEffectRect(system, mode, sourceRect, &unpadded); + QRect effectRect = effectRectF.toAlignedRect(); if (offset) *offset = effectRect.topLeft(); @@ -11396,7 +11397,9 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP if (effectRect.isEmpty()) return QPixmap(); - QPixmap pixmap(effectRect.size()); + const auto dpr = info ? info->painter->device()->devicePixelRatioF() : 1.0; + QPixmap pixmap(QRectF(effectRectF.topLeft(), effectRectF.size() * dpr).toAlignedRect().size()); + pixmap.setDevicePixelRatio(dpr); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing); diff --git a/src/widgets/graphicsview/qgraphicsitem_p.h b/src/widgets/graphicsview/qgraphicsitem_p.h index d586a225446..54c25bf6e16 100644 --- a/src/widgets/graphicsview/qgraphicsitem_p.h +++ b/src/widgets/graphicsview/qgraphicsitem_p.h @@ -644,7 +644,7 @@ public: QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const override; - QRect paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = 0) const; + QRectF paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = 0) const; QGraphicsItem *item; QGraphicsItemPaintInfo *info; diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index bba992144d0..3dce958b087 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -4847,7 +4847,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * && painter->worldTransform().type() <= QTransform::TxTranslate) { QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates); - QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect); + QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect).toAlignedRect(); sourced->setCachedOffset(effectRect.topLeft()); } else { From 064a731a110efc5ad7e314bc686f74c759f39437 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 10 Apr 2019 10:38:05 +0200 Subject: [PATCH 15/52] Correct the description of the "C" locale It is not identical to en_US, as we have long claimed. Fixes: QTBUG-75069 Change-Id: I236adcefdcb4120d2bf5adbcde727c5e3ca13986 Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/corelib/tools/qlocale.cpp | 11 +++++++++++ src/corelib/tools/qlocale.qdoc | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index df768fb8758..506b32a257d 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -2351,6 +2351,17 @@ QString QLocale::toString(double i, char f, int prec) const Returns a QLocale object initialized to the "C" locale. + This locale is based on en_US but with various quirks of its own, such as + simplified number formatting and its own date formatting. It implements the + POSIX standards that describe the behavior of standard library functions of + the "C" programming language. + + Among other things, this means its collation order is based on the ASCII + values of letters, so that (for case-sensitive sorting) all upper-case + letters sort before any lower-case one (rather than each letter's upper- and + lower-case forms sorting adjacent to one another, before the next letter's + two forms). + \sa system() */ diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc index 76ca909d835..4a4aa4ba2b5 100644 --- a/src/corelib/tools/qlocale.qdoc +++ b/src/corelib/tools/qlocale.qdoc @@ -104,7 +104,7 @@ This enumerated type is used to specify a language. \value AnyLanguage - \value C The "C" locale is identical in behavior to English/UnitedStates. + \value C A simplified English locale; see QLocale::c() \value Abkhazian \value Oromo \value Afan Obsolete, please use Oromo From e1167ed650afae90ab4b73036f58ae0f416ae500 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 25 Mar 2019 12:39:56 +0100 Subject: [PATCH 16/52] tslib: fix detection of missing release coordinates The release coordinates may be simply initialized to 0 in lower levels of the tslib. They are then passed through the calibration stage, which applies offset and multiplication to them, so they may end up even as positive numbers. Since we can't know if we can trust them or not simply ignore all release coordinates and just always use the ones from the previous event. Change-Id: Ib845b5ab1c5b81967cc089d601576893f433fa4a Reviewed-by: Martin Kepplinger Reviewed-by: Laszlo Agocs --- src/platformsupport/input/tslib/qtslib.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platformsupport/input/tslib/qtslib.cpp b/src/platformsupport/input/tslib/qtslib.cpp index 84a468f60cf..7609416fea6 100644 --- a/src/platformsupport/input/tslib/qtslib.cpp +++ b/src/platformsupport/input/tslib/qtslib.cpp @@ -114,8 +114,8 @@ void QTsLibMouseHandler::readMouseData() int x = sample.x; int y = sample.y; - // work around missing coordinates on mouse release - if (sample.pressure == 0 && sample.x == 0 && sample.y == 0) { + // coordinates on release events can contain arbitrary values, just ignore them + if (sample.pressure == 0) { x = m_x; y = m_y; } From 10327549cb91aa77e778c03c797a705241f1f06d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 22 Mar 2019 08:39:23 +0100 Subject: [PATCH 17/52] QOffscreenSurface: Suppress setting of a default geometry on the window When investigating the bug report, it was discovered that the offscreen window is assigned a default geometry by QPlatformWindow::initialGeometry(), causing subsequent resize events and flushing of event queues. Suppress that by making it a popup which is not subject to window title bar restrictions on Windows and setting the respective flags. Task-number: QTBUG-74176 Change-Id: I7f9c1a3bfd57072c8188a98124bde87491dd25eb Reviewed-by: Laszlo Agocs --- src/gui/kernel/qoffscreensurface.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp index ae027af627e..0cc11ca3bb7 100644 --- a/src/gui/kernel/qoffscreensurface.cpp +++ b/src/gui/kernel/qoffscreensurface.cpp @@ -46,6 +46,8 @@ #include "qwindow.h" #include "qplatformwindow.h" +#include + QT_BEGIN_NAMESPACE /*! @@ -199,12 +201,18 @@ void QOffscreenSurface::create() if (QThread::currentThread() != qGuiApp->thread()) qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."); d->offscreenWindow = new QWindow(d->screen); + // Make the window frameless to prevent Windows from enlarging it, should it + // violate the minimum title bar width on the platform. + d->offscreenWindow->setFlags(d->offscreenWindow->flags() + | Qt::CustomizeWindowHint | Qt::FramelessWindowHint); d->offscreenWindow->setObjectName(QLatin1String("QOffscreenSurface")); // Remove this window from the global list since we do not want it to be destroyed when closing the app. // The QOffscreenSurface has to be usable even after exiting the event loop. QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow); d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface); d->offscreenWindow->setFormat(d->requestedFormat); + // Prevent QPlatformWindow::initialGeometry() and platforms from setting a default geometry. + qt_window_private(d->offscreenWindow)->setAutomaticPositionAndResizeEnabled(false); d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height()); d->offscreenWindow->create(); } From 7b4f9dbf270b6e3369da5f5c0187876dfad69e70 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 11 Apr 2019 16:22:55 +0000 Subject: [PATCH 18/52] Revert "QMacStyle - workaround NSButtonCell (disclose button type)" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a868942b11a586861e167aaafaa9c65fde23e88d. We know how to fix it properly. Change-Id: I9180aeca82f884333d53bab9c6d588ee3a23d3cb Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 71 +------------------------ 1 file changed, 2 insertions(+), 69 deletions(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 0745e917a28..847b1a60341 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -1156,66 +1156,6 @@ static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(const QWidget *widg, QS } #endif -static NSColor *qt_convertColorForContext(CGContextRef context, NSColor *color) -{ - Q_ASSERT(color); - Q_ASSERT(context); - - CGColorSpaceRef targetCGColorSpace = CGBitmapContextGetColorSpace(context); - NSColorSpace *targetNSColorSpace = [[NSColorSpace alloc] initWithCGColorSpace:targetCGColorSpace]; - NSColor *adjusted = [color colorUsingColorSpace:targetNSColorSpace]; - [targetNSColorSpace release]; - - return adjusted; -} - -static NSColor *qt_colorForContext(CGContextRef context, const CGFloat (&rgba)[4]) -{ - Q_ASSERT(context); - - auto colorSpace = CGBitmapContextGetColorSpace(context); - if (!colorSpace) - return nil; - - return qt_convertColorForContext(context, [NSColor colorWithSRGBRed:rgba[0] green:rgba[1] blue:rgba[2] alpha:rgba[3]]); -} - -static void qt_drawDisclosureButton(CGContextRef context, NSInteger state, bool selected, CGRect rect) -{ - Q_ASSERT(context); - - static const CGFloat gray[] = {0.55, 0.55, 0.55, 0.97}; - static const CGFloat white[] = {1.0, 1.0, 1.0, 0.9}; - - NSColor *fillColor = qt_colorForContext(context, selected ? white : gray); - [fillColor setFill]; - - if (state == NSOffState) { - static NSBezierPath *triangle = [[NSBezierPath alloc] init]; - [triangle removeAllPoints]; - // In off state, a disclosure button is an equilateral triangle - // ('pointing' to the right) with a bound rect that can be described - // as NSMakeRect(0, 0, 8, 9). Inside the 'rect' it's translated by - // (2, 4). - [triangle moveToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4)]; - [triangle lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4 + 9)]; - [triangle lineToPoint:NSMakePoint(rect.origin.x + 2 + 8, rect.origin.y + 4 + 4.5)]; - [triangle closePath]; - [triangle fill]; - } else { - static NSBezierPath *openTriangle = [[NSBezierPath alloc] init]; - [openTriangle removeAllPoints]; - // In 'on' state, the button is an equilateral triangle (looking down) - // with the bounding rect NSMakeRect(0, 0, 9, 8). Inside the 'rect' - // it's translated by (1, 4). - [openTriangle moveToPoint:NSMakePoint(rect.origin.x + 1, rect.origin.y + 4 + 8)]; - [openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 9, rect.origin.y + 4 + 8)]; - [openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 4.5, rect.origin.y + 4)]; - [openTriangle closePath]; - [openTriangle fill]; - } -} - void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const { QPainterPath focusRingPath; @@ -3301,15 +3241,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai CGContextScaleCTM(cg, 1, -1); CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y); - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave && !qt_mac_applicationIsInDarkMode()) { - // When the real system theme is one of the 'Dark' themes, and an application forces the 'Aqua' theme, - // under some conditions (see QTBUG-74515 for more details) NSButtonCell seems to select the 'Dark' - // code path and is becoming transparent, thus 'invisible' on the white background. To workaround this, - // we draw the disclose triangle manually: - qt_drawDisclosureButton(cg, triangleCell.state, (opt->state & State_Selected) && viewHasFocus, rect); - } else { - [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]]; - } + [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]]; + d->restoreNSGraphicsContext(cg); break; } From bb8a3dfc9584f3178e615308a6ade583d3e1ba95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Thu, 7 Mar 2019 11:11:54 +0100 Subject: [PATCH 19/52] CMake: fix generation of config files for external Qt modules on macOS This is a follow-up to f5850cb0da5d9b610711d4fd3c1eaded9d6414e1, which did not take into account some special-casing for macOS framework build, thus causing CMake to look for QtFoo.framework instead of Foo.framework. Change-Id: I261b14e75fde66fb57486bde43fc936f796a6f96 Reviewed-by: Joerg Bornemann Reviewed-by: Kevin Funk --- mkspecs/features/create_cmake.prf | 25 +++++++++++-------- .../data/cmake/Qt5BasicConfig.cmake.in | 10 ++++---- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/mkspecs/features/create_cmake.prf b/mkspecs/features/create_cmake.prf index 6bf1380716d..2ab7775fea4 100644 --- a/mkspecs/features/create_cmake.prf +++ b/mkspecs/features/create_cmake.prf @@ -26,20 +26,29 @@ contains(CMAKE_INSTALL_LIBS_DIR, ^(/usr)?/lib(64)?.*): CMAKE_USR_MOVE_WORKAROUND CMAKE_OUT_DIR = $$MODULE_BASE_OUTDIR/lib/cmake +# Core, Network, an external module named Foo CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE}) +# QtCore, QtNetwork, still Foo +CMAKE_INCLUDE_NAME = $$eval(QT.$${MODULE}.name) + +# TARGET here is the one changed at the end of qt_module.prf, +# which already contains the Qt5 prefix and QT_LIBINFIX suffix : +# Qt5Core_suffix, Qt5Network_suffix, Foo_suffix +# (or QtCore_suffix, Foo_suffix on macos with -framework) +CMAKE_QT_STEM = $${TARGET} + !generated_privates { isEmpty(SYNCQT.INJECTED_PRIVATE_HEADER_FILES):isEmpty(SYNCQT.PRIVATE_HEADER_FILES): \ CMAKE_NO_PRIVATE_INCLUDES = true } - split_incpath { CMAKE_ADD_SOURCE_INCLUDE_DIRS = true CMAKE_SOURCE_INCLUDES = \ - $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}) + $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}) CMAKE_SOURCE_PRIVATE_INCLUDES = \ - $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION) \ - $$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION)/Qt$${CMAKE_MODULE_NAME}) + $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}/$$eval(QT.$${MODULE}.VERSION) \ + $$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}/$$eval(QT.$${MODULE}.VERSION)/$${CMAKE_INCLUDE_NAME}) cmake_extra_source_includes.input = $$PWD/data/cmake/ExtraSourceIncludes.cmake.in cmake_extra_source_includes.output = $$CMAKE_OUT_DIR/Qt5$${CMAKE_MODULE_NAME}/ExtraSourceIncludes.cmake @@ -200,10 +209,6 @@ CMAKE_QT5_MODULE_DEPS = $$join(lib_deps, ";") CMAKE_INTERFACE_MODULE_DEPS = $$join(aux_mod_deps, ";") CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";") -# TARGET here is the one changed at the end of qt_module.prf, -# which already contains the Qt5 prefix and QT_LIBINFIX suffix -CMAKE_QT_STEM = $${TARGET} - mac { !isEmpty(CMAKE_STATIC_TYPE) { CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.a @@ -213,8 +218,8 @@ mac { CMAKE_PRL_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.prl } else { qt_framework { - CMAKE_LIB_FILE_LOCATION_DEBUG = Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}.framework/Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX} - CMAKE_LIB_FILE_LOCATION_RELEASE = Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}.framework/Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX} + CMAKE_LIB_FILE_LOCATION_DEBUG = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM} + CMAKE_LIB_FILE_LOCATION_RELEASE = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM} CMAKE_BUILD_IS_FRAMEWORK = "true" } else { CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.$$eval(QT.$${MODULE}.VERSION).dylib diff --git a/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in b/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in index 3ed6dd58891..c7298928890 100644 --- a/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in +++ b/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in @@ -89,13 +89,13 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME}) !!IF !no_module_headers !!IF !isEmpty(CMAKE_BUILD_IS_FRAMEWORK) set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS - \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework\" - \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Headers\" + \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework\" + \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Headers\" ) !!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES) set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS - \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/\" - \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/$${MODULE_INCNAME}\" + \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/\" + \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/$${MODULE_INCNAME}\" ) !!ELSE set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\") @@ -112,7 +112,7 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME}) set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\") !!ENDIF !!ELSE - set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\" \"$${CMAKE_INCLUDE_DIR}Qt$${CMAKE_MODULE_NAME}\") + set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\" \"$${CMAKE_INCLUDE_DIR}$${CMAKE_INCLUDE_NAME}\") !!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES) set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"$${CMAKE_INCLUDE_DIR}$${MODULE_INCNAME}/$$VERSION\" From 09228604d8cd38c331bcb4f34d8d8aa3b34488e4 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 11 Apr 2019 13:22:18 +0200 Subject: [PATCH 20/52] Generic bearer engine - do not ignore WLAN interfaces (Windows) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous code and comments refer to the "separate engine" and skip such interfaces. Given we explicitly disabled this "separate engine", skipping the interfaces is a bit cruel. Task-number: QTBUG-65593 Change-Id: Ie9dce1661bd697f22044ca6fb4a5e2485ef74253 Reviewed-by: Mårten Nordheim --- src/plugins/bearer/generic/qgenericengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp index 7472758418d..b1f28849a7a 100644 --- a/src/plugins/bearer/generic/qgenericengine.cpp +++ b/src/plugins/bearer/generic/qgenericengine.cpp @@ -300,7 +300,7 @@ void QGenericEngine::doRequestUpdate() if (interface.flags() & QNetworkInterface::IsLoopBack) continue; -#ifndef Q_OS_WINRT +#ifndef Q_OS_WIN // ignore WLAN interface handled in separate engine if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN) continue; From 2593463eafcf8b3cb62dd4f8f9545359336bc005 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 12 Apr 2019 10:24:09 +0200 Subject: [PATCH 21/52] kms: Add support for "skip" key in the output config "off" is not quite suitable because that turns the output off, as the name suggests. Disconnected outputs are skipped automatically - it is natural to have a way to request the same for connected outputs as well. Task-number: QTBUG-74871 Change-Id: I8bea83428ae0424601b19482b6e6ef809491d0fb Reviewed-by: Johan Helsing --- src/platformsupport/kmsconvenience/qkmsdevice.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index ef81f6162d5..5f134f5867d 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -59,6 +59,7 @@ enum OutputConfiguration { OutputConfigOff, OutputConfigPreferred, OutputConfigCurrent, + OutputConfigSkip, OutputConfigMode, OutputConfigModeline }; @@ -191,6 +192,8 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, configuration = OutputConfigPreferred; } else if (mode == "current") { configuration = OutputConfigCurrent; + } else if (mode == "skip") { + configuration = OutputConfigSkip; } else if (sscanf(mode.constData(), "%dx%d@%d", &configurationSize.rwidth(), &configurationSize.rheight(), &configurationRefresh) == 3) { @@ -229,6 +232,11 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, return nullptr; } + if (configuration == OutputConfigSkip) { + qCDebug(qLcKmsDebug) << "Skipping output" << connectorName; + return nullptr; + } + // Get the current mode on the current crtc drmModeModeInfo crtc_mode; memset(&crtc_mode, 0, sizeof crtc_mode); From 21dcb96ddca357a6e8ace4b1c7252ec465e77727 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 15 Oct 2018 16:39:03 +0200 Subject: [PATCH 22/52] QStyleSheetStyle::repolish: only run on direct children When re-parenting, some widgets change their children. For example QLabel, when set to rich text, will not update, until receiving a polish call, at which time getting a list of all children recursively and then trying to call functions on them will crash, since the children change in the middle of this operation. Fixes: QTBUG-69204 Fixes: QTBUG-74667 Change-Id: I95dd83ebeed14c017e22552ddd47658ae8a09353 Reviewed-by: Shawn Rutledge --- src/widgets/styles/qstylesheetstyle.cpp | 5 ++++- .../qstylesheetstyle/tst_qstylesheetstyle.cpp | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 73b147e6227..4518d8c7365 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -2905,7 +2905,10 @@ void QStyleSheetStyle::polish(QPalette &pal) void QStyleSheetStyle::repolish(QWidget *w) { - QList children = w->findChildren(QString()); + QList children; + children.reserve(w->children().size() + 1); + for (auto child: qAsConst(w->children())) + children.append(child); children.append(w); styleSheetCaches->styleSheetCache.remove(w); updateObjects(children); diff --git a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp index 0e5c40f1b6a..8760ed03736 100644 --- a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -48,6 +48,7 @@ public: private slots: void init(); void repolish(); + void repolish_without_crashing(); void numinstances(); void widgetsBeforeAppStyleSheet(); void widgetsAfterAppStyleSheet(); @@ -367,6 +368,26 @@ void tst_QStyleSheetStyle::repolish() QCOMPARE(BACKGROUND(p1), APPBACKGROUND(p1)); } +void tst_QStyleSheetStyle::repolish_without_crashing() +{ + // This used to crash, QTBUG-69204 + QMainWindow w; + QScopedPointer splitter1(new QSplitter(w.centralWidget())); + QScopedPointer splitter2(new QSplitter); + QScopedPointer splitter3(new QSplitter); + splitter2->addWidget(splitter3.data()); + + splitter2->setStyleSheet("color: red"); + QScopedPointer label(new QLabel); + label->setTextFormat(Qt::RichText); + splitter3->addWidget(label.data()); + label->setText("hey"); + + splitter1->addWidget(splitter2.data()); + w.show(); + QCOMPARE(COLOR(*label), QColor(Qt::red)); +} + void tst_QStyleSheetStyle::widgetStyle() { qApp->setStyleSheet(""); From ab2c1e20fadc59a1a2365bda9e0e6b8eb295f5c9 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 9 Apr 2019 17:18:49 +0200 Subject: [PATCH 23/52] Windows QPA: Fix QComboBox accessibility with screen readers Screen readers like NVDA and Narrator were not reading the contents of a QComboBox when changing its value using the keyboard, without expanding it, due to missing UI Automation notifications in this case. This change should also help in other cases where updated string values were not notified to screen readers. Fixes: QTBUG-75066 Change-Id: Id7f488380aec5ad27fd11b3cf854d44ab1b28688 Reviewed-by: Friedemann Kleint --- .../uiautomation/qwindowsuiaaccessibility.cpp | 3 ++ .../uiautomation/qwindowsuiamainprovider.cpp | 37 ++++++++++++++++++- .../uiautomation/qwindowsuiamainprovider.h | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp index 85a931e0157..c7c0deab3f1 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp @@ -113,6 +113,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event case QAccessible::ValueChanged: QWindowsUiaMainProvider::notifyValueChange(static_cast(event)); break; + case QAccessible::SelectionAdd: + QWindowsUiaMainProvider::notifySelectionChange(event); + break; case QAccessible::TextAttributeChanged: case QAccessible::TextColumnChanged: case QAccessible::TextInserted: diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index fad83fb1651..44328492a66 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -146,9 +146,33 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event) { if (QAccessibleInterface *accessible = event->accessibleInterface()) { - if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { - // Notifies changes in values of controls supporting the value interface. + if (accessible->role() == QAccessible::ComboBox && accessible->childCount() > 0) { + QAccessibleInterface *listacc = accessible->child(0); + if (listacc && listacc->role() == QAccessible::List) { + int count = listacc->childCount(); + for (int i = 0; i < count; ++i) { + QAccessibleInterface *item = listacc->child(i); + if (item && item->text(QAccessible::Name) == event->value()) { + if (!item->state().selected) { + if (QAccessibleActionInterface *actionInterface = item->actionInterface()) + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + } + break; + } + } + } + } + if (event->value().type() == QVariant::String) { if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + // Notifies changes in string values. + VARIANT oldVal, newVal; + clearVariant(&oldVal); + setVariantString(event->value().toString(), &newVal); + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal); + } + } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + // Notifies changes in values of controls supporting the value interface. VARIANT oldVal, newVal; clearVariant(&oldVal); setVariantDouble(valueInterface->currentValue().toDouble(), &newVal); @@ -158,6 +182,15 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve } } +void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId); + } + } +} + // Notifies changes in text content and selection state of text controls. void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event) { diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h index 325d5b3de4b..df0d60f9c95 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h @@ -68,6 +68,7 @@ public: static void notifyFocusChange(QAccessibleEvent *event); static void notifyStateChange(QAccessibleStateChangeEvent *event); static void notifyValueChange(QAccessibleValueChangeEvent *event); + static void notifySelectionChange(QAccessibleEvent *event); static void notifyTextChange(QAccessibleEvent *event); // IUnknown From 2a815855a9b91a3537ab3d804ad1ee47d741b64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Beauz=C3=A9e-Luyssen?= Date: Wed, 3 Apr 2019 18:30:43 +0200 Subject: [PATCH 24/52] corelib: invokeMethod: Allow non copyable functors to be used [ChangeLog][QtCore][QMetaObject] Non-copyable lambdas can now be used with invokeMethod(). For consistency reasons, the functor object is now always moved. Fixes: QTBUG-69683 Change-Id: I66ff5e21d6d1926f0f7c5f8c304bed1a90b69917 Reviewed-by: Thiago Macieira Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qobjectdefs.h | 4 ++-- .../corelib/kernel/qmetaobject/qmetaobject.pro | 1 + .../kernel/qmetaobject/tst_qmetaobject.cpp | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index d7ed2b02820..059bb44e100 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -523,7 +523,7 @@ struct Q_CORE_EXPORT QMetaObject Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr) { return invokeMethodImpl(context, - new QtPrivate::QFunctorSlotObjectWithNoArgs(function), + new QtPrivate::QFunctorSlotObjectWithNoArgs(std::move(function)), type, ret); } @@ -535,7 +535,7 @@ struct Q_CORE_EXPORT QMetaObject invokeMethod(QObject *context, Func function, typename std::result_of::type *ret) { return invokeMethodImpl(context, - new QtPrivate::QFunctorSlotObjectWithNoArgs(function), + new QtPrivate::QFunctorSlotObjectWithNoArgs(std::move(function)), Qt::AutoConnection, ret); } diff --git a/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro b/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro index e7e5a03a861..980c247ab52 100644 --- a/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro +++ b/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro @@ -1,4 +1,5 @@ CONFIG += testcase +qtConfig(c++14): CONFIG += c++14 TARGET = tst_qmetaobject QT = core-private testlib SOURCES = tst_qmetaobject.cpp diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index cfe1443fd33..ac0731b8839 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -815,6 +815,15 @@ void tst_QMetaObject::invokePointer() QCOMPARE(obj.slotResult, QString("sl1:bubu")); } QCOMPARE(countedStructObjectsCount, 0); +#ifdef __cpp_init_captures + { + CountedStruct str; + std::unique_ptr ptr( new int ); + QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj, p = std::move(ptr)]() { obj.sl1(t1); })); + QCOMPARE(obj.slotResult, QString("sl1:1")); + } + QCOMPARE(countedStructObjectsCount, 0); +#endif } void tst_QMetaObject::invokeQueuedMetaMember() @@ -1120,6 +1129,15 @@ void tst_QMetaObject::invokeBlockingQueuedPointer() QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } +#ifdef __cpp_init_captures + { + std::unique_ptr ptr(new int); + QVERIFY(QMetaObject::invokeMethod(&obj, + [&obj, p = std::move(ptr)]() { return obj.sl1("hehe"); }, + Qt::BlockingQueuedConnection)); + QCOMPARE(obj.slotResult, QString("sl1:hehe")); + } +#endif QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection)); t.quit(); QVERIFY(t.wait()); From 5b3dfa470ed7ea40103daa785286ab71fb7aa230 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 19 Dec 2018 12:46:52 +0100 Subject: [PATCH 25/52] qmake: link qt libraries by full path this avoids the scenario where the linker would pick up the wrong qt libraries for LIBS_PRIVATE because LIBS added the "wrong" path first. this is also consistent with configure-supplied dependencies as of recently. as a side effect, this also removes pretenses of lsb linker handling, as it makes no sense after the change and is certainly obsolete anyway. Fixes: QTBUG-50921 Change-Id: I84398c9143f393c2eefb3c69a31bd9f633669924 Reviewed-by: Oswald Buddenhagen Reviewed-by: Joerg Bornemann --- mkspecs/features/qt.prf | 31 +++++++++++++----------------- mkspecs/features/win32/opengl.prf | 16 +++++++++++---- mkspecs/features/win32/windows.prf | 7 +++---- mkspecs/linux-lsb-g++/qmake.conf | 1 - 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index d8d5acaafd1..89f4946c507 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -145,12 +145,14 @@ import_plugins:qtConfig(static) { # the plugin path. Unknown plugins must rely on the default link path. plug_type = $$eval(QT_PLUGIN.$${plug}.TYPE) !isEmpty(plug_type) { + plug_name = $$QMAKE_PREFIX_STATICLIB$${plug}$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB plug_path = $$eval(QT_PLUGIN.$${plug}.PATH) isEmpty(plug_path): \ plug_path = $$[QT_INSTALL_PLUGINS/get] - LIBS += -L$$plug_path/$$plug_type + LIBS += $$plug_path/$$plug_type/$$plug_name + } else { + LIBS += -l$${plug}$$qtPlatformTargetSuffix() } - LIBS += -l$${plug}$$qtPlatformTargetSuffix() } } @@ -195,8 +197,6 @@ for(ever) { qtProcessModuleFlags(DEFINES, QT.$${QTLIB}.DEFINES) MODULE_INCLUDES -= $$QMAKE_DEFAULT_INCDIRS - MODULE_LIBS_ADD = $$MODULE_LIBS - MODULE_LIBS_ADD -= $$QMAKE_DEFAULT_LIBDIRS # Frameworks shouldn't need include paths, but much code does not use # module-qualified #includes, so by default we add paths which point @@ -209,23 +209,17 @@ for(ever) { !isEmpty(MODULE_MODULE) { contains(MODULE_CONFIG, lib_bundle) { framework = $$MODULE_MODULE + # Linking frameworks by absolute path does not work. LIBS$$var_sfx += -framework $$framework } else { - !isEmpty(MODULE_LIBS_ADD): \ - LIBS$$var_sfx += -L$$MODULE_LIBS_ADD - lib = $$MODULE_MODULE$$qtPlatformTargetSuffix() - LIBS$$var_sfx += -l$$lib - - contains(MODULE_CONFIG, staticlib): \ - PRE_TARGETDEPS *= $$MODULE_LIBS/$${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB} - - !isEmpty(QMAKE_LSB) { - !isEmpty(MODULE_LIBS_ADD): \ - QMAKE_LFLAGS *= --lsb-libpath=$$MODULE_LIBS_ADD - QMAKE_LFLAGS *= --lsb-shared-libs=$$lib - QMAKE_LIBDIR *= /opt/lsb/lib + win32|contains(MODULE_CONFIG, staticlib) { + lib = $$MODULE_LIBS/$$QMAKE_PREFIX_STATICLIB$${lib}.$$QMAKE_EXTENSION_STATICLIB + PRE_TARGETDEPS += $$lib + } else { + lib = $$MODULE_LIBS/$$QMAKE_PREFIX_SHLIB$${lib}.$$QMAKE_EXTENSION_SHLIB } + LIBS$$var_sfx += $$lib } } QMAKE_USE$$var_sfx += $$MODULE_USES @@ -295,7 +289,8 @@ contains(all_qt_module_deps, qml): \ for (key, IMPORTS._KEYS_) { PATH = $$eval(IMPORTS.$${key}.path) PLUGIN = $$eval(IMPORTS.$${key}.plugin) - !isEmpty(PATH):!isEmpty(PLUGIN): LIBS *= -L$$PATH -l$${PLUGIN}$$qtPlatformTargetSuffix() + !isEmpty(PATH):!isEmpty(PLUGIN): \ + LIBS += $$PATH/$$QMAKE_PREFIX_STATICLIB$${PLUGIN}$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB } # create qml_plugin_import.cpp diff --git a/mkspecs/features/win32/opengl.prf b/mkspecs/features/win32/opengl.prf index c6fba7770fd..f21848f9419 100644 --- a/mkspecs/features/win32/opengl.prf +++ b/mkspecs/features/win32/opengl.prf @@ -1,13 +1,21 @@ QT_FOR_CONFIG += gui +defineTest(prependOpenGlLib) { + path = $$QT.core.libs/$$QMAKE_PREFIX_STATICLIB$$1 + ext = .$$QMAKE_EXTENSION_STATICLIB + QMAKE_LIBS_OPENGL_ES2 = $${path}$${ext} $$QMAKE_LIBS_OPENGL_ES2 + QMAKE_LIBS_OPENGL_ES2_DEBUG = $${path}d$${ext} $$QMAKE_LIBS_OPENGL_ES2_DEBUG + export(QMAKE_LIBS_OPENGL_ES2) + export(QMAKE_LIBS_OPENGL_ES2_DEBUG) +} + qtConfig(opengles2) { # Depending on the configuration we use libQtANGLE or libEGL and libGLESv2 qtConfig(combined-angle-lib) { - QMAKE_LIBS_OPENGL_ES2 = -l$${LIBQTANGLE_NAME} $$QMAKE_LIBS_OPENGL_ES2 - QMAKE_LIBS_OPENGL_ES2_DEBUG = -l$${LIBQTANGLE_NAME}d $$QMAKE_LIBS_OPENGL_ES2_DEBUG + prependOpenGlLib($$LIBQTANGLE_NAME) } else { - QMAKE_LIBS_OPENGL_ES2 = -l$${LIBEGL_NAME} -l$${LIBGLESV2_NAME} $$QMAKE_LIBS_OPENGL_ES2 - QMAKE_LIBS_OPENGL_ES2_DEBUG = -l$${LIBEGL_NAME}d -l$${LIBGLESV2_NAME}d $$QMAKE_LIBS_OPENGL_ES2_DEBUG + prependOpenGlLib($$LIBGLESV2_NAME) + prependOpenGlLib($$LIBEGL_NAME) } # For Desktop, use the ANGLE library location passed on from configure. INCLUDEPATH += $$QMAKE_INCDIR_OPENGL_ES2 diff --git a/mkspecs/features/win32/windows.prf b/mkspecs/features/win32/windows.prf index ecb167bf18e..272170d4280 100644 --- a/mkspecs/features/win32/windows.prf +++ b/mkspecs/features/win32/windows.prf @@ -6,10 +6,9 @@ contains(TEMPLATE, ".*app") { qt:for(entryLib, $$list($$unique(QMAKE_LIBS_QT_ENTRY))) { isEqual(entryLib, -lqtmain) { - !contains(QMAKE_DEFAULT_LIBDIRS, $$QT.core.libs): \ - QMAKE_LIBS += -L$$QT.core.libs - CONFIG(debug, debug|release): QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX}d - else: QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX} + lib = $$QT.core.libs/$${QMAKE_PREFIX_STATICLIB}qtmain$$QT_LIBINFIX$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB + PRE_TARGETDEPS += $$lib + QMAKE_LIBS += $$lib } else { QMAKE_LIBS += $${entryLib} } diff --git a/mkspecs/linux-lsb-g++/qmake.conf b/mkspecs/linux-lsb-g++/qmake.conf index 80353cd5f66..eb7b87b57b6 100644 --- a/mkspecs/linux-lsb-g++/qmake.conf +++ b/mkspecs/linux-lsb-g++/qmake.conf @@ -13,7 +13,6 @@ load(qt_config) QMAKE_LIBS_THREAD += -lrt -QMAKE_LSB = 1 QMAKE_CC = lsbcc QMAKE_CXX = lsbc++ From 12b96dbb81a1a7bc5ffc08c24942038b007985e9 Mon Sep 17 00:00:00 2001 From: Kavindra Palaraja Date: Fri, 12 Apr 2019 14:55:01 +0200 Subject: [PATCH 26/52] doc: Add clang to the Unix list for Precompiled Headers documentation Task-number: QTBUG-50011 Change-Id: I18261e62e387eeb74fc7584bf034a11ac75db1be Reviewed-by: Joerg Bornemann --- qmake/doc/src/qmake-manual.qdoc | 1 + 1 file changed, 1 insertion(+) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index aba5be61ddd..d91d056d100 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -4813,6 +4813,7 @@ \li Unix \list \li GCC 3.4 and above + \li clang \endlist \endlist From 7c6b969383a403474a63715fd7a12caddd826611 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 15 Apr 2019 15:50:15 +0200 Subject: [PATCH 27/52] eglfs: Call destroy() from dtors of concrete windows Calling destroy from the QEglFSWindow dtor() triggers the virtual invalidateSurface() to be called on a partly destroyed object. As the child windows deregister themselves from their screens on invalidateSurface() this is dangerous: It leaves a dangling pointer in the screen. Fixes: QTBUG-75075 Change-Id: Idd3fea18562d41973f364340df875a50dbd5691e Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/api/qeglfswindow.cpp | 3 +++ .../eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h | 3 +++ .../eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp | 2 ++ .../eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp index 98e9ee47285..c1d5af47aa8 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp @@ -167,6 +167,9 @@ void QEglFSWindow::create() void QEglFSWindow::destroy() { + if (!m_flags.testFlag(Created)) + return; // already destroyed + #ifndef QT_NO_OPENGL QOpenGLCompositor::instance()->removeWindow(this); #endif diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h index a19cf7e8bc2..ee4b7978f17 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h @@ -55,6 +55,9 @@ public: : QEglFSWindow(w), m_integration(integration) { } + + ~QEglFSKmsGbmWindow() { destroy(); } + void resetSurface() override; void invalidateSurface() override; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index ecdfb352ab2..3e78196227c 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -116,6 +116,8 @@ public: , m_egl_stream(EGL_NO_STREAM_KHR) { } + ~QEglFSKmsEglDeviceWindow() { destroy(); } + void invalidateSurface() override; void resetSurface() override; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp index 0d9b6b62904..d1250ec9bff 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp @@ -205,6 +205,9 @@ public: : QEglFSWindow(w) , m_integration(integration) {} + + ~QEglFSKmsVsp2Window() { destroy(); } + void resetSurface() override; void invalidateSurface() override; const QEglFSKmsVsp2Integration *m_integration; From 0bd27f80e0fff56e5450bb10aa7da8ba1ac00406 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Tue, 16 Apr 2019 10:19:27 +0200 Subject: [PATCH 28/52] ANGLE: clean up displays on dll unload If the displays are not cleaned up on dll unloading, profilers might report memory leaks. Change-Id: I04cbc3c2448bfb450f7d840e216827f86856e963 Reviewed-by: Friedemann Kleint Reviewed-by: Andre de la Rocha Reviewed-by: Andy Shaw --- src/3rdparty/angle/src/libANGLE/Display.cpp | 17 ++++ src/3rdparty/angle/src/libANGLE/Display.h | 1 + .../angle/src/libGLESv2/global_state.cpp | 2 + ...NGLE-clean-up-displays-on-dll-unload.patch | 78 +++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp index 735b4727877..0bb0bb05b1a 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.cpp +++ b/src/3rdparty/angle/src/libANGLE/Display.cpp @@ -364,6 +364,23 @@ Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attri return display; } +//static +void Display::CleanupDisplays() +{ + // ~Display takes care of removing the entry from the according map + { + ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); + while (!displays->empty()) + delete displays->begin()->second; + } + + { + DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap(); + while (!displays->empty()) + delete displays->begin()->second; + } +} + Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice) : mImplementation(nullptr), mDisplayId(displayId), diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h index aa1d1c3b372..2a1c386d750 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.h +++ b/src/3rdparty/angle/src/libANGLE/Display.h @@ -65,6 +65,7 @@ class Display final : angle::NonCopyable static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, const AttributeMap &attribMap); + static void CleanupDisplays(); static const ClientExtensions &GetClientExtensions(); static const std::string &GetClientExtensionString(); diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp index c5f3dfe4e12..26045bf5b26 100644 --- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp +++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp @@ -13,6 +13,7 @@ #include "common/tls.h" #include "libANGLE/Thread.h" +#include "libANGLE/Display.h" namespace gl { @@ -140,6 +141,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) return static_cast(egl::DeallocateCurrentThread()); case DLL_PROCESS_DETACH: + egl::Display::CleanupDisplays(); return static_cast(egl::TerminateProcess()); } diff --git a/src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch b/src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch new file mode 100644 index 00000000000..fce3fd76b22 --- /dev/null +++ b/src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch @@ -0,0 +1,78 @@ +From d8ca4f6d0d8fffd8319f340685e03751049678ae Mon Sep 17 00:00:00 2001 +From: Oliver Wolff +Date: Tue, 16 Apr 2019 10:19:27 +0200 +Subject: [PATCH] ANGLE: clean up displays on dll unload + +If the displays are not cleaned up on dll unloading, profilers might +report memory leaks. + +Change-Id: I04cbc3c2448bfb450f7d840e216827f86856e963 +--- + src/3rdparty/angle/src/libANGLE/Display.cpp | 17 +++++++++++++++++ + src/3rdparty/angle/src/libANGLE/Display.h | 1 + + .../angle/src/libGLESv2/global_state.cpp | 2 ++ + 3 files changed, 20 insertions(+) + +diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp +index 735b472787..0bb0bb05b1 100644 +--- a/src/3rdparty/angle/src/libANGLE/Display.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Display.cpp +@@ -364,6 +364,23 @@ Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attri + return display; + } + ++//static ++void Display::CleanupDisplays() ++{ ++ // ~Display takes care of removing the entry from the according map ++ { ++ ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); ++ while (!displays->empty()) ++ delete displays->begin()->second; ++ } ++ ++ { ++ DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap(); ++ while (!displays->empty()) ++ delete displays->begin()->second; ++ } ++} ++ + Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice) + : mImplementation(nullptr), + mDisplayId(displayId), +diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h +index aa1d1c3b37..2a1c386d75 100644 +--- a/src/3rdparty/angle/src/libANGLE/Display.h ++++ b/src/3rdparty/angle/src/libANGLE/Display.h +@@ -65,6 +65,7 @@ class Display final : angle::NonCopyable + static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); + static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, + const AttributeMap &attribMap); ++ static void CleanupDisplays(); + + static const ClientExtensions &GetClientExtensions(); + static const std::string &GetClientExtensionString(); +diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp +index c5f3dfe4e1..26045bf5b2 100644 +--- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp +@@ -13,6 +13,7 @@ + #include "common/tls.h" + + #include "libANGLE/Thread.h" ++#include "libANGLE/Display.h" + + namespace gl + { +@@ -140,6 +141,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) + return static_cast(egl::DeallocateCurrentThread()); + + case DLL_PROCESS_DETACH: ++ egl::Display::CleanupDisplays(); + return static_cast(egl::TerminateProcess()); + } + +-- +2.20.1.windows.1 + From 7ee449a18695f7ec17bed18b59956003fabfe53e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 16 Apr 2019 12:23:26 +0200 Subject: [PATCH 29/52] Fix threaded QOpenGL when robustness is requested If the shared context had robustness set then all child contexts must as well, otherwise we will fallback to a non-shared context breaking threaded rendering. Change-Id: Ie5526e632ad21289b6164c1ca06e54ec714187c7 Reviewed-by: Laszlo Agocs --- .../platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 476de6d1e5d..4adf6621523 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -270,7 +270,9 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) // ES does not support any format option m_format.setOptions(QSurfaceFormat::FormatOptions()); } - + // Robustness must match that of the shared context. + if (share && share->format().testOption(QSurfaceFormat::ResetNotification)) + m_format.setOption(QSurfaceFormat::ResetNotification); Q_ASSERT(glVersions.count() > 0); for (int i = 0; !m_context && i < glVersions.count(); i++) { From e4d2c74aad2a04208981355ee1698dcf08b8cd95 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Fri, 12 Apr 2019 17:06:25 +0200 Subject: [PATCH 30/52] Fix setting Qt::WA_ShowWithoutActivating on eglfs window WebEngine HTML based popups depends on setting Qt::WA_ShowWithoutActivating, to keep forwarding events to chromium event handling. This works well with xcb, windows or coca windows backends, however was not respected on eglfs. Add check before activating the window. Task-number: QTBUG-69533 Change-Id: I66b249ec497af890c8a2228eee3bac3c806e77ed Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/api/qeglfsintegration.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 48469b0f8c8..c8a1ddf9b9b 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -199,6 +199,10 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const QEglFSWindow *w = qt_egl_device_integration()->createWindow(window); w->create(); + const auto showWithoutActivating = window->property("_q_showWithoutActivating"); + if (showWithoutActivating.isValid() && showWithoutActivating.toBool()) + return w; + // Activate only the window for the primary screen to make input work if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen()) w->requestActivateWindow(); From 4298658bef89fb79974530bfa3723a48a6bf7efc Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Thu, 11 Apr 2019 14:37:44 +0200 Subject: [PATCH 31/52] Fix corner case in openglcompositor for eglfs Add 'source' window offset. This covers the cases where platform window is created besides one full screen window (like for popups), where content has qquickwidget / qopenglwidgtet. In that case fbos/textures from those widgets have offset according to 'source' window. Note backingstore texture has geometry of 'source' window. Task-number: QTBUG-69533 Change-Id: I2514b36fd3a6b9b86f51999df1c2b3e9565aafde Reviewed-by: Laszlo Agocs --- .../platformcompositor/qopenglcompositor.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/platformsupport/platformcompositor/qopenglcompositor.cpp b/src/platformsupport/platformcompositor/qopenglcompositor.cpp index 0f4946f81af..635bf0107f2 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositor.cpp @@ -188,14 +188,15 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) topLeftRect.width(), topLeftRect.height()); } -static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &targetWindowRect, +static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &sourceWindowRect, + const QRect &targetWindowRect, QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix) { const QRect clipRect = textures->clipRect(idx); if (clipRect.isEmpty()) return; - const QRect rectInWindow = textures->geometry(idx); + const QRect rectInWindow = textures->geometry(idx).translated(sourceWindowRect.topLeft()); const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); @@ -218,7 +219,7 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size()); float currentOpacity = 1.0f; BlendStateBinder blend; - + const QRect sourceWindowRect = window->sourceWindow()->geometry(); for (int i = 0; i < textures->count(); ++i) { uint textureId = textures->textureId(i); const float opacity = window->sourceWindow()->opacity(); @@ -243,16 +244,16 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) target = m_rotationMatrix * target; m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - // Texture from an FBO belonging to a QOpenGLWidget + // Texture from an FBO belonging to a QOpenGLWidget or QQuickWidget blend.set(false); - clippedBlit(textures, i, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); + clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); } } for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { blend.set(true); - clippedBlit(textures, i, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); + clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); } } From c096d97097e37b36281f8ad25852a2397f20a32f Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 15 Apr 2019 16:37:11 +0200 Subject: [PATCH 32/52] Windows QPA: Fix custom drop formats being ignored Changes QWindowsDropDataObject to only ignore non-CF_HDROP formats when the drop contains only "text/uri-list" mime data, and the URIs are for local files, to avoid messing with custom formats set by the developer, while still fixing the case reported in QTBUG-62662. Fixes: QTBUG-74232 Change-Id: I946ced222377716876d0aea54b3eb05d40e7fa44 Reviewed-by: Friedemann Kleint --- .../windows/qwindowsdropdataobject.cpp | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp index 229ff928944..e1a41c0ede9 100644 --- a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp +++ b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp @@ -41,6 +41,7 @@ #include #include +#include "qwindowsmime.h" QT_BEGIN_NAMESPACE @@ -48,8 +49,9 @@ QT_BEGIN_NAMESPACE \class QWindowsDropDataObject \brief QWindowsOleDataObject subclass specialized for handling Drag&Drop. - Only allows "text/uri-list" data to be exported as CF_HDROP, to allow dropped - files to be attached to Office applications (instead of adding an URL link). + Prevents "text/uri-list" data for local files from being exported as text + or URLs, to allow dropped files to be attached to Office applications + (instead of creating local hyperlinks). \internal \ingroup qt-lighthouse-win @@ -80,14 +82,22 @@ QWindowsDropDataObject::QueryGetData(LPFORMATETC pformatetc) return QWindowsOleDataObject::QueryGetData(pformatetc); } -// If the data is text/uri-list for local files, tell we can only export it as CF_HDROP. +// If the data is "text/uri-list" only, and all URIs are for local files, +// we prevent it from being exported as text or URLs, to make target applications +// like MS Office attach or open the files instead of creating local hyperlinks. bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const { QMimeData *dropData = mimeData(); - if (dropData && dropData->hasFormat(QStringLiteral("text/uri-list")) && (pformatetc->cfFormat != CF_HDROP)) { - QList urls = dropData->urls(); - return std::any_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); }); + if (dropData && dropData->formats().size() == 1 && dropData->hasUrls()) { + QString formatName = QWindowsMimeConverter::clipboardFormatName(pformatetc->cfFormat); + if (pformatetc->cfFormat == CF_UNICODETEXT + || pformatetc->cfFormat == CF_TEXT + || formatName == QStringLiteral("UniformResourceLocator") + || formatName == QStringLiteral("UniformResourceLocatorW")) { + QList urls = dropData->urls(); + return std::all_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); }); + } } return false; From c381df060f16a522e6edd3541b09af06c0aa3024 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 17 Apr 2019 15:03:58 +0200 Subject: [PATCH 33/52] Doc: Document QMAKE_[L|C[XX]]FLAGS_RELEASE_WITH_DEBUGINFO Fixes: QTBUG-17463 Change-Id: Ic2f0870da14db21b1da053716b6d63ba0ed679c9 Reviewed-by: Leena Miettinen --- qmake/doc/src/qmake-manual.qdoc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 1e1b365141e..a4c314b709f 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -1580,6 +1580,14 @@ The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + \section1 QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + + Specifies the C compiler flags for release builds where + \c{force_debug_info} is set in \c{CONFIG}. + The value of this variable is typically handled by + qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CFLAGS_SHLIB \section1 QMAKE_CFLAGS_SHLIB @@ -1648,6 +1656,14 @@ The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO + \section1 QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO + + Specifies the C++ compiler flags for release builds where + \c{force_debug_info} is set in \c{CONFIG}. + The value of this variable is typically handled by + qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CXXFLAGS_SHLIB \section1 QMAKE_CXXFLAGS_SHLIB @@ -2028,6 +2044,12 @@ The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \section1 QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO + + Specifies the linker flags for release builds where \c{force_debug_info} is + set in \c{CONFIG}. The value of this variable is typically handled by + qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \section1 QMAKE_LFLAGS_APP Specifies the linker flags for building applications. From b556890a9f7dd45550f0d4e9da981e2f779a943b Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 17 Apr 2019 17:19:03 +0200 Subject: [PATCH 34/52] Windows QPA: fix media keys losing autorepeat/keycode information For WM_APPCOMMAND messages that also trigger WM_KEYDOWN/WM_KEYUP, let the latter messages be handled, instead of stripping them and synthesizing a press/release from the command code, in order to get the correct scan codes and autorepeat info. Fixes: QTBUG-73879 Change-Id: I936cd76be87a76dc6b6223eeb246e4e7aee3a4ac Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowskeymapper.cpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index c0503698018..c5af4d80426 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -879,21 +879,16 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con #if defined(WM_APPCOMMAND) const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam); // QTBUG-57198, do not send mouse-synthesized commands as key events in addition + bool skipPressRelease = false; switch (GET_DEVICE_LPARAM(msg.lParam)) { case FAPPCOMMAND_MOUSE: return false; case FAPPCOMMAND_KEY: - // QTBUG-62838, swallow WM_KEYDOWN, WM_KEYUP for commands that are - // reflected in VK(s) like VK_MEDIA_NEXT_TRACK. Don't do that for - // APPCOMMAND_BROWSER_HOME as that one does not trigger two events - if (cmd != APPCOMMAND_BROWSER_HOME) { - MSG peekedMsg; - if (PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_NOREMOVE) - && peekedMsg.message == WM_KEYDOWN) { - PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE); - PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE); - } - } + // QTBUG-62838, use WM_KEYDOWN/WM_KEYUP for commands that are reflected + // in VK(s) like VK_MEDIA_NEXT_TRACK, to get correct codes and autorepeat. + // Don't do that for APPCOMMAND_BROWSER_HOME as that one does not trigger two events. + if (cmd != APPCOMMAND_BROWSER_HOME) + skipPressRelease = true; break; } @@ -908,7 +903,8 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con return false; const int qtKey = int(CmdTbl[cmd]); - sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0); + if (!skipPressRelease) + sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0); // QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise, // the keys are not passed to the active media player. # if QT_CONFIG(shortcut) From 8ae8c6690b41f6cd40dae14d471ce29b500c66c9 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 17 Apr 2019 15:03:23 +0200 Subject: [PATCH 35/52] MinGW: Fix developer build In some build configurations, the build with MinGW would fail due to missing declaration of localtime_r(). This is only visible when _POSIX_THREAD_SAFE_FUNCTIONS is defined, which is achieved by including . Amends 6c543879a31d7d13a6b87e6332f6913f2f89f5e6. Task-number: QTBUG-71030 Change-Id: I71296f24a450159d1c548e1ad836a2b42e42009f Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal_p.h | 3 +++ src/corelib/tools/qdatetime.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h index d52f6268e4b..58bc8b7bf3d 100644 --- a/src/corelib/global/qglobal_p.h +++ b/src/corelib/global/qglobal_p.h @@ -61,6 +61,9 @@ #endif #if defined(__cplusplus) +#ifdef Q_CC_MINGW +# include // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r() +#endif #include QT_BEGIN_NAMESPACE diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 80d6dada60b..511dbf0db8f 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -58,6 +58,9 @@ #endif #include +#ifdef Q_CC_MINGW +# include // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r() +#endif #include #ifdef Q_OS_WIN # include From 38deb05109bcee9ad25a10eff024eaf8ce7a57f1 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 17 Apr 2019 15:45:58 +0200 Subject: [PATCH 36/52] Rename c++1z to c++17 in the configure api It is 2019, so the name c++17 is more than fixed by now. At the same time remove an old restriction on using -c++std= with MSVC, since VS2017 (15.7), we have been able to request c++14 and c++17. Change-Id: I7129799a2e46301b7ec1322251a3805f4d6b20a8 Reviewed-by: Thiago Macieira --- config_help.txt | 4 ++-- configure.json | 4 ++-- configure.pri | 5 +---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/config_help.txt b/config_help.txt index 8eea64e03ae..d63f9be5f88 100644 --- a/config_help.txt +++ b/config_help.txt @@ -139,8 +139,8 @@ Build options: -coverage {trace-pc-guard} Add code coverage instrumentation (Clang only) - -c++std .... Select C++ standard [c++1z/c++14/c++11] - (Not supported with MSVC) + -c++std .... Select C++ standard [c++17/c++14/c++11] + (Not supported with MSVC 2015) -sse2 ................ Use SSE2 instructions [auto] -sse3/-ssse3/-sse4.1/-sse4.2/-avx/-avx2/-avx512 diff --git a/configure.json b/configure.json index f7449ec0685..da8308a80cf 100644 --- a/configure.json +++ b/configure.json @@ -319,7 +319,7 @@ } }, "c++1z": { - "label": "C++1z support", + "label": "C++17 support", "type": "compile", "test": { "head": [ @@ -907,7 +907,7 @@ "output": [ "publicFeature", "publicQtConfig" ] }, "c++1z": { - "label": "C++1z", + "label": "C++17", "condition": "features.c++14 && tests.c++1z", "output": [ "publicFeature", "publicQtConfig" ] }, diff --git a/configure.pri b/configure.pri index d8d0260fa06..bfc0ca013fa 100644 --- a/configure.pri +++ b/configure.pri @@ -14,9 +14,6 @@ defineTest(qtConfCommandline_qmakeArgs) { } defineTest(qtConfCommandline_cxxstd) { - msvc: \ - qtConfAddError("Command line option -c++std is not supported with MSVC compilers.") - arg = $${1} val = $${2} isEmpty(val): val = $$qtConfGetNextCommandlineArg() @@ -26,7 +23,7 @@ defineTest(qtConfCommandline_cxxstd) { } else: contains(val, "(c\+\+)?(14|1y)") { qtConfCommandlineSetInput("c++14", "yes") qtConfCommandlineSetInput("c++1z", "no") - } else: contains(val, "(c\+\+)?(1z)") { + } else: contains(val, "(c\+\+)?(17|1z)") { qtConfCommandlineSetInput("c++14", "yes") qtConfCommandlineSetInput("c++1z", "yes") } else { From 51bae0331c1fde52d0b3f1184d38a2be462ebd42 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 17 Apr 2019 16:01:46 +0200 Subject: [PATCH 37/52] Add qmake support for c++2a Makes it possible to build user projects and Qt with C++2a. It is not automatically upgraded to yet though. Change-Id: I949ce94871ddc53f21b7265a52b9c0e1370456c8 Reviewed-by: Thiago Macieira --- config_help.txt | 2 +- configure.json | 22 +++++++++++++++++++++- configure.pri | 8 ++++++++ mkspecs/common/clang.conf | 2 ++ mkspecs/common/g++-base.conf | 2 ++ mkspecs/common/msvc-version.conf | 2 ++ mkspecs/features/default_post.prf | 7 ++++--- mkspecs/features/qt_common.prf | 1 + 8 files changed, 41 insertions(+), 5 deletions(-) diff --git a/config_help.txt b/config_help.txt index d63f9be5f88..6b27529bdc1 100644 --- a/config_help.txt +++ b/config_help.txt @@ -139,7 +139,7 @@ Build options: -coverage {trace-pc-guard} Add code coverage instrumentation (Clang only) - -c++std .... Select C++ standard [c++17/c++14/c++11] + -c++std .... Select C++ standard [c++2a/c++17/c++14/c++11] (Not supported with MSVC 2015) -sse2 ................ Use SSE2 instructions [auto] diff --git a/configure.json b/configure.json index da8308a80cf..7f3018ed230 100644 --- a/configure.json +++ b/configure.json @@ -339,6 +339,20 @@ "qmake": "CONFIG += c++11 c++14 c++1z" } }, + "c++2a": { + "label": "C++2a support", + "type": "compile", + "test": { + "head": [ + "#if __cplusplus > 201703L", + "// Compiler claims to support experimental C++2a, trust it", + "#else", + "# error __cplusplus must be > 201703L (the value for C++17)", + "#endif" + ], + "qmake": "CONFIG += c++11 c++14 c++1z c++2a" + } + }, "precompile_header": { "label": "precompiled header support", "type": "compile", @@ -911,6 +925,12 @@ "condition": "features.c++14 && tests.c++1z", "output": [ "publicFeature", "publicQtConfig" ] }, + "c++2a": { + "label": "C++2a", + "autoDetect": false, + "condition": "features.c++1z && tests.c++2a", + "output": [ "publicFeature", "publicQtConfig" ] + }, "c89": { "label": "C89" }, @@ -1413,7 +1433,7 @@ Configure with '-qreal float' to create a build that is binary-compatible with 5 { "message": "Using C++ standard", "type": "firstAvailableFeature", - "args": "c++1z c++14 c++11" + "args": "c++2a c++1z c++14 c++11" }, { "type": "feature", diff --git a/configure.pri b/configure.pri index bfc0ca013fa..81133da3d7e 100644 --- a/configure.pri +++ b/configure.pri @@ -20,12 +20,20 @@ defineTest(qtConfCommandline_cxxstd) { !contains(val, "^-.*"):!isEmpty(val) { contains(val, "(c\+\+)?11") { qtConfCommandlineSetInput("c++14", "no") + qtConfCommandlineSetInput("c++1z", "no") + qtConfCommandlineSetInput("c++2a", "no") } else: contains(val, "(c\+\+)?(14|1y)") { qtConfCommandlineSetInput("c++14", "yes") qtConfCommandlineSetInput("c++1z", "no") + qtConfCommandlineSetInput("c++2a", "no") } else: contains(val, "(c\+\+)?(17|1z)") { qtConfCommandlineSetInput("c++14", "yes") qtConfCommandlineSetInput("c++1z", "yes") + qtConfCommandlineSetInput("c++2a", "no") + } else: contains(val, "(c\+\+)?(2a)") { + qtConfCommandlineSetInput("c++14", "yes") + qtConfCommandlineSetInput("c++1z", "yes") + qtConfCommandlineSetInput("c++2a", "yes") } else { qtConfAddError("Invalid argument $$val to command line parameter $$arg") } diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf index dacd1539cf9..df210fe42d6 100644 --- a/mkspecs/common/clang.conf +++ b/mkspecs/common/clang.conf @@ -31,9 +31,11 @@ QMAKE_CXXFLAGS_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG QMAKE_CXXFLAGS_CXX11 = -std=c++11 QMAKE_CXXFLAGS_CXX14 = -std=c++1y QMAKE_CXXFLAGS_CXX1Z = -std=c++1z +QMAKE_CXXFLAGS_CXX2A = -std=c++2a QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11 QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z +QMAKE_CXXFLAGS_GNUCXX2A = -std=gnu++2a QMAKE_LFLAGS_CXX11 = QMAKE_LFLAGS_CXX14 = diff --git a/mkspecs/common/g++-base.conf b/mkspecs/common/g++-base.conf index fa0f0c391dc..8053feb876e 100644 --- a/mkspecs/common/g++-base.conf +++ b/mkspecs/common/g++-base.conf @@ -32,9 +32,11 @@ QMAKE_CFLAGS_GNUC11 = -std=gnu11 QMAKE_CXXFLAGS_CXX11 = -std=c++11 QMAKE_CXXFLAGS_CXX14 = -std=c++1y QMAKE_CXXFLAGS_CXX1Z = -std=c++1z +QMAKE_CXXFLAGS_CXX2A = -std=c++2a QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11 QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z +QMAKE_CXXFLAGS_GNUCXX2A = -std=gnu++2a QMAKE_LFLAGS_CXX11 = QMAKE_LFLAGS_CXX14 = QMAKE_LFLAGS_CXX1Z = diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index 06af6abf13b..af331320773 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -116,6 +116,8 @@ greaterThan(QMAKE_MSC_VER, 1910) { greaterThan(QMAKE_MSC_VER, 1919) { # Visual Studio 2019 (16.0) / Visual C++ 19.20 and up MSVC_VER = 16.0 + QMAKE_CXXFLAGS_CXX2A = -std:c++latest + } !isEmpty(COMPAT_MKSPEC):!$$COMPAT_MKSPEC: CONFIG += $$COMPAT_MKSPEC diff --git a/mkspecs/features/default_post.prf b/mkspecs/features/default_post.prf index 69da78c5b7c..9df99b86484 100644 --- a/mkspecs/features/default_post.prf +++ b/mkspecs/features/default_post.prf @@ -121,15 +121,16 @@ breakpad { c++17: CONFIG += c++1z -!c++11:!c++14:!c++1z { +!c++11:!c++14:!c++1z:!c++2a { # Qt requires C++11 since 5.7, check if we need to force a compiler option QT_COMPILER_STDCXX_no_L = $$replace(QT_COMPILER_STDCXX, "L$", "") !greaterThan(QT_COMPILER_STDCXX_no_L, 199711): CONFIG += c++11 } -c++11|c++14|c++1z { +c++11|c++14|c++1z|c++2a { # Disable special compiler flags for host builds !host_build|!cross_compile { - c++1z: cxxstd = CXX1Z + c++2a: cxxstd = CXX2A + else: c++1z: cxxstd = CXX1Z else: c++14: cxxstd = CXX14 else: cxxstd = CXX11 } else { diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf index ae859a81ff2..004b32fd228 100644 --- a/mkspecs/features/qt_common.prf +++ b/mkspecs/features/qt_common.prf @@ -17,6 +17,7 @@ DEFINES *= QT_NO_NARROWING_CONVERSIONS_IN_CONNECT qtConfig(c++11): CONFIG += c++11 strict_c++ qtConfig(c++14): CONFIG += c++14 qtConfig(c++1z): CONFIG += c++1z +qtConfig(c++2a): CONFIG += c++2a qtConfig(c99): CONFIG += c99 qtConfig(c11): CONFIG += c11 qtConfig(stack-protector-strong): CONFIG += stack_protector_strong From 585150e3d947d0ee30489f275e7fc39bce4fe059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 22 Mar 2019 15:13:25 +0100 Subject: [PATCH 38/52] macOS: Clean up and deduplicate QMacCGContext We now use QCFType to track the CGContextRef, instead of manually maintaining the lifetime of the context. A bunch of unused methods were removed, including completely broken ones like isNull(). Change-Id: Ib5a05aadbf8f228192e74c9a4c8919580b831497 Reviewed-by: Timur Pocheptsov --- src/gui/painting/qcoregraphics.mm | 162 ++++++++++++++++------------- src/gui/painting/qcoregraphics_p.h | 36 ++----- 2 files changed, 95 insertions(+), 103 deletions(-) diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm index 53066687d3c..e2497eaadbc 100644 --- a/src/gui/painting/qcoregraphics.mm +++ b/src/gui/painting/qcoregraphics.mm @@ -366,40 +366,35 @@ void qt_mac_scale_region(QRegion *region, qreal scaleFactor) // ---------------------- QMacCGContext ---------------------- -QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0) +QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) { - // In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. - QImage *image = 0; - if (paintDevice->devType() == QInternal::Image) { - image = static_cast(paintDevice); - } else if (paintDevice->devType() == QInternal::Pixmap) { - - const QPixmap *pm = static_cast(paintDevice); - QPlatformPixmap *data = const_cast(pm)->data_ptr().data(); - if (data && data->classId() == QPlatformPixmap::RasterClass) { - image = data->buffer(); - } else { - qDebug("QMacCGContext: Unsupported pixmap class"); - } - } else if (paintDevice->devType() == QInternal::Widget) { - // TODO test: image = static_cast(static_cast(paintDevice)->backingStore()->paintDevice()); - qDebug("QMacCGContext: not implemented: Widget class"); - } - - if (!image) - return; // Context type not supported. - - QCFType colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), 8, - image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); - - CGContextTranslateCTM(context, 0, image->height()); - const qreal devicePixelRatio = paintDevice->devicePixelRatioF(); - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - CGContextScaleCTM(context, 1, -1); + initialize(paintDevice); } -QMacCGContext::QMacCGContext(QPainter *painter) : context(0) +void QMacCGContext::initialize(QPaintDevice *paintDevice) +{ + // Find the underlying QImage of the paint device + switch (int deviceType = paintDevice->devType()) { + case QInternal::Pixmap: { + auto *platformPixmap = static_cast(paintDevice)->handle(); + if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass) + initialize(platformPixmap->buffer()); + else + qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId(); + break; + } + case QInternal::Image: + initialize(static_cast(paintDevice)); + break; + case QInternal::Widget: + qWarning() << "QMacCGContext: not implemented: Widget class"; + break; + default: + qWarning() << "QMacCGContext:: Unsupported paint device type" << deviceType; + } +} + +QMacCGContext::QMacCGContext(QPainter *painter) { QPaintEngine *paintEngine = painter->paintEngine(); @@ -414,51 +409,68 @@ QMacCGContext::QMacCGContext(QPainter *painter) : context(0) return; } - int devType = painter->device()->devType(); - if (paintEngine->type() == QPaintEngine::Raster - && (devType == QInternal::Widget || - devType == QInternal::Pixmap || - devType == QInternal::Image)) { - - const QImage *image = static_cast(paintEngine->paintDevice()); - QCFType colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8, - image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); - - // Invert y axis - CGContextTranslateCTM(context, 0, image->height()); - CGContextScaleCTM(context, 1, -1); - - const qreal devicePixelRatio = image->devicePixelRatio(); - - if (devType == QInternal::Widget) { - // Set the clip rect which is an intersection of the system clip - // and the painter clip. To make matters more interesting these - // are in device pixels and device-independent pixels, respectively. - QRegion clip = painter->paintEngine()->systemClip(); // get system clip in device pixels - QTransform native = painter->deviceTransform(); // get device transform. dx/dy is in device pixels - - if (painter->hasClipping()) { - QRegion r = painter->clipRegion(); // get painter clip, which is in device-independent pixels - qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels - r.translate(native.dx(), native.dy()); - if (clip.isEmpty()) - clip = r; - else - clip &= r; - } - qt_mac_clip_cg(context, clip, 0); // clip in device pixels - - // Scale the context so that painting happens in device-independent pixels - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio); - } else { - // Scale to paint in device-independent pixels - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - } - } else { - qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; + if (paintEngine->type() != QPaintEngine::Raster) { + qWarning() << "QMacCGContext:: Unsupported paint engine type" << paintEngine->type(); + return; } + + // The raster paint engine always operates on a QImage + Q_ASSERT(paintEngine->paintDevice()->devType() == QInternal::Image); + + // On behalf of one of these supported painter devices + switch (int painterDeviceType = painter->device()->devType()) { + case QInternal::Pixmap: + case QInternal::Image: + case QInternal::Widget: + break; + default: + qWarning() << "QMacCGContext:: Unsupported paint device type" << painterDeviceType; + return; + } + + // Applying the clip is so entangled with the rest of the context setup + // that for simplicity we just pass in the painter. + initialize(static_cast(paintEngine->paintDevice()), painter); +} + +void QMacCGContext::initialize(const QImage *image, QPainter *painter) +{ + QCFType colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8, + image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); + + // Invert y axis + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); + + const qreal devicePixelRatio = image->devicePixelRatio(); + + if (painter && painter->device()->devType() == QInternal::Widget) { + // Set the clip rect which is an intersection of the system clip and the painter clip + QRegion clip = painter->paintEngine()->systemClip(); + QTransform deviceTransform = painter->deviceTransform(); + + if (painter->hasClipping()) { + // To make matters more interesting the painter clip is in device-independent pixels, + // so we need to scale it to match the device-pixels of the system clip. + QRegion painterClip = painter->clipRegion(); + qt_mac_scale_region(&painterClip, devicePixelRatio); + + painterClip.translate(deviceTransform.dx(), deviceTransform.dy()); + + if (clip.isEmpty()) + clip = painterClip; + else + clip &= painterClip; + } + + qt_mac_clip_cg(context, clip, 0); + + CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy()); + } + + // Scale the context so that painting happens in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); } QT_END_NAMESPACE diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h index 868c2b08b5d..ba2cde8325f 100644 --- a/src/gui/painting/qcoregraphics_p.h +++ b/src/gui/painting/qcoregraphics_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include + #include #include #include @@ -89,38 +91,16 @@ Q_GUI_EXPORT QBrush qt_mac_toQBrush(CGColorRef color); class Q_GUI_EXPORT QMacCGContext { public: - inline QMacCGContext() { context = 0; } + QMacCGContext() = default; QMacCGContext(QPaintDevice *pdev); QMacCGContext(QPainter *p); - inline QMacCGContext(CGContextRef cg, bool takeOwnership = false) { - context = cg; - if (!takeOwnership) - CGContextRetain(context); - } - inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; } - inline ~QMacCGContext() { - if (context) - CGContextRelease(context); - } - inline bool isNull() const { return context; } - inline operator CGContextRef() { return context; } - inline QMacCGContext &operator=(const QMacCGContext ©) { - if (context) - CGContextRelease(context); - context = copy.context; - CGContextRetain(context); - return *this; - } - inline QMacCGContext &operator=(CGContextRef cg) { - if (context) - CGContextRelease(context); - context = cg; - CGContextRetain(context); //we do not take ownership - return *this; - } + + operator CGContextRef() { return context; } private: - CGContextRef context; + void initialize(QPaintDevice *paintDevice); + void initialize(const QImage *, QPainter *painter = nullptr); + QCFType context; }; QT_END_NAMESPACE From 2b2133f85362325dbb7c0a8e73b8a4697128b5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 21 Mar 2019 15:26:45 +0100 Subject: [PATCH 39/52] macOS: Gracefully handle devicePixelRatio mismatch in QCALayerBackingStore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the client of the backingstore fails to pick up dpr changes, and tries to flush the backingstore without a repaint, we will end up flushing a back-buffer with a stale dpr. Detect when this happens, warn the user, and smooth out the situation by adjusting the layer accordingly. Change-Id: If4596a8976a3902252c81d8e28c7aeb9fdd908bf Reviewed-by: Laszlo Agocs Reviewed-by: Morten Johan Sørvig --- .../platforms/cocoa/qcocoabackingstore.h | 1 + .../platforms/cocoa/qcocoabackingstore.mm | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 508f24d5780..6f245982500 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -93,6 +93,7 @@ private: QRegion dirtyRegion; // In unscaled coordinates QImage *asImage(); + qreal devicePixelRatio() const { return m_devicePixelRatio; } private: qreal m_devicePixelRatio; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 8e4e928bc5f..d42a723b470 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -460,12 +460,29 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, NSView *backingStoreView = static_cast(window()->handle())->view(); NSView *flushedView = static_cast(flushedWindow->handle())->view(); + // If the backingstore is just flushed, without being painted to first, then we may + // end in a situation where the backingstore is flushed to a layer with a different + // scale factor than the one it was created for in beginPaint. This is the client's + // fault in not picking up the change in scale factor of the window and re-painting + // the backingstore accordingly. To smoothing things out, we warn about this situation, + // and change the layer's contentsScale to match the scale of the back buffer, so that + // we at least cover the whole layer. This is necessary since we set the view's + // contents placement policy to NSViewLayerContentsPlacementTopLeft, which means + // AppKit will not do any scaling on our behalf. + if (m_buffers.back()->devicePixelRatio() != flushedView.layer.contentsScale) { + qCWarning(lcQpaBackingStore) << "Back buffer dpr of" << m_buffers.back()->devicePixelRatio() + << "doesn't match" << flushedView.layer << "contents scale of" << flushedView.layer.contentsScale + << "- updating layer to match."; + flushedView.layer.contentsScale = m_buffers.back()->devicePixelRatio(); + } + id backBufferSurface = (__bridge id)m_buffers.back()->surface(); if (flushedView.layer.contents == backBufferSurface) { // We've managed to paint to the back buffer again before Core Animation had time - // to flush the transaction and persist the layer changes to the window server. - // The layer already knows about the back buffer, and we don't need to re-apply - // it to pick up the surface changes, so bail out early. + // to flush the transaction and persist the layer changes to the window server, or + // we've been asked to flush without painting anything. The layer already knows about + // the back buffer, and we don't need to re-apply it to pick up any possible surface + // changes, so bail out early. qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView << ", layer already reflects back buffer"; return; From 6a21dc9d734fbde681dc4bf01d41561766a4359c Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 23 Apr 2019 10:10:08 +0200 Subject: [PATCH 40/52] Fix typo in QHostAddress::SpecialAddress description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia4269b74eb85d5055ca0e893277be92df012c000 Fixes: QTBUG-75332 Reviewed-by: Akihito Izawa Reviewed-by: Mårten Nordheim --- src/network/kernel/qhostaddress.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index fba91c62c80..5d0ef150f30 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -385,8 +385,8 @@ QHostAddress QNetmask::address(QAbstractSocket::NetworkLayerProtocol protocol) c \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1"). \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1"). \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255"). - \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interaces. - \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interaces. + \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interfaces. + \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interfaces. \value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces. */ From 49be1a3c1f81a85ab3e9061bc95bf61ebc35ef08 Mon Sep 17 00:00:00 2001 From: Kavindra Palaraja Date: Fri, 12 Apr 2019 16:32:51 +0200 Subject: [PATCH 41/52] doc: Explain the config members for INSTALLS Task-number: QTBUG-3209 Change-Id: I00f181a9f29d4ae440a9ad6a2d99877cab482db8 Reviewed-by: Joerg Bornemann --- qmake/doc/src/qmake-manual.qdoc | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index d91d056d100..efc049e03a2 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -1271,6 +1271,41 @@ \snippet code/doc_src_qmake-manual.pro 36 + \c INSTALLS has a \c{.CONFIG} member that can take several values: + + \table + \header + \li Value + \li Description + \row + \li no_check_exists + \li If not set, qmake looks to see if the files to install actually + exist. If these files don't exist, qmake doesn’t create the + install rule. Use this config value if you need to install + files that are generated as part of your build process, like + HTML files created by qdoc. + \row + \li nostrip + \li If set, the typical Unix strip functionality is turned off and + the debug information will remain in the binary. + \row + \li executable + \li On Unix, this sets the executable flag. + \row + \li no_build + \li When you do a \c{make install}, and you don't have a build of + the project yet, the project is first built, and then installed. + If you don't want this behavior, set this config value to ensure + that the build target is not added as a dependency to the install + target. + \row + \li no_default_install + \li A project has a top-level project target where, when you do a + \c{make install}, everything is installed. But, if you have an + install target with this config value set, it's not installed by + default. You then have to explicitly say \c{make install_}. + \endtable + For more information, see \l{Installing Files}. This variable is also used to specify which additional files will be From c2917243a96d19c9cd49c827e63d40b7c0110d7d Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 15 Apr 2019 12:41:52 +0200 Subject: [PATCH 42/52] syncqt: Fix resolution of injected headers for external modules Injected headers were made relative to MODULE_BASE_OUTDIR by syncqt and made absolute by resolving against REAL_MODULE_BASE_OUTDIR. This breaks for modules that reside outside the original Qt source tree (if the directory depth doesn't coincidentally match). Now, we resolve injected headers against build_basedir, which is REAL_MODULE_BASE_OUTDIR. To emphasize the equivalence of REAL_MODULE_BASE_OUTDIR and syncqt's build_basedir, use the former for syncqt's -output argument. This commit amends 2aa779e8. Fixes: QTBUG-70587 Change-Id: I2935d87d7ee681fa4aa795a270b94ab7a43abe59 Reviewed-by: Dominik Holland Reviewed-by: Oliver Wolff --- bin/syncqt.pl | 2 +- mkspecs/features/qt_module_headers.prf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 972717efcfa..7793811c9f0 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -1111,7 +1111,7 @@ foreach my $lib (@modules_to_sync) { elsif (!$shadow) { $pri_install_pfiles.= "$pri_install_iheader ";; } - $pri_injections .= fixPaths($iheader, $out_basedir) + $pri_injections .= fixPaths($iheader, $build_basedir) .":".($no_stamp ? "^" : "").fixPaths($oheader, "$out_basedir/include/$lib") .$injection." " if ($shadow); } diff --git a/mkspecs/features/qt_module_headers.prf b/mkspecs/features/qt_module_headers.prf index 6b4b9143fa5..37b69e31c82 100644 --- a/mkspecs/features/qt_module_headers.prf +++ b/mkspecs/features/qt_module_headers.prf @@ -23,7 +23,7 @@ load(qt_build_paths) QMAKE_SYNCQT += -module $$mod QMAKE_SYNCQT += \ -version $$VERSION -outdir $$system_quote($$MODULE_BASE_OUTDIR) \ - -builddir $$system_quote($$shadowed($$MODULE_BASE_INDIR)) $$MODULE_SYNCQT_DIR + -builddir $$system_quote($$REAL_MODULE_BASE_OUTDIR) $$MODULE_SYNCQT_DIR !silent: message($$QMAKE_SYNCQT) system($$QMAKE_SYNCQT)|error("Failed to run: $$QMAKE_SYNCQT") From f36a306563b4e77e4c64884382da22f3412708a0 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 17 Apr 2019 14:16:36 +0200 Subject: [PATCH 43/52] configure: Support the = prefix for -I and -L For gcc's -I and -L arguments a = prefix is replaced by the sysroot. Since we're resolving include paths and library paths, we have to support this feature. For example, the linux-rasp-pi3-g++ makes use of this and is broken without this patch. Change-Id: Ie39e63322bd35e2a93aa8e55d52260164b8c6a6b Reviewed-by: Kai Koehne --- mkspecs/features/qt_configure.prf | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index 62ad9727961..aa4348235ea 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -515,6 +515,17 @@ defineTest(qtConfSetupLibraries) { } } +defineReplace(qtGccSysrootifiedPath) { + return($$replace(1, ^=, $$[QT_SYSROOT])) +} + +defineReplace(qtGccSysrootifiedPaths) { + sysrootified = + for (path, 1): \ + sysrootified += $$qtGccSysrootifiedPath($$path) + return($$sysrootified) +} + # libs-var, libs, in-paths, out-paths-var defineTest(qtConfResolveLibs) { ret = true @@ -531,6 +542,7 @@ defineTest(qtConfResolveLibs) { out += $$l } else: contains(l, "^-L.*") { lp = $$replace(l, "^-L", ) + gcc: lp = $$qtGccSysrootifiedPath($$lp) !exists($$lp/.) { qtLog("Library path $$val_escape(lp) is invalid.") ret = false @@ -604,6 +616,7 @@ defineTest(qtConfResolveAllLibs) { # libs-var, in-paths, libs defineTest(qtConfResolvePathLibs) { ret = true + gcc: 2 = $$qtGccSysrootifiedPaths($$2) for (libdir, 2) { !exists($$libdir/.) { qtLog("Library path $$val_escape(libdir) is invalid.") @@ -654,6 +667,7 @@ defineReplace(qtConfGetTestIncludes) { # includes-var, in-paths, test-object-var defineTest(qtConfResolvePathIncs) { ret = true + gcc: 2 = $$qtGccSysrootifiedPaths($$2) for (incdir, 2) { !exists($$incdir/.) { qtLog("Include path $$val_escape(incdir) is invalid.") From de854aa37f49de6d8f6ee12c0e9d247c5143c2da Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 23 Apr 2019 09:54:46 +0200 Subject: [PATCH 44/52] Teach qmake MSVC's compiler options /std:c++[14|17|latest] This fixes the "could not parse compiler option" warning when generating VS project files. Fixes: QTBUG-75275 Change-Id: Idd98ae5fdb8ebf5a4e311cbb6cd3ed1daba74ca4 Reviewed-by: Kai Koehne --- qmake/generators/win32/msbuild_objectmodel.cpp | 2 ++ qmake/generators/win32/msvc_objectmodel.cpp | 8 ++++++++ qmake/generators/win32/msvc_objectmodel.h | 1 + 3 files changed, 11 insertions(+) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index ad2976aa016..87cd560552d 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -143,6 +143,7 @@ const char _InterfaceIdentifierFileName[] = "InterfaceIdentifierFileName"; const char _IntermediateDirectory[] = "IntermediateDirectory"; const char _KeyContainer[] = "KeyContainer"; const char _KeyFile[] = "KeyFile"; +const char _LanguageStandard[] = "LanguageStandard"; const char _LargeAddressAware[] = "LargeAddressAware"; const char _LinkDLL[] = "LinkDLL"; const char _LinkErrorReporting[] = "LinkErrorReporting"; @@ -1492,6 +1493,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCCLCompilerTool &tool) << attrTagT(_IntrinsicFunctions, tool.EnableIntrinsicFunctions) << attrTagT(_MinimalRebuild, tool.MinimalRebuild) << attrTagT(_MultiProcessorCompilation, tool.MultiProcessorCompilation) + << attrTagS(_LanguageStandard, tool.LanguageStandard) << attrTagS(_ObjectFileName, tool.ObjectFile) << attrTagT(_OmitDefaultLibName, tool.OmitDefaultLibName) << attrTagT(_OmitFramePointers, tool.OmitFramePointers) diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 7335211f301..f08554d0f5b 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -1146,6 +1146,14 @@ bool VCCLCompilerTool::parseOption(const char* option) ShowIncludes = _True; break; } + if (strlen(option) > 8 && second == 't' && third == 'd') { + const QString version = option + 8; + static const QStringList knownVersions = { "14", "17", "latest" }; + if (knownVersions.contains(version)) { + LanguageStandard = "stdcpp" + version; + break; + } + } found = false; break; case 'u': if (!second) diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h index 41a6ffafa70..f6d1fc8023d 100644 --- a/qmake/generators/win32/msvc_objectmodel.h +++ b/qmake/generators/win32/msvc_objectmodel.h @@ -526,6 +526,7 @@ public: triState ImproveFloatingPointConsistency; inlineExpansionOption InlineFunctionExpansion; triState KeepComments; + QString LanguageStandard; triState MinimalRebuild; QString ObjectFile; triState OmitDefaultLibName; From ba6e0e4aac4d06782325c7032c8ea475f2d3eab0 Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 13 Apr 2019 19:37:37 +0200 Subject: [PATCH 45/52] QHeaderView: fix assert when restoring section sizes over less columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If columns are removed and we get notified via layoutChanged, the code tries to restore old section sizes, and went out of bounds, leading to an assert in QVector. Simply add an if() to skip restoring out-of-bounds columns. This comes from https://bugs.kde.org/show_bug.cgi?id=395181, which translates into the unittest that is part of this commit. Change-Id: Ide42176a758f87b21957c40508127d67f1d5a2d9 Reviewed-by: Christian Ehrlicher Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/itemviews/qheaderview.cpp | 14 ++++++++------ .../itemviews/qheaderview/tst_qheaderview.cpp | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 62abf567511..99309633a7b 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2283,13 +2283,15 @@ void QHeaderViewPrivate::_q_sectionsChanged(const QList & : index.row()); // the new visualIndices are already adjusted / reset by initializeSections() const int newVisualIndex = visualIndex(newLogicalIndex); - auto &newSection = sectionItems[newVisualIndex]; - newSection = item.section; + if (newVisualIndex < sectionItems.count()) { + auto &newSection = sectionItems[newVisualIndex]; + newSection = item.section; - if (newSection.isHidden) { - // otherwise setSectionHidden will return without doing anything - newSection.isHidden = false; - q->setSectionHidden(newLogicalIndex, true); + if (newSection.isHidden) { + // otherwise setSectionHidden will return without doing anything + newSection.isHidden = false; + q->setSectionHidden(newLogicalIndex, true); + } } } diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index eaf75e74945..1b3e1e1f34e 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -248,6 +248,7 @@ private slots: void sizeHintCrash(); void testResetCachedSizeHint(); void statusTips(); + void testRemovingColumnsViaLayoutChanged(); protected: void setupTestData(bool use_reset_model = false); @@ -353,6 +354,7 @@ public: void cleanup() { + emit layoutAboutToBeChanged(); cols = 3; rows = 3; emit layoutChanged(); @@ -3489,5 +3491,20 @@ void tst_QHeaderView::statusTips() QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header")); } +void tst_QHeaderView::testRemovingColumnsViaLayoutChanged() +{ + const int persistentSectionSize = 101; + + QtTestModel model; + model.rows = model.cols = 5; + view->setModel(&model); + for (int i = 0; i < model.cols; ++i) + view->resizeSection(i, persistentSectionSize + i); + model.cleanup(); // down to 3 via layoutChanged (not columnsRemoved) + for (int j = 0; j < model.cols; ++j) + QCOMPARE(view->sectionSize(j), persistentSectionSize + j); + // The main point of this test is that the section-size restoring code didn't go out of bounds. +} + QTEST_MAIN(tst_QHeaderView) #include "tst_qheaderview.moc" From 7718b708983cfcbd6fcb0e3b89519b2f8a02942d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 18 Apr 2019 09:43:31 +0200 Subject: [PATCH 46/52] Blacklist tst_QWidget::windowState on WinRT Task-number: QTBUG-75270 Change-Id: Icf1089b4d3681bc6a42be9c095acb5315dd67781 Reviewed-by: Gatis Paeglis --- tests/auto/widgets/kernel/qwidget/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index 3287d67875f..03bec4286b6 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -46,3 +46,6 @@ osx osx-10.12 ci [multipleToplevelFocusCheck] linux +[windowState] +# QTBUG-75270 +winrt From 54ceb8a5f86465dcde334973dedf401b31210e63 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Mon, 15 Apr 2019 14:48:23 +0200 Subject: [PATCH 47/52] qglxconvenience: use QMAKE_USE instead of QMAKE_USE_PRIVATE The provided API uses Xlib types, so it should publicly link with Xlib. Fixes: QTBUG-75045 Change-Id: Ifea1e8df27cdcc57fb04cd68a7aa1e9fa339c53d Reviewed-by: Laszlo Agocs Reviewed-by: Joerg Bornemann --- src/platformsupport/glxconvenience/glxconvenience.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformsupport/glxconvenience/glxconvenience.pro b/src/platformsupport/glxconvenience/glxconvenience.pro index 8367dc5e312..1b9cf790804 100644 --- a/src/platformsupport/glxconvenience/glxconvenience.pro +++ b/src/platformsupport/glxconvenience/glxconvenience.pro @@ -6,7 +6,7 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII -QMAKE_USE_PRIVATE += xlib +QMAKE_USE += xlib HEADERS += qglxconvenience_p.h SOURCES += qglxconvenience.cpp From 20e286107344f2cb188f5292d31dc62bf7708365 Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 13 Apr 2019 15:38:15 +0200 Subject: [PATCH 48/52] Optimize QAbstractTableModel::hasChildren Valid indexes cannot have children, in a table model, so there's no point in asking the model about it (by calling rowCount and columnCount). Change-Id: Ic2d7b52538a7b67acb2c35b26e69bba5956ef5af Reviewed-by: Giuseppe D'Angelo Reviewed-by: Friedemann Kleint Reviewed-by: Christian Ehrlicher --- src/corelib/itemmodels/qabstractitemmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 18f0f6f55f7..25a80a640c4 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -3618,7 +3618,7 @@ QModelIndex QAbstractTableModel::sibling(int row, int column, const QModelIndex bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const { - if (parent.model() == this || !parent.isValid()) + if (!parent.isValid()) return rowCount(parent) > 0 && columnCount(parent) > 0; return false; } From ed66c932b1460ce5dcb3f7f1cb4c37f726683175 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 15 Apr 2019 21:07:40 +0200 Subject: [PATCH 49/52] QListWidgetItem constructors: don't emit dataChanged(invalid, invalid) This is a regression introduced by 63967313f57add which blocked signals on the view, but not on the model. Change-Id: Ib2f93fe6ef842264aaba200c98ee4a19065ca220 Reviewed-by: Shawn Rutledge Reviewed-by: Konstantin Shegunov Reviewed-by: Laurent Montel Reviewed-by: Christian Ehrlicher --- src/widgets/itemviews/qlistwidget.cpp | 8 ++++++-- .../widgets/itemviews/qlistwidget/tst_qlistwidget.cpp | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index a9899983c2e..e46d25bef19 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -650,11 +650,13 @@ QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *listview, int |Qt::ItemIsEnabled |Qt::ItemIsDragEnabled) { + QListModel *model = listModel(); { QSignalBlocker b(view); + QSignalBlocker bm(model); setData(Qt::DisplayRole, text); } - if (QListModel *model = listModel()) + if (model) model->insert(model->rowCount(), this); } @@ -683,12 +685,14 @@ QListWidgetItem::QListWidgetItem(const QIcon &icon,const QString &text, |Qt::ItemIsEnabled |Qt::ItemIsDragEnabled) { + QListModel *model = listModel(); { QSignalBlocker b(view); + QSignalBlocker bm(model); setData(Qt::DisplayRole, text); setData(Qt::DecorationRole, icon); } - if (QListModel *model = listModel()) + if (model) model->insert(model->rowCount(), this); } diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp index 30afa69c317..91088aeeca4 100644 --- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp @@ -267,6 +267,7 @@ tst_QListWidget::tst_QListWidget(): testWidget(0), rcParent(8), rcFirst(8,0), rc void tst_QListWidget::initTestCase() { + qRegisterMetaType("QListWidgetItem*"); testWidget = new QListWidget(); testWidget->show(); @@ -663,6 +664,9 @@ void tst_QListWidget::insertItems() QFETCH(int, rowCount); QFETCH(int, insertType); + QSignalSpy itemChangedSpy(testWidget, &QListWidget::itemChanged); + QSignalSpy dataChangedSpy(testWidget->model(), &QAbstractItemModel::dataChanged); + if (insertType == 3) { QStringList strings; for (int i=0; icount(); ++i) QCOMPARE(testWidget->item(i)->listWidget(), testWidget); + + QCOMPARE(itemChangedSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); } void tst_QListWidget::itemAssignment() @@ -1257,7 +1264,6 @@ void tst_QListWidget::setData() QFETCH(IntList, roles); QFETCH(QVariantList, values); QFETCH(int, expectedSignalCount); - qRegisterMetaType("QListWidgetItem*"); QCOMPARE(roles.count(), values.count()); @@ -1715,7 +1721,6 @@ void tst_QListWidget::task258949_keypressHangup() void tst_QListWidget::QTBUG8086_currentItemChangedOnClick() { - qRegisterMetaType("QListWidgetItem*"); QWidget win; QHBoxLayout layout(&win); QListWidget list; @@ -1837,7 +1842,6 @@ void tst_QListWidget::mimeData() void tst_QListWidget::QTBUG50891_ensureSelectionModelSignalConnectionsAreSet() { - qRegisterMetaType("QListWidgetItem*"); QListWidget list; for (int i = 0 ; i < 4; ++i) new QListWidgetItem(QString::number(i), &list); From 40d9ac93e0bf974439ae2abecbcc979c7dc9d06d Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 20 Feb 2019 12:17:19 +0100 Subject: [PATCH 50/52] Clean up help message for the public suffix list processor The grep given in the help from the program to process the effective-TLD list only worked for voodoo reasons. Replaced it with an actually-correct use of grep. The commands given used the name effective_tld_names.dat in the URL fetched; however, the relevant file has (for some time now) said explicitly "Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat" Changed the name used to match that URL. Revised the output file's suggested name and the instructions for what to do with its contents, making clear they *replace* what was there before ... Fixed some typos and related ugliness. Change-Id: Iacd186c0003227d657099716262eb3a89c9e5f1b Reviewed-by: Volker Hilsheimer --- util/corelib/qurl-generateTLDs/main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/util/corelib/qurl-generateTLDs/main.cpp b/util/corelib/qurl-generateTLDs/main.cpp index 7268fb077af..e1fe97646fd 100644 --- a/util/corelib/qurl-generateTLDs/main.cpp +++ b/util/corelib/qurl-generateTLDs/main.cpp @@ -57,15 +57,15 @@ int main(int argc, char **argv) { QCoreApplication app(argc, argv); if (argc < 3) { - printf("\nusage: %s inputFile outputFile\n\n", argv[0]); + printf("\nUsage: ./%s inputFile outputFile\n\n", argv[0]); printf("'inputFile' should be a list of effective TLDs, one per line,\n"); - printf("as obtained from http://publicsuffix.org . To create indices and data file\n"); + printf("as obtained from http://publicsuffix.org/. To create indices and data\n"); printf("file, do the following:\n\n"); - printf(" wget https://publicsuffix.org/list/effective_tld_names.dat -O effective_tld_names.dat\n"); - printf(" grep '^[^\\/\\/]' effective_tld_names.dat > effective_tld_names.dat.trimmed\n"); - printf(" %s effective_tld_names.dat.trimmed effective_tld_names.dat.qt\n\n", argv[0]); - printf("Now copy the data from effective_tld_names.dat.qt to the file src/corelib/io/qurltlds_p.h in your Qt repo\n\n"); - exit(1); + printf(" wget https://publicsuffix.org/list/public_suffix_list.dat -O public_suffix_list.dat\n"); + printf(" grep -v '^//' public_suffix_list.dat | grep . > public_suffix_list.dat.trimmed\n"); + printf(" ./%s public_suffix_list.dat.trimmed public_suffix_list.cpp\n\n", argv[0]); + printf("Now replace the code in qtbase/src/corelib/io/qurltlds_p.h with public_suffix_list.cpp's contents\n\n"); + return 1; } QFile file(argv[1]); QFile outFile(argv[2]); From 9dfc2aa75d930c6676f901e817bbc8c900a966f5 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 11 Apr 2019 12:35:12 +0200 Subject: [PATCH 51/52] Purge use of some deprecated methods from QDateTime tests QDateTime's short names setUtcOffset() and utcOffset() have been deprecated since 5.2, in favor of setOffsetFromUtc() and offsetFromUtc(). QDate's shortDayName() and shortMOnthName() have been deprecated since 5.10, in favor of QLocale's dayName() and monthName(). Also, the tests that were using them are testing methods only present when the datestring feature is enabled; so condition them on that feature. Change-Id: Ibfd4b132523ca8fbc1cb163353a44e0500877fd5 Reviewed-by: Thiago Macieira --- src/corelib/tools/qdatetime.h | 2 +- .../corelib/tools/qdatetime/tst_qdatetime.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index 43271b34ed4..8b2a60acaab 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -335,7 +335,7 @@ public: inline bool operator>(const QDateTime &other) const { return other < *this; } inline bool operator>=(const QDateTime &other) const { return !(*this < other); } -#if QT_DEPRECATED_SINCE(5, 2) +#if QT_DEPRECATED_SINCE(5, 2) // ### Qt 6: remove QT_DEPRECATED void setUtcOffset(int seconds); QT_DEPRECATED int utcOffset() const; #endif // QT_DEPRECATED_SINCE diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 6ad3357f405..38b72ab91fe 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -78,9 +78,11 @@ private slots: void toString_isoDate_data(); void toString_isoDate(); void toString_isoDate_extra(); +#if QT_CONFIG(datestring) void toString_textDate_data(); void toString_textDate(); void toString_textDate_extra(); +#endif void toString_rfcDate_data(); void toString_rfcDate(); void toString_enumformat(); @@ -800,11 +802,11 @@ void tst_QDateTime::toString_isoDate_data() QTest::newRow("positive OffsetFromUTC") << dt << Qt::ISODate << QString("1978-11-09T13:28:34+05:30"); - dt.setUtcOffset(-7200); + dt.setOffsetFromUtc(-7200); QTest::newRow("negative OffsetFromUTC") << dt << Qt::ISODate << QString("1978-11-09T13:28:34-02:00"); - dt.setUtcOffset(-900); + dt.setOffsetFromUtc(-900); QTest::newRow("negative non-integral OffsetFromUTC") << dt << Qt::ISODate << QString("1978-11-09T13:28:34-00:15"); @@ -840,7 +842,7 @@ void tst_QDateTime::toString_isoDate() QCOMPARE(resultDatetime.date(), datetime.date()); QCOMPARE(resultDatetime.time(), datetime.time()); QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec()); - QCOMPARE(resultDatetime.utcOffset(), datetime.utcOffset()); + QCOMPARE(resultDatetime.offsetFromUtc(), datetime.offsetFromUtc()); } else { QCOMPARE(resultDatetime, QDateTime()); } @@ -870,12 +872,14 @@ void tst_QDateTime::toString_isoDate_extra() #endif // timezone } +#if QT_CONFIG(datestring) void tst_QDateTime::toString_textDate_data() { QTest::addColumn("datetime"); QTest::addColumn("expected"); - QString wednesdayJanuary = QDate::shortDayName(3) + ' ' + QDate::shortMonthName(1); + QString wednesdayJanuary = QLocale::system().dayName(3, QLocale::ShortFormat) + + ' ' + QLocale::system().monthName(1, QLocale::ShortFormat); QTest::newRow("localtime") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::LocalTime) << wednesdayJanuary + QString(" 2 01:02:03 2013"); @@ -904,7 +908,7 @@ void tst_QDateTime::toString_textDate() QCOMPARE(resultDatetime.date(), datetime.date()); QCOMPARE(resultDatetime.time(), datetime.time()); QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec()); - QCOMPARE(resultDatetime.utcOffset(), datetime.utcOffset()); + QCOMPARE(resultDatetime.offsetFromUtc(), datetime.offsetFromUtc()); } void tst_QDateTime::toString_textDate_extra() @@ -953,6 +957,7 @@ void tst_QDateTime::toString_textDate_extra() dt = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC); QVERIFY(dt.toString().endsWith(GMT)); } +#endif // datestring void tst_QDateTime::toString_rfcDate_data() { @@ -968,11 +973,11 @@ void tst_QDateTime::toString_rfcDate_data() << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) << QString("09 Nov 1978 13:28:34 +0000"); QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34)); - dt.setUtcOffset(19800); + dt.setOffsetFromUtc(19800); QTest::newRow("positive OffsetFromUTC") << dt << QString("09 Nov 1978 13:28:34 +0530"); - dt.setUtcOffset(-7200); + dt.setOffsetFromUtc(-7200); QTest::newRow("negative OffsetFromUTC") << dt << QString("09 Nov 1978 13:28:34 -0200"); From 2947435d8737f9b97a80532864ec2302f6719355 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Mon, 4 Feb 2019 18:42:35 +0300 Subject: [PATCH 52/52] QSystemTrayIcon/X11: Create tray icon window when system tray appears ... and destroy it otherwise. Fixes: QTBUG-61898 Fixes: QTBUG-73459 Done-with: Gatis Paeglis Change-Id: I6bd8f397f7ccdb123f6a60d4fa466f7b0d760dfc Reviewed-by: Gatis Paeglis --- src/widgets/util/qsystemtrayicon_p.h | 4 ++ src/widgets/util/qsystemtrayicon_x11.cpp | 75 +++++++++++++++++------- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/widgets/util/qsystemtrayicon_p.h b/src/widgets/util/qsystemtrayicon_p.h index 5bdf020a472..e31532ea193 100644 --- a/src/widgets/util/qsystemtrayicon_p.h +++ b/src/widgets/util/qsystemtrayicon_p.h @@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE class QSystemTrayIconSys; +class QSystemTrayWatcher; class QPlatformSystemTrayIcon; class QToolButton; class QLabel; @@ -90,6 +91,8 @@ public: void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs); + void destroyIcon(); + static bool isSystemTrayAvailable_sys(); static bool supportsMessages_sys(); @@ -101,6 +104,7 @@ public: QSystemTrayIconSys *sys; QPlatformSystemTrayIcon *qpa_sys; bool visible; + QSystemTrayWatcher *trayWatcher; private: void install_sys_qpa(); diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index 86532456c76..70e5f3678ea 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -92,9 +92,6 @@ protected: virtual void resizeEvent(QResizeEvent *) override; virtual void moveEvent(QMoveEvent *) override; -private slots: - void systemTrayWindowChanged(QScreen *screen); - private: QSystemTrayIcon *q; }; @@ -116,15 +113,6 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) setMouseTracking(true); } -void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *) -{ - if (!locateSystemTray()) { - QBalloonTip::hideBalloon(); - hide(); // still no luck - destroy(); - } -} - QRect QSystemTrayIconSys::globalGeometry() const { return QRect(mapToGlobal(QPoint(0, 0)), size()); @@ -199,10 +187,41 @@ void QSystemTrayIconSys::resizeEvent(QResizeEvent *event) } //////////////////////////////////////////////////////////////////////////// +class QSystemTrayWatcher: public QObject +{ + Q_OBJECT +public: + QSystemTrayWatcher(QSystemTrayIcon *trayIcon) + : QObject(trayIcon) + , mTrayIcon(trayIcon) + { + // This code uses string-based syntax because we want to connect to a signal + // which is defined in XCB plugin - QXcbNativeInterface::systemTrayWindowChanged(). + connect(qGuiApp->platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), + this, SLOT(systemTrayWindowChanged(QScreen*))); + } + +private slots: + void systemTrayWindowChanged(QScreen *) + { + auto icon = static_cast(QObjectPrivate::get(mTrayIcon)); + icon->destroyIcon(); + if (icon->visible && locateSystemTray()) { + icon->sys = new QSystemTrayIconSys(mTrayIcon); + icon->sys->show(); + } + } + +private: + QSystemTrayIcon *mTrayIcon = nullptr; +}; +//////////////////////////////////////////////////////////////////////////// + QSystemTrayIconPrivate::QSystemTrayIconPrivate() : sys(0), qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()), - visible(false) + visible(false), + trayWatcher(nullptr) { } @@ -213,16 +232,21 @@ QSystemTrayIconPrivate::~QSystemTrayIconPrivate() void QSystemTrayIconPrivate::install_sys() { + Q_Q(QSystemTrayIcon); + if (qpa_sys) { install_sys_qpa(); return; } - Q_Q(QSystemTrayIcon); - if (!sys && locateSystemTray()) { - sys = new QSystemTrayIconSys(q); - QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), - sys, SLOT(systemTrayWindowChanged(QScreen*))); - sys->show(); + + if (!sys) { + if (!trayWatcher) + trayWatcher = new QSystemTrayWatcher(q); + + if (locateSystemTray()) { + sys = new QSystemTrayIconSys(q); + sys->show(); + } } } @@ -241,14 +265,21 @@ void QSystemTrayIconPrivate::remove_sys() remove_sys_qpa(); return; } + + destroyIcon(); +} + +void QSystemTrayIconPrivate::destroyIcon() +{ if (!sys) return; QBalloonTip::hideBalloon(); - sys->hide(); // this should do the trick, but... - delete sys; // wm may resize system tray only for DestroyEvents - sys = 0; + sys->hide(); + delete sys; + sys = nullptr; } + void QSystemTrayIconPrivate::updateIcon_sys() { if (qpa_sys) {