Use signal/slot for passing messages through QQmlDebugServer
authorUlf Hermann <ulf.hermann@theqtcompany.com>
Mon, 13 Jul 2015 13:56:25 +0000 (15:56 +0200)
committerUlf Hermann <ulf.hermann@theqtcompany.com>
Fri, 31 Jul 2015 06:44:13 +0000 (06:44 +0000)
This results in much cleaner code than the previous implementation
using QMetaObject::invokeMethod().

We have to use read locks now for adding and removing engines, as we
should have done already before. If a condition is waiting on a write
lock you cannot acquire a read lock from another thread. So, if we kept
the write locks we wouldn't be able to receive messages while the engines
are waiting.

Change-Id: Icfe641601dec2f8d7181ae579146ed603d57a4c2
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
15 files changed:
src/plugins/qmltooling/shared/abstractviewinspector.cpp
src/qml/debugger/qdebugmessageservice.cpp
src/qml/debugger/qqmldebugconnector_p.h
src/qml/debugger/qqmldebugserver.cpp
src/qml/debugger/qqmldebugservice.cpp
src/qml/debugger/qqmldebugservice_p.h
src/qml/debugger/qqmlenginecontrolservice.cpp
src/qml/debugger/qqmlenginedebugservice.cpp
src/qml/debugger/qqmlinspectorservice.cpp
src/qml/debugger/qqmlinspectorservice_p.h
src/qml/debugger/qqmlprofilerservice.cpp
src/qml/debugger/qv4debugservice.cpp
tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
tests/auto/qml/debugger/shared/qqmldebugtestservice.h

index b23cff9a782935f47aba5956b114c4ec49596570..c32a297d6a75c679860b0190d3cff7634ab5915f 100644 (file)
@@ -266,7 +266,7 @@ void AbstractViewInspector::onQmlObjectDestroyed(QObject *object)
     QQmlDebugStream rs(&response, QIODevice::WriteOnly);
     rs << QByteArray(RESPONSE) << ids.first << true << ids.second;
 
-    m_debugService->sendMessage(response);
+    emit m_debugService->messageToClient(m_debugService->name(), response);
 }
 
 void AbstractViewInspector::handleMessage(const QByteArray &message)
@@ -360,7 +360,7 @@ void AbstractViewInspector::handleMessage(const QByteArray &message)
     QByteArray response;
     QQmlDebugStream rs(&response, QIODevice::WriteOnly);
     rs << QByteArray(RESPONSE) << requestId << success;
-    m_debugService->sendMessage(response);
+    emit m_debugService->messageToClient(m_debugService->name(), response);
 }
 
 void AbstractViewInspector::sendCurrentObjects(const QList<QObject*> &objects)
@@ -376,7 +376,7 @@ void AbstractViewInspector::sendCurrentObjects(const QList<QObject*> &objects)
         debugIds << QQmlDebugService::idForObject(object);
     ds << debugIds;
 
-    m_debugService->sendMessage(message);
+    emit m_debugService->messageToClient(m_debugService->name(), message);
 }
 
 void AbstractViewInspector::sendQmlFileReloaded(bool success)
@@ -389,7 +389,7 @@ void AbstractViewInspector::sendQmlFileReloaded(bool success)
     QQmlDebugStream rs(&response, QIODevice::WriteOnly);
     rs << QByteArray(RESPONSE) << m_reloadEventId << success;
 
-    m_debugService->sendMessage(response);
+    emit m_debugService->messageToClient(m_debugService->name(), response);
 }
 
 QString AbstractViewInspector::idStringForObject(QObject *obj) const
index 4483cf1573449585222b41e69756318f6a7d8cb7..88ef9eb96ca7536b50cc70d47f08526b2f14be78 100644 (file)
@@ -93,7 +93,7 @@ void QDebugMessageService::sendDebugMessage(QtMsgType type,
     ws << QString::fromLatin1(ctxt.file).toUtf8();
     ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8();
 
-    sendMessage(message);
+    emit messageToClient(name(), message);
     if (d->oldMsgHandler)
         (*d->oldMsgHandler)(type, ctxt, buf);
 }
index e7b8b98c66a026c0dd0761f2c887244dd2e321c8..30283eae6709e30edee324b6e73b399794b065e4 100644 (file)
@@ -70,7 +70,6 @@ public:
     virtual bool addService(QQmlDebugService *service) = 0;
     virtual bool removeService(QQmlDebugService *service) = 0;
 
