diff options
Diffstat (limited to 'src/qmldebug')
-rw-r--r-- | src/qmldebug/qmldebug.pro | 13 | ||||
-rw-r--r-- | src/qmldebug/qqmlenginedebugclient.cpp | 566 | ||||
-rw-r--r-- | src/qmldebug/qqmlenginedebugclient_p.h | 168 | ||||
-rw-r--r-- | src/qmldebug/qqmlenginedebugclient_p_p.h | 76 | ||||
-rw-r--r-- | src/qmldebug/qqmlinspectorclient.cpp | 150 | ||||
-rw-r--r-- | src/qmldebug/qqmlinspectorclient_p.h | 85 | ||||
-rw-r--r-- | src/qmldebug/qqmlinspectorclient_p_p.h | 69 | ||||
-rw-r--r-- | src/qmldebug/qv4debugclient.cpp | 578 | ||||
-rw-r--r-- | src/qmldebug/qv4debugclient_p.h | 121 | ||||
-rw-r--r-- | src/qmldebug/qv4debugclient_p_p.h | 80 |
10 files changed, 1904 insertions, 2 deletions
diff --git a/src/qmldebug/qmldebug.pro b/src/qmldebug/qmldebug.pro index 0807482d23..94d300b765 100644 --- a/src/qmldebug/qmldebug.pro +++ b/src/qmldebug/qmldebug.pro @@ -9,20 +9,27 @@ SOURCES += \ qqmldebugconnection.cpp \ qqmldebugmessageclient.cpp \ qqmlenginecontrolclient.cpp \ + qqmlenginedebugclient.cpp \ + qqmlinspectorclient.cpp \ qqmlpreviewclient.cpp \ qqmlprofilerclient.cpp \ qqmlprofilerevent.cpp \ qqmlprofilereventlocation.cpp \ qqmlprofilereventtype.cpp \ - qqmlprofilertypedevent.cpp + qqmlprofilertypedevent.cpp \ + qv4debugclient.cpp HEADERS += \ qqmldebugclient_p.h \ qqmldebugclient_p_p.h \ qqmldebugconnection_p.h \ qqmldebugmessageclient_p.h \ + qqmlenginedebugclient_p.h \ + qqmlenginedebugclient_p_p.h \ qqmlenginecontrolclient_p.h \ qqmlenginecontrolclient_p_p.h \ + qqmlinspectorclient_p.h \ + qqmlinspectorclient_p_p.h \ qqmlpreviewclient_p.h \ qqmlpreviewclient_p_p.h \ qqmlprofilerclient_p.h \ @@ -32,4 +39,6 @@ HEADERS += \ qqmlprofilereventreceiver_p.h \ qqmlprofilereventtype_p.h \ qqmlprofilertypedevent_p.h \ - qqmlprofilerclientdefinitions_p.h + qqmlprofilerclientdefinitions_p.h \ + qv4debugclient_p.h \ + qv4debugclient_p_p.h diff --git a/src/qmldebug/qqmlenginedebugclient.cpp b/src/qmldebug/qqmlenginedebugclient.cpp new file mode 100644 index 0000000000..ec45ec33bc --- /dev/null +++ b/src/qmldebug/qqmlenginedebugclient.cpp @@ -0,0 +1,566 @@ +/**************************************************************************** +** +** 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:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlenginedebugclient_p_p.h" +#include <private/qqmldebugconnection_p.h> + +QT_BEGIN_NAMESPACE + +struct QQmlObjectData { + QUrl url; + int lineNumber = -1; + int columnNumber = -1; + QString idString; + QString objectName; + QString objectType; + int objectId = -1; + int contextId = -1; + int parentId = -1; +}; + +QPacket &operator>>(QPacket &ds, QQmlObjectData &data) +{ + ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString + >> data.objectName >> data.objectType >> data.objectId >> data.contextId + >> data.parentId; + return ds; +} + +struct QQmlObjectProperty { + enum Type { Unknown, Basic, Object, List, SignalProperty }; + Type type = Unknown; + QString name; + QVariant value; + QString valueTypeName; + QString binding; + bool hasNotifySignal = false; +}; + +QPacket &operator>>(QPacket &ds, QQmlObjectProperty &data) +{ + int type; + ds >> type >> data.name >> data.value >> data.valueTypeName + >> data.binding >> data.hasNotifySignal; + data.type = (QQmlObjectProperty::Type)type; + return ds; +} + +QQmlEngineDebugClient::QQmlEngineDebugClient(QQmlDebugConnection *connection) : + QQmlDebugClient(*new QQmlEngineDebugClientPrivate(connection)) +{ +} + +QQmlEngineDebugClientPrivate::QQmlEngineDebugClientPrivate(QQmlDebugConnection *connection) : + QQmlDebugClientPrivate (QLatin1String("QmlDebugger"), connection) +{ +} + + +quint32 QQmlEngineDebugClient::addWatch( + const QQmlEngineDebugPropertyReference &property, bool *success) +{ + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("WATCH_PROPERTY") << id << property.objectDebugId + << property.name.toUtf8(); + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::addWatch( + const QQmlEngineDebugContextReference &, const QString &, bool *success) +{ + *success = false; + qWarning("QQmlEngineDebugClient::addWatch(): Not implemented"); + return 0; +} + +quint32 QQmlEngineDebugClient::addWatch( + const QQmlEngineDebugObjectReference &object, const QString &expr, + bool *success) +{ + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("WATCH_EXPR_OBJECT") << id << object.debugId << expr; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::addWatch( + const QQmlEngineDebugObjectReference &object, bool *success) +{ + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("WATCH_OBJECT") << id << object.debugId; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::addWatch( + const QQmlEngineDebugFileReference &, bool *success) +{ + *success = false; + qWarning("QQmlEngineDebugClient::addWatch(): Not implemented"); + return 0; +} + +void QQmlEngineDebugClient::removeWatch(quint32 id, bool *success) +{ + *success = false; + if (state() == QQmlDebugClient::Enabled) { + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("NO_WATCH") << id; + sendMessage(ds.data()); + *success = true; + } +} + +quint32 QQmlEngineDebugClient::queryAvailableEngines(bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->engines.clear(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("LIST_ENGINES") << id; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryRootContexts( + const QQmlEngineDebugEngineReference &engine, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->rootContext = QQmlEngineDebugContextReference(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled && engine.debugId != -1) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("LIST_OBJECTS") << id << engine.debugId; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryObject( + const QQmlEngineDebugObjectReference &object, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->object = QQmlEngineDebugObjectReference(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled && object.debugId != -1) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("FETCH_OBJECT") << id << object.debugId << false << true; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryObjectsForLocation( + const QString &file, int lineNumber, int columnNumber, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->objects.clear(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id << file << lineNumber + << columnNumber << false << true; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryObjectRecursive( + const QQmlEngineDebugObjectReference &object, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->object = QQmlEngineDebugObjectReference(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled && object.debugId != -1) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("FETCH_OBJECT") << id << object.debugId << true << true; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryObjectsForLocationRecursive(const QString &file, + int lineNumber, int columnNumber, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->objects.clear(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id << file << lineNumber + << columnNumber << true << true; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryExpressionResult( + int objectDebugId, const QString &expr, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->exprResult = QVariant(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr + << engines()[0].debugId; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::queryExpressionResultBC( + int objectDebugId, const QString &expr, bool *success) +{ + Q_D(QQmlEngineDebugClient); + d->exprResult = QVariant(); + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::setBindingForObject( + int objectDebugId, + const QString &propertyName, + const QVariant &bindingExpression, + bool isLiteralValue, + const QString &source, int line, + bool *success) +{ + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("SET_BINDING") << id << objectDebugId << propertyName + << bindingExpression << isLiteralValue << source << line; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::resetBindingForObject( + int objectDebugId, + const QString &propertyName, + bool *success) +{ + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("RESET_BINDING") << id << objectDebugId << propertyName; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +quint32 QQmlEngineDebugClient::setMethodBody( + int objectDebugId, const QString &methodName, + const QString &methodBody, bool *success) +{ + quint32 id = -1; + *success = false; + if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) { + id = getId(); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("SET_METHOD_BODY") << id << objectDebugId + << methodName << methodBody; + sendMessage(ds.data()); + *success = true; + } + return id; +} + +void QQmlEngineDebugClient::decode(QPacket &ds, + QQmlEngineDebugObjectReference &o, + bool simple) +{ + QQmlObjectData data; + ds >> data; + o.debugId = data.objectId; + o.className = data.objectType; + o.idString = data.idString; + o.name = data.objectName; + o.source.url = data.url; + o.source.lineNumber = data.lineNumber; + o.source.columnNumber = data.columnNumber; + o.contextDebugId = data.contextId; + + if (simple) + return; + + int childCount; + bool recur; + ds >> childCount >> recur; + + for (int ii = 0; ii < childCount; ++ii) { + o.children.append(QQmlEngineDebugObjectReference()); + decode(ds, o.children.last(), !recur); + } + + int propCount; + ds >> propCount; + + for (int ii = 0; ii < propCount; ++ii) { + QQmlObjectProperty data; + ds >> data; + QQmlEngineDebugPropertyReference prop; + prop.objectDebugId = o.debugId; + prop.name = data.name; + prop.binding = data.binding; + prop.hasNotifySignal = data.hasNotifySignal; + prop.valueTypeName = data.valueTypeName; + switch (data.type) { + case QQmlObjectProperty::Basic: + case QQmlObjectProperty::List: + case QQmlObjectProperty::SignalProperty: + { + prop.value = data.value; + break; + } + case QQmlObjectProperty::Object: + { + QQmlEngineDebugObjectReference obj; + obj.name = data.value.toString(); + obj.className = prop.valueTypeName; + prop.value = qVariantFromValue(obj); + break; + } + case QQmlObjectProperty::Unknown: + break; + } + o.properties << prop; + } +} + +void QQmlEngineDebugClient::decode(QPacket &ds, + QList<QQmlEngineDebugObjectReference> &o, + bool simple) +{ + int count; + ds >> count; + for (int i = 0; i < count; i++) { + QQmlEngineDebugObjectReference obj; + decode(ds, obj, simple); + o << obj; + } +} + +QList<QQmlEngineDebugEngineReference> QQmlEngineDebugClient::engines() const +{ + Q_D(const QQmlEngineDebugClient); + return d->engines; +} + +QQmlEngineDebugContextReference QQmlEngineDebugClient::rootContext() const +{ + Q_D(const QQmlEngineDebugClient); + return d->rootContext; +} + +QQmlEngineDebugObjectReference QQmlEngineDebugClient::object() const +{ + Q_D(const QQmlEngineDebugClient); + return d->object; +} + +QList<QQmlEngineDebugObjectReference> QQmlEngineDebugClient::objects() const +{ + Q_D(const QQmlEngineDebugClient); + return d->objects; +} + +QVariant QQmlEngineDebugClient::resultExpr() const +{ + Q_D(const QQmlEngineDebugClient); + return d->exprResult; +} + +bool QQmlEngineDebugClient::valid() const +{ + Q_D(const QQmlEngineDebugClient); + return d->valid; +} + +void QQmlEngineDebugClient::decode(QPacket &ds, + QQmlEngineDebugContextReference &c) +{ + ds >> c.name >> c.debugId; + + int contextCount; + ds >> contextCount; + + for (int ii = 0; ii < contextCount; ++ii) { + c.contexts.append(QQmlEngineDebugContextReference()); + decode(ds, c.contexts.last()); + } + + int objectCount; + ds >> objectCount; + + for (int ii = 0; ii < objectCount; ++ii) { + QQmlEngineDebugObjectReference obj; + decode(ds, obj, true); + + obj.contextDebugId = c.debugId; + c.objects << obj; + } +} + +void QQmlEngineDebugClient::messageReceived(const QByteArray &data) +{ + Q_D(QQmlEngineDebugClient); + d->valid = false; + QPacket ds(connection()->currentDataStreamVersion(), data); + + int queryId; + QByteArray type; + ds >> type >> queryId; + + //qDebug() << "QQmlEngineDebugPrivate::message()" << type; + + if (type == "LIST_ENGINES_R") { + int count; + ds >> count; + + d->engines.clear(); + for (int ii = 0; ii < count; ++ii) { + QQmlEngineDebugEngineReference eng; + ds >> eng.name; + ds >> eng.debugId; + d->engines << eng; + } + } else if (type == "LIST_OBJECTS_R") { + if (!ds.atEnd()) + decode(ds, d->rootContext); + + } else if (type == "FETCH_OBJECT_R") { + if (!ds.atEnd()) + decode(ds, d->object, false); + + } else if (type == "FETCH_OBJECTS_FOR_LOCATION_R") { + if (!ds.atEnd()) + decode(ds, d->objects, false); + + } else if (type == "EVAL_EXPRESSION_R") {; + ds >> d->exprResult; + + } else if (type == "WATCH_PROPERTY_R") { + ds >> d->valid; + + } else if (type == "WATCH_OBJECT_R") { + ds >> d->valid; + + } else if (type == "WATCH_EXPR_OBJECT_R") { + ds >> d->valid; + + } else if (type == "UPDATE_WATCH") { + int debugId; + QByteArray name; + QVariant value; + ds >> debugId >> name >> value; + emit valueChanged(name, value); + return; + + } else if (type == "OBJECT_CREATED") { + int engineId, objectId, parentId; + ds >> engineId >> objectId >> parentId; + emit newObject(objectId); + return; + } else if (type == "SET_BINDING_R") { + ds >> d->valid; + } else if (type == "RESET_BINDING_R") { + ds >> d->valid; + } else if (type == "SET_METHOD_BODY_R") { + ds >> d->valid; + } else if (type == "NO_WATCH_R") { + ds >> d->valid; + } + emit result(); +} + + +quint32 QQmlEngineDebugClient::getId() +{ + Q_D(QQmlEngineDebugClient); + return d->nextId++; +} + +QT_END_NAMESPACE diff --git a/src/qmldebug/qqmlenginedebugclient_p.h b/src/qmldebug/qqmlenginedebugclient_p.h new file mode 100644 index 0000000000..4a9cc3a020 --- /dev/null +++ b/src/qmldebug/qqmlenginedebugclient_p.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLENGINEDEBUGCLIENT_H +#define QQMLENGINEDEBUGCLIENT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qqmldebugclient_p.h> +#include <private/qpacket_p.h> + +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +struct QQmlEngineDebugPropertyReference +{ + int objectDebugId = -1; + QString name; + QVariant value; + QString valueTypeName; + QString binding; + bool hasNotifySignal = false; +}; + +struct QQmlEngineDebugFileReference +{ + QUrl url; + int lineNumber = -1; + int columnNumber = -1; +}; + +struct QQmlEngineDebugObjectReference +{ + int debugId = -1; + QString className; + QString idString; + QString name; + QQmlEngineDebugFileReference source; + int contextDebugId = -1; + QList<QQmlEngineDebugPropertyReference> properties; + QList<QQmlEngineDebugObjectReference> children; +}; + +struct QQmlEngineDebugContextReference +{ + int debugId = -1; + QString name; + QList<QQmlEngineDebugObjectReference> objects; + QList<QQmlEngineDebugContextReference> contexts; +}; + +struct QQmlEngineDebugEngineReference +{ + int debugId = -1; + QString name; +}; + +class QQmlEngineDebugClientPrivate; +class QQmlEngineDebugClient : public QQmlDebugClient +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQmlEngineDebugClient) + +public: + explicit QQmlEngineDebugClient(QQmlDebugConnection *conn); + + quint32 addWatch(const QQmlEngineDebugPropertyReference &, + bool *success); + quint32 addWatch(const QQmlEngineDebugContextReference &, const QString &, + bool *success); + quint32 addWatch(const QQmlEngineDebugObjectReference &, const QString &, + bool *success); + quint32 addWatch(const QQmlEngineDebugObjectReference &, + bool *success); + quint32 addWatch(const QQmlEngineDebugFileReference &, + bool *success); + + void removeWatch(quint32 watch, bool *success); + + quint32 queryAvailableEngines(bool *success); + quint32 queryRootContexts(const QQmlEngineDebugEngineReference &, + bool *success); + quint32 queryObject(const QQmlEngineDebugObjectReference &, + bool *success); + quint32 queryObjectsForLocation(const QString &file, + int lineNumber, int columnNumber, bool *success); + quint32 queryObjectRecursive(const QQmlEngineDebugObjectReference &, + bool *success); + quint32 queryObjectsForLocationRecursive(const QString &file, + int lineNumber, int columnNumber, bool *success); + quint32 queryExpressionResult(int objectDebugId, + const QString &expr, + bool *success); + quint32 queryExpressionResultBC(int objectDebugId, + const QString &expr, + bool *success); + quint32 setBindingForObject(int objectDebugId, const QString &propertyName, + const QVariant &bindingExpression, + bool isLiteralValue, + const QString &source, int line, bool *success); + quint32 resetBindingForObject(int objectDebugId, + const QString &propertyName, bool *success); + quint32 setMethodBody(int objectDebugId, const QString &methodName, + const QString &methodBody, bool *success); + + quint32 getId(); + + void decode(QPacket &ds, QQmlEngineDebugContextReference &); + void decode(QPacket &ds, QQmlEngineDebugObjectReference &, bool simple); + void decode(QPacket &ds, QList<QQmlEngineDebugObjectReference> &o, bool simple); + + QList<QQmlEngineDebugEngineReference> engines() const; + QQmlEngineDebugContextReference rootContext() const; + QQmlEngineDebugObjectReference object() const; + QList<QQmlEngineDebugObjectReference> objects() const; + QVariant resultExpr() const; + bool valid() const; + +signals: + void newObject(int objectId); + void valueChanged(QByteArray,QVariant); + void result(); + +protected: + void messageReceived(const QByteArray &) override; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QQmlEngineDebugObjectReference) + +#endif // QQMLENGINEDEBUGCLIENT_H diff --git a/src/qmldebug/qqmlenginedebugclient_p_p.h b/src/qmldebug/qqmlenginedebugclient_p_p.h new file mode 100644 index 0000000000..7c992ad3ab --- /dev/null +++ b/src/qmldebug/qqmlenginedebugclient_p_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QQMLENGINEDEBUGCLIENT_P_P_H +#define QQMLENGINEDEBUGCLIENT_P_P_H + +#include "qqmlenginedebugclient_p.h" +#include "qqmldebugclient_p_p.h" + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QQmlEngineDebugClientPrivate : public QQmlDebugClientPrivate +{ + Q_DECLARE_PUBLIC(QQmlEngineDebugClient) +public: + QQmlEngineDebugClientPrivate(QQmlDebugConnection *connection); + + quint32 nextId = 0; + bool valid = false; + QList<QQmlEngineDebugEngineReference> engines; + QQmlEngineDebugContextReference rootContext; + QQmlEngineDebugObjectReference object; + QList<QQmlEngineDebugObjectReference> objects; + QVariant exprResult; +}; + +QT_END_NAMESPACE + +#endif // QQMLENGINEDEBUGCLIENT_P_P_H diff --git a/src/qmldebug/qqmlinspectorclient.cpp b/src/qmldebug/qqmlinspectorclient.cpp new file mode 100644 index 0000000000..1de52bd0c1 --- /dev/null +++ b/src/qmldebug/qqmlinspectorclient.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "qqmlinspectorclient_p_p.h" + +#include <private/qpacket_p.h> +#include <private/qqmldebugconnection_p.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QQmlInspectorClient::QQmlInspectorClient(QQmlDebugConnection *connection) : + QQmlDebugClient(*new QQmlInspectorClientPrivate(connection)) +{ +} + +QQmlInspectorClientPrivate::QQmlInspectorClientPrivate(QQmlDebugConnection *connection) : + QQmlDebugClientPrivate(QLatin1String("QmlInspector"), connection) +{ +} + +int QQmlInspectorClient::setInspectToolEnabled(bool enabled) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray(enabled ? "enable" : "disable"); + + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +int QQmlInspectorClient::setShowAppOnTop(bool showOnTop) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray("showAppOnTop") << showOnTop; + + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +int QQmlInspectorClient::setAnimationSpeed(qreal speed) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray("setAnimationSpeed") << speed; + + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +int QQmlInspectorClient::select(const QList<int> &objectIds) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray("select") << objectIds; + + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +int QQmlInspectorClient::createObject(const QString &qml, int parentId, const QStringList &imports, + const QString &filename) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray("createObject") << qml << parentId << imports << filename; + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +int QQmlInspectorClient::moveObject(int childId, int newParentId) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray("moveObject") << childId << newParentId; + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +int QQmlInspectorClient::destroyObject(int objectId) +{ + Q_D(QQmlInspectorClient); + QPacket ds(connection()->currentDataStreamVersion()); + ds << QByteArray("request") << ++(d->m_lastRequestId) + << QByteArray("destroyObject") << objectId; + sendMessage(ds.data()); + return d->m_lastRequestId; +} + +void QQmlInspectorClient::messageReceived(const QByteArray &message) +{ + QPacket ds(connection()->currentDataStreamVersion(), message); + QByteArray type; + ds >> type; + + if (type != QByteArray("response")) { + qDebug() << "Unhandled message of type" << type; + return; + } + + int responseId; + bool result; + ds >> responseId >> result; + emit responseReceived(responseId, result); +} + +QT_END_NAMESPACE diff --git a/src/qmldebug/qqmlinspectorclient_p.h b/src/qmldebug/qqmlinspectorclient_p.h new file mode 100644 index 0000000000..d4ab136c9a --- /dev/null +++ b/src/qmldebug/qqmlinspectorclient_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QQMLINSPECTORCLIENT_P_H +#define QQMLINSPECTORCLIENT_P_H + +#include <private/qqmldebugclient_p.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QQmlInspectorClientPrivate; +class QQmlInspectorClient : public QQmlDebugClient +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQmlInspectorClient) + +public: + QQmlInspectorClient(QQmlDebugConnection *connection); + + int setInspectToolEnabled(bool enabled); + int setShowAppOnTop(bool showOnTop); + int setAnimationSpeed(qreal speed); + int select(const QList<int> &objectIds); + int createObject(const QString &qml, int parentId, const QStringList &imports, + const QString &filename); + int moveObject(int childId, int newParentId); + int destroyObject(int objectId); + +signals: + void responseReceived(int requestId, bool result); + +protected: + void messageReceived(const QByteArray &message) override; +}; + +QT_END_NAMESPACE + +#endif // QQMLINSPECTORCLIENT_P_H diff --git a/src/qmldebug/qqmlinspectorclient_p_p.h b/src/qmldebug/qqmlinspectorclient_p_p.h new file mode 100644 index 0000000000..91537dd994 --- /dev/null +++ b/src/qmldebug/qqmlinspectorclient_p_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QQMLINSPECTORCLIENT_P_P_H +#define QQMLINSPECTORCLIENT_P_P_H + +#include "qqmlinspectorclient_p.h" +#include "qqmldebugclient_p_p.h" + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QQmlInspectorClientPrivate : public QQmlDebugClientPrivate +{ + Q_DECLARE_PUBLIC(QQmlInspectorClient) +public: + QQmlInspectorClientPrivate(QQmlDebugConnection *connection); + int m_lastRequestId = -1; +}; + +QT_END_NAMESPACE + +#endif // QQMLINSPECTORCLIENT_P_P_H diff --git a/src/qmldebug/qv4debugclient.cpp b/src/qmldebug/qv4debugclient.cpp new file mode 100644 index 0000000000..76c2f1ebea --- /dev/null +++ b/src/qmldebug/qv4debugclient.cpp @@ -0,0 +1,578 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "qv4debugclient_p.h" +#include "qv4debugclient_p_p.h" +#include "qqmldebugconnection_p.h" + +#include <private/qpacket_p.h> + +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonValue> +#include <QJsonArray> + +QT_BEGIN_NAMESPACE + +const char *V8REQUEST = "v8request"; +const char *V8MESSAGE = "v8message"; +const char *SEQ = "seq"; +const char *TYPE = "type"; +const char *COMMAND = "command"; +const char *ARGUMENTS = "arguments"; +const char *STEPACTION = "stepaction"; +const char *STEPCOUNT = "stepcount"; +const char *EXPRESSION = "expression"; +const char *FRAME = "frame"; +const char *CONTEXT = "context"; +const char *GLOBAL = "global"; +const char *DISABLEBREAK = "disable_break"; +const char *HANDLES = "handles"; +const char *INCLUDESOURCE = "includeSource"; +const char *FROMFRAME = "fromFrame"; +const char *TOFRAME = "toFrame"; +const char *BOTTOM = "bottom"; +const char *NUMBER = "number"; +const char *FRAMENUMBER = "frameNumber"; +const char *TYPES = "types"; +const char *IDS = "ids"; +const char *FILTER = "filter"; +const char *FROMLINE = "fromLine"; +const char *TOLINE = "toLine"; +const char *TARGET = "target"; +const char *LINE = "line"; +const char *COLUMN = "column"; +const char *ENABLED = "enabled"; +const char *CONDITION = "condition"; +const char *IGNORECOUNT = "ignoreCount"; +const char *BREAKPOINT = "breakpoint"; +const char *FLAGS = "flags"; + +const char *CONTINEDEBUGGING = "continue"; +const char *EVALUATE = "evaluate"; +const char *LOOKUP = "lookup"; +const char *BACKTRACE = "backtrace"; +const char *SCOPE = "scope"; +const char *SCOPES = "scopes"; +const char *SCRIPTS = "scripts"; +const char *SOURCE = "source"; +const char *SETBREAKPOINT = "setbreakpoint"; +const char *CLEARBREAKPOINT = "clearbreakpoint"; +const char *CHANGEBREAKPOINT = "changebreakpoint"; +const char *SETEXCEPTIONBREAK = "setexceptionbreak"; +const char *VERSION = "version"; +const char *DISCONNECT = "disconnect"; +const char *GARBAGECOLLECTOR = "gc"; + +const char *CONNECT = "connect"; +const char *INTERRUPT = "interrupt"; + +const char *REQUEST = "request"; +const char *IN = "in"; +const char *NEXT = "next"; +const char *OUT = "out"; + +const char *SCRIPT = "script"; +const char *SCRIPTREGEXP = "scriptRegExp"; +const char *EVENT = "event"; + +const char *ALL = "all"; +const char *UNCAUGHT = "uncaught"; + +#define VARIANTMAPINIT \ + Q_D(QV4DebugClient); \ + QJsonObject jsonVal; \ + jsonVal.insert(QLatin1String(SEQ), d->seq++); \ + jsonVal.insert(QLatin1String(TYPE), QLatin1String(REQUEST)); + +QV4DebugClient::QV4DebugClient(QQmlDebugConnection *connection) + : QQmlDebugClient(*new QV4DebugClientPrivate(connection)) +{ + QObject::connect(this, &QQmlDebugClient::stateChanged, + this, [this](State state) { d_func()->onStateChanged(state); }); +} + +QV4DebugClientPrivate::QV4DebugClientPrivate(QQmlDebugConnection *connection) : + QQmlDebugClientPrivate(QLatin1String("V8Debugger"), connection) +{ +} + +void QV4DebugClient::connect() +{ + Q_D(QV4DebugClient); + d->sendMessage(CONNECT); +} + +void QV4DebugClient::interrupt() +{ + Q_D(QV4DebugClient); + d->sendMessage(INTERRUPT); +} + +void QV4DebugClient::continueDebugging(StepAction action) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "continue", + // "arguments" : { "stepaction" : <"in", "next" or "out">, + // "stepcount" : <number of steps (default 1)> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(CONTINEDEBUGGING)); + + if (action != Continue) { + QJsonObject args; + switch (action) { + case In: + args.insert(QLatin1String(STEPACTION), QLatin1String(IN)); + break; + case Out: + args.insert(QLatin1String(STEPACTION), QLatin1String(OUT)); + break; + case Next: + args.insert(QLatin1String(STEPACTION), QLatin1String(NEXT)); + break; + default: + break; + } + jsonVal.insert(QLatin1String(ARGUMENTS), args); + } + + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::evaluate(const QString &expr, int frame, int context) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "evaluate", + // "arguments" : { "expression" : <expression to evaluate>, + // "frame" : <number>, + // "context" : <object ID> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(EVALUATE)); + + QJsonObject args; + args.insert(QLatin1String(EXPRESSION), expr); + + if (frame != -1) + args.insert(QLatin1String(FRAME), frame); + + if (context != -1) + args.insert(QLatin1String(CONTEXT), context); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::lookup(const QList<int> &handles, bool includeSource) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "lookup", + // "arguments" : { "handles" : <array of handles>, + // "includeSource" : <boolean indicating whether the source will be included when script objects are returned>, + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND),(QLatin1String(LOOKUP))); + + QJsonObject args; + QJsonArray array; + + for (int handle : handles) + array.append(handle); + + args.insert(QLatin1String(HANDLES), array); + + if (includeSource) + args.insert(QLatin1String(INCLUDESOURCE), includeSource); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::backtrace(int fromFrame, int toFrame, bool bottom) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "backtrace", + // "arguments" : { "fromFrame" : <number> + // "toFrame" : <number> + // "bottom" : <boolean, set to true if the bottom of the stack is requested> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(BACKTRACE)); + + QJsonObject args; + + if (fromFrame != -1) + args.insert(QLatin1String(FROMFRAME), fromFrame); + + if (toFrame != -1) + args.insert(QLatin1String(TOFRAME), toFrame); + + if (bottom) + args.insert(QLatin1String(BOTTOM), bottom); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::frame(int number) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "frame", + // "arguments" : { "number" : <frame number> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(FRAME)); + + if (number != -1) { + QJsonObject args; + args.insert(QLatin1String(NUMBER), number); + jsonVal.insert(QLatin1String(ARGUMENTS), args); + } + + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::scope(int number, int frameNumber) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "scope", + // "arguments" : { "number" : <scope number> + // "frameNumber" : <frame number, optional uses selected frame if missing> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SCOPE)); + + if (number != -1) { + QJsonObject args; + args.insert(QLatin1String(NUMBER), number); + + if (frameNumber != -1) + args.insert(QLatin1String(FRAMENUMBER), frameNumber); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + } + + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::scripts(int types, const QList<int> &ids, bool includeSource) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "scripts", + // "arguments" : { "types" : <types of scripts to retrieve + // set bit 0 for native scripts + // set bit 1 for extension scripts + // set bit 2 for normal scripts + // (default is 4 for normal scripts)> + // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned> + // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned> + // "filter" : <string or number: filter string or script id. + // If a number is specified, then only the script with the same number as its script id will be retrieved. + // If a string is specified, then only scripts whose names contain the filter string will be retrieved.> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SCRIPTS)); + + QJsonObject args; + args.insert(QLatin1String(TYPES), types); + + if (ids.count()) { + QJsonArray array; + for (int id : ids) + array.append(id); + + args.insert(QLatin1String(IDS), array); + } + + if (includeSource) + args.insert(QLatin1String(INCLUDESOURCE), includeSource); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::setBreakpoint(const QString &target, int line, int column, bool enabled, + const QString &condition, int ignoreCount) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "setbreakpoint", + // "arguments" : { "type" : "scriptRegExp" + // "target" : <function expression or script identification> + // "line" : <line in script or function> + // "column" : <character position within the line> + // "enabled" : <initial enabled state. True or false, default is true> + // "condition" : <string with break point condition> + // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0> + // } + // } + + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SETBREAKPOINT)); + + QJsonObject args; + + args.insert(QLatin1String(TYPE), QLatin1String(SCRIPTREGEXP)); + args.insert(QLatin1String(TARGET), target); + + if (line != -1) + args.insert(QLatin1String(LINE), line); + + if (column != -1) + args.insert(QLatin1String(COLUMN), column); + + args.insert(QLatin1String(ENABLED), enabled); + + if (!condition.isEmpty()) + args.insert(QLatin1String(CONDITION), condition); + + if (ignoreCount != -1) + args.insert(QLatin1String(IGNORECOUNT), ignoreCount); + + jsonVal.insert(QLatin1String(ARGUMENTS),args); + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::clearBreakpoint(int breakpoint) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "clearbreakpoint", + // "arguments" : { "breakpoint" : <number of the break point to clear> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(CLEARBREAKPOINT)); + + QJsonObject args; + args.insert(QLatin1String(BREAKPOINT), breakpoint); + jsonVal.insert(QLatin1String(ARGUMENTS),args); + + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::changeBreakpoint(int breakpoint, bool enabled) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "changebreakpoint", + // "arguments" : { "breakpoint" : <number of the break point to change> + // "enabled" : <bool: enables the break type if true, disables if false> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(CHANGEBREAKPOINT)); + + QJsonObject args; + args.insert(QLatin1String(BREAKPOINT), breakpoint); + args.insert(QLatin1String(ENABLED), enabled); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::setExceptionBreak(Exception type, bool enabled) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "setexceptionbreak", + // "arguments" : { "type" : <string: "all", or "uncaught">, + // "enabled" : <optional bool: enables the break type if true> + // } + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(SETEXCEPTIONBREAK)); + + QJsonObject args; + + if (type == All) + args.insert(QLatin1String(TYPE), QLatin1String(ALL)); + else if (type == Uncaught) + args.insert(QLatin1String(TYPE), QLatin1String(UNCAUGHT)); + + if (enabled) + args.insert(QLatin1String(ENABLED), enabled); + + jsonVal.insert(QLatin1String(ARGUMENTS), args); + d->sendMessage(V8REQUEST, jsonVal); +} + +void QV4DebugClient::version() +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "version", + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(VERSION)); + d->sendMessage(V8REQUEST, jsonVal); +} + +QV4DebugClient::Response QV4DebugClient::response() const +{ + Q_D(const QV4DebugClient); + const QJsonObject value = QJsonDocument::fromJson(d->response).object(); + return { + value.value(QLatin1String(COMMAND)).toString(), + value.value(QLatin1String("body")) + }; +} + +void QV4DebugClient::disconnect() +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "disconnect", + // } + VARIANTMAPINIT; + jsonVal.insert(QLatin1String(COMMAND), QLatin1String(DISCONNECT)); + d->sendMessage(DISCONNECT, jsonVal); +} + +void QV4DebugClientPrivate::onStateChanged(QQmlDebugClient::State state) +{ + if (state == QQmlDebugClient::Enabled) + flushSendBuffer(); +} + +void QV4DebugClient::messageReceived(const QByteArray &data) +{ + Q_D(QV4DebugClient); + QPacket ds(connection()->currentDataStreamVersion(), data); + QByteArray command; + ds >> command; + + if (command == "V8DEBUG") { + QByteArray type; + ds >> type >> d->response; + + if (type == CONNECT) { + emit connected(); + + } else if (type == INTERRUPT) { + emit interrupted(); + + } else if (type == V8MESSAGE) { + const QJsonObject value = QJsonDocument::fromJson(d->response).object(); + QString type = value.value(QLatin1String(TYPE)).toString(); + + if (type == QLatin1String("response")) { + + if (!value.value(QLatin1String("success")).toBool()) { + emit failure(); + qDebug() << "Received success == false response from application:" + << value.value(QLatin1String("message")).toString(); + return; + } + + QString debugCommand(value.value(QLatin1String(COMMAND)).toString()); + if (debugCommand == QLatin1String(BACKTRACE) || + debugCommand == QLatin1String(LOOKUP) || + debugCommand == QLatin1String(SETBREAKPOINT) || + debugCommand == QLatin1String(EVALUATE) || + debugCommand == QLatin1String(VERSION) || + debugCommand == QLatin1String(DISCONNECT) || + debugCommand == QLatin1String(GARBAGECOLLECTOR) || + debugCommand == QLatin1String(CHANGEBREAKPOINT) || + debugCommand == QLatin1String(CLEARBREAKPOINT) || + debugCommand == QLatin1String(FRAME) || + debugCommand == QLatin1String(SCOPE) || + debugCommand == QLatin1String(SCOPES) || + debugCommand == QLatin1String(SCRIPTS) || + debugCommand == QLatin1String(SOURCE) || + debugCommand == QLatin1String(SETEXCEPTIONBREAK)) { + emit result(); + } else { + // DO NOTHING + } + + } else if (type == QLatin1String(EVENT)) { + QString event(value.value(QLatin1String(EVENT)).toString()); + + if (event == QLatin1String("break") || event == QLatin1String("exception")) + emit stopped(); + } + } + } +} + +void QV4DebugClientPrivate::sendMessage(const QByteArray &command, const QJsonObject &args) +{ + Q_Q(QV4DebugClient); + const QByteArray msg = packMessage(command, args); + if (q->state() == QQmlDebugClient::Enabled) { + q->sendMessage(msg); + } else { + sendBuffer.append(msg); + } +} + +void QV4DebugClientPrivate::flushSendBuffer() +{ + foreach (const QByteArray &msg, sendBuffer) + sendMessage(msg); + sendBuffer.clear(); +} + +QByteArray QV4DebugClientPrivate::packMessage(const QByteArray &type, const QJsonObject &object) +{ + QPacket rs(connection->currentDataStreamVersion()); + QByteArray cmd = "V8DEBUG"; + rs << cmd << type << QJsonDocument(object).toJson(QJsonDocument::Compact); + return rs.data(); +} + +QT_END_NAMESPACE diff --git a/src/qmldebug/qv4debugclient_p.h b/src/qmldebug/qv4debugclient_p.h new file mode 100644 index 0000000000..fdcf4284c5 --- /dev/null +++ b/src/qmldebug/qv4debugclient_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QV4DEBUGCLIENT_P_H +#define QV4DEBUGCLIENT_P_H + +#include <QtQmlDebug/private/qqmldebugclient_p.h> +#include <QtCore/qjsonvalue.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QV4DebugClientPrivate; +class QV4DebugClient : public QQmlDebugClient +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QV4DebugClient) + +public: + enum StepAction + { + Continue, + In, + Out, + Next + }; + + enum Exception + { + All, + Uncaught + }; + + struct Response + { + QString command; + QJsonValue body; + }; + + QV4DebugClient(QQmlDebugConnection *connection); + + void connect(); + void disconnect(); + + void interrupt(); + void continueDebugging(StepAction stepAction); + void evaluate(const QString &expr, int frame = -1, int context = -1); + void lookup(const QList<int> &handles, bool includeSource = false); + void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false); + void frame(int number = -1); + void scope(int number = -1, int frameNumber = -1); + void scripts(int types = 4, const QList<int> &ids = QList<int>(), bool includeSource = false); + void setBreakpoint(const QString &target, int line = -1, int column = -1, bool enabled = true, + const QString &condition = QString(), int ignoreCount = -1); + void clearBreakpoint(int breakpoint); + void changeBreakpoint(int breakpoint, bool enabled); + void setExceptionBreak(Exception type, bool enabled = false); + void version(); + + Response response() const; + +protected: + void messageReceived(const QByteArray &data) override; + +signals: + void connected(); + void interrupted(); + void result(); + void failure(); + void stopped(); +}; + +QT_END_NAMESPACE + +#endif // QV4DEBUGCLIENT_P_H diff --git a/src/qmldebug/qv4debugclient_p_p.h b/src/qmldebug/qv4debugclient_p_p.h new file mode 100644 index 0000000000..993c281632 --- /dev/null +++ b/src/qmldebug/qv4debugclient_p_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#ifndef QV4DEBUGCLIENT_P_P_H +#define QV4DEBUGCLIENT_P_P_H + +#include "qv4debugclient_p.h" +#include "qqmldebugclient_p_p.h" + +#include <QtCore/qjsonobject.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QV4DebugClientPrivate : public QQmlDebugClientPrivate +{ + Q_DECLARE_PUBLIC(QV4DebugClient) + +public: + QV4DebugClientPrivate(QQmlDebugConnection *connection); + + void sendMessage(const QByteArray &command, const QJsonObject &args = QJsonObject()); + void flushSendBuffer(); + QByteArray packMessage(const QByteArray &type, const QJsonObject &object); + void onStateChanged(QQmlDebugClient::State state); + + int seq = 0; + QList<QByteArray> sendBuffer; + QByteArray response; +}; + +QT_END_NAMESPACE + +#endif // QV4DEBUGCLIENT_P_P_H |