diff --git a/interface/src/scripting/DesktopScriptingInterface.cpp b/interface/src/scripting/DesktopScriptingInterface.cpp
index ef5bd7abb9..678e698033 100644
--- a/interface/src/scripting/DesktopScriptingInterface.cpp
+++ b/interface/src/scripting/DesktopScriptingInterface.cpp
@@ -111,10 +111,11 @@ void DesktopScriptingInterface::show(const QString& path, const QString& title)
InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString& sourceUrl, const QVariantMap& properties) {
if (QThread::currentThread() != thread()) {
InteractiveWindowPointer interactiveWindow = nullptr;
- BLOCKING_INVOKE_METHOD(this, "createWindow",
+ BLOCKING_INVOKE_METHOD(this, "createWindowOnThread",
Q_RETURN_ARG(InteractiveWindowPointer, interactiveWindow),
Q_ARG(QString, sourceUrl),
- Q_ARG(QVariantMap, properties));
+ Q_ARG(QVariantMap, properties),
+ Q_ARG(QThread*, QThread::currentThread()));
return interactiveWindow;
}
@@ -129,3 +130,17 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString&
return new InteractiveWindow(sourceUrl, properties);
}
+
+InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread) {
+
+ // The offscreen surface already validates against non-local QML sources, but we also need to ensure that
+ // if we create top level QML, like dock widgets or other types of QQuickView containing desktop windows
+ // that the source URL is permitted
+ const auto& urlValidator = OffscreenQmlSurface::getUrlValidator();
+ if (!urlValidator(sourceUrl)) {
+ return nullptr;
+ }
+ InteractiveWindowPointer window = new InteractiveWindow(sourceUrl, properties);
+ window->moveToThread(targetThread);
+ return window;
+}
diff --git a/interface/src/scripting/DesktopScriptingInterface.h b/interface/src/scripting/DesktopScriptingInterface.h
index b4ff159176..525fd7c803 100644
--- a/interface/src/scripting/DesktopScriptingInterface.h
+++ b/interface/src/scripting/DesktopScriptingInterface.h
@@ -101,6 +101,8 @@ private:
static int flagAlwaysOnTop() { return AlwaysOnTop; }
static int flagCloseButtonHides() { return CloseButtonHides; }
+ Q_INVOKABLE InteractiveWindowPointer createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread);
+
static QVariantMap getDockArea();
Q_INVOKABLE static QVariantMap getPresentationMode();
diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index dfef16b536..c85d7bc301 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -85,13 +85,13 @@ void InteractiveWindow::forwardKeyReleaseEvent(int key, int modifiers) {
* @property {string} [title="InteractiveWindow] - The title of the window.
* @property {Vec2} [position] - The initial position of the window, in pixels.
* @property {Vec2} [size] - The initial size of the window, in pixels
- * @property {boolean} [visible=true] - true
to make the window visible when created, false
to make
+ * @property {boolean} [visible=true] - true
to make the window visible when created, false
to make
* it invisible.
- * @property {InteractiveWindow.PresentationMode} [presentationMode=Desktop.PresentationMode.VIRTUAL] -
- * Desktop.PresentationMode.VIRTUAL
to display the window inside Interface, .NATIVE
to display it
+ * @property {InteractiveWindow.PresentationMode} [presentationMode=Desktop.PresentationMode.VIRTUAL] -
+ * Desktop.PresentationMode.VIRTUAL
to display the window inside Interface, .NATIVE
to display it
* as its own separate window.
- * @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a NATIVE
window is
- * displayed. If used, the window is docked to the specified edge of the Interface window, otherwise the window is
+ * @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a NATIVE
window is
+ * displayed. If used, the window is docked to the specified edge of the Interface window, otherwise the window is
* displayed as its own separate window.
* @property {InteractiveWindow.AdditionalFlags} [additionalFlags=0] - Window behavior flags in addition to "native window flags" (minimize/maximize/close),
* set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}.
@@ -124,7 +124,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
auto mainWindow = qApp->getWindow();
_dockWidget = std::shared_ptr(new DockWidget(title, mainWindow), dockWidgetDeleter);
auto quickView = _dockWidget->getQuickView();
-
+
Application::setupQmlSurface(quickView->rootContext() , true);
//add any whitelisted callbacks
@@ -176,7 +176,6 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
});
_dockWidget->setSource(QUrl(sourceUrl));
-
mainWindow->addDockWidget(dockArea, _dockWidget.get());
} else {
auto offscreenUi = DependencyManager::get();
@@ -254,55 +253,35 @@ void InteractiveWindow::sendToQml(const QVariant& message) {
}
void InteractiveWindow::emitScriptEvent(const QVariant& scriptMessage) {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, scriptMessage));
- } else {
- emit scriptEventReceived(scriptMessage);
- }
+ emit scriptEventReceived(scriptMessage);
}
void InteractiveWindow::emitWebEvent(const QVariant& webMessage) {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, webMessage));
- } else {
- emit webEventReceived(webMessage);
- }
+ emit webEventReceived(webMessage);
}
void InteractiveWindow::close() {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "close");
- return;
- }
-
if (_qmlWindow) {
_qmlWindow->deleteLater();
}
- qApp->getWindow()->removeDockWidget(_dockWidget.get());
+ if (_dockWidget) {
+ auto window = qApp->getWindow();
+ BLOCKING_INVOKE_METHOD(window, "removeDockWidget", Q_ARG(QDockWidget*, _dockWidget.get()));
+ }
_dockWidget = nullptr;
_qmlWindow = nullptr;
}
void InteractiveWindow::show() {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "show");
- return;
- }
-
if (_qmlWindow) {
- QMetaObject::invokeMethod(_qmlWindow, "show", Qt::DirectConnection);
+ QMetaObject::invokeMethod(_qmlWindow, "show");
}
}
void InteractiveWindow::raise() {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "raise");
- return;
- }
-
if (_qmlWindow) {
- QMetaObject::invokeMethod(_qmlWindow, "raiseWindow", Qt::DirectConnection);
+ QMetaObject::invokeMethod(_qmlWindow, "raiseWindow");
}
}
@@ -323,17 +302,12 @@ void InteractiveWindow::setVisible(bool visible) {
}
if (!_qmlWindow.isNull()) {
- _qmlWindow->setProperty(INTERACTIVE_WINDOW_VISIBLE_PROPERTY, visible);
+ QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_VISIBLE_PROPERTY),
+ Q_ARG(bool, visible));
}
}
bool InteractiveWindow::isVisible() const {
- if (QThread::currentThread() != thread()) {
- bool result = false;
- BLOCKING_INVOKE_METHOD(const_cast(this), "isVisible", Q_RETURN_ARG(bool, result));
- return result;
- }
-
if (_qmlWindow.isNull()) {
return false;
}
@@ -342,12 +316,6 @@ bool InteractiveWindow::isVisible() const {
}
glm::vec2 InteractiveWindow::getPosition() const {
- if (QThread::currentThread() != thread()) {
- glm::vec2 result;
- BLOCKING_INVOKE_METHOD(const_cast(this), "getPosition", Q_RETURN_ARG(glm::vec2, result));
- return result;
- }
-
if (_qmlWindow.isNull()) {
return {};
}
@@ -362,18 +330,13 @@ void InteractiveWindow::setPosition(const glm::vec2& position) {
}
if (!_qmlWindow.isNull()) {
- _qmlWindow->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y));
- QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowPositionForMode", Qt::DirectConnection);
+ QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_POSITION_PROPERTY),
+ Q_ARG(QPointF, QPointF(position.x, position.y)));
+ QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowPositionForMode");
}
}
glm::vec2 InteractiveWindow::getSize() const {
- if (QThread::currentThread() != thread()) {
- glm::vec2 result;
- BLOCKING_INVOKE_METHOD(const_cast(this), "getSize", Q_RETURN_ARG(glm::vec2, result));
- return result;
- }
-
if (_qmlWindow.isNull()) {
return {};
}
@@ -381,24 +344,14 @@ glm::vec2 InteractiveWindow::getSize() const {
}
void InteractiveWindow::setSize(const glm::vec2& size) {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "setSize", Q_ARG(const glm::vec2&, size));
- return;
- }
-
if (!_qmlWindow.isNull()) {
- _qmlWindow->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y));
- QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowSizeForMode", Qt::DirectConnection);
+ QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_SIZE_PROPERTY),
+ Q_ARG(QSize, QSize(size.x, size.y)));
+ QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowSizeForMode");
}
}
QString InteractiveWindow::getTitle() const {
- if (QThread::currentThread() != thread()) {
- QString result;
- BLOCKING_INVOKE_METHOD(const_cast(this), "getTitle", Q_RETURN_ARG(QString, result));
- return result;
- }
-
if (_qmlWindow.isNull()) {
return QString();
}
@@ -406,24 +359,13 @@ QString InteractiveWindow::getTitle() const {
}
void InteractiveWindow::setTitle(const QString& title) {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "setTitle", Q_ARG(const QString&, title));
- return;
- }
-
if (!_qmlWindow.isNull()) {
- _qmlWindow->setProperty(TITLE_PROPERTY, title);
+ QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, TITLE_PROPERTY),
+ Q_ARG(QString, title));
}
}
int InteractiveWindow::getPresentationMode() const {
- if (QThread::currentThread() != thread()) {
- int result;
- BLOCKING_INVOKE_METHOD(const_cast(this), "getPresentationMode",
- Q_RETURN_ARG(int, result));
- return result;
- }
-
if (_qmlWindow.isNull()) {
return Virtual;
}
@@ -449,12 +391,8 @@ void InteractiveWindow::parentNativeWindowToMainWindow() {
}
void InteractiveWindow::setPresentationMode(int presentationMode) {
- if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "setPresentationMode", Q_ARG(int, presentationMode));
- return;
- }
-
if (!_qmlWindow.isNull()) {
- _qmlWindow->setProperty(PRESENTATION_MODE_PROPERTY, presentationMode);
+ QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, PRESENTATION_MODE_PROPERTY),
+ Q_ARG(int, presentationMode));
}
}