From c4b63ed5e428d7d8d0f2fe59f859c33c580d32b1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 24 Jul 2019 11:20:08 -0700 Subject: [PATCH] Fix qmlToScript getting called on script thread and causing crash --- interface/src/ui/InteractiveWindow.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index fc2d8c56bf..1a4d631c23 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -187,8 +187,11 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap if (status == QQuickView::Ready) { QQuickItem* rootItem = _dockWidget->getRootItem(); _dockWidget->getQuickView()->rootContext()->setContextProperty(EVENT_BRIDGE_PROPERTY, this); + // The qmlToScript method handles the thread-safety of this call. Because the QVariant argument + // passed to the sendToScript signal may wrap an externally managed and thread-unsafe QJSValue, + // qmlToScript needs to be called directly, so the QJSValue can be immediately converted to a plain QVariant. QObject::connect(rootItem, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), - Qt::QueuedConnection); + Qt::DirectConnection); QObject::connect(rootItem, SIGNAL(keyPressEvent(int, int)), this, SLOT(forwardKeyPressEvent(int, int)), Qt::QueuedConnection); QObject::connect(rootItem, SIGNAL(keyReleaseEvent(int, int)), this, SLOT(forwardKeyReleaseEvent(int, int)), @@ -229,7 +232,10 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap object->setProperty(VISIBLE_PROPERTY, properties[INTERACTIVE_WINDOW_VISIBLE_PROPERTY].toBool()); } - connect(object, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::QueuedConnection); + // The qmlToScript method handles the thread-safety of this call. Because the QVariant argument + // passed to the sendToScript signal may wrap an externally managed and thread-unsafe QJSValue, + // qmlToScript needs to be called directly, so the QJSValue can be immediately converted to a plain QVariant. + connect(object, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::DirectConnection); QObject::connect(object, SIGNAL(keyPressEvent(int, int)), this, SLOT(forwardKeyPressEvent(int, int)), Qt::QueuedConnection); QObject::connect(object, SIGNAL(keyReleaseEvent(int, int)), this, SLOT(forwardKeyReleaseEvent(int, int)), @@ -315,13 +321,21 @@ void InteractiveWindow::raise() { } } -void InteractiveWindow::qmlToScript(const QVariant& message) { +void InteractiveWindow::qmlToScript(const QVariant& originalMessage) { + QVariant message = originalMessage; if (message.canConvert()) { - emit fromQml(qvariant_cast(message).toVariant()); + message = qvariant_cast(message).toVariant(); } else if (message.canConvert()) { - emit fromQml(message.toString()); + message = message.toString(); } else { qWarning() << "Unsupported message type " << message; + return; + } + + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "fromQml", Q_ARG(const QVariant&, message)); + } else { + emit fromQml(message); } }