6#include <private/qhooks_p.h>
7#include <private/qversionedpacket_p.h>
9#include <QtQml/qjsengine.h>
10#include <QtCore/qdebug.h>
11#include <QtCore/qjsonarray.h>
12#include <QtCore/qjsondocument.h>
13#include <QtCore/qjsonobject.h>
14#include <QtCore/qjsonvalue.h>
15#include <QtCore/qpointer.h>
16#include <QtCore/qvector.h>
19#define TRACE_PROTOCOL(s)
27# define QML_DEBUG_EXPORT Q_DECL_EXPORT
29# define QML_DEBUG_EXPORT
45 QQmlNativeDebugConnector::setDataStreamVersion(version);
63 responseBuffer->clear();
71 QByteArray msg = QByteArray::fromHex(hexData);
73 QQmlDebugConnector *instance = QQmlDebugConnector::instance();
77 QQmlDebugService *recipient = instance->service(serviceName);
81 TRACE_PROTOCOL(
"Recipient: " << recipient <<
" got message: " << msg);
83 recipient->messageReceived(msg);
92 QQmlDebugConnector *instance = QQmlDebugConnector::instance();
96 QString name = QString::fromLatin1(data);
97 QQmlDebugService *service = instance->service(name);
98 if (!service || service->state() == QQmlDebugService::Enabled)
101 service->stateAboutToBeChanged(QQmlDebugService::Enabled);
102 service->setState(QQmlDebugService::Enabled);
103 service->stateChanged(QQmlDebugService::Enabled);
109 QQmlDebugConnector *instance = QQmlDebugConnector::instance();
113 QString name = QString::fromLatin1(data);
114 QQmlDebugService *service = instance->service(name);
115 if (!service || service->state() == QQmlDebugService::Unavailable)
118 service->stateAboutToBeChanged(QQmlDebugService::Unavailable);
119 service->setState(QQmlDebugService::Unavailable);
120 service->stateChanged(QQmlDebugService::Unavailable);
143 qtHookData[QHooks::Startup] = quintptr(&qt_qmlDebugTestHooks);
155QQmlNativeDebugConnector::QQmlNativeDebugConnector()
156 : m_blockingMode(
false)
158 const QString args = commandLineArguments();
159 const auto lstjsDebugArguments = QStringView{args}.split(QLatin1Char(
','), Qt::SkipEmptyParts);
160 QStringList services;
161 for (
const QStringView &strArgument : lstjsDebugArguments) {
162 if (strArgument == QLatin1String(
"block")) {
163 m_blockingMode =
true;
164 }
else if (strArgument == QLatin1String(
"native")) {
167 }
else if (strArgument.startsWith(QLatin1String(
"services:"))) {
168 services.append(strArgument.mid(9).toString());
169 }
else if (!services.isEmpty()) {
170 services.append(strArgument.toString());
171 }
else if (!strArgument.startsWith(QLatin1String(
"connector:"))) {
172 qWarning(
"QML Debugger: Invalid argument \"%s\" detected. Ignoring the same.",
173 strArgument.toUtf8().constData());
176 setServices(services);
179QQmlNativeDebugConnector::~QQmlNativeDebugConnector()
181 for (QQmlDebugService *service : std::as_const(m_services)) {
182 service->stateAboutToBeChanged(QQmlDebugService::NotConnected);
183 service->setState(QQmlDebugService::NotConnected);
184 service->stateChanged(QQmlDebugService::NotConnected);
188bool QQmlNativeDebugConnector::blockingMode()
const
190 return m_blockingMode;
193QQmlDebugService *QQmlNativeDebugConnector::service(
const QString &name)
const
195 for (QVector<QQmlDebugService *>::ConstIterator i = m_services.begin(); i != m_services.end();
197 if ((*i)->name() == name)
203void QQmlNativeDebugConnector::addEngine(QJSEngine *engine)
205 Q_ASSERT(!m_engines.contains(engine));
208 for (QQmlDebugService *service : std::as_const(m_services))
209 service->engineAboutToBeAdded(engine);
211 announceObjectAvailability(QLatin1String(
"qmlengine"), engine,
true);
213 for (QQmlDebugService *service : std::as_const(m_services))
214 service->engineAdded(engine);
216 m_engines.append(engine);
219void QQmlNativeDebugConnector::removeEngine(QJSEngine *engine)
221 Q_ASSERT(m_engines.contains(engine));
224 for (QQmlDebugService *service : std::as_const(m_services))
225 service->engineAboutToBeRemoved(engine);
227 announceObjectAvailability(QLatin1String(
"qmlengine"), engine,
false);
229 for (QQmlDebugService *service : std::as_const(m_services))
230 service->engineRemoved(engine);
232 m_engines.removeOne(engine);
235bool QQmlNativeDebugConnector::hasEngine(QJSEngine *engine)
const
237 return m_engines.contains(engine);
240void QQmlNativeDebugConnector::announceObjectAvailability(
const QString &objectType,
241 QObject *object,
bool available)
244 ob.insert(QLatin1String(
"objecttype"), objectType);
245 ob.insert(QLatin1String(
"object"), QString::number(quintptr(object)));
246 ob.insert(QLatin1String(
"available"), available);
250 QByteArray ba = doc.toJson(QJsonDocument::Compact);
259bool QQmlNativeDebugConnector::addService(
const QString &name, QQmlDebugService *service)
261 TRACE_PROTOCOL(
"Add service to connector: " << qPrintable(name) << service);
262 for (
auto it = m_services.cbegin(), end = m_services.cend(); it != end; ++it) {
263 if ((*it)->name() == name)
267 connect(service, &QQmlDebugService::messageToClient,
268 this, &QQmlNativeDebugConnector::sendMessage);
269 connect(service, &QQmlDebugService::messagesToClient,
270 this, &QQmlNativeDebugConnector::sendMessages);
272 service->setState(QQmlDebugService::Unavailable);
274 m_services << service;
278bool QQmlNativeDebugConnector::removeService(
const QString &name)
280 for (QVector<QQmlDebugService *>::Iterator i = m_services.begin(); i != m_services.end(); ++i) {
281 if ((*i)->name() == name) {
282 QQmlDebugService *service = *i;
284 service->setState(QQmlDebugService::NotConnected);
286 disconnect(service, &QQmlDebugService::messagesToClient,
287 this, &QQmlNativeDebugConnector::sendMessages);
288 disconnect(service, &QQmlDebugService::messageToClient,
289 this, &QQmlNativeDebugConnector::sendMessage);
297bool QQmlNativeDebugConnector::open(
const QVariantHash &configuration)
299 m_blockingMode = configuration.value(QStringLiteral(
"block"), m_blockingMode).toBool();
305void QQmlNativeDebugConnector::setDataStreamVersion(
int version)
307 Q_ASSERT(version <= QDataStream::Qt_DefaultCompiledVersion);
308 s_dataStreamVersion = version;
311void QQmlNativeDebugConnector::sendMessage(
const QString &name,
const QByteArray &message)
313 (*responseBuffer) += name.toUtf8() +
' ' + QByteArray::number(message.size()) +
' ' + message;
314 qt_qmlDebugMessageBuffer = responseBuffer->constData();
315 qt_qmlDebugMessageLength = responseBuffer->size();
330void QQmlNativeDebugConnector::sendMessages(
const QString &name,
const QList<QByteArray> &messages)
332 for (
int i = 0; i != messages.size(); ++i)
333 sendMessage(name, messages.at(i));
338 return key == QLatin1String(
"QQmlNativeDebugConnector") ?
new QQmlNativeDebugConnector :
nullptr;
343#include "moc_qqmlnativedebugconnector.cpp"
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
quintptr qt_qmlDebugTestHooks[]
QML_DEBUG_EXPORT const char * qt_qmlDebugMessageBuffer
QML_DEBUG_EXPORT void qt_qmlDebugClearBuffer()
QML_DEBUG_EXPORT void qt_qmlDebugSetStreamVersion(int version)
QML_DEBUG_EXPORT int qt_qmlDebugMessageLength
QML_DEBUG_EXPORT void qt_qmlDebugConnectorOpen()
QML_DEBUG_EXPORT bool qt_qmlDebugSendDataToService(const char *serviceName, const char *hexData)
QML_DEBUG_EXPORT void qt_qmlDebugObjectAvailable()
QML_DEBUG_EXPORT void qt_qmlDebugMessageAvailable()
QML_DEBUG_EXPORT bool qt_qmlDebugDisableService(const char *data)
static QT_USE_NAMESPACE bool expectSyncronousResponse
QML_DEBUG_EXPORT bool qt_qmlDebugEnableService(const char *data)
QML_DEBUG_EXPORT bool qt_qmlDebugConnectionBlocker
#define TRACE_PROTOCOL(x)