Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmldebugserverfactory.cpp
Go to the documentation of this file.
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
5
6#include <private/qqmldebugserver_p.h>
7#include <private/qqmldebugserverconnection_p.h>
8#include <private/qqmldebugservice_p.h>
9#include <private/qjsengine_p.h>
10#include <private/qqmlglobal_p.h>
11#include <private/qqmldebugpluginmanager_p.h>
12#include <private/qqmldebugserviceinterfaces_p.h>
13#include <private/qpacketprotocol_p.h>
14#include <private/qversionedpacket_p.h>
15
16#include <QtCore/QAtomicInt>
17#include <QtCore/QDir>
18#include <QtCore/QPluginLoader>
19#include <QtCore/QStringList>
20#include <QtCore/QVector>
21#include <QtCore/qwaitcondition.h>
22
24
25/*
26 QQmlDebug Protocol (Version 1):
27
28 handshake:
29 1. Client sends
30 "QDeclarativeDebugServer" 0 version pluginNames [QDataStream version]
31 version: an int representing the highest protocol version the client knows
32 pluginNames: plugins available on client side
33 2. Server sends
34 "QDeclarativeDebugClient" 0 version pluginNames pluginVersions [QDataStream version]
35 version: an int representing the highest protocol version the client & server know
36 pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
37 client plugin advertisement
38 1. Client sends
39 "QDeclarativeDebugServer" 1 pluginNames
40 server plugin advertisement (not implemented: all services are required to register before open())
41 1. Server sends
42 "QDeclarativeDebugClient" 1 pluginNames pluginVersions
43 plugin communication:
44 Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin.
45 */
46
48
49const int protocolVersion = 1;
51
54{
55public:
56 QQmlDebugServerThread() : m_server(nullptr), m_portFrom(-1), m_portTo(-1) {}
57
59 {
60 m_server = server;
61 }
62
63 void setPortRange(int portFrom, int portTo, const QString &hostAddress)
64 {
65 m_pluginName = QLatin1String("QTcpServerConnection");
66 m_portFrom = portFrom;
67 m_portTo = portTo;
68 m_hostAddress = hostAddress;
69 }
70
72 {
73 m_pluginName = QLatin1String("QLocalClientConnection");
74 m_fileName = fileName;
75 }
76
77 const QString &pluginName() const
78 {
79 return m_pluginName;
80 }
81
82 void run() override;
83
84private:
85 QQmlDebugServerImpl *m_server;
86 QString m_pluginName;
87 int m_portFrom;
88 int m_portTo;
89 QString m_hostAddress;
90 QString m_fileName;
91};
92
94{
96public:
98
99 bool blockingMode() const override;
100
101 QQmlDebugService *service(const QString &name) const override;
102
103 void addEngine(QJSEngine *engine) override;
104 void removeEngine(QJSEngine *engine) override;
105 bool hasEngine(QJSEngine *engine) const override;
106
107 bool addService(const QString &name, QQmlDebugService *service) override;
108 bool removeService(const QString &name) override;
109
110 bool open(const QVariantHash &configuration) override;
111 void setDevice(QIODevice *socket) override;
112
113 void parseArguments();
114
115 static void cleanup();
116
117private:
120
121 class EngineCondition {
122 public:
123 EngineCondition() : numServices(0), condition(new QWaitCondition) {}
124
125 bool waitForServices(QMutex *locked, int numEngines);
126 bool isWaiting() const { return numServices > 0; }
127
128 void wake();
129 private:
130 int numServices;
131
132 // shared pointer to allow for QHash-inflicted copying.
133 QSharedPointer<QWaitCondition> condition;
134 };
135
136 bool canSendMessage(const QString &name);
137 void doSendMessage(const QString &name, const QByteArray &message);
138 void wakeEngine(QJSEngine *engine);
139 void sendMessage(const QString &name, const QByteArray &message);
140 void sendMessages(const QString &name, const QList<QByteArray> &messages);
141 void changeServiceState(const QString &serviceName, QQmlDebugService::State state);
142 void removeThread();
143 void receiveMessage();
144 void protocolError();
145
146 QQmlDebugServerConnection *m_connection;
147 QHash<QString, QQmlDebugService *> m_plugins;
148 QStringList m_clientPlugins;
149 bool m_gotHello;
150 bool m_blockingMode;
151
152 QHash<QJSEngine *, EngineCondition> m_engineConditions;
153
154 mutable QMutex m_helloMutex;
155 QWaitCondition m_helloCondition;
156 QQmlDebugServerThread m_thread;
157 QPacketProtocol *m_protocol;
158 QAtomicInt m_changeServiceStateCalls;
159};
160
162{
165 if (!server)
166 return;
167
168 {
169 QObject signalSource;
170 for (QHash<QString, QQmlDebugService *>::ConstIterator i = server->m_plugins.constBegin();
171 i != server->m_plugins.constEnd(); ++i) {
172 server->m_changeServiceStateCalls.ref();
173 QString key = i.key();
174 // Process this in the server's thread.
175 connect(&signalSource, &QObject::destroyed, server, [key, server](){
176 server->changeServiceState(key, QQmlDebugService::NotConnected);
178 }
179 }
180
181 // Wait for changeServiceState calls to finish
182 // (while running an event loop because some services
183 // might again defer execution of stuff in the GUI thread)
184 QEventLoop loop;
185 while (!server->m_changeServiceStateCalls.testAndSetOrdered(0, 0))
186 loop.processEvents();
187
188 // Stop the thread while the application is still there.
189 server->m_thread.exit();
190 server->m_thread.wait();
191}
192
194{
195 Q_ASSERT_X(m_server != nullptr, Q_FUNC_INFO, "There should always be a debug server available here.");
196 QQmlDebugServerConnection *connection = loadQQmlDebugServerConnection(m_pluginName);
197 if (connection) {
198 {
199 QMutexLocker connectionLocker(&m_server->m_helloMutex);
200 m_server->m_connection = connection;
201 connection->setServer(m_server);
202 m_server->m_helloCondition.wakeAll();
203 }
204
205 if (m_fileName.isEmpty()) {
206 if (!connection->setPortRange(m_portFrom, m_portTo, m_server->blockingMode(),
207 m_hostAddress))
208 return;
209 } else if (!connection->setFileName(m_fileName, m_server->blockingMode())) {
210 return;
211 }
212
213 if (m_server->blockingMode())
214 connection->waitForConnection();
215 } else {
216 qWarning() << "QML Debugger: Couldn't load plugin" << m_pluginName;
217 return;
218 }
219
220 exec();
221
222 // make sure events still waiting are processed
223 QEventLoop eventLoop;
225}
226
228{
229 return m_blockingMode;
230}
231
232static void cleanupOnShutdown()
233{
234 // We cannot do this in the destructor as the connection plugin will get unloaded before the
235 // server plugin and we need the connection to send any remaining data. This function is
236 // triggered before any plugins are unloaded.
238}
239
241 m_connection(nullptr),
242 m_gotHello(false),
243 m_blockingMode(false)
244{
245 static bool postRoutineAdded = false;
246 if (!postRoutineAdded) {
248 postRoutineAdded = true;
249 }
250
251 // used in sendMessages
252 qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
253 // used in changeServiceState
254 qRegisterMetaType<QQmlDebugService::State>("QQmlDebugService::State");
255
256 m_thread.setServer(this);
257 moveToThread(&m_thread);
258
259 // Remove the thread immmediately when it finishes, so that we don't have to wait for the
260 // event loop to signal that.
261 QObject::connect(&m_thread, &QThread::finished, this, &QQmlDebugServerImpl::removeThread,
263 m_thread.setObjectName(QStringLiteral("QQmlDebugServerThread"));
265}
266
268{
269 if (m_thread.isRunning())
270 return false;
271 if (!configuration.isEmpty()) {
272 m_blockingMode = configuration[QLatin1String("block")].toBool();
273 if (configuration.contains(QLatin1String("portFrom"))) {
274 int portFrom = configuration[QLatin1String("portFrom")].toInt();
275 int portTo = configuration[QLatin1String("portTo")].toInt();
276 m_thread.setPortRange(portFrom, portTo == -1 ? portFrom : portTo,
277 configuration[QLatin1String("hostAddress")].toString());
278 } else if (configuration.contains(QLatin1String("fileName"))) {
279 m_thread.setFileName(configuration[QLatin1String("fileName")].toString());
280 } else {
281 return false;
282 }
283 }
284
285 if (m_thread.pluginName().isEmpty())
286 return false;
287
288 QMutexLocker locker(&m_helloMutex);
289 m_thread.start();
290 m_helloCondition.wait(&m_helloMutex); // wait for connection
291 if (m_blockingMode && !m_gotHello)
292 m_helloCondition.wait(&m_helloMutex); // wait for hello
293 return true;
294}
295
297{
298 // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block]
299 const QString args = commandLineArguments();
300 if (args.isEmpty())
301 return; // Manual initialization, through QQmlDebugServer::open()
302
303 // ### remove port definition when protocol is changed
304 int portFrom = 0;
305 int portTo = 0;
306 bool block = false;
307 bool ok = false;
308 QString hostAddress;
311
312 const auto lstjsDebugArguments = QStringView{args}.split(QLatin1Char(','), Qt::SkipEmptyParts);
313 for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) {
314 const QStringView &strArgument = *argsIt;
315 if (strArgument.startsWith(QLatin1String("port:"))) {
316 portFrom = strArgument.mid(5).toInt(&ok);
317 portTo = portFrom;
318 const auto argsNext = argsIt + 1;
319 if (argsNext == argsItEnd)
320 break;
321 if (ok) {
322 portTo = argsNext->toString().toInt(&ok);
323 if (ok) {
324 ++argsIt;
325 } else {
326 portTo = portFrom;
327 ok = true;
328 }
329 }
330 } else if (strArgument.startsWith(QLatin1String("host:"))) {
331 hostAddress = strArgument.mid(5).toString();
332 } else if (strArgument == QLatin1String("block")) {
333 block = true;
334 } else if (strArgument.startsWith(QLatin1String("file:"))) {
335 fileName = strArgument.mid(5).toString();
336 ok = !fileName.isEmpty();
337 } else if (strArgument.startsWith(QLatin1String("services:"))) {
338 services.append(strArgument.mid(9).toString());
339 } else if (!services.isEmpty()) {
340 services.append(strArgument.toString());
341 } else if (!strArgument.startsWith(QLatin1String("connector:"))) {
342 const QString message = tr("QML Debugger: Invalid argument \"%1\" detected."
343 " Ignoring the same.").arg(strArgument.toString());
345 }
346 }
347
348 if (ok) {
349 setServices(services);
350 m_blockingMode = block;
351 if (!fileName.isEmpty())
352 m_thread.setFileName(fileName);
353 else
354 m_thread.setPortRange(portFrom, portTo, hostAddress);
355 } else {
358 str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n'
359 << tr("The format is \"-qmljsdebugger=[file:<file>|port:<port_from>][,<port_to>]"
360 "[,host:<ip address>][,block][,services:<service>][,<service>]*\"") << '\n'
361 << tr("\"file:\" can be used to specify the name of a file the debugger will try "
362 "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and"
363 "\"port:\" arguments will be ignored.") << '\n'
364 << tr("\"host:\" and \"port:\" can be used to specify an address and a single "
365 "port or a range of ports the debugger will try to bind to with a "
366 "QTcpServer.") << '\n'
367 << tr("\"block\" makes the debugger and some services wait for clients to be "
368 "connected and ready before the first QML engine starts.") << '\n'
369 << tr("\"services:\" can be used to specify which debug services the debugger "
370 "should load. Some debug services interact badly with others. The V4 "
371 "debugger should not be loaded when using the QML profiler as it will force "
372 "any V4 engines to use the JavaScript interpreter rather than the JIT. The "
373 "following debug services are available by default:") << '\n'
374 << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n'
375 << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n'
376 << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n'
377 << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n'
378 << QQmlEngineControlService::s_key << "\t- "
379 //: Please preserve the line breaks and formatting
380 << tr("Allows the client to delay the starting and stopping of\n"
381 "\t\t QML engines until other services are ready. QtCreator\n"
382 "\t\t uses this service with the QML profiler in order to\n"
383 "\t\t profile multiple QML engines at the same time.")
384 << '\n' << QDebugMessageService::s_key << "\t- "
385 //: Please preserve the line breaks and formatting
386 << tr("Sends qDebug() and similar messages over the QML debug\n"
387 "\t\t connection. QtCreator uses this for showing debug\n"
388 "\t\t messages in the debugger console.") << '\n'
389#if QT_CONFIG(translation)
390 << '\n' << QQmlDebugTranslationService::s_key << "\t- "
391 //: Please preserve the line breaks and formatting
392 << tr("helps to see if a translated text\n"
393 "\t\t will result in an elided text\n"
394 "\t\t in QML elements.") << '\n'
395#endif //QT_CONFIG(translation)
396 << tr("Other services offered by qmltooling plugins that implement "
397 "QQmlDebugServiceFactory and which can be found in the standard plugin "
398 "paths will also be available and can be specified. If no \"services\" "
399 "argument is given, all services found this way, including the default "
400 "ones, are loaded.");
401 qWarning("%s", qPrintable(usage));
402 }
403}
404
405void QQmlDebugServerImpl::receiveMessage()
406{
407 typedef QHash<QString, QQmlDebugService*>::const_iterator DebugServiceConstIt;
408
409 // to be executed in debugger thread
410 Q_ASSERT(QThread::currentThread() == thread());
411
412 if (!m_protocol)
413 return;
414
415 QQmlDebugPacket in(m_protocol->read());
416
418
419 in >> name;
420 if (name == QLatin1String("QDeclarativeDebugServer")) {
421 int op = -1;
422 in >> op;
423 if (op == 0) {
424 int version;
425 in >> version >> m_clientPlugins;
426
427 //Get the supported QDataStream version
428 if (!in.atEnd()) {
429 in >> s_dataStreamVersion;
430 if (s_dataStreamVersion > QDataStream::Qt_DefaultCompiledVersion)
431 s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion;
432 }
433
434 bool clientSupportsMultiPackets = false;
435 if (!in.atEnd())
436 in >> clientSupportsMultiPackets;
437
438 // Send the hello answer immediately, since it needs to arrive before
439 // the plugins below start sending messages.
440
442 QStringList pluginNames;
443 QList<float> pluginVersions;
444 if (clientSupportsMultiPackets) { // otherwise, disable all plugins
445 const int count = m_plugins.size();
446 pluginNames.reserve(count);
447 pluginVersions.reserve(count);
449 i != m_plugins.constEnd(); ++i) {
450 pluginNames << i.key();
451 pluginVersions << i.value()->version();
452 }
453 }
454
455 out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion
456 << pluginNames << pluginVersions << dataStreamVersion();
457
458 m_protocol->send(out.data());
459 m_connection->flush();
460
461 QMutexLocker helloLock(&m_helloMutex);
462 m_gotHello = true;
463
464 for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) {
466 if (m_clientPlugins.contains(iter.key()))
468 m_changeServiceStateCalls.ref();
469 changeServiceState(iter.key(), newState);
470 }
471
472 m_helloCondition.wakeAll();
473
474 } else if (op == 1) {
475 // Service Discovery
476 QStringList oldClientPlugins = m_clientPlugins;
477 in >> m_clientPlugins;
478
479 for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) {
480 const QString &pluginName = iter.key();
482 if (m_clientPlugins.contains(pluginName))
484
485 if (oldClientPlugins.contains(pluginName)
486 != m_clientPlugins.contains(pluginName)) {
487 m_changeServiceStateCalls.ref();
488 changeServiceState(iter.key(), newState);
489 }
490 }
491
492 } else {
493 qWarning("QML Debugger: Invalid control message %d.", op);
494 protocolError();
495 return;
496 }
497
498 } else {
499 if (m_gotHello) {
500 const auto iter = m_plugins.constFind(name);
501 if (iter == m_plugins.cend()) {
502 qWarning() << "QML Debugger: Message received for missing plugin" << name << '.';
503 } else {
506 while (!in.atEnd()) {
507 in >> message;
508 service->messageReceived(message);
509 }
510 }
511 } else {
512 qWarning("QML Debugger: Invalid hello message.");
513 }
514
515 }
516}
517
518void QQmlDebugServerImpl::changeServiceState(const QString &serviceName,
520{
521 // to be executed in debugger thread
522 Q_ASSERT(QThread::currentThread() == thread());
523
524 QQmlDebugService *service = m_plugins.value(serviceName);
525 if (service && service->state() != newState) {
526 service->stateAboutToBeChanged(newState);
527 service->setState(newState);
528 service->stateChanged(newState);
529 }
530
531 m_changeServiceStateCalls.deref();
532}
533
534void QQmlDebugServerImpl::removeThread()
535{
536 Q_ASSERT(m_thread.isFinished());
537 Q_ASSERT(QThread::currentThread() == thread());
538
539 QThread *parentThread = m_thread.thread();
540
541 delete m_connection;
542 m_connection = nullptr;
543
544 // Move it back to the parent thread so that we can potentially restart it on a new thread.
545 moveToThread(parentThread);
546}
547
549{
550 return m_plugins.value(name);
551}
552
554{
555 // to be executed outside of debugger thread
556 Q_ASSERT(QThread::currentThread() != &m_thread);
557
558 QMutexLocker locker(&m_helloMutex);
559 Q_ASSERT(!m_engineConditions.contains(engine));
560
561 for (QQmlDebugService *service : std::as_const(m_plugins))
562 service->engineAboutToBeAdded(engine);
563
564 m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.size());
565
566 for (QQmlDebugService *service : std::as_const(m_plugins))
567 service->engineAdded(engine);
568}
569
571{
572 // to be executed outside of debugger thread
573 Q_ASSERT(QThread::currentThread() != &m_thread);
574
575 QMutexLocker locker(&m_helloMutex);
576 Q_ASSERT(m_engineConditions.contains(engine));
577
578 for (QQmlDebugService *service : std::as_const(m_plugins))
579 service->engineAboutToBeRemoved(engine);
580
581 m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.size());
582
583 for (QQmlDebugService *service : std::as_const(m_plugins))
584 service->engineRemoved(engine);
585
586 m_engineConditions.remove(engine);
587}
588
590{
591 QMutexLocker locker(&m_helloMutex);
593 // if we're still waiting the engine isn't fully "there", yet, nor fully removed.
594 return i != m_engineConditions.constEnd() && !i.value().isWaiting();
595}
596
598{
599 // to be executed before thread starts
600 Q_ASSERT(!m_thread.isRunning());
601
602 if (!service || m_plugins.contains(name))
603 return false;
604
606 this, &QQmlDebugServerImpl::sendMessage);
608 this, &QQmlDebugServerImpl::sendMessages);
609
611 this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection);
613 this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection);
614
616 m_plugins.insert(name, service);
617
618 return true;
619}
620
622{
623 // to be executed after thread ends
624 Q_ASSERT(!m_thread.isRunning());
625
626 QQmlDebugService *service = m_plugins.value(name);
627 if (!service)
628 return false;
629
630 m_plugins.remove(name);
632
634 this, &QQmlDebugServerImpl::wakeEngine);
636 this, &QQmlDebugServerImpl::wakeEngine);
637
639 this, &QQmlDebugServerImpl::sendMessages);
641 this, &QQmlDebugServerImpl::sendMessage);
642
643 return true;
644}
645
646bool QQmlDebugServerImpl::canSendMessage(const QString &name)
647{
648 // to be executed in debugger thread
649 Q_ASSERT(QThread::currentThread() == thread());
650 return m_connection && m_connection->isConnected() && m_protocol &&
651 m_clientPlugins.contains(name);
652}
653
654void QQmlDebugServerImpl::doSendMessage(const QString &name, const QByteArray &message)
655{
657 out << name << message;
658 m_protocol->send(out.data());
659}
660
661void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message)
662{
663 if (canSendMessage(name)) {
664 doSendMessage(name, message);
665 m_connection->flush();
666 }
667}
668
669void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages)
670{
671 if (canSendMessage(name)) {
673 out << name;
674 for (const QByteArray &message : messages)
675 out << message;
676 m_protocol->send(out.data());
677 m_connection->flush();
678 }
679}
680
681void QQmlDebugServerImpl::wakeEngine(QJSEngine *engine)
682{
683 // to be executed in debugger thread
684 Q_ASSERT(QThread::currentThread() == thread());
685
686 QMutexLocker locker(&m_helloMutex);
687 m_engineConditions[engine].wake();
688}
689
690bool QQmlDebugServerImpl::EngineCondition::waitForServices(QMutex *locked, int num)
691{
692 Q_ASSERT_X(numServices == 0, Q_FUNC_INFO, "Request to wait again before previous wait finished");
693 numServices = num;
694 return numServices > 0 ? condition->wait(locked) : true;
695}
696
697void QQmlDebugServerImpl::EngineCondition::wake()
698{
699 if (--numServices == 0)
700 condition->wakeAll();
701 Q_ASSERT_X(numServices >=0, Q_FUNC_INFO, "Woken more often than #services.");
702}
703
705{
706 m_protocol = new QPacketProtocol(socket, this);
708 this, &QQmlDebugServerImpl::receiveMessage);
710 this, &QQmlDebugServerImpl::protocolError);
711
712 if (blockingMode())
713 m_protocol->waitForReadyRead(-1);
714}
715
716void QQmlDebugServerImpl::protocolError()
717{
718 qWarning("QML Debugger: A protocol error has occurred! Giving up ...");
719 m_connection->disconnect();
720 // protocol might still be processing packages at this point
721 m_protocol->deleteLater();
722 m_protocol = nullptr;
723}
724
726{
727 // Cannot parent it to this because it gets moved to another thread
728 return (key == QLatin1String("QQmlDebugServer") ? new QQmlDebugServerImpl : nullptr);
729}
730
732
733#include "moc_qqmldebugserverfactory.cpp"
734#include "qqmldebugserverfactory.moc"
std::vector< ObjCStrongReference< CBMutableService > > services
\inmodule QtCore
Definition qatomic.h:112
bool ref() noexcept
bool deref() noexcept
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qeventloop.h:16
bool processEvents(ProcessEventsFlags flags=AllEvents)
Processes some pending events that match flags.
\inmodule QtCore
Definition qhash.h:1145
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:927
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1219
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1215
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
const_iterator cend() const noexcept
Definition qhash.h:1218
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
\inmodule QtCore \reentrant
Definition qiodevice.h:34
The QJSEngine class provides an environment for evaluating JavaScript code.
Definition qjsengine.h:26
bool isEmpty() const noexcept
Definition qlist.h:401
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:127
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
The QPacketProtocol class encapsulates communicating discrete packets across fragmented IO channels,...
void send(const QByteArray &data)
Transmit the packet.
void readyRead()
Emitted whenever a new packet is received.
bool waitForReadyRead(int msecs=3000)
This function locks until a new packet is available for reading and the \l{QIODevice::}{readyRead()} ...
QByteArray read()
Return the next unread packet, or an empty QByteArray if no packets are available.
static Service * service()
static QQmlDebugConnector * instance()
virtual void flush()=0
virtual bool isConnected() const =0
virtual void disconnect()=0
QQmlDebugConnector * create(const QString &key) override
void addEngine(QJSEngine *engine) override
bool removeService(const QString &name) override
bool addService(const QString &name, QQmlDebugService *service) override
bool blockingMode() const override
void removeEngine(QJSEngine *engine) override
void setDevice(QIODevice *socket) override
bool open(const QVariantHash &configuration) override
bool hasEngine(QJSEngine *engine) const override
void setPortRange(int portFrom, int portTo, const QString &hostAddress)
void setServer(QQmlDebugServerImpl *server)
void setFileName(const QString &fileName)
const QString & pluginName() const
void messageToClient(const QString &name, const QByteArray &message)
void detachedFromEngine(QJSEngine *)
void attachedToEngine(QJSEngine *)
void messagesToClient(const QString &name, const QList< QByteArray > &messages)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
\inmodule QtCore
void start(Priority=InheritPriority)
Definition qthread.cpp:996
bool isRunning() const
Definition qthread.cpp:1064
bool isFinished() const
Definition qthread.cpp:1059
static QThread * currentThread()
Definition qthread.cpp:1039
void finished(QPrivateSignal)
int exec()
Definition qthread.cpp:991
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
QString str
[2]
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
const PluginKeyMapConstIterator cend
Combined button and popup list for selecting options.
@ QueuedConnection
@ DirectConnection
@ SkipEmptyParts
Definition qnamespace.h:128
#define Q_FUNC_INFO
QHash< QString, QVariant > QVariantHash
void qAddPostRoutine(QtCleanUpFunction p)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall DBusPendingCall return DBusPendingCall return dbus_int32_t return DBusServer * server
DBusConnection * connection
#define qWarning
Definition qlogging.h:166
GLuint64 key
GLenum condition
GLenum GLenum GLsizei count
GLuint GLsizei const GLchar * message
GLuint name
GLuint in
GLuint num
GLsizeiptr const void GLenum usage
Definition qopenglext.h:543
#define Q_QML_DEBUG_PLUGIN_LOADER(interfaceName)
QT_BEGIN_NAMESPACE const int protocolVersion
static void cleanupOnShutdown()
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define qPrintable(string)
Definition qstring.h:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define tr(X)
#define Q_OBJECT
QTextStream out(stdout)
[7]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QObject::connect nullptr
myObject disconnect()
[26]
QTcpSocket * socket
[1]
myObject moveToThread(QApplication::instance() ->thread())
[6]
QJSValueList args
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18