From 7c024b4e8aa3e49fa1d78c6152fdc2dfb57764e6 Mon Sep 17 00:00:00 2001
From: dante ruiz <dante@highfidelity.io>
Date: Thu, 13 Jun 2019 11:37:42 -0700
Subject: [PATCH 1/4] fix interactive window crash

---
 .../scripting/DesktopScriptingInterface.cpp   |  19 ++-
 .../src/scripting/DesktopScriptingInterface.h |   2 +
 interface/src/ui/InteractiveWindow.cpp        | 114 ++++--------------
 3 files changed, 45 insertions(+), 90 deletions(-)

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] - <code>true</code> to make the window visible when created, <code>false</code> to make 
+ * @property {boolean} [visible=true] - <code>true</code> to make the window visible when created, <code>false</code> to make
  *     it invisible.
- * @property {InteractiveWindow.PresentationMode} [presentationMode=Desktop.PresentationMode.VIRTUAL] - 
- *     <code>Desktop.PresentationMode.VIRTUAL</code> to display the window inside Interface, <code>.NATIVE</code> to display it 
+ * @property {InteractiveWindow.PresentationMode} [presentationMode=Desktop.PresentationMode.VIRTUAL] -
+ *     <code>Desktop.PresentationMode.VIRTUAL</code> to display the window inside Interface, <code>.NATIVE</code> to display it
  *     as its own separate window.
