From 269c9fce3c3bde763b14d9805a10f7a57c45a11d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 20 Sep 2017 08:37:25 +0200 Subject: [PATCH 01/42] QGestureManager::filterEventThroughContexts(): Reduce debug output Log only relevant input events which are ignored. This reduces the output when COIN re-runs failing item view tests with full debug output enabled. Change-Id: Ifce9a56fdf313b7572baff9de8fb298b38e8b33a Reviewed-by: Simon Hausmann --- src/widgets/kernel/qgesturemanager.cpp | 37 ++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 2873703cb7..f27961b817 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -246,6 +246,36 @@ QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recogni return state; } +static bool logIgnoredEvent(QEvent::Type t) +{ + bool result = false; + switch (t) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchCancel: + case QEvent::TouchEnd: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::GraphicsSceneMouseDoubleClick: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMouseMove: + result = true; + break; + default: + break; + + } + return result; +} + bool QGestureManager::filterEventThroughContexts(const QMultiMap &contexts, QEvent *event) @@ -291,10 +321,13 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMaptype())) + qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event; } else { - qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer" + if (logIgnoredEvent(event->type())) { + qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer" << "ignored the event: " << state << event; + } } if (resultHint & QGestureRecognizer::ConsumeEventHint) { qCDebug(lcGestureManager) << "QGestureManager: we were asked to consume the event: " From 35bb55cd122bf1aba391aee157869dc68269c157 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 9 Aug 2017 11:32:07 +0200 Subject: [PATCH 02/42] Itemviews: Set the WA_InputMethodEnabled attribute correctly When focus is put back onto an itemview and the current item is editable then the WA_InputMethodEnabled attribute should be set. Likewise this should be set/unset when the current index changes too, depending on whether the index is editable or not. Change-Id: Iaea075e669efd21bdaa89a49c500c449272d098b Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qabstractitemview.cpp | 18 ++- .../tst_qabstractitemview.cpp | 106 ++++++++++++++++++ 2 files changed, 114 insertions(+), 10 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 88b6a30409..9870d9d49a 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -2230,7 +2230,7 @@ void QAbstractItemView::focusInEvent(QFocusEvent *event) QAbstractScrollArea::focusInEvent(event); const QItemSelectionModel* model = selectionModel(); - const bool currentIndexValid = currentIndex().isValid(); + bool currentIndexValid = currentIndex().isValid(); if (model && !d->currentIndexSet @@ -2238,19 +2238,16 @@ void QAbstractItemView::focusInEvent(QFocusEvent *event) bool autoScroll = d->autoScroll; d->autoScroll = false; QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index - if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) + if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) { selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + currentIndexValid = true; + } d->autoScroll = autoScroll; } - if (model && currentIndexValid) { - if (currentIndex().flags() != Qt::ItemIsEditable) - setAttribute(Qt::WA_InputMethodEnabled, false); - else - setAttribute(Qt::WA_InputMethodEnabled); - } - - if (!currentIndexValid) + if (model && currentIndexValid) + setAttribute(Qt::WA_InputMethodEnabled, (currentIndex().flags() & Qt::ItemIsEditable)); + else if (!currentIndexValid) setAttribute(Qt::WA_InputMethodEnabled, false); d->viewport->update(); @@ -3652,6 +3649,7 @@ void QAbstractItemView::currentChanged(const QModelIndex ¤t, const QModelI d->shouldScrollToCurrentOnShow = d->autoScroll; } } + setAttribute(Qt::WA_InputMethodEnabled, (current.isValid() && (current.flags() & Qt::ItemIsEditable))); } #ifndef QT_NO_DRAGANDDROP diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 83912fa2c3..2234b2b488 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -55,6 +55,8 @@ #include #include +Q_DECLARE_METATYPE(Qt::ItemFlags); + static inline void setFrameless(QWidget *w) { Qt::WindowFlags flags = w->windowFlags(); @@ -154,6 +156,8 @@ private slots: void testDialogAsEditor(); void QTBUG46785_mouseout_hover_state(); void testClearModelInClickedSignal(); + void inputMethodEnabled_data(); + void inputMethodEnabled(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -2291,5 +2295,107 @@ void tst_QAbstractItemView::testClearModelInClickedSignal() QCOMPARE(view.model(), nullptr); } +void tst_QAbstractItemView::inputMethodEnabled_data() +{ + QTest::addColumn("viewType"); + QTest::addColumn("itemFlags"); + QTest::addColumn("result"); + + QList widgets; + widgets << "QListView" << "QTreeView" << "QTableView"; + + for (const QByteArray &widget : qAsConst(widgets)) { + QTest::newRow(widget + ": no flags") << widget << Qt::ItemFlags(Qt::NoItemFlags) << false; + QTest::newRow(widget + ": checkable") << widget << Qt::ItemFlags(Qt::ItemIsUserCheckable) << false; + QTest::newRow(widget + ": selectable") << widget << Qt::ItemFlags(Qt::ItemIsSelectable) << false; + QTest::newRow(widget + ": enabled") << widget << Qt::ItemFlags(Qt::ItemIsEnabled) << false; + QTest::newRow(widget + ": selectable|enabled") + << widget << Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled) << false; + QTest::newRow(widget + ": editable|enabled") + << widget << Qt::ItemFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled) << true; + QTest::newRow(widget + ": editable|enabled|selectable") + << widget << Qt::ItemFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable) << true; + } +} + +void tst_QAbstractItemView::inputMethodEnabled() +{ + QFETCH(QByteArray, viewType); + QFETCH(Qt::ItemFlags, itemFlags); + QFETCH(bool, result); + + QScopedPointer view; + if (viewType == "QListView") + view.reset(new QListView()); + else if (viewType == "QTableView") + view.reset(new QTableView()); + else if (viewType == "QTreeView") + view.reset(new QTreeView()); + else + QVERIFY(0); + + centerOnScreen(view.data()); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view.data())); + + QStandardItemModel *model = new QStandardItemModel(view.data()); + QStandardItem *item = new QStandardItem("first item"); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + model->appendRow(item); + + QStandardItem *secondItem = new QStandardItem("test item"); + secondItem->setFlags(Qt::ItemFlags(itemFlags)); + model->appendRow(secondItem); + + view->setModel(model); + + // Check current changed + view->setCurrentIndex(model->index(0, 0)); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + view->setCurrentIndex(model->index(1, 0)); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); + view->setCurrentIndex(model->index(0, 0)); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + + // Check focus by switching the activation of the window to force a focus in + view->setCurrentIndex(model->index(1, 0)); + QApplication::setActiveWindow(0); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); + + view->setCurrentIndex(QModelIndex()); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + QApplication::setActiveWindow(0); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + QModelIndex index = model->index(1, 0); + QPoint p = view->visualRect(index).center(); + QTest::mouseClick(view->viewport(), Qt::LeftButton, Qt::NoModifier, p); + if (itemFlags & Qt::ItemIsEnabled) + QCOMPARE(view->currentIndex(), index); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); + + index = model->index(0, 0); + QApplication::setActiveWindow(0); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + p = view->visualRect(index).center(); + QTest::mouseClick(view->viewport(), Qt::LeftButton, Qt::NoModifier, p); + QCOMPARE(view->currentIndex(), index); + QVERIFY(!view->testAttribute(Qt::WA_InputMethodEnabled)); + + // There is a case when it goes to the first visible item so we + // make the flags of the first item match the ones we are testing + // to check the attribute correctly + QApplication::setActiveWindow(0); + view->setCurrentIndex(QModelIndex()); + view->reset(); + item->setFlags(Qt::ItemFlags(itemFlags)); + QApplication::setActiveWindow(view.data()); + QVERIFY(QTest::qWaitForWindowActive(view.data())); + QCOMPARE(view->testAttribute(Qt::WA_InputMethodEnabled), result); +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" From bbaedb9744810fe75d3254da5a51be6f49c23b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Wed, 13 Sep 2017 10:15:37 +0300 Subject: [PATCH 03/42] Blacklist flaky QItemDelegate tests in openSUSE 42.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-62967 Change-Id: I05cbf06f068701ee16b54e7052e02becc0c47702 Reviewed-by: Jędrzej Nowacki --- tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST index 0d658dcfb6..cd9d206f00 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST +++ b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST @@ -1,4 +1,2 @@ -[enterKey:plaintextedit tab] -opensuse-42.3 -[enterKey:plaintextedit backtab] -opensuse-42.3 +[enterKey] +opensuse-42.3 ci From 30a6557eb0922787b6879404e1c3bc2756b49702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Mon, 18 Sep 2017 15:49:25 +0300 Subject: [PATCH 04/42] Blacklist tst_QItemDelegate::testLineEditValidation in openSUSE 42.3 This autotest is blacklisted as it is deemed flaky. Task-number: QTBUG-63262 Change-Id: I216985e81d1c1cb3528fd8a005be48cad2a31ab7 Reviewed-by: Richard Moe Gustavsen --- tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST index cd9d206f00..fea108f3fd 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST +++ b/tests/auto/widgets/itemviews/qitemdelegate/BLACKLIST @@ -1,2 +1,4 @@ [enterKey] opensuse-42.3 ci +[testLineEditValidation] +opensuse-42.3 ci From e0c2d328b11ab893538393fad66ad61d22d823c6 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 20 Sep 2017 10:28:48 +0200 Subject: [PATCH 05/42] Fix #if-ery and accompanying comment The comment was back-to-front on the meaning it needed to address; and the #if-ery used a deprecated define, now changed to match what sanity-bot asked for. Change-Id: I0a971ab2e405e5908066da86964d67c8b852f114 Reviewed-by: Timur Pocheptsov --- .../kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp b/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp index 01566d795d..7fef603003 100644 --- a/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp +++ b/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp @@ -368,8 +368,8 @@ void tst_QNetworkProxyFactory::genericSystemProxy() QFETCH(QString, hostName); QFETCH(int, port); -// The generic system proxy is only available on the following platforms -#if (!defined Q_OS_WIN) && (!defined Q_OS_OSX) && !QT_CONFIG(libproxy) +// We can only use the generic system proxy where available: +#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) && !QT_CONFIG(libproxy) qputenv(envVar, url); const QList systemProxy = QNetworkProxyFactory::systemProxyForQuery(); QCOMPARE(systemProxy.size(), 1); From bcd81a9e2d59bb90567fbc8dec85fc51fd5befa0 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Wed, 6 Sep 2017 16:04:51 +0300 Subject: [PATCH 06/42] QAbstractSocket: remove disconnect timer Nowadays, there is no need for this additional timer. It was intended to forcibly disconnect the socket if an appropriate write notification has not arrived. After several fixes in the notification system this does not occur anymore, because otherwise we might have seen the hangs in the regular data transmitting. Also, it can break a delaying disconnect of the socket, if a write chunk is large enough. Task-number: QTBUG-63000 Change-Id: I9b9fd46af0209f9ce006a6d5ee5bfac9ea85482d Reviewed-by: Anthony Groyer Reviewed-by: Oswald Buddenhagen Reviewed-by: Edward Welbourne --- src/network/socket/qabstractsocket.cpp | 26 -------------------------- src/network/socket/qabstractsocket.h | 1 - src/network/socket/qabstractsocket_p.h | 2 -- 3 files changed, 29 deletions(-) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 7ecbf35489..92c18fb0f1 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -565,7 +565,6 @@ QAbstractSocketPrivate::QAbstractSocketPrivate() isBuffered(false), hasPendingData(false), connectTimer(0), - disconnectTimer(0), hostLookupId(-1), socketType(QAbstractSocket::UnknownSocketType), state(QAbstractSocket::UnconnectedState), @@ -604,8 +603,6 @@ void QAbstractSocketPrivate::resetSocketLayer() } if (connectTimer) connectTimer->stop(); - if (disconnectTimer) - disconnectTimer->stop(); } /*! \internal @@ -1222,15 +1219,6 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt() } } -void QAbstractSocketPrivate::_q_forceDisconnect() -{ - Q_Q(QAbstractSocket); - if (socketEngine && socketEngine->isValid() && state == QAbstractSocket::ClosingState) { - socketEngine->close(); - q->disconnectFromHost(); - } -} - /*! \internal Reads data from the socket layer into the read buffer. Returns @@ -2753,20 +2741,6 @@ void QAbstractSocket::disconnectFromHost() // Wait for pending data to be written. if (d->socketEngine && d->socketEngine->isValid() && (!d->allWriteBuffersEmpty() || d->socketEngine->bytesToWrite() > 0)) { - // hack: when we are waiting for the socket engine to write bytes (only - // possible when using Socks5 or HTTP socket engine), then close - // anyway after 2 seconds. This is to prevent a timeout on Mac, where we - // sometimes just did not get the write notifier from the underlying - // CFSocket and no progress was made. - if (d->allWriteBuffersEmpty() && d->socketEngine->bytesToWrite() > 0) { - if (!d->disconnectTimer) { - d->disconnectTimer = new QTimer(this); - connect(d->disconnectTimer, SIGNAL(timeout()), this, - SLOT(_q_forceDisconnect()), Qt::DirectConnection); - } - if (!d->disconnectTimer->isActive()) - d->disconnectTimer->start(2000); - } d->socketEngine->setWriteNotificationEnabled(true); #if defined(QABSTRACTSOCKET_DEBUG) diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index 73a8f11537..875609aa28 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -231,7 +231,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_startConnecting(const QHostInfo &)) Q_PRIVATE_SLOT(d_func(), void _q_abortConnectionAttempt()) Q_PRIVATE_SLOT(d_func(), void _q_testConnection()) - Q_PRIVATE_SLOT(d_func(), void _q_forceDisconnect()) }; diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 8a96cb9d48..5411133ea9 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -95,7 +95,6 @@ public: void _q_startConnecting(const QHostInfo &hostInfo); void _q_testConnection(); void _q_abortConnectionAttempt(); - void _q_forceDisconnect(); bool emittedReadyRead; bool emittedBytesWritten; @@ -148,7 +147,6 @@ public: bool hasPendingData; QTimer *connectTimer; - QTimer *disconnectTimer; int hostLookupId; From 92ca09147fc239762927595165f71a0d1ecff98f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 13 Sep 2017 19:20:46 -0700 Subject: [PATCH 07/42] Restore compatibility with pre-5.9 Keccak calculation Commit 12c5264d9add1826d543c36d893db77262195fc6 fixed the calculation of SHA-3 in QCryptographicHash: we were previously calculating Keccak. Unfortunately, turns out that replacing the algorithm wasn't the best idea: there are people who need to compare with the result obtained from a previous version of Qt and stored somewhere. This commit restores the enum values 7 through 10 to mean Keccak and moves SHA-3 to 12 through 15. The "Sha3_nnn" enums will switch between the two according to the QT_SHA3_KECCAK_COMPAT macro. [ChangeLog][Important Behavior Changes] This version of Qt restores compatibility with pre-5.9.0 calculation of QCryptographicHash algorithms that were labelled "Sha3_nnn": that is, applications compiled with old versions of Qt will continue using the Keccak algorithm. Applications recompiled with this version will use SHA-3, unless QT_SHA3_KECCAK_COMPAT is #define'd prior to #include . [ChangeLog][Binary Compatibility Note] This version of Qt changes the values assigned to enumerations QCryptographicHash::Sha3_nnn. Applications compiled with this version and using those enumerations will not work with Qt 5.9.0 and 5.9.1, unless QT_SHA3_KECCAK_COMPAT is defined. Task-number: QTBUG-62025 Discussed-at: http://lists.qt-project.org/pipermail/development/2017-September/030818.html Change-Id: I6e1fe42ae4b742a7b811fffd14e418fc04f096c3 Reviewed-by: Lars Knoll --- src/corelib/tools/qcryptographichash.cpp | 89 +++++++++++++++---- src/corelib/tools/qcryptographichash.h | 24 ++++- .../tools/qmessageauthenticationcode.cpp | 12 ++- .../corelib/tools/qcryptographichash/main.cpp | 8 ++ 4 files changed, 106 insertions(+), 27 deletions(-) diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index 5410adc737..a1b121f1ee 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -181,13 +181,18 @@ public: #endif }; #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 - void sha3Finish(int bitCount); + enum class Sha3Variant + { + Sha3, + Keccak + }; + void sha3Finish(int bitCount, Sha3Variant sha3Variant); #endif QByteArray result; }; #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -void QCryptographicHashPrivate::sha3Finish(int bitCount) +void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant) { /* FIPS 202 §6.1 defines SHA-3 in terms of calculating the Keccak function @@ -214,7 +219,15 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount) result.resize(bitCount / 8); SHA3Context copy = sha3Context; - sha3Update(©, reinterpret_cast(&sha3FinalSuffix), 2); + + switch (sha3Variant) { + case Sha3Variant::Sha3: + sha3Update(©, reinterpret_cast(&sha3FinalSuffix), 2); + break; + case Sha3Variant::Keccak: + break; + } + sha3Final(©, reinterpret_cast(result.data())); } #endif @@ -239,6 +252,12 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount) /*! \enum QCryptographicHash::Algorithm + \note In Qt versions before 5.9, when asked to generate a SHA3 hash sum, + QCryptographicHash actually calculated Keccak. If you need compatibility with + SHA-3 hashes produced by those versions of Qt, use the \c{Keccak_} + enumerators. Alternatively, if source compatibility is required, define the + macro \c QT_SHA3_KECCAK_COMPAT. + \value Md4 Generate an MD4 hash sum \value Md5 Generate an MD5 hash sum \value Sha1 Generate an SHA-1 hash sum @@ -250,6 +269,14 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount) \value Sha3_256 Generate an SHA3-256 hash sum. Introduced in Qt 5.1 \value Sha3_384 Generate an SHA3-384 hash sum. Introduced in Qt 5.1 \value Sha3_512 Generate an SHA3-512 hash sum. Introduced in Qt 5.1 + \value Keccak_224 Generate a Keccak-224 hash sum. Introduced in Qt 5.9.2 + \value Keccak_256 Generate a Keccak-256 hash sum. Introduced in Qt 5.9.2 + \value Keccak_384 Generate a Keccak-384 hash sum. Introduced in Qt 5.9.2 + \value Keccak_512 Generate a Keccak-512 hash sum. Introduced in Qt 5.9.2 + \omitvalue RealSha3_224 + \omitvalue RealSha3_256 + \omitvalue RealSha3_384 + \omitvalue RealSha3_512 */ /*! @@ -303,16 +330,20 @@ void QCryptographicHash::reset() case Sha512: SHA512Reset(&d->sha512Context); break; - case Sha3_224: + case RealSha3_224: + case Keccak_224: sha3Init(&d->sha3Context, 224); break; - case Sha3_256: + case RealSha3_256: + case Keccak_256: sha3Init(&d->sha3Context, 256); break; - case Sha3_384: + case RealSha3_384: + case Keccak_384: sha3Init(&d->sha3Context, 384); break; - case Sha3_512: + case RealSha3_512: + case Keccak_512: sha3Init(&d->sha3Context, 512); break; #endif @@ -354,16 +385,20 @@ void QCryptographicHash::addData(const char *data, int length) case Sha512: SHA512Input(&d->sha512Context, reinterpret_cast(data), length); break; - case Sha3_224: + case RealSha3_224: + case Keccak_224: sha3Update(&d->sha3Context, reinterpret_cast(data), length*8); break; - case Sha3_256: + case RealSha3_256: + case Keccak_256: sha3Update(&d->sha3Context, reinterpret_cast(data), length*8); break; - case Sha3_384: + case RealSha3_384: + case Keccak_384: sha3Update(&d->sha3Context, reinterpret_cast(data), length*8); break; - case Sha3_512: + case RealSha3_512: + case Keccak_512: sha3Update(&d->sha3Context, reinterpret_cast(data), length*8); break; #endif @@ -462,20 +497,36 @@ QByteArray QCryptographicHash::result() const SHA512Result(©, reinterpret_cast(d->result.data())); break; } - case Sha3_224: { - d->sha3Finish(224); + case RealSha3_224: { + d->sha3Finish(224, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } - case Sha3_256: { - d->sha3Finish(256); + case RealSha3_256: { + d->sha3Finish(256, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } - case Sha3_384: { - d->sha3Finish(384); + case RealSha3_384: { + d->sha3Finish(384, QCryptographicHashPrivate::Sha3Variant::Sha3); break; } - case Sha3_512: { - d->sha3Finish(512); + case RealSha3_512: { + d->sha3Finish(512, QCryptographicHashPrivate::Sha3Variant::Sha3); + break; + } + case Keccak_224: { + d->sha3Finish(224, QCryptographicHashPrivate::Sha3Variant::Keccak); + break; + } + case Keccak_256: { + d->sha3Finish(256, QCryptographicHashPrivate::Sha3Variant::Keccak); + break; + } + case Keccak_384: { + d->sha3Finish(384, QCryptographicHashPrivate::Sha3Variant::Keccak); + break; + } + case Keccak_512: { + d->sha3Finish(512, QCryptographicHashPrivate::Sha3Variant::Keccak); break; } #endif diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h index 0f17baa036..2f74d42405 100644 --- a/src/corelib/tools/qcryptographichash.h +++ b/src/corelib/tools/qcryptographichash.h @@ -65,10 +65,26 @@ public: Sha256, Sha384, Sha512, - Sha3_224, - Sha3_256, - Sha3_384, - Sha3_512 + + Keccak_224 = 7, + Keccak_256, + Keccak_384, + Keccak_512, + RealSha3_224 = 11, + RealSha3_256, + RealSha3_384, + RealSha3_512, +# ifndef QT_SHA3_KECCAK_COMPAT + Sha3_224 = RealSha3_224, + Sha3_256 = RealSha3_256, + Sha3_384 = RealSha3_384, + Sha3_512 = RealSha3_512 +# else + Sha3_224 = Keccak_224, + Sha3_256 = Keccak_256, + Sha3_384 = Keccak_384, + Sha3_512 = Keccak_512 +# endif #endif }; Q_ENUM(Algorithm) diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp index 9a84191452..40a1193622 100644 --- a/src/corelib/tools/qmessageauthenticationcode.cpp +++ b/src/corelib/tools/qmessageauthenticationcode.cpp @@ -99,13 +99,17 @@ static int qt_hash_block_size(QCryptographicHash::Algorithm method) return SHA384_Message_Block_Size; case QCryptographicHash::Sha512: return SHA512_Message_Block_Size; - case QCryptographicHash::Sha3_224: + case QCryptographicHash::RealSha3_224: + case QCryptographicHash::Keccak_224: return 144; - case QCryptographicHash::Sha3_256: + case QCryptographicHash::RealSha3_256: + case QCryptographicHash::Keccak_256: return 136; - case QCryptographicHash::Sha3_384: + case QCryptographicHash::RealSha3_384: + case QCryptographicHash::Keccak_384: return 104; - case QCryptographicHash::Sha3_512: + case QCryptographicHash::RealSha3_512: + case QCryptographicHash::Keccak_512: return 72; } return 0; diff --git a/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp b/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp index 5799b32b1c..507e2af708 100644 --- a/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp +++ b/tests/benchmarks/corelib/tools/qcryptographichash/main.cpp @@ -79,6 +79,14 @@ const char *algoname(int i) return "sha3_384-"; case QCryptographicHash::Sha3_512: return "sha3_512-"; + case QCryptographicHash::Keccak_224: + return "keccak_224-"; + case QCryptographicHash::Keccak_256: + return "keccak_256-"; + case QCryptographicHash::Keccak_384: + return "keccak_384-"; + case QCryptographicHash::Keccak_512: + return "keccak_512-"; } Q_UNREACHABLE(); return 0; From 72188001bbb408be22e5ad0fc90ca13b97c408f8 Mon Sep 17 00:00:00 2001 From: Iceyer Lee Date: Mon, 18 Sep 2017 11:46:51 +0800 Subject: [PATCH 08/42] Fix QGraphicsEffect draw error size in decimal scale factor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When QT_SCALE_FACTOR=1.5 or other decimal, QWidget draw QGraphicsEffect in error size. Use QPaintDevice::devicePixelRatioF instead QPaintDevice::devicePixelRatio() will fix it. Change-Id: I423e224d73b948ecdeca0e6b24c51f12a724a0ba Reviewed-by: Jesus Fernandez Reviewed-by: Morten Johan Sørvig --- src/widgets/kernel/qwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 53b240d4d2..9b6c3df828 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5924,7 +5924,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * pixmapOffset -= effectRect.topLeft(); - const qreal dpr = context->painter->device()->devicePixelRatio(); + const qreal dpr = context->painter->device()->devicePixelRatioF(); QPixmap pixmap(effectRect.size() * dpr); pixmap.setDevicePixelRatio(dpr); From 64ab7489b3d1ee9cc473d900e08f64d45412e1fc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 19 Sep 2017 10:29:05 -0700 Subject: [PATCH 09/42] XCB: also test for Xinerama's presence It's included unconditionally from qxcbconnection.cpp and qxcbscreen.h. Task-number: QTBUG-53537 Change-Id: I6e1fe42ae4b742a7b811fffd14e5d374155660f3 Reviewed-by: Gatis Paeglis --- src/gui/configure.json | 5 +++-- src/plugins/platforms/xcb/xcb_qpa_lib.pro | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/configure.json b/src/gui/configure.json index 6fdeefe14a..28c8034c75 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -433,6 +433,7 @@ "xcb/xfixes.h", "xcb/xcb_image.h", "xcb/xcb_keysyms.h", + "xcb/xinerama.h", "xcb/sync.h", "xcb/randr.h", "xcb/shm.h" @@ -450,8 +451,8 @@ }, "sources": [ { "type": "pkgConfig", - "args": "xcb xcb-shm xcb-sync xcb-xfixes xcb-randr xcb-image xcb-keysyms xcb-icccm xcb-shape" }, - "-lxcb -lxcb-shm -lxcb-sync -lxcb-xfixes -lxcb-randr -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-shape" + "args": "xcb xcb-shm xcb-sync xcb-xfixes xcb-xinerama xcb-randr xcb-image xcb-keysyms xcb-icccm xcb-shape" }, + "-lxcb -lxcb-shm -lxcb-sync -lxcb-xfixes -lxcb-xinerama -lxcb-randr -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-shape" ] }, "xcb_xlib": { diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 1c76b49650..284711075e 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -69,7 +69,6 @@ include(gl_integrations/gl_integrations.pri) !qtConfig(system-xcb) { QMAKE_USE += xcb-static xcb } else { - LIBS += -lxcb-xinerama ### there is no configure test for this! qtConfig(xkb): QMAKE_USE += xcb_xkb qtConfig(xcb-render): QMAKE_USE += xcb_render QMAKE_USE += xcb_syslibs From d25346417238b7dc0fb37359a9b56eff2908a5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= Date: Mon, 18 Sep 2017 22:33:55 +0200 Subject: [PATCH 10/42] Only call mysql_library_end() once when using MariaDB MariaDB allows only a single call to mysql_library_end(), all subsequent calls to mysql_library_init() or any other API call will fail. Since QMYSQLDriver calls mysql_library_end() function whenever the refcount drops to 0, this breaks applications that close and reopen database connections. This change registers call to mysql_library_init() via qAddPostRoutine() when compiled against MariaDB, so that we only call it once. Task-number: QTBUG-63108 Change-Id: I22c1f0c5b081216f12596a32748dca25cae919e9 Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/mysql/qsql_mysql.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index ee439fa33e..6e428fb878 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -1158,16 +1158,22 @@ static void qLibraryInit() } # endif // MYSQL_VERSION_ID #endif // Q_NO_MYSQL_EMBEDDED + +#ifdef MARIADB_BASE_VERSION + qAddPostRoutine(mysql_server_end); +#endif } static void qLibraryEnd() { -#ifndef Q_NO_MYSQL_EMBEDDED -# if MYSQL_VERSION_ID > 40000 -# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 - mysql_library_end(); -# else - mysql_server_end(); +#if !defined(MARIADB_BASE_VERSION) +# if !defined(Q_NO_MYSQL_EMBEDDED) +# if MYSQL_VERSION_ID > 40000 +# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 + mysql_library_end(); +# else + mysql_server_end(); +# endif # endif # endif #endif From c84b4ff4958bf3be513b3108d5a07d6565f95a98 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 29 Aug 2017 11:44:27 +0700 Subject: [PATCH 11/42] QTabWidget: Don't build expensive parts of the style option when hidden We end up calling setUpLayout() quite a few times and, in particular, every time we add a new tab. Even if the tab widget is hidden, we set the layout item margins to ensure that whatever layout will contain the tab widget can get the proper sizing. For all practical purposes, layout item margins don't depend on the contents itself, but are rather a simple constant returned by the style. This means that QStyleOptionTabWidgetFrame ::tabBarSize, among a few other properties, is not needed right away. This property in particular is quite expensive to compute because it requires measuring the text size of each tab. This can lead to a quadratic behavior: the size of each tab's text will be computed for each tab we add. Besides, text size computing has become a relatively expensive function in itself (see QTBUG-53151, for example). The current solution just uses a partially initialized style option object for the sole purpose of getting the tab widget's layout item margins from the style. The performance improvements detailed show the creation time for QTabWidget with the specified amount of tabs (times in ms): Tabs Before After ------------------- 1 6 5 5 6 6 10 8 6 50 57 17 100 178 21 200 673 33 Task-number: QTBUG-55126 Change-Id: I79505dbd0014f6ed185da28047d8b68f9462ba94 Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qtabwidget.cpp | 83 ++++++++++++++++++------------ 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp index c496d267b3..dc866a38cf 100644 --- a/src/widgets/widgets/qtabwidget.cpp +++ b/src/widgets/widgets/qtabwidget.cpp @@ -195,6 +195,8 @@ public: void _q_tabMoved(int from, int to); void init(); + void initBasicStyleOption(QStyleOptionTabWidgetFrame *option) const; + QTabBar *tabs; QStackedWidget *stack; QRect panelRect; @@ -257,6 +259,43 @@ bool QTabWidget::hasHeightForWidth() const return has; } +/*! + \internal + + Initialize only time inexpensive parts of the style option + for QTabWidget::setUpLayout()'s non-visible code path. +*/ +void QTabWidgetPrivate::initBasicStyleOption(QStyleOptionTabWidgetFrame *option) const +{ + Q_Q(const QTabWidget); + option->initFrom(q); + + if (q->documentMode()) + option->lineWidth = 0; + else + option->lineWidth = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, q); + + switch (pos) { + case QTabWidget::North: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedNorth + : QTabBar::TriangularNorth; + break; + case QTabWidget::South: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedSouth + : QTabBar::TriangularSouth; + break; + case QTabWidget::West: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedWest + : QTabBar::TriangularWest; + break; + case QTabWidget::East: + option->shape = shape == QTabWidget::Rounded ? QTabBar::RoundedEast + : QTabBar::TriangularEast; + break; + } + + option->tabBarRect = q->tabBar()->geometry(); +} /*! Initialize \a option with the values from this QTabWidget. This method is useful @@ -271,12 +310,7 @@ void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const return; Q_D(const QTabWidget); - option->initFrom(this); - - if (documentMode()) - option->lineWidth = 0; - else - option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); + d->initBasicStyleOption(option); int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0, this); QSize t(0, d->stack->frameWidth()); @@ -307,31 +341,10 @@ void QTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const option->leftCornerWidgetSize = QSize(0, 0); } - switch (d->pos) { - case QTabWidget::North: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedNorth - : QTabBar::TriangularNorth; - break; - case QTabWidget::South: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedSouth - : QTabBar::TriangularSouth; - break; - case QTabWidget::West: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedWest - : QTabBar::TriangularWest; - break; - case QTabWidget::East: - option->shape = d->shape == QTabWidget::Rounded ? QTabBar::RoundedEast - : QTabBar::TriangularEast; - break; - } - option->tabBarSize = t; - QRect tbRect = tabBar()->geometry(); QRect selectedTabRect = tabBar()->tabRect(tabBar()->currentIndex()); - option->tabBarRect = tbRect; - selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + tbRect.topLeft()); + selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + option->tabBarRect.topLeft()); option->selectedTabRect = selectedTabRect; } @@ -763,17 +776,19 @@ void QTabWidget::setUpLayout(bool onlyCheck) if (onlyCheck && !d->dirty) return; // nothing to do - QStyleOptionTabWidgetFrame option; - initStyleOption(&option); - - // this must be done immediately, because QWidgetItem relies on it (even if !isVisible()) - d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &option); - if (!isVisible()) { + // this must be done immediately, because QWidgetItem relies on it (even if !isVisible()) + QStyleOptionTabWidgetFrame basicOption; + d->initBasicStyleOption(&basicOption); + d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &basicOption); d->dirty = true; return; // we'll do it later } + QStyleOptionTabWidgetFrame option; + initStyleOption(&option); + d->setLayoutItemMargins(QStyle::SE_TabWidgetLayoutItem, &option); + QRect tabRect = style()->subElementRect(QStyle::SE_TabWidgetTabBar, &option, this); d->panelRect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this); QRect contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this); From d29f0bc65c1817bb73153cd546d7ab76e0768be0 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 25 Aug 2017 16:24:44 +0700 Subject: [PATCH 12/42] Avoid calling QCompleter::popup() internally QCompleter::popup() is used to lazily create the popup itself. However, we oftentimes call this function only to check if the popup is visible. Change-Id: I55531e1e6810c02a44f5f65124cf641b1a89de69 Reviewed-by: Gabriel de Dietrich Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/util/qcompleter_p.h | 3 +++ src/widgets/widgets/qcombobox.cpp | 15 ++++++++------- src/widgets/widgets/qwidgetlinecontrol.cpp | 11 +++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/widgets/util/qcompleter_p.h b/src/widgets/util/qcompleter_p.h index 40b08cc20a..5b89f9d8b5 100644 --- a/src/widgets/util/qcompleter_p.h +++ b/src/widgets/util/qcompleter_p.h @@ -101,6 +101,9 @@ public: void _q_autoResizePopup(); void _q_fileSystemModelDirectoryLoaded(const QString &path); void setCurrentIndex(QModelIndex, bool = true); + + static QCompleterPrivate *get(QCompleter *o) { return o->d_func(); } + static const QCompleterPrivate *get(const QCompleter *o) { return o->d_func(); } }; class QIndexMapper diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index b6bb31c391..54d33a7eea 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -71,6 +71,7 @@ #include #include #include +#include #include #if 0 /* Used to be included in Qt4 for Q_WS_MAC */ && QT_CONFIG(effetcts) && QT_CONFIG(style_mac) #include @@ -3140,13 +3141,13 @@ void QComboBox::keyPressEvent(QKeyEvent *e) Q_D(QComboBox); #if QT_CONFIG(completer) - if (d->lineEdit - && d->lineEdit->completer() - && d->lineEdit->completer()->popup() - && d->lineEdit->completer()->popup()->isVisible()) { - // provide same autocompletion support as line edit - d->lineEdit->event(e); - return; + if (const auto *cmpltr = completer()) { + const auto *popup = QCompleterPrivate::get(cmpltr)->popup; + if (popup && popup->isVisible()) { + // provide same autocompletion support as line edit + d->lineEdit->event(e); + return; + } } #endif diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 1b7a41d547..32944b3918 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -44,6 +44,7 @@ #endif #include "qclipboard.h" #include +#include #include #include #ifndef QT_NO_ACCESSIBILITY @@ -1484,7 +1485,8 @@ void QWidgetLineControl::complete(int key) } else { #ifndef QT_KEYPAD_NAVIGATION if (text.isEmpty()) { - m_completer->popup()->hide(); + if (auto *popup = QCompleterPrivate::get(m_completer)->popup) + popup->hide(); return; } #endif @@ -1630,10 +1632,10 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) #if QT_CONFIG(completer) if (m_completer) { QCompleter::CompletionMode completionMode = m_completer->completionMode(); + auto *popup = QCompleterPrivate::get(m_completer)->popup; if ((completionMode == QCompleter::PopupCompletion || completionMode == QCompleter::UnfilteredPopupCompletion) - && m_completer->popup() - && m_completer->popup()->isVisible()) { + && popup && popup->isVisible()) { // The following keys are forwarded by the completer to the widget // Ignoring the events lets the completer provide suitable default behavior switch (event->key()) { @@ -1648,7 +1650,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) if (!QApplication::keypadNavigationEnabled()) break; #endif - m_completer->popup()->hide(); // just hide. will end up propagating to parent + popup->hide(); // just hide. will end up propagating to parent + break; default: break; // normal key processing } From 4c025ca9c73bda320f0e7577a4fbd141c31d7c8c Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 28 Aug 2017 10:04:35 +0700 Subject: [PATCH 13/42] QCompleter: Send activated() signal only once on return key Due to the complex event forwarding logic between QCompleter, QComboBox, QLineEdit and QWidgetLineControl, in some cases the same single user return key press could result in duplicated activated() signals being emitted by QComboBox. The first one would be emitted because QLineEdit emitted editingFinished() as a result of QCompleter::eventFilter() having forwarded the return key press event to QComboBox. The second one, would happen right after, as QCompleter::eventFilter() would process the same event on behalf of its popup. (We recall that QCompleter is installed as its own popup event filter. That's also the case for the completer's widget, although the purpose there is limited to focus-out events). The current fix consists on skipping the emit as a result of QLineEdit::editingFinished() if the completer's popup is still active. For this to be accurate, it helps to test whether the completer's popup is visible, so we will not be hiding it in QWidgetLineControl::processKeyEvent() anymore. Indeed, we know that if the popup is visible, that means that processKeyEvent() was called after being forwarded by the completer's popup event filter. Furthermore, the popup will be hidden by its event filter shortly after it returns from said event forwarding call. Based on a patch by Alexey Chernov <4ernov@gmail.com>. Task-number: QTBUG-51858 Task-number: QTBUG-51889 Change-Id: I013f6c3000ae37b5b0ec20eaf5cf7746c9c903e3 Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qcombobox.cpp | 23 +++- src/widgets/widgets/qwidgetlinecontrol.cpp | 10 -- .../util/qcompleter/tst_qcompleter.cpp | 105 ++++++++++++++++++ 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 54d33a7eea..e0bc198d2e 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -1210,8 +1210,27 @@ Qt::MatchFlags QComboBoxPrivate::matchFlags() const void QComboBoxPrivate::_q_editingFinished() { Q_Q(QComboBox); - if (lineEdit && !lineEdit->text().isEmpty() && itemText(currentIndex) != lineEdit->text()) { - const int index = q_func()->findText(lineEdit->text(), matchFlags()); + if (!lineEdit) + return; + const auto leText = lineEdit->text(); + if (!leText.isEmpty() && itemText(currentIndex) != leText) { +#if QT_CONFIG(completer) + const auto *leCompleter = lineEdit->completer(); + const auto *popup = leCompleter ? QCompleterPrivate::get(leCompleter)->popup : nullptr; + if (popup && popup->isVisible()) { + // QLineEdit::editingFinished() will be emitted before the code flow returns + // to QCompleter::eventFilter(), where QCompleter::activated() may be emitted. + // We know that the completer popup will still be visible at this point, and + // that any selection should be valid. + const QItemSelectionModel *selModel = popup->selectionModel(); + const QModelIndex curIndex = popup->currentIndex(); + const bool completerIsActive = selModel && selModel->selectedIndexes().contains(curIndex); + + if (completerIsActive) + return; + } +#endif + const int index = q_func()->findText(leText, matchFlags()); if (index != -1) { q->setCurrentIndex(index); emitActivated(currentIndex); diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 32944b3918..4f4a6f70b5 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -1642,16 +1642,6 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) case Qt::Key_Escape: event->ignore(); return; - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_F4: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Select: - if (!QApplication::keypadNavigationEnabled()) - break; -#endif - popup->hide(); // just hide. will end up propagating to parent - break; default: break; // normal key processing } diff --git a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp index f8095badb8..3818b83584 100644 --- a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp @@ -143,6 +143,8 @@ private slots: void task253125_lineEditCompletion(); void task247560_keyboardNavigation(); void QTBUG_14292_filesystem(); + void QTBUG_52028_tabAutoCompletes(); + void QTBUG_51889_activatedSentTwice(); private: void filter(bool assync = false); @@ -1742,5 +1744,108 @@ void tst_QCompleter::QTBUG_14292_filesystem() QVERIFY(!comp.popup()->isVisible()); } +void tst_QCompleter::QTBUG_52028_tabAutoCompletes() +{ + QStringList words; + words << "foobar1" << "foobar2" << "hux"; + + QWidget w; + w.setLayout(new QVBoxLayout); + + QComboBox cbox; + cbox.setEditable(true); + cbox.setInsertPolicy(QComboBox::NoInsert); + cbox.addItems(words); + + cbox.completer()->setCaseSensitivity(Qt::CaseInsensitive); + cbox.completer()->setCompletionMode(QCompleter::PopupCompletion); + + w.layout()->addWidget(&cbox); + + // Adding a line edit is a good reason for tab to do something unrelated + QLineEdit le; + w.layout()->addWidget(&le); + + const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200); + w.move(pos); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QSignalSpy activatedSpy(&cbox, QOverload::of(&QComboBox::activated)); + + // Tab key will complete but not activate + cbox.lineEdit()->clear(); + QTest::keyClick(&cbox, Qt::Key_H); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Tab); + QCOMPARE(cbox.completer()->currentCompletion(), QLatin1String("hux")); + QCOMPARE(activatedSpy.count(), 0); + QEXPECT_FAIL("", "QTBUG-52028 will not be fixed today.", Abort); + QCOMPARE(cbox.currentText(), QLatin1String("hux")); + QCOMPARE(activatedSpy.count(), 0); + QVERIFY(!le.hasFocus()); +} + +void tst_QCompleter::QTBUG_51889_activatedSentTwice() +{ + QStringList words; + words << "foobar1" << "foobar2" << "bar" <<"hux"; + + QWidget w; + w.setLayout(new QVBoxLayout); + + QComboBox cbox; + setFrameless(&cbox); + cbox.setEditable(true); + cbox.setInsertPolicy(QComboBox::NoInsert); + cbox.addItems(words); + + cbox.completer()->setCaseSensitivity(Qt::CaseInsensitive); + cbox.completer()->setCompletionMode(QCompleter::PopupCompletion); + + w.layout()->addWidget(&cbox); + + QLineEdit le; + w.layout()->addWidget(&le); + + const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200); + w.move(pos); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QSignalSpy activatedSpy(&cbox, QOverload::of(&QComboBox::activated)); + + // Navigate + enter activates only once (first item) + cbox.lineEdit()->clear(); + QTest::keyClick(&cbox, Qt::Key_F); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Down); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Return); + QTRY_COMPARE(activatedSpy.count(), 1); + + // Navigate + enter activates only once (non-first item) + cbox.lineEdit()->clear(); + activatedSpy.clear(); + QTest::keyClick(&cbox, Qt::Key_H); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Down); + QTest::keyClick(cbox.completer()->popup(), Qt::Key_Return); + QTRY_COMPARE(activatedSpy.count(), 1); + + // Full text + enter activates only once + cbox.lineEdit()->clear(); + activatedSpy.clear(); + QTest::keyClicks(&cbox, "foobar1"); + QVERIFY(cbox.completer()->popup()); + QTRY_VERIFY(cbox.completer()->popup()->isVisible()); + QTest::keyClick(&cbox, Qt::Key_Return); + QTRY_COMPARE(activatedSpy.count(), 1); +} + QTEST_MAIN(tst_QCompleter) #include "tst_qcompleter.moc" From 12a382e3bc75192a11145ef5cf29ef1baf377dc9 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 13 Sep 2017 12:46:44 +0200 Subject: [PATCH 14/42] Fix saving QImage with longer than necessary bytes-per-line We should only copy the minimum bytes-per-line when saving an image. Task-number: QTBUG-30515 Change-Id: Idd34a389cf88210c3f127599ccf54d27d3ec9a06 Reviewed-by: Eirik Aavitsland --- src/gui/image/qbmphandler.cpp | 65 +++++++++++++++-------------------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 4350a5c192..703c5c0f31 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -562,27 +562,12 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, qint64 offset, } // this is also used in qmime_win.cpp -bool qt_write_dib(QDataStream &s, QImage image) +bool qt_write_dib(QDataStream &s, const QImage &image, int bpl, int bpl_bmp, int nbits) { - int nbits; - int bpl_bmp; - int bpl = image.bytesPerLine(); - QIODevice* d = s.device(); if (!d->isWritable()) return false; - if (image.depth() == 8 && image.colorCount() <= 16) { - bpl_bmp = (((bpl+1)/2+3)/4)*4; - nbits = 4; - } else if (image.depth() == 32) { - bpl_bmp = ((image.width()*24+31)/32)*4; - nbits = 24; - } else { - bpl_bmp = bpl; - nbits = image.depth(); - } - BMP_INFOHDR bi; bi.biSize = BMP_WIN; // build info header bi.biWidth = image.width(); @@ -617,9 +602,6 @@ bool qt_write_dib(QDataStream &s, QImage image) delete [] color_table; } - if (image.format() == QImage::Format_MonoLSB) - image = image.convertToFormat(QImage::Format_Mono); - int y; if (nbits == 1 || nbits == 8) { // direct output @@ -769,21 +751,17 @@ bool QBmpHandler::read(QImage *image) bool QBmpHandler::write(const QImage &img) { - if (m_format == DibFormat) { - QDataStream dibStream(device()); - dibStream.setByteOrder(QDataStream::LittleEndian); // Intel byte order - return qt_write_dib(dibStream, img); - } - QImage image; switch (img.format()) { case QImage::Format_Mono: - case QImage::Format_MonoLSB: case QImage::Format_Indexed8: case QImage::Format_RGB32: case QImage::Format_ARGB32: image = img; break; + case QImage::Format_MonoLSB: + image = img.convertToFormat(QImage::Format_Mono); + break; case QImage::Format_Alpha8: case QImage::Format_Grayscale8: image = img.convertToFormat(QImage::Format_Indexed8); @@ -796,20 +774,31 @@ bool QBmpHandler::write(const QImage &img) break; } + int nbits; + int bpl_bmp; + // Calculate a minimum bytes-per-line instead of using whatever value this QImage is using internally. + int bpl = ((image.width() * image.depth() + 31) >> 5) << 2; + + if (image.depth() == 8 && image.colorCount() <= 16) { + bpl_bmp = (((bpl+1)/2+3)/4)*4; + nbits = 4; + } else if (image.depth() == 32) { + bpl_bmp = ((image.width()*24+31)/32)*4; + nbits = 24; + } else { + bpl_bmp = bpl; + nbits = image.depth(); + } + + if (m_format == DibFormat) { + QDataStream dibStream(device()); + dibStream.setByteOrder(QDataStream::LittleEndian); // Intel byte order + return qt_write_dib(dibStream, img, bpl, bpl_bmp, nbits); + } + QIODevice *d = device(); QDataStream s(d); BMP_FILEHDR bf; - int bpl_bmp; - int bpl = image.bytesPerLine(); - - // Code partially repeated in qt_write_dib - if (image.depth() == 8 && image.colorCount() <= 16) { - bpl_bmp = (((bpl+1)/2+3)/4)*4; - } else if (image.depth() == 32) { - bpl_bmp = ((image.width()*24+31)/32)*4; - } else { - bpl_bmp = bpl; - } // Intel byte order s.setByteOrder(QDataStream::LittleEndian); @@ -825,7 +814,7 @@ bool QBmpHandler::write(const QImage &img) s << bf; // write image - return qt_write_dib(s, image); + return qt_write_dib(s, image, bpl, bpl_bmp, nbits); } bool QBmpHandler::supportsOption(ImageOption option) const From b0ffb332f2aa2ffc0b752c2ad740fbb6a69e0167 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Fri, 22 Sep 2017 13:19:36 -0700 Subject: [PATCH 15/42] Add missing math.h include (for sqrt function) Change-Id: Ia9cee8a941e31d71d3df6094b21d20a26f1b46f1 Reviewed-by: Thiago Macieira --- src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index 11f7311bb7..5d839cced7 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -55,6 +55,8 @@ #include #endif +#include + #if QT_CONFIG(mtdev) extern "C" { #include From 370f8ecaa9c9b3a968119e8fb735c3a35c92a0cc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 15 Sep 2017 14:15:41 -0700 Subject: [PATCH 16/42] Fix parsing of tzfile(5) files in QTimeZonePrivate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The leap second record sizes were not properly taken into account. The comments in the code were right, but not the code itself. Fortunately, on most Linux systems the leap seconds are not stored in the tzfiles, so we never ran into a parsing issue. Task-number: QTBUG-63205 Change-Id: I6e1fe42ae4b742a7b811fffd14e4a57f5d142f97 Reviewed-by: Maximilian Baumgartner Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/tools/qtimezoneprivate_tz.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 1714c9802f..4fdc2e36ac 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -277,8 +277,9 @@ static void parseTzLeapSeconds(QDataStream &ds, int tzh_leapcnt, bool longTran) { // Parse tzh_leapcnt x pairs of leap seconds // We don't use leap seconds, so only read and don't store - qint64 val; + qint32 val; if (longTran) { + // v2 file format, each entry is 12 bytes long qint64 time; for (int i = 0; i < tzh_leapcnt && ds.status() == QDataStream::Ok; ++i) { // Parse Leap Occurrence Time, 8 bytes @@ -288,6 +289,7 @@ static void parseTzLeapSeconds(QDataStream &ds, int tzh_leapcnt, bool longTran) ds >> val; } } else { + // v0 file format, each entry is 8 bytes long for (int i = 0; i < tzh_leapcnt && ds.status() == QDataStream::Ok; ++i) { // Parse Leap Occurrence Time, 4 bytes ds >> val; From 32ca19b2c5fbd515cdb84ebf379cb5b43e3570cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Tue, 12 Sep 2017 09:20:19 +0100 Subject: [PATCH 17/42] Fix typo in debug statement: QPlatformScren -> QPlatformScreen Change-Id: Ibf5046ff88cbad1f03966f39f62183b0bd750221 Reviewed-by: Laszlo Agocs --- src/platformsupport/kmsconvenience/qkmsdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index 669abab331..a8eefe65ed 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -489,7 +489,7 @@ void QKmsDevice::createScreens() } else { virtualPos = orderedScreen.vinfo.virtualPos; } - qCDebug(qLcKmsDebug) << "Adding QPlatformScren" << s << "(" << s->name() << ")" + qCDebug(qLcKmsDebug) << "Adding QPlatformScreen" << s << "(" << s->name() << ")" << "to QPA with geometry" << s->geometry() << "and isPrimary=" << orderedScreen.vinfo.isPrimary; // The order in qguiapp's screens list will match the order set by From 8d20fa11a50cbc7f2a9a5a282dcfc0b59f0fc092 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Sun, 24 Sep 2017 14:50:53 -0700 Subject: [PATCH 18/42] Fix namespaced build on macOS Change-Id: I6c570b668fd3a182991ba79cb12ec47d4db8a541 Reviewed-by: Thiago Macieira --- src/network/access/qnetworkaccessmanager.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 92b7fcbe11..848761c4a7 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -75,6 +75,12 @@ #include +#if defined(Q_OS_MACOS) +#include +#include +#include +#endif + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) @@ -87,11 +93,6 @@ Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend) #endif #if defined(Q_OS_MACX) - -#include -#include -#include - bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password) { OSStatus err; From 4dcd9145e74dfb8c59016cf0011987cdeb6b3576 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 23 Sep 2017 09:37:24 +0200 Subject: [PATCH 19/42] moc: don't use const_cast in qt_metacast generated code qt_metacast is not const so there is no need to use const_cast. This fixes a warning in generated code. Task-number: QTBUG-63352 Change-Id: I0c37442ac268a654316bc0e7e04f77fb51cae019 Reviewed-by: Thiago Macieira --- src/tools/moc/generator.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index c4184929ef..6795e3b2cf 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -561,14 +561,14 @@ void Generator::generateCode() fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData()); fprintf(out, " if (!_clname) return nullptr;\n"); fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n" - " return static_cast(const_cast< %s*>(this));\n", - qualifiedClassNameIdentifier.constData(), cdef->classname.constData()); + " return static_cast(this);\n", + qualifiedClassNameIdentifier.constData()); for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one if (cdef->superclassList.at(i).second == FunctionDef::Private) continue; const char *cname = cdef->superclassList.at(i).first.constData(); - fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(const_cast< %s*>(this));\n", - cname, cname, cdef->classname.constData()); + fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n", + cname, cname); } for (int i = 0; i < cdef->interfaceList.size(); ++i) { const QVector &iface = cdef->interfaceList.at(i); @@ -576,8 +576,7 @@ void Generator::generateCode() fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData()); for (int k = j; k >= 0; --k) fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData()); - fprintf(out, "const_cast< %s*>(this)%s;\n", - cdef->classname.constData(), QByteArray(j+1, ')').constData()); + fprintf(out, "this%s;\n", QByteArray(j + 1, ')').constData()); } } if (!purestSuperClass.isEmpty() && !isQObject) { From 2c35ef04ffab5a603e25d50e00d7dc87699effa9 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 22 Sep 2017 15:45:39 +0200 Subject: [PATCH 20/42] doc: fix code snippet of qConstOverload usage Change-Id: I11628d2f9372f21f371ccf93000c26079eb9ef72 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index 1169ad5536..8d4bd36beb 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -617,7 +617,7 @@ template<> class QTypeInfo : public QTypeInfoMerger {}; void overloadedFunction(int, QString); void overloadedFunction(int, QString) const; }; - ... qConstOverload<>(&Foo::overloadedFunction) + ... qConstOverload(&Foo::overloadedFunction) ... qNonConstOverload(&Foo::overloadedFunction) //! [54] From aa4fef88121f536f40760449fa81c03be076d68d Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 11 Sep 2017 18:14:51 +0200 Subject: [PATCH 21/42] Make QDateTimeParser a separate feature It was being mis-described in some places by a QT_CONFIG(timezone) test, replacing older QT_BOOTSTRAPPED checks; but it has no time-zone dependency (until 5.10). So make it a separate feature in its own right. It turns out QAbstractSpinBox's presumed dependency on datetimeedit was an illusion caused by use of QDATETIMEEDIT_*_MIN symbols actually provided by datetimeparser; so remove its bogus dependency. Change-Id: Ibc12f4a9ee35acb64a39a1c7a15d2934b5710dc0 Reviewed-by: Thiago Macieira --- src/corelib/configure.json | 8 +++++++- src/corelib/global/qconfig-bootstrapped.h | 1 + src/corelib/tools/qdatetime.cpp | 8 +++++--- src/corelib/tools/qdatetimeparser.cpp | 4 ---- src/corelib/tools/qdatetimeparser_p.h | 6 ++---- src/corelib/tools/qlocale.cpp | 8 +++++--- src/corelib/tools/tools.pri | 7 +++++-- src/widgets/configure.json | 2 +- src/widgets/widgets/qabstractspinbox.cpp | 13 ++++++++++--- 9 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/corelib/configure.json b/src/corelib/configure.json index 91f7bb4fd6..a5b69a2df6 100644 --- a/src/corelib/configure.json +++ b/src/corelib/configure.json @@ -733,10 +733,16 @@ }, "timezone": { "label": "QTimeZone", - "purpose": "Provides support for timezone handling.", + "purpose": "Provides support for time-zone handling.", "section": "Utilities", "output": [ "publicFeature" ] }, + "datetimeparser": { + "label": "QDateTimeParser", + "purpose": "Provides support for parsing date-time texts.", + "section": "Utilities", + "output": [ "privateFeature" ] + }, "commandlineparser": { "label": "QCommandlineParser", "purpose": "Provides support for command line parsing.", diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 0b02ecc8ec..58a9ca918a 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -87,6 +87,7 @@ #define QT_FEATURE_temporaryfile 1 #define QT_NO_THREAD #define QT_FEATURE_timezone -1 +#define QT_FEATURE_datetimeparser -1 #define QT_FEATURE_topleveldomain -1 #define QT_NO_TRANSLATION #define QT_FEATURE_translation -1 diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 11c023f762..9d26207a0f 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -40,7 +40,9 @@ #include "qplatformdefs.h" #include "private/qdatetime_p.h" +#if QT_CONFIG(datetimeparser) #include "private/qdatetimeparser_p.h" +#endif #include "qdatastream.h" #include "qset.h" @@ -1331,7 +1333,7 @@ QDate QDate::fromString(const QString& string, Qt::DateFormat format) QDate QDate::fromString(const QString &string, const QString &format) { QDate date; -#if QT_CONFIG(timezone) +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) @@ -2037,7 +2039,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format) QTime QTime::fromString(const QString &string, const QString &format) { QTime time; -#if QT_CONFIG(timezone) +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) @@ -4997,7 +4999,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) QDateTime QDateTime::fromString(const QString &string, const QString &format) { -#if QT_CONFIG(timezone) +#if QT_CONFIG(datetimeparser) QTime time; QDate date; diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index 62dd25e072..3ddbc13fdf 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -58,8 +58,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_BOOTSTRAPPED - QDateTimeParser::~QDateTimeParser() { } @@ -1715,6 +1713,4 @@ bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::S return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count); } -#endif // QT_BOOTSTRAPPED - QT_END_NAMESPACE diff --git a/src/corelib/tools/qdatetimeparser_p.h b/src/corelib/tools/qdatetimeparser_p.h index b50c88b4c1..39abdf555f 100644 --- a/src/corelib/tools/qdatetimeparser_p.h +++ b/src/corelib/tools/qdatetimeparser_p.h @@ -63,6 +63,8 @@ #include "QtCore/qvector.h" #include "QtCore/qcoreapplication.h" +QT_REQUIRE_CONFIG(datetimeparser); + #define QDATETIMEEDIT_TIME_MIN QTime(0, 0, 0, 0) #define QDATETIMEEDIT_TIME_MAX QTime(23, 59, 59, 999) #define QDATETIMEEDIT_DATE_MIN QDate(100, 1, 1) @@ -75,8 +77,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_BOOTSTRAPPED - class Q_CORE_EXPORT QDateTimeParser { Q_DECLARE_TR_FUNCTIONS(QDateTimeParser) @@ -287,8 +287,6 @@ Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDat Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections) Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo) -#endif // QT_BOOTSTRAPPED - QT_END_NAMESPACE #endif // QDATETIME_P_H diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 63219b5bab..d65c84c09f 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -54,7 +54,9 @@ #include "qlocale.h" #include "qlocale_p.h" #include "qlocale_tools_p.h" +#if QT_CONFIG(datetimeparser) #include "qdatetimeparser_p.h" +#endif #include "qnamespace.h" #include "qdatetime.h" #include "qstringlist.h" @@ -1862,7 +1864,7 @@ QDateTime QLocale::toDateTime(const QString &string, FormatType format) const QTime QLocale::toTime(const QString &string, const QString &format) const { QTime time; -#ifndef QT_BOOTSTRAPPED +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); dt.setDefaultLocale(*this); if (dt.parseFormat(format)) @@ -1893,7 +1895,7 @@ QTime QLocale::toTime(const QString &string, const QString &format) const QDate QLocale::toDate(const QString &string, const QString &format) const { QDate date; -#ifndef QT_BOOTSTRAPPED +#if QT_CONFIG(datetimeparser) QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); dt.setDefaultLocale(*this); if (dt.parseFormat(format)) @@ -1923,7 +1925,7 @@ QDate QLocale::toDate(const QString &string, const QString &format) const #ifndef QT_NO_DATESTRING QDateTime QLocale::toDateTime(const QString &string, const QString &format) const { -#ifndef QT_BOOTSTRAPPED +#if QT_CONFIG(datetimeparser) QTime time; QDate date; diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index b705d4221a..7ba3ff4a8b 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -21,7 +21,6 @@ HEADERS += \ tools/qcryptographichash.h \ tools/qdatetime.h \ tools/qdatetime_p.h \ - tools/qdatetimeparser_p.h \ tools/qdoublescanprint_p.h \ tools/qeasingcurve.h \ tools/qfreelist_p.h \ @@ -82,7 +81,6 @@ SOURCES += \ tools/qcollator.cpp \ tools/qcryptographichash.cpp \ tools/qdatetime.cpp \ - tools/qdatetimeparser.cpp \ tools/qeasingcurve.cpp \ tools/qfreelist.cpp \ tools/qhash.cpp \ @@ -170,6 +168,11 @@ qtConfig(timezone) { SOURCES += tools/qtimezoneprivate_icu.cpp } +qtConfig(datetimeparser) { + HEADERS += tools/qdatetimeparser_p.h + SOURCES += tools/qdatetimeparser.cpp +} + qtConfig(regularexpression) { QMAKE_USE_PRIVATE += pcre2 diff --git a/src/widgets/configure.json b/src/widgets/configure.json index 7c00f8c3f4..7ec5fe9ef8 100644 --- a/src/widgets/configure.json +++ b/src/widgets/configure.json @@ -135,7 +135,7 @@ "label": "QDateTimeEdit", "purpose": "Supports editing dates and times.", "section": "Widgets", - "condition": "features.calendarwidget && features.datestring && features.textdate", + "condition": "features.calendarwidget && features.datestring && features.textdate && features.datetimeparser", "output": [ "publicFeature", "feature" ] }, "stackedwidget": { diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index c72c060f9a..3427579d1f 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -39,7 +39,9 @@ #include #include +#if QT_CONFIG(datetimeparser) #include +#endif #include #include @@ -47,9 +49,6 @@ #include #include #include -#if QT_CONFIG(datetimeedit) -#include -#endif #include #if QT_CONFIG(menu) #include @@ -1962,12 +1961,15 @@ QVariant operator+(const QVariant &arg1, const QVariant &arg2) break; } case QVariant::Double: ret = QVariant(arg1.toDouble() + arg2.toDouble()); break; +#if QT_CONFIG(datetimeparser) case QVariant::DateTime: { QDateTime a2 = arg2.toDateTime(); QDateTime a1 = arg1.toDateTime().addDays(QDATETIMEEDIT_DATETIME_MIN.daysTo(a2)); a1.setTime(a1.time().addMSecs(QTime().msecsTo(a2.time()))); ret = QVariant(a1); + break; } +#endif // datetimeparser default: break; } return ret; @@ -2022,6 +2024,7 @@ QVariant operator*(const QVariant &arg1, double multiplier) ret = static_cast(qBound(INT_MIN, arg1.toInt() * multiplier, INT_MAX)); break; case QVariant::Double: ret = QVariant(arg1.toDouble() * multiplier); break; +#if QT_CONFIG(datetimeparser) case QVariant::DateTime: { double days = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDateTime().date()) * multiplier; int daysInt = (int)days; @@ -2031,6 +2034,7 @@ QVariant operator*(const QVariant &arg1, double multiplier) ret = QDateTime(QDate().addDays(int(days)), QTime().addMSecs(msecs)); break; } +#endif // datetimeparser default: ret = arg1; break; } @@ -2053,11 +2057,14 @@ double operator/(const QVariant &arg1, const QVariant &arg2) a1 = arg1.toDouble(); a2 = arg2.toDouble(); break; +#if QT_CONFIG(datetimeparser) case QVariant::DateTime: a1 = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDate()); a2 = QDATETIMEEDIT_DATE_MIN.daysTo(arg2.toDate()); a1 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg1.toDateTime().time()) / (long)(3600 * 24 * 1000); a2 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg2.toDateTime().time()) / (long)(3600 * 24 * 1000); + break; +#endif // datetimeparser default: break; } From d03dba3f4abf21de842d3f1146d78ca4655c94e2 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 6 Sep 2017 16:22:45 +0200 Subject: [PATCH 22/42] Windows QPA: Move function to find screen by HWND to QWindowsScreenManager Task-number: QTBUG-62971 Change-Id: Ida0a8e758723f0f617011a89dc89c266d2506aad Reviewed-by: Joerg Bornemann --- src/plugins/platforms/windows/qwindowsscreen.cpp | 15 +++++++++++++++ src/plugins/platforms/windows/qwindowsscreen.h | 1 + src/plugins/platforms/windows/qwindowswindow.cpp | 16 ++++++++-------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 3a4793efcd..cfddb3cc71 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -566,4 +566,19 @@ const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const return Q_NULLPTR; } +const QWindowsScreen *QWindowsScreenManager::screenForHwnd(HWND hwnd) const +{ + HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); + if (hMonitor == NULL) + return nullptr; + const auto it = + std::find_if(m_screens.cbegin(), m_screens.cend(), + [hMonitor](const QWindowsScreen *s) + { + return s->data().hMonitor == hMonitor + && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0; + }); + return it != m_screens.cend() ? *it : nullptr; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 9a8997326b..7cf73f03af 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -134,6 +134,7 @@ public: const WindowsScreenList &screens() const { return m_screens; } const QWindowsScreen *screenAtDp(const QPoint &p) const; + const QWindowsScreen *screenForHwnd(HWND hwnd) const; private: void removeScreen(int index); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 5e0fd77776..050829e6f5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1542,15 +1542,15 @@ void QWindowsWindow::handleGeometryChange() fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) { - HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL); QPlatformScreen *currentScreen = screen(); - const auto screens = QWindowsContext::instance()->screenManager().screens(); - auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) { - return s->data().hMonitor == hMonitor - && s->data().flags & QWindowsScreenData::VirtualDesktop; - }); - if (newScreenIt != screens.end() && *newScreenIt != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen()); + const QWindowsScreen *newScreen = + QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd); + if (newScreen != nullptr && newScreen != currentScreen) { + qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ + << ' ' << window() << " \"" << currentScreen->name() + << "\"->\"" << newScreen->name() << '"'; + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + } } if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); From bd72ead4d12ff56c2856294d84f3e5d7e188b817 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Tue, 19 Sep 2017 15:06:41 +0200 Subject: [PATCH 23/42] Fix docs about QMAKESPEC in INCLUDEPATH QMAKESPEC is added in makefile generator, it is not in INCLUDEPATH. Change-Id: I2451b3c7b30bc237157e68e5ce9de67f55e784b2 Reviewed-by: Leena Miettinen --- qmake/doc/src/qmake-manual.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 216cc30af1..9db8a9af48 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -3754,8 +3754,8 @@ compiled (see QLibraryInfo::DataPath). \endlist - \note The \c QMAKESPEC path will automatically be added to the - \l{INCLUDEPATH} system variable. + \note The \c QMAKESPEC path will be automatically added to the generated + Makefile after the contents of the \l{INCLUDEPATH} system variable. \target cache \section1 Cache File From f1ec81b543fe1d5090acff298e24faf10a7bac63 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 19 Sep 2017 13:18:49 +0200 Subject: [PATCH 24/42] Windows QPA: Detect screen by mouse position when dragging a window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When dragging a window by its border, detect the screen by mouse position to prevent it from oscillating between screens when it resizes. Task-number: QTBUG-62971 Change-Id: I0a4a584ef8ff3bb7288d1abec4de51fb4091dccd Reviewed-by: Oliver Wolff Reviewed-by: Thorbjørn Lund Martsum --- .../platforms/windows/qtwindowsglobal.h | 6 ++++ .../platforms/windows/qwindowscontext.cpp | 7 ++++ .../platforms/windows/qwindowswindow.cpp | 34 +++++++++++++------ .../platforms/windows/qwindowswindow.h | 3 ++ 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index b2152e7ed4..d2e1309280 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -101,6 +101,8 @@ enum WindowsEventType // Simplify event types FocusOutEvent = WindowEventFlag + 18, WhatsThisEvent = WindowEventFlag + 19, DpiChangedEvent = WindowEventFlag + 21, + EnterSizeMoveEvent = WindowEventFlag + 22, + ExitSizeMoveEvent = WindowEventFlag + 23, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, @@ -274,6 +276,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return QtWindows::DeviceChangeEvent; case WM_DPICHANGED: return QtWindows::DpiChangedEvent; + case WM_ENTERSIZEMOVE: + return QtWindows::EnterSizeMoveEvent; + case WM_EXITSIZEMOVE: + return QtWindows::ExitSizeMoveEvent; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index e6e6ee8b1a..f108be96e7 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1055,6 +1055,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); #endif break; + case QtWindows::EnterSizeMoveEvent: + platformWindow->setFlag(QWindowsWindow::ResizeMoveActive); + return true; + case QtWindows::ExitSizeMoveEvent: + platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive); + platformWindow->checkForScreenChanged(); + return true; case QtWindows::ScrollEvent: #if QT_CONFIG(sessionmanager) return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 050829e6f5..d97ebb7545 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1527,6 +1527,26 @@ void QWindowsWindow::handleResized(int wParam) } } +void QWindowsWindow::checkForScreenChanged() +{ + if (parent()) + return; + + QPlatformScreen *currentScreen = screen(); + const auto &screenManager = QWindowsContext::instance()->screenManager(); + // QTBUG-62971: When dragging a window by its border, detect by mouse position + // to prevent it from oscillating between screens when it resizes + const QWindowsScreen *newScreen = testFlag(ResizeMoveActive) + ? screenManager.screenAtDp(QWindowsCursor::mousePosition()) + : screenManager.screenForHwnd(m_data.hwnd); + if (newScreen != nullptr && newScreen != currentScreen) { + qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ + << ' ' << window() << " \"" << currentScreen->name() + << "\"->\"" << newScreen->name() << '"'; + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + } +} + void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; @@ -1541,17 +1561,9 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } - if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) { - QPlatformScreen *currentScreen = screen(); - const QWindowsScreen *newScreen = - QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd); - if (newScreen != nullptr && newScreen != currentScreen) { - qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ - << ' ' << window() << " \"" << currentScreen->name() - << "\"->\"" << newScreen->name() << '"'; - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); - } - } + + checkForScreenChanged(); + if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index aa8ce7e73a..2b447751ba 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -208,6 +208,7 @@ public: Compositing = 0x200000, HasBorderInFullScreen = 0x400000, WithinDpiChanged = 0x800000, + ResizeMoveActive = 0x2000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -313,6 +314,8 @@ public: void alertWindow(int durationMs = 0); void stopAlertWindow(); + void checkForScreenChanged(); + static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); static void setHasBorderInFullScreenStatic(QWindow *window, bool border); From bc31d2235cbf81c05ef80de723ebc4dc45a89695 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 19 Sep 2017 14:34:55 +0200 Subject: [PATCH 25/42] Windows QPA: Call raise() also for SubWindows with WindowStaysOnTopHint QMdiSubWindows may have WindowStaysOnTopHint set. Task-number: QTBUG-63121 Change-Id: I21f80311fdf57e775df895122299bb7beb6ec4e6 Reviewed-by: Joerg Bornemann Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowswindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index d97ebb7545..bea849383d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -872,7 +872,9 @@ void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other window void QWindowsBaseWindow::raise_sys() { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); - if (window()->type() == Qt::Popup + const Qt::WindowType type = window()->type(); + if (type == Qt::Popup + || type == Qt::SubWindow // Special case for QTBUG-63121: MDI subwindows with WindowStaysOnTopHint || (window()->flags() & (Qt::WindowStaysOnTopHint | Qt::WindowStaysOnBottomHint)) == 0) { SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } From 35781b358887facf954307b0d6c5958ce089eb72 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Wed, 23 Aug 2017 11:48:11 +0200 Subject: [PATCH 26/42] Return focus to correct widget after showing menu By the time we call setKeyboardMode(true), the menu may already have taken focus. This change sets keyboardFocusWidget before opening the popup, and makes sure that keyboardFocusWidget is not set to the popup. (We cannot remove the assignment from setKeyboardMode(), since it's called from several places.) [ChangeLog][QtWidgets] Fixed widget losing focus after showing menu second time. Task-number: QTBUG-56860 Change-Id: Ic01726bf694e6f365dd7b601ad555156e0fdf6c5 Reviewed-by: Richard Moe Gustavsen --- src/widgets/widgets/qmenubar.cpp | 3 +- .../widgets/widgets/qmenubar/tst_qmenubar.cpp | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 3d24cc0387..41b6bf49f8 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -288,7 +288,7 @@ void QMenuBarPrivate::setKeyboardMode(bool b) keyboardState = b; if(b) { QWidget *fw = QApplication::focusWidget(); - if (fw != q) + if (fw && fw != q && fw->window() != QApplication::activePopupWidget()) keyboardFocusWidget = fw; focusFirstAction(); q->setFocus(Qt::MenuBarFocusReason); @@ -1706,6 +1706,7 @@ void QMenuBarPrivate::_q_internalShortcutActivated(int id) } } + keyboardFocusWidget = QApplication::focusWidget(); setCurrentAction(act, true, true); if (act && !act->menu()) { activateAction(act, QAction::Trigger); diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 9a0ca0565e..251a351cc1 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,7 @@ private slots: void allowActiveAndDisabled(); #endif + void taskQTBUG56860_focus(); void check_endKey(); void check_homeKey(); @@ -710,6 +712,52 @@ void tst_QMenuBar::check_cursorKeys3() } #endif +void tst_QMenuBar::taskQTBUG56860_focus() +{ +#if defined(Q_OS_DARWIN) + QSKIP("Native key events are needed to test menu action activation on macOS."); +#endif + QMainWindow w; + QMenuBar *mb = w.menuBar(); + + if (mb->platformMenuBar()) + QSKIP("This test requires the Qt menubar."); + + QMenu *em = mb->addMenu("&Edit"); + em->setObjectName("EditMenu"); + em->addAction("&Cut"); + em->addAction("C&opy"); + QPlainTextEdit *e = new QPlainTextEdit; + e->setObjectName("edit"); + + w.setCentralWidget(e); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QTRY_COMPARE(QApplication::focusWidget(), e); + + // Open menu + QTest::keyClick(static_cast(0), Qt::Key_E, Qt::AltModifier ); + QTRY_COMPARE(QApplication::activePopupWidget(), em); + // key down to trigger focus + QTest::keyClick(static_cast(0), Qt::Key_Down ); + // and press ENTER to close + QTest::keyClick(static_cast(0), Qt::Key_Enter ); + QTRY_COMPARE(QApplication::activePopupWidget(), nullptr); + // focus should have returned to the editor by now + QTRY_COMPARE(QApplication::focusWidget(), e); + + // Now do it all over again... + QTest::keyClick(static_cast(0), Qt::Key_E, Qt::AltModifier ); + QTRY_COMPARE(QApplication::activePopupWidget(), em); + QTest::keyClick(static_cast(0), Qt::Key_Down ); + QTest::keyClick(static_cast(0), Qt::Key_Enter ); + QTRY_COMPARE(QApplication::activePopupWidget(), nullptr); + QTRY_COMPARE(QApplication::focusWidget(), e); + +} + /*! If a popupmenu is active you can use home to go quickly to the first item in the menu. */ From 33693473d4bf6b28bee2d5fe740633d6867c26af Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Mon, 25 Sep 2017 19:17:02 +0800 Subject: [PATCH 27/42] Remove unnecessary copying in QSet::subtract() Task-number: QTBUG-42810 Change-Id: I5d4793a12b078e34bea034b4500e270d42609de0 Reviewed-by: Thiago Macieira --- src/corelib/tools/qset.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index 08b38a08c2..7ded120ab7 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -340,13 +340,14 @@ Q_INLINE_TEMPLATE bool QSet::intersects(const QSet &other) const template Q_INLINE_TEMPLATE QSet &QSet::subtract(const QSet &other) { - QSet copy1(*this); - QSet copy2(other); - typename QSet::const_iterator i = copy1.constEnd(); - while (i != copy1.constBegin()) { - --i; - if (copy2.contains(*i)) + if (&other == this) { + clear(); + } else { + auto i = other.constEnd(); + while (i != other.constBegin()) { + --i; remove(*i); + } } return *this; } From 3d0fa4d4fb870450f6e77d7248db91984ddf8b50 Mon Sep 17 00:00:00 2001 From: Eric Lemanissier Date: Tue, 26 Sep 2017 11:45:56 +0200 Subject: [PATCH 28/42] moc: remove useless cast in qt_static_metacall generated code _a[1] was reinterpret_casted twice in a row, which triggers clang's warning undefined-reinterpret-cast: "dereference of type '_t *' (aka ...) that was reinterpret_cast from type 'void **' has undefined behavior " only the last reinterpret_cast is kept Change-Id: I71d52c5ff08c674003aec29f8a907c90905c0d4c Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/tools/moc/generator.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 6795e3b2cf..7e1ec3522f 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1237,7 +1237,6 @@ void Generator::generateStaticMetacall() Q_ASSERT(needElse); // if there is signal, there was method. fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n"); fprintf(out, " int *result = reinterpret_cast(_a[0]);\n"); - fprintf(out, " void **func = reinterpret_cast(_a[1]);\n"); bool anythingUsed = false; for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) { const FunctionDef &f = cdef->signalList.at(methodindex); @@ -1263,14 +1262,14 @@ void Generator::generateStaticMetacall() fprintf(out, ") const;\n"); else fprintf(out, ");\n"); - fprintf(out, " if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&%s::%s)) {\n", + fprintf(out, " if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&%s::%s)) {\n", cdef->classname.constData(), f.name.constData()); fprintf(out, " *result = %d;\n", methodindex); fprintf(out, " return;\n"); fprintf(out, " }\n }\n"); } if (!anythingUsed) - fprintf(out, " Q_UNUSED(result);\n Q_UNUSED(func);\n"); + fprintf(out, " Q_UNUSED(result);\n"); fprintf(out, " }"); needElse = true; } From 3c59065d5cb5f82f90ed2e830e10c5807deeaf2c Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Tue, 12 Sep 2017 16:18:58 +0200 Subject: [PATCH 29/42] qglxconvenience: Avoid null pointer dereference glXGetVisualFromFBConfig according to documentation can return NULL [1]. This may result in a crash when running Qt applications using ARGB windows with XLIB_SKIP_ARGB_VISUALS defined. Also guard QXlibScopedPointerDeleter against illegally calling XFree(nullptr). [1] https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXGetVisualFromFBConfig.xml Task-number: QTBUG-58910 Change-Id: Ie076a1e906ed632543bdab03ef365f699533a61a Reviewed-by: Gatis Paeglis --- src/platformsupport/glxconvenience/qglxconvenience.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 8c26550c1e..74b7c63473 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -164,7 +164,8 @@ bool QXcbSoftwareOpenGLEnforcer::forceSoftwareOpenGL = false; template struct QXlibScopedPointerDeleter { static inline void cleanup(T *pointer) { - XFree(pointer); + if (pointer) + XFree(pointer); } }; @@ -202,6 +203,8 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format GLXFBConfig candidate = configs[i]; QXlibPointer visual(glXGetVisualFromFBConfig(display, candidate)); + if (visual.isNull()) + continue; const int actualRed = qPopulationCount(visual->red_mask); const int actualGreen = qPopulationCount(visual->green_mask); From f03cd9a7bcbf88eefb8e77b99b4c194da759c7ff Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Wed, 9 Nov 2016 18:40:43 +0200 Subject: [PATCH 30/42] QAbstractSocket: fix handling of successful connectToHostByName() In case connectToHostByName() returns 'true', we should fetch the connection parameters and emit connected() signal. Change-Id: Id36b6d71005b8cec070a1b12e7bb0caf8bf0bcb9 Reviewed-by: Thiago Macieira Reviewed-by: Timur Pocheptsov --- src/network/socket/qabstractsocket.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 92c18fb0f1..0f13b1d1b8 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -962,13 +962,17 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host) emit q->stateChanged(state); if (cachedSocketDescriptor != -1 || initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) { - if (socketEngine->connectToHostByName(host, port) || - socketEngine->state() == QAbstractSocket::ConnectingState) { - cachedSocketDescriptor = socketEngine->socketDescriptor(); - + // Try to connect to the host. If it succeeds immediately + // (e.g. QSocks5SocketEngine in UDPASSOCIATE mode), emit + // connected() and return. + if (socketEngine->connectToHostByName(host, port)) { + fetchConnectionParameters(); return; } + if (socketEngine->state() == QAbstractSocket::ConnectingState) + return; + // failed to connect setError(socketEngine->error(), socketEngine->errorString()); } From 16f144db2916e5be5d4409154d77e01e07714251 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 26 Sep 2017 10:48:14 +0200 Subject: [PATCH 31/42] Do not define _HAS_EXCEPTIONS=0 in MSVC builds This definition causes a build error if concrt.h is included. According to Microsoft [1], this macro is unsupported. It was added in f5908363 to silence compiler warnings that are generated when exceptions are turned off and certain STL headers are included. We specifically disable the warnings in question now. [1] https://blogs.msdn.microsoft.com/vcblog/2015/07/14/stl-fixes-in-vs-2015-part-2/ Task-number: QTBUG-63409 Change-Id: I567d5d46292fbd7898394e217bb0987fbcdca9de Reviewed-by: Oliver Wolff Reviewed-by: Thiago Macieira --- mkspecs/common/msvc-version.conf | 2 +- mkspecs/common/winrt_winphone/qmake.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index d8ec089f55..ba74c49f9c 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -37,7 +37,7 @@ greaterThan(QMAKE_MSC_VER, 1699) { # Visual Studio 2012 (11.0) / Visual C++ 17.0 and up MSVC_VER = 11.0 COMPAT_MKSPEC = win32-msvc2012 - QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0 + QMAKE_CXXFLAGS_EXCEPTIONS_OFF = /wd4530 /wd4577 QT_CONFIG += c++11 CONFIG += c++11 } diff --git a/mkspecs/common/winrt_winphone/qmake.conf b/mkspecs/common/winrt_winphone/qmake.conf index 2bb6f9bcbd..0fa9c22e87 100644 --- a/mkspecs/common/winrt_winphone/qmake.conf +++ b/mkspecs/common/winrt_winphone/qmake.conf @@ -50,7 +50,7 @@ QMAKE_CXXFLAGS_STL_OFF = QMAKE_CXXFLAGS_RTTI_ON = -GR QMAKE_CXXFLAGS_RTTI_OFF = QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc -QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0 +QMAKE_CXXFLAGS_EXCEPTIONS_OFF = /wd4530 /wd4577 QMAKE_INCDIR = From d5ae3b1747f0b323847318e04fcd1677b66e91f1 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 25 Sep 2017 17:02:50 +0200 Subject: [PATCH 32/42] Reorder defines to respect alphabetic order in bootstrap config Apparently it's all meant to be in alphabetic order by feature name (except for where it isn't). So move my new addition to it to where that would put it, re-order everything else to follow that rule and add a comment documenting it. Change-Id: I6f00d3d18fc8c492992e9f701520f3e8731739b5 Reviewed-by: Oswald Buddenhagen --- src/corelib/global/qconfig-bootstrapped.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 58a9ca918a..05a492fb96 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -66,8 +66,7 @@ #define QT_NO_USING_NAMESPACE #define QT_NO_DEPRECATED -#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -#define QT_NO_DATASTREAM +// Keep feature-test macros in alphabetic order by feature name: #define QT_FEATURE_alloca 1 #define QT_FEATURE_alloca_h -1 #ifdef _WIN32 @@ -75,25 +74,27 @@ #else # define QT_FEATURE_alloca_malloc_h -1 #endif +#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1 +#define QT_NO_DATASTREAM +#define QT_FEATURE_datetimeparser -1 +#define QT_NO_GEOM_VARIANT #define QT_FEATURE_iconv -1 #define QT_FEATURE_icu -1 #define QT_FEATURE_journald -1 #define QT_FEATURE_library -1 #define QT_NO_QOBJECT #define QT_FEATURE_process -1 -#define QT_NO_SYSTEMLOCALE +#define QT_FEATURE_sharedmemory -1 #define QT_FEATURE_slog2 -1 #define QT_FEATURE_syslog -1 +#define QT_NO_SYSTEMLOCALE +#define QT_FEATURE_systemsemaphore -1 #define QT_FEATURE_temporaryfile 1 #define QT_NO_THREAD #define QT_FEATURE_timezone -1 -#define QT_FEATURE_datetimeparser -1 #define QT_FEATURE_topleveldomain -1 #define QT_NO_TRANSLATION #define QT_FEATURE_translation -1 -#define QT_NO_GEOM_VARIANT -#define QT_FEATURE_sharedmemory -1 -#define QT_FEATURE_systemsemaphore -1 #ifdef QT_BUILD_QMAKE #define QT_FEATURE_commandlineparser -1 From e96c56c740768143878d9e0f0acc5aa01dd52bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Tue, 26 Sep 2017 14:18:02 +0300 Subject: [PATCH 33/42] Blacklist tst_QWindow:testInputEvents on RHEL 7.4 Swapping from RHEL 7.2 to 7.4 produces new autotest failures. Task-number: QTBUG-63433 Change-Id: I3e59aa73b5874cfec06e166f521e06b0c7829743 Reviewed-by: Timur Pocheptsov --- tests/auto/gui/kernel/qwindow/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index 1443359377..1a4885b895 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -19,3 +19,5 @@ ubuntu-16.04 osx [modalWindowModallity] osx +[testInputEvents] +rhel-7.4 From ff2e9a17e7583fe18b9ac3527e4aab2a6b395174 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 26 Sep 2017 18:08:25 +0200 Subject: [PATCH 34/42] Fix crash when reparenting window container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QWindowContainer assumed that a widget could never change from native to non-native. This is not a fact when the window container is reparented to toplevel and back. In this case, usesNativeWidgets would be stuck at true, and parentWasChanged() would go down the native widget path, triggering an assert. The solution is to always recalculate the usesNativeWidgets bool. Task-number: QTBUG-63168 Change-Id: I88178259878ace9eb5de2ee45ff5e69b170da71c Reviewed-by: Laszlo Agocs Reviewed-by: Richard Moe Gustavsen Reviewed-by: Błażej Szczygieł --- src/widgets/kernel/qwindowcontainer.cpp | 6 +++-- .../qwindowcontainer/tst_qwindowcontainer.cpp | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index bffc1f45f2..56114350d2 100644 --- a/src/widgets/kernel/qwindowcontainer.cpp +++ b/src/widgets/kernel/qwindowcontainer.cpp @@ -89,7 +89,7 @@ public: void updateUsesNativeWidgets() { - if (usesNativeWidgets || window->parent() == 0) + if (window->parent() == 0) return; Q_Q(QWindowContainer); if (q->internalWinId()) { @@ -97,6 +97,7 @@ public: usesNativeWidgets = true; return; } + bool nativeWidgetSet = false; QWidget *p = q->parentWidget(); while (p) { if (false @@ -108,11 +109,12 @@ public: #endif ) { q->winId(); - usesNativeWidgets = true; + nativeWidgetSet = true; break; } p = p->parentWidget(); } + usesNativeWidgets = nativeWidgetSet; } void markParentChain() { diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index 6ec1b754d0..a3e549aa50 100644 --- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -74,6 +74,7 @@ private slots: void testOwnership(); void testBehindTheScenesDeletion(); void testUnparenting(); + void testUnparentReparent(); void testActivation(); void testAncestorChange(); void testDockWidget(); @@ -241,6 +242,31 @@ void tst_QWindowContainer::testUnparenting() QVERIFY(!window->isVisible()); } +void tst_QWindowContainer::testUnparentReparent() +{ + QWidget root; + + QWindow *window = new QWindow(); + QScopedPointer container(QWidget::createWindowContainer(window, &root)); + container->setWindowTitle(QTest::currentTestFunction()); + container->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 100); + + root.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&root)); + + QTRY_VERIFY(window->isVisible()); + + container->setParent(nullptr); + QTRY_VERIFY(!window->isVisible()); + + container->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QTRY_VERIFY(window->isVisible()); + + container->setParent(&root); // This should not crash (QTBUG-63168) +} + void tst_QWindowContainer::testAncestorChange() { QWidget root; From cbbf843e96de3067e4cb7c0a7b4e59a6c27b10f7 Mon Sep 17 00:00:00 2001 From: Anders Hafreager Date: Thu, 28 Sep 2017 09:11:20 +0200 Subject: [PATCH 35/42] macOS: Bail out early when handling shortcut event results in closing window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Cmd+W is used to close a window, check if m_platformWindow is still valid before accessing window property. Task-number: QTBUG-63389 Change-Id: I9abda19b8482e7a1fd07b07d8981b6a768e96c2e Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 9207feb5fd..ec9d25fff9 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1559,6 +1559,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) if (m_composingText.isEmpty()) { m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1); + + // Handling a shortcut may result in closing the window + if (!m_platformWindow) + return true; } QObject *fo = m_platformWindow->window()->focusObject(); From 8ea5c401094b78c40c21811c9514462797218ae2 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 26 Sep 2017 13:27:55 -0700 Subject: [PATCH 36/42] QWindowsMouseHandler: Add documentation link for bitmask magic Change-Id: I743aef0e15ef42347c5222d0e50577b006483cc4 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsmousehandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index d21581ba8a..0cabb66bca 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -233,6 +233,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch. // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem // since we do not want to ignore mouse events coming from a tablet. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx const quint64 extraInfo = quint64(GetMessageExtraInfo()); if ((extraInfo & signatureMask) == miWpSignature) { if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen. From 06cb408979831250298c4492ea8133e362c1bcc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Wed, 27 Sep 2017 00:24:31 +0300 Subject: [PATCH 37/42] Add support for ICC in toolchain.prf Task-number: QTBUG-62531 Change-Id: Ie15a349c830258058d48c9da18b52b343bdb943a Reviewed-by: Thiago Macieira --- mkspecs/features/toolchain.prf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf index 35175f1744..7b6f48de72 100644 --- a/mkspecs/features/toolchain.prf +++ b/mkspecs/features/toolchain.prf @@ -120,7 +120,7 @@ isEmpty($${target_prefix}.INCDIRS) { } } } - !darwin:clang { + if(!darwin:clang)|intel_icc { # Clang on a non-Apple system (that is, a system without ld64 -- say, with GNU ld # or gold under Linux) will not print any library search path. Need to use another # invocation with different options (which in turn doesn't print include search @@ -205,7 +205,7 @@ isEmpty($${target_prefix}.COMPILER_MACROS) { vars = $$qtVariablesFromGCC($$QMAKE_CXX) } for (v, vars) { - isEmpty(v)|contains(v, $${LITERAL_HASH}.*): next() + contains(v, $${LITERAL_HASH}.*)|contains(v, " *"): next() # Set both for the outer scope ... eval($$v) v ~= s/ .*// From 49643145e13ff74cb3ecf6f5680fa23c91f661ff Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 29 Sep 2017 10:16:11 +0200 Subject: [PATCH 38/42] HTTP/2 protocol handler: set redirect URL on reply For HTTP/1 it's done when no data expected and response headers received - protocol handler emits channel->allDone which handles the status code and sets (if needed) a redirectUrl. HTTP/2 protocol handler cannot emit allDone (it has many requests multiplexed and actually cannot say allDone yet). So we set a redirect url if we have the corresponding status code and found 'location' header. Task-number: QTBUG-63471 Change-Id: Ibd3438ef918c245a46b8c0128910a89b9a418448 Reviewed-by: Andy Shaw Reviewed-by: Edward Welbourne --- src/network/access/qhttp2protocolhandler.cpp | 21 +++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 44ab637da8..114feb91b7 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -1034,12 +1034,26 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } const auto httpReplyPrivate = httpReply->d_func(); + + // For HTTP/1 'location' is handled (and redirect URL set) when a protocol + // handler emits channel->allDone(). Http/2 protocol handler never emits + // allDone, since we have many requests multiplexed in one channel at any + // moment and we are probably not done yet. So we extract url and set it + // here, if needed. + int statusCode = 0; + QUrl redirectUrl; + for (const auto &pair : headers) { const auto &name = pair.name; auto value = pair.value; + // TODO: part of this code copies what SPDY protocol handler does when + // processing headers. Binary nature of HTTP/2 and SPDY saves us a lot + // of parsing and related errors/bugs, but it would be nice to have + // more detailed validation of headers. if (name == ":status") { - httpReply->setStatusCode(value.left(3).toInt()); + statusCode = value.left(3).toInt(); + httpReply->setStatusCode(statusCode); httpReplyPrivate->reasonPhrase = QString::fromLatin1(value.mid(4)); } else if (name == ":version") { httpReplyPrivate->majorVersion = value.at(5) - '0'; @@ -1050,6 +1064,8 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader if (ok) httpReply->setContentLength(length); } else { + if (name == "location") + redirectUrl = QUrl::fromEncoded(value); QByteArray binder(", "); if (name == "set-cookie") binder = "\n"; @@ -1057,6 +1073,9 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } } + if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid()) + httpReply->setRedirectUrl(redirectUrl); + if (connectionType == Qt::DirectConnection) emit httpReply->headerChanged(); else From 8b64a1054ab5a428b7fcc4efad3ff31bc55dd7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Thu, 28 Sep 2017 10:47:53 +0200 Subject: [PATCH 39/42] Fix cookies not being applied on redirect Task-number: QTBUG-63313 Change-Id: I5245fc837557f19062cbbf0f1dfb86353c85229f Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- src/network/access/qnetworkreplyhttpimpl.cpp | 8 ++++++ .../qnetworkreply/tst_qnetworkreply.cpp | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index fec3b0a100..9f1b37c4e9 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1165,6 +1165,14 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining); operation = getRedirectOperation(operation, httpStatus); + if (const QNetworkCookieJar *const cookieJar = (manager ? manager->cookieJar() : nullptr)) { + auto cookies = cookieJar->cookiesForUrl(url); + if (!cookies.empty()) { + redirectRequest.setHeader(QNetworkRequest::KnownHeaders::CookieHeader, + QVariant::fromValue(cookies)); + } + } + if (httpRequest.redirectPolicy() != QNetworkRequest::UserVerifiedRedirectPolicy) followRedirect(); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index e995b69f60..542246ff2d 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -487,6 +487,7 @@ private Q_SLOTS: void ioHttpRedirectPolicyErrors(); void ioHttpUserVerifiedRedirect_data(); void ioHttpUserVerifiedRedirect(); + void ioHttpCookiesDuringRedirect(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -8410,6 +8411,33 @@ void tst_QNetworkReply::ioHttpUserVerifiedRedirect() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); } +void tst_QNetworkReply::ioHttpCookiesDuringRedirect() +{ + MiniHttpServer target(httpEmpty200Response, false); + + const QString cookieHeader = QStringLiteral("Set-Cookie: hello=world; Path=/;\r\n"); + QString redirect = tempRedirectReplyStr(); + // Insert 'cookieHeader' before the final \r\n + redirect.insert(redirect.length() - 2, cookieHeader); + + QUrl url("http://localhost/"); + url.setPort(target.serverPort()); + redirect = redirect.arg(url.toString()); + MiniHttpServer redirectServer(redirect.toLatin1(), false); + + url = QUrl("http://localhost/"); + url.setPort(redirectServer.serverPort()); + QNetworkRequest request(url); + auto oldRedirectPolicy = manager.redirectPolicy(); + manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); + QNetworkReplyPtr reply(manager.get(request)); + // Set policy back to whatever it was + manager.setRedirectPolicy(oldRedirectPolicy); + + QVERIFY(waitForFinish(reply) == Success); + QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n")); +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject From 291233a8d05b79a19e3ae2951824d1c0444cbd27 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Sun, 1 Oct 2017 16:34:33 -0700 Subject: [PATCH 40/42] Fix strict-prototypes warning with qVersion function This is enabled by default with Xcode 9 and would therefore be seen by anyone calling this function from C or Objective-C. Task-number: QTBUG-63450 Change-Id: Iecd67017b6774c9f2fce2433002ff852058dd3ed Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 6023cc8564..35c35ac64d 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -355,7 +355,7 @@ typedef double qreal; #if !defined(QT_NAMESPACE) && defined(__cplusplus) && !defined(Q_QDOC) extern "C" #endif -Q_CORE_EXPORT const char *qVersion() Q_DECL_NOTHROW; +Q_CORE_EXPORT const char *qVersion(void) Q_DECL_NOTHROW; #if defined(__cplusplus) From 3e2de481617aabb51dd8d635fd1d8d363610ed3f Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Sat, 9 Sep 2017 01:31:27 +0200 Subject: [PATCH 41/42] OCI: Clear the cache in the result for a forward only query When the query is forward-only then nextIndex() is always 0, therefore the cache values need to be cleared beforehand so that they are not reused when the next row is retrieved. Task-number: QTBUG-57765 Change-Id: I49e8427b24ec2d932e5b387699ac7f3496e9a48c Reviewed-by: Konstantin Ritt Reviewed-by: Edward Welbourne --- src/plugins/sqldrivers/oci/qsql_oci.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp index 32d3681a17..a4793351de 100644 --- a/src/plugins/sqldrivers/oci/qsql_oci.cpp +++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp @@ -206,6 +206,7 @@ protected: QVariant lastInsertId() const Q_DECL_OVERRIDE; bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE; void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + bool fetchNext() override; }; class QOCIResultPrivate: public QSqlCachedResultPrivate @@ -2097,6 +2098,14 @@ void QOCIResult::virtual_hook(int id, void *data) QSqlCachedResult::virtual_hook(id, data); } +bool QOCIResult::fetchNext() +{ + Q_D(QOCIResult); + if (isForwardOnly()) + d->cache.clear(); + return QSqlCachedResult::fetchNext(); +} + //////////////////////////////////////////////////////////////////////////// From 3faf8f4d48abd982be8470786cc5f61372519722 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 3 Oct 2017 10:31:38 +0200 Subject: [PATCH 42/42] tst_QSsl(longlongnamefollows) - fix a flakey auto-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original test was using QSslSocket::waitForEncrypted function, which is apparently a bad idea on Windows: connecting to 'www.qt.io' we have to verify certs and there is no guarantee a given Windows VM has the required CA certificate ready in its cert store. In such cases we start a background thread (aka CA fetcher's thread) and it calls a (potentially blocking for a significant amount of time) function (CryptoAPI). When finished, this thread reports the results via queued connection, which does not work if we are sitting in a tiny-loop inside waitForEncrypted. Re-factor the test to use signals/slots and a normally running event loop. Also, the last test makes a wrong assumption about Windows - fixed. Task-number: QTBUG-63481 Change-Id: I4abe9cda2a6c52d841ac858cccb6bf068e550cb8 Reviewed-by: Mårten Nordheim Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- ...qsslsocket_onDemandCertificates_member.cpp | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp index b5bfde3cab..25c2701f69 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp @@ -168,29 +168,59 @@ void tst_QSslSocket_onDemandCertificates_member::proxyAuthenticationRequired(con #ifndef QT_NO_OPENSSL +static bool waitForEncrypted(QSslSocket *socket) +{ + Q_ASSERT(socket); + + QEventLoop eventLoop; + + QTimer connectionTimeoutWatcher; + connectionTimeoutWatcher.setSingleShot(true); + connectionTimeoutWatcher.connect(&connectionTimeoutWatcher, &QTimer::timeout, + [&eventLoop]() { + eventLoop.exit(); + }); + + bool encrypted = false; + socket->connect(socket, &QSslSocket::encrypted, [&eventLoop, &encrypted](){ + eventLoop.exit(); + encrypted = true; + }); + + socket->connect(socket, QOverload&>::of(&QSslSocket::sslErrors), + [&eventLoop](){ + eventLoop.exit(); + }); + + // Wait for 30 s. maximum - the default timeout in our QSslSocket::waitForEncrypted ... + connectionTimeoutWatcher.start(30000); + eventLoop.exec(); + return encrypted; +} + void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMethods() { - QString host("www.qt.io"); + const QString host("www.qt.io"); // not using any root certs -> should not work QSslSocketPtr socket2 = newSocket(); this->socket = socket2.data(); socket2->setCaCertificates(QList()); socket2->connectToHostEncrypted(host, 443); - QVERIFY(!socket2->waitForEncrypted()); + QVERIFY(!waitForEncrypted(socket2.data())); // default: using on demand loading -> should work QSslSocketPtr socket = newSocket(); this->socket = socket.data(); socket->connectToHostEncrypted(host, 443); - QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QVERIFY2(waitForEncrypted(socket.data()), qPrintable(socket->errorString())); // not using any root certs again -> should not work QSslSocketPtr socket3 = newSocket(); this->socket = socket3.data(); socket3->setCaCertificates(QList()); socket3->connectToHostEncrypted(host, 443); - QVERIFY(!socket3->waitForEncrypted()); + QVERIFY(!waitForEncrypted(socket3.data())); // setting empty SSL configuration explicitly -> depends on on-demand loading QSslSocketPtr socket4 = newSocket(); @@ -199,24 +229,16 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe socket4->setSslConfiguration(conf); socket4->connectToHostEncrypted(host, 443); #ifdef QT_BUILD_INTERNAL - bool rootCertLoadingAllowed = QSslSocketPrivate::rootCertOnDemandLoadingSupported(); -#if defined(Q_OS_LINUX) - QCOMPARE(rootCertLoadingAllowed, true); + const bool works = QSslSocketPrivate::rootCertOnDemandLoadingSupported(); +#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) + QCOMPARE(works, true); #elif defined(Q_OS_MAC) - QCOMPARE(rootCertLoadingAllowed, false); -#endif // other platforms: undecided (Windows: depends on the version) - // when we allow on demand loading, it is enabled by default, - // so on Unix it will work without setting any certificates. Otherwise, - // the configuration contains an empty set of certificates - // and will fail. - bool works; -#if defined (Q_OS_WIN) - works = false; // on Windows, this won't work even though we use on demand loading - Q_UNUSED(rootCertLoadingAllowed) -#else - works = rootCertLoadingAllowed; -#endif - QCOMPARE(socket4->waitForEncrypted(), works); + QCOMPARE(works, false); +#endif // other platforms: undecided. + // When we *allow* on-demand loading, we enable it by default; so, on Unix, + // it will work without setting any certificates. Otherwise, the configuration + // contains an empty set of certificates, so on-demand loading shall fail. + QCOMPARE(waitForEncrypted(socket4.data()), works); #endif // QT_BUILD_INTERNAL }