diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index abfc66ac55..efced972a0 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -141,7 +142,7 @@ void AssignmentClient::stopAssignmentClient() { QThread* currentAssignmentThread = _currentAssignment->thread(); // ask the current assignment to stop - QMetaObject::invokeMethod(_currentAssignment, "stop", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(_currentAssignment, "stop"); // ask the current assignment to delete itself on its thread _currentAssignment->deleteLater(); diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 57456b00c3..6443e7bf4b 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include "ScriptableAvatar.h" @@ -49,7 +50,7 @@ void ScriptableAvatar::stopAnimation() { AnimationDetails ScriptableAvatar::getAnimationDetails() { if (QThread::currentThread() != thread()) { AnimationDetails result; - QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "getAnimationDetails", Q_RETURN_ARG(AnimationDetails, result)); return result; } 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 d0845131f6..377819c0a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -48,6 +48,7 @@ #include +#include #include #include #include @@ -1207,15 +1208,26 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Make sure we don't time out during slow operations at startup updateHeartbeat(); - int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now - connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings); - connect(&_settingsThread, SIGNAL(started()), &_settingsTimer, SLOT(start())); - connect(&_settingsThread, SIGNAL(finished()), &_settingsTimer, SLOT(stop())); - _settingsTimer.moveToThread(&_settingsThread); - _settingsTimer.setSingleShot(false); - _settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable - _settingsThread.setPriority(QThread::LowestPriority); - _settingsThread.start(); + + QTimer* settingsTimer = new QTimer(); + moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ + connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{ + // Disconnect the signal from the save settings + QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); + // Stop the settings timer + settingsTimer->stop(); + // Delete it (this will trigger the thread destruction + settingsTimer->deleteLater(); + // Mark the settings thread as finished, so we know we can safely save in the main application + // shutdown code + _settingsGuard.trigger(); + }); + + int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now + settingsTimer->setSingleShot(false); + settingsTimer->setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable + QObject::connect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); + }, QThread::LowestPriority); if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); // So that camera doesn't auto-switch to third person. @@ -1643,7 +1655,7 @@ QString Application::getUserAgent() { if (QThread::currentThread() != thread()) { QString userAgent; - QMetaObject::invokeMethod(this, "getUserAgent", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, userAgent)); + BLOCKING_INVOKE_METHOD(this, "getUserAgent", Q_RETURN_ARG(QString, userAgent)); return userAgent; } @@ -1801,11 +1813,13 @@ void Application::cleanupBeforeQuit() { locationUpdateTimer.stop(); identityPacketTimer.stop(); pingTimer.stop(); - QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection); - // save state - _settingsThread.quit(); - saveSettings(); + // Wait for the settings thread to shut down, and save the settings one last time when it's safe + if (_settingsGuard.wait()) { + // save state + saveSettings(); + } + _window->saveGeometry(); // Destroy third party processes after scripts have finished using them. @@ -1829,8 +1843,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/Application.h b/interface/src/Application.h index c26b3b215e..28d95a280c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -596,8 +597,7 @@ private: bool _notifiedPacketVersionMismatchThisDomain; - QThread _settingsThread; - QTimer _settingsTimer; + ConditionalGuard _settingsGuard; GLCanvas* _glWidget{ nullptr }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 20b3949bc6..c46d61cf68 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -25,6 +25,7 @@ #endif +#include #include #include #include @@ -482,7 +483,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& const QScriptValue& avatarIdsToDiscard) { RayToAvatarIntersectionResult result; if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(const_cast(this), "findRayIntersection", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersection", Q_RETURN_ARG(RayToAvatarIntersectionResult, result), Q_ARG(const PickRay&, ray), Q_ARG(const QScriptValue&, avatarIdsToInclude), diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8d81154cab..8cd39b298f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -21,6 +21,7 @@ #include +#include #include #include #include @@ -897,7 +898,7 @@ void MyAvatar::restoreAnimation() { QStringList MyAvatar::getAnimationRoles() { if (QThread::currentThread() != thread()) { QStringList result; - QMetaObject::invokeMethod(this, "getAnimationRoles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QStringList, result)); + BLOCKING_INVOKE_METHOD(this, "getAnimationRoles", Q_RETURN_ARG(QStringList, result)); return result; } return _skeletonModel->getRig().getAnimationRoles(); @@ -1368,7 +1369,7 @@ void MyAvatar::resetFullAvatarURL() { void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL", Q_ARG(const QUrl&, fullAvatarURL), Q_ARG(const QString&, modelName)); return; @@ -1394,7 +1395,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN void MyAvatar::setAttachmentData(const QVector& attachmentData) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setAttachmentData", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "setAttachmentData", Q_ARG(const QVector, attachmentData)); return; } @@ -2371,7 +2372,7 @@ bool MyAvatar::safeLanding(const glm::vec3& position) { if (QThread::currentThread() != thread()) { bool result; - QMetaObject::invokeMethod(this, "safeLanding", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result), Q_ARG(const glm::vec3&, position)); + BLOCKING_INVOKE_METHOD(this, "safeLanding", Q_RETURN_ARG(bool, result), Q_ARG(const glm::vec3&, position)); return result; } glm::vec3 better; diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 4576190413..8125f9a9f0 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -11,6 +11,8 @@ #include "Audio.h" +#include + #include "Application.h" #include "AudioClient.h" #include "ui/AvatarInputs.h" @@ -49,27 +51,22 @@ float Audio::loudnessToLevel(float loudness) { Audio::Audio() : _devices(_contextIsHMD) { auto client = DependencyManager::get().data(); connect(client, &AudioClient::muteToggled, this, &Audio::onMutedChanged); + connect(client, &AudioClient::noiseReductionChanged, this, &Audio::onNoiseReductionChanged); connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged); + connect(client, &AudioClient::inputVolumeChanged, this, &Audio::onInputVolumeChanged); connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged); - connect(&_devices._inputs, &AudioDeviceList::deviceChanged, this, &Audio::onInputChanged); enableNoiseReduction(enableNoiseReductionSetting.get()); } void Audio::setMuted(bool isMuted) { if (_isMuted != isMuted) { auto client = DependencyManager::get().data(); - QMetaObject::invokeMethod(client, "toggleMute", Qt::BlockingQueuedConnection); - - _isMuted = isMuted; - emit mutedChanged(_isMuted); + QMetaObject::invokeMethod(client, "toggleMute"); } } void Audio::onMutedChanged() { - auto client = DependencyManager::get().data(); - bool isMuted; - QMetaObject::invokeMethod(client, "isMuted", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isMuted)); - + bool isMuted = DependencyManager::get()->isMuted(); if (_isMuted != isMuted) { _isMuted = isMuted; emit mutedChanged(_isMuted); @@ -79,11 +76,16 @@ void Audio::onMutedChanged() { void Audio::enableNoiseReduction(bool enable) { if (_enableNoiseReduction != enable) { auto client = DependencyManager::get().data(); - QMetaObject::invokeMethod(client, "setNoiseReduction", Qt::BlockingQueuedConnection, Q_ARG(bool, enable)); - + QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable)); enableNoiseReductionSetting.set(enable); - _enableNoiseReduction = enable; - emit noiseReductionChanged(enable); + } +} + +void Audio::onNoiseReductionChanged() { + bool noiseReductionEnabled = DependencyManager::get()->isNoiseReductionEnabled(); + if (_enableNoiseReduction != noiseReductionEnabled) { + _enableNoiseReduction = noiseReductionEnabled; + emit noiseReductionChanged(_enableNoiseReduction); } } @@ -93,19 +95,11 @@ void Audio::setInputVolume(float volume) { if (_inputVolume != volume) { auto client = DependencyManager::get().data(); - QMetaObject::invokeMethod(client, "setInputVolume", Qt::BlockingQueuedConnection, Q_ARG(float, volume)); - - _inputVolume = volume; - emit inputVolumeChanged(_inputVolume); + QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume)); } } -// different audio input devices may have different volumes -void Audio::onInputChanged() { - auto client = DependencyManager::get().data(); - float volume; - QMetaObject::invokeMethod(client, "getInputVolume", Qt::BlockingQueuedConnection, Q_RETURN_ARG(float, volume)); - +void Audio::onInputVolumeChanged(float volume) { if (_inputVolume != volume) { _inputVolume = volume; emit inputVolumeChanged(_inputVolume); diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 953727ede8..ca89521489 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -62,9 +62,12 @@ signals: void contextChanged(const QString& context); public slots: - void onMutedChanged(); void onContextChanged(); - void onInputChanged(); + +private slots: + void onMutedChanged(); + void onNoiseReductionChanged(); + void onInputVolumeChanged(float volume); void onInputLoudnessChanged(float loudness); protected: diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index b0ea8226e8..98b8a7c12c 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -11,6 +11,8 @@ #include +#include + #include "AudioDevices.h" #include "Application.h" @@ -71,22 +73,14 @@ bool AudioDeviceList::setData(const QModelIndex& index, const QVariant& value, i bool AudioDeviceList::setDevice(int row, bool fromUser) { bool success = false; auto& device = _devices[row]; + _userSelection = fromUser; // skip if already selected if (!device.selected) { auto client = DependencyManager::get(); - QMetaObject::invokeMethod(client.data(), "switchAudioDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, success), + QMetaObject::invokeMethod(client.data(), "switchAudioDevice", Q_ARG(QAudio::Mode, _mode), Q_ARG(const QAudioDeviceInfo&, device.info)); - - if (success) { - device.selected = true; - if (fromUser) { - emit deviceSelected(device.info, _selectedDevice); - } - emit deviceChanged(device.info); - } } emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); @@ -135,12 +129,12 @@ void AudioDeviceList::resetDevice(bool contextIsHMD, const QString& device) { } void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) { + auto oldDevice = _selectedDevice; _selectedDevice = device; QModelIndex index; for (auto i = 0; i < _devices.size(); ++i) { AudioDevice& device = _devices[i]; - if (device.selected && device.info != _selectedDevice) { device.selected = false; } else if (device.info == _selectedDevice) { @@ -149,6 +143,11 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) { } } + if (_userSelection) { + _userSelection = false; + emit deviceSelected(_selectedDevice, oldDevice); + } + emit deviceChanged(_selectedDevice); emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index cd47ab4191..8e82ddc4fb 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -58,7 +58,7 @@ private: static QHash _roles; static Qt::ItemFlags _flags; - + bool _userSelection { false }; QAudio::Mode _mode; QAudioDeviceInfo _selectedDevice; QList _devices; diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index b803080538..f8db061299 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -8,9 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Application.h" #include "ClipboardScriptingInterface.h" +#include + +#include "Application.h" + ClipboardScriptingInterface::ClipboardScriptingInterface() { } @@ -24,7 +27,7 @@ float ClipboardScriptingInterface::getClipboardContentsLargestDimension() { bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector& entityIDs) { bool retVal; - QMetaObject::invokeMethod(qApp, "exportEntities", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(qApp, "exportEntities", Q_RETURN_ARG(bool, retVal), Q_ARG(const QString&, filename), Q_ARG(const QVector&, entityIDs)); @@ -33,7 +36,7 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, const bool ClipboardScriptingInterface::exportEntities(const QString& filename, float x, float y, float z, float s) { bool retVal; - QMetaObject::invokeMethod(qApp, "exportEntities", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(qApp, "exportEntities", Q_RETURN_ARG(bool, retVal), Q_ARG(const QString&, filename), Q_ARG(float, x), @@ -45,7 +48,7 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float bool ClipboardScriptingInterface::importEntities(const QString& filename) { bool retVal; - QMetaObject::invokeMethod(qApp, "importEntities", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(qApp, "importEntities", Q_RETURN_ARG(bool, retVal), Q_ARG(const QString&, filename)); return retVal; @@ -53,7 +56,7 @@ bool ClipboardScriptingInterface::importEntities(const QString& filename) { QVector ClipboardScriptingInterface::pasteEntities(glm::vec3 position) { QVector retVal; - QMetaObject::invokeMethod(qApp, "pasteEntities", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(qApp, "pasteEntities", Q_RETURN_ARG(QVector, retVal), Q_ARG(float, position.x), Q_ARG(float, position.y), diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 3c10475242..826732c777 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -13,6 +13,10 @@ #include +#include + +#include + /**jsdoc * @namespace Clipboard */ diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 883a6e758e..35f2e2aa86 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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 91fba1ce9e..d9372978e8 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include "Menu.h" @@ -43,7 +44,7 @@ bool MenuScriptingInterface::menuExists(const QString& menu) { return Menu::getInstance()->menuExists(menu); } bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "menuExists", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(Menu::getInstance(), "menuExists", Q_RETURN_ARG(bool, result), Q_ARG(const QString&, menu)); return result; @@ -86,7 +87,7 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& return Menu::getInstance()->menuItemExists(menu, menuitem); } bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "menuItemExists", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(Menu::getInstance(), "menuItemExists", Q_RETURN_ARG(bool, result), Q_ARG(const QString&, menu), Q_ARG(const QString&, menuitem)); @@ -114,7 +115,7 @@ bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { return Menu::getInstance()->isOptionChecked(menuOption); } bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isOptionChecked", Q_RETURN_ARG(bool, result), Q_ARG(const QString&, menuOption)); return result; @@ -131,7 +132,7 @@ bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) { return Menu::getInstance()->isOptionChecked(menuOption); } bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "isMenuEnabled", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isMenuEnabled", Q_RETURN_ARG(bool, result), Q_ARG(const QString&, menuOption)); return result; @@ -157,7 +158,7 @@ bool MenuScriptingInterface::isInfoViewVisible(const QString& path) { } bool result; - QMetaObject::invokeMethod(Menu::getInstance(), "isInfoViewVisible", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isInfoViewVisible", Q_RETURN_ARG(bool, result), Q_ARG(const QString&, path)); return result; } diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 84c742d0ab..d4b4ba1480 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; + BLOCKING_INVOKE_METHOD(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/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 38f467f22b..84f4cbbbd8 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "WindowScriptingInterface.h" + #include #include #include #include +#include #include #include @@ -24,8 +27,6 @@ #include "Menu.h" #include "OffscreenUi.h" -#include "WindowScriptingInterface.h" - static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation"; static const QString LAST_BROWSE_ASSETS_LOCATION_SETTING = "LastBrowseAssetsLocation"; @@ -316,7 +317,7 @@ bool WindowScriptingInterface::isPhysicsEnabled() { int WindowScriptingInterface::openMessageBox(QString title, QString text, int buttons, int defaultButton) { if (QThread::currentThread() != thread()) { int result; - QMetaObject::invokeMethod(this, "openMessageBox", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "openMessageBox", Q_RETURN_ARG(int, result), Q_ARG(QString, title), Q_ARG(QString, text), diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 4fb4829636..f8ed20f42f 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -18,6 +18,8 @@ #include #include +#include + class CustomPromptResult { public: QVariant value; diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 79314ce49a..443f11fb23 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -115,7 +116,7 @@ void JSConsole::executeCommand(const QString& command) { QScriptValue JSConsole::executeCommandInWatcher(const QString& command) { QScriptValue result; - QMetaObject::invokeMethod(_scriptEngine, "evaluate", Qt::ConnectionType::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(_scriptEngine, "evaluate", Q_RETURN_ARG(QScriptValue, result), Q_ARG(const QString&, command), Q_ARG(const QString&, _consoleFileName)); 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..0c73f1fa70 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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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; + BLOCKING_INVOKE_METHOD(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()) { + BLOCKING_INVOKE_METHOD(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/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 7d4c0f4e92..9aa315beb8 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -9,15 +9,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AnimationCache.h" + #include #include -#include "AnimationCache.h" -#include "AnimationLogging.h" +#include #include #include #include +#include "AnimationLogging.h" + int animationPointerMetaTypeId = qRegisterMetaType(); AnimationCache::AnimationCache(QObject* parent) : @@ -31,7 +34,7 @@ AnimationCache::AnimationCache(QObject* parent) : AnimationPointer AnimationCache::getAnimation(const QUrl& url) { if (QThread::currentThread() != thread()) { AnimationPointer result; - QMetaObject::invokeMethod(this, "getAnimation", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "getAnimation", Q_RETURN_ARG(AnimationPointer, result), Q_ARG(const QUrl&, url)); return result; } @@ -97,7 +100,7 @@ bool Animation::isLoaded() const { QStringList Animation::getJointNames() const { if (QThread::currentThread() != thread()) { QStringList result; - QMetaObject::invokeMethod(const_cast(this), "getJointNames", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointNames", Q_RETURN_ARG(QStringList, result)); return result; } @@ -111,7 +114,7 @@ QStringList Animation::getJointNames() const { QVector Animation::getFrames() const { if (QThread::currentThread() != thread()) { QVector result; - QMetaObject::invokeMethod(const_cast(this), "getFrames", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getFrames", Q_RETURN_ARG(QVector, result)); return result; } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 43af7afdef..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) { @@ -1335,6 +1346,14 @@ void AudioClient::toggleMute() { emit muteToggled(); } +void AudioClient::setNoiseReduction(bool enable) { + if (_isNoiseGateEnabled != enable) { + _isNoiseGateEnabled = enable; + emit noiseReductionChanged(); + } +} + + void AudioClient::setIsStereoInput(bool isStereoInput) { if (isStereoInput != _isStereoInput) { _isStereoInput = isStereoInput; @@ -1446,6 +1465,8 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this); _numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat); _audioInput->setBufferSize(_numInputCallbackBytes); + // different audio input devices may have different volumes + emit inputVolumeChanged(_audioInput->volume()); // how do we want to handle input working, but output not working? int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes); @@ -1703,7 +1724,7 @@ float AudioClient::azimuthForSource(const glm::vec3& relativePosition) { // produce an oriented angle about the y-axis glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2)); - float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" + float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" return (direction.x < 0.0f) ? -angle : angle; } else { @@ -1847,3 +1868,10 @@ void AudioClient::setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 sca void AudioClient::startThread() { moveToNewNamedThread(this, "Audio Thread", [this] { start(); }); } + +void AudioClient::setInputVolume(float volume) { + if (_audioInput && volume != (float)_audioInput->volume()) { + _audioInput->setVolume(volume); + emit inputVolumeChanged(_audioInput->volume()); + } +} diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 54ce3aa6c2..62b99d2443 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -180,7 +180,8 @@ public slots: virtual void setIsStereoInput(bool stereo) override; - void setNoiseReduction(bool isNoiseGateEnabled) { _isNoiseGateEnabled = isNoiseGateEnabled; } + void setNoiseReduction(bool isNoiseGateEnabled); + bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; } void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; } void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; } @@ -197,7 +198,7 @@ public slots: bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName); float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; } - void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } + void setInputVolume(float volume); void setReverb(bool reverb); void setReverbOptions(const AudioEffectOptions* options); @@ -207,7 +208,9 @@ public slots: void saveSettings(); signals: - bool muteToggled(); + void inputVolumeChanged(float volume); + void muteToggled(); + void noiseReductionChanged(); void mutedByMixer(); void inputReceived(const QByteArray& inputSamples); void inputLoudnessChanged(float loudness); diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 1646540da6..162e833da2 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -9,10 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "SoundCache.h" + +#include + +#include #include "AudioLogging.h" -#include "SoundCache.h" static const int SOUNDS_LOADING_PRIORITY { -7 }; // Make sure sounds load after the low rez texture mips @@ -29,7 +32,7 @@ SoundCache::SoundCache(QObject* parent) : SharedSoundPointer SoundCache::getSound(const QUrl& url) { if (QThread::currentThread() != thread()) { SharedSoundPointer result; - QMetaObject::invokeMethod(this, "getSound", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "getSound", Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); return result; } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index a0a348388e..d303b2e66d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -1010,7 +1011,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const { int Avatar::getJointIndex(const QString& name) const { if (QThread::currentThread() != thread()) { int result; - QMetaObject::invokeMethod(const_cast(this), "getJointIndex", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointIndex", Q_RETURN_ARG(int, result), Q_ARG(const QString&, name)); return result; } @@ -1024,7 +1025,7 @@ int Avatar::getJointIndex(const QString& name) const { QStringList Avatar::getJointNames() const { if (QThread::currentThread() != thread()) { QStringList result; - QMetaObject::invokeMethod(const_cast(this), "getJointNames", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointNames", Q_RETURN_ARG(QStringList, result)); return result; } @@ -1034,7 +1035,7 @@ QStringList Avatar::getJointNames() const { glm::vec3 Avatar::getJointPosition(int index) const { if (QThread::currentThread() != thread()) { glm::vec3 position; - QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointPosition", Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index)); return position; } @@ -1046,7 +1047,7 @@ glm::vec3 Avatar::getJointPosition(int index) const { glm::vec3 Avatar::getJointPosition(const QString& name) const { if (QThread::currentThread() != thread()) { glm::vec3 position; - QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointPosition", Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name)); return position; } @@ -1105,7 +1106,7 @@ static std::shared_ptr allocateAttachmentModel(bool isSoft, const Rig& ri void Avatar::setAttachmentData(const QVector& attachmentData) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setAttachmentData", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "setAttachmentData", Q_ARG(const QVector, attachmentData)); return; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 5023bd7ae5..6eed23fb5b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -1227,7 +1228,7 @@ bool AvatarData::isJointDataValid(int index) const { } if (QThread::currentThread() != thread()) { bool result; - QMetaObject::invokeMethod(const_cast(this), "isJointDataValid", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "isJointDataValid", Q_RETURN_ARG(bool, result), Q_ARG(int, index)); return result; } @@ -1240,7 +1241,7 @@ glm::quat AvatarData::getJointRotation(int index) const { } if (QThread::currentThread() != thread()) { glm::quat result; - QMetaObject::invokeMethod(const_cast(this), "getJointRotation", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointRotation", Q_RETURN_ARG(glm::quat, result), Q_ARG(int, index)); return result; } @@ -1255,7 +1256,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const { } if (QThread::currentThread() != thread()) { glm::vec3 result; - QMetaObject::invokeMethod(const_cast(this), "getJointTranslation", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointTranslation", Q_RETURN_ARG(glm::vec3, result), Q_ARG(int, index)); return result; } @@ -1266,7 +1267,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const { glm::vec3 AvatarData::getJointTranslation(const QString& name) const { if (QThread::currentThread() != thread()) { glm::vec3 result; - QMetaObject::invokeMethod(const_cast(this), "getJointTranslation", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointTranslation", Q_RETURN_ARG(glm::vec3, result), Q_ARG(const QString&, name)); return result; } @@ -1344,7 +1345,7 @@ void AvatarData::clearJointData(const QString& name) { bool AvatarData::isJointDataValid(const QString& name) const { if (QThread::currentThread() != thread()) { bool result; - QMetaObject::invokeMethod(const_cast(this), "isJointDataValid", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "isJointDataValid", Q_RETURN_ARG(bool, result), Q_ARG(const QString&, name)); return result; } @@ -1354,7 +1355,7 @@ bool AvatarData::isJointDataValid(const QString& name) const { glm::quat AvatarData::getJointRotation(const QString& name) const { if (QThread::currentThread() != thread()) { glm::quat result; - QMetaObject::invokeMethod(const_cast(this), "getJointRotation", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointRotation", Q_RETURN_ARG(glm::quat, result), Q_ARG(const QString&, name)); return result; } @@ -1364,8 +1365,7 @@ glm::quat AvatarData::getJointRotation(const QString& name) const { QVector AvatarData::getJointRotations() const { if (QThread::currentThread() != thread()) { QVector result; - QMetaObject::invokeMethod(const_cast(this), - "getJointRotations", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointRotations", Q_RETURN_ARG(QVector, result)); return result; } @@ -1380,8 +1380,7 @@ QVector AvatarData::getJointRotations() const { void AvatarData::setJointRotations(QVector jointRotations) { if (QThread::currentThread() != thread()) { QVector result; - QMetaObject::invokeMethod(const_cast(this), - "setJointRotations", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "setJointRotations", Q_ARG(QVector, jointRotations)); } QWriteLocker writeLock(&_jointDataLock); @@ -1398,8 +1397,7 @@ void AvatarData::setJointRotations(QVector jointRotations) { QVector AvatarData::getJointTranslations() const { if (QThread::currentThread() != thread()) { QVector result; - QMetaObject::invokeMethod(const_cast(this), - "getJointTranslations", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointTranslations", Q_RETURN_ARG(QVector, result)); return result; } @@ -1414,8 +1412,7 @@ QVector AvatarData::getJointTranslations() const { void AvatarData::setJointTranslations(QVector jointTranslations) { if (QThread::currentThread() != thread()) { QVector result; - QMetaObject::invokeMethod(const_cast(this), - "setJointTranslations", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "setJointTranslations", Q_ARG(QVector, jointTranslations)); } QWriteLocker writeLock(&_jointDataLock); @@ -1616,7 +1613,7 @@ void AvatarData::setDisplayName(const QString& displayName) { QVector AvatarData::getAttachmentData() const { if (QThread::currentThread() != thread()) { QVector result; - QMetaObject::invokeMethod(const_cast(this), "getAttachmentData", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getAttachmentData", Q_RETURN_ARG(QVector, result)); return result; } @@ -2339,7 +2336,7 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID) { AvatarEntityMap AvatarData::getAvatarEntityData() const { AvatarEntityMap result; if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(const_cast(this), "getAvatarEntityData", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getAvatarEntityData", Q_RETURN_ARG(AvatarEntityMap, result)); return result; } @@ -2380,7 +2377,7 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() { AvatarEntityIDs result; if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(const_cast(this), "getAndClearRecentlyDetachedIDs", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getAndClearRecentlyDetachedIDs", Q_RETURN_ARG(AvatarEntityIDs, result)); return result; } diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index d8e0c59da7..29b8aee08b 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -11,14 +11,16 @@ #include #include +#include + #include #include #include #include -#include #include #include +#include #include #include #include @@ -289,7 +291,7 @@ glm::vec2 CompositorHelper::getReticleMaximumPosition() const { void CompositorHelper::sendFakeMouseEvent() { if (qApp->thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "sendFakeMouseEvent", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "sendFakeMouseEvent"); return; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 1684c06512..a8eca41077 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -380,7 +381,7 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loading // Only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "allocateModel", Q_RETURN_ARG(ModelPointer, model), Q_ARG(const QString&, url)); @@ -397,7 +398,7 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loading ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl) { // Only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "updateModel", Q_RETURN_ARG(ModelPointer, model), Q_ARG(ModelPointer, model), Q_ARG(const QString&, newUrl)); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7351d49dff..f22631d363 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -9,19 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityScriptingInterface.h" + #include #include -#include "EntityScriptingInterface.h" - #include #include -#include "EntityItemID.h" +#include #include #include #include +#include "EntityItemID.h" #include "EntitiesLogging.h" #include "EntityDynamicFactoryInterface.h" #include "EntityDynamicInterface.h" @@ -1488,7 +1489,7 @@ int EntityScriptingInterface::getJointIndex(const QUuid& entityID, const QString return -1; } int result; - QMetaObject::invokeMethod(_entityTree.get(), "getJointIndex", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(_entityTree.get(), "getJointIndex", Q_RETURN_ARG(int, result), Q_ARG(QUuid, entityID), Q_ARG(QString, name)); return result; } @@ -1498,7 +1499,7 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) { return QStringList(); } QStringList result; - QMetaObject::invokeMethod(_entityTree.get(), "getJointNames", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(_entityTree.get(), "getJointNames", Q_RETURN_ARG(QStringList, result), Q_ARG(QUuid, entityID)); return result; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index e8506e5263..262f0318b6 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -232,7 +233,7 @@ void NodeList::processICEPingPacket(QSharedPointer message) { void NodeList::reset() { if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "reset", Qt::BlockingQueuedConnection); + QMetaObject::invokeMethod(this, "reset"); return; } diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index f07514cd85..43f0e9335d 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -9,22 +9,24 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ResourceCache.h" + #include #include +#include #include #include #include -#include +#include +#include +#include #include "NetworkAccessManager.h" #include "NetworkLogging.h" #include "NodeList.h" -#include "ResourceCache.h" -#include -#include #define clamp(x, min, max) (((x) < (min)) ? (min) :\ (((x) > (max)) ? (max) :\ @@ -178,7 +180,7 @@ ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra) { if (QThread::currentThread() != thread()) { // Must be called in thread to ensure getResource returns a valid pointer - QMetaObject::invokeMethod(this, "prefetch", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "prefetch", Q_RETURN_ARG(ScriptableResource*, result), Q_ARG(QUrl, url), Q_ARG(void*, extra)); return result; @@ -301,7 +303,7 @@ QVariantList ResourceCache::getResourceList() { QVariantList list; if (QThread::currentThread() != thread()) { // NOTE: invokeMethod does not allow a const QObject* - QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "getResourceList", Q_RETURN_ARG(QVariantList, list)); } else { auto resources = _resources.uniqueKeys(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 357f8a64d8..a3374a0f47 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -17,6 +17,7 @@ #include +#include #include #include "../NetworkLogging.h" @@ -276,7 +277,7 @@ Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { void Socket::clearConnections() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "clearConnections"); return; } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 04b1e3b370..9234ac6585 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -11,6 +11,8 @@ #include +#include + #include "DisplayPlugin.h" #include "InputPlugin.h" #include "PluginManager.h" @@ -21,7 +23,7 @@ InputConfiguration::InputConfiguration() { QStringList InputConfiguration::inputPlugins() { if (QThread::currentThread() != thread()) { QStringList result; - QMetaObject::invokeMethod(this, "inputPlugins", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "inputPlugins", Q_RETURN_ARG(QStringList, result)); return result; } @@ -42,7 +44,7 @@ QStringList InputConfiguration::inputPlugins() { QStringList InputConfiguration::activeInputPlugins() { if (QThread::currentThread() != thread()) { QStringList result; - QMetaObject::invokeMethod(this, "activeInputPlugins", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "activeInputPlugins", Q_RETURN_ARG(QStringList, result)); return result; } @@ -64,7 +66,7 @@ QStringList InputConfiguration::activeInputPlugins() { QString InputConfiguration::configurationLayout(QString pluginName) { if (QThread::currentThread() != thread()) { QString result; - QMetaObject::invokeMethod(this, "configurationLayout", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "configurationLayout", Q_RETURN_ARG(QString, result), Q_ARG(QString, pluginName)); return result; @@ -81,7 +83,7 @@ QString InputConfiguration::configurationLayout(QString pluginName) { void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setConfigurationSettings", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "setConfigurationSettings", Q_ARG(QJsonObject, configurationSettings), Q_ARG(QString, pluginName)); return; @@ -97,7 +99,7 @@ void InputConfiguration::setConfigurationSettings(QJsonObject configurationSetti QJsonObject InputConfiguration::configurationSettings(QString pluginName) { if (QThread::currentThread() != thread()) { QJsonObject result; - QMetaObject::invokeMethod(this, "configurationSettings", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "configurationSettings", Q_RETURN_ARG(QJsonObject, result), Q_ARG(QString, pluginName)); return result; @@ -113,7 +115,7 @@ QJsonObject InputConfiguration::configurationSettings(QString pluginName) { void InputConfiguration::calibratePlugin(QString pluginName) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "calibratePlugin", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "calibratePlugin"); return; } @@ -128,7 +130,7 @@ void InputConfiguration::calibratePlugin(QString pluginName) { bool InputConfiguration::uncalibratePlugin(QString pluginName) { if (QThread::currentThread() != thread()) { bool result; - QMetaObject::invokeMethod(this, "uncalibratePlugin", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "uncalibratePlugin", Q_ARG(bool, result)); return result; } diff --git a/libraries/recording/src/recording/ClipCache.cpp b/libraries/recording/src/recording/ClipCache.cpp index 5c55c6bb1c..0fbbf1bc8e 100644 --- a/libraries/recording/src/recording/ClipCache.cpp +++ b/libraries/recording/src/recording/ClipCache.cpp @@ -8,6 +8,8 @@ #include +#include + #include "ClipCache.h" #include "impl/PointerClip.h" #include "Logging.h" @@ -37,7 +39,7 @@ ClipCache::ClipCache(QObject* parent) : NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) { if (QThread::currentThread() != thread()) { NetworkClipLoaderPointer result; - QMetaObject::invokeMethod(this, "getClipLoader", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "getClipLoader", Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url)); return result; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 67452c5d33..45be09b701 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -870,7 +871,7 @@ bool Model::getRelativeDefaultJointTranslation(int jointIndex, glm::vec3& transl QStringList Model::getJointNames() const { if (QThread::currentThread() != thread()) { QStringList result; - QMetaObject::invokeMethod(const_cast(this), "getJointNames", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(const_cast(this), "getJointNames", Q_RETURN_ARG(QStringList, result)); return result; } diff --git a/libraries/render/src/task/Config.cpp b/libraries/render/src/task/Config.cpp index 0e630311f6..b378237c9c 100644 --- a/libraries/render/src/task/Config.cpp +++ b/libraries/render/src/task/Config.cpp @@ -10,9 +10,12 @@ // #include "Config.h" -#include "Task.h" #include +#include + +#include "Task.h" + using namespace task; void JobConfig::setPresetList(const QJsonObject& object) { @@ -58,7 +61,7 @@ void TaskConfig::transferChildrenConfigs(QConfigPointer source) { void TaskConfig::refresh() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "refresh", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "refresh"); return; } diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index ecaffaf35c..28bf5ed163 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -13,6 +13,8 @@ #include +#include + #include "ScriptAudioInjector.h" #include "ScriptEngineLogging.h" @@ -32,7 +34,7 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(SharedSoundPointer sound if (QThread::currentThread() != thread()) { ScriptAudioInjector* injector = NULL; - QMetaObject::invokeMethod(this, "playSound", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "playSound", Q_RETURN_ARG(ScriptAudioInjector*, injector), Q_ARG(SharedSoundPointer, sound), Q_ARG(const AudioInjectorOptions&, injectorOptions)); diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 7583f562e6..b51e9cd529 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -98,7 +99,7 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue void RecordingScriptingInterface::startPlaying() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "startPlaying"); return; } @@ -115,7 +116,7 @@ void RecordingScriptingInterface::setPlayerAudioOffset(float audioOffset) { void RecordingScriptingInterface::setPlayerTime(float time) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setPlayerTime", Qt::BlockingQueuedConnection, Q_ARG(float, time)); + BLOCKING_INVOKE_METHOD(this, "setPlayerTime", Q_ARG(float, time)); return; } _player->seek(time); @@ -147,7 +148,7 @@ void RecordingScriptingInterface::setPlayerUseSkeletonModel(bool useSkeletonMode void RecordingScriptingInterface::pausePlayer() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "pausePlayer", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "pausePlayer"); return; } _player->pause(); @@ -155,7 +156,7 @@ void RecordingScriptingInterface::pausePlayer() { void RecordingScriptingInterface::stopPlaying() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "stopPlaying", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "stopPlaying"); return; } _player->stop(); @@ -176,7 +177,7 @@ void RecordingScriptingInterface::startRecording() { } if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "startRecording", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "startRecording"); return; } @@ -199,7 +200,7 @@ QString RecordingScriptingInterface::getDefaultRecordingSaveDirectory() { void RecordingScriptingInterface::saveRecording(const QString& filename) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "saveRecording", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "saveRecording", Q_ARG(QString, filename)); return; } @@ -220,7 +221,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr if (QThread::currentThread() != thread()) { bool result; - QMetaObject::invokeMethod(this, "saveRecordingToAsset", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "saveRecordingToAsset", Q_RETURN_ARG(bool, result), Q_ARG(QScriptValue, getClipAtpUrl)); return result; @@ -257,7 +258,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr void RecordingScriptingInterface::loadLastRecording() { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "loadLastRecording", Qt::BlockingQueuedConnection); + BLOCKING_INVOKE_METHOD(this, "loadLastRecording"); return; } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 11bb044d72..b51cb0ee3b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -36,6 +36,7 @@ #include +#include #include #include #include @@ -436,12 +437,12 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { _fileNameString = url.toString(); _isReloading = reload; - // Check that script has a supported file extension + // Check that script has a supported file extension if (!hasValidScriptSuffix(_fileNameString)) { scriptErrorMessage("File extension of file: " + _fileNameString + " is not a currently supported script type"); emit errorLoadingScript(_fileNameString); return; - } + } const auto maxRetries = 0; // for consistency with previous scriptCache->getScript() behavior auto scriptCache = DependencyManager::get(); @@ -964,7 +965,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; #endif - QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "evaluate", Q_RETURN_ARG(QScriptValue, result), Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName), diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 72392ac376..57b04eeb82 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -452,7 +453,7 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL bool activateMainWindow, bool reload) { if (thread() != QThread::currentThread()) { ScriptEngine* result { nullptr }; - QMetaObject::invokeMethod(this, "loadScript", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ScriptEngine*, result), + BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEngine*, result), Q_ARG(QUrl, scriptFilename), Q_ARG(bool, isUserLoaded), Q_ARG(bool, loadScriptFromEditor), diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h index 6461fa5724..6e024f787a 100644 --- a/libraries/shared/src/ThreadHelpers.h +++ b/libraries/shared/src/ThreadHelpers.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -34,4 +35,25 @@ void withLock(QMutex& lock, F function) { void moveToNewNamedThread(QObject* object, const QString& name, std::function startCallback, QThread::Priority priority = QThread::InheritPriority); void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority = QThread::InheritPriority); +class ConditionalGuard { +public: + void trigger() { + QMutexLocker locker(&_mutex); + _triggered = true; + _condition.wakeAll(); + } + + bool wait(unsigned long time = ULONG_MAX) { + QMutexLocker locker(&_mutex); + if (!_triggered) { + _condition.wait(&_mutex, time); + } + return _triggered; + } +private: + QMutex _mutex; + QWaitCondition _condition; + bool _triggered { false }; +}; + #endif diff --git a/libraries/shared/src/shared/QtHelpers.cpp b/libraries/shared/src/shared/QtHelpers.cpp new file mode 100644 index 0000000000..1ce1c3e07c --- /dev/null +++ b/libraries/shared/src/shared/QtHelpers.cpp @@ -0,0 +1,58 @@ +// +// Created by Bradley Austin Davis on 2015/11/09 +// Copyright 2013-2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QtHelpers.h" + +#include +#include +#include + +Q_LOGGING_CATEGORY(thread_safety, "hifi.thread_safety") + +namespace hifi { namespace qt { + +bool blockingInvokeMethod( + const char* function, + QObject *obj, const char *member, + QGenericReturnArgument ret, + QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) { + if (QThread::currentThread() == qApp->thread()) { + qCWarning(thread_safety) << "BlockingQueuedConnection invoked on main thread from " << function; + } + return QMetaObject::invokeMethod(obj, member, + Qt::BlockingQueuedConnection, ret, val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); +} + +bool blockingInvokeMethod( + const char* function, + QObject *obj, const char *member, + QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) { + return blockingInvokeMethod(function, obj, member, QGenericReturnArgument(), val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); +} + + + +} } diff --git a/libraries/shared/src/shared/QtHelpers.h b/libraries/shared/src/shared/QtHelpers.h new file mode 100644 index 0000000000..5da65a378f --- /dev/null +++ b/libraries/shared/src/shared/QtHelpers.h @@ -0,0 +1,52 @@ +// +// Created by Bradley Austin Davis on 2017/06/29 +// Copyright 2013-2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_Shared_QtHelpers_h +#define hifi_Shared_QtHelpers_h + +#include + + +namespace hifi { namespace qt { + +bool blockingInvokeMethod( + const char* function, + QObject *obj, const char *member, + QGenericReturnArgument ret, + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()); + +bool blockingInvokeMethod( + const char* function, + QObject *obj, const char *member, + QGenericArgument val0 = QGenericArgument(Q_NULLPTR), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()); + +} } + +#define BLOCKING_INVOKE_METHOD(obj, member, ...) \ + hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__) + +#endif diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 76a8a780b9..135729653e 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -249,7 +250,7 @@ int OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) { QMessageBox::StandardButton OffscreenUi::messageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { if (QThread::currentThread() != thread()) { QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; - QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "messageBox", Q_RETURN_ARG(QMessageBox::StandardButton, result), Q_ARG(Icon, icon), Q_ARG(QString, title), @@ -351,7 +352,7 @@ QVariant OffscreenUi::getCustomInfo(const Icon icon, const QString& title, const QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { QVariant result; - QMetaObject::invokeMethod(this, "inputDialog", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "inputDialog", Q_RETURN_ARG(QVariant, result), Q_ARG(Icon, icon), Q_ARG(QString, title), @@ -366,7 +367,7 @@ QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const Q QVariant OffscreenUi::customInputDialog(const Icon icon, const QString& title, const QVariantMap& config) { if (QThread::currentThread() != thread()) { QVariant result; - QMetaObject::invokeMethod(this, "customInputDialog", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "customInputDialog", Q_RETURN_ARG(QVariant, result), Q_ARG(Icon, icon), Q_ARG(QString, title), @@ -640,7 +641,7 @@ QString OffscreenUi::fileDialog(const QVariantMap& properties) { QString OffscreenUi::fileOpenDialog(const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { if (QThread::currentThread() != thread()) { QString result; - QMetaObject::invokeMethod(this, "fileOpenDialog", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "fileOpenDialog", Q_RETURN_ARG(QString, result), Q_ARG(QString, caption), Q_ARG(QString, dir), @@ -662,7 +663,7 @@ QString OffscreenUi::fileOpenDialog(const QString& caption, const QString& dir, QString OffscreenUi::fileSaveDialog(const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { if (QThread::currentThread() != thread()) { QString result; - QMetaObject::invokeMethod(this, "fileSaveDialog", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "fileSaveDialog", Q_RETURN_ARG(QString, result), Q_ARG(QString, caption), Q_ARG(QString, dir), @@ -686,7 +687,7 @@ QString OffscreenUi::fileSaveDialog(const QString& caption, const QString& dir, QString OffscreenUi::existingDirectoryDialog(const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) { if (QThread::currentThread() != thread()) { QString result; - QMetaObject::invokeMethod(this, "existingDirectoryDialog", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "existingDirectoryDialog", Q_RETURN_ARG(QString, result), Q_ARG(QString, caption), Q_ARG(QString, dir), @@ -773,7 +774,7 @@ QString OffscreenUi::assetOpenDialog(const QString& caption, const QString& dir, // ATP equivalent of fileOpenDialog(). if (QThread::currentThread() != thread()) { QString result; - QMetaObject::invokeMethod(this, "assetOpenDialog", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "assetOpenDialog", Q_RETURN_ARG(QString, result), Q_ARG(QString, caption), Q_ARG(QString, dir), diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 68bb872667..44a0af7787 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; + BLOCKING_INVOKE_METHOD(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..14d8ec8985 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()); + BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_ARG(QVariantMap, properties)); + } else { + retVal->initQml(properties); + } connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); return engine->newQObject(retVal); } @@ -90,9 +93,10 @@ QmlWindowClass::QmlWindowClass() { void QmlWindowClass::initQml(QVariantMap properties) { auto offscreenUi = DependencyManager::get(); - _toolWindow = properties.contains(TOOLWINDOW_PROPERTY) && properties[TOOLWINDOW_PROPERTY].toBool(); _source = properties[SOURCE_PROPERTY].toString(); +#if QML_TOOL_WINDOW + _toolWindow = properties.contains(TOOLWINDOW_PROPERTY) && properties[TOOLWINDOW_PROPERTY].toBool(); if (_toolWindow) { // Build the event bridge and wrapper on the main thread _qmlWindow = offscreenUi->getToolWindow(); @@ -103,10 +107,11 @@ void QmlWindowClass::initQml(QVariantMap properties) { Q_ARG(QVariant, QVariant::fromValue(properties))); Q_ASSERT(invokeResult); } else { +#endif // Build the event bridge and wrapper on the main thread offscreenUi->loadInNewContext(qmlSource(), [&](QQmlContext* context, QObject* object) { _qmlWindow = object; - context->setContextProperty("eventBridge", this); + context->setContextProperty(EVENT_BRIDGE_PROPERTY, this); context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); context->engine()->setObjectOwnership(object, QQmlEngine::CppOwnership); if (properties.contains(TITLE_PROPERTY)) { @@ -133,7 +138,9 @@ void QmlWindowClass::initQml(QVariantMap properties) { connect(_qmlWindow, SIGNAL(moved(QVector2D)), this, SLOT(hasMoved(QVector2D)), Qt::QueuedConnection); connect(_qmlWindow, SIGNAL(windowClosed()), this, SLOT(hasClosed()), Qt::QueuedConnection); }); +#if QML_TOOL_WINDOW } +#endif Q_ASSERT(_qmlWindow); Q_ASSERT(dynamic_cast(_qmlWindow.data())); } @@ -207,56 +214,77 @@ QmlWindowClass::~QmlWindowClass() { } QQuickItem* QmlWindowClass::asQuickItem() const { +#if QML_TOOL_WINDOW if (_toolWindow) { return DependencyManager::get()->getToolWindow(); } +#endif return _qmlWindow.isNull() ? nullptr : dynamic_cast(_qmlWindow.data()); } void QmlWindowClass::setVisible(bool visible) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setVisible", Q_ARG(bool, visible)); + return; + } + QQuickItem* targetWindow = asQuickItem(); +#if QML_TOOL_WINDOW 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); - }); + return; + } +#endif + targetWindow->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible); +} + +bool QmlWindowClass::isVisible() { + if (QThread::currentThread() != thread()) { + bool result = false; + BLOCKING_INVOKE_METHOD(this, "isVisible", Q_RETURN_ARG(bool, result)); + return result; } -} -bool QmlWindowClass::isVisible() const { // 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 QML_TOOL_WINDOW + if (_toolWindow) { + return dynamic_cast(_qmlWindow.data())->isEnabled(); + } +#endif + + 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; + BLOCKING_INVOKE_METHOD(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 +296,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; + BLOCKING_INVOKE_METHOD(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 +326,37 @@ 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 QML_TOOL_WINDOW + 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; + } +#endif + + if (_qmlWindow) { + _qmlWindow->deleteLater(); + } + _qmlWindow = nullptr; } void QmlWindowClass::hasMoved(QVector2D position) { @@ -325,10 +368,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..e01bc8f14b 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -19,6 +19,8 @@ class QScriptEngine; class QScriptContext; +#define QML_TOOL_WINDOW 0 + // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping class QmlWindowClass : public QObject { Q_OBJECT @@ -31,18 +33,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); @@ -85,9 +87,12 @@ protected: virtual QString qmlSource() const { return "QmlWindow.qml"; } +#if QML_TOOL_WINDOW // FIXME needs to be initialized in the ctor once we have support // for tool window panes in QML bool _toolWindow { false }; +#endif + QPointer _qmlWindow; QString _source; diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 7511448c38..4e61eba28f 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -13,12 +13,12 @@ #include #include +#include #include "../VrMenu.h" #include "../OffscreenUi.h" #include "Logging.h" - using namespace ui; static QList groups; @@ -246,7 +246,7 @@ void Menu::removeAction(MenuWrapper* menu, const QString& actionName) { void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "setIsOptionChecked", Qt::BlockingQueuedConnection, + BLOCKING_INVOKE_METHOD(this, "setIsOptionChecked", Q_ARG(const QString&, menuOption), Q_ARG(bool, isChecked)); return; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 648bdad1bf..19cd37a6cb 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -34,7 +36,6 @@ #include #include #include -#include #include #include @@ -886,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; - QMetaObject::invokeMethod(this, "returnFromUiThread", Qt::BlockingQueuedConnection, - 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/QmlWrapper.cpp b/libraries/ui/src/ui/QmlWrapper.cpp index 518a05613a..3879e1bc8f 100644 --- a/libraries/ui/src/ui/QmlWrapper.cpp +++ b/libraries/ui/src/ui/QmlWrapper.cpp @@ -11,6 +11,8 @@ #include #include +#include + QmlWrapper::QmlWrapper(QObject* qmlObject, QObject* parent) : QObject(parent), _qmlObject(qmlObject) { Q_ASSERT(QThread::currentThread() == qApp->thread()); @@ -36,7 +38,7 @@ void QmlWrapper::writeProperties(QVariant propertyMap) { QVariant QmlWrapper::readProperty(const QString& propertyName) { if (QThread::currentThread() != thread()) { QVariant result; - QMetaObject::invokeMethod(this, "readProperty", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, result), Q_ARG(QString, propertyName)); + BLOCKING_INVOKE_METHOD(this, "readProperty", Q_RETURN_ARG(QVariant, result), Q_ARG(QString, propertyName)); return result; } @@ -46,7 +48,7 @@ QVariant QmlWrapper::readProperty(const QString& propertyName) { QVariant QmlWrapper::readProperties(const QVariant& propertyList) { if (QThread::currentThread() != thread()) { QVariant result; - QMetaObject::invokeMethod(this, "readProperties", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, propertyList)); + BLOCKING_INVOKE_METHOD(this, "readProperties", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, propertyList)); return result; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 1e426dd8f0..857cae15cc 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,7 @@ ToolbarProxy* TabletScriptingInterface::getSystemToolbarProxy() { TabletProxy* TabletScriptingInterface::getTablet(const QString& tabletId) { TabletProxy* tabletProxy = nullptr; if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "getTablet", Qt::BlockingQueuedConnection, Q_RETURN_ARG(TabletProxy*, tabletProxy), Q_ARG(QString, tabletId)); + BLOCKING_INVOKE_METHOD(this, "getTablet", Q_RETURN_ARG(TabletProxy*, tabletProxy), Q_ARG(QString, tabletId)); return tabletProxy; } @@ -213,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(); @@ -292,7 +291,7 @@ void TabletProxy::initialScreen(const QVariant& url) { bool TabletProxy::isMessageDialogOpen() { if (QThread::currentThread() != thread()) { bool result = false; - QMetaObject::invokeMethod(this, "isMessageDialogOpen", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); + BLOCKING_INVOKE_METHOD(this, "isMessageDialogOpen", Q_RETURN_ARG(bool, result)); return result; } @@ -317,7 +316,7 @@ void TabletProxy::emitWebEvent(const QVariant& msg) { bool TabletProxy::isPathLoaded(const QVariant& path) { if (QThread::currentThread() != thread()) { bool result = false; - QMetaObject::invokeMethod(this, "isPathLoaded", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result), Q_ARG(QVariant, path)); + BLOCKING_INVOKE_METHOD(this, "isPathLoaded", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, path)); return result; } @@ -480,7 +479,7 @@ void TabletProxy::loadQMLSource(const QVariant& path) { bool TabletProxy::pushOntoStack(const QVariant& path) { if (QThread::currentThread() != thread()) { bool result = false; - QMetaObject::invokeMethod(this, "pushOntoStack", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result), Q_ARG(QVariant, path)); + BLOCKING_INVOKE_METHOD(this, "pushOntoStack", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, path)); return result; } @@ -606,7 +605,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { if (QThread::currentThread() != thread()) { TabletButtonProxy* result = nullptr; - QMetaObject::invokeMethod(this, "addButton", Qt::BlockingQueuedConnection, Q_RETURN_ARG(TabletButtonProxy*, result), Q_ARG(QVariant, properties)); + BLOCKING_INVOKE_METHOD(this, "addButton", Q_RETURN_ARG(TabletButtonProxy*, result), Q_ARG(QVariant, properties)); return result; } @@ -633,7 +632,7 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { bool TabletProxy::onHomeScreen() { if (QThread::currentThread() != thread()) { bool result = false; - QMetaObject::invokeMethod(this, "onHomeScreen", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); + BLOCKING_INVOKE_METHOD(this, "onHomeScreen", Q_RETURN_ARG(bool, result)); return result; } @@ -840,7 +839,7 @@ void TabletButtonProxy::setToolbarButtonProxy(QObject* toolbarButtonProxy) { QVariantMap TabletButtonProxy::getProperties() { if (QThread::currentThread() != thread()) { QVariantMap result; - QMetaObject::invokeMethod(this, "getProperties", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariantMap, result)); + BLOCKING_INVOKE_METHOD(this, "getProperties", Q_RETURN_ARG(QVariantMap, result)); return result; } diff --git a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp index 330c652cdc..d01b538004 100644 --- a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp +++ b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp @@ -12,6 +12,8 @@ #include #include #include + +#include #include "../OffscreenUi.h" QScriptValue toolbarToScriptValue(QScriptEngine* engine, ToolbarProxy* const &in) { @@ -68,7 +70,7 @@ ToolbarProxy::ToolbarProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qml ToolbarButtonProxy* ToolbarProxy::addButton(const QVariant& properties) { if (QThread::currentThread() != thread()) { ToolbarButtonProxy* result = nullptr; - QMetaObject::invokeMethod(this, "addButton", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ToolbarButtonProxy*, result), Q_ARG(QVariant, properties)); + BLOCKING_INVOKE_METHOD(this, "addButton", Q_RETURN_ARG(ToolbarButtonProxy*, result), Q_ARG(QVariant, properties)); return result; } @@ -99,18 +101,14 @@ void ToolbarProxy::removeButton(const QVariant& name) { ToolbarProxy* ToolbarScriptingInterface::getToolbar(const QString& toolbarId) { if (QThread::currentThread() != thread()) { ToolbarProxy* result = nullptr; - QMetaObject::invokeMethod(this, "getToolbar", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ToolbarProxy*, result), Q_ARG(QString, toolbarId)); + BLOCKING_INVOKE_METHOD(this, "getToolbar", Q_RETURN_ARG(ToolbarProxy*, result), Q_ARG(QString, toolbarId)); return result; } auto offscreenUi = DependencyManager::get(); auto desktop = offscreenUi->getDesktop(); - Qt::ConnectionType connectionType = Qt::AutoConnection; - if (QThread::currentThread() != desktop->thread()) { - connectionType = Qt::BlockingQueuedConnection; - } QVariant resultVar; - bool invokeResult = QMetaObject::invokeMethod(desktop, "getToolbar", connectionType, Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, toolbarId)); + bool invokeResult = QMetaObject::invokeMethod(desktop, "getToolbar", Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, toolbarId)); if (!invokeResult) { return nullptr; }