- * @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a <code>NATIVE</code> 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 <code>NATIVE</code> 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<DockWidget>(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<OffscreenUi>();
@@ -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<InteractiveWindow*>(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<InteractiveWindow*>(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<InteractiveWindow*>(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<InteractiveWindow*>(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<InteractiveWindow*>(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));
     }
 }

From c4a0b39068f7c0666be1c1ed6859e0c64c8afb2c Mon Sep 17 00:00:00 2001
From: dante ruiz <dante@highfidelity.io>
Date: Wed, 10 Jul 2019 17:56:54 -0700
Subject: [PATCH 2/4] requested changes

---
 interface/src/ui/InteractiveWindow.cpp | 30 +++++++++++++++++---------
 interface/src/ui/InteractiveWindow.h   | 23 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index c85d7bc301..84094a2500 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -51,6 +51,26 @@ static const QStringList KNOWN_SCHEMES = QStringList() << "http" << "https" << "
 
 static const int DEFAULT_HEIGHT = 60;
 
+QmlWindowProxy::QmlWindowProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qmlObject, parent) {
+    _qmlWindow = qmlObject;
+}
+
+void QmlWindowProxy::updateInteractiveWindowPositionForMode() {
+}
+
+void QmlWindowProxy::setPosition(const glm::vec2& position) {
+}
+
+glm::vec2 QmlWindowProxy::getPosition() const {
+}
+
+void QmlWindowProxy::setSize(const glm::vec2& size) {
+}
+
+glm::vec2 QmlWindowProxy::getSize() const {
+}
+
+void QmlWindowProxy::setTitle(const QString& title
 static void dockWidgetDeleter(DockWidget* dockWidget) {
     dockWidget->deleteLater();
 }
@@ -296,11 +316,6 @@ void InteractiveWindow::qmlToScript(const QVariant& message) {
 }
 
 void InteractiveWindow::setVisible(bool visible) {
-    if (QThread::currentThread() != thread()) {
-        QMetaObject::invokeMethod(this, "setVisible", Q_ARG(bool, visible));
-        return;
-    }
-
     if (!_qmlWindow.isNull()) {
         QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_VISIBLE_PROPERTY),
                                   Q_ARG(bool, visible));
@@ -324,11 +339,6 @@ glm::vec2 InteractiveWindow::getPosition() const {
 }
 
 void InteractiveWindow::setPosition(const glm::vec2& position) {
-    if (QThread::currentThread() != thread()) {
-        QMetaObject::invokeMethod(this, "setPosition", Q_ARG(const glm::vec2&, position));
-        return;
-    }
-
     if (!_qmlWindow.isNull()) {
         QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_POSITION_PROPERTY),
                                   Q_ARG(QPointF, QPointF(position.x, position.y)));
diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h
index c7b3631dde..d9886bd138 100644
--- a/interface/src/ui/InteractiveWindow.h
+++ b/interface/src/ui/InteractiveWindow.h
@@ -18,10 +18,33 @@
 #include <QtCore/QPointer>
 #include <QtScript/QScriptValue>
 #include <QQmlEngine>
+#include <ui/QmlWrapper.h>
 
 #include <glm/glm.hpp>
 #include <GLMHelpers.h>
 
+class QmlWindowProxy : QmlWrapper {
+    Q_OBJECT
+
+public:
+    QmlWindowProxy(QObject* qmlObject, QObject* parent = nullptr);
+
+    Q_INVOKABLE void updateInteractiveWindowPositionForMode();
+
+    Q_INVOKABLE void setPosition(const glm::vec2& position);
+    glm::vec2 getPositiion() const;
+
+    Q_INVOKABLE void setSize(const glm::vec2& size);
+    glm::vec2 getSize() const;
+
+    Q_INVOKABLE void setTitle(const QString& title);
+    QString getTitle() const;
+private:
+    QObject* _qmlWindow;
+
+};
+
+
 namespace InteractiveWindowEnums {
     Q_NAMESPACE
 

From 2f74f8253fc232a82ac903192933b75b0bcf7d5f Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Thu, 11 Jul 2019 15:32:44 -0700
Subject: [PATCH 3/4] finishing requested changes

---
 interface/src/ui/InteractiveWindow.cpp | 167 +++++++++++++++++--------
 interface/src/ui/InteractiveWindow.h   |  18 ++-
 2 files changed, 126 insertions(+), 59 deletions(-)

diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index 84094a2500..2c580deb47 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -55,22 +55,96 @@ QmlWindowProxy::QmlWindowProxy(QObject* qmlObject, QObject* parent) : QmlWrapper
     _qmlWindow = qmlObject;
 }
 
-void QmlWindowProxy::updateInteractiveWindowPositionForMode() {
-}
-
 void QmlWindowProxy::setPosition(const glm::vec2& position) {
+    if (_qmlWindow) {
+        _qmlWindow->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y));
+        QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowPositionForMode");
+    }
 }
 
 glm::vec2 QmlWindowProxy::getPosition() const {
+    if (!_qmlWindow) {
+        return {};
+    }
+
+    return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_POSITION_PROPERTY).toPointF());
 }
 
 void QmlWindowProxy::setSize(const glm::vec2& size) {
+    if (_qmlWindow) {
+        _qmlWindow->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y));
+        QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowSizeForMode");
+    }
 }
 
 glm::vec2 QmlWindowProxy::getSize() const {
+    if (!_qmlWindow) {
+        return {};
+    }
+
+    return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_SIZE_PROPERTY).toSize());
+}
+
+void QmlWindowProxy::setTitle(const QString& title) {
+    if (_qmlWindow) {
+        _qmlWindow->setProperty(TITLE_PROPERTY, title);
+    }
+}
+
+QString QmlWindowProxy::getTitle() const {
+    if (!_qmlWindow) {
+        return QString();
+    }
+
+    return _qmlWindow->property(TITLE_PROPERTY).toString();
+}
+
+void QmlWindowProxy::setVisible(bool visible) {
+    if (_qmlWindow) {
+        _qmlWindow->setProperty(INTERACTIVE_WINDOW_VISIBLE_PROPERTY, visible);
+    }
+}
+
+bool QmlWindowProxy::isVisible() const {
+    if (!_qmlWindow) {
+        return false;
+    }
+
+    return _qmlWindow->property(INTERACTIVE_WINDOW_VISIBLE_PROPERTY).toBool();
+}
+
+void QmlWindowProxy::setPresentationMode(int presentationMode) {
+    if (_qmlWindow) {
+        _qmlWindow->setProperty(PRESENTATION_MODE_PROPERTY, presentationMode);
+    }
+}
+
+int QmlWindowProxy::getPresentationMode() const {
+    if (!_qmlWindow) {
+        return Virtual;
+    }
+
+    return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt();
+}
+
+void QmlWindowProxy::parentNativeWindowToMainWindow() {
+#ifdef Q_OS_WIN
+    if (!_qmlWindow) {
+        return;
+    }
+    const auto nativeWindowProperty = _qmlWindow->property("nativeWindow");
+    if (nativeWindowProperty.isNull() || !nativeWindowProperty.isValid()) {
+        return;
+    }
+    const auto nativeWindow = qvariant_cast<QQuickWindow*>(nativeWindowProperty);
+    SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId());
+#endif
+}
+
+static void qmlWindowProxyDeleter(QmlWindowProxy* qmlWindowProxy) {
+    qmlWindowProxy->deleteLater();
 }
 
