Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libqt5-qtwebchannel for openSUSE:Factory checked in at 2022-01-25 17:35:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libqt5-qtwebchannel (Old) and /work/SRC/openSUSE:Factory/.libqt5-qtwebchannel.new.1938 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libqt5-qtwebchannel" Tue Jan 25 17:35:43 2022 rev:29 rq:948156 version:5.15.2+kde5 Changes: -------- --- /work/SRC/openSUSE:Factory/libqt5-qtwebchannel/libqt5-qtwebchannel.changes 2021-06-27 18:59:38.680320417 +0200 +++ /work/SRC/openSUSE:Factory/.libqt5-qtwebchannel.new.1938/libqt5-qtwebchannel.changes 2022-01-25 17:36:28.094169824 +0100 @@ -1,0 +2,8 @@ +Fri Jan 21 08:14:38 UTC 2022 - Fabian Vogt <fab...@ritter-vogt.de> + +- Update to version 5.15.2+kde5: + * QMetaObjectPublisher: Never send stale queued messages + * Handle per-transport client idle status + * Handle signals in the registered object's thread + +------------------------------------------------------------------- Old: ---- qtwebchannel-everywhere-src-5.15.2+kde2.obscpio New: ---- qtwebchannel-everywhere-src-5.15.2+kde5.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libqt5-qtwebchannel.spec ++++++ --- /var/tmp/diff_new_pack.zkgsCO/_old 2022-01-25 17:36:28.838164700 +0100 +++ /var/tmp/diff_new_pack.zkgsCO/_new 2022-01-25 17:36:28.842164672 +0100 @@ -23,7 +23,7 @@ %define so_version 5.15.2 %define tar_version qtwebchannel-everywhere-src-%{version} Name: libqt5-qtwebchannel -Version: 5.15.2+kde2 +Version: 5.15.2+kde5 Release: 0 Summary: Qt 5 WebChannel Addon License: LGPL-3.0-only OR (GPL-2.0-only OR GPL-3.0-or-later) ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.zkgsCO/_old 2022-01-25 17:36:28.894164314 +0100 +++ /var/tmp/diff_new_pack.zkgsCO/_new 2022-01-25 17:36:28.898164286 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://invent.kde.org/qt/qt/qtwebchannel.git</param> - <param name="changesrevision">47be9a51b01d9fd9e7f6dca81e98d4eedcec6d38</param></service></servicedata> + <param name="changesrevision">fa8b07105b5e274daaa8adcc129fa4aa0447f9f7</param></service></servicedata> (No newline at EOF) ++++++ qtwebchannel-everywhere-src-5.15.2+kde2.obscpio -> qtwebchannel-everywhere-src-5.15.2+kde5.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/.gitignore new/qtwebchannel-everywhere-src-5.15.2+kde5/.gitignore --- old/qtwebchannel-everywhere-src-5.15.2+kde2/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/.gitignore 2021-12-17 12:10:52.000000000 +0100 @@ -0,0 +1 @@ +build*/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/0001-Revert-Bump-version.patch new/qtwebchannel-everywhere-src-5.15.2+kde5/0001-Revert-Bump-version.patch --- old/qtwebchannel-everywhere-src-5.15.2+kde2/0001-Revert-Bump-version.patch 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/0001-Revert-Bump-version.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ -From f3471e79d65b83de45431cfc5b42b65ba59d4644 Mon Sep 17 00:00:00 2001 -From: Fabian Vogt <fv...@suse.de> -Date: Tue, 22 Jun 2021 20:59:30 +0200 -Subject: [PATCH] Revert "Bump version" - -This reverts commit 0159fb80446f2fc472a2391de9fc83f55ca2d50e. ---- - .qmake.conf | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/.qmake.conf b/.qmake.conf -index 31592a4..b8b8ec0 100644 ---- a/.qmake.conf -+++ b/.qmake.conf -@@ -1,4 +1,4 @@ - load(qt_build_config) - CONFIG += warning_clean - --MODULE_VERSION = 5.15.3 -+MODULE_VERSION = 5.15.2 --- -2.20.1 - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/src/webchannel/qmetaobjectpublisher.cpp new/qtwebchannel-everywhere-src-5.15.2+kde5/src/webchannel/qmetaobjectpublisher.cpp --- old/qtwebchannel-everywhere-src-5.15.2+kde2/src/webchannel/qmetaobjectpublisher.cpp 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/src/webchannel/qmetaobjectpublisher.cpp 2021-12-17 12:10:52.000000000 +0100 @@ -186,8 +186,6 @@ QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel) : QObject(webChannel) , webChannel(webChannel) - , signalHandler(this) - , clientIsIdle(false) , blockUpdates(false) , propertyUpdatesInitialized(false) { @@ -301,17 +299,17 @@ return data; } -void QMetaObjectPublisher::setClientIsIdle(bool isIdle) +void QMetaObjectPublisher::setClientIsIdle(bool isIdle, QWebChannelAbstractTransport *transport) { - if (clientIsIdle == isIdle) { - return; - } - clientIsIdle = isIdle; - if (!isIdle && timer.isActive()) { - timer.stop(); - } else if (isIdle && !timer.isActive()) { - timer.start(PROPERTY_UPDATE_INTERVAL, this); - } + transportState[transport].clientIsIdle = isIdle; + if (isIdle) + sendEnqueuedPropertyUpdates(transport); +} + +bool QMetaObjectPublisher::isClientIdle(QWebChannelAbstractTransport *transport) +{ + auto found = transportState.find(transport); + return found != transportState.end() && found.value().clientIsIdle; } QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport *transport) @@ -333,6 +331,7 @@ void QMetaObjectPublisher::initializePropertyUpdates(const QObject *const object, const QJsonObject &objectInfo) { + auto *signalHandler = signalHandlerFor(object); foreach (const QJsonValue &propertyInfoVar, objectInfo[KEY_PROPERTIES].toArray()) { const QJsonArray &propertyInfo = propertyInfoVar.toArray(); if (propertyInfo.size() < 2) { @@ -353,19 +352,19 @@ // Only connect for a property update once if (connectedProperties.isEmpty()) { - signalHandler.connectTo(object, signalIndex); + signalHandler->connectTo(object, signalIndex); } connectedProperties.insert(propertyIndex); } // also always connect to destroyed signal - signalHandler.connectTo(object, s_destroyedSignalIndex); + signalHandler->connectTo(object, s_destroyedSignalIndex); } void QMetaObjectPublisher::sendPendingPropertyUpdates() { - if (blockUpdates || !clientIsIdle || pendingPropertyUpdates.isEmpty()) { + if (blockUpdates) { return; } @@ -415,18 +414,19 @@ // data does not contain specific updates if (!data.isEmpty()) { - setClientIsIdle(false); - message[KEY_DATA] = data; - broadcastMessage(message); + enqueueBroadcastMessage(message); } // send every property update which is not supposed to be broadcasted const QHash<QWebChannelAbstractTransport*, QJsonArray>::const_iterator suend = specificUpdates.constEnd(); for (QHash<QWebChannelAbstractTransport*, QJsonArray>::const_iterator it = specificUpdates.constBegin(); it != suend; ++it) { message[KEY_DATA] = it.value(); - it.key()->sendMessage(message); + enqueueMessage(message, it.key()); } + + for (auto state = transportState.begin(); state != transportState.end(); ++state) + sendEnqueuedPropertyUpdates(state.key()); } QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const QMetaMethod &method, @@ -572,7 +572,7 @@ } } else { pendingPropertyUpdates[object][signalIndex] = arguments; - if (clientIsIdle && !blockUpdates && !timer.isActive()) { + if (!blockUpdates && !timer.isActive()) { timer.start(PROPERTY_UPDATE_INTERVAL, this); } } @@ -590,7 +590,7 @@ // only remove from handler when we initialized the property updates // cf: https://bugreports.qt.io/browse/QTBUG-60250 if (propertyUpdatesInitialized) { - signalHandler.remove(object); + signalHandlerFor(object)->remove(object); signalToPropertyMap.remove(object); } pendingPropertyUpdates.remove(object); @@ -852,6 +852,52 @@ } } +void QMetaObjectPublisher::enqueueBroadcastMessage(const QJsonObject &message) +{ + if (webChannel->d_func()->transports.isEmpty()) { + qWarning("QWebChannel is not connected to any transports, cannot send message: %s", + QJsonDocument(message).toJson().constData()); + return; + } + + for (auto *transport : webChannel->d_func()->transports) { + auto &state = transportState[transport]; + state.queuedMessages.append(message); + } +} + +void QMetaObjectPublisher::enqueueMessage(const QJsonObject &message, + QWebChannelAbstractTransport *transport) +{ + auto &state = transportState[transport]; + state.queuedMessages.append(message); +} + +void QMetaObjectPublisher::sendEnqueuedPropertyUpdates(QWebChannelAbstractTransport *transport) +{ + auto found = transportState.find(transport); + if (found != transportState.end() && found.value().clientIsIdle + && !found.value().queuedMessages.isEmpty()) { + + // If the client is connected with an in-process transport, it can + // happen that a message triggers a subsequent property change. In + // that case, we need to ensure that the queued messages have already + // been cleared; otherwise the recursive call will send everythig again. + // Case in point: The qmlwebchannel tests fail if we don't clear the + // queued messages before sending them out. + // For that same reason set the client to "busy" (aka non-idle) just + // right before sending out the messages; otherwise a potential + // "Idle" type message will not correctly restore the Idle state. + const auto messages = std::move(found.value().queuedMessages); + Q_ASSERT(found.value().queuedMessages.isEmpty()); + found.value().clientIsIdle = false; + + for (const auto &message : messages) { + transport->sendMessage(message); + } + } +} + void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport) { if (!webChannel->d_func()->transports.contains(transport)) { @@ -866,7 +912,7 @@ const MessageType type = toType(message.value(KEY_TYPE)); if (type == TypeIdle) { - setClientIsIdle(true); + setClientIsIdle(true, transport); } else if (type == TypeInit) { if (!message.contains(KEY_ID)) { qWarning("JSON message object is missing the id property: %s", @@ -913,9 +959,9 @@ return; transport->sendMessage(createResponse(message.value(KEY_ID), wrapResult(result, transport))); } else if (type == TypeConnectToSignal) { - signalHandler.connectTo(object, message.value(KEY_SIGNAL).toInt(-1)); + signalHandlerFor(object)->connectTo(object, message.value(KEY_SIGNAL).toInt(-1)); } else if (type == TypeDisconnectFromSignal) { - signalHandler.disconnectFrom(object, message.value(KEY_SIGNAL).toInt(-1)); + signalHandlerFor(object)->disconnectFrom(object, message.value(KEY_SIGNAL).toInt(-1)); } else if (type == TypeSetProperty) { setProperty(object, message.value(KEY_PROPERTY).toInt(-1), message.value(KEY_VALUE)); @@ -931,6 +977,7 @@ blockUpdates = block; if (!blockUpdates) { + timer.start(PROPERTY_UPDATE_INTERVAL, this); sendPendingPropertyUpdates(); } else if (timer.isActive()) { timer.stop(); @@ -948,4 +995,15 @@ } } +SignalHandler<QMetaObjectPublisher> *QMetaObjectPublisher::signalHandlerFor(const QObject *object) +{ + auto thread = object->thread(); + auto it = signalHandlers.find(thread); + if (it == signalHandlers.end()) { + it = signalHandlers.emplace(thread, this).first; + it->second.moveToThread(thread); + } + return &it->second; +} + QT_END_NAMESPACE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/src/webchannel/qmetaobjectpublisher_p.h new/qtwebchannel-everywhere-src-5.15.2+kde5/src/webchannel/qmetaobjectpublisher_p.h --- old/qtwebchannel-everywhere-src-5.15.2+kde2/src/webchannel/qmetaobjectpublisher_p.h 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/src/webchannel/qmetaobjectpublisher_p.h 2021-12-17 12:10:52.000000000 +0100 @@ -59,6 +59,9 @@ #include <QBasicTimer> #include <QPointer> #include <QJsonObject> +#include <QQueue> + +#include <unordered_map> #include "qwebchannelglobal.h" @@ -110,16 +113,35 @@ void broadcastMessage(const QJsonObject &message) const; /** + * Enqueue the given @p message to all known transports. + */ + void enqueueBroadcastMessage(const QJsonObject &message); + + /** + * Enqueue the given @p message to @p transport. + */ + void enqueueMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport); + + /** + * If client for given @p transport is idle, send queued messaged to @p transport and then mark + * the client as not idle. + */ + void sendEnqueuedPropertyUpdates(QWebChannelAbstractTransport *transport); + + /** * Serialize the QMetaObject of @p object and return it in JSON form. */ QJsonObject classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport); /** - * Set the client to idle or busy, based on the value of @p isIdle. - * - * When the value changed, start/stop the property update timer accordingly. + * Set the client to idle or busy for a single @p transport, based on the value of @p isIdle. + */ + void setClientIsIdle(bool isIdle, QWebChannelAbstractTransport *transport); + + /** + * Check that client is idle for @p transport. */ - void setClientIsIdle(bool isIdle); + bool isClientIdle(QWebChannelAbstractTransport *transport); /** * Initialize clients by sending them the class information of the registered objects. @@ -272,10 +294,18 @@ friend class TestWebChannel; QWebChannel *webChannel; - SignalHandler<QMetaObjectPublisher> signalHandler; + std::unordered_map<const QThread*, SignalHandler<QMetaObjectPublisher>> signalHandlers; + SignalHandler<QMetaObjectPublisher> *signalHandlerFor(const QObject *object); - // true when the client is idle, false otherwise - bool clientIsIdle; + struct TransportState + { + TransportState() : clientIsIdle(false) { } + // true when the client is idle, false otherwise + bool clientIsIdle; + // messages to send + QQueue<QJsonObject> queuedMessages; + }; + QHash<QWebChannelAbstractTransport *, TransportState> transportState; // true when no property updates should be sent, false otherwise bool blockUpdates; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/src/webchannel/signalhandler_p.h new/qtwebchannel-everywhere-src-5.15.2+kde5/src/webchannel/signalhandler_p.h --- old/qtwebchannel-everywhere-src-5.15.2+kde2/src/webchannel/signalhandler_p.h 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/src/webchannel/signalhandler_p.h 2021-12-17 12:10:52.000000000 +0100 @@ -56,6 +56,7 @@ #include <QVector> #include <QMetaMethod> #include <QDebug> +#include <QThread> QT_BEGIN_NAMESPACE @@ -71,6 +72,7 @@ template<class Receiver> class SignalHandler : public QObject { + Q_DISABLE_COPY(SignalHandler) public: SignalHandler(Receiver *receiver, QObject *parent = 0); @@ -268,6 +270,7 @@ if (call == QMetaObject::InvokeMetaMethod) { const QObject *object = sender(); Q_ASSERT(object); + Q_ASSERT(QThread::currentThread() == object->thread()); Q_ASSERT(senderSignalIndex() == methodId); Q_ASSERT(m_connectionsCounter.contains(object)); Q_ASSERT(m_connectionsCounter.value(object).contains(methodId)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/tests/auto/qml/testwebchannel.cpp new/qtwebchannel-everywhere-src-5.15.2+kde5/tests/auto/qml/testwebchannel.cpp --- old/qtwebchannel-everywhere-src-5.15.2+kde2/tests/auto/qml/testwebchannel.cpp 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/tests/auto/qml/testwebchannel.cpp 2021-12-17 12:10:52.000000000 +0100 @@ -46,7 +46,11 @@ bool TestWebChannel::clientIsIdle() const { - return QWebChannel::d_func()->publisher->clientIsIdle; + for (auto *transport : QWebChannel::d_func()->transports) { + if (QWebChannel::d_func()->publisher->isClientIdle(transport)) + return true; + } + return false; } QT_END_NAMESPACE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/tests/auto/webchannel/tst_webchannel.cpp new/qtwebchannel-everywhere-src-5.15.2+kde5/tests/auto/webchannel/tst_webchannel.cpp --- old/qtwebchannel-everywhere-src-5.15.2+kde2/tests/auto/webchannel/tst_webchannel.cpp 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/tests/auto/webchannel/tst_webchannel.cpp 2021-12-17 12:10:52.000000000 +0100 @@ -785,7 +785,7 @@ DummyTransport *dummyTransport = new DummyTransport(this); channel.connectTo(dummyTransport); channel.d_func()->publisher->initializeClient(dummyTransport); - channel.d_func()->publisher->setClientIsIdle(true); + channel.d_func()->publisher->setClientIsIdle(true, dummyTransport); QCOMPARE(channel.d_func()->publisher->transportedWrappedObjects.size(), 0); @@ -943,8 +943,6 @@ void TestWebChannel::testAsyncObject() { - QSKIP("This test is broken. See QTBUG-80729"); - QWebChannel channel; channel.connectTo(m_dummyTransport); @@ -990,6 +988,50 @@ thread.wait(); } +void TestWebChannel::testPropertyMultipleTransports() +{ + DummyTransport transport1; + DummyTransport transport2; + + QWebChannel channel; + QMetaObjectPublisher *publisher = channel.d_func()->publisher; + + TestObject testObj; + testObj.setObjectName("testObject"); + channel.registerObject(testObj.objectName(), &testObj); + channel.connectTo(&transport1); + channel.connectTo(&transport2); + + testObj.setProp("Hello"); + + publisher->initializeClient(&transport1); + publisher->initializeClient(&transport2); + publisher->setClientIsIdle(true, &transport1); + QCOMPARE(publisher->isClientIdle(&transport1), true); + QCOMPARE(publisher->isClientIdle(&transport2), false); + QVERIFY(transport1.messagesSent().isEmpty()); + QVERIFY(transport2.messagesSent().isEmpty()); + + testObj.setProp("World"); + QTRY_COMPARE_WITH_TIMEOUT(transport1.messagesSent().size(), 1u, 2000); + QCOMPARE(transport2.messagesSent().size(), 0u); + publisher->setClientIsIdle(true, &transport2); + QTRY_COMPARE_WITH_TIMEOUT(transport2.messagesSent().size(), 1u, 2000); + QCOMPARE(publisher->isClientIdle(&transport1), false); + QCOMPARE(publisher->isClientIdle(&transport2), false); + + testObj.setProp("!!!"); + publisher->setClientIsIdle(true, &transport2); + QCOMPARE(publisher->isClientIdle(&transport2), true); + QCOMPARE(publisher->isClientIdle(&transport1), false); + QTRY_COMPARE_WITH_TIMEOUT(transport2.messagesSent().size(), 2u, 2000); + QCOMPARE(transport1.messagesSent().size(), 1u); + publisher->setClientIsIdle(true, &transport1); + QTRY_COMPARE_WITH_TIMEOUT(transport1.messagesSent().size(), 2u, 2000); + QCOMPARE(publisher->isClientIdle(&transport1), false); + QCOMPARE(publisher->isClientIdle(&transport2), false); +} + class FunctionWrapper : public QObject { Q_OBJECT @@ -1082,7 +1124,7 @@ publisher->propertyUpdatesInitialized = false; publisher->signalToPropertyMap.clear(); - publisher->signalHandler.clear(); + publisher->signalHandlers.clear(); } } @@ -1107,7 +1149,7 @@ obj->change(); } - channel.d_func()->publisher->clientIsIdle = true; + channel.d_func()->publisher->setClientIsIdle(true, m_dummyTransport); channel.d_func()->publisher->sendPendingPropertyUpdates(); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qtwebchannel-everywhere-src-5.15.2+kde2/tests/auto/webchannel/tst_webchannel.h new/qtwebchannel-everywhere-src-5.15.2+kde5/tests/auto/webchannel/tst_webchannel.h --- old/qtwebchannel-everywhere-src-5.15.2+kde2/tests/auto/webchannel/tst_webchannel.h 2020-10-28 14:07:52.000000000 +0100 +++ new/qtwebchannel-everywhere-src-5.15.2+kde5/tests/auto/webchannel/tst_webchannel.h 2021-12-17 12:10:52.000000000 +0100 @@ -348,6 +348,7 @@ void testJsonToVariant(); void testInfiniteRecursion(); void testAsyncObject(); + void testPropertyMultipleTransports(); void testDeletionDuringMethodInvocation_data(); void testDeletionDuringMethodInvocation(); ++++++ qtwebchannel-everywhere-src.obsinfo ++++++ --- /var/tmp/diff_new_pack.zkgsCO/_old 2022-01-25 17:36:29.086162992 +0100 +++ /var/tmp/diff_new_pack.zkgsCO/_new 2022-01-25 17:36:29.090162964 +0100 @@ -1,6 +1,5 @@ name: qtwebchannel-everywhere-src -version: 5.15.2+kde2 -mtime: 1603890472 -commit: 47be9a51b01d9fd9e7f6dca81e98d4eedcec6d38 - +version: 5.15.2+kde5 +mtime: 1639739452 +commit: fa8b07105b5e274daaa8adcc129fa4aa0447f9f7