1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlenginecontrolclient_p.h"
5#include "qqmlenginecontrolclient_p_p.h"
6#include "qqmldebugconnection_p.h"
7
8#include <private/qpacket_p.h>
9
10QT_BEGIN_NAMESPACE
11
12QQmlEngineControlClient::QQmlEngineControlClient(QQmlDebugConnection *connection) :
13 QQmlDebugClient(*(new QQmlEngineControlClientPrivate(connection)))
14{
15}
16
17QQmlEngineControlClient::QQmlEngineControlClient(QQmlEngineControlClientPrivate &dd) :
18 QQmlDebugClient(dd)
19{
20}
21
22/*!
23 * Block the starting or stopping of the engine with id \a engineId for now. By calling
24 * releaseEngine later the block can be lifted again. In the debugged application the engine control
25 * server waits until a message is received before continuing. So by not sending a message here we
26 * delay the process. Blocks add up. You have to call releaseEngine() as often as you've called
27 * blockEngine before. The intention of that is to allow different debug clients to use the same
28 * engine control and communicate with their respective counterparts before the QML engine starts or
29 * shuts down.
30 */
31void QQmlEngineControlClient::blockEngine(int engineId)
32{
33 Q_D(QQmlEngineControlClient);
34 Q_ASSERT(d->blockedEngines.contains(engineId));
35 d->blockedEngines[engineId].blockers++;
36}
37
38/*!
39 * Release the engine with id \a engineId. If no other blocks are present, depending on what the
40 * engine is waiting for, the start or stop command is sent to the process being debugged.
41 */
42void QQmlEngineControlClient::releaseEngine(int engineId)
43{
44 Q_D(QQmlEngineControlClient);
45 Q_ASSERT(d->blockedEngines.contains(engineId));
46
47 QQmlEngineControlClientPrivate::EngineState &state = d->blockedEngines[engineId];
48 if (--state.blockers == 0) {
49 Q_ASSERT(state.releaseCommand != QQmlEngineControlClientPrivate::InvalidCommand);
50 d->sendCommand(command: state.releaseCommand, engineId);
51 d->blockedEngines.remove(key: engineId);
52 }
53}
54
55QList<int> QQmlEngineControlClient::blockedEngines() const
56{
57 Q_D(const QQmlEngineControlClient);
58 return d->blockedEngines.keys();
59}
60
61void QQmlEngineControlClient::messageReceived(const QByteArray &data)
62{
63 Q_D(QQmlEngineControlClient);
64 QPacket stream(d->connection->currentDataStreamVersion(), data);
65 qint32 message;
66 qint32 id;
67 QString name;
68
69 stream >> message >> id;
70
71 if (!stream.atEnd())
72 stream >> name;
73
74 auto handleWaiting = [&](
75 QQmlEngineControlClientPrivate::CommandType command, std::function<void()> emitter) {
76 QQmlEngineControlClientPrivate::EngineState &state = d->blockedEngines[id];
77 Q_ASSERT(state.blockers == 0);
78 Q_ASSERT(state.releaseCommand == QQmlEngineControlClientPrivate::InvalidCommand);
79 state.releaseCommand = command;
80 emitter();
81 if (state.blockers == 0) {
82 d->sendCommand(command: state.releaseCommand, engineId: id);
83 d->blockedEngines.remove(key: id);
84 }
85 };
86
87 switch (message) {
88 case QQmlEngineControlClientPrivate::EngineAboutToBeAdded:
89 handleWaiting(QQmlEngineControlClientPrivate::StartWaitingEngine, [&](){
90 emit engineAboutToBeAdded(engineId: id, name);
91 });
92 break;
93 case QQmlEngineControlClientPrivate::EngineAdded:
94 emit engineAdded(engineId: id, name);
95 break;
96 case QQmlEngineControlClientPrivate::EngineAboutToBeRemoved:
97 handleWaiting(QQmlEngineControlClientPrivate::StopWaitingEngine, [&](){
98 emit engineAboutToBeRemoved(engineId: id, name);
99 });
100 break;
101 case QQmlEngineControlClientPrivate::EngineRemoved:
102 emit engineRemoved(engineId: id, name);
103 break;
104 }
105}
106
107QQmlEngineControlClientPrivate::QQmlEngineControlClientPrivate(QQmlDebugConnection *connection) :
108 QQmlDebugClientPrivate(QLatin1String("EngineControl"), connection)
109{
110}
111
112void QQmlEngineControlClientPrivate::sendCommand(
113 QQmlEngineControlClientPrivate::CommandType command, int engineId)
114{
115 Q_Q(QQmlEngineControlClient);
116 QPacket stream(connection->currentDataStreamVersion());
117 stream << static_cast<qint32>(command) << engineId;
118 q->sendMessage(message: stream.data());
119}
120
121QT_END_NAMESPACE
122
123#include "moc_qqmlenginecontrolclient_p.cpp"
124

source code of qtdeclarative/src/qmldebug/qqmlenginecontrolclient.cpp