-void QmlWindowProxy::setTitle(const QString& title
 static void dockWidgetDeleter(DockWidget* dockWidget) {
     dockWidget->deleteLater();
 }
@@ -201,7 +275,7 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
         auto offscreenUi = DependencyManager::get<OffscreenUi>();
         // Build the event bridge and wrapper on the main thread
         offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) {
-            _qmlWindow = object;
+            _qmlWindowProxy = std::shared_ptr<QmlWindowProxy>(new QmlWindowProxy(object, nullptr), qmlWindowProxyDeleter);
             context->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
             if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) {
                 object->setProperty(ADDITIONAL_FLAGS_PROPERTY, properties[ADDITIONAL_FLAGS_PROPERTY].toUInt());
@@ -268,7 +342,7 @@ void InteractiveWindow::sendToQml(const QVariant& message) {
             QMetaObject::invokeMethod(rootItem, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
         }
     } else {
-        QMetaObject::invokeMethod(_qmlWindow, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
+        QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
     }
 }
 
@@ -281,8 +355,12 @@ void InteractiveWindow::emitWebEvent(const QVariant& webMessage) {
 }
 
 void InteractiveWindow::close() {
-    if (_qmlWindow) {
-        _qmlWindow->deleteLater();
+    if (_qmlWindowProxy) {
+        QObject* qmlWindow = _qmlWindowProxy->getQmlWindow();
+        if (qmlWindow) {
+            qmlWindow->deleteLater();
+        }
+        _qmlWindowProxy->deleteLater();
     }
 
     if (_dockWidget) {
@@ -290,18 +368,18 @@ void InteractiveWindow::close() {
         BLOCKING_INVOKE_METHOD(window, "removeDockWidget", Q_ARG(QDockWidget*, _dockWidget.get()));
     }
     _dockWidget = nullptr;
-    _qmlWindow = nullptr;
+    _qmlWindowProxy = nullptr;
 }
 
 void InteractiveWindow::show() {
-    if (_qmlWindow) {
-        QMetaObject::invokeMethod(_qmlWindow, "show");
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "show");
     }
 }
 
 void InteractiveWindow::raise() {
-    if (_qmlWindow) {
-        QMetaObject::invokeMethod(_qmlWindow, "raiseWindow");
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "raiseWindow");
     }
 }
 
@@ -316,93 +394,74 @@ void InteractiveWindow::qmlToScript(const QVariant& message) {
 }
 
 void InteractiveWindow::setVisible(bool visible) {
-    if (!_qmlWindow.isNull()) {
-        QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_VISIBLE_PROPERTY),
-                                  Q_ARG(bool, visible));
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setVisible", Q_ARG(bool, visible));
     }
 }
 
 bool InteractiveWindow::isVisible() const {
-    if (_qmlWindow.isNull()) {
+    if (!_qmlWindowProxy) {
         return false;
     }
 
-    return _qmlWindow->property(INTERACTIVE_WINDOW_VISIBLE_PROPERTY).toBool();
+    return _qmlWindowProxy->isVisible();
 }
 
 glm::vec2 InteractiveWindow::getPosition() const {
-    if (_qmlWindow.isNull()) {
+    if (!_qmlWindowProxy) {
         return {};
     }
 
-    return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_POSITION_PROPERTY).toPointF());
+    return _qmlWindowProxy->getPosition();
 }
 
 void InteractiveWindow::setPosition(const glm::vec2& position) {
-    if (!_qmlWindow.isNull()) {
-        QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_POSITION_PROPERTY),
-                                  Q_ARG(QPointF, QPointF(position.x, position.y)));
-        QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowPositionForMode");
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setPosition", Q_ARG(const glm::vec2&, position));
     }
 }
 
 glm::vec2 InteractiveWindow::getSize() const {
-    if (_qmlWindow.isNull()) {
+    if (!_qmlWindowProxy) {
         return {};
     }
-    return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_SIZE_PROPERTY).toSize());
+    return _qmlWindowProxy->getSize();
 }
 
 void InteractiveWindow::setSize(const glm::vec2& size) {
-    if (!_qmlWindow.isNull()) {
-        QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, INTERACTIVE_WINDOW_SIZE_PROPERTY),
-                                  Q_ARG(QSize, QSize(size.x, size.y)));
-        QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowSizeForMode");
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setSize", Q_ARG(const glm::vec2&, size));
     }
 }
 
 QString InteractiveWindow::getTitle() const {
-    if (_qmlWindow.isNull()) {
+    if (!_qmlWindowProxy) {
         return QString();
     }
-    return _qmlWindow->property(TITLE_PROPERTY).toString();
+    return _qmlWindowProxy->getTitle();
 }
 
 void InteractiveWindow::setTitle(const QString& title) {
-    if (!_qmlWindow.isNull()) {
-        QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, TITLE_PROPERTY),
-                                  Q_ARG(QString, title));
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setTitle", Q_ARG(const QString&, title));
     }
 }
 
 int InteractiveWindow::getPresentationMode() const {
-    if (_qmlWindow.isNull()) {
+    if (!_qmlWindowProxy) {
         return Virtual;
     }
-    return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt();
+    return _qmlWindowProxy->getPresentationMode();
 }
 
 void InteractiveWindow::parentNativeWindowToMainWindow() {
-#ifdef Q_OS_WIN
-    if (QThread::currentThread() != thread()) {
-        QMetaObject::invokeMethod(this, "parentNativeWindowToMainWindow");
-        return;
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "parentNativeWindowToMainWindow");
     }
-    if (_qmlWindow.isNull()) {
-        return;
-    }
-    const auto nativeWindowProperty = _qmlWindow->property("nativeWindow");
-    if (nativeWindowProperty.isNull() || !nativeWindowProperty.isValid()) {
-        return;
-    }
-    const auto nativeWindow = qvariant_cast<QQuickWindow*>(nativeWindowProperty);
-    SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId());
-#endif
 }
 
 void InteractiveWindow::setPresentationMode(int presentationMode) {
-    if (!_qmlWindow.isNull()) {
-        QMetaObject::invokeMethod(_qmlWindow, "setProperty", Q_ARG(const char*, PRESENTATION_MODE_PROPERTY),
-                                  Q_ARG(int, presentationMode));
+    if (_qmlWindowProxy) {
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setPresentationMode", Q_ARG(int, presentationMode));
     }
 }
diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h
index d9886bd138..7abdc5210a 100644
--- a/interface/src/ui/InteractiveWindow.h
+++ b/interface/src/ui/InteractiveWindow.h
@@ -23,22 +23,30 @@
 #include <glm/glm.hpp>
 #include <GLMHelpers.h>
 
-class QmlWindowProxy : QmlWrapper {
+class QmlWindowProxy : public QmlWrapper {
     Q_OBJECT
 
 public:
     QmlWindowProxy(QObject* qmlObject, QObject* parent = nullptr);
 
-    Q_INVOKABLE void updateInteractiveWindowPositionForMode();
-
     Q_INVOKABLE void setPosition(const glm::vec2& position);
-    glm::vec2 getPositiion() const;
+    glm::vec2 getPosition() const;
 
     Q_INVOKABLE void setSize(const glm::vec2& size);
     glm::vec2 getSize() const;
 
     Q_INVOKABLE void setTitle(const QString& title);
     QString getTitle() const;
+
+    Q_INVOKABLE void setVisible(bool visible);
+    bool isVisible() const;
+
+    Q_INVOKABLE void setPresentationMode(int presentationMode);
+    int getPresentationMode() const;
+
+    Q_INVOKABLE void parentNativeWindowToMainWindow();
+
+    QObject* getQmlWindow() const { return _qmlWindow; }
 private:
     QObject* _qmlWindow;
 
@@ -314,7 +322,7 @@ protected slots:
     void forwardKeyReleaseEvent(int key, int modifiers);
 
 private:
-    QPointer<QObject> _qmlWindow;
+    std::shared_ptr<QmlWindowProxy> _qmlWindowProxy;
     std::shared_ptr<DockWidget> _dockWidget { nullptr };
 };
 

From d78661a47f6c191a88a4e133b49a3e2dbb9b31bf Mon Sep 17 00:00:00 2001
From: dante ruiz <dante@highfidelity.io>
Date: Fri, 12 Jul 2019 13:34:08 -0700
Subject: [PATCH 4/4] redo requested work

---
 interface/src/ui/InteractiveWindow.cpp | 118 ++++++++-----------------
 interface/src/ui/InteractiveWindow.h   |  15 ----
 2 files changed, 35 insertions(+), 98 deletions(-)

diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index 2c580deb47..dff1f4dcb5 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -55,78 +55,6 @@ QmlWindowProxy::QmlWindowProxy(QObject* qmlObject, QObject* parent) : QmlWrapper
     _qmlWindow = qmlObject;
 }
 
-void QmlWindowProxy::setPosition(const glm::vec2& position) {
-    if (_qmlWindow) {
-        _qmlWindow->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y));
-        QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowPositionForMode");
-    }
-}
-
-glm::vec2 QmlWindowProxy::getPosition() const {
-    if (!_qmlWindow) {
-        return {};
-    }
-
-    return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_POSITION_PROPERTY).toPointF());
-}
-
-void QmlWindowProxy::setSize(const glm::vec2& size) {
-    if (_qmlWindow) {
-        _qmlWindow->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y));
-        QMetaObject::invokeMethod(_qmlWindow, "updateInteractiveWindowSizeForMode");
-    }
-}
-
-glm::vec2 QmlWindowProxy::getSize() const {
-    if (!_qmlWindow) {
-        return {};
-    }
-
-    return toGlm(_qmlWindow->property(INTERACTIVE_WINDOW_SIZE_PROPERTY).toSize());
-}
-
-void QmlWindowProxy::setTitle(const QString& title) {
-    if (_qmlWindow) {
-        _qmlWindow->setProperty(TITLE_PROPERTY, title);
-    }
-}
-
-QString QmlWindowProxy::getTitle() const {
-    if (!_qmlWindow) {
-        return QString();
-    }
-
-    return _qmlWindow->property(TITLE_PROPERTY).toString();
-}
-
-void QmlWindowProxy::setVisible(bool visible) {
-    if (_qmlWindow) {
-        _qmlWindow->setProperty(INTERACTIVE_WINDOW_VISIBLE_PROPERTY, visible);
-    }
-}
-
-bool QmlWindowProxy::isVisible() const {
-    if (!_qmlWindow) {
-        return false;
-    }
-
-    return _qmlWindow->property(INTERACTIVE_WINDOW_VISIBLE_PROPERTY).toBool();
-}
-
-void QmlWindowProxy::setPresentationMode(int presentationMode) {
-    if (_qmlWindow) {
-        _qmlWindow->setProperty(PRESENTATION_MODE_PROPERTY, presentationMode);
-    }
-}
-
-int QmlWindowProxy::getPresentationMode() const {
-    if (!_qmlWindow) {
-        return Virtual;
-    }
-
-    return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt();
-}
-
 void QmlWindowProxy::parentNativeWindowToMainWindow() {
 #ifdef Q_OS_WIN
     if (!_qmlWindow) {
@@ -395,7 +323,8 @@ void InteractiveWindow::qmlToScript(const QVariant& message) {
 
 void InteractiveWindow::setVisible(bool visible) {
     if (_qmlWindowProxy) {
-        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setVisible", Q_ARG(bool, visible));
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_VISIBLE_PROPERTY),
+                                  Q_ARG(QVariant, visible));
     }
 }
 
@@ -403,8 +332,10 @@ bool InteractiveWindow::isVisible() const {
     if (!_qmlWindowProxy) {
         return false;
     }
-
-    return _qmlWindowProxy->isVisible();
+    QVariant result;
+    BLOCKING_INVOKE_METHOD(_qmlWindowProxy.get(), "readProperty", Q_RETURN_ARG(QVariant, result),
+                           Q_ARG(QString, INTERACTIVE_WINDOW_VISIBLE_PROPERTY));
+    return result.toBool();
 }
 
 glm::vec2 InteractiveWindow::getPosition() const {
@@ -412,12 +343,18 @@ glm::vec2 InteractiveWindow::getPosition() const {
         return {};
     }
 
-    return _qmlWindowProxy->getPosition();
+    QVariant result;
+    BLOCKING_INVOKE_METHOD(_qmlWindowProxy.get(), "readProperty", Q_RETURN_ARG(QVariant, result),
+                           Q_ARG(QString, INTERACTIVE_WINDOW_POSITION_PROPERTY));
+
+    return toGlm(result.toPointF());
 }
 
 void InteractiveWindow::setPosition(const glm::vec2& position) {
     if (_qmlWindowProxy) {
-        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setPosition", Q_ARG(const glm::vec2&, position));
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_POSITION_PROPERTY),
+                                  Q_ARG(QVariant, QPointF(position.x, position.y)));
+        QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "updateInteractiveWindowPositionForMode");
     }
 }
 
@@ -425,12 +362,18 @@ glm::vec2 InteractiveWindow::getSize() const {
     if (!_qmlWindowProxy) {
         return {};
     }
-    return _qmlWindowProxy->getSize();
+
+    QVariant result;
+    BLOCKING_INVOKE_METHOD(_qmlWindowProxy.get(), "readProperty", Q_RETURN_ARG(QVariant, result),
+                           Q_ARG(QString, INTERACTIVE_WINDOW_SIZE_PROPERTY));
+    return toGlm(result.toSize());
 }
 
 void InteractiveWindow::setSize(const glm::vec2& size) {
     if (_qmlWindowProxy) {
-        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setSize", Q_ARG(const glm::vec2&, size));
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_SIZE_PROPERTY),
+                                  Q_ARG(QVariant, QSize(size.x, size.y)));
+        QMetaObject::invokeMethod(_qmlWindowProxy->getQmlWindow(), "updateInteractiveWindowSizeForMode");
     }
 }
 
@@ -438,12 +381,17 @@ QString InteractiveWindow::getTitle() const {
     if (!_qmlWindowProxy) {
         return QString();
     }
-    return _qmlWindowProxy->getTitle();
+
+    QVariant result;
+    BLOCKING_INVOKE_METHOD(_qmlWindowProxy.get(), "readProperty", Q_RETURN_ARG(QVariant, result),
+                           Q_ARG(QString, TITLE_PROPERTY));
+    return result.toString();
 }
 
 void InteractiveWindow::setTitle(const QString& title) {
     if (_qmlWindowProxy) {
-        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setTitle", Q_ARG(const QString&, title));
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, TITLE_PROPERTY),
+                                  Q_ARG(QVariant, title));
     }
 }
 