-    virtual void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages) = 0;
     virtual bool open(const QVariantHash &configuration = QVariantHash()) = 0;
 };
 
index c48424f0fd0a6ce679a09ff96df49e85c8891c9c..a2cb8fd5a1bdd8ddd4682c88c884c8081ea998c6 100644 (file)
@@ -102,7 +102,6 @@ public:
     bool open(const QVariantHash &configuration);
 
     void receiveMessage(const QByteArray &message);
-    void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages);
 
     template<class Action>
     bool enable(Action action);
@@ -110,7 +109,8 @@ public:
 
 private slots:
     void wakeEngine(QQmlEngine *engine);
-    void sendMessages(const QList<QByteArray> &messages);
+    void sendMessage(const QString &name, const QByteArray &message);
+    void sendMessages(const QString &name, const QList<QByteArray> &messages);
     void changeServiceState(const QString &serviceName, QQmlDebugService::State state);
     void removeThread();
 
@@ -623,15 +623,6 @@ void QQmlDebugServerImpl::changeServiceState(const QString &serviceName,
     m_changeServiceStateCalls.deref();
 }
 
-void QQmlDebugServerImpl::sendMessages(const QList<QByteArray> &messages)
-{
-    // to be executed in debugger thread
-    Q_ASSERT(QThread::currentThread() == thread());
-
-    if (m_connection)
-        m_connection->send(messages);
-}
-
 void QQmlDebugServerImpl::removeThread()
 {
     Q_ASSERT(m_thread->isFinished());
@@ -690,6 +681,11 @@ bool QQmlDebugServerImpl::addService(QQmlDebugService *service)
     // to be executed before thread starts
     Q_ASSERT(!m_thread);
 
+    connect(service, SIGNAL(messageToClient(QString,QByteArray)),
+            this, SLOT(sendMessage(QString,QByteArray)));
+    connect(service, SIGNAL(messagesToClient(QString,QList<QByteArray>)),
+            this, SLOT(sendMessages(QString,QList<QByteArray>)));
+
     connect(service, SIGNAL(attachedToEngine(QQmlEngine*)),
             this, SLOT(wakeEngine(QQmlEngine*)), Qt::QueuedConnection);
     connect(service, SIGNAL(detachedFromEngine(QQmlEngine*)),
@@ -720,24 +716,46 @@ bool QQmlDebugServerImpl::removeService(QQmlDebugService *service)
 
     if (!service || !m_plugins.contains(service->name()))
         return false;
+
+    disconnect(service, SIGNAL(messagesToClient(QString,QList<QByteArray>)),
+               this, SLOT(sendMessages(QString,QList<QByteArray>)));
+    disconnect(service, SIGNAL(messageToClient(QString,QByteArray)),
+               this, SLOT(sendMessage(QString,QByteArray)));
+
     m_plugins.remove(service->name());
 
     return true;
 }
 
-void QQmlDebugServerImpl::sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages)
+void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message)
 {
-    QList<QByteArray> prefixedMessages;
-    prefixedMessages.reserve(messages.count());
-    foreach (const QByteArray &message, messages) {
-        QByteArray prefixed;
-        QQmlDebugStream out(&prefixed, QIODevice::WriteOnly);
-        out << service->name() << message;
-        prefixedMessages << prefixed;
-    }
+    sendMessages(name, QList<QByteArray>() << message);
+}
 
-    QMetaObject::invokeMethod(this, "sendMessages", Qt::QueuedConnection,
-                              Q_ARG(QList<QByteArray>, prefixedMessages));
+void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages)
+{
+    // to be executed in debugger thread
+    Q_ASSERT(QThread::currentThread() == thread());
+
+    if (!m_connection)
+        return;
+
+    if (!name.isEmpty()) {
+        if (!m_clientPlugins.contains(name))
+            return;
+        QList<QByteArray> prefixedMessages;
+        prefixedMessages.reserve(messages.count());
+        foreach (const QByteArray &message, messages) {
+            QByteArray prefixed;
+            QQmlDebugStream out(&prefixed, QIODevice::WriteOnly);
+            out << name << message;
+            prefixedMessages << prefixed;
+        }
+
+        m_connection->send(prefixedMessages);
+    } else {
+        m_connection->send(messages);
+    }
 }
 
 template<class Action>
