aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp')
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp767
1 files changed, 0 insertions, 767 deletions
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
deleted file mode 100644
index 13d5292eb2..0000000000
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ /dev/null
@@ -1,767 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmldebugserverfactory.h"
-
-#include <private/qqmldebugserver_p.h>
-#include <private/qqmldebugserverconnection_p.h>
-#include <private/qqmldebugservice_p.h>
-#include <private/qjsengine_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qqmldebugpluginmanager_p.h>
-#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qpacketprotocol_p.h>
-#include <private/qversionedpacket_p.h>
-
-#include <QtCore/QAtomicInt>
-#include <QtCore/QDir>
-#include <QtCore/QPluginLoader>
-#include <QtCore/QStringList>
-#include <QtCore/QVector>
-#include <QtCore/qwaitcondition.h>
-
-QT_BEGIN_NAMESPACE
-
-/*
- QQmlDebug Protocol (Version 1):
-
- handshake:
- 1. Client sends
- "QDeclarativeDebugServer" 0 version pluginNames [QDataStream version]
- version: an int representing the highest protocol version the client knows
- pluginNames: plugins available on client side
- 2. Server sends
- "QDeclarativeDebugClient" 0 version pluginNames pluginVersions [QDataStream version]
- version: an int representing the highest protocol version the client & server know
- pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
- client plugin advertisement
- 1. Client sends
- "QDeclarativeDebugServer" 1 pluginNames
- server plugin advertisement (not implemented: all services are required to register before open())
- 1. Server sends
- "QDeclarativeDebugClient" 1 pluginNames pluginVersions
- plugin communication:
- Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin.
- */
-
-Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugServerConnection)
-
-const int protocolVersion = 1;
-using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>;
-
-class QQmlDebugServerImpl;
-class QQmlDebugServerThread : public QThread
-{
-public:
- QQmlDebugServerThread() : m_server(nullptr), m_portFrom(-1), m_portTo(-1) {}
-
- void setServer(QQmlDebugServerImpl *server)
- {
- m_server = server;
- }
-
- void setPortRange(int portFrom, int portTo, const QString &hostAddress)
- {
- m_pluginName = QLatin1String("QTcpServerConnection");
- m_portFrom = portFrom;
- m_portTo = portTo;
- m_hostAddress = hostAddress;
- }
-
- void setFileName(const QString &fileName)
- {
- m_pluginName = QLatin1String("QLocalClientConnection");
- m_fileName = fileName;
- }
-
- const QString &pluginName() const
- {
- return m_pluginName;
- }
-
- void run() override;
-
-private:
- QQmlDebugServerImpl *m_server;
- QString m_pluginName;
- int m_portFrom;
- int m_portTo;
- QString m_hostAddress;
- QString m_fileName;
-};
-
-class QQmlDebugServerImpl : public QQmlDebugServer
-{
- Q_OBJECT
-public:
- QQmlDebugServerImpl();
-
- bool blockingMode() const override;
-
- QQmlDebugService *service(const QString &name) const override;
-
- void addEngine(QJSEngine *engine) override;
- void removeEngine(QJSEngine *engine) override;
- bool hasEngine(QJSEngine *engine) const override;
-
- bool addService(const QString &name, QQmlDebugService *service) override;
- bool removeService(const QString &name) override;
-
- bool open(const QVariantHash &configuration) override;
- void setDevice(QIODevice *socket) override;
-
- void parseArguments();
-
- static void cleanup();
-
-private:
- friend class QQmlDebugServerThread;
- friend class QQmlDebugServerFactory;
-
- class EngineCondition {
- public:
- EngineCondition() : numServices(0), condition(new QWaitCondition) {}
-
- bool waitForServices(QMutex *locked, int numEngines);
- bool isWaiting() const { return numServices > 0; }
-
- void wake();
- private:
- int numServices;
-
- // shared pointer to allow for QHash-inflicted copying.
- QSharedPointer<QWaitCondition> condition;
- };
-
- bool canSendMessage(const QString &name);
- void doSendMessage(const QString &name, const QByteArray &message);
- void wakeEngine(QJSEngine *engine);
- 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();
- void receiveMessage();
- void protocolError();
-
- QQmlDebugServerConnection *m_connection;
- QHash<QString, QQmlDebugService *> m_plugins;
- QStringList m_clientPlugins;
- bool m_gotHello;
- bool m_blockingMode;
-
- QHash<QJSEngine *, EngineCondition> m_engineConditions;
-
- mutable QMutex m_helloMutex;
- QWaitCondition m_helloCondition;
- QQmlDebugServerThread m_thread;
- QPacketProtocol *m_protocol;
- QAtomicInt m_changeServiceStateCalls;
-};
-
-void QQmlDebugServerImpl::cleanup()
-{
- QQmlDebugServerImpl *server = static_cast<QQmlDebugServerImpl *>(
- QQmlDebugConnector::instance());
- if (!server)
- return;
-
- {
- QObject signalSource;
- for (QHash<QString, QQmlDebugService *>::ConstIterator i = server->m_plugins.constBegin();
- i != server->m_plugins.constEnd(); ++i) {
- server->m_changeServiceStateCalls.ref();
- QString key = i.key();
- // Process this in the server's thread.
- connect(&signalSource, &QObject::destroyed, server, [key, server](){
- server->changeServiceState(key, QQmlDebugService::NotConnected);
- }, Qt::QueuedConnection);
- }
- }
-
- // Wait for changeServiceState calls to finish
- // (while running an event loop because some services
- // might again defer execution of stuff in the GUI thread)
- QEventLoop loop;
- while (!server->m_changeServiceStateCalls.testAndSetOrdered(0, 0))
- loop.processEvents();
-
- // Stop the thread while the application is still there.
- server->m_thread.exit();
- server->m_thread.wait();
-}
-
-void QQmlDebugServerThread::run()
-{
- Q_ASSERT_X(m_server != nullptr, Q_FUNC_INFO, "There should always be a debug server available here.");
- QQmlDebugServerConnection *connection = loadQQmlDebugServerConnection(m_pluginName);
- if (connection) {
- {
- QMutexLocker connectionLocker(&m_server->m_helloMutex);
- m_server->m_connection = connection;
- connection->setServer(m_server);
- m_server->m_helloCondition.wakeAll();
- }
-
- if (m_fileName.isEmpty()) {
- if (!connection->setPortRange(m_portFrom, m_portTo, m_server->blockingMode(),
- m_hostAddress))
- return;
- } else if (!connection->setFileName(m_fileName, m_server->blockingMode())) {
- return;
- }
-
- if (m_server->blockingMode())
- connection->waitForConnection();
- } else {
- qWarning() << "QML Debugger: Couldn't load plugin" << m_pluginName;
- return;
- }
-
- exec();
-
- // make sure events still waiting are processed
- QEventLoop eventLoop;
- eventLoop.processEvents(QEventLoop::AllEvents);
-}
-
-bool QQmlDebugServerImpl::blockingMode() const
-{
- return m_blockingMode;
-}
-
-static void cleanupOnShutdown()
-{
- // We cannot do this in the destructor as the connection plugin will get unloaded before the
- // server plugin and we need the connection to send any remaining data. This function is
- // triggered before any plugins are unloaded.
- QQmlDebugServerImpl::cleanup();
-}
-
-QQmlDebugServerImpl::QQmlDebugServerImpl() :
- m_connection(nullptr),
- m_gotHello(false),
- m_blockingMode(false)
-{
- static bool postRoutineAdded = false;
- if (!postRoutineAdded) {
- qAddPostRoutine(cleanupOnShutdown);
- postRoutineAdded = true;
- }
-
- // used in sendMessages
- qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
- // used in changeServiceState
- qRegisterMetaType<QQmlDebugService::State>("QQmlDebugService::State");
-
- m_thread.setServer(this);
- moveToThread(&m_thread);
-
- // Remove the thread immmediately when it finishes, so that we don't have to wait for the
- // event loop to signal that.
- QObject::connect(&m_thread, &QThread::finished, this, &QQmlDebugServerImpl::removeThread,
- Qt::DirectConnection);
- m_thread.setObjectName(QStringLiteral("QQmlDebugServerThread"));
- parseArguments();
-}
-
-bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash())
-{
- if (m_thread.isRunning())
- return false;
- if (!configuration.isEmpty()) {
- m_blockingMode = configuration[QLatin1String("block")].toBool();
- if (configuration.contains(QLatin1String("portFrom"))) {
- int portFrom = configuration[QLatin1String("portFrom")].toInt();
- int portTo = configuration[QLatin1String("portTo")].toInt();
- m_thread.setPortRange(portFrom, portTo == -1 ? portFrom : portTo,
- configuration[QLatin1String("hostAddress")].toString());
- } else if (configuration.contains(QLatin1String("fileName"))) {
- m_thread.setFileName(configuration[QLatin1String("fileName")].toString());
- } else {
- return false;
- }
- }
-
- if (m_thread.pluginName().isEmpty())
- return false;
-
- QMutexLocker locker(&m_helloMutex);
- m_thread.start();
- m_helloCondition.wait(&m_helloMutex); // wait for connection
- if (m_blockingMode && !m_gotHello)
- m_helloCondition.wait(&m_helloMutex); // wait for hello
- return true;
-}
-
-void QQmlDebugServerImpl::parseArguments()
-{
- // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block]
- const QString args = commandLineArguments();
- if (args.isEmpty())
- return; // Manual initialization, through QQmlDebugServer::open()
-
- // ### remove port definition when protocol is changed
- int portFrom = 0;
- int portTo = 0;
- bool block = false;
- bool ok = false;
- QString hostAddress;
- QString fileName;
- QStringList services;
-
- const auto lstjsDebugArguments = QStringView{args}.split(QLatin1Char(','), Qt::SkipEmptyParts);
- for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) {
- const QStringView &strArgument = *argsIt;
- if (strArgument.startsWith(QLatin1String("port:"))) {
- portFrom = strArgument.mid(5).toInt(&ok);
- portTo = portFrom;
- const auto argsNext = argsIt + 1;
- if (argsNext == argsItEnd)
- break;
- if (ok) {
- portTo = argsNext->toString().toInt(&ok);
- if (ok) {
- ++argsIt;
- } else {
- portTo = portFrom;
- ok = true;
- }
- }
- } else if (strArgument.startsWith(QLatin1String("host:"))) {
- hostAddress = strArgument.mid(5).toString();
- } else if (strArgument == QLatin1String("block")) {
- block = true;
- } else if (strArgument.startsWith(QLatin1String("file:"))) {
- fileName = strArgument.mid(5).toString();
- ok = !fileName.isEmpty();
- } else if (strArgument.startsWith(QLatin1String("services:"))) {
- services.append(strArgument.mid(9).toString());
- } else if (!services.isEmpty()) {
- services.append(strArgument.toString());
- } else if (!strArgument.startsWith(QLatin1String("connector:"))) {
- const QString message = tr("QML Debugger: Invalid argument \"%1\" detected."
- " Ignoring the same.").arg(strArgument.toString());
- qWarning("%s", qPrintable(message));
- }
- }
-
- if (ok) {
- setServices(services);
- m_blockingMode = block;
- if (!fileName.isEmpty())
- m_thread.setFileName(fileName);
- else
- m_thread.setPortRange(portFrom, portTo, hostAddress);
- } else {
- QString usage;
- QTextStream str(&usage);
- str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n'
- << tr("The format is \"-qmljsdebugger=[file:<file>|port:<port_from>][,<port_to>]"
- "[,host:<ip address>][,block][,services:<service>][,<service>]*\"") << '\n'
- << tr("\"file:\" can be used to specify the name of a file the debugger will try "
- "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and"
- "\"port:\" arguments will be ignored.") << '\n'
- << tr("\"host:\" and \"port:\" can be used to specify an address and a single "
- "port or a range of ports the debugger will try to bind to with a "
- "QTcpServer.") << '\n'
- << tr("\"block\" makes the debugger and some services wait for clients to be "
- "connected and ready before the first QML engine starts.") << '\n'
- << tr("\"services:\" can be used to specify which debug services the debugger "
- "should load. Some debug services interact badly with others. The V4 "
- "debugger should not be loaded when using the QML profiler as it will force "
- "any V4 engines to use the JavaScript interpreter rather than the JIT. The "
- "following debug services are available by default:") << '\n'
- << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n'
- << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n'
- << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n'
- << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n'
- << QQmlEngineControlService::s_key << "\t- "
- //: Please preserve the line breaks and formatting
- << tr("Allows the client to delay the starting and stopping of\n"
- "\t\t QML engines until other services are ready. QtCreator\n"
- "\t\t uses this service with the QML profiler in order to\n"
- "\t\t profile multiple QML engines at the same time.")
- << '\n' << QDebugMessageService::s_key << "\t- "
- //: Please preserve the line breaks and formatting
- << tr("Sends qDebug() and similar messages over the QML debug\n"
- "\t\t connection. QtCreator uses this for showing debug\n"
- "\t\t messages in the debugger console.") << '\n'
- << '\n' << QQmlDebugTranslationService::s_key << "\t- "
- //: Please preserve the line breaks and formatting
- << tr("helps to see if a translated text\n"
- "\t\t will result in an elided text\n"
- "\t\t in QML elements.") << '\n'
- << tr("Other services offered by qmltooling plugins that implement "
- "QQmlDebugServiceFactory and which can be found in the standard plugin "
- "paths will also be available and can be specified. If no \"services\" "
- "argument is given, all services found this way, including the default "
- "ones, are loaded.");
- qWarning("%s", qPrintable(usage));
- }
-}
-
-void QQmlDebugServerImpl::receiveMessage()
-{
- typedef QHash<QString, QQmlDebugService*>::const_iterator DebugServiceConstIt;
-
- // to be executed in debugger thread
- Q_ASSERT(QThread::currentThread() == thread());
-
- if (!m_protocol)
- return;
-
- QQmlDebugPacket in(m_protocol->read());
-
- QString name;
-
- in >> name;
- if (name == QLatin1String("QDeclarativeDebugServer")) {
- int op = -1;
- in >> op;
- if (op == 0) {
- int version;
- in >> version >> m_clientPlugins;
-
- //Get the supported QDataStream version
- if (!in.atEnd()) {
- in >> s_dataStreamVersion;
- if (s_dataStreamVersion > QDataStream::Qt_DefaultCompiledVersion)
- s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion;
- }
-
- bool clientSupportsMultiPackets = false;
- if (!in.atEnd())
- in >> clientSupportsMultiPackets;
-
- // Send the hello answer immediately, since it needs to arrive before
- // the plugins below start sending messages.
-
- QQmlDebugPacket out;
- QStringList pluginNames;
- QList<float> pluginVersions;
- if (clientSupportsMultiPackets) { // otherwise, disable all plugins
- const int count = m_plugins.count();
- pluginNames.reserve(count);
- pluginVersions.reserve(count);
- for (QHash<QString, QQmlDebugService *>::ConstIterator i = m_plugins.constBegin();
- i != m_plugins.constEnd(); ++i) {
- pluginNames << i.key();
- pluginVersions << i.value()->version();
- }
- }
-
- out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion
- << pluginNames << pluginVersions << dataStreamVersion();
-
- m_protocol->send(out.data());
- m_connection->flush();
-
- QMutexLocker helloLock(&m_helloMutex);
- m_gotHello = true;
-
- for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) {
- QQmlDebugService::State newState = QQmlDebugService::Unavailable;
- if (m_clientPlugins.contains(iter.key()))
- newState = QQmlDebugService::Enabled;
- m_changeServiceStateCalls.ref();
- changeServiceState(iter.key(), newState);
- }
-
- m_helloCondition.wakeAll();
-
- } else if (op == 1) {
- // Service Discovery
- QStringList oldClientPlugins = m_clientPlugins;
- in >> m_clientPlugins;
-
- for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) {
- const QString &pluginName = iter.key();
- QQmlDebugService::State newState = QQmlDebugService::Unavailable;
- if (m_clientPlugins.contains(pluginName))
- newState = QQmlDebugService::Enabled;
-
- if (oldClientPlugins.contains(pluginName)
- != m_clientPlugins.contains(pluginName)) {
- m_changeServiceStateCalls.ref();
- changeServiceState(iter.key(), newState);
- }
- }
-
- } else {
- qWarning("QML Debugger: Invalid control message %d.", op);
- protocolError();
- return;
- }
-
- } else {
- if (m_gotHello) {
- QHash<QString, QQmlDebugService *>::Iterator iter = m_plugins.find(name);
- if (iter == m_plugins.end()) {
- qWarning() << "QML Debugger: Message received for missing plugin" << name << '.';
- } else {
- QQmlDebugService *service = *iter;
- QByteArray message;
- while (!in.atEnd()) {
- in >> message;
- service->messageReceived(message);
- }
- }
- } else {
- qWarning("QML Debugger: Invalid hello message.");
- }
-
- }
-}
-
-void QQmlDebugServerImpl::changeServiceState(const QString &serviceName,
- QQmlDebugService::State newState)
-{
- // to be executed in debugger thread
- Q_ASSERT(QThread::currentThread() == thread());
-
- QQmlDebugService *service = m_plugins.value(serviceName);
- if (service && service->state() != newState) {
- service->stateAboutToBeChanged(newState);
- service->setState(newState);
- service->stateChanged(newState);
- }
-
- m_changeServiceStateCalls.deref();
-}
-
-void QQmlDebugServerImpl::removeThread()
-{
- Q_ASSERT(m_thread.isFinished());
- Q_ASSERT(QThread::currentThread() == thread());
-
- QThread *parentThread = m_thread.thread();
-
- delete m_connection;
- m_connection = nullptr;
-
- // Move it back to the parent thread so that we can potentially restart it on a new thread.
- moveToThread(parentThread);
-}
-
-QQmlDebugService *QQmlDebugServerImpl::service(const QString &name) const
-{
- return m_plugins.value(name);
-}
-
-void QQmlDebugServerImpl::addEngine(QJSEngine *engine)
-{
- // to be executed outside of debugger thread
- Q_ASSERT(QThread::currentThread() != &m_thread);
-
- QMutexLocker locker(&m_helloMutex);
- Q_ASSERT(!m_engineConditions.contains(engine));
-
- for (QQmlDebugService *service : qAsConst(m_plugins))
- service->engineAboutToBeAdded(engine);
-
- m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count());
-
- for (QQmlDebugService *service : qAsConst(m_plugins))
- service->engineAdded(engine);
-}
-
-void QQmlDebugServerImpl::removeEngine(QJSEngine *engine)
-{
- // to be executed outside of debugger thread
- Q_ASSERT(QThread::currentThread() != &m_thread);
-
- QMutexLocker locker(&m_helloMutex);
- Q_ASSERT(m_engineConditions.contains(engine));
-
- for (QQmlDebugService *service : qAsConst(m_plugins))
- service->engineAboutToBeRemoved(engine);
-
- m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count());
-
- for (QQmlDebugService *service : qAsConst(m_plugins))
- service->engineRemoved(engine);
-
- m_engineConditions.remove(engine);
-}
-
-bool QQmlDebugServerImpl::hasEngine(QJSEngine *engine) const
-{
- QMutexLocker locker(&m_helloMutex);
- QHash<QJSEngine *, EngineCondition>::ConstIterator i = m_engineConditions.constFind(engine);
- // if we're still waiting the engine isn't fully "there", yet, nor fully removed.
- return i != m_engineConditions.constEnd() && !i.value().isWaiting();
-}
-
-bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *service)
-{
- // to be executed before thread starts
- Q_ASSERT(!m_thread.isRunning());
-
- if (!service || m_plugins.contains(name))
- return false;
-
- connect(service, &QQmlDebugService::messageToClient,
- this, &QQmlDebugServerImpl::sendMessage);
- connect(service, &QQmlDebugService::messagesToClient,
- this, &QQmlDebugServerImpl::sendMessages);
-
- connect(service, &QQmlDebugService::attachedToEngine,
- this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection);
- connect(service, &QQmlDebugService::detachedFromEngine,
- this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection);
-
- service->setState(QQmlDebugService::Unavailable);
- m_plugins.insert(name, service);
-
- return true;
-}
-
-bool QQmlDebugServerImpl::removeService(const QString &name)
-{
- // to be executed after thread ends
- Q_ASSERT(!m_thread.isRunning());
-
- QQmlDebugService *service = m_plugins.value(name);
- if (!service)
- return false;
-
- m_plugins.remove(name);
- service->setState(QQmlDebugService::NotConnected);
-
- disconnect(service, &QQmlDebugService::detachedFromEngine,
- this, &QQmlDebugServerImpl::wakeEngine);
- disconnect(service, &QQmlDebugService::attachedToEngine,
- this, &QQmlDebugServerImpl::wakeEngine);
-
- disconnect(service, &QQmlDebugService::messagesToClient,
- this, &QQmlDebugServerImpl::sendMessages);
- disconnect(service, &QQmlDebugService::messageToClient,
- this, &QQmlDebugServerImpl::sendMessage);
-
- return true;
-}
-
-bool QQmlDebugServerImpl::canSendMessage(const QString &name)
-{
- // to be executed in debugger thread
- Q_ASSERT(QThread::currentThread() == thread());
- return m_connection && m_connection->isConnected() && m_protocol &&
- m_clientPlugins.contains(name);
-}
-
-void QQmlDebugServerImpl::doSendMessage(const QString &name, const QByteArray &message)
-{
- QQmlDebugPacket out;
- out << name << message;
- m_protocol->send(out.data());
-}
-
-void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message)
-{
- if (canSendMessage(name)) {
- doSendMessage(name, message);
- m_connection->flush();
- }
-}
-
-void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages)
-{
- if (canSendMessage(name)) {
- QQmlDebugPacket out;
- out << name;
- for (const QByteArray &message : messages)
- out << message;
- m_protocol->send(out.data());
- m_connection->flush();
- }
-}
-
-void QQmlDebugServerImpl::wakeEngine(QJSEngine *engine)
-{
- // to be executed in debugger thread
- Q_ASSERT(QThread::currentThread() == thread());
-
- QMutexLocker locker(&m_helloMutex);
- m_engineConditions[engine].wake();
-}
-
-bool QQmlDebugServerImpl::EngineCondition::waitForServices(QMutex *locked, int num)
-{
- Q_ASSERT_X(numServices == 0, Q_FUNC_INFO, "Request to wait again before previous wait finished");
- numServices = num;
- return numServices > 0 ? condition->wait(locked) : true;
-}
-
-void QQmlDebugServerImpl::EngineCondition::wake()
-{
- if (--numServices == 0)
- condition->wakeAll();
- Q_ASSERT_X(numServices >=0, Q_FUNC_INFO, "Woken more often than #services.");
-}
-
-void QQmlDebugServerImpl::setDevice(QIODevice *socket)
-{
- m_protocol = new QPacketProtocol(socket, this);
- QObject::connect(m_protocol, &QPacketProtocol::readyRead,
- this, &QQmlDebugServerImpl::receiveMessage);
- QObject::connect(m_protocol, &QPacketProtocol::error,
- this, &QQmlDebugServerImpl::protocolError);
-
- if (blockingMode())
- m_protocol->waitForReadyRead(-1);
-}
-
-void QQmlDebugServerImpl::protocolError()
-{
- qWarning("QML Debugger: A protocol error has occurred! Giving up ...");
- m_connection->disconnect();
- // protocol might still be processing packages at this point
- m_protocol->deleteLater();
- m_protocol = nullptr;
-}
-
-QQmlDebugConnector *QQmlDebugServerFactory::create(const QString &key)
-{
- // Cannot parent it to this because it gets moved to another thread
- return (key == QLatin1String("QQmlDebugServer") ? new QQmlDebugServerImpl : nullptr);
-}
-
-QT_END_NAMESPACE
-
-#include "qqmldebugserver.moc"