1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qqmldebugpluginmanager_p.h"
41 #include "qqmldebugconnector_p.h"
42 #include "qqmldebugservicefactory_p.h"
43 #include <QtCore/QPluginLoader>
44 #include <QtCore/QCoreApplication>
45 #include <QtCore/QDir>
46 #include <QtCore/QDebug>
47 #include <QtCore/QJsonArray>
48 #include <QtCore/QDataStream>
49
50 #include <private/qcoreapplication_p.h>
51 #include <private/qqmlengine_p.h>
52
53 QT_BEGIN_NAMESPACE
54
55 // Connectors. We could add more plugins here, and distinguish by arguments to instance()
56 Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugConnector)
57
58 // Services
59 Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugService)
60
61 int QQmlDebugConnector::s_dataStreamVersion = QDataStream::Qt_4_7;
62
63 struct QQmlDebugConnectorParams {
64 QString pluginKey;
65 QStringList services;
66 QString arguments;
67 QQmlDebugConnector *instance;
68
QQmlDebugConnectorParamsQQmlDebugConnectorParams69 QQmlDebugConnectorParams() : instance(nullptr)
70 {
71 if (qApp) {
72 QCoreApplicationPrivate *appD =
73 static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
74 if (appD)
75 arguments = appD->qmljsDebugArgumentsString();
76 }
77 }
78 };
79
Q_GLOBAL_STATIC(QQmlDebugConnectorParams,qmlDebugConnectorParams)80 Q_GLOBAL_STATIC(QQmlDebugConnectorParams, qmlDebugConnectorParams)
81
82 void QQmlDebugConnector::setPluginKey(const QString &key)
83 {
84 QQmlDebugConnectorParams *params = qmlDebugConnectorParams();
85 if (params && params->pluginKey != key) {
86 if (params->instance)
87 qWarning() << "QML debugger: Cannot set plugin key after loading the plugin.";
88 else
89 params->pluginKey = key;
90 }
91 }
92
setServices(const QStringList & services)93 void QQmlDebugConnector::setServices(const QStringList &services)
94 {
95 QQmlDebugConnectorParams *params = qmlDebugConnectorParams();
96 if (params)
97 params->services = services;
98 }
99
commandLineArguments()100 QString QQmlDebugConnector::commandLineArguments()
101 {
102 QQmlDebugConnectorParams *params = qmlDebugConnectorParams();
103 if (!params)
104 return QString();
105 return params->arguments;
106 }
107
instance()108 QQmlDebugConnector *QQmlDebugConnector::instance()
109 {
110 QQmlDebugConnectorParams *params = qmlDebugConnectorParams();
111 if (!params)
112 return nullptr;
113
114 if (!QQmlEnginePrivate::qml_debugging_enabled) {
115 if (!params->arguments.isEmpty()) {
116 qWarning().noquote() << QString::fromLatin1(
117 "QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging "
118 "has not been enabled.").arg(params->arguments);
119 params->arguments.clear();
120 }
121 return nullptr;
122 }
123
124 if (!params->instance) {
125 if (!params->pluginKey.isEmpty()) {
126 params->instance = loadQQmlDebugConnector(params->pluginKey);
127 } else if (params->arguments.isEmpty()) {
128 return nullptr; // no explicit class name given and no command line arguments
129 } else if (params->arguments.startsWith(QLatin1String("connector:"))) {
130 static const int connectorBegin = int(strlen("connector:"));
131
132 int connectorEnd = params->arguments.indexOf(QLatin1Char(','), connectorBegin);
133 if (connectorEnd == -1)
134 connectorEnd = params->arguments.length();
135
136 params->instance = loadQQmlDebugConnector(params->arguments.mid(
137 connectorBegin,
138 connectorEnd - connectorBegin));
139 } else {
140 params->instance = loadQQmlDebugConnector(
141 params->arguments.startsWith(QLatin1String("native")) ?
142 QStringLiteral("QQmlNativeDebugConnector") :
143 QStringLiteral("QQmlDebugServer"));
144 }
145
146 if (params->instance) {
147 const auto metaData = metaDataForQQmlDebugService();
148 for (const QJsonObject &object : metaData) {
149 const auto keys = object.value(QLatin1String("MetaData")).toObject()
150 .value(QLatin1String("Keys")).toArray();
151 for (const QJsonValue &key : keys) {
152 QString keyString = key.toString();
153 if (params->services.isEmpty() || params->services.contains(keyString))
154 loadQQmlDebugService(keyString);
155 }
156 }
157 }
158 }
159
160 return params->instance;
161 }
162
~QQmlDebugConnectorFactory()163 QQmlDebugConnectorFactory::~QQmlDebugConnectorFactory()
164 {
165 // This is triggered when the plugin is unloaded.
166 QQmlDebugConnectorParams *params = qmlDebugConnectorParams();
167 if (params) {
168 params->pluginKey.clear();
169 params->arguments.clear();
170 params->services.clear();
171 delete params->instance;
172 params->instance = nullptr;
173 }
174 }
175
176 QT_END_NAMESPACE
177
178 #include "moc_qqmldebugconnector_p.cpp"
179