diff --git a/gvr-interface/src/RenderingClient.cpp b/gvr-interface/src/RenderingClient.cpp index b7c6f30a73..f04be5cb7f 100644 --- a/gvr-interface/src/RenderingClient.cpp +++ b/gvr-interface/src/RenderingClient.cpp @@ -63,10 +63,7 @@ void RenderingClient::sendAvatarPacket() { } void RenderingClient::cleanupBeforeQuit() { - - QMetaObject::invokeMethod(DependencyManager::get().data(), - "stop", Qt::BlockingQueuedConnection); - + DependencyManager::get()->cleanupBeforeQuit(); // destroy the AudioClient so it and its thread will safely go down DependencyManager::destroy(); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a31877c1b..2b6c6033a2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1844,7 +1844,7 @@ void Application::cleanupBeforeQuit() { // FIXME: something else is holding a reference to AudioClient, // so it must be explicitly synchronously stopped here - QMetaObject::invokeMethod(DependencyManager::get().data(), "cleanupBeforeQuit", Qt::BlockingQueuedConnection); + DependencyManager::get()->cleanupBeforeQuit(); // destroy Audio so it and its threads have a chance to go down safely // this must happen after QML, as there are unexplained audio crashes originating in qtwebengine diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 883a6e758e..81a806b8ab 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -152,22 +153,31 @@ QString HMDScriptingInterface::preferredAudioOutput() const { return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); } -bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const { +bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) { + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "setHandLasers", Q_RETURN_ARG(bool, result), + Q_ARG(int, hands), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction)); + return result; + } + auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([offscreenUi, enabled] { - offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); - }); + offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); return qApp->getActiveDisplayPlugin()->setHandLaser(hands, enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None, color, direction); } -bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) const { - auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([offscreenUi, enabled] { - offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); - }); +bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) { + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "setExtraLaser", Q_RETURN_ARG(bool, result), + Q_ARG(glm::vec3, worldStart), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction)); + return result; + } + auto offscreenUi = DependencyManager::get(); + offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled); auto myAvatar = DependencyManager::get()->getMyAvatar(); auto sensorToWorld = myAvatar->getSensorToWorldMatrix(); @@ -179,11 +189,11 @@ bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enab color, sensorStart, sensorDirection); } -void HMDScriptingInterface::disableExtraLaser() const { +void HMDScriptingInterface::disableExtraLaser() { setExtraLaser(vec3(0), false, vec4(0), vec3(0)); } -void HMDScriptingInterface::disableHandLasers(int hands) const { +void HMDScriptingInterface::disableHandLasers(int hands) { setHandLasers(hands, false, vec4(0), vec3(0)); } diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 4657e61d05..3ed7db0232 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -51,11 +51,11 @@ public: Q_INVOKABLE void requestHideHandControllers(); Q_INVOKABLE bool shouldShowHandControllers() const; - Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const; - Q_INVOKABLE void disableHandLasers(int hands) const; + Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction); + Q_INVOKABLE void disableHandLasers(int hands); - Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) const; - Q_INVOKABLE void disableExtraLaser() const; + Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction); + Q_INVOKABLE void disableExtraLaser(); /// Suppress the activation of any on-screen keyboard so that a script operation will diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 84c742d0ab..4d3e3b94a1 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -57,20 +58,25 @@ void TestScriptingInterface::waitIdle() { } bool TestScriptingInterface::loadTestScene(QString scene) { + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "loadTestScene", Q_RETURN_ARG(bool, result), Q_ARG(QString, scene)); + return result; + } + static const QString TEST_ROOT = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/"; static const QString TEST_BINARY_ROOT = "https://hifi-public.s3.amazonaws.com/test_scene_data/"; static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/"; static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/"; - return DependencyManager::get()->returnFromUiThread([scene]()->QVariant { - DependencyManager::get()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/"); - auto tree = qApp->getEntities()->getTree(); - auto treeIsClient = tree->getIsClient(); - // Force the tree to accept the load regardless of permissions - tree->setIsClient(false); - auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json"); - tree->setIsClient(treeIsClient); - return result; - }).toBool(); + + DependencyManager::get()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/"); + auto tree = qApp->getEntities()->getTree(); + auto treeIsClient = tree->getIsClient(); + // Force the tree to accept the load regardless of permissions + tree->setIsClient(false); + auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json"); + tree->setIsClient(treeIsClient); + return result; } bool TestScriptingInterface::startTracing(QString logrules) { diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 3e0bb74bc4..c8c9c36a1d 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -45,11 +45,13 @@ Image3DOverlay::~Image3DOverlay() { } void Image3DOverlay::update(float deltatime) { +#if OVERLAY_PANELS if (usecTimestampNow() > _transformExpiry) { Transform transform = getTransform(); applyTransformTo(transform); setTransform(transform); } +#endif } void Image3DOverlay::render(RenderArgs* args) { diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 4ad1b070b1..494c287676 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -84,9 +84,9 @@ public: void setColorPulse(float value) { _colorPulse = value; } void setAlphaPulse(float value) { _alphaPulse = value; } - virtual void setProperties(const QVariantMap& properties); - virtual Overlay* createClone() const = 0; - virtual QVariant getProperty(const QString& property); + Q_INVOKABLE virtual void setProperties(const QVariantMap& properties); + Q_INVOKABLE virtual Overlay* createClone() const = 0; + Q_INVOKABLE virtual QVariant getProperty(const QString& property); render::ItemID getRenderItemID() const { return _renderItemID; } void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; } diff --git a/interface/src/ui/overlays/OverlayPanel.cpp b/interface/src/ui/overlays/OverlayPanel.cpp index df2b91c4ef..06480109ce 100644 --- a/interface/src/ui/overlays/OverlayPanel.cpp +++ b/interface/src/ui/overlays/OverlayPanel.cpp @@ -11,6 +11,8 @@ #include "OverlayPanel.h" +#if OVERLAY_PANELS + #include #include #include @@ -185,3 +187,4 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { pointTransformAtCamera(transform, getOffsetRotation()); } } +#endif \ No newline at end of file diff --git a/interface/src/ui/overlays/OverlayPanel.h b/interface/src/ui/overlays/OverlayPanel.h index 5bffe3851e..cff2bc224d 100644 --- a/interface/src/ui/overlays/OverlayPanel.h +++ b/interface/src/ui/overlays/OverlayPanel.h @@ -22,6 +22,7 @@ #include "Billboardable.h" #include "Overlay.h" +#if OVERLAY_PANELS class PropertyBinding { public: PropertyBinding() {} @@ -80,4 +81,6 @@ private: QScriptEngine* _scriptEngine; }; +#endif + #endif // hifi_OverlayPanel_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index a9efd51a3e..c27800a5bb 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -40,8 +41,6 @@ Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") void Overlays::cleanupAllOverlays() { { - QWriteLocker lock(&_lock); - QWriteLocker deleteLock(&_deleteLock); foreach(Overlay::Pointer overlay, _overlaysHUD) { _overlaysToDelete.push_back(overlay); } @@ -50,19 +49,22 @@ void Overlays::cleanupAllOverlays() { } _overlaysHUD.clear(); _overlaysWorld.clear(); +#if OVERLAY_PANELS _panels.clear(); +#endif } cleanupOverlaysToDelete(); } void Overlays::init() { +#if OVERLAY_PANELS _scriptEngine = new QScriptEngine(); +#endif } void Overlays::update(float deltatime) { { - QWriteLocker lock(&_lock); foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { thisOverlay->update(deltatime); } @@ -80,8 +82,6 @@ void Overlays::cleanupOverlaysToDelete() { render::Transaction transaction; { - QWriteLocker lock(&_deleteLock); - do { Overlay::Pointer overlay = _overlaysToDelete.takeLast(); @@ -100,7 +100,6 @@ void Overlays::cleanupOverlaysToDelete() { void Overlays::renderHUD(RenderArgs* renderArgs) { PROFILE_RANGE(render_overlays, __FUNCTION__); - QReadLocker lock(&_lock); gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); @@ -126,12 +125,10 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { } void Overlays::disable() { - QWriteLocker lock(&_lock); _enabled = false; } void Overlays::enable() { - QWriteLocker lock(&_lock); _enabled = true; } @@ -146,6 +143,12 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const { } OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) { + if (QThread::currentThread() != thread()) { + OverlayID result; + hifi::qt::blockingInvokeMethod(this, "addOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(QString, type), Q_ARG(QVariant, properties)); + return result; + } + Overlay::Pointer thisOverlay = nullptr; if (type == ImageOverlay::TYPE) { @@ -185,8 +188,7 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) return UNKNOWN_OVERLAY_ID; } -OverlayID Overlays::addOverlay(Overlay::Pointer overlay) { - QWriteLocker lock(&_lock); +OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { OverlayID thisID = OverlayID(QUuid::createUuid()); overlay->setOverlayID(thisID); overlay->setStackOrder(_stackOrder++); @@ -205,14 +207,22 @@ OverlayID Overlays::addOverlay(Overlay::Pointer overlay) { } OverlayID Overlays::cloneOverlay(OverlayID id) { + if (QThread::currentThread() != thread()) { + OverlayID result; + hifi::qt::blockingInvokeMethod(this, "cloneOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(OverlayID, id)); + return result; + } + Overlay::Pointer thisOverlay = getOverlay(id); if (thisOverlay) { OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone())); +#if OVERLAY_PANELS auto attachable = std::dynamic_pointer_cast(thisOverlay); if (attachable && attachable->getParentPanel()) { attachable->getParentPanel()->addChild(cloneId); } +#endif return cloneId; } @@ -220,21 +230,29 @@ OverlayID Overlays::cloneOverlay(OverlayID id) { } bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { - QWriteLocker lock(&_lock); + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "editOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id), Q_ARG(QVariant, properties)); + return result; + } Overlay::Pointer thisOverlay = getOverlay(id); if (thisOverlay) { thisOverlay->setProperties(properties.toMap()); - return true; } return false; } bool Overlays::editOverlays(const QVariant& propertiesById) { + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "editOverlays", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, propertiesById)); + return result; + } + QVariantMap map = propertiesById.toMap(); bool success = true; - QWriteLocker lock(&_lock); for (const auto& key : map.keys()) { OverlayID id = OverlayID(key); Overlay::Pointer thisOverlay = getOverlay(id); @@ -249,10 +267,14 @@ bool Overlays::editOverlays(const QVariant& propertiesById) { } void Overlays::deleteOverlay(OverlayID id) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "deleteOverlay", Q_ARG(OverlayID, id)); + return; + } + Overlay::Pointer overlayToDelete; { - QWriteLocker lock(&_lock); if (_overlaysHUD.contains(id)) { overlayToDelete = _overlaysHUD.take(id); } else if (_overlaysWorld.contains(id)) { @@ -262,19 +284,25 @@ void Overlays::deleteOverlay(OverlayID id) { } } +#if OVERLAY_PANELS auto attachable = std::dynamic_pointer_cast(overlayToDelete); if (attachable && attachable->getParentPanel()) { attachable->getParentPanel()->removeChild(id); attachable->setParentPanel(nullptr); } +#endif - QWriteLocker lock(&_deleteLock); _overlaysToDelete.push_back(overlayToDelete); - emit overlayDeleted(id); } -QString Overlays::getOverlayType(OverlayID overlayId) const { +QString Overlays::getOverlayType(OverlayID overlayId) { + if (QThread::currentThread() != thread()) { + QString result; + hifi::qt::blockingInvokeMethod(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(OverlayID, overlayId)); + return result; + } + Overlay::Pointer overlay = getOverlay(overlayId); if (overlay) { return overlay->getType(); @@ -283,6 +311,12 @@ QString Overlays::getOverlayType(OverlayID overlayId) const { } QObject* Overlays::getOverlayObject(OverlayID id) { + if (QThread::currentThread() != thread()) { + QObject* result; + hifi::qt::blockingInvokeMethod(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id)); + return result; + } + Overlay::Pointer thisOverlay = getOverlay(id); if (thisOverlay) { return qobject_cast(&(*thisOverlay)); @@ -290,6 +324,7 @@ QObject* Overlays::getOverlayObject(OverlayID id) { return nullptr; } +#if OVERLAY_PANELS OverlayID Overlays::getParentPanel(OverlayID childId) const { Overlay::Pointer overlay = getOverlay(childId); auto attachable = std::dynamic_pointer_cast(overlay); @@ -330,10 +365,16 @@ void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) { } } } +#endif OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { + if (QThread::currentThread() != thread()) { + OverlayID result; + hifi::qt::blockingInvokeMethod(this, "getOverlayAtPoint", Q_RETURN_ARG(OverlayID, result), Q_ARG(glm::vec2, point)); + return result; + } + glm::vec2 pointCopy = point; - QReadLocker lock(&_lock); if (!_enabled) { return UNKNOWN_OVERLAY_ID; } @@ -365,9 +406,14 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { } OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) { + if (QThread::currentThread() != thread()) { + OverlayPropertyResult result; + hifi::qt::blockingInvokeMethod(this, "getProperty", Q_RETURN_ARG(OverlayPropertyResult, result), Q_ARG(OverlayID, id), Q_ARG(QString, property)); + return result; + } + OverlayPropertyResult result; Overlay::Pointer thisOverlay = getOverlay(id); - QReadLocker lock(&_lock); if (thisOverlay && thisOverlay->supportsGetProperty()) { result.value = thisOverlay->getProperty(property); } @@ -405,7 +451,18 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR const QVector& overlaysToInclude, const QVector& overlaysToDiscard, bool visibleOnly, bool collidableOnly) { - QReadLocker lock(&_lock); + if (QThread::currentThread() != thread()) { + RayToOverlayIntersectionResult result; + hifi::qt::blockingInvokeMethod(this, "findRayIntersectionInternal", Q_RETURN_ARG(RayToOverlayIntersectionResult, result), + Q_ARG(PickRay, ray), + Q_ARG(bool, precisionPicking), + Q_ARG(QVector, overlaysToInclude), + Q_ARG(QVector, overlaysToDiscard), + Q_ARG(bool, visibleOnly), + Q_ARG(bool, collidableOnly)); + return result; + } + float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; @@ -448,16 +505,6 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR return result; } -RayToOverlayIntersectionResult::RayToOverlayIntersectionResult() : - intersects(false), - overlayID(UNKNOWN_OVERLAY_ID), - distance(0), - face(), - intersection(), - extraInfo() -{ -} - QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) { auto obj = engine->newObject(); obj.setProperty("intersects", value.intersects); @@ -531,7 +578,12 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar } bool Overlays::isLoaded(OverlayID id) { - QReadLocker lock(&_lock); + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id)); + return result; + } + Overlay::Pointer thisOverlay = getOverlay(id); if (!thisOverlay) { return false; // not found @@ -539,7 +591,13 @@ bool Overlays::isLoaded(OverlayID id) { return thisOverlay->isLoaded(); } -QSizeF Overlays::textSize(OverlayID id, const QString& text) const { +QSizeF Overlays::textSize(OverlayID id, const QString& text) { + if (QThread::currentThread() != thread()) { + QSizeF result; + hifi::qt::blockingInvokeMethod(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(OverlayID, id), Q_ARG(QString, text)); + return result; + } + Overlay::Pointer thisOverlay = _overlaysHUD[id]; if (thisOverlay) { if (auto textOverlay = std::dynamic_pointer_cast(thisOverlay)) { @@ -554,6 +612,7 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) const { return QSizeF(0.0f, 0.0f); } +#if OVERLAY_PANELS OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) { QWriteLocker lock(&_lock); @@ -607,8 +666,15 @@ void Overlays::deletePanel(OverlayID panelId) { emit panelDeleted(panelId); } +#endif bool Overlays::isAddedOverlay(OverlayID id) { + if (QThread::currentThread() != thread()) { + bool result; + hifi::qt::blockingInvokeMethod(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id)); + return result; + } + return _overlaysHUD.contains(id) || _overlaysWorld.contains(id); } @@ -636,20 +702,43 @@ void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) { emit hoverLeaveOverlay(id, event); } -OverlayID Overlays::getKeyboardFocusOverlay() const { +OverlayID Overlays::getKeyboardFocusOverlay() { + if (QThread::currentThread() != thread()) { + OverlayID result; + hifi::qt::blockingInvokeMethod(this, "getKeyboardFocusOverlay", Q_RETURN_ARG(OverlayID, result)); + return result; + } + return qApp->getKeyboardFocusOverlay(); } void Overlays::setKeyboardFocusOverlay(OverlayID id) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setKeyboardFocusOverlay", Q_ARG(OverlayID, id)); + return; + } + qApp->setKeyboardFocusOverlay(id); } -float Overlays::width() const { +float Overlays::width() { + if (QThread::currentThread() != thread()) { + float result; + hifi::qt::blockingInvokeMethod(this, "width", Q_RETURN_ARG(float, result)); + return result; + } + auto offscreenUi = DependencyManager::get(); return offscreenUi->getWindow()->size().width(); } -float Overlays::height() const { +float Overlays::height() { + if (QThread::currentThread() != thread()) { + float result; + hifi::qt::blockingInvokeMethod(this, "height", Q_RETURN_ARG(float, result)); + return result; + } + auto offscreenUi = DependencyManager::get(); return offscreenUi->getWindow()->size().height(); } @@ -705,7 +794,6 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r auto thisOverlay = std::dynamic_pointer_cast(overlay); - QReadLocker lock(&_lock); auto position = thisOverlay->getPosition(); auto rotation = thisOverlay->getRotation(); auto dimensions = thisOverlay->getSize(); @@ -854,8 +942,13 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { return false; } -QVector Overlays::findOverlays(const glm::vec3& center, float radius) const { +QVector Overlays::findOverlays(const glm::vec3& center, float radius) { QVector result; + if (QThread::currentThread() != thread()) { + hifi::qt::blockingInvokeMethod(this, "findOverlays", Q_RETURN_ARG(QVector, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius)); + return result; + } + QMapIterator i(_overlaysWorld); int checked = 0; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index a1d4be8376..d3fa70225e 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -25,8 +25,9 @@ #include #include "Overlay.h" -#include "OverlayPanel.h" + #include "PanelAttachable.h" +#include "OverlayPanel.h" class PickRay; @@ -41,6 +42,8 @@ Q_DECLARE_METATYPE(OverlayPropertyResult); QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value); void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value); +const OverlayID UNKNOWN_OVERLAY_ID = OverlayID(); + /**jsdoc * @typedef Overlays.RayToOverlayIntersectionResult * @property {bool} intersects True if the PickRay intersected with a 3D overlay. @@ -51,10 +54,9 @@ void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPro */ class RayToOverlayIntersectionResult { public: - RayToOverlayIntersectionResult(); - bool intersects; - OverlayID overlayID; - float distance; + bool intersects { false }; + OverlayID overlayID { UNKNOWN_OVERLAY_ID }; + float distance { 0 }; BoxFace face; glm::vec3 surfaceNormal; glm::vec3 intersection; @@ -77,8 +79,6 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R * @namespace Overlays */ -const OverlayID UNKNOWN_OVERLAY_ID = OverlayID(); - class Overlays : public QObject { Q_OBJECT @@ -94,11 +94,13 @@ public: void enable(); Overlay::Pointer getOverlay(OverlayID id) const; +#if OVERLAY_PANELS OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; } +#endif /// adds an overlay that's already been created OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } - OverlayID addOverlay(Overlay::Pointer overlay); + OverlayID addOverlay(const Overlay::Pointer& overlay); bool mousePressEvent(QMouseEvent* event); bool mouseDoublePressEvent(QMouseEvent* event); @@ -156,7 +158,7 @@ public slots: * @param {Overlays.OverlayID} overlayID The ID of the overlay to get the type of. * @return {string} The type of the overlay if found, otherwise the empty string. */ - QString getOverlayType(OverlayID overlayId) const; + QString getOverlayType(OverlayID overlayId); /**jsdoc * Get the overlay Script object. @@ -215,7 +217,7 @@ public slots: * @param {float} radius search radius * @return {Overlays.OverlayID[]} list of overlays withing the radius */ - QVector findOverlays(const glm::vec3& center, float radius) const; + QVector findOverlays(const glm::vec3& center, float radius); /**jsdoc * Check whether an overlay's assets have been loaded. For example, if the @@ -237,7 +239,7 @@ public slots: * @param {string} The string to measure. * @return {Vec2} The size of the text. */ - QSizeF textSize(OverlayID id, const QString& text) const; + QSizeF textSize(OverlayID id, const QString& text); /**jsdoc * Get the width of the virtual 2D HUD. @@ -245,7 +247,7 @@ public slots: * @function Overlays.width * @return {float} The width of the 2D HUD. */ - float width() const; + float width(); /**jsdoc * Get the height of the virtual 2D HUD. @@ -253,11 +255,12 @@ public slots: * @function Overlays.height * @return {float} The height of the 2D HUD. */ - float height() const; + float height(); /// return true if there is an overlay with that id else false bool isAddedOverlay(OverlayID id); +#if OVERLAY_PANELS OverlayID getParentPanel(OverlayID childId) const; void setParentPanel(OverlayID childId, OverlayID panelId); @@ -279,6 +282,8 @@ public slots: /// return true if there is a panel with that id else false bool isAddedPanel(OverlayID id) { return _panels.contains(id); } +#endif + void sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event); void sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event); void sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event); @@ -287,7 +292,7 @@ public slots: void sendHoverOverOverlay(OverlayID id, PointerEvent event); void sendHoverLeaveOverlay(OverlayID id, PointerEvent event); - OverlayID getKeyboardFocusOverlay() const; + OverlayID getKeyboardFocusOverlay(); void setKeyboardFocusOverlay(OverlayID id); signals: @@ -316,13 +321,15 @@ private: QMap _overlaysHUD; QMap _overlaysWorld; +#if OVERLAY_PANELS QMap _panels; +#endif QList _overlaysToDelete; unsigned int _stackOrder { 1 }; - QReadWriteLock _lock; - QReadWriteLock _deleteLock; +#if OVERLAY_PANELS QScriptEngine* _scriptEngine; +#endif bool _enabled = true; PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult, @@ -331,7 +338,7 @@ private: OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID }; - RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, + Q_INVOKABLE RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, const QVector& overlaysToInclude, const QVector& overlaysToDiscard, bool visibleOnly = false, bool collidableOnly = false); diff --git a/interface/src/ui/overlays/PanelAttachable.cpp b/interface/src/ui/overlays/PanelAttachable.cpp index 7f1c4e2e50..421155083c 100644 --- a/interface/src/ui/overlays/PanelAttachable.cpp +++ b/interface/src/ui/overlays/PanelAttachable.cpp @@ -16,11 +16,15 @@ #include "OverlayPanel.h" bool PanelAttachable::getParentVisible() const { +#if OVERLAY_PANELS if (getParentPanel()) { return getParentPanel()->getVisible() && getParentPanel()->getParentVisible(); } else { return true; } +#else + return true; +#endif } QVariant PanelAttachable::getProperty(const QString& property) { @@ -61,11 +65,13 @@ void PanelAttachable::applyTransformTo(Transform& transform, bool force) { if (force || usecTimestampNow() > _transformExpiry) { const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz _transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD; +#if OVERLAY_PANELS if (getParentPanel()) { getParentPanel()->applyTransformTo(transform, true); transform.postTranslate(getOffsetPosition()); transform.postRotate(getOffsetRotation()); transform.postScale(getOffsetScale()); } +#endif } } diff --git a/interface/src/ui/overlays/PanelAttachable.h b/interface/src/ui/overlays/PanelAttachable.h index 270addbfcf..4f37cd2258 100644 --- a/interface/src/ui/overlays/PanelAttachable.h +++ b/interface/src/ui/overlays/PanelAttachable.h @@ -30,6 +30,8 @@ #ifndef hifi_PanelAttachable_h #define hifi_PanelAttachable_h +#define OVERLAY_PANELS 0 + #include #include @@ -39,18 +41,21 @@ #include class OverlayPanel; - class PanelAttachable { public: // getters +#if OVERLAY_PANELS std::shared_ptr getParentPanel() const { return _parentPanel; } +#endif glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); } glm::quat getOffsetRotation() const { return _offset.getRotation(); } glm::vec3 getOffsetScale() const { return _offset.getScale(); } bool getParentVisible() const; // setters +#if OVERLAY_PANELS void setParentPanel(std::shared_ptr panel) { _parentPanel = panel; } +#endif void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); } void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); } void setOffsetScale(float scale) { _offset.setScale(scale); } @@ -66,7 +71,9 @@ protected: quint64 _transformExpiry = 0; private: +#if OVERLAY_PANELS std::shared_ptr _parentPanel = nullptr; +#endif Transform _offset; }; diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp index eb909de993..15e72cf1e3 100644 --- a/interface/src/ui/overlays/QmlOverlay.cpp +++ b/interface/src/ui/overlays/QmlOverlay.cpp @@ -32,21 +32,20 @@ QmlOverlay::QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay) } void QmlOverlay::buildQmlElement(const QUrl& url) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "buildQmlElement", Q_ARG(QUrl, url)); + return; + } + auto offscreenUi = DependencyManager::get(); - offscreenUi->returnFromUiThread([=] { - offscreenUi->load(url, [=](QQmlContext* context, QObject* object) { - QQuickItem* rawPtr = dynamic_cast(object); - // Create a shared ptr with a custom deleter lambda, that calls deleteLater - _qmlElement = std::shared_ptr(rawPtr, [](QQuickItem* ptr) { - if (ptr) { - ptr->deleteLater(); - } - }); + offscreenUi->load(url, [=](QQmlContext* context, QObject* object) { + QQuickItem* rawPtr = dynamic_cast(object); + // Create a shared ptr with a custom deleter lambda, that calls deleteLater + _qmlElement = std::shared_ptr(rawPtr, [](QQuickItem* ptr) { + if (ptr) { + ptr->deleteLater(); + } }); - while (!_qmlElement) { - qApp->processEvents(); - } - return QVariant(); }); } @@ -55,20 +54,23 @@ QmlOverlay::~QmlOverlay() { } void QmlOverlay::setProperties(const QVariantMap& properties) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setProperties", Q_ARG(QVariantMap, properties)); + return; + } + Overlay2D::setProperties(properties); auto bounds = _bounds; std::weak_ptr weakQmlElement = _qmlElement; - DependencyManager::get()->executeOnUiThread([weakQmlElement, bounds, properties] { - // check to see if qmlElement still exists - auto qmlElement = weakQmlElement.lock(); - if (qmlElement) { - qmlElement->setX(bounds.left()); - qmlElement->setY(bounds.top()); - qmlElement->setWidth(bounds.width()); - qmlElement->setHeight(bounds.height()); - QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); - } - }); + // check to see if qmlElement still exists + auto qmlElement = weakQmlElement.lock(); + if (qmlElement) { + qmlElement->setX(bounds.left()); + qmlElement->setY(bounds.top()); + qmlElement->setWidth(bounds.width()); + qmlElement->setHeight(bounds.height()); + QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); + } } void QmlOverlay::render(RenderArgs* args) { diff --git a/interface/src/ui/overlays/QmlOverlay.h b/interface/src/ui/overlays/QmlOverlay.h index 736d3884b5..ced2b6fa1f 100644 --- a/interface/src/ui/overlays/QmlOverlay.h +++ b/interface/src/ui/overlays/QmlOverlay.h @@ -32,7 +32,7 @@ public: void render(RenderArgs* args) override; private: - void buildQmlElement(const QUrl& url); + Q_INVOKABLE void buildQmlElement(const QUrl& url); protected: std::shared_ptr _qmlElement; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 01af69e3ad..c630fe09e4 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -259,10 +259,21 @@ void AudioClient::customDeleter() { void AudioClient::cleanupBeforeQuit() { // FIXME: this should be put in customDeleter, but there is still a reference to this when it is called, // so this must be explicitly, synchronously stopped + static ConditionalGuard guard; + if (QThread::currentThread() != thread()) { + // This will likely be called from the main thread, but we don't want to do blocking queued calls + // from the main thread, so we use a normal auto-connection invoke, and then use a conditional to wait + // for completion + // The effect is the same, yes, but we actually want to avoid the use of Qt::BlockingQueuedConnection + // in the code + QMetaObject::invokeMethod(this, "cleanupBeforeQuit"); + guard.wait(); + return; + } stop(); - _checkDevicesTimer->stop(); + guard.trigger(); } void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { @@ -1859,7 +1870,7 @@ void AudioClient::startThread() { } void AudioClient::setInputVolume(float volume) { - if (_audioInput && volume != _audioInput->volume()) { + if (_audioInput && volume != (float)_audioInput->volume()) { _audioInput->setVolume(volume); emit inputVolumeChanged(_audioInput->volume()); } diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 68bb872667..a370d7999b 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "OffscreenUi.h" static const char* const URL_PROPERTY = "source"; @@ -21,39 +22,51 @@ static const char* const SCRIPT_PROPERTY = "scriptUrl"; // Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { auto properties = parseArguments(context); - QmlWebWindowClass* retVal { nullptr }; auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([&] { - retVal = new QmlWebWindowClass(); - retVal->initQml(properties); - }, true); + QmlWebWindowClass* retVal = new QmlWebWindowClass(); Q_ASSERT(retVal); + if (QThread::currentThread() != qApp->thread()) { + retVal->moveToThread(qApp->thread()); + QMetaObject::invokeMethod(retVal, "initQml", Q_ARG(QVariantMap, properties)); + } else { + retVal->initQml(properties); + } connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); return engine->newQObject(retVal); } -QString QmlWebWindowClass::getURL() const { - QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { - if (_qmlWindow.isNull()) { - return QVariant(); - } - return _qmlWindow->property(URL_PROPERTY); - }); - return result.toString(); +QString QmlWebWindowClass::getURL() { + if (QThread::currentThread() != thread()) { + QString result = false; + hifi::qt::blockingInvokeMethod(this, "getURL", Q_RETURN_ARG(QString, result)); + return result; + } + + if (_qmlWindow.isNull()) { + return QString(); + } + + return _qmlWindow->property(URL_PROPERTY).toString(); } void QmlWebWindowClass::setURL(const QString& urlString) { - DependencyManager::get()->executeOnUiThread([=] { - if (!_qmlWindow.isNull()) { - _qmlWindow->setProperty(URL_PROPERTY, urlString); - } - }); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setURL", Q_ARG(QString, urlString)); + return; + } + + if (!_qmlWindow.isNull()) { + _qmlWindow->setProperty(URL_PROPERTY, urlString); + } } void QmlWebWindowClass::setScriptURL(const QString& script) { - DependencyManager::get()->executeOnUiThread([=] { - if (!_qmlWindow.isNull()) { - _qmlWindow->setProperty(SCRIPT_PROPERTY, script); - } - }); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setScriptURL", Q_ARG(QString, script)); + return; + } + + if (!_qmlWindow.isNull()) { + _qmlWindow->setProperty(SCRIPT_PROPERTY, script); + } } diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index 15ebe74a4f..cdc07265cd 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -20,7 +20,7 @@ public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); public slots: - QString getURL() const; + QString getURL(); void setURL(const QString& url); void setScriptURL(const QString& script); diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index f5bb880957..e773ea0c5d 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "OffscreenUi.h" static const char* const SOURCE_PROPERTY = "source"; @@ -73,13 +74,15 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { // Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { auto properties = parseArguments(context); - QmlWindowClass* retVal { nullptr }; auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([&] { - retVal = new QmlWindowClass(); - retVal->initQml(properties); - }, true); + QmlWindowClass* retVal = new QmlWindowClass(); Q_ASSERT(retVal); + if (QThread::currentThread() != qApp->thread()) { + retVal->moveToThread(qApp->thread()); + hifi::qt::blockingInvokeMethod(retVal, "initQml", Q_ARG(QVariantMap, properties)); + } else { + retVal->initQml(properties); + } connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); return engine->newQObject(retVal); } @@ -214,49 +217,64 @@ QQuickItem* QmlWindowClass::asQuickItem() const { } void QmlWindowClass::setVisible(bool visible) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setVisible", Q_ARG(bool, visible)); + return; + } + QQuickItem* targetWindow = asQuickItem(); if (_toolWindow) { // For tool window tabs we special case visibility as a function call on the tab parent // The tool window itself has special logic based on whether any tabs are visible QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible)); } else { - DependencyManager::get()->executeOnUiThread([=] { - targetWindow->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible); - }); + targetWindow->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible); } } -bool QmlWindowClass::isVisible() const { +bool QmlWindowClass::isVisible() { + if (QThread::currentThread() != thread()) { + bool result = false; + hifi::qt::blockingInvokeMethod(this, "isVisible", Q_RETURN_ARG(bool, result)); + return result; + } + // The tool window itself has special logic based on whether any tabs are enabled - return DependencyManager::get()->returnFromUiThread([&] { - if (_qmlWindow.isNull()) { - return QVariant::fromValue(false); - } - if (_toolWindow) { - return QVariant::fromValue(dynamic_cast(_qmlWindow.data())->isEnabled()); - } else { - return QVariant::fromValue(asQuickItem()->isVisible()); - } - }).toBool(); + if (_qmlWindow.isNull()) { + return false; + } + + if (_toolWindow) { + return dynamic_cast(_qmlWindow.data())->isEnabled(); + } + + return asQuickItem()->isVisible(); } -glm::vec2 QmlWindowClass::getPosition() const { - QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { - if (_qmlWindow.isNull()) { - return QVariant(QPointF(0, 0)); - } - return asQuickItem()->position(); - }); - return toGlm(result.toPointF()); +glm::vec2 QmlWindowClass::getPosition() { + if (QThread::currentThread() != thread()) { + vec2 result; + hifi::qt::blockingInvokeMethod(this, "getPosition", Q_RETURN_ARG(vec2, result)); + return result; + } + + if (_qmlWindow.isNull()) { + return {}; + } + + return toGlm(asQuickItem()->position()); } void QmlWindowClass::setPosition(const glm::vec2& position) { - DependencyManager::get()->executeOnUiThread([=] { - if (!_qmlWindow.isNull()) { - asQuickItem()->setPosition(QPointF(position.x, position.y)); - } - }); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setPosition", Q_ARG(vec2, position)); + return; + } + + if (!_qmlWindow.isNull()) { + asQuickItem()->setPosition(QPointF(position.x, position.y)); + } } void QmlWindowClass::setPosition(int x, int y) { @@ -268,23 +286,29 @@ glm::vec2 toGlm(const QSizeF& size) { return glm::vec2(size.width(), size.height()); } -glm::vec2 QmlWindowClass::getSize() const { - QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { - if (_qmlWindow.isNull()) { - return QVariant(QSizeF(0, 0)); - } - QQuickItem* targetWindow = asQuickItem(); - return QSizeF(targetWindow->width(), targetWindow->height()); - }); - return toGlm(result.toSizeF()); +glm::vec2 QmlWindowClass::getSize() { + if (QThread::currentThread() != thread()) { + vec2 result; + hifi::qt::blockingInvokeMethod(this, "getSize", Q_RETURN_ARG(vec2, result)); + return result; + } + + if (_qmlWindow.isNull()) { + return {}; + } + QQuickItem* targetWindow = asQuickItem(); + return vec2(targetWindow->width(), targetWindow->height()); } void QmlWindowClass::setSize(const glm::vec2& size) { - DependencyManager::get()->executeOnUiThread([=] { - if (!_qmlWindow.isNull()) { - asQuickItem()->setSize(QSizeF(size.x, size.y)); - } - }); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setSize", Q_ARG(vec2, size)); + return; + } + + if (!_qmlWindow.isNull()) { + asQuickItem()->setSize(QSizeF(size.x, size.y)); + } } void QmlWindowClass::setSize(int width, int height) { @@ -292,28 +316,33 @@ void QmlWindowClass::setSize(int width, int height) { } void QmlWindowClass::setTitle(const QString& title) { - DependencyManager::get()->executeOnUiThread([=] { - if (!_qmlWindow.isNull()) { - asQuickItem()->setProperty(TITLE_PROPERTY, title); - } - }); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setTitle", Q_ARG(QString, title)); + return; + } + + if (!_qmlWindow.isNull()) { + asQuickItem()->setProperty(TITLE_PROPERTY, title); + } } void QmlWindowClass::close() { - if (_qmlWindow) { - if (_toolWindow) { - auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([=] { - auto toolWindow = offscreenUi->getToolWindow(); - auto invokeResult = QMetaObject::invokeMethod(toolWindow, "removeTabForUrl", Qt::DirectConnection, - Q_ARG(QVariant, _source)); - Q_ASSERT(invokeResult); - }); - } else { - _qmlWindow->deleteLater(); - } - _qmlWindow = nullptr; + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "close"); + return; } + + if (_toolWindow) { + auto offscreenUi = DependencyManager::get(); + auto toolWindow = offscreenUi->getToolWindow(); + auto invokeResult = QMetaObject::invokeMethod(toolWindow, "removeTabForUrl", Qt::DirectConnection, + Q_ARG(QVariant, _source)); + Q_ASSERT(invokeResult); + return; + } else if (_qmlWindow) { + _qmlWindow->deleteLater(); + } + _qmlWindow = nullptr; } void QmlWindowClass::hasMoved(QVector2D position) { @@ -325,10 +354,13 @@ void QmlWindowClass::hasClosed() { } void QmlWindowClass::raise() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "raise"); + return; + } + auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([=] { - if (!_qmlWindow.isNull()) { - QMetaObject::invokeMethod(asQuickItem(), "raise", Qt::DirectConnection); - } - }); + if (_qmlWindow) { + QMetaObject::invokeMethod(asQuickItem(), "raise", Qt::DirectConnection); + } } diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index 4f604133a5..d3e1912d45 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -31,18 +31,18 @@ public: QmlWindowClass(); ~QmlWindowClass(); - virtual void initQml(QVariantMap properties); + Q_INVOKABLE virtual void initQml(QVariantMap properties); QQuickItem* asQuickItem() const; public slots: - bool isVisible() const; + bool isVisible(); void setVisible(bool visible); - glm::vec2 getPosition() const; + glm::vec2 getPosition(); void setPosition(const glm::vec2& position); void setPosition(int x, int y); - glm::vec2 getSize() const; + glm::vec2 getSize(); void setSize(const glm::vec2& size); void setSize(int width, int height); void setTitle(const QString& title); diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 573d873bab..19cd37a6cb 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -887,28 +887,6 @@ QQmlContext* OffscreenQmlSurface::getSurfaceContext() { return _qmlContext; } -void OffscreenQmlSurface::executeOnUiThread(std::function function, bool blocking ) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "executeOnUiThread", blocking ? Qt::BlockingQueuedConnection : Qt::QueuedConnection, - Q_ARG(std::function, function)); - return; - } - - function(); -} - -QVariant OffscreenQmlSurface::returnFromUiThread(std::function function) { - if (QThread::currentThread() != thread()) { - QVariant result; - hifi::qt::blockingInvokeMethod(this, "returnFromUiThread", - Q_RETURN_ARG(QVariant, result), - Q_ARG(std::function, function)); - return result; - } - - return function(); -} - void OffscreenQmlSurface::focusDestroyed(QObject *obj) { _currentFocusItem = nullptr; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index ae81ae48b4..54f27e3b1f 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -55,10 +55,6 @@ public: return load(QUrl(qmlSourceFile), f); } void clearCache(); - - Q_INVOKABLE void executeOnUiThread(std::function function, bool blocking = false); - Q_INVOKABLE QVariant returnFromUiThread(std::function function); - void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; } // Optional values for event handling void setProxyWindow(QWindow* window); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index ade8c73df5..0dbcfac25c 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -214,20 +214,18 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { // create new desktop window auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([=] { - auto tabletRootWindow = new TabletRootWindow(); - tabletRootWindow->initQml(QVariantMap()); - auto quickItem = tabletRootWindow->asQuickItem(); - _desktopWindow = tabletRootWindow; - QMetaObject::invokeMethod(quickItem, "setShown", Q_ARG(const QVariant&, QVariant(false))); + auto tabletRootWindow = new TabletRootWindow(); + tabletRootWindow->initQml(QVariantMap()); + auto quickItem = tabletRootWindow->asQuickItem(); + _desktopWindow = tabletRootWindow; + QMetaObject::invokeMethod(quickItem, "setShown", Q_ARG(const QVariant&, QVariant(false))); - QObject::connect(quickItem, SIGNAL(windowClosed()), this, SLOT(desktopWindowClosed())); + QObject::connect(quickItem, SIGNAL(windowClosed()), this, SLOT(desktopWindowClosed())); - QObject::connect(tabletRootWindow, SIGNAL(webEventReceived(QVariant)), this, SLOT(emitWebEvent(QVariant)), Qt::DirectConnection); + QObject::connect(tabletRootWindow, SIGNAL(webEventReceived(QVariant)), this, SLOT(emitWebEvent(QVariant)), Qt::DirectConnection); - // forward qml surface events to interface js - connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml); - }); + // forward qml surface events to interface js + connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml); } else { _state = State::Home; removeButtonsFromToolbar();