From 6a5a443eff7dc2edf4c8a55e134f7afce331a199 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 24 Mar 2016 18:03:51 -0700 Subject: [PATCH 1/5] Avatar: Eye-tracking works again This replaces the calculation of the Head left and right eye positions used for eye tracking. Which was inadvertently removed in this commit 7483b8546b8e5003f87ea814a90fce144edafad9 --- interface/src/avatar/Head.cpp | 7 +++++++ interface/src/avatar/MyAvatar.cpp | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 620c35c832..5587096ce3 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -231,6 +231,13 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _leftEyePosition = _rightEyePosition = getPosition(); _eyePosition = calculateAverageEyePosition(); + + if (!billboard && _owningAvatar) { + auto skeletonModel = static_cast(_owningAvatar)->getSkeletonModel(); + if (skeletonModel) { + skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition); + } + } } void Head::calculateMouthShapes() { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8f11c635e9..210e6feb5b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -897,7 +897,9 @@ void MyAvatar::updateLookAtTargetAvatar() { // Scale by proportional differences between avatar and human. float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye) * ipdScale; float avatarEyeSeparation = glm::length(avatarLeftEye - avatarRightEye); - gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; + if (avatarEyeSeparation > 0.0f) { + gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; + } } // And now we can finally add that offset to the camera. From d3d724530a97018f16699da3d8854652390202eb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 24 Mar 2016 21:09:45 -0700 Subject: [PATCH 2/5] minor optimiztion --- libraries/entities/src/EntitySimulation.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 014ab33094..14bfc5ac7a 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -101,12 +101,15 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { prepareEntityForDelete(entity); } else { if (expiry < _nextExpiry) { - // remeber the smallest _nextExpiry so we know when to start the next search + // remember the smallest _nextExpiry so we know when to start the next search _nextExpiry = expiry; } ++itemItr; } } + if (_mortalEntities.size() < 1) { + _nextExpiry = -1; + } } } From ac5c055a1ea1fe07ed2aa3664a8ce1ce366335f5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 24 Mar 2016 21:11:05 -0700 Subject: [PATCH 3/5] don't verify simulated bit when adding to delete list --- .../physics/src/PhysicalEntitySimulation.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 497ed2031f..2d219915c8 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -57,16 +57,18 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { } void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { - EntitySimulation::removeEntityInternal(entity); - QMutexLocker lock(&_mutex); - _entitiesToAddToPhysics.remove(entity); + if (entity->isSimulated()) { + EntitySimulation::removeEntityInternal(entity); + QMutexLocker lock(&_mutex); + _entitiesToAddToPhysics.remove(entity); - EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); - if (motionState) { - _outgoingChanges.remove(motionState); - _entitiesToRemoveFromPhysics.insert(entity); - } else { - _entitiesToDelete.insert(entity); + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState) { + _outgoingChanges.remove(motionState); + _entitiesToRemoveFromPhysics.insert(entity); + } else { + _entitiesToDelete.insert(entity); + } } } @@ -175,7 +177,7 @@ void PhysicalEntitySimulation::getObjectsToRemoveFromPhysics(VectorOfMotionState _entitiesToRelease.insert(entity); } - if (entity->isSimulated() && entity->isDead()) { + if (entity->isDead()) { _entitiesToDelete.insert(entity); } } @@ -190,7 +192,7 @@ void PhysicalEntitySimulation::deleteObjectsRemovedFromPhysics() { entity->setPhysicsInfo(nullptr); delete motionState; - if (entity->isSimulated() && entity->isDead()) { + if (entity->isDead()) { _entitiesToDelete.insert(entity); } } From a47614c9b6970e32065b45f9f5961f28b6b3fd08 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 25 Mar 2016 09:48:25 -0700 Subject: [PATCH 4/5] Revert "Build a better event bridge" This reverts commit a43fde0803141657c45f82371136079455bed263. --- examples/html/eventBridgeLoader.js | 49 ++++++++++++-- examples/html/qmlWebTest.html | 10 ++- examples/tests/qmlWebTest.js | 28 +++++--- interface/resources/qml/QmlWebWindow.qml | 12 ---- interface/resources/qml/ToolWindow.qml | 61 ++++++----------- interface/resources/qml/controls/WebView.qml | 5 +- libraries/ui/src/QmlWebWindowClass.cpp | 23 ------- libraries/ui/src/QmlWebWindowClass.h | 12 ---- libraries/ui/src/QmlWindowClass.cpp | 69 +++++++++++++++++++- libraries/ui/src/QmlWindowClass.h | 31 ++++++++- 10 files changed, 192 insertions(+), 108 deletions(-) diff --git a/examples/html/eventBridgeLoader.js b/examples/html/eventBridgeLoader.js index de6553ee1c..ebfb6dc740 100644 --- a/examples/html/eventBridgeLoader.js +++ b/examples/html/eventBridgeLoader.js @@ -10,11 +10,50 @@ var EventBridge; -openEventBridge = function(callback) { - new QWebChannel(qt.webChannelTransport, function(channel) { - console.log("uid " + EventBridgeUid); - EventBridge = channel.objects[EventBridgeUid]; - callback(EventBridge); +EventBridgeConnectionProxy = function(parent) { + this.parent = parent; + this.realSignal = this.parent.realBridge.scriptEventReceived + this.webWindowId = this.parent.webWindow.windowId; +} + +EventBridgeConnectionProxy.prototype.connect = function(callback) { + var that = this; + this.realSignal.connect(function(id, message) { + if (id === that.webWindowId) { callback(message); } }); } +EventBridgeProxy = function(webWindow) { + this.webWindow = webWindow; + this.realBridge = this.webWindow.eventBridge; + this.scriptEventReceived = new EventBridgeConnectionProxy(this); +} + +EventBridgeProxy.prototype.emitWebEvent = function(data) { + this.realBridge.emitWebEvent(data); +} + +openEventBridge = function(callback) { + EVENT_BRIDGE_URI = "ws://localhost:51016"; + socket = new WebSocket(this.EVENT_BRIDGE_URI); + + socket.onclose = function() { + console.error("web channel closed"); + }; + + socket.onerror = function(error) { + console.error("web channel error: " + error); + }; + + socket.onopen = function() { + channel = new QWebChannel(socket, function(channel) { + console.log("Document url is " + document.URL); + var webWindow = channel.objects[document.URL.toLowerCase()]; + console.log("WebWindow is " + webWindow) + eventBridgeProxy = new EventBridgeProxy(webWindow); + EventBridge = eventBridgeProxy; + if (callback) { callback(eventBridgeProxy); } + }); + } +} + diff --git a/examples/html/qmlWebTest.html b/examples/html/qmlWebTest.html index 553ce83417..e59535701d 100644 --- a/examples/html/qmlWebTest.html +++ b/examples/html/qmlWebTest.html @@ -4,17 +4,21 @@ + diff --git a/examples/tests/qmlWebTest.js b/examples/tests/qmlWebTest.js index d29f2ba002..5faa68668d 100644 --- a/examples/tests/qmlWebTest.js +++ b/examples/tests/qmlWebTest.js @@ -8,14 +8,26 @@ webWindow.eventBridge.webEventReceived.connect(function(data) { print("JS Side event received: " + data); }); +var titles = ["A", "B", "C"]; +var titleIndex = 0; + Script.setInterval(function() { - var message = [ Math.random(), Math.random() ]; - print("JS Side sending: " + message); - webWindow.emitScriptEvent(message); -}, 5 * 1000); + webWindow.eventBridge.emitScriptEvent("JS Event sent"); + var size = webWindow.size; + var position = webWindow.position; + print("Window url: " + webWindow.url) + print("Window visible: " + webWindow.visible) + print("Window size: " + size.x + "x" + size.y) + print("Window pos: " + position.x + "x" + position.y) + webWindow.setVisible(!webWindow.visible); + webWindow.setTitle(titles[titleIndex]); + webWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100); + titleIndex += 1; + titleIndex %= titles.length; +}, 2 * 1000); -Script.scriptEnding.connect(function(){ +Script.setTimeout(function() { + print("Closing script"); webWindow.close(); - webWindow.deleteLater(); -}); - + Script.stop(); +}, 15 * 1000) diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 0058770462..fd4e629568 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -1,7 +1,6 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 import QtWebEngine 1.1 -import QtWebChannel 1.0 import "windows" as Windows import "controls" as Controls @@ -16,22 +15,11 @@ Windows.Window { // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false property alias source: webview.url - property alias webChannel: webview.webChannel - // A unique identifier to let the HTML JS find the event bridge - // object (our C++ wrapper) - property string uid; - - // This is for JS/QML communication, which is unused in a WebWindow, - // but not having this here results in spurious warnings about a - // missing signal - signal sendToScript(var message); Controls.WebView { id: webview url: "about:blank" anchors.fill: parent focus: true - onUrlChanged: webview.runJavaScript("EventBridgeUid = \"" + uid + "\";"); - Component.onCompleted: webview.runJavaScript("EventBridgeUid = \"" + uid + "\";"); } } // dialog diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml index 5313ca23e9..75aa50aa34 100644 --- a/interface/resources/qml/ToolWindow.qml +++ b/interface/resources/qml/ToolWindow.qml @@ -37,33 +37,14 @@ Windows.Window { Repeater { model: 4 Tab { - // Force loading of the content even if the tab is not visible - // (required for letting the C++ code access the webview) active: true - enabled: false + enabled: false; + // we need to store the original url here for future identification property string originalUrl: ""; - + onEnabledChanged: toolWindow.updateVisiblity(); Controls.WebView { id: webView; - // we need to store the original url here for future identification - // A unique identifier to let the HTML JS find the event bridge - // object (our C++ wrapper) - property string uid; anchors.fill: parent - enabled: false - - // This is for JS/QML communication, which is unused in a WebWindow, - // but not having this here results in spurious warnings about a - // missing signal - signal sendToScript(var message); - - onUrlChanged: webView.runJavaScript("EventBridgeUid = \"" + uid + "\";"); - onEnabledChanged: toolWindow.updateVisiblity(); - onLoadingChanged: { - if (loadRequest.status == WebEngineView.LoadSucceededStatus) { - webView.runJavaScript("EventBridgeUid = \"" + uid + "\";"); - } - } } } } @@ -132,23 +113,20 @@ Windows.Window { var tab = tabView.getTab(index); tab.title = ""; - tab.enabled = false; tab.originalUrl = ""; - tab.item.url = "about:blank"; - tab.item.enabled = false; + tab.enabled = false; } function addWebTab(properties) { if (!properties.source) { - console.warn("Attempted to open Web Tool Pane without URL"); + console.warn("Attempted to open Web Tool Pane without URL") return; } var existingTabIndex = findIndexForUrl(properties.source); if (existingTabIndex >= 0) { - console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source); - var tab = tabView.getTab(existingTabIndex); - return tab.item; + console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source) + return tabView.getTab(existingTabIndex); } var freeTabIndex = findFreeTab(); @@ -157,22 +135,25 @@ Windows.Window { return; } + var newTab = tabView.getTab(freeTabIndex); + newTab.title = properties.title || "Unknown"; + newTab.originalUrl = properties.source; + newTab.item.url = properties.source; + newTab.active = true; + if (properties.width) { - tabView.width = Math.min(Math.max(tabView.width, properties.width), toolWindow.maxSize.x); + tabView.width = Math.min(Math.max(tabView.width, properties.width), + toolWindow.maxSize.x); } if (properties.height) { - tabView.height = Math.min(Math.max(tabView.height, properties.height), toolWindow.maxSize.y); + tabView.height = Math.min(Math.max(tabView.height, properties.height), + toolWindow.maxSize.y); } - var tab = tabView.getTab(freeTabIndex); - tab.title = properties.title || "Unknown"; - tab.enabled = true; - tab.originalUrl = properties.source; - - var result = tab.item; - result.enabled = true; - result.url = properties.source; - return result; + console.log("Updating visibility based on child tab added"); + newTab.enabledChanged.connect(updateVisiblity) + updateVisiblity(); + return newTab } } diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 1361e6e322..18080cd448 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -59,7 +59,6 @@ WebEngineView { request.openIn(newWindow.webView) } - // This breaks the webchannel used for passing messages. Fixed in Qt 5.6 - // See https://bugreports.qt.io/browse/QTBUG-49521 - //profile: desktop.browserProfile + + profile: desktop.browserProfile } diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 43fd5a64df..0228f77f4f 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -14,8 +14,6 @@ #include -#include - #include #include @@ -37,29 +35,8 @@ QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngi } QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) : QmlWindowClass(qmlWindow) { - _uid = QUuid::createUuid().toString(); - asQuickItem()->setProperty("uid", _uid); - auto webchannelVar = qmlWindow->property("webChannel"); - _webchannel = qvariant_cast(webchannelVar); - Q_ASSERT(_webchannel); - _webchannel->registerObject(_uid, this); } -void QmlWebWindowClass::emitScriptEvent(const QVariant& scriptMessage) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, scriptMessage)); - } else { - emit scriptEventReceived(scriptMessage); - } -} - -void QmlWebWindowClass::emitWebEvent(const QVariant& webMessage) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, webMessage)); - } else { - emit webEventReceived(webMessage); - } -} QString QmlWebWindowClass::getURL() const { QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index 35322ef0ea..27c0e6996d 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -11,13 +11,10 @@ #include "QmlWindowClass.h" -class QWebChannel; - // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping class QmlWebWindowClass : public QmlWindowClass { Q_OBJECT Q_PROPERTY(QString url READ getURL CONSTANT) - Q_PROPERTY(QString uid READ getUid CONSTANT) public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); @@ -26,18 +23,9 @@ public: public slots: QString getURL() const; void setURL(const QString& url); - const QString& getUid() const { return _uid; } - void emitScriptEvent(const QVariant& scriptMessage); - void emitWebEvent(const QVariant& webMessage); signals: void urlChanged(); - void scriptEventReceived(const QVariant& message); - void webEventReceived(const QVariant& message); - -private: - QString _uid; - QWebChannel* _webchannel { nullptr }; }; #endif diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 37d461acd0..b7fe330a4e 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -26,6 +26,10 @@ #include "OffscreenUi.h" +QWebSocketServer* QmlWindowClass::_webChannelServer { nullptr }; +static QWebChannel webChannel; +static const uint16_t WEB_CHANNEL_PORT = 51016; +static std::atomic nextWindowId; static const char* const SOURCE_PROPERTY = "source"; static const char* const TITLE_PROPERTY = "title"; static const char* const WIDTH_PROPERTY = "width"; @@ -33,6 +37,54 @@ static const char* const HEIGHT_PROPERTY = "height"; static const char* const VISIBILE_PROPERTY = "visible"; static const char* const TOOLWINDOW_PROPERTY = "toolWindow"; +void QmlScriptEventBridge::emitWebEvent(const QString& data) { + QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); +} + +void QmlScriptEventBridge::emitScriptEvent(const QString& data) { + QMetaObject::invokeMethod(this, "scriptEventReceived", Qt::QueuedConnection, + Q_ARG(int, _webWindow->getWindowId()), Q_ARG(QString, data)); +} + +class QmlWebTransport : public QWebChannelAbstractTransport { + Q_OBJECT +public: + QmlWebTransport(QWebSocket* webSocket) : _webSocket(webSocket) { + // Translate from the websocket layer to the webchannel layer + connect(webSocket, &QWebSocket::textMessageReceived, [this](const QString& message) { + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(message.toUtf8(), &error); + if (error.error || !document.isObject()) { + qWarning() << "Unable to parse incoming JSON message" << message; + return; + } + emit messageReceived(document.object(), this); + }); + } + + virtual void sendMessage(const QJsonObject &message) override { + // Translate from the webchannel layer to the websocket layer + _webSocket->sendTextMessage(QJsonDocument(message).toJson(QJsonDocument::Compact)); + } + +private: + QWebSocket* const _webSocket; +}; + + +void QmlWindowClass::setupServer() { + if (!_webChannelServer) { + _webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); + if (!_webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { + qFatal("Failed to open web socket server."); + } + + QObject::connect(_webChannelServer, &QWebSocketServer::newConnection, [] { + webChannel.connectTo(new QmlWebTransport(_webChannelServer->nextPendingConnection())); + }); + } +} + QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, QScriptContext* context, QScriptEngine* engine, std::function builder) @@ -116,8 +168,10 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, } offscreenUi->returnFromUiThread([&] { + setupServer(); retVal = builder(newTab); retVal->_toolWindow = true; + registerObject(url.toLower(), retVal); return QVariant(); }); } else { @@ -125,8 +179,10 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, QMetaObject::invokeMethod(offscreenUi.data(), "load", Qt::BlockingQueuedConnection, Q_ARG(const QString&, qmlSource), Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { + setupServer(); retVal = builder(object); context->engine()->setObjectOwnership(retVal->_qmlWindow, QQmlEngine::CppOwnership); + registerObject(url.toLower(), retVal); if (!title.isEmpty()) { retVal->setTitle(title); } @@ -153,7 +209,10 @@ QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* }); } -QmlWindowClass::QmlWindowClass(QObject* qmlWindow) : _qmlWindow(qmlWindow) { +QmlWindowClass::QmlWindowClass(QObject* qmlWindow) + : _windowId(++nextWindowId), _qmlWindow(qmlWindow) +{ + qDebug() << "Created window with ID " << _windowId; Q_ASSERT(_qmlWindow); Q_ASSERT(dynamic_cast(_qmlWindow.data())); // Forward messages received from QML on to the script @@ -169,6 +228,14 @@ QmlWindowClass::~QmlWindowClass() { close(); } +void QmlWindowClass::registerObject(const QString& name, QObject* object) { + webChannel.registerObject(name, object); +} + +void QmlWindowClass::deregisterObject(QObject* object) { + webChannel.deregisterObject(object); +} + QQuickItem* QmlWindowClass::asQuickItem() const { if (_toolWindow) { return DependencyManager::get()->getToolWindow(); diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index eda6ce674c..fb7dbf1253 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -13,16 +13,38 @@ #include #include #include +#include #include class QScriptEngine; class QScriptContext; +class QmlWindowClass; +class QWebSocketServer; +class QWebSocket; +class QmlScriptEventBridge : public QObject { + Q_OBJECT +public: + QmlScriptEventBridge(const QmlWindowClass* webWindow) : _webWindow(webWindow) {} + +public slots : + void emitWebEvent(const QString& data); + void emitScriptEvent(const QString& data); + +signals: + void webEventReceived(const QString& data); + void scriptEventReceived(int windowId, const QString& data); + +private: + const QmlWindowClass* _webWindow { nullptr }; + QWebSocket *_socket { nullptr }; +}; // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping class QmlWindowClass : public QObject { Q_OBJECT Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) + Q_PROPERTY(int windowId READ getWindowId CONSTANT) Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) @@ -47,7 +69,8 @@ public slots: Q_INVOKABLE void raise(); Q_INVOKABLE void close(); - Q_INVOKABLE QObject* getEventBridge() { return this; }; + Q_INVOKABLE int getWindowId() const { return _windowId; }; + Q_INVOKABLE QmlScriptEventBridge* getEventBridge() const { return _eventBridge; }; // Scripts can use this to send a message to the QML object void sendToQml(const QVariant& message); @@ -69,12 +92,18 @@ protected: static QScriptValue internalConstructor(const QString& qmlSource, QScriptContext* context, QScriptEngine* engine, std::function function); + static void setupServer(); + static void registerObject(const QString& name, QObject* object); + static void deregisterObject(QObject* object); + static QWebSocketServer* _webChannelServer; QQuickItem* asQuickItem() const; + QmlScriptEventBridge* const _eventBridge { new QmlScriptEventBridge(this) }; // FIXME needs to be initialized in the ctor once we have support // for tool window panes in QML bool _toolWindow { false }; + const int _windowId; QPointer _qmlWindow; QString _source; }; From aad40f5de0d1e152c20ba060f242610e0713cf33 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 09:58:34 -0700 Subject: [PATCH 5/5] Drop network data after processing --- libraries/animation/src/AnimNodeLoader.cpp | 2 +- libraries/animation/src/AnimNodeLoader.h | 2 +- .../model-networking/src/model-networking/ModelCache.cpp | 4 ++-- .../model-networking/src/model-networking/ModelCache.h | 4 ++-- libraries/networking/src/ResourceCache.cpp | 6 +++--- libraries/networking/src/ResourceCache.h | 4 +--- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index e222de54f9..70cf7e248f 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -611,7 +611,7 @@ AnimNode::Pointer AnimNodeLoader::load(const QByteArray& contents, const QUrl& j return loadNode(rootVal.toObject(), jsonUrl); } -void AnimNodeLoader::onRequestDone(const QByteArray& data) { +void AnimNodeLoader::onRequestDone(const QByteArray data) { auto node = load(data, _url); if (node) { emit success(node); diff --git a/libraries/animation/src/AnimNodeLoader.h b/libraries/animation/src/AnimNodeLoader.h index 27b94f81bb..d6fdfa7e2c 100644 --- a/libraries/animation/src/AnimNodeLoader.h +++ b/libraries/animation/src/AnimNodeLoader.h @@ -36,7 +36,7 @@ protected: static AnimNode::Pointer load(const QByteArray& contents, const QUrl& jsonUrl); protected slots: - void onRequestDone(const QByteArray& data); + void onRequestDone(const QByteArray data); void onRequestError(QNetworkReply::NetworkError error); protected: diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index b0b769d5e9..e5094a5224 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -293,7 +293,7 @@ void NetworkGeometry::requestModel(const QUrl& url) { connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError); } -void NetworkGeometry::mappingRequestDone(const QByteArray& data) { +void NetworkGeometry::mappingRequestDone(const QByteArray data) { assert(_state == RequestMappingState); // parse the mapping file @@ -325,7 +325,7 @@ void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) { emit onFailure(*this, MappingRequestError); } -void NetworkGeometry::modelRequestDone(const QByteArray& data) { +void NetworkGeometry::modelRequestDone(const QByteArray data) { assert(_state == RequestModelState); _state = ParsingModelState; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 1c76a0b878..550b16d2ba 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -113,10 +113,10 @@ public slots: void textureLoaded(const QWeakPointer& networkTexture); protected slots: - void mappingRequestDone(const QByteArray& data); + void mappingRequestDone(const QByteArray data); void mappingRequestError(QNetworkReply::NetworkError error); - void modelRequestDone(const QByteArray& data); + void modelRequestDone(const QByteArray data); void modelRequestError(QNetworkReply::NetworkError error); void modelParseSuccess(FBXGeometry* geometry); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 3de94ed839..9738233c85 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -423,12 +423,12 @@ void Resource::handleReplyFinished() { auto result = _request->getResult(); if (result == ResourceRequest::Success) { - _data = _request->getData(); auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); - emit loaded(_data); - downloadFinished(_data); + auto data = _request->getData(); + emit loaded(data); + downloadFinished(data); } else { switch (result) { case ResourceRequest::Result::Timeout: { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 77878794b5..7f4d86393b 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -194,12 +194,11 @@ public: Q_INVOKABLE void allReferencesCleared(); const QUrl& getURL() const { return _url; } - const QByteArray& getData() const { return _data; } signals: /// Fired when the resource has been downloaded. /// This can be used instead of downloadFinished to access data before it is processed. - void loaded(const QByteArray& request); + void loaded(const QByteArray request); /// Fired when the resource has finished loading. void finished(bool success); @@ -235,7 +234,6 @@ protected: QHash, float> _loadPriorities; QWeakPointer _self; QPointer _cache; - QByteArray _data; private slots: void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal);