From 44a2c0006546ba39a4a523904f75a9cb01cfe5fc Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 12 Dec 2017 09:55:14 +0100 Subject: Bump version Change-Id: Ie8406d47cd22d913ef481bbf3bf9eda5e3f2a4d7 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index ee30acf..db844c0 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.9.3 +MODULE_VERSION = 5.9.4 -- cgit v1.2.1 From b90fbebbb5e257f771e96980109fb543647b1844 Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Thu, 4 Jan 2018 13:53:43 +0200 Subject: Add changes file for Qt 5.9.4 Change-Id: I45a8551cd6ae0e8531cfde1de95d25d2e2494aea Reviewed-by: Milian Wolff --- dist/changes-5.9.4 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 dist/changes-5.9.4 diff --git a/dist/changes-5.9.4 b/dist/changes-5.9.4 new file mode 100644 index 0000000..d49a42f --- /dev/null +++ b/dist/changes-5.9.4 @@ -0,0 +1,25 @@ +Qt 5.9.4 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.9.4 Changes * +**************************************************************************** + + - This release contains only minor code improvements. + -- cgit v1.2.1 From 6701ff310933ec33f9199b53d78299764f646387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Fri, 15 Dec 2017 13:04:02 +0100 Subject: Allow deleting a channel during method invocation A real-life use case is the session restore page in KDE Falkon or, more generally, any kind of closeTab() method exposed to JS in a QWebEnginePage. The approach taken in this patch will only work if the transport can also deal with deletion during a messageReceived signal emission. Alternatively, method invocation could be delayed via the event loop, but this would come with an obvious performance penalty. Change-Id: I2940f61e07c77365f6e3e7cd29463d4cb5b525a6 Reviewed-by: Milian Wolff --- src/webchannel/qmetaobjectpublisher.cpp | 12 ++++++-- tests/auto/webchannel/tst_webchannel.cpp | 52 ++++++++++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 13 +++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index cfc6ad2..8e83237 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -664,9 +664,15 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel return; } - transport->sendMessage(createResponse(message.value(KEY_ID), - wrapResult(invokeMethod(object, message.value(KEY_METHOD).toInt(-1), - message.value(KEY_ARGS).toArray()), transport))); + QPointer publisherExists(this); + QPointer transportExists(transport); + QVariant result = + invokeMethod(object, + message.value(KEY_METHOD).toInt(-1), + message.value(KEY_ARGS).toArray()); + if (!publisherExists || !transportExists) + return; + transport->sendMessage(createResponse(message.value(KEY_ID), wrapResult(result, transport))); } else if (type == TypeConnectToSignal) { signalHandler.connectTo(object, message.value(KEY_SIGNAL).toInt(-1)); } else if (type == TypeDisconnectFromSignal) { diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index f214b7e..602a101 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -814,6 +814,58 @@ void TestWebChannel::testAsyncObject() thread.wait(); } +class FunctionWrapper : public QObject +{ + Q_OBJECT + std::function m_fun; +public: + FunctionWrapper(std::function fun) : m_fun(std::move(fun)) {} +public slots: + void invoke() + { + m_fun(); + } +}; + +void TestWebChannel::testDeletionDuringMethodInvocation_data() +{ + QTest::addColumn("deleteChannel"); + QTest::addColumn("deleteTransport"); + QTest::newRow("delete neither") << false << false; + QTest::newRow("delete channel") << true << false; + QTest::newRow("delete transport") << false << true; + QTest::newRow("delete both") << true << true; +} + +void TestWebChannel::testDeletionDuringMethodInvocation() +{ + QFETCH(bool, deleteChannel); + QFETCH(bool, deleteTransport); + + QScopedPointer channel(new QWebChannel); + QScopedPointer transport(new DummyTransport(nullptr)); + FunctionWrapper deleter([&](){ + if (deleteChannel) + channel.reset(); + if (deleteTransport) + transport.reset(); + }); + channel->registerObject("deleter", &deleter); + channel->connectTo(transport.data()); + + transport->emitMessageReceived({ + {"type", TypeInvokeMethod}, + {"object", "deleter"}, + {"method", deleter.metaObject()->indexOfMethod("invoke()")}, + {"id", 42} + }); + + QCOMPARE(deleteChannel, !channel); + QCOMPARE(deleteTransport, !transport); + if (!deleteTransport) + QCOMPARE(transport->messagesSent().size(), deleteChannel ? 0 : 1); +} + static QHash createObjects(QObject *parent) { const int num = 100; diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index d2597e5..85a9f39 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -53,10 +54,18 @@ public: emit messageReceived(message, this); } + QVector messagesSent() const + { + return mMessagesSent; + } + public slots: - void sendMessage(const QJsonObject &/*message*/) Q_DECL_OVERRIDE + void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE { + mMessagesSent.push_back(message); } +private: + QVector mMessagesSent; }; class TestObject : public QObject @@ -296,6 +305,8 @@ private slots: void testPassWrappedObjectBack(); void testInfiniteRecursion(); void testAsyncObject(); + void testDeletionDuringMethodInvocation_data(); + void testDeletionDuringMethodInvocation(); void benchClassInfo(); void benchInitializeClients(); -- cgit v1.2.1 From 6d51090572d843d781376d0128dddb3c9a0e307c Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Thu, 28 Dec 2017 13:43:03 +0200 Subject: Fix TestWebChannel::testAsyncObject If signal is emitted directly, QSignalSpy::wait() is called too late. In that case the correct information about emitted signal can be checked with QSignalSpy::count(). Task-number: QTBUG-63152 Change-Id: I0c3da52ab17f9138ad1a7a17f5065b8a87911b8f (cherry picked from commit d2f9396f048ef8fdd494626d92b3d7106fb10304) Reviewed-by: Jani Heikkinen --- tests/auto/webchannel/tst_webchannel.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index f214b7e..4309647 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -770,6 +770,11 @@ void TestWebChannel::testInfiniteRecursion() void TestWebChannel::testAsyncObject() { + auto waitForSignal = [] (QSignalSpy& spy) { + for (int i=0; (i<5) && (spy.count() == 0); i++) + spy.wait(1000); + }; + QWebChannel channel; channel.connectTo(m_dummyTransport); @@ -788,7 +793,8 @@ void TestWebChannel::testAsyncObject() { QSignalSpy spy(&obj, &TestObject::propChanged); channel.d_func()->publisher->invokeMethod(&obj, method, args); - QVERIFY(spy.wait()); + waitForSignal(spy); + QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).at(0).toString(), args.at(0).toString()); } @@ -804,10 +810,13 @@ void TestWebChannel::testAsyncObject() { QSignalSpy spy(&obj, &TestObject::replay); QMetaObject::invokeMethod(&obj, "fire"); - QVERIFY(spy.wait()); + waitForSignal(spy); + QCOMPARE(spy.count(), 1); channel.deregisterObject(&obj); QMetaObject::invokeMethod(&obj, "fire"); - QVERIFY(spy.wait()); + spy.takeFirst(); + waitForSignal(spy); + QCOMPARE(spy.count(), 1); } thread.quit(); -- cgit v1.2.1 From 2661593df95b8a5a56af0a8fd22af5be7f7ea8fb Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Fri, 29 Dec 2017 09:51:58 +0200 Subject: Clean up TestWebChannel::testAsyncObject Task-number: QTBUG-63152 Change-Id: I22df2328f0ab6d2a2d12458dbeaec68bfbe36985 (cherry picked from commit 5a9dd81f260f320b5af108c1a6b3d0b82a04f15d) Reviewed-by: Jani Heikkinen --- tests/auto/webchannel/tst_webchannel.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 4309647..a44220f 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -770,11 +770,6 @@ void TestWebChannel::testInfiniteRecursion() void TestWebChannel::testAsyncObject() { - auto waitForSignal = [] (QSignalSpy& spy) { - for (int i=0; (i<5) && (spy.count() == 0); i++) - spy.wait(1000); - }; - QWebChannel channel; channel.connectTo(m_dummyTransport); @@ -793,8 +788,7 @@ void TestWebChannel::testAsyncObject() { QSignalSpy spy(&obj, &TestObject::propChanged); channel.d_func()->publisher->invokeMethod(&obj, method, args); - waitForSignal(spy); - QCOMPARE(spy.count(), 1); + QTRY_COMPARE(spy.count(), 1); QCOMPARE(spy.at(0).at(0).toString(), args.at(0).toString()); } @@ -810,13 +804,10 @@ void TestWebChannel::testAsyncObject() { QSignalSpy spy(&obj, &TestObject::replay); QMetaObject::invokeMethod(&obj, "fire"); - waitForSignal(spy); - QCOMPARE(spy.count(), 1); + QTRY_COMPARE(spy.count(), 1); channel.deregisterObject(&obj); QMetaObject::invokeMethod(&obj, "fire"); - spy.takeFirst(); - waitForSignal(spy); - QCOMPARE(spy.count(), 1); + QTRY_COMPARE(spy.count(), 2); } thread.quit(); -- cgit v1.2.1