@@ -451,7 +399,10 @@ int InteractiveWindow::getPresentationMode() const {
     if (!_qmlWindowProxy) {
         return Virtual;
     }
-    return _qmlWindowProxy->getPresentationMode();
+    QVariant result;
+    BLOCKING_INVOKE_METHOD(_qmlWindowProxy.get(), "readProperty", Q_RETURN_ARG(QVariant, result),
+                           Q_ARG(QString, PRESENTATION_MODE_PROPERTY));
+    return result.toInt();
 }
 
 void InteractiveWindow::parentNativeWindowToMainWindow() {
@@ -462,6 +413,7 @@ void InteractiveWindow::parentNativeWindowToMainWindow() {
 
 void InteractiveWindow::setPresentationMode(int presentationMode) {
     if (_qmlWindowProxy) {
-        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "setPresentationMode", Q_ARG(int, presentationMode));
+        QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, PRESENTATION_MODE_PROPERTY),
+                                  Q_ARG(QVariant, presentationMode));
     }
 }
diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h
index 7abdc5210a..0098658c16 100644
--- a/interface/src/ui/InteractiveWindow.h
+++ b/interface/src/ui/InteractiveWindow.h
@@ -29,21 +29,6 @@ class QmlWindowProxy : public QmlWrapper {
 public:
     QmlWindowProxy(QObject* qmlObject, QObject* parent = nullptr);
 
-    Q_INVOKABLE void setPosition(const glm::vec2& position);
-    glm::vec2 getPosition() const;
-
-    Q_INVOKABLE void setSize(const glm::vec2& size);
-    glm::vec2 getSize() const;
-
-    Q_INVOKABLE void setTitle(const QString& title);
-    QString getTitle() const;
-
-    Q_INVOKABLE void setVisible(bool visible);
-    bool isVisible() const;
-
-    Q_INVOKABLE void setPresentationMode(int presentationMode);
-    int getPresentationMode() const;
-
     Q_INVOKABLE void parentNativeWindowToMainWindow();
 
     QObject* getQmlWindow() const { return _qmlWindow; }