From cc4c0b43a54d9606f491c193df381a424ae696bf Mon Sep 17 00:00:00 2001 From: Ryan Chu Date: Fri, 3 May 2019 16:14:19 +0200 Subject: [PATCH 01/35] QDataStream: Fix inconsistent results of iostream with QPalette objects The value of NColorRoles got changed since 5.11. It introduced one more role called "PlaceholderText" in the ColorRole enumeration. When using QDataStream (5.12) to read QPalette objects from a file written by 5.9 (<5.11), the processing results are inconsistent. Fixes: QTBUG-74885 Change-Id: I14d57f9603a26e5890b4fd57c7e464c5b38eb3f2 Reviewed-by: Eirik Aavitsland --- src/gui/kernel/qpalette.cpp | 5 ++ .../qdatastream/tst_qdatastream.cpp | 54 +++++++++++++++---- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp index 9ccfb9b819..c6805dd4e6 100644 --- a/src/gui/kernel/qpalette.cpp +++ b/src/gui/kernel/qpalette.cpp @@ -1006,6 +1006,8 @@ QDataStream &operator<<(QDataStream &s, const QPalette &p) max = QPalette::HighlightedText + 1; else if (s.version() <= QDataStream::Qt_4_3) max = QPalette::AlternateBase + 1; + else if (s.version() <= QDataStream::Qt_5_11) + max = QPalette::ToolTipText + 1; for (int r = 0; r < max; r++) s << p.d->br[grp][r]; } @@ -1046,6 +1048,9 @@ QDataStream &operator>>(QDataStream &s, QPalette &p) } else if (s.version() <= QDataStream::Qt_4_3) { p = QPalette(); max = QPalette::AlternateBase + 1; + } else if (s.version() <= QDataStream::Qt_5_11) { + p = QPalette(); + max = QPalette::ToolTipText + 1; } QBrush tmp; diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp index 011a0e1a85..041d9d7a09 100644 --- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp @@ -174,6 +174,7 @@ private slots: void floatingPointPrecision(); + void compatibility_Qt5(); void compatibility_Qt3(); void compatibility_Qt2(); @@ -260,17 +261,17 @@ static int NColorRoles[] = { QPalette::HighlightedText + 1, // Qt_4_0, Qt_4_1 QPalette::HighlightedText + 1, // Qt_4_2 QPalette::AlternateBase + 1, // Qt_4_3 - QPalette::PlaceholderText + 1, // Qt_4_4 - QPalette::PlaceholderText + 1, // Qt_4_5 - QPalette::PlaceholderText + 1, // Qt_4_6 - QPalette::PlaceholderText + 1, // Qt_5_0 - QPalette::PlaceholderText + 1, // Qt_5_1 - QPalette::PlaceholderText + 1, // Qt_5_2 - QPalette::PlaceholderText + 1, // Qt_5_3 - QPalette::PlaceholderText + 1, // Qt_5_4 - QPalette::PlaceholderText + 1, // Qt_5_5 - QPalette::PlaceholderText + 1, // Qt_5_6 - 0 // add the correct value for Qt_5_7 here later + QPalette::ToolTipText + 1, // Qt_4_4 + QPalette::ToolTipText + 1, // Qt_4_5 + QPalette::ToolTipText + 1, // Qt_4_6, Qt_4_7, Qt_4_8, Qt_4_9 + QPalette::ToolTipText + 1, // Qt_5_0 + QPalette::ToolTipText + 1, // Qt_5_1 + QPalette::ToolTipText + 1, // Qt_5_2, Qt_5_3 + QPalette::ToolTipText + 1, // Qt_5_4, Qt_5_5 + QPalette::ToolTipText + 1, // Qt_5_6, Qt_5_7, Qt_5_8, Qt_5_9, Qt_5_10, Qt_5_11 + QPalette::PlaceholderText + 1, // Qt_5_12 + QPalette::PlaceholderText + 1, // Qt_5_13 + 0 // add the correct value for Qt_5_14 here later }; // Testing get/set functions @@ -3102,6 +3103,37 @@ void tst_QDataStream::streamRealDataTypes() } } +void tst_QDataStream::compatibility_Qt5() +{ + QLinearGradient gradient(QPointF(0,0), QPointF(1,1)); + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(1, Qt::blue); + + QBrush brush(gradient); + QPalette palette; + palette.setBrush(QPalette::Button, brush); + palette.setColor(QPalette::Light, Qt::green); + + QByteArray stream; + { + QDataStream out(&stream, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_5_7); + out << palette; + out << brush; + } + QBrush in_brush; + QPalette in_palette; + { + QDataStream in(stream); + in.setVersion(QDataStream::Qt_5_7); + in >> in_palette; + in >> in_brush; + } + QCOMPARE(in_brush.style(), Qt::LinearGradientPattern); + QCOMPARE(in_palette.brush(QPalette::Button).style(), Qt::LinearGradientPattern); + QCOMPARE(in_palette.color(QPalette::Light), QColor(Qt::green)); +} + void tst_QDataStream::compatibility_Qt3() { QByteArray ba("hello"); From ebddd02896709d5856dc73f1a4f1479133c7ed2f Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 24 May 2019 14:32:51 +0200 Subject: [PATCH 02/35] QMacStyle - fix the separator's color in the Dark theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's too dark as it is now. Since there is no similar UI element in AppKit, we take the same color as the toolbar's handle has (looks OK-eysh with 'Dark' and there is no reason to have the separator with a color different from the bar handle, both elements essentialy are lines of dots). Fixes: QTBUG-72759 Change-Id: I28277f80174a1c4c0af17961aba8ed6135aa3189 Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index cf7cf18c17..ee5556ec9e 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3152,7 +3152,9 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai theStroker.setCapStyle(Qt::FlatCap); theStroker.setDashPattern(QVector() << 1 << 2); path = theStroker.createStroke(path); - p->fillPath(path, QColor(0, 0, 0, 119)); + const auto dark = qt_mac_applicationIsInDarkMode() ? opt->palette.dark().color().darker() + : QColor(0, 0, 0, 119); + p->fillPath(path, dark); } break; case PE_FrameWindow: From c04bd30de072793faee5166cff866a4c4e0a9dd7 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Wed, 8 May 2019 15:24:14 +0200 Subject: [PATCH 03/35] Guard against numerical overflow when processing QPainterPaths Many operations on and with QPainterPaths do calculations on the path coordinates, e.g. computing the distance between points, which may cause numerical overflow for extreme coordinate values. This patch introduces a limit on the coordinate values and extends the previous check against nan/inf coordinates to also check against out of range coordinates. Fixes: QTBUG-75574 Change-Id: I3a2fa88bfc6a9f19934c43d3dbbfb41855c78107 Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qpainterpath.cpp | 57 ++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index c5ccf0003d..9b82b768d4 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -71,6 +71,24 @@ QT_BEGIN_NAMESPACE +static inline bool isValidCoord(qreal c) +{ + if (sizeof(qreal) >= sizeof(double)) + return qIsFinite(c) && fabs(c) < 1e128; + else + return qIsFinite(c) && fabsf(float(c)) < 1e16f; +} + +static bool hasValidCoords(QPointF p) +{ + return isValidCoord(p.x()) && isValidCoord(p.y()); +} + +static bool hasValidCoords(QRectF r) +{ + return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height()); +} + struct QPainterPathPrivateDeleter { static inline void cleanup(QPainterPathPrivate *d) @@ -675,9 +693,9 @@ void QPainterPath::moveTo(const QPointF &p) printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y()); #endif - if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) { + if (!hasValidCoords(p)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call"); + qWarning("QPainterPath::moveTo: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -725,9 +743,9 @@ void QPainterPath::lineTo(const QPointF &p) printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y()); #endif - if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) { + if (!hasValidCoords(p)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call"); + qWarning("QPainterPath::lineTo: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -784,10 +802,9 @@ void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF & c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y()); #endif - if (!qt_is_finite(c1.x()) || !qt_is_finite(c1.y()) || !qt_is_finite(c2.x()) || !qt_is_finite(c2.y()) - || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) { + if (!hasValidCoords(c1) || !hasValidCoords(c2) || !hasValidCoords(e)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN or Inf, ignoring call"); + qWarning("QPainterPath::cubicTo: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -841,9 +858,9 @@ void QPainterPath::quadTo(const QPointF &c, const QPointF &e) c.x(), c.y(), e.x(), e.y()); #endif - if (!qt_is_finite(c.x()) || !qt_is_finite(c.y()) || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) { + if (!hasValidCoords(c) || !hasValidCoords(e)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::quadTo: Adding point where x or y is NaN or Inf, ignoring call"); + qWarning("QPainterPath::quadTo: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -912,10 +929,9 @@ void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength); #endif - if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height()) - || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) { + if (!hasValidCoords(rect) || !isValidCoord(startAngle) || !isValidCoord(sweepLength)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call"); + qWarning("QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -1018,9 +1034,9 @@ QPointF QPainterPath::currentPosition() const */ void QPainterPath::addRect(const QRectF &r) { - if (!qt_is_finite(r.x()) || !qt_is_finite(r.y()) || !qt_is_finite(r.width()) || !qt_is_finite(r.height())) { + if (!hasValidCoords(r)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN or Inf, ignoring call"); + qWarning("QPainterPath::addRect: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -1098,10 +1114,9 @@ void QPainterPath::addPolygon(const QPolygonF &polygon) */ void QPainterPath::addEllipse(const QRectF &boundingRect) { - if (!qt_is_finite(boundingRect.x()) || !qt_is_finite(boundingRect.y()) - || !qt_is_finite(boundingRect.width()) || !qt_is_finite(boundingRect.height())) { + if (!hasValidCoords(boundingRect)) { #ifndef QT_NO_DEBUG - qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN or Inf, ignoring call"); + qWarning("QPainterPath::addEllipse: Adding point with invalid coordinates, ignoring call"); #endif return; } @@ -2446,6 +2461,7 @@ QDataStream &operator<<(QDataStream &s, const QPainterPath &p) */ QDataStream &operator>>(QDataStream &s, QPainterPath &p) { + bool errorDetected = false; int size; s >> size; @@ -2464,10 +2480,11 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p) s >> x; s >> y; Q_ASSERT(type >= 0 && type <= 3); - if (!qt_is_finite(x) || !qt_is_finite(y)) { + if (!isValidCoord(qreal(x)) || !isValidCoord(qreal(y))) { #ifndef QT_NO_DEBUG - qWarning("QDataStream::operator>>: NaN or Inf element found in path, skipping it"); + qWarning("QDataStream::operator>>: Invalid QPainterPath coordinates read, skipping it"); #endif + errorDetected = true; continue; } QPainterPath::Element elm = { qreal(x), qreal(y), QPainterPath::ElementType(type) }; @@ -2480,6 +2497,8 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p) p.d_func()->fillRule = Qt::FillRule(fillRule); p.d_func()->dirtyBounds = true; p.d_func()->dirtyControlBounds = true; + if (errorDetected) + p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash return s; } #endif // QT_NO_DATASTREAM From b9f96cacc99c8a242f45f4581843a6b1c67501f4 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 27 May 2019 19:00:09 +0200 Subject: [PATCH 04/35] QRegExp: remove an out of bounds access into QString ... spotted with the brand-new checks for that in QCharRef. The rx[i] == ~~~ check is clearly wrong, as rx is the regexp we're building and `i` was not supposed to index into it. The intended meaning was wc[i] == ~~~, testing if we were seeing the closing bracket of a character set. We need to check for that immediately for dealing with the special syntax of []...] where the ] belongs to the character set (it can't be the closing one as character sets cannot be empty). Fix and add a regression test. Bonus: this code was almost unchanged since 2009. Change-Id: I958cd87fc25558e9d202d18b3dd4a35d0db16d8d Reviewed-by: Marc Mutz Reviewed-by: hjk --- src/corelib/tools/qregexp.cpp | 2 +- tests/auto/corelib/tools/qregexp/tst_qregexp.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp index 87b30c952e..ef24c952eb 100644 --- a/src/corelib/tools/qregexp.cpp +++ b/src/corelib/tools/qregexp.cpp @@ -825,7 +825,7 @@ static QString wc2rx(const QString &wc_str, const bool enableEscaping) if (wc[i] == QLatin1Char('^')) rx += wc[i++]; if (i < wclen) { - if (rx[i] == QLatin1Char(']')) + if (wc[i] == QLatin1Char(']')) rx += wc[i++]; while (i < wclen && wc[i] != QLatin1Char(']')) { if (wc[i] == QLatin1Char('\\')) diff --git a/tests/auto/corelib/tools/qregexp/tst_qregexp.cpp b/tests/auto/corelib/tools/qregexp/tst_qregexp.cpp index a98d37d733..a8111af6c1 100644 --- a/tests/auto/corelib/tools/qregexp/tst_qregexp.cpp +++ b/tests/auto/corelib/tools/qregexp/tst_qregexp.cpp @@ -834,6 +834,13 @@ void tst_QRegExp::testEscapingWildcard_data(){ QTest::newRow("a true '\\' in input") << "\\Qt;" << "\\Qt;" << true; QTest::newRow("two true '\\' in input") << "\\\\Qt;" << "\\\\Qt;" << true; QTest::newRow("a '\\' at the end") << "\\\\Qt;\\" << "\\\\Qt;\\" << true; + + QTest::newRow("[]\\] matches ]") << "[]\\]" << "]" << true; + QTest::newRow("[]\\] matches \\") << "[]\\]" << "\\" << true; + QTest::newRow("[]\\] does not match [") << "[]\\]" << "[" << false; + QTest::newRow("[]\\]a matches ]a") << "[]\\]a" << "]a" << true; + QTest::newRow("[]\\]a matches \\a") << "[]\\]a" << "\\a" << true; + QTest::newRow("[]\\]a does not match [a") << "[]\\]a" << "[a" << false; } void tst_QRegExp::testEscapingWildcard(){ From 978987981ac1ad0689e042cc241c1732496b59bb Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 22 May 2019 14:56:58 +0200 Subject: [PATCH 05/35] Automatically sysrootify $$[FOO/get] properties If automatic sysrootification is in effect (SysrootifyPrefix=true in qt.conf) then the qmake property variants $$[FOO] and $$[FOO/get] must be sysrootified. The latter was never sysrootified. All other variants (src, dev, raw) are supposed to be without sysroot. Flesh out a sysrootify function and readabilitify the code a bit while we're at it. Fixes: QTBUG-71673 Change-Id: Ifcbce8c035b9da447da9d6937edd5a4aa84573ba Reviewed-by: Oliver Wolff --- src/corelib/global/qlibraryinfo.cpp | 35 ++++++++++++++++++----------- src/corelib/global/qlibraryinfo.h | 1 + 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 4119012d85..d19e54154e 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -432,7 +432,24 @@ void QLibraryInfo::reload() { QLibraryInfoPrivate::reload(); } -#endif + +void QLibraryInfo::sysrootify(QString *path) +{ + if (!QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool()) + return; + + const QString sysroot = rawLocation(SysrootPath, FinalPaths); + if (sysroot.isEmpty()) + return; + + if (path->length() > 2 && path->at(1) == QLatin1Char(':') + && (path->at(2) == QLatin1Char('/') || path->at(2) == QLatin1Char('\\'))) { + path->replace(0, 2, sysroot); // Strip out the drive on Windows targets + } else { + path->prepend(sysroot); + } +} +#endif // QT_BUILD_QMAKE /*! Returns the location specified by \a loc. @@ -444,18 +461,8 @@ QLibraryInfo::location(LibraryLocation loc) QString ret = rawLocation(loc, FinalPaths); // Automatically prepend the sysroot to target paths - if (loc < SysrootPath || loc > LastHostPath) { - QString sysroot = rawLocation(SysrootPath, FinalPaths); - if (!sysroot.isEmpty() - && QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool()) { - if (ret.length() > 2 && ret.at(1) == QLatin1Char(':') - && (ret.at(2) == QLatin1Char('/') || ret.at(2) == QLatin1Char('\\'))) { - ret.replace(0, 2, sysroot); // Strip out the drive on Windows targets - } else { - ret.prepend(sysroot); - } - } - } + if (loc < SysrootPath || loc > LastHostPath) + sysrootify(&ret); return ret; } @@ -598,6 +605,8 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) } else { // we make any other path absolute to the prefix directory baseDir = rawLocation(PrefixPath, group); + if (group == EffectivePaths) + sysrootify(&baseDir); } #else if (loc == PrefixPath) { diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index 80fc5bd4fc..9414af9b7d 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -107,6 +107,7 @@ public: enum PathGroup { FinalPaths, EffectivePaths, EffectiveSourcePaths, DevicePaths }; static QString rawLocation(LibraryLocation, PathGroup); static void reload(); + static void sysrootify(QString *path); #endif static QStringList platformPluginArguments(const QString &platformName); From 0f417efe0fb37d03d2c1e98958d4213d263c90c0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 28 May 2019 14:22:07 +0200 Subject: [PATCH 06/35] Windows QPA: Fix QGuiApplication::topLevelAt() with screen recorder applications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Special applications like screen recorders can create special, invisible windows which are detected by the ChildWindowFromPointEx() as used in QWindowsContext::findPlatformWindowAt(). Fall back to WindowFromPoint() which skips those in case nothing is found. Fixes: QTBUG-40815 Change-Id: Idb5253c412fb4522c844edf5eadedc6e0fad3979 Reviewed-by: André de la Rocha --- src/plugins/platforms/windows/qwindowscontext.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 55e7e32979..e7ac01e411 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -749,6 +749,12 @@ QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent, QWindowsWindow *result = nullptr; const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() }; while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {} + // QTBUG-40815: ChildWindowFromPointEx() can hit on special windows from + // screen recorder applications like ScreenToGif. Fall back to WindowFromPoint(). + if (result == nullptr) { + if (const HWND window = WindowFromPoint(screenPoint)) + result = findPlatformWindow(window); + } return result; } From c150c7a566234a7bf69fa114d493ac9839c57ad5 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 28 May 2019 18:24:33 +0200 Subject: [PATCH 07/35] Windows QPA: Optimize code that gets window under pointer It's not necessary to call QWindowsScreen::windowAt() for every mouse message received, but only when the mouse is captured, like it's done in the legacy mouse handler. Change-Id: Ib1035921291d22a32dfa3a619815a3f4ff9b3622 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index fd3d711470..8b88007949 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -269,7 +269,10 @@ static Qt::MouseButtons queryMouseButtons() static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { - QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); + QWindowsWindow *platformWindow = static_cast(window->handle()); + + QWindow *currentWindowUnderPointer = platformWindow->hasMouseCapture() ? + QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window; while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput) currentWindowUnderPointer = currentWindowUnderPointer->parent(); From 4df554c652568805424e3fa256380c7310ccac72 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 24 May 2019 14:56:59 +0200 Subject: [PATCH 08/35] Windows QPA: Fix clang warnings about narrowing conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iba173b45fb77918694fc2c7506885fdeef9f6064 Reviewed-by: André de la Rocha --- .../platforms/direct2d/qwindowsdirect2dhelpers.h | 7 +++++-- src/plugins/platforms/windows/qwindowscontext.cpp | 5 +++-- src/plugins/platforms/windows/qwindowsscreen.cpp | 2 +- src/plugins/platforms/windows/qwindowswindow.cpp | 10 ++++++---- .../windows/uiautomation/qwindowsuiautils.cpp | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h index babe646fd8..6d880e24cf 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h @@ -69,12 +69,15 @@ inline D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect) inline D2D1_SIZE_U to_d2d_size_u(const QSizeF &qsize) { - return D2D1::SizeU(qsize.width(), qsize.height()); + + return D2D1::SizeU(UINT32(qRound(qsize.width())), + UINT32(qRound(qsize.height()))); } inline D2D1_SIZE_U to_d2d_size_u(const QSize &qsize) { - return D2D1::SizeU(qsize.width(), qsize.height()); + return D2D1::SizeU(UINT32(qsize.width()), + UINT32(qsize.height())); } inline D2D1_POINT_2F to_d2d_point_2f(const QPointF &qpoint) diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index e7ac01e411..76747b7956 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -931,7 +931,7 @@ bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out, const QPlatformScreen *screen) { - return systemParametersInfo(action, param, out, screen ? screen->logicalDpi().first : 0); + return systemParametersInfo(action, param, out, screen ? unsigned(screen->logicalDpi().first) : 0u); } bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out, @@ -950,7 +950,8 @@ bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi) bool QWindowsContext::nonClientMetricsForScreen(NONCLIENTMETRICS *ncm, const QPlatformScreen *screen) { - return nonClientMetrics(ncm, screen ? screen->logicalDpi().first : 0); + const int dpi = screen ? qRound(screen->logicalDpi().first) : 0; + return nonClientMetrics(ncm, unsigned(dpi)); } bool QWindowsContext::nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win) diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index b28a113ce6..cc0f3c1a6e 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -91,7 +91,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) } else { if (const HDC hdc = CreateDC(info.szDevice, nullptr, nullptr, nullptr)) { const QDpi dpi = monitorDPI(hMonitor); - data->dpi = dpi.first ? dpi : deviceDPI(hdc); + data->dpi = dpi.first > 0 ? dpi : deviceDPI(hdc); data->depth = GetDeviceCaps(hdc, BITSPIXEL); data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 3bf424d0ac..eb521dac52 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -851,10 +851,12 @@ static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) { if (QHighDpiScaling::isActive()) { const qreal factor = QHighDpiScaling::factor(w); - if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) - dip.rwidth() *= factor; - if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX) - dip.rheight() *= factor; + if (!qFuzzyCompare(factor, qreal(1))) { + if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) + dip.setWidth(qRound(qreal(dip.width()) * factor)); + if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX) + dip.setHeight(qRound(qreal(dip.height()) * factor)); + } } return dip; } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index 7980826b49..ab04384616 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -114,7 +114,7 @@ void setVariantBool(bool value, VARIANT *variant) void setVariantDouble(double value, VARIANT *variant) { variant->vt = VT_R8; - variant->boolVal = value; + variant->dblVal = value; } BSTR bStrFromQString(const QString &value) From c3571d2922d41617e81fa9e8ae971d08fb9e94af Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 23 May 2019 10:48:28 +0200 Subject: [PATCH 09/35] Correct qfloat16's 1/inf == 0 test It should have been qfloat16(1)/qfloat16(infinity) in any case. Sadly, that behaves no better than qfloat16(1.f/qfloat16(infinity)), which was promoting the infinity back to float. So retain the check for over-optimization (but make the comment more accurate). This is a follow-up to d441f6bba7b2aaf1e11b95c1ad4c785e6939f6ba. Change-Id: Iec4afe4b04081b0ebfbf98058da606dc3ade07f4 Reviewed-by: Qt CI Bot Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira --- tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp index aa6f0935e8..b73a297245 100644 --- a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp +++ b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp @@ -172,9 +172,9 @@ void tst_qfloat16::qNan() QVERIFY(qIsInf(-inf)); QVERIFY(qIsInf(2.f*inf)); QVERIFY(qIsInf(inf*2.f)); - // QTBUG-75812: QEMU's over-optimized arm64 flakily fails 1/inf == 0 :-( + // QTBUG-75812: QEMU/arm64 compiler over-optimizes, so flakily fails 1/inf == 0 :-( if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) - QCOMPARE(qfloat16(1.f/inf), qfloat16(0.f)); + QCOMPARE(qfloat16(1.f) / inf, qfloat16(0.f)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif From a67b25067ee78e0c2bc4e77a4c61af43528d9bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 27 May 2019 18:36:13 +0200 Subject: [PATCH 10/35] Rename QMacScopedObserver to the more fittingly QMacNotificationObserver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I1d8280fe88871572a3a27e612de49717b3b9ef77 Reviewed-by: Tor Arne Vestbø --- src/corelib/kernel/qcore_mac_p.h | 16 ++++++++-------- src/plugins/platforms/cocoa/qcocoaglcontext.h | 2 +- src/plugins/platforms/cocoa/qcocoaglcontext.mm | 8 ++++---- src/plugins/platforms/cocoa/qcocoaintegration.h | 2 +- src/plugins/platforms/cocoa/qcocoaintegration.mm | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index f96e7358a2..2428faed15 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -295,13 +295,13 @@ QT_MAC_WEAK_IMPORT(_os_activity_current); // ------------------------------------------------------------------------- #if defined( __OBJC__) -class QMacScopedObserver +class QMacNotificationObserver { public: - QMacScopedObserver() {} + QMacNotificationObserver() {} template - QMacScopedObserver(id object, NSNotificationName name, Functor callback) { + QMacNotificationObserver(id object, NSNotificationName name, Functor callback) { observer = [[NSNotificationCenter defaultCenter] addObserverForName:name object:object queue:nil usingBlock:^(NSNotification *) { callback(); @@ -309,13 +309,13 @@ public: ]; } - QMacScopedObserver(const QMacScopedObserver& other) = delete; - QMacScopedObserver(QMacScopedObserver&& other) : observer(other.observer) { + QMacNotificationObserver(const QMacNotificationObserver& other) = delete; + QMacNotificationObserver(QMacNotificationObserver&& other) : observer(other.observer) { other.observer = nil; } - QMacScopedObserver &operator=(const QMacScopedObserver& other) = delete; - QMacScopedObserver &operator=(QMacScopedObserver&& other) { + QMacNotificationObserver &operator=(const QMacNotificationObserver& other) = delete; + QMacNotificationObserver &operator=(QMacNotificationObserver&& other) { if (this != &other) { remove(); observer = other.observer; @@ -329,7 +329,7 @@ public: [[NSNotificationCenter defaultCenter] removeObserver:observer]; observer = nil; } - ~QMacScopedObserver() { remove(); } + ~QMacNotificationObserver() { remove(); } private: id observer = nil; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index eefb1cd0fb..c1041ac2da 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -80,7 +80,7 @@ private: NSOpenGLContext *m_shareContext = nil; QSurfaceFormat m_format; bool m_didCheckForSoftwareContext = false; - QVarLengthArray m_updateObservers; + QVarLengthArray m_updateObservers; QAtomicInt m_needsUpdate = false; }; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 93d95b38ea..d0100d0410 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -404,13 +404,13 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) m_updateObservers.clear(); if (view.layer) { - m_updateObservers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback)); - m_updateObservers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); } else { - m_updateObservers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); } - m_updateObservers.append(QMacScopedObserver([NSApplication sharedApplication], + m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication], NSApplicationDidChangeScreenParametersNotification, updateCallback)); // If any of the observers fire at this point it's fine. We check the diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 04cb4e1226..ecbd19c9a2 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -144,7 +144,7 @@ private: #endif QScopedPointer mPlatformTheme; QList mScreens; - QMacScopedObserver m_screensObserver; + QMacNotificationObserver m_screensObserver; #ifndef QT_NO_CLIPBOARD QCocoaClipboard *mCocoaClipboard; #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index cbbf6b115e..232c74b1e9 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -207,7 +207,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) // which will resolve to an actual value and result in screen invalidation. cocoaApplication.presentationOptions = NSApplicationPresentationDefault; - m_screensObserver = QMacScopedObserver([NSApplication sharedApplication], + m_screensObserver = QMacNotificationObserver([NSApplication sharedApplication], NSApplicationDidChangeScreenParametersNotification, [&]() { updateScreens(); }); updateScreens(); From 1eac947ce2c1d63bd04a94939c4f04e9086913c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 22 May 2019 14:01:41 +0200 Subject: [PATCH 11/35] Work around crash where a destroyed window becomes focus_window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clear QGuiApplication::focus_window (again) in the QWindow destructor. Task-number: QTBUG-75326 Change-Id: Ief00b6adfb267fcc7e3881fd728e12df07fc1094 Reviewed-by: Christian Andersen Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index bcd8351619..a19df4da0f 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -218,6 +218,12 @@ QWindow::~QWindow() QGuiApplicationPrivate::window_list.removeAll(this); if (!QGuiApplicationPrivate::is_app_closing) QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this); + + // focus_window is normally cleared in destroy(), but the window may in + // some cases end up becoming the focus window again. Clear it again + // here as a workaround. See QTBUG-75326. + if (QGuiApplicationPrivate::focus_window == this) + QGuiApplicationPrivate::focus_window = 0; } void QWindowPrivate::init(QScreen *targetScreen) From 364240ed11f5f72341d9e2fa5009baecb4398b1b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 30 May 2019 19:06:02 +0200 Subject: [PATCH 12/35] macOS: Enable VK_MVK_macos_surface on the instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reports say some systems get "Failed to find vkCreateMacOSSurfaceMVK" even though MoltenVK and the corresponding extensionare there. While not reproducable on single GPU Intel systems, it could be that not enabling the extension on the Vulkan instance is causing this. Not opting in to the extension is incorrect in theory anyway. So fix it in cocoa as well, similarly to how other platform plugins do this already. Task-number: QTBUG-76117 Change-Id: I75220f3582a700ce0037003086123d3d38524648 Reviewed-by: Tor Arne Vestbø Reviewed-by: Mike Krus --- src/plugins/platforms/cocoa/qcocoavulkaninstance.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index b00fde6c6f..7ce78ee738 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -54,7 +54,7 @@ QCocoaVulkanInstance::~QCocoaVulkanInstance() void QCocoaVulkanInstance::createOrAdoptInstance() { - initInstance(m_instance, QByteArrayList()); + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface")); } VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window) From 81b33a8252d8a69277782f51c9c7401c7009c72e Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 27 May 2019 14:35:18 +0200 Subject: [PATCH 13/35] Fusion: Fill the rect with base brush when drawing the combobox frame Instead of doing this directly inside the PE_FrameLineEdit as this can be used directly when a stylesheet is set the rect of the lineedit used in the combobox in fusion style is filled directly with the base brush. This ensures it still renders the background correctly when using fusion style, but enables stylesheets to work as it will not override that if the background is set in a stylesheet for a combobox. Fixes: QTBUG-75816 Change-Id: I50a0600b500088ebcf1d70a02f9c74c6040d34d9 Reviewed-by: Friedemann Kleint Reviewed-by: Richard Moe Gustavsen --- src/widgets/styles/qfusionstyle.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index c565932889..64954dc833 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -2769,8 +2769,16 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption buttonOption.state &= ~State_MouseOver; } - if (comboBox->frame) + if (comboBox->frame) { + cachePainter.save(); + cachePainter.setRenderHint(QPainter::Antialiasing, true); + cachePainter.translate(0.5, 0.5); + cachePainter.setPen(Qt::NoPen); + cachePainter.setBrush(buttonOption.palette.base()); + cachePainter.drawRoundedRect(rect.adjusted(0, 0, -1, -1), 2, 2); + cachePainter.restore(); proxy()->drawPrimitive(PE_FrameLineEdit, &buttonOption, &cachePainter, widget); + } // Draw button clipped cachePainter.save(); From 90c683e41cd978b55de57cb424a986db3b637fcc Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 15 May 2019 15:06:20 +0200 Subject: [PATCH 14/35] Q(Plain)TextEdit: Observe color hints from style sheet depending on focus state Ask the style sheet style to adapt the palette in WidgetTextControl::getPaintContext() as is done for QLineEdit. Use the palette color in QPlainTextEdit. Change-Id: I67758716b66feaeac8c2433c2a4d3744cd0d5327 Fixes: QTBUG-72100 Reviewed-by: Christian Ehrlicher Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qplaintextedit.cpp | 1 + src/widgets/widgets/qwidgettextcontrol.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index 0b5e69b6c3..3b5132a8c8 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -1957,6 +1957,7 @@ void QPlainTextEdit::paintEvent(QPaintEvent *e) } QAbstractTextDocumentLayout::PaintContext context = getPaintContext(); + painter.setPen(context.palette.text().color()); while (block.isValid()) { diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index 6b8ce63380..ee757bf870 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -64,6 +64,9 @@ #include "private/qtextdocument_p.h" #include "qtextlist.h" #include "private/qwidgettextcontrol_p.h" +#if QT_CONFIG(style_stylesheet) +# include "private/qstylesheetstyle_p.h" +#endif #if QT_CONFIG(graphicsview) #include "qgraphicssceneevent.h" #endif @@ -3187,6 +3190,15 @@ QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QW ctx.selections = d->extraSelections; ctx.palette = d->palette; +#if QT_CONFIG(style_stylesheet) + if (widget) { + if (auto cssStyle = qt_styleSheet(widget->style())) { + QStyleOption option; + option.initFrom(widget); + cssStyle->styleSheetPalette(widget, &option, &ctx.palette); + } + } +#endif // style_stylesheet if (d->cursorOn && d->isEnabled) { if (d->hideCursor) ctx.cursorPosition = -1; From 085d1335d16210467cbd29f44e046a0f5fe8970f Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 28 May 2019 13:22:39 +0200 Subject: [PATCH 15/35] Warn about invalid SUBDIRS content Invalid SUBDIRS values like SUBDIRS += foo \ bar \ \ baz would produce a Makefile with a sub-- target that will call the make on the same Makefile again recursively, letting make run forever. Ignore values like this and print a warning message. Fixes: QTBUG-76068 Change-Id: I6ca0f8c8238249f1be02d8c311b4c148fd80e707 Reviewed-by: Oliver Wolff --- qmake/generators/makefile.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index d53dbf9fa5..bfef31f17e 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2400,8 +2400,15 @@ MakefileGenerator::findSubDirsSubTargets() const st->profile = file; } } else { - if(!file.isEmpty() && !project->isActiveConfig("subdir_first_pro")) - st->profile = file.section(Option::dir_sep, -1) + Option::pro_ext; + if (!file.isEmpty() && !project->isActiveConfig("subdir_first_pro")) { + const QString baseName = file.section(Option::dir_sep, -1); + if (baseName.isEmpty()) { + warn_msg(WarnLogic, "Ignoring invalid SUBDIRS entry %s", + subdirs[subdir].toLatin1().constData()); + continue; + } + st->profile = baseName + Option::pro_ext; + } st->in_directory = file; } while(st->in_directory.endsWith(Option::dir_sep)) From 67c569add0a3db5f730d81b6bcb3fed22d3a4ce6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 9 May 2019 13:44:12 +0200 Subject: [PATCH 16/35] Make tst_qwidget pass on High-DPI screens (Windows) - Move the fuzz check introduced by 63090627220a6209652d236cf991305fbeb188b8 to a shared header for reuse. Use it in in more places to account for rounding errors introduced by odd window frame sizes when scaling is active. - Use the test widget size to ensure windows do not violate the minimum decorated window size on Windows when scaling is inactive on large monitors. Task-number: QTBUG-46615 Change-Id: Icf803a4bc2c275eadb8f98e60b08e39b2ebebedd Reviewed-by: Oliver Wolff --- tests/auto/shared/highdpi.h | 109 ++++++++++++++++++ .../widgets/kernel/qwidget/tst_qwidget.cpp | 68 +++++------ 2 files changed, 143 insertions(+), 34 deletions(-) create mode 100644 tests/auto/shared/highdpi.h diff --git a/tests/auto/shared/highdpi.h b/tests/auto/shared/highdpi.h new file mode 100644 index 0000000000..f0c34bea25 --- /dev/null +++ b/tests/auto/shared/highdpi.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HIGHDPI_H +#define HIGHDPI_H + +#include +#include +#include +#include + +// Helpers for comparing geometries a that may go through scaling in the +// platform plugin with fuzz (pass rounded-down device pixel ratios or +// scaling factors). Error message for use with QVERIFY2() are also provided. + +class HighDpi +{ +public: + HighDpi() = delete; + HighDpi(const HighDpi &) = delete; + HighDpi &operator=(const HighDpi &) = delete; + HighDpi(HighDpi &&) = delete; + HighDpi &operator=(HighDpi &&) = delete; + ~HighDpi() = delete; + + static int manhattanDelta(const QPoint &p1, const QPoint p2) + { + return (p1 - p2).manhattanLength(); + } + + static bool fuzzyCompare(const QPoint &p1, const QPoint p2, int fuzz) + { + return manhattanDelta(p1, p2) <= fuzz; + } + + static QByteArray msgPointMismatch(const QPoint &p1, const QPoint p2) + { + return QByteArray::number(p1.x()) + ',' + QByteArray::number(p1.y()) + + " != " + QByteArray::number(p2.x()) + ',' + QByteArray::number(p2.y()) + + ", manhattanLength=" + QByteArray::number(manhattanDelta(p1, p2)); + } + + // Compare a size that may go through scaling in the platform plugin with fuzz. + + static inline int manhattanDelta(const QSize &s1, const QSize &s2) + { + return qAbs(s1.width() - s2.width()) + qAbs(s1.height() - s2.height()); + } + + static inline bool fuzzyCompare(const QSize &s1, const QSize &s2, int fuzz) + { + return manhattanDelta(s1, s2) <= fuzz; + } + + static QByteArray msgSizeMismatch(const QSize &s1, const QSize &s2) + { + return QByteArray::number(s1.width()) + 'x' + QByteArray::number(s1.height()) + + " != " + QByteArray::number(s2.width()) + 'x' + QByteArray::number(s2.height()) + + ", manhattanLength=" + QByteArray::number(manhattanDelta(s1, s2)); + } + + // Compare a geometry that may go through scaling in the platform plugin with fuzz. + + static inline bool fuzzyCompare(const QRect &r1, const QRect &r2, int fuzz) + { + return manhattanDelta(r1.topLeft(), r2.topLeft()) <= fuzz + && manhattanDelta(r1.size(), r2.size()) <= fuzz; + } + + static QByteArray msgRectMismatch(const QRect &r1, const QRect &r2) + { + return formatRect(r1) + " != " + formatRect(r2); + } + +private: + static QByteArray formatRect(const QRect &r) + { + return QByteArray::number(r.width()) + 'x' + QByteArray::number(r.height()) + + (r.left() < 0 ? '-' : '+') + QByteArray::number(r.left()) + + (r.top() < 0 ? '-' : '+') + QByteArray::number(r.top()); + } +}; + +#endif // HIGHDPI_H diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index bbaed67a36..c0dfaf80a3 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -26,6 +26,7 @@ ** ****************************************************************************/ +#include "../../../shared/highdpi.h" #include #include @@ -140,19 +141,6 @@ static QByteArray msgComparisonFailed(T v1, const char *op, T v2) return s.toLocal8Bit(); } -// Compare a window position that may go through scaling in the platform plugin with fuzz. -static inline bool qFuzzyCompareWindowPosition(const QPoint &p1, const QPoint p2, int fuzz) -{ - return (p1 - p2).manhattanLength() <= fuzz; -} - -static QString msgPointMismatch(const QPoint &p1, const QPoint p2) -{ - QString result; - QDebug(&result) << p1 << "!=" << p2 << ", manhattanLength=" << (p1 - p2).manhattanLength(); - return result; -} - class tst_QWidget : public QObject { Q_OBJECT @@ -416,6 +404,7 @@ private: QPoint m_safeCursorPos; const bool m_windowsAnimationsEnabled; QTouchDevice *m_touchScreen; + const int m_fuzz; }; bool tst_QWidget::ensureScreenSize(int width, int height) @@ -574,6 +563,7 @@ tst_QWidget::tst_QWidget() , m_safeCursorPos(0, 0) , m_windowsAnimationsEnabled(windowsAnimationsEnabled()) , m_touchScreen(QTest::createTouchDevice()) + , m_fuzz(int(QGuiApplication::primaryScreen()->devicePixelRatio())) { if (m_windowsAnimationsEnabled) // Disable animations which can interfere with screen grabbing in moveChild(), showAndMoveChild() setWindowsAnimationsEnabled(false); @@ -2047,10 +2037,9 @@ void tst_QWidget::windowState() widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); QTest::qWait(100); - const int fuzz = int(QHighDpiScaling::factor(widget1.windowHandle())); QVERIFY(!(widget1.windowState() & Qt::WindowMaximized)); - QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz), - qPrintable(msgPointMismatch(widget1.pos(), pos))); + QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos))); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); widget1.setWindowState(Qt::WindowMinimized); @@ -2071,8 +2060,8 @@ void tst_QWidget::windowState() widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); QTest::qWait(100); QVERIFY(!(widget1.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized))); - QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz), - qPrintable(msgPointMismatch(widget1.pos(), pos))); + QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos))); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); widget1.setWindowState(Qt::WindowFullScreen); @@ -2093,8 +2082,8 @@ void tst_QWidget::windowState() widget1.setWindowState(Qt::WindowNoState); QTest::qWait(100); VERIFY_STATE(Qt::WindowNoState); - QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz), - qPrintable(msgPointMismatch(widget1.pos(), pos))); + QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos))); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); widget1.setWindowState(Qt::WindowFullScreen); @@ -2127,8 +2116,8 @@ void tst_QWidget::windowState() QVERIFY(!(widget1.windowState() & stateMask)); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); - QTRY_VERIFY2(qFuzzyCompareWindowPosition(widget1.pos(), pos, fuzz), - qPrintable(msgPointMismatch(widget1.pos(), pos))); + QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos))); QTRY_COMPARE(widget1.size(), size); } @@ -2321,7 +2310,7 @@ void tst_QWidget::resizeEvent() { QWidget wParent; wParent.setWindowTitle(QLatin1String(QTest::currentTestFunction())); - wParent.resize(200, 200); + wParent.resize(m_testWidgetSize); ResizeWidget wChild(&wParent); wParent.show(); QVERIFY(QTest::qWaitForWindowExposed(&wParent)); @@ -2339,7 +2328,7 @@ void tst_QWidget::resizeEvent() { ResizeWidget wTopLevel; wTopLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction())); - wTopLevel.resize(200, 200); + wTopLevel.resize(m_testWidgetSize); wTopLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel)); if (m_platform == QStringLiteral("winrt")) @@ -2377,17 +2366,20 @@ void tst_QWidget::showMinimized() #ifdef Q_OS_WINRT QEXPECT_FAIL("", "Winrt does not support move and resize", Abort); #endif - QCOMPARE(plain.pos(), pos); + QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos))); plain.showNormal(); QVERIFY(!plain.isMinimized()); QVERIFY(plain.isVisible()); - QCOMPARE(plain.pos(), pos); + QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos))); plain.showMinimized(); QVERIFY(plain.isMinimized()); QVERIFY(plain.isVisible()); - QCOMPARE(plain.pos(), pos); + QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos))); plain.hide(); QVERIFY(plain.isMinimized()); @@ -2779,7 +2771,9 @@ void tst_QWidget::setGeometry() tlw.setWindowTitle(QLatin1String(QTest::currentTestFunction())); QWidget child(&tlw); - QRect tr(100,100,200,200); + const QPoint topLeft = QGuiApplication::primaryScreen()->availableGeometry().topLeft(); + const QSize initialSize = 2 * m_testWidgetSize; + QRect tr(topLeft + QPoint(100,100), initialSize); QRect cr(50,50,50,50); tlw.setGeometry(tr); child.setGeometry(cr); @@ -2790,8 +2784,7 @@ void tst_QWidget::setGeometry() QCOMPARE(child.geometry(), cr); tlw.setParent(nullptr, Qt::Window|Qt::FramelessWindowHint); - tr = QRect(0,0,100,100); - tr.moveTopLeft(QGuiApplication::primaryScreen()->availableGeometry().topLeft()); + tr = QRect(topLeft, initialSize / 2); tlw.setGeometry(tr); QCOMPARE(tlw.geometry(), tr); tlw.showNormal(); @@ -3263,7 +3256,8 @@ void tst_QWidget::saveRestoreGeometry() if (m_platform == QStringLiteral("winrt")) QEXPECT_FAIL("", "WinRT does not support move/resize", Abort); - QTRY_COMPARE(widget.pos(), position); + QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget.pos(), position))); QCOMPARE(widget.size(), size); savedGeometry = widget.saveGeometry(); } @@ -3291,10 +3285,12 @@ void tst_QWidget::saveRestoreGeometry() QVERIFY(QTest::qWaitForWindowExposed(&widget)); QApplication::processEvents(); - QTRY_COMPARE(widget.pos(), position); + QVERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget.pos(), position))); QCOMPARE(widget.size(), size); widget.show(); - QCOMPARE(widget.pos(), position); + QVERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget.pos(), position))); QCOMPARE(widget.size(), size); } @@ -3408,6 +3404,9 @@ void tst_QWidget::restoreVersion1Geometry() QFETCH(QSize, expectedSize); QFETCH(QRect, expectedNormalGeometry); + if (m_platform == QLatin1String("windows") && QGuiApplication::primaryScreen()->geometry().width() > 2000) + QSKIP("Skipping due to minimum decorated window size on Windows"); + // WindowActive is uninteresting for this test const Qt::WindowStates WindowStateMask = Qt::WindowFullScreen | Qt::WindowMaximized | Qt::WindowMinimized; @@ -4988,7 +4987,8 @@ void tst_QWidget::windowMoveResize() widget.showNormal(); QTest::qWait(10); - QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), rect.topLeft(), m_fuzz), + qPrintable(HighDpi::msgPointMismatch(widget.pos(), rect.topLeft()))); // Windows: Minimum size of decorated windows. const bool expectResizeFail = (!windowFlags && (rect.width() < 160 || rect.height() < 40)) && m_platform == QStringLiteral("windows"); From 68866b1a7bcade79e425f609fc1680203b89112e Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 31 May 2019 10:22:44 +0200 Subject: [PATCH 17/35] Fix QMAKE_EXTRA_COMPILER names in VS projects Use the whole value of 'name', not just the first element, and also replace variables like ${QMAKE_FILE_IN}. This fixes the file_copies feature (COPIES) for Visual Studio projects, because for every entry in COPIES an extra compiler is created with a name 'COPY ${QMAKE_FILE_IN}'. Before this patch the name and the generated file filter would be just 'COPY'. However, duplicate filters are being skipped by the VS project generator. All but the first COPIES entry was ignored. Fixes: QTBUG-76010 Change-Id: Icaa5d2cb8d88ae3ef8ce86220198bca1b9e673f5 Reviewed-by: Oliver Wolff --- qmake/generators/win32/msvc_vcproj.cpp | 28 +++++++++++++++++++------- qmake/generators/win32/msvc_vcproj.h | 2 ++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index be0b67a9e6..0115dc1313 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -1524,6 +1524,18 @@ void VcprojGenerator::initDistributionFiles() vcProject.DistributionFiles.Config = &(vcProject.Configuration); } +QString VcprojGenerator::extraCompilerName(const ProString &extraCompiler, + const QStringList &inputs, + const QStringList &outputs) +{ + QString name = project->values(ProKey(extraCompiler + ".name")).join(' '); + if (name.isEmpty()) + name = extraCompiler.toQString(); + else + name = replaceExtraCompilerVariables(name, inputs, outputs, NoShell); + return name; +} + void VcprojGenerator::initExtraCompilerOutputs() { ProStringList otherFilters; @@ -1541,13 +1553,16 @@ void VcprojGenerator::initExtraCompilerOutputs() << "YACCSOURCES"; const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { - ProString extracompilerName = project->first(ProKey(*it + ".name")); - if (extracompilerName.isEmpty()) - extracompilerName = (*it); + const ProStringList &inputVars = project->values(ProKey(*it + ".input")); + ProStringList inputFiles; + for (auto var : inputVars) + inputFiles.append(project->values(var.toKey())); + const ProStringList &outputs = project->values(ProKey(*it + ".output")); // Create an extra compiler filter and add the files VCFilter extraCompile; - extraCompile.Name = extracompilerName.toQString(); + extraCompile.Name = extraCompilerName(it->toQString(), inputFiles.toQStringList(), + outputs.toQStringList()); extraCompile.ParseFiles = _False; extraCompile.Filter = ""; extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it); @@ -1560,14 +1575,14 @@ void VcprojGenerator::initExtraCompilerOutputs() if (!outputVar.isEmpty() && otherFilters.contains(outputVar)) continue; - QString tmp_out = project->first(ProKey(*it + ".output")).toQString(); + QString tmp_out = project->first(outputs.first().toKey()).toQString(); if (project->values(ProKey(*it + ".CONFIG")).indexOf("combine") != -1) { // Combined output, only one file result extraCompile.addFile(Option::fixPathToTargetOS( replaceExtraCompilerVariables(tmp_out, QString(), QString(), NoShell), false)); } else { // One output file per input - const ProStringList &tmp_in = project->values(project->first(ProKey(*it + ".input")).toKey()); + const ProStringList &tmp_in = project->values(inputVars.first().toKey()); for (int i = 0; i < tmp_in.count(); ++i) { const QString &filename = tmp_in.at(i).toQString(); if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename)) @@ -1580,7 +1595,6 @@ void VcprojGenerator::initExtraCompilerOutputs() // build steps there. So, we turn it around and add it to the input files instead, // provided that the input file variable is not handled already (those in otherFilters // are handled, so we avoid them). - const ProStringList &inputVars = project->values(ProKey(*it + ".input")); for (const ProString &inputVar : inputVars) { if (!otherFilters.contains(inputVar)) { const ProStringList &tmp_in = project->values(inputVar.toKey()); diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h index 0b9770e962..e87eb733fc 100644 --- a/qmake/generators/win32/msvc_vcproj.h +++ b/qmake/generators/win32/msvc_vcproj.h @@ -73,6 +73,8 @@ protected: bool doDepends() const override { return false; } // Never necessary using Win32MakefileGenerator::replaceExtraCompilerVariables; QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor) override; + QString extraCompilerName(const ProString &extraCompiler, const QStringList &inputs, + const QStringList &outputs); bool supportsMetaBuild() override { return true; } bool supportsMergedBuilds() override { return true; } bool mergeBuildProject(MakefileGenerator *other) override; From 7029ecade96876d08af7d576e0b81417502acbaa Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Mon, 20 May 2019 11:37:27 +0200 Subject: [PATCH 18/35] cmake: correct version dependency for qt5_add_big_resources qt5_add_big_resources is only available if using CMake 3.9 and later. This amends cdccd0222bbed1954d5d7fe0da9d2308c202f3b1. Task-number: QTBUG-55680 Task-number: QTBUG-75806 Change-Id: Ibba7af6ee7edfb226368937d543b7ec5cc93eb16 Reviewed-by: Alexandru Croitor Reviewed-by: Kai Koehne --- src/corelib/Qt5CoreMacros.cmake | 5 +++++ src/corelib/doc/src/cmake-macros.qdoc | 2 ++ tests/auto/cmake/CMakeLists.txt | 7 ++++++- tests/auto/cmake/test_add_big_resource/CMakeLists.txt | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index 7ae5e4fd16..3a60b8e0d2 100644 --- a/src/corelib/Qt5CoreMacros.cmake +++ b/src/corelib/Qt5CoreMacros.cmake @@ -296,6 +296,9 @@ endfunction() # qt5_add_big_resources(outfiles inputfile ... ) function(QT5_ADD_BIG_RESOURCES outfiles ) + if (CMAKE_VERSION VERSION_LESS 3.9) + message(FATAL_ERROR, "qt5_add_big_resources requires CMake 3.9 or newer") + endif() set(options) set(oneValueArgs) @@ -326,6 +329,8 @@ function(QT5_ADD_BIG_RESOURCES outfiles ) set_target_properties(rcc_object_${outfilename} PROPERTIES AUTOMOC OFF) set_target_properties(rcc_object_${outfilename} PROPERTIES AUTOUIC OFF) add_dependencies(rcc_object_${outfilename} big_resources_${outfilename}) + # The modification of TARGET_OBJECTS needs the following change in cmake + # https://gitlab.kitware.com/cmake/cmake/commit/93c89bc75ceee599ba7c08b8fe1ac5104942054f add_custom_command(OUTPUT ${outfile} COMMAND ${Qt5Core_RCC_EXECUTABLE} ARGS ${rcc_options} --name ${outfilename} --pass 2 --temp $ --output ${outfile} ${infile} diff --git a/src/corelib/doc/src/cmake-macros.qdoc b/src/corelib/doc/src/cmake-macros.qdoc index 6140e8be44..7fb133020f 100644 --- a/src/corelib/doc/src/cmake-macros.qdoc +++ b/src/corelib/doc/src/cmake-macros.qdoc @@ -131,6 +131,8 @@ files (\c .o, \c .obj) files instead of C++ source code. This allows to embed bigger resources, where compiling to C++ sources and then to binaries would be too time consuming or memory intensive. +Note that this macro is only available if using \c{CMake} 3.9 or later. + \section1 Arguments You can set additional \c{OPTIONS} that should be added to the \c{rcc} calls. diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 51d0d2879e..5b10a74d3f 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -146,7 +146,12 @@ endif() expect_pass(test_interface_link_libraries) expect_pass(test_moc_macro_target) -expect_pass(test_add_big_resource) + +if (NOT CMAKE_VERSION VERSION_LESS 3.9) + # The modification of TARGET_OBJECTS needs the following change in cmake + # https://gitlab.kitware.com/cmake/cmake/commit/93c89bc75ceee599ba7c08b8fe1ac5104942054f + expect_pass(test_add_big_resource) +endif() if (NOT CMAKE_VERSION VERSION_LESS 3.8) # With earlier CMake versions, this test would simply run moc multiple times and lead to: diff --git a/tests/auto/cmake/test_add_big_resource/CMakeLists.txt b/tests/auto/cmake/test_add_big_resource/CMakeLists.txt index f928b11278..45ed2c79d5 100644 --- a/tests/auto/cmake/test_add_big_resource/CMakeLists.txt +++ b/tests/auto/cmake/test_add_big_resource/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.9) project(test_add_big_resource) From 60136b1a846ca5aedeb588edaa178927abb002ec Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 3 Jun 2019 14:39:07 +0200 Subject: [PATCH 19/35] Fix meta file replacements if matches are empty QMake code like rplc.match = QMAKE_PRL_INSTALL_REPLACE += rplc led to the generation of invalid sed calls in the Makefile. It is already actively checked for empty matches, but if *all* matches are empty, the sed call looks like sed foo > bar which is invalid. Task-number: QTBUG-75901 Change-Id: I173ed99826414dcf06253a15a247f7d067ee3977 Reviewed-by: Thiago Macieira --- qmake/generators/makefile.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index bfef31f17e..6edaf1f70e 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -3437,19 +3437,23 @@ QString MakefileGenerator::installMetaFile(const ProKey &replace_rule, const QSt || project->isActiveConfig("no_sed_meta_install")) { ret += "-$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst); } else { - ret += "-$(SED)"; + QString sedargs; const ProStringList &replace_rules = project->values(replace_rule); for (int r = 0; r < replace_rules.size(); ++r) { const ProString match = project->first(ProKey(replace_rules.at(r) + ".match")), replace = project->first(ProKey(replace_rules.at(r) + ".replace")); if (!match.isEmpty() /*&& match != replace*/) { - ret += " -e " + shellQuote("s," + match + "," + replace + ",g"); + sedargs += " -e " + shellQuote("s," + match + "," + replace + ",g"); if (isWindowsShell() && project->first(ProKey(replace_rules.at(r) + ".CONFIG")).contains("path")) - ret += " -e " + shellQuote("s," + windowsifyPath(match.toQString()) + sedargs += " -e " + shellQuote("s," + windowsifyPath(match.toQString()) + "," + windowsifyPath(replace.toQString()) + ",gi"); } } - ret += ' ' + escapeFilePath(src) + " > " + escapeFilePath(dst); + if (sedargs.isEmpty()) { + ret += "-$(INSTALL_FILE) " + escapeFilePath(src) + ' ' + escapeFilePath(dst); + } else { + ret += "-$(SED) " + sedargs + ' ' + escapeFilePath(src) + " > " + escapeFilePath(dst); + } } return ret; } From c64f8ca232cc1f2131282d9eb6279ef9b565be88 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 3 Jun 2019 14:52:49 +0200 Subject: [PATCH 20/35] Do not write 'Libs:' into .pc files if TEMPLATE is not 'lib' Especially for header modules we don't want a 'Libs:' entry in their .pc file. Task-number: QTBUG-75901 Change-Id: I39037d3132e39dd360532e1425f794ebec28e0bd Reviewed-by: Thiago Macieira --- qmake/generators/makefile.cpp | 72 ++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 6edaf1f70e..4a99a60892 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -3359,42 +3359,44 @@ MakefileGenerator::writePkgConfigFile() if (!version.isEmpty()) t << "Version: " << version << endl; - // libs - t << "Libs: "; - QString pkgConfiglibName; - if (target_mode == TARG_MAC_MODE && project->isActiveConfig("lib_bundle")) { - if (libDir != QLatin1String("/Library/Frameworks")) - t << "-F${libdir} "; - ProString bundle; - if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME")) - bundle = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME"); - else - bundle = project->first("TARGET"); - int suffix = bundle.lastIndexOf(".framework"); - if (suffix != -1) - bundle = bundle.left(suffix); - t << "-framework "; - pkgConfiglibName = bundle.toQString(); - } else { - if (!project->values("QMAKE_DEFAULT_LIBDIRS").contains(libDir)) - t << "-L${libdir} "; - pkgConfiglibName = "-l" + project->first("QMAKE_ORIG_TARGET"); - if (project->isActiveConfig("shared")) - pkgConfiglibName += project->first("TARGET_VERSION_EXT").toQString(); - } - t << shellQuote(pkgConfiglibName) << " \n"; + if (project->first("TEMPLATE") == "lib") { + // libs + t << "Libs: "; + QString pkgConfiglibName; + if (target_mode == TARG_MAC_MODE && project->isActiveConfig("lib_bundle")) { + if (libDir != QLatin1String("/Library/Frameworks")) + t << "-F${libdir} "; + ProString bundle; + if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME")) + bundle = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME"); + else + bundle = project->first("TARGET"); + int suffix = bundle.lastIndexOf(".framework"); + if (suffix != -1) + bundle = bundle.left(suffix); + t << "-framework "; + pkgConfiglibName = bundle.toQString(); + } else { + if (!project->values("QMAKE_DEFAULT_LIBDIRS").contains(libDir)) + t << "-L${libdir} "; + pkgConfiglibName = "-l" + project->first("QMAKE_ORIG_TARGET"); + if (project->isActiveConfig("shared")) + pkgConfiglibName += project->first("TARGET_VERSION_EXT").toQString(); + } + t << shellQuote(pkgConfiglibName) << " \n"; - if (project->isActiveConfig("staticlib")) { - ProStringList libs; - libs << "LIBS"; // FIXME: this should not be conditional on staticlib - libs << "LIBS_PRIVATE"; - libs << "QMAKE_LIBS"; // FIXME: this should not be conditional on staticlib - libs << "QMAKE_LIBS_PRIVATE"; - libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? - t << "Libs.private:"; - for (ProStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) - t << ' ' << fixLibFlags((*it).toKey()).join(' '); - t << endl; + if (project->isActiveConfig("staticlib")) { + ProStringList libs; + libs << "LIBS"; // FIXME: this should not be conditional on staticlib + libs << "LIBS_PRIVATE"; + libs << "QMAKE_LIBS"; // FIXME: this should not be conditional on staticlib + libs << "QMAKE_LIBS_PRIVATE"; + libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? + t << "Libs.private:"; + for (ProStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) + t << ' ' << fixLibFlags((*it).toKey()).join(' '); + t << endl; + } } // flags From 4da47d0fba04e5d50bf6b63e73bc0de986560f42 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 3 Jun 2019 14:59:16 +0200 Subject: [PATCH 21/35] Make sure .pc, .prl and .la files are created for header_only modules Those modules are TEMPLATE=aux, so they weren't triggering the file creation here. To make this work properly we have to: - check for TEMPLATE aux in the right places - add a dummy target to INSTALLS to actually trigger the creation - initialize PRL_TARGET for aux templates Fixes: QTBUG-75901 Started-by: Thiago Macieira Change-Id: Idce141629dd34287808bfffd159f92ac28c6c8b1 Reviewed-by: Thiago Macieira --- mkspecs/features/qt_module.prf | 5 +++++ qmake/generators/makefile.cpp | 3 ++- qmake/generators/unix/unixmake.cpp | 2 +- qmake/generators/unix/unixmake2.cpp | 10 +++++++--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 51b5bde67a..18060cd490 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -82,6 +82,11 @@ header_module { CONFIG += force_qt # Needed for the headers_clean tests. !lib_bundle: \ CONFIG += qt_no_install_library + + # Allow creation of .prl, .la and .pc files. + target.path = $$[QT_INSTALL_LIBS] + target.CONFIG += dummy_install + INSTALLS += target } else { TEMPLATE = lib } diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 4a99a60892..caaf6e71b6 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1120,7 +1120,8 @@ MakefileGenerator::writePrlFile() && project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty() && project->isActiveConfig("create_prl") && (project->first("TEMPLATE") == "lib" - || project->first("TEMPLATE") == "vclib") + || project->first("TEMPLATE") == "vclib" + || project->first("TEMPLATE") == "aux") && (!project->isActiveConfig("plugin") || project->isActiveConfig("static"))) { //write prl file QString local_prl = prlFileName(); QString prl = fileFixify(local_prl); diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 7f42fbe09e..b809bb6c19 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -726,7 +726,7 @@ UnixMakefileGenerator::defaultInstall(const QString &t) } } } - if(project->first("TEMPLATE") == "lib") { + if (isAux || project->first("TEMPLATE") == "lib") { QStringList types; types << "prl" << "libtool" << "pkgconfig"; for(int i = 0; i < types.size(); ++i) { diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 24215ae7b0..d9bcccf2e2 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -48,12 +48,15 @@ void UnixMakefileGenerator::writePrlFile(QTextStream &t) { MakefileGenerator::writePrlFile(t); + const ProString tmplt = project->first("TEMPLATE"); + if (tmplt != "lib" && tmplt != "aux") + return; // libtool support - if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib") { //write .la + if (project->isActiveConfig("create_libtool")) { writeLibtoolFile(); } // pkg-config support - if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib") + if (project->isActiveConfig("create_pc")) writePkgConfigFile(); } @@ -1199,7 +1202,8 @@ void UnixMakefileGenerator::init2() project->values("QMAKE_FRAMEWORK_VERSION").append(project->first("VER_MAJ")); if (project->first("TEMPLATE") == "aux") { - // nothing + project->values("PRL_TARGET") = + project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB")); } else if (!project->values("QMAKE_APP_FLAG").isEmpty()) { if(!project->isEmpty("QMAKE_BUNDLE")) { ProString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION"); From 9a47768b46f5e5eed407b70dfa9183fa1d21e242 Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Mon, 27 May 2019 14:27:49 +0200 Subject: [PATCH 22/35] macOS: Fix reported mouse event buttons Use m_buttons instead of currentlyPressedMouseButtons. The latter returns the state of devices combined with synthesized events at the moment, independent of which events have been delivered via the event stream, so this method is not suitable for tracking. Task-number: QTBUG-74057 Task-number: QTBUG-74121 Change-Id: Iabf99ada6c3d25a995c9ddf895059b70833a9051 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/cocoa/qnsview_mouse.mm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index d4419b42a4..a887cb841d 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -277,20 +277,19 @@ nativeDrag->setLastMouseEvent(theEvent, self); const auto modifiers = [QNSView convertKeyModifiers:theEvent.modifierFlags]; - const auto buttons = currentlyPressedMouseButtons(); auto button = cocoaButton2QtButton(theEvent); if (button == Qt::LeftButton && m_sendUpAsRightButton) button = Qt::RightButton; const auto eventType = cocoaEvent2QtMouseEvent(theEvent); if (eventType == QEvent::MouseMove) - qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << buttons; + qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons; else - qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << buttons; + qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << m_buttons; QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, - buttons, button, eventType, modifiers); + m_buttons, button, eventType, modifiers); } - (bool)handleMouseDownEvent:(NSEvent *)theEvent From 15d73a9f479e88af85944119e79d88ed26d4f346 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 14 May 2019 14:20:08 +0200 Subject: [PATCH 23/35] Qt Widgets: Make tests pass on High DPI screens and scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the comparison helpers to do fuzzy checking of geometries. Change-Id: I00f4403f3bca2e8a3996e938a85ba799e083058c Reviewed-by: Morten Johan Sørvig Reviewed-by: Richard Moe Gustavsen --- tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp | 5 ++++- tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp | 2 +- .../itemviews/qitemdelegate/tst_qitemdelegate.cpp | 11 ++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp index afe49368ae..c840dabc1a 100644 --- a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp +++ b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp @@ -26,6 +26,7 @@ ** ****************************************************************************/ +#include "../../../shared/highdpi.h" #include @@ -388,8 +389,10 @@ void tst_QDialog::toolDialogPosition() dialog.move(QPoint(100,100)); const QPoint beforeShowPosition = dialog.pos(); dialog.show(); + const int fuzz = int(dialog.devicePixelRatioF()); const QPoint afterShowPosition = dialog.pos(); - QCOMPARE(afterShowPosition, beforeShowPosition); + QVERIFY2(HighDpi::fuzzyCompare(afterShowPosition, beforeShowPosition, fuzz), + HighDpi::msgPointMismatch(afterShowPosition, beforeShowPosition).constData()); } class Dialog : public QDialog diff --git a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp index a5b8646d40..63f6e67a3e 100644 --- a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp +++ b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp @@ -2551,7 +2551,7 @@ void tst_QWizard::task183550_stretchFactor() page2->enableVerticalExpansion(); wizard.next(); QCOMPARE(wizard.currentPage(), static_cast(page2)); - QVERIFY(page2->treeWidgetHeight() > page2->treeWidgetSizeHintHeight()); + QVERIFY(page2->treeWidgetHeight() >= page2->treeWidgetSizeHintHeight()); wizard.back(); QCOMPARE(wizard.currentPage(), static_cast(page1)); diff --git a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp index aa11ed709f..961c8aa4ad 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp +++ b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp @@ -26,6 +26,7 @@ ** ****************************************************************************/ +#include "../../../shared/highdpi.h" #include @@ -51,6 +52,8 @@ #include #include +#include + #include Q_DECLARE_METATYPE(QAbstractItemDelegate::EndEditHint) @@ -223,8 +226,8 @@ private slots: void dateTextForRole_data(); void dateTextForRole(); -#ifdef QT_BUILD_INTERNAL private: +#ifdef QT_BUILD_INTERNAL struct RoleDelegate : public QItemDelegate { QString textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale) @@ -234,6 +237,8 @@ private: } }; #endif + + const int m_fuzz = int(QGuiApplication::primaryScreen()->devicePixelRatio()); }; @@ -286,8 +291,8 @@ void tst_QItemDelegate::textRectangle() QFont font; TestItemDelegate delegate; QRect result = delegate.textRectangle(0, rect, font, text); - - QCOMPARE(result, expected); + QVERIFY2(HighDpi::fuzzyCompare(result, expected, m_fuzz), + HighDpi::msgRectMismatch(result, expected).constData()); } void tst_QItemDelegate::sizeHint_data() From b53994de5f1b641ca2f6c79048339ff34fe14b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 29 May 2019 16:36:09 +0200 Subject: [PATCH 24/35] macOS: Use QMacNotificationObserver over manual notification handling This also fixes a bug where we were implicitly capturing this inside the block, which meant that we would crash if the theme was recreated. The capture is now tied to the lifetime of QCocoaTheme. Change-Id: I37df8e6c0b33bf41e76d66be3cf29576041a7546 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/cocoa/qcocoatheme.h | 3 +++ src/plugins/platforms/cocoa/qcocoatheme.mm | 6 ++--- src/plugins/styles/mac/qmacstyle_mac.mm | 28 +++++++++------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index c42fa7d2e8..63227ed6c1 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -45,6 +45,8 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver)); +#include + QT_BEGIN_NAMESPACE class QPalette; @@ -82,6 +84,7 @@ public: private: mutable QPalette *m_systemPalette; + QMacNotificationObserver m_systemColorObserver; mutable QHash m_palettes; mutable QHash m_fonts; QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index efe670abed..ba93560689 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -133,10 +133,10 @@ QCocoaTheme::QCocoaTheme() m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this]; #endif - [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification - object:nil queue:nil usingBlock:^(NSNotification *) { + m_systemColorObserver = QMacNotificationObserver(nil, + NSSystemColorsDidChangeNotification, [this] { handleSystemThemeChange(); - }]; + }); } QCocoaTheme::~QCocoaTheme() diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index ee5556ec9e..f88e3203bc 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -161,18 +161,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver); return self; } -- (void)scrollBarStyleDidChange:(NSNotification *)notification -{ - Q_UNUSED(notification); - - // purge destroyed scroll bars: - QMacStylePrivate::scrollBars.removeAll(QPointer()); - - QEvent event(QEvent::StyleChange); - for (const auto &o : QMacStylePrivate::scrollBars) - QCoreApplication::sendEvent(o, &event); -} - - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { @@ -2095,11 +2083,18 @@ QMacStyle::QMacStyle() Q_D(QMacStyle); QMacAutoReleasePool pool; + static QMacNotificationObserver scrollbarStyleObserver(nil, + NSPreferredScrollerStyleDidChangeNotification, []() { + // Purge destroyed scroll bars + QMacStylePrivate::scrollBars.removeAll(QPointer()); + + QEvent event(QEvent::StyleChange); + for (const auto &o : QMacStylePrivate::scrollBars) + QCoreApplication::sendEvent(o, &event); + }); + d->receiver = [[NotificationReceiver alloc] initWithPrivateStyle:d]; - [[NSNotificationCenter defaultCenter] addObserver:d->receiver - selector:@selector(scrollBarStyleDidChange:) - name:NSPreferredScrollerStyleDidChangeNotification - object:nil]; + #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) { [NSApplication.sharedApplication addObserver:d->receiver forKeyPath:@"effectiveAppearance" @@ -2113,7 +2108,6 @@ QMacStyle::~QMacStyle() Q_D(QMacStyle); QMacAutoReleasePool pool; - [[NSNotificationCenter defaultCenter] removeObserver:d->receiver]; #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) [NSApplication.sharedApplication removeObserver:d->receiver forKeyPath:@"effectiveAppearance"]; From 9d9b944b4468b2e312b02f66cb7dd1a0340332ac Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Tue, 4 Jun 2019 16:50:00 +0900 Subject: [PATCH 25/35] Fix configure comment in/for -device linux-rasp-pi3-vc4-g++ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name was renamed in 8e445f8434f1525bce5bd4ba4b561f379b5f2cf4 Change-Id: I5a74b65309cf5dc64621db281fad3a62a2f026b1 Reviewed-by: Jörg Bornemann --- mkspecs/devices/linux-rasp-pi3-vc4-g++/qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/devices/linux-rasp-pi3-vc4-g++/qmake.conf b/mkspecs/devices/linux-rasp-pi3-vc4-g++/qmake.conf index 75b6ad7db5..b4a4484594 100644 --- a/mkspecs/devices/linux-rasp-pi3-vc4-g++/qmake.conf +++ b/mkspecs/devices/linux-rasp-pi3-vc4-g++/qmake.conf @@ -20,7 +20,7 @@ # output check that "EGLFS GBM .......... yes" is present, otherwise # eglfs will not be functional. # -# ./configure -release -opengl es2 -device linux-rpi3-vc4-g++ \ +# ./configure -release -opengl es2 -device linux-rasp-pi3-vc4-g++ \ # -device-option CROSS_COMPILE=~/raspbian/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf- \ # -sysroot ~/raspbian/sysroot \ # -prefix /usr/local/qt5pi -extprefix ~/raspbian/qt5pi -hostprefix ~/raspbian/qt5 \ From 6f40331058071e628e83e74c7f2032e41b1a3f3d Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Mon, 27 May 2019 15:45:29 +0200 Subject: [PATCH 26/35] macOS: Fix QMouseEvent::button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cocoaButton2QtButton(NSEvent *event) did not handle NSEventTypeLeftMouseDragged, NSEventTypeRightMouseDragged, NSEventTypeOtherMouseDragged. Task-number: QTBUG-74763 Change-Id: I9f48230599f16400b49edbff392f712eb1fff782 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoahelpers.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 9c705616ba..d36a7f6d09 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -297,13 +297,12 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) */ Qt::MouseButton cocoaButton2QtButton(NSEvent *event) { - switch (event.type) { - case NSEventTypeMouseMoved: + if (cocoaEvent2QtMouseEvent(event) == QEvent::MouseMove) return Qt::NoButton; + switch (event.type) { case NSEventTypeRightMouseUp: case NSEventTypeRightMouseDown: - case NSEventTypeRightMouseDragged: return Qt::RightButton; default: From 8c7589d992a5615fa3a98f67d098d5a2fca579cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Wed, 29 May 2019 18:02:19 +0200 Subject: [PATCH 27/35] Do not strip off the fragment and query in the qfileselector This is needed for cases where we use e.g. "file:///test.html?query#Fragment". The fragment and query were already preserved for the qrc scheme. This fixes it for the file scheme. Change-Id: I5713e4a25372fdd55ac255b1c6228b4dea419244 Reviewed-by: Shawn Rutledge --- src/corelib/io/qfileselector.cpp | 11 +++++++++++ .../corelib/io/qfileselector/tst_qfileselector.cpp | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index ce06c8e00b..500b475d1d 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -228,7 +228,18 @@ QUrl QFileSelector::select(const QUrl &filePath) const QString selectedPath = d->select(equivalentPath); ret.setPath(selectedPath.remove(0, scheme.size())); } else { + // we need to store the original query and fragment, since toLocalFile() will strip it off + QString frag; + if (ret.hasFragment()) + frag = ret.fragment(); + QString query; + if (ret.hasQuery()) + query= ret.query(); ret = QUrl::fromLocalFile(d->select(ret.toLocalFile())); + if (!frag.isNull()) + ret.setFragment(frag); + if (!query.isNull()) + ret.setQuery(query); } return ret; } diff --git a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp index c9f1e3d9f6..11b1fdaeeb 100644 --- a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp +++ b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp @@ -205,15 +205,23 @@ void tst_QFileSelector::urlConvenience_data() QString test("/test");// '/' is here so dir string can also be selector string QString custom1("custom1"); + QString testWithQueryAndFragment("/test?query#Fragment"); QTest::newRow("qrc") << QUrl("qrc:///extras/test") << (QStringList() << custom1) << QUrl(QString("qrc:///extras/") + QLatin1Char(selectorIndicator) + custom1 + test); + QTest::newRow("qrc with query and fragment") << QUrl(QString::fromLatin1("qrc:///extras%1").arg(testWithQueryAndFragment)) << (QStringList() << custom1) + << QUrl(QString("qrc:///extras/") + QLatin1Char(selectorIndicator) + custom1 + testWithQueryAndFragment); QString fileBasePath = QFINDTESTDATA("extras/test"); QString fileSelectedPath = QFINDTESTDATA(QString("extras/") + QLatin1Char(selectorIndicator) + custom1 + QString("/test")); QTest::newRow("file") << QUrl::fromLocalFile(fileBasePath) << (QStringList() << custom1) << QUrl::fromLocalFile(fileSelectedPath); + // do not strip off the query and fragment + QString strUrlWithFragment = QString("file://") + testWithQueryAndFragment; + QTest::newRow("file with query and fragment") << QUrl(strUrlWithFragment) << (QStringList()) << QUrl(strUrlWithFragment); + strUrlWithFragment = QString("file:") + testWithQueryAndFragment; + QTest::newRow("file with query and fragment too") << QUrl(strUrlWithFragment) << (QStringList()) << QUrl(strUrlWithFragment); // http://qt-project.org/images/qtdn/sprites-combined-latest.png is chosen as a representative real world URL // But note that this test is checking that http urls are NOT selected so it shouldn't be checked From ff4ef79e0ddc1310262d2db60e6f9ba51df9dc6c Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 24 May 2019 14:20:43 +0200 Subject: [PATCH 28/35] Overhaul Q(Date|Time)+ documentation Various things were out of date, misdescribed or just plain wrong. Change-Id: I11b7bd419604067fce2577a42882ebf126629016 Reviewed-by: Paul Wicking --- src/corelib/tools/qdatetime.cpp | 191 +++++++++++++++++--------------- 1 file changed, 99 insertions(+), 92 deletions(-) diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 3cba786865..b0e443c3dc 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -326,19 +326,17 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) Q_DECL_ \brief The QDate class provides date functions. - A QDate object encodes a calendar date, i.e. year, month, and day numbers, - in the proleptic Gregorian calendar by default. It can read the current date - from the system clock. It provides functions for comparing dates, and for - manipulating dates. For example, it is possible to add and subtract days, - months, and years to dates. + A QDate object represents a particular date. This can be expressed as a + calendar date, i.e. year, month, and day numbers, in the proleptic Gregorian + calendar. A QDate object is typically created by giving the year, month, and day - numbers explicitly. Note that QDate interprets two digit years as presented, - i.e., as years 0 through 99, without adding any offset. A QDate can also be - constructed with the static function currentDate(), which creates a QDate - object containing the system clock's date. An explicit date can also be set - using setDate(). The fromString() function returns a QDate given a string - and a date format which is used to interpret the date within the string. + numbers explicitly. Note that QDate interprets year numbers less than 100 as + presented, i.e., as years 1 through 99, without adding any offset. The + static function currentDate() creates a QDate object containing the date + read from the system clock. An explicit date can also be set using + setDate(). The fromString() function returns a QDate given a string and a + date format which is used to interpret the date within the string. The year(), month(), and day() functions provide access to the year, month, and day numbers. Also, dayOfWeek() and dayOfYear() @@ -372,7 +370,7 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) Q_DECL_ every day in a contiguous range, with 24 November 4714 BCE in the Gregorian calendar being Julian Day 0 (1 January 4713 BCE in the Julian calendar). As well as being an efficient and accurate way of storing an absolute date, - it is suitable for converting a Date into other calendar systems such as + it is suitable for converting a date into other calendar systems such as Hebrew, Islamic or Chinese. The Julian Day number can be obtained using QDate::toJulianDay() and can be set using QDate::fromJulianDay(). @@ -1434,12 +1432,10 @@ bool QDate::isLeapYear(int y) Unlike QDateTime, QTime knows nothing about time zones or daylight-saving time (DST). - A QTime object is typically created either by giving the number - of hours, minutes, seconds, and milliseconds explicitly, or by - using the static function currentTime(), which creates a QTime - object that contains the system's local time. Note that the - accuracy depends on the accuracy of the underlying operating - system; not all systems provide 1-millisecond accuracy. + A QTime object is typically created either by giving the number of hours, + minutes, seconds, and milliseconds explicitly, or by using the static + function currentTime(), which creates a QTime object that represents the + system's local time. The hour(), minute(), second(), and msec() functions provide access to the number of hours, minutes, seconds, and milliseconds @@ -1899,6 +1895,12 @@ int QTime::msecsTo(const QTime &t) const Note that the accuracy depends on the accuracy of the underlying operating system; not all systems provide 1-millisecond accuracy. + + Furthermore, currentTime() only increases within each day; it shall drop by + 24 hours each time midnight passes; and, beside this, changes in it may not + correspond to elapsed time, if a daylight-saving transition intervenes. + + \sa QDateTime::currentDateTime(), QDateTime::curentDateTimeUtc() */ #if QT_CONFIG(datestring) @@ -3027,15 +3029,30 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT provides functions for comparing datetimes and for manipulating a datetime by adding a number of seconds, days, months, or years. - A QDateTime object is typically created either by giving a date - and time explicitly in the constructor, or by using the static - function currentDateTime() that returns a QDateTime object set - to the system clock's time. The date and time can be changed with - setDate() and setTime(). A datetime can also be set using the - setTime_t() function that takes a POSIX-standard "number of - seconds since 00:00:00 on January 1, 1970" value. The fromString() - function returns a QDateTime, given a string and a date format - used to interpret the date within the string. + QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local + time}, to \l{Qt::UTC}{UTC}, to a specified \l{{Qt::OffsetFromUTC}{offset + from UTC} or to a specified \l{{Qt::TimeZone}{time zone}, in conjunction + with the QTimeZone class. For example, a time zone of "Europe/Berlin" will + apply the daylight-saving rules as used in Germany since 1970. In contrast, + an offset from UTC of +3600 seconds is one hour ahead of UTC (usually + written in ISO standard notation as "UTC+01:00"), with no daylight-saving + offset or changes. When using either local time or a specified time zone, + time-zone transitions such as the starts and ends of daylight-saving time + (DST) are taken into account. The choice of system used to represent a + datetime is described as its "timespec". + + A QDateTime object is typically created either by giving a date and time + explicitly in the constructor, or by using a static function such as + currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed + with setDate() and setTime(). A datetime can also be set using the + setMSecsSinceEpoch() function that takes the time, in milliseconds, since + 00:00:00 on January 1, 1970. The fromString() function returns a QDateTime, + given a string and a date format used to interpret the date within the + string. + + QDateTime::currentDateTime() returns a QDateTime that expresses the current + time with respect to local time. QDateTime::currentDateTimeUtc() returns a + QDateTime that expresses the current time with respect to UTC. The date() and time() functions provide access to the date and time parts of the datetime. The same information is provided in @@ -3046,18 +3063,20 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT later. You can increment (or decrement) a datetime by a given number of - milliseconds using addMSecs(), seconds using addSecs(), or days - using addDays(). Similarly, you can use addMonths() and addYears(). - The daysTo() function returns the number of days between two datetimes, - secsTo() returns the number of seconds between two datetimes, and - msecsTo() returns the number of milliseconds between two datetimes. + milliseconds using addMSecs(), seconds using addSecs(), or days using + addDays(). Similarly, you can use addMonths() and addYears(). The daysTo() + function returns the number of days between two datetimes, secsTo() returns + the number of seconds between two datetimes, and msecsTo() returns the + number of milliseconds between two datetimes. These operations are aware of + daylight-saving time (DST) and other time-zone transitions, where + applicable. - QDateTime can store datetimes as \l{Qt::LocalTime}{local time} or - as \l{Qt::UTC}{UTC}. QDateTime::currentDateTime() returns a - QDateTime expressed as local time; use toUTC() to convert it to - UTC. You can also use timeSpec() to find out if a QDateTime - object stores a UTC time or a local time. Operations such as - addSecs() and secsTo() are aware of daylight-saving time (DST). + Use toTimeSpec() to express a datetime in local time or UTC, + toOffsetFromUtc() to express in terms of an offset from UTC, or toTimeZone() + to express it with respect to a general time zone. You can use timeSpec() to + find out what time-spec a QDateTime object stores its time relative to. When + that is Qt::TimeZone, you can use timeZone() to find out which zone it is + using. \note QDateTime does not account for leap seconds. @@ -3071,67 +3090,55 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT \section2 Range of Valid Dates - The range of valid values able to be stored in QDateTime is dependent on - the internal storage implementation. QDateTime is currently stored in a - qint64 as a serial msecs value encoding the date and time. This restricts - the date range to about +/- 292 million years, compared to the QDate range - of +/- 2 billion years. Care must be taken when creating a QDateTime with - extreme values that you do not overflow the storage. The exact range of - supported values varies depending on the Qt::TimeSpec and time zone. + The range of values that QDateTime can represent is dependent on the + internal storage implementation. QDateTime is currently stored in a qint64 + as a serial msecs value encoding the date and time. This restricts the date + range to about +/- 292 million years, compared to the QDate range of +/- 2 + billion years. Care must be taken when creating a QDateTime with extreme + values that you do not overflow the storage. The exact range of supported + values varies depending on the Qt::TimeSpec and time zone. - \section2 Use of System Timezone + \section2 Use of Timezones - QDateTime uses the system's time zone information to determine the - offset of local time from UTC. If the system is not configured - correctly or not up-to-date, QDateTime will give wrong results as - well. + QDateTime uses the system's time zone information to determine the current + local time zone and its offset from UTC. If the system is not configured + correctly or not up-to-date, QDateTime will give wrong results. + + QDateTime likewise uses system-provided information to determine the offsets + of other timezones from UTC. If this information is incomplete or out of + date, QDateTime will give wrong results. See the QTimeZone documentation for + more details. + + On modern Unix systems, this means QDateTime usually has accurate + information about historical transitions (including DST, see below) whenever + possible. On Windows, where the system doesn't support historical timezone + data, historical accuracy is not maintained with respect to timezone + transitions, notably including DST. \section2 Daylight-Saving Time (DST) - QDateTime takes into account the system's time zone information - when dealing with DST. On modern Unix systems, this means it - applies the correct historical DST data whenever possible. On - Windows, where the system doesn't support historical DST data, - historical accuracy is not maintained with respect to DST. + QDateTime takes into account transitions between Standard Time and + Daylight-Saving Time. For example, if the transition is at 2am and the clock + goes forward to 3am, then there is a "missing" hour from 02:00:00 to + 02:59:59.999 which QDateTime considers to be invalid. Any date arithmetic + performed will take this missing hour into account and return a valid + result. For example, adding one minute to 01:59:59 will get 03:00:00. - The range of valid dates taking DST into account is 1970-01-01 to - the present, and rules are in place for handling DST correctly - until 2037-12-31, but these could change. For dates falling - outside that range, QDateTime makes a \e{best guess} using the - rules for year 1970 or 2037, but we can't guarantee accuracy. This - means QDateTime doesn't take into account changes in a locale's - time zone before 1970, even if the system's time zone database - supports that information. + The range of valid dates taking DST into account is 1970-01-01 to the + present, and rules are in place for handling DST correctly until 2037-12-31, + but these could change. For dates falling outside that range, QDateTime + makes a \e{best guess} using the rules for year 1970 or 2037, but we can't + guarantee accuracy. This means QDateTime doesn't take into account changes + in a time zone before 1970, even if the system's time zone database provides + that information. - QDateTime takes into consideration the Standard Time to Daylight-Saving Time - transition. For example if the transition is at 2am and the clock goes - forward to 3am, then there is a "missing" hour from 02:00:00 to 02:59:59.999 - which QDateTime considers to be invalid. Any date maths performed - will take this missing hour into account and return a valid result. + \section2 Offsets From UTC - \section2 Offset From UTC - - A Qt::TimeSpec of Qt::OffsetFromUTC is also supported. This allows you - to define a QDateTime relative to UTC at a fixed offset of a given number - of seconds from UTC. For example, an offset of +3600 seconds is one hour - ahead of UTC and is usually written in ISO standard notation as - "UTC+01:00". Daylight-Saving Time never applies with this TimeSpec. - - There is no explicit size restriction to the offset seconds, but there is - an implicit limit imposed when using the toString() and fromString() - methods which use a format of [+|-]hh:mm, effectively limiting the range - to +/- 99 hours and 59 minutes and whole minutes only. Note that currently - no time zone lies outside the range of +/- 14 hours. - - \section2 Time Zone Support - - A Qt::TimeSpec of Qt::TimeZone is also supported in conjunction with the - QTimeZone class. This allows you to define a datetime in a named time zone - adhering to a consistent set of daylight-saving transition rules. For - example a time zone of "Europe/Berlin" will apply the daylight-saving - rules as used in Germany since 1970. Note that the transition rules - applied depend on the platform support. See the QTimeZone documentation - for more details. + There is no explicit size restriction on an offset from UTC, but there is an + implicit limit imposed when using the toString() and fromString() methods + which use a [+|-]hh:mm format, effectively limiting the range to +/- 99 + hours and 59 minutes and whole minutes only. Note that currently no time + zone lies outside the range of +/- 14 hours. \sa QDate, QTime, QDateTimeEdit, QTimeZone */ @@ -4254,7 +4261,7 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const Example: \snippet code/src_corelib_tools_qdatetime.cpp 16 - \sa timeSpec(), toTimeZone(), toUTC(), toLocalTime() + \sa timeSpec(), toTimeZone(), toOffsetFromUtc() */ QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const From 224a60989ed95e8b91ac88a12666af6e5a66e619 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 31 May 2019 15:06:14 +0200 Subject: [PATCH 29/35] Fix determination of source and build roots QMake searches a .qmake.conf file to determine the source root of the project, and a .qmake.cache to determine the build root. If a .qmake.conf exists but no .qmake.cache in the build directory is found, a build root would be set that is only valid if the build directory is at the same depth as the source directory. The invalid build root resulted in the creation of .qmake.cache files at "interesting" locations (e.g. high up in the directory tree), a potential cause for even more interesting build failures in the future. Fix this by splitting up the loop that determined build and source root. Both are now determined independently of each other. Fixes: QTBUG-76140 Change-Id: Ib5c922b87879fcf2f076298a69abcdbc4e8587b3 Reviewed-by: Alexandru Croitor --- qmake/library/qmakeevaluator.cpp | 39 +++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 432339d48e..09c1f80222 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -1128,35 +1128,48 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) } superdir = qdfi.path(); } - QString sdir = inDir; QString dir = m_outputDir; forever { - conffile = sdir + QLatin1String("/.qmake.conf"); - if (!m_vfs->exists(conffile, flags)) - conffile.clear(); cachefile = dir + QLatin1String("/.qmake.cache"); if (!m_vfs->exists(cachefile, flags)) cachefile.clear(); - if (!conffile.isEmpty() || !cachefile.isEmpty()) { - if (dir != sdir) - m_sourceRoot = sdir; + if (!cachefile.isEmpty()) { m_buildRoot = dir; break; } if (dir == superdir) goto no_cache; - QFileInfo qsdfi(sdir); QFileInfo qdfi(dir); - if (qsdfi.isRoot() || qdfi.isRoot()) - goto no_cache; - sdir = qsdfi.path(); + if (qdfi.isRoot()) { + cachefile.clear(); + break; + } dir = qdfi.path(); } + QString sdir = inDir; + forever { + conffile = sdir + QLatin1String("/.qmake.conf"); + if (!m_vfs->exists(conffile, flags)) + conffile.clear(); + if (!conffile.isEmpty()) { + if (sdir != m_buildRoot) + m_sourceRoot = sdir; + break; + } + QFileInfo qsdfi(sdir); + if (qsdfi.isRoot()) { + conffile.clear(); + break; + } + sdir = qsdfi.path(); + } } else { m_buildRoot = QFileInfo(cachefile).path(); } - m_conffile = QDir::cleanPath(conffile); - m_cachefile = QDir::cleanPath(cachefile); + if (!conffile.isEmpty()) + m_conffile = QDir::cleanPath(conffile); + if (!cachefile.isEmpty()) + m_cachefile = QDir::cleanPath(cachefile); } no_cache: From 761f88f8baa23fab70ed5e96d6344bef6e2aca94 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 3 Jun 2019 12:26:08 +0200 Subject: [PATCH 30/35] Diaglib: Improve formatting of DebugProxyStyle The class used the default debug operator for QObject, which outputs the object's address. This makes it hard to compare the log output. Make the existing QObject formatting helper from the EventFilter publicly usable by providing a helper with a stream operator. Change-Id: Ifab83e23cc792a5efe231fd9ae84e0439ab0d609 Reviewed-by: Shawn Rutledge Reviewed-by: Andy Shaw --- tests/manual/diaglib/debugproxystyle.cpp | 23 ++++++++++------- tests/manual/diaglib/eventfilter.cpp | 32 +++++++++++------------- tests/manual/diaglib/eventfilter.h | 13 ++++++++++ 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/tests/manual/diaglib/debugproxystyle.cpp b/tests/manual/diaglib/debugproxystyle.cpp index d4e62f5dd6..ed35af5962 100644 --- a/tests/manual/diaglib/debugproxystyle.cpp +++ b/tests/manual/diaglib/debugproxystyle.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "debugproxystyle.h" +#include "eventfilter.h" #include #include @@ -73,7 +74,7 @@ QDebug operator<<(QDebug debug, const QStyleOption *option) debug << ", state=" << option->state; #if QT_VERSION >= 0x050000 if (option->styleObject && !option->styleObject->isWidgetType()) - debug << ", styleObject=" << option->styleObject; + debug << ", styleObject=" << QtDiag::formatQObject(option->styleObject); #endif debug << ')'; return debug; @@ -97,19 +98,19 @@ DebugProxyStyle::DebugProxyStyle(QStyle *style) : QProxyStyle(style) void DebugProxyStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { - qDebug() << __FUNCTION__ << "element=" << element << option << widget; + qDebug() << __FUNCTION__ << "element=" << element << option << QtDiag::formatQObject(widget); QProxyStyle::drawPrimitive( element, option, painter, widget); } void DebugProxyStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { - qDebug() << __FUNCTION__ << "element=" << element << option << widget; + qDebug() << __FUNCTION__ << "element=" << element << option << QtDiag::formatQObject(widget); QProxyStyle::drawControl(element, option, painter, widget); } void DebugProxyStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { - qDebug() << __FUNCTION__ << "control=" << control << option << widget; + qDebug() << __FUNCTION__ << "control=" << control << option << QtDiag::formatQObject(widget); QProxyStyle::drawComplexControl(control, option, painter, widget); } @@ -122,21 +123,24 @@ void DebugProxyStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int a QSize DebugProxyStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const { const QSize result = QProxyStyle::sizeFromContents(type, option, size, widget); - qDebug() << __FUNCTION__ << size << "type=" << type << option << widget << "returns" << result; + qDebug() << __FUNCTION__ << size << "type=" << type << option + << QtDiag::formatQObject(widget) << "returns" << result; return result; } QRect DebugProxyStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const { const QRect result = QProxyStyle::subElementRect(element, option, widget); - qDebug() << __FUNCTION__ << "element=" << element << option << widget << "returns" << result; + qDebug() << __FUNCTION__ << "element=" << element << option + << QtDiag::formatQObject(widget) << "returns" << result; return result; } QRect DebugProxyStyle::subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, const QWidget *widget) const { const QRect result = QProxyStyle::subControlRect(cc, opt, sc, widget); - qDebug() << __FUNCTION__ << "cc=" << cc << "sc=" << sc << opt << widget << "returns" << result; + qDebug() << __FUNCTION__ << "cc=" << cc << "sc=" << sc << opt + << QtDiag::formatQObject(widget) << "returns" << result; return result; } @@ -159,7 +163,7 @@ int DebugProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QStyleHintReturn *returnData) const { const int result = QProxyStyle::styleHint(hint, option, widget, returnData); - qDebug() << __FUNCTION__ << hint << option << widget << "returnData=" + qDebug() << __FUNCTION__ << hint << option << QtDiag::formatQObject(widget) << "returnData=" << returnData << "returns" << result; return result; } @@ -167,7 +171,8 @@ int DebugProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const int DebugProxyStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const { const int result = QProxyStyle::pixelMetric(metric, option, widget); - qDebug() << __FUNCTION__ << "metric=" << metric << option << widget << "returns" << result; + qDebug() << __FUNCTION__ << "metric=" << metric << option + << QtDiag::formatQObject(widget) << "returns" << result; return result; } diff --git a/tests/manual/diaglib/eventfilter.cpp b/tests/manual/diaglib/eventfilter.cpp index 0646964b4a..39898f0781 100644 --- a/tests/manual/diaglib/eventfilter.cpp +++ b/tests/manual/diaglib/eventfilter.cpp @@ -154,7 +154,7 @@ static inline bool matchesType(const QObject *o, EventFilter::ObjectTypes types) return types & EventFilter::OtherType; } -static void formatObject(const QObject *o, QDebug debug) +void EventFilter::formatObject(const QObject *o, QDebug debug) { if (o) { debug << o->metaObject()->className(); @@ -166,32 +166,30 @@ static void formatObject(const QObject *o, QDebug debug) } } +QDebug operator<<(QDebug d, const formatQObject &fo) +{ + EventFilter::formatObject(fo.m_object, d); + return d; +} + static void formatApplicationState(QDebug debug) { #if defined(HAVE_APPLICATION) - if (const QWidget *mw = QApplication::activeModalWidget()) { - debug << "\n QApplication::activeModalWidget = "; - formatObject(mw, debug); - } - if (const QWidget *pw = QApplication::activePopupWidget()) { - debug << "\n QApplication::activePopupWidget = "; - formatObject(pw, debug); - } - debug << "\n QApplication::activeWindow = "; - formatObject(QApplication::activeWindow(), debug); + if (const QWidget *mw = QApplication::activeModalWidget()) + debug << "\n QApplication::activeModalWidget = " << formatQObject(mw); + if (const QWidget *pw = QApplication::activePopupWidget()) + debug << "\n QApplication::activePopupWidget = " << formatQObject(pw); + debug << "\n QApplication::activeWindow = " << formatQObject(QApplication::activeWindow()); #endif // HAVE_APPLICATION #if defined(HAVE_GUI_APPLICATION) if (const QWindow *mw = QGuiApplication::modalWindow()) { - debug << "\n QGuiApplication::modalWindow = "; - formatObject(mw, debug); + debug << "\n QGuiApplication::modalWindow = " << formatQObject(mw); } const QObject *focusObject = QGuiApplication::focusObject(); const QObject *focusWindow = QGuiApplication::focusWindow(); - debug << "\n QGuiApplication::focusObject = "; - formatObject(focusObject, debug); + debug << "\n QGuiApplication::focusObject = " << formatQObject(focusObject); if (focusWindow && focusWindow != focusObject) - debug << "\n QGuiApplication::focusWindow = "; - formatObject(focusWindow, debug); + debug << "\n QGuiApplication::focusWindow = " << formatQObject(focusWindow); #endif // HAVE_GUI_APPLICATION } diff --git a/tests/manual/diaglib/eventfilter.h b/tests/manual/diaglib/eventfilter.h index a65cd9f17d..1f57fbeb8b 100644 --- a/tests/manual/diaglib/eventfilter.h +++ b/tests/manual/diaglib/eventfilter.h @@ -33,6 +33,8 @@ #include #include +QT_FORWARD_DECLARE_CLASS(QDebug) + namespace QtDiag { // Event filter that can for example be installed on QApplication @@ -74,6 +76,8 @@ public: ObjectTypes objectTypes() const { return m_objectTypes; } void setObjectTypes(ObjectTypes objectTypes) { m_objectTypes = objectTypes; } + static void formatObject(const QObject *o, QDebug debug); + private: void init(EventCategories eventCategories); @@ -84,6 +88,15 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::EventCategories) Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::ObjectTypes) +struct formatQObject +{ + explicit formatQObject(const QObject *o) : m_object(o) {} + + const QObject *m_object; +}; + +QDebug operator<<(QDebug d, const formatQObject &fo); + } // namespace QtDiag #endif From 5f30fd64269822d4696ac071e17a39ae62a7b50f Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 5 Jun 2019 10:47:28 +0200 Subject: [PATCH 31/35] qmake: Cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix clang warnings that are disabled in the default build. Change-Id: I4e773a24884db94acdc6c295d3f66da07cd8a5bd Reviewed-by: Jörg Bornemann Reviewed-by: Albert Astals Cid --- qmake/generators/mac/pbuilder_pbx.cpp | 2 -- qmake/generators/makefile.cpp | 2 +- qmake/generators/makefiledeps.cpp | 2 +- qmake/generators/projectgenerator.h | 2 +- qmake/generators/win32/msvc_objectmodel.cpp | 1 + qmake/generators/win32/winmakefile.cpp | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 07832041a7..d5994639b3 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -518,7 +518,6 @@ bool ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) { ProStringList tmp; - bool did_preprocess = false; //HEADER const int pbVersion = pbuilderVersion(); @@ -736,7 +735,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) QFile mkf(mkfile); if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) { writingUnixMakefileGenerator = true; - did_preprocess = true; debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData()); QTextStream mkt(&mkf); writeHeader(mkt); diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index caaf6e71b6..bc59eaaea2 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -900,7 +900,7 @@ MakefileGenerator::processPrlFile(QString &file, bool baseOnly) bool MakefileGenerator::processPrlFileBase(QString &origFile, const QStringRef &origName, - const QStringRef &fixedBase, int slashOff) + const QStringRef &fixedBase, int /*slashOff*/) { return processPrlFileCore(origFile, origName, fixedBase + Option::prl_ext); } diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 1aab1987d2..1995cf63ba 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -815,7 +815,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file) break; } cpp_state = InCode; - // ... and fall through to handle buffer[x] as such. + Q_FALLTHROUGH(); // to handle buffer[x] as such. case InCode: // matching quotes (string literals and character literals) if (buffer[x] == '\'' || buffer[x] == '"') { diff --git a/qmake/generators/projectgenerator.h b/qmake/generators/projectgenerator.h index cbc9f371ab..02a331bd4f 100644 --- a/qmake/generators/projectgenerator.h +++ b/qmake/generators/projectgenerator.h @@ -43,7 +43,7 @@ protected: void init() override; bool writeMakefile(QTextStream &) override; - QString escapeFilePath(const QString &path) const override { Q_ASSERT(false); return QString(); } + QString escapeFilePath(const QString &) const override { Q_ASSERT(false); return QString(); } public: ProjectGenerator(); diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index f08554d0f5..68f62c8dda 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -1990,6 +1990,7 @@ bool VCMIDLTool::parseOption(const char* option) break; case 0x5eb7af2: // /header filename offset = 5; + Q_FALLTHROUGH(); case 0x0000358: // /h filename HeaderFileName = option + offset + 3; break; diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 208af1327f..cc612921f7 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -671,7 +671,7 @@ void Win32MakefileGenerator::writeObjectsPart(QTextStream &t) t << "OBJECTS = " << valList(escapeDependencyPaths(project->values("OBJECTS"))) << endl; } -void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &t) +void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &) { } From 4ebac33644d5db0b727680f1dacb18616daafe86 Mon Sep 17 00:00:00 2001 From: Damien Caliste Date: Mon, 20 May 2019 15:44:18 +0200 Subject: [PATCH 32/35] Detect system time zone from linked symlinks [ChangeLog][QtCore][QTimeZone] The IANA timezone database backend now properly follows symlinks even when they point to variable locations like /run or /var (useful when /etc is mounted read-only). Fixes: QTBUG-75936 Fixes: QTBUG-75527 Change-Id: If0dc2bfa20659e76c3bd062c75597a9ad01ad954 Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/corelib/tools/qtimezoneprivate_tz.cpp | 43 ++++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 7d85bc077d..57bc000af5 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -51,6 +51,12 @@ #include "qlocale_tools_p.h" #include +#include +#include +#if !defined(Q_OS_INTEGRITY) +#include // to use MAXSYMLINKS constant +#endif +#include // to use _SC_SYMLOOP_MAX constant QT_BEGIN_NAMESPACE @@ -1045,6 +1051,27 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs return last > m_tranTimes.cbegin() ? dataForTzTransition(*--last) : invalidData(); } +static long getSymloopMax() +{ +#if defined(SYMLOOP_MAX) + return SYMLOOP_MAX; // if defined, at runtime it can only be greater than this, so this is a safe bet +#else + errno = 0; + long result = sysconf(_SC_SYMLOOP_MAX); + if (result >= 0) + return result; + // result is -1, meaning either error or no limit + Q_ASSERT(!errno); // ... but it can't be an error, POSIX mandates _SC_SYMLOOP_MAX + + // therefore we can make up our own limit +# if defined(MAXSYMLINKS) + return MAXSYMLINKS; +# else + return 8; +# endif +#endif +} + // TODO Could cache the value and monitor the required files for any changes QByteArray QTzTimeZonePrivate::systemTimeZoneId() const { @@ -1062,12 +1089,18 @@ QByteArray QTzTimeZonePrivate::systemTimeZoneId() const // On most distros /etc/localtime is a symlink to a real file so extract name from the path if (ianaId.isEmpty()) { - const QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime")); - if (!path.isEmpty()) { + const QLatin1String zoneinfo("/zoneinfo/"); + QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime")); + int index = -1; + long iteration = getSymloopMax(); + // Symlink may point to another symlink etc. before being under zoneinfo/ + // We stop on the first path under /zoneinfo/, even if it is itself a + // symlink, like America/Montreal pointing to America/Toronto + while (iteration-- > 0 && !path.isEmpty() && (index = path.indexOf(zoneinfo)) < 0) + path = QFile::symLinkTarget(path); + if (index >= 0) { // /etc/localtime is a symlink to the current TZ file, so extract from path - int index = path.indexOf(QLatin1String("/zoneinfo/")); - if (index != -1) - ianaId = path.mid(index + 10).toUtf8(); + ianaId = path.mid(index + zoneinfo.size()).toUtf8(); } } From 804a18ef0ec4a054778e223c8cec6ee26dec3f76 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 15 May 2019 13:42:16 +0200 Subject: [PATCH 33/35] Document that QHeaderView rendered with themed style might ignore roles While this is generally true for widgets, QHeaderView's documentation about how appearance related data roles are respected can be misleading. Fixes: QTBUG-31804 Change-Id: I93c6562e59ecf771d938d282723169202ac15bc2 Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qheaderview.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 7bfa51337d..ed418f143c 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -146,7 +146,10 @@ static const int maxSizeSection = 1048575; // since section size is in a bitfiel Not all \l{Qt::}{ItemDataRole}s will have an effect on a QHeaderView. If you need to draw other roles, you can subclass QHeaderView and reimplement \l{QHeaderView::}{paintEvent()}. - QHeaderView respects the following item data roles: + QHeaderView respects the following item data roles, unless they are + in conflict with the style (which can happen for styles that follow + the desktop theme): + \l{Qt::}{TextAlignmentRole}, \l{Qt::}{DisplayRole}, \l{Qt::}{FontRole}, \l{Qt::}{DecorationRole}, \l{Qt::}{ForegroundRole}, and \l{Qt::}{BackgroundRole}. From d212c179db318a20d74592b02dd57b9bb1b668ce Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 23 May 2019 12:44:07 +0200 Subject: [PATCH 34/35] Change default of optimize-debug to off for developer-builds Backtraces with optimize-debug are less useful due to scoped variables no longer alive, and some gcc bugs with inlining. Fixes: QTBUG-75514 Change-Id: I6d62441047daee8f7079d1538dfc92015dd7ea63 Reviewed-by: Kai Koehne Reviewed-by: Jarek Kobus --- configure.json | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.json b/configure.json index 9fce6d039e..cffef79a6a 100644 --- a/configure.json +++ b/configure.json @@ -639,6 +639,7 @@ }, "optimize_debug": { "label": "Optimize debug build", + "autoDetect": "!features.developer-build", "condition": "!config.msvc && !config.clang && (features.debug || features.debug_and_release) && tests.optimize_debug", "output": [ "privateConfig" ] }, From 99636127d10f96d8313bc26030cabf9841381914 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 5 Jun 2019 12:42:14 +0200 Subject: [PATCH 35/35] Fix prefix_build check for top-level builds The checks whether we have a Qt prefix build were broken for top-level builds. Non-prefix top-level builds were incorrectly detected as prefix builds. For top-level non-prefix builds QT_HOST_DATA/QT_INSTALL_PREFIX becomes something like "~/my/build/dir/qtbase" but .qmake.cache (and .qmake.super) is/are created in "~/my/build/dir". This patch extends the prefix_build check by probing for the existence of .qmake.super, which only exists for top-level builds. Also, we add qt_prefix_build_check.prf as central place for determining whether we have a prefix build to make sure that qt_configure.prf and qt_build_config.prf use the same logic. Fixes: QTBUG-76185 Change-Id: I2b76fe26013496aaf2dac96ea711b06a69550a29 Reviewed-by: Oliver Wolff --- mkspecs/features/qt_build_config.prf | 4 +++- mkspecs/features/qt_configure.prf | 10 ++++++---- mkspecs/features/qt_prefix_build_check.prf | 21 +++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 mkspecs/features/qt_prefix_build_check.prf diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 0c6c10dded..8a7c9c28d3 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -37,8 +37,10 @@ intel_icl { QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR +load(qt_prefix_build_check) + # force_independent can be set externally. prefix_build not. -!exists($$[QT_HOST_DATA]/.qmake.cache): \ +qtIsPrefixBuild($$[QT_HOST_DATA]): \ CONFIG += prefix_build force_independent !build_pass:!isEmpty(_QMAKE_SUPER_CACHE_):force_independent { diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index 95e54d72c9..242544d41b 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -2502,17 +2502,19 @@ logn("Configure summary:") logn() qtConfPrintReport() +load(qt_prefix_build_check) + # final notes for the user logn() logn("Qt is now configured for building. Just run '$$QMAKE_MAKE_NAME'.") pfx = $$[QT_INSTALL_PREFIX] -exists($$pfx/.qmake.cache) { +qtIsPrefixBuild($$pfx) { + logn("Once everything is built, you must run '$$QMAKE_MAKE_NAME install'.") + logn("Qt will be installed into '$$system_path($$pfx)'.") +} else { logn("Once everything is built, Qt is installed.") logn("You should NOT run '$$QMAKE_MAKE_NAME install'.") logn("Note that this build cannot be deployed to other machines or devices.") -} else { - logn("Once everything is built, you must run '$$QMAKE_MAKE_NAME install'.") - logn("Qt will be installed into '$$system_path($$pfx)'.") } logn() logn("Prior to reconfiguration, make sure you remove any leftovers from") diff --git a/mkspecs/features/qt_prefix_build_check.prf b/mkspecs/features/qt_prefix_build_check.prf new file mode 100644 index 0000000000..3f98847de9 --- /dev/null +++ b/mkspecs/features/qt_prefix_build_check.prf @@ -0,0 +1,21 @@ +# +# W A R N I N G +# ------------- +# +# This file is not part of the Qt API. It exists purely as an +# implementation detail. It may change from version to version +# without notice, or even be removed. +# +# We mean it. +# + +defineTest(qtIsPrefixBuild) { + prefixdir = $$1 + # qtbase non-prefix build? + exists($$prefixdir/.qmake.cache): \ + return(false) + # top-level non-prefix build? + contains(prefixdir, .*/qtbase):exists($$dirname(prefixdir)/.qmake.super): \ + return(false) + return(true) +}