index 44f42af5e42c74ca7c3dc1933b2c976196e06011..edebf7a8cbe26fa31bbe423d6afbcf1ff9dd107e 100644 (file)
@@ -174,20 +174,6 @@ const QHash<int, QObject *> &QQmlDebugService::objectsForIds()
     return objectReferenceHash()->ids;
 }
 
-void QQmlDebugService::sendMessage(const QByteArray &message)
-{
-    sendMessages(QList<QByteArray>() << message);
-}
-
-void QQmlDebugService::sendMessages(const QList<QByteArray> &messages)
-{
-    if (state() != Enabled)
-        return;
-
-    if (QQmlDebugConnector *inst = QQmlDebugConnector::instance())
-        inst->sendMessages(this, messages);
-}
-
 void QQmlDebugService::stateAboutToBeChanged(State)
 {
 }
index e17c02b477748c5004398f174b1cd494abdcfb70..311ce3e3558ce995d1143dbe2144539e7f51cae7 100644 (file)
@@ -81,9 +81,6 @@ public:
     virtual void engineAdded(QQmlEngine *);
     virtual void engineRemoved(QQmlEngine *);
 
-    void sendMessage(const QByteArray &);
-    void sendMessages(const QList<QByteArray> &);
-
     static const QHash<int, QObject *> &objectsForIds();
     static int idForObject(QObject *);
     static QObject *objectForId(int id) { return objectsForIds().value(id); }
@@ -97,6 +94,9 @@ protected:
 signals:
     void attachedToEngine(QQmlEngine *);
     void detachedFromEngine(QQmlEngine *);
+
+    void messageToClient(const QString &name, const QByteArray &message);
+    void messagesToClient(const QString &name, const QList<QByteArray> &messages);
 };
 
 class Q_QML_PRIVATE_EXPORT QQmlDebugStream : public QDataStream
index ed3fc9e1de656da6d311e51a405fbc6c53d98bd0..eaf948426df9066ce3a2ee1be37ce38a3e102709 100644 (file)
@@ -117,7 +117,7 @@ void QQmlEngineControlService::sendMessage(QQmlEngineControlService::MessageType
     QByteArray message;
     QQmlDebugStream d(&message, QIODevice::WriteOnly);
     d << type << idForObject(engine);
-    QQmlDebugService::sendMessage(message);
+    emit messageToClient(name(), message);
 }
 
 void QQmlEngineControlService::stateChanged(State)
index ad8f4fb15a2a3b82c60302d48e8d92f094cd63c0..1d481d9edaf4b2fa5b3e46dab635bb4312e15e42 100644 (file)
@@ -626,7 +626,7 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message)
         rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok;
 
     }
-    sendMessage(reply);
+    emit messageToClient(name(), reply);
 }
 
 bool QQmlEngineDebugService::setBinding(int objectId,
@@ -783,7 +783,7 @@ void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaPr
 
     rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
 
-    sendMessage(reply);
+    emit messageToClient(name(), reply);
 }
 
 void QQmlEngineDebugService::engineAboutToBeAdded(QQmlEngine *engine)
@@ -818,7 +818,7 @@ void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object)
 
     //unique queryId -1
     rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId << parentId;
-    sendMessage(reply);
+    emit messageToClient(name(), reply);
 }
 
 void QQmlEngineDebugService::setStatesDelegate(QQmlDebugStatesDelegate *delegate)
index e3c7ad7d557747f352c2ce02144fc3c1ac3af0d0..c6ee8e4d52523bc939de09584d7e84395852f5a0 100644 (file)
@@ -73,14 +73,6 @@ void QQmlInspectorService::removeView(QObject *view)
     updateState();
 }
 
-void QQmlInspectorService::sendMessage(const QByteArray &message)
-{
-    if (state() != Enabled)
-        return;
-
-    QQmlDebugService::sendMessage(message);
-}
-
 void QQmlInspectorService::stateChanged(State /*state*/)
 {
     QMetaObject::invokeMethod(this, "updateState", Qt::QueuedConnection);
index f49c36aacb368ec3e8e9ffbef5f65f9c1265d925..e69575788aa899bb3c07556ef347e8653cdf7983 100644 (file)
@@ -66,8 +66,6 @@ public:
     void addView(QObject *);
     void removeView(QObject *);
 
-    void sendMessage(const QByteArray &message);
-
 protected:
     virtual void stateChanged(State state);
     virtual void messageReceived(const QByteArray &);
index e48771090ea353011263a3fb1c1c6ec09d4c807b..62eae0ddd80d242cb10503266ae81f12e92026fb 100644 (file)
@@ -245,7 +245,7 @@ void QQmlProfilerService::startProfiling(QQmlEngine *engine, quint64 features)
         }
     }
 
-    QQmlDebugService::sendMessage(message);
+    emit messageToClient(name(), message);
 }
 
 /*!
@@ -334,7 +334,7 @@ void QQmlProfilerService::sendMessages()
     ds << (qint64)-1 << (int)Complete;
     messages << data;
 
-    QQmlDebugService::sendMessages(messages);
+    emit messagesToClient(name(), messages);
 }
 
 void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
index 06772739824974f3d251f16a9e3b7122d9dffbe5..81d4c7b70a1e48a3c634fa22873b7d2ba21b6fda 100644 (file)
@@ -373,7 +373,7 @@ public:
 
         TRACE_PROTOCOL(qDebug() << "sending response for:" << responseData.constData() << endl);
 
-        q_func()->sendMessage(packMessage("v8message", responseData));
+        emit q_func()->messageToClient(name, packMessage("v8message", responseData));
     }
 
     void processCommand(const QByteArray &command, const QByteArray &data);
@@ -1136,7 +1136,7 @@ void QV4DebugService::messageReceived(const QByteArray &message)
         TRACE_PROTOCOL(qDebug() << "... type:" << type);
 
         if (type == V4_CONNECT) {
-            sendMessage(d->packMessage(type));
+            emit messageToClient(name(), d->packMessage(type));
             stopWaiting();
         } else if (type == V4_PAUSE) {
             d->debuggerAgent.pauseAll();
@@ -1170,7 +1170,7 @@ void QV4DebugService::sendSomethingToSomebody(const char *type, int magicNumber)
     QQmlDebugStream rs(&response, QIODevice::WriteOnly);
     rs << QByteArray(type)
        << QByteArray::number(d->version) << QByteArray::number(magicNumber);
-    sendMessage(d->packMessage(type, response));
+    emit messageToClient(name(), d->packMessage(type, response));
 }
 
 void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason)
index 6ae59078f603272620fc7b77243fd2d1daaa15ca..b63c5c0a6d30b1726630bea17ae05b3d6c6e5229 100644 (file)
@@ -178,7 +178,7 @@ void tst_QQmlDebugService::sendMessage()
     QTest::ignoreMessage(QtWarningMsg,
                          "QQmlDebugService: Conflicting plugin name \"tst_QQmlDebugService\"");
     QQmlDebugTestService duplicate("tst_QQmlDebugService");
-    duplicate.sendMessage("msg");
+    emit duplicate.messageToClient(duplicate.name(), "msg");
     QTest::ignoreMessage(QtWarningMsg,
                          "QQmlDebugService: Plugin \"tst_QQmlDebugService\" is not registered.");
 }
index 94eaa2c083dfaaf817b526056408bfa7515e7214..e62aa2ce61729910158428f6429418d185f356e1 100644 (file)
@@ -42,7 +42,7 @@ QQmlDebugTestService::QQmlDebugTestService(const QString &s, float version, QObj
 void QQmlDebugTestService::messageReceived(const QByteArray &ba)
 {
     Q_ASSERT(QThread::currentThread() != thread());
-    QMetaObject::invokeMethod(this, "_sendMessage", Qt::QueuedConnection, Q_ARG(QByteArray, ba));
+    emit messageToClient(name(), ba);
 }
 
 void QQmlDebugTestService::stateAboutToBeChanged(QQmlDebugService::State)
@@ -55,8 +55,3 @@ void QQmlDebugTestService::stateChanged(State)
     Q_ASSERT(QThread::currentThread() != thread());
     emit stateHasChanged();
 }
-
-void QQmlDebugTestService::_sendMessage(const QByteArray &msg)
-{
-    QQmlDebugService::sendMessage(msg);
-}
index 7cb09798deb1bbbab0302a7f43de6a5bb5394a68..cc24f3c1195adf0f0a780c42d93c70edbe1a9f91 100644 (file)
@@ -46,9 +46,6 @@ public:
 signals:
     void stateHasChanged();
 
-private slots:
-    void _sendMessage(const QByteArray &msg);
-
 protected:
     virtual void messageReceived(const QByteArray &ba);
     virtual void stateAboutToBeChanged(State state);