mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge remote-tracking branch 'hifi/master' into android_friends_main
This commit is contained in:
commit
efdafc2a8f
54 changed files with 688 additions and 389 deletions
|
@ -827,10 +827,6 @@ void Agent::processAgentAvatarAudio() {
|
|||
void Agent::aboutToFinish() {
|
||||
setIsAvatar(false);// will stop timers for sending identity packets
|
||||
|
||||
if (_scriptEngine) {
|
||||
_scriptEngine->stop();
|
||||
}
|
||||
|
||||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||
|
||||
|
@ -843,7 +839,6 @@ void Agent::aboutToFinish() {
|
|||
|
||||
// destroy all other created dependencies
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
|
||||
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||
DependencyManager::destroy<SoundCacheScriptingInterface>();
|
||||
|
@ -862,3 +857,11 @@ void Agent::aboutToFinish() {
|
|||
_encoder = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::stop() {
|
||||
if (_scriptEngine) {
|
||||
_scriptEngine->stop();
|
||||
} else {
|
||||
setFinished(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,8 @@ public slots:
|
|||
void setIsAvatar(bool isAvatar);
|
||||
bool isAvatar() const { return _isAvatar; }
|
||||
|
||||
Q_INVOKABLE virtual void stop() override;
|
||||
|
||||
private slots:
|
||||
void requestScript();
|
||||
void scriptRequestFinished();
|
||||
|
|
|
@ -46,6 +46,14 @@
|
|||
"default": "40102",
|
||||
"type": "int",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "enable_packet_verification",
|
||||
"label": "Enable Packet Verification",
|
||||
"help": "Enable secure checksums on communication that uses the High Fidelity protocol. Increases security with possibly a small performance penalty.",
|
||||
"default": true,
|
||||
"type": "checkbox",
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -630,6 +630,7 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) {
|
|||
|
||||
void DomainServer::setupNodeListAndAssignments() {
|
||||
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
||||
static const QString ENABLE_PACKET_AUTHENTICATION = "metaverse.enable_packet_verification";
|
||||
|
||||
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
||||
int domainServerPort = localPortValue.toInt();
|
||||
|
@ -696,6 +697,9 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
}
|
||||
}
|
||||
|
||||
bool isAuthEnabled = _settingsManager.valueOrDefaultValueForKeyPath(ENABLE_PACKET_AUTHENTICATION).toBool();
|
||||
nodeList->setAuthenticatePackets(isAuthEnabled);
|
||||
|
||||
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
||||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
||||
|
||||
|
@ -1133,7 +1137,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
extendedHeaderStream << node->getUUID();
|
||||
extendedHeaderStream << node->getLocalID();
|
||||
extendedHeaderStream << node->getPermissions();
|
||||
|
||||
extendedHeaderStream << limitedNodeList->getAuthenticatePackets();
|
||||
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
||||
|
||||
// always send the node their own UUID back
|
||||
|
|
|
@ -62,6 +62,7 @@ Windows.ScrollingWindow {
|
|||
url: "about:blank"
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ Item {
|
|||
anchors.fill: stackView
|
||||
id: controllerPrefereneces
|
||||
objectName: "TabletControllerPreferences"
|
||||
showCategories: [( (HMD.active) ? "VR Movement" : "Movement"), "Game Controller", "Sixense Controllers", "Perception Neuron", "Leap Motion"]
|
||||
showCategories: ["VR Movement", "Game Controller", "Sixense Controllers", "Perception Neuron", "Leap Motion"]
|
||||
categoryProperties: {
|
||||
"VR Movement" : {
|
||||
"User real-world height (meters)" : { "anchors.right" : "undefined" },
|
||||
|
|
|
@ -6619,11 +6619,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
bool clientScript = scriptEngine->isClientScript();
|
||||
scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor);
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor);
|
||||
#endif
|
||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
||||
scriptEngine->registerFunction("QmlFragment", QmlFragmentClass::constructor);
|
||||
scriptEngine->registerFunction("QmlFragment", clientScript ? QmlFragmentClass::constructor : QmlFragmentClass::restricted_constructor);
|
||||
|
||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
|
||||
|
|
|
@ -412,9 +412,6 @@ void AvatarManager::clearOtherAvatars() {
|
|||
while (avatarIterator != _avatarHash.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
||||
if (avatar != _myAvatar) {
|
||||
if (avatar->isInScene()) {
|
||||
avatar->removeFromScene(avatar, scene, transaction);
|
||||
}
|
||||
handleRemovedAvatar(avatar);
|
||||
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||
} else {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
assert(_avatar);
|
||||
_type = MOTIONSTATE_TYPE_AVATAR;
|
||||
cacheShapeDiameter();
|
||||
}
|
||||
|
||||
void AvatarMotionState::handleEasyChanges(uint32_t& flags) {
|
||||
|
@ -57,9 +58,6 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const {
|
|||
const btCollisionShape* AvatarMotionState::computeNewShape() {
|
||||
ShapeInfo shapeInfo;
|
||||
std::static_pointer_cast<Avatar>(_avatar)->computeShapeInfo(shapeInfo);
|
||||
glm::vec3 halfExtents = shapeInfo.getHalfExtents();
|
||||
halfExtents.y = 0.0f;
|
||||
_diameter = 2.0f * glm::length(halfExtents);
|
||||
return getShapeManager()->getShape(shapeInfo);
|
||||
}
|
||||
|
||||
|
@ -98,6 +96,10 @@ void AvatarMotionState::setWorldTransform(const btTransform& worldTrans) {
|
|||
btVector3 velocity = glmToBullet(getObjectLinearVelocity()) + (1.0f / SPRING_TIMESCALE) * offsetToTarget;
|
||||
_body->setLinearVelocity(velocity);
|
||||
_body->setAngularVelocity(glmToBullet(getObjectAngularVelocity()));
|
||||
// slam its rotation
|
||||
btTransform newTransform = worldTrans;
|
||||
newTransform.setRotation(glmToBullet(getObjectRotation()));
|
||||
_body->setWorldTransform(newTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +143,10 @@ glm::vec3 AvatarMotionState::getObjectLinearVelocity() const {
|
|||
|
||||
// virtual
|
||||
glm::vec3 AvatarMotionState::getObjectAngularVelocity() const {
|
||||
return _avatar->getWorldAngularVelocity();
|
||||
// HACK: avatars use a capusle collision shape and their angularVelocity in the local simulation is unimportant.
|
||||
// Therefore, as optimization toward support for larger crowds we ignore it and return zero.
|
||||
//return _avatar->getWorldAngularVelocity();
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
@ -174,3 +179,28 @@ float AvatarMotionState::getMass() const {
|
|||
return std::static_pointer_cast<Avatar>(_avatar)->computeMass();
|
||||
}
|
||||
|
||||
void AvatarMotionState::cacheShapeDiameter() {
|
||||
if (_shape) {
|
||||
// shape is capsuleY
|
||||
btVector3 aabbMin, aabbMax;
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
_shape->getAabb(transform, aabbMin, aabbMax);
|
||||
_diameter = (aabbMax - aabbMin).getX();
|
||||
} else {
|
||||
_diameter = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMotionState::setRigidBody(btRigidBody* body) {
|
||||
ObjectMotionState::setRigidBody(body);
|
||||
if (_body) {
|
||||
// remove angular dynamics from this body
|
||||
_body->setAngularFactor(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMotionState::setShape(const btCollisionShape* shape) {
|
||||
ObjectMotionState::setShape(shape);
|
||||
cacheShapeDiameter();
|
||||
}
|
||||
|
|
|
@ -74,6 +74,10 @@ public:
|
|||
friend class Avatar;
|
||||
|
||||
protected:
|
||||
void setRigidBody(btRigidBody* body) override;
|
||||
void setShape(const btCollisionShape* shape) override;
|
||||
void cacheShapeDiameter();
|
||||
|
||||
// the dtor had been made protected to force the compiler to verify that it is only
|
||||
// ever called by the Avatar class dtor.
|
||||
~AvatarMotionState();
|
||||
|
|
|
@ -1135,7 +1135,6 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||
settings.setValue("userHeight", getUserHeight());
|
||||
settings.setValue("flyingDesktop", getFlyingDesktopPref());
|
||||
settings.setValue("flyingHMD", getFlyingHMDPref());
|
||||
|
||||
settings.endGroup();
|
||||
|
@ -1289,7 +1288,6 @@ void MyAvatar::loadData() {
|
|||
|
||||
// Flying preferences must be loaded before calling setFlyingEnabled()
|
||||
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
||||
setFlyingDesktopPref(firstRunVal.get() ? true : settings.value("flyingDesktop").toBool());
|
||||
setFlyingHMDPref(firstRunVal.get() ? false : settings.value("flyingHMD").toBool());
|
||||
setFlyingEnabled(getFlyingEnabled());
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
/**jsdoc
|
||||
* The Audio API features tools to help control audio contexts and settings.
|
||||
* The <code>Audio</code> API provides facilities to interact with audio inputs and outputs and to play sounds.
|
||||
*
|
||||
* @namespace Audio
|
||||
*
|
||||
|
@ -35,14 +35,23 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
|||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {boolean} muted
|
||||
* @property {boolean} noiseReduction
|
||||
* @property {number} inputVolume
|
||||
* @property {number} inputLevel <em>Read-only.</em>
|
||||
* @property {string} context <em>Read-only.</em>
|
||||
* @property {} devices <em>Read-only.</em>
|
||||
* @property {boolean} muted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||
* @property {boolean} noiseReduction - <code>true</code> if noise reduction is enabled, otherwise <code>false</code>. When
|
||||
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
||||
* above the noise floor.
|
||||
* @property {number} inputLevel - The loudness of the audio input, range <code>0.0</code> (no sound) –
|
||||
* <code>1.0</code> (the onset of clipping). <em>Read-only.</em>
|
||||
* @property {number} inputVolume - Adjusts the volume of the input audio; range <code>0.0</code> – <code>1.0</code>.
|
||||
* If set to a value, the resulting value depends on the input device: for example, the volume can't be changed on some
|
||||
* devices, and others might only support values of <code>0.0</code> and <code>1.0</code>.
|
||||
* @property {boolean} isStereoInput - <code>true</code> if the input audio is being used in stereo, otherwise
|
||||
* <code>false</code>. Some devices do not support stereo, in which case the value is always <code>false</code>.
|
||||
* @property {string} context - The current context of the audio: either <code>"Desktop"</code> or <code>"HMD"</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {object} devices <em>Read-only.</em> <strong>Deprecated:</strong> This property is deprecated and will be
|
||||
* removed.
|
||||
*/
|
||||
|
||||
|
||||
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
||||
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
||||
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
||||
|
@ -69,45 +78,91 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* @function Audio.setInputDevice
|
||||
* @param {} device
|
||||
* @param {object} device
|
||||
* @param {boolean} isHMD
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||
|
||||
/**jsdoc
|
||||
* @function Audio.setOutputDevice
|
||||
* @param {} device
|
||||
* @param {object} device
|
||||
* @param {boolean} isHMD
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||
|
||||
/**jsdoc
|
||||
* Enable or disable reverberation. Reverberation is done by the client, on the post-mix audio. The reverberation options
|
||||
* come from either the domain's audio zone if used — configured on the server — or as scripted by
|
||||
* {@link Audio.setReverbOptions|setReverbOptions}.
|
||||
* @function Audio.setReverb
|
||||
* @param {boolean} enable
|
||||
*/
|
||||
* @param {boolean} enable - <code>true</code> to enable reverberation, <code>false</code> to disable.
|
||||
* @example <caption>Enable reverberation for a short while.</caption>
|
||||
* var sound = SoundCache.getSound(Script.resourcesPath() + "sounds/sample.wav");
|
||||
* var injector;
|
||||
* var injectorOptions = {
|
||||
* position: MyAvatar.position
|
||||
* };
|
||||
*
|
||||
* Script.setTimeout(function () {
|
||||
* print("Reverb OFF");
|
||||
* Audio.setReverb(false);
|
||||
* injector = Audio.playSound(sound, injectorOptions);
|
||||
* }, 1000);
|
||||
*
|
||||
* Script.setTimeout(function () {
|
||||
* var reverbOptions = new AudioEffectOptions();
|
||||
* reverbOptions.roomSize = 100;
|
||||
* Audio.setReverbOptions(reverbOptions);
|
||||
* print("Reverb ON");
|
||||
* Audio.setReverb(true);
|
||||
* }, 4000);
|
||||
*
|
||||
* Script.setTimeout(function () {
|
||||
* print("Reverb OFF");
|
||||
* Audio.setReverb(false);
|
||||
* }, 8000); */
|
||||
Q_INVOKABLE void setReverb(bool enable);
|
||||
|
||||
/**jsdoc
|
||||
* Configure reverberation options. Use {@link Audio.setReverb|setReverb} to enable or disable reverberation.
|
||||
* @function Audio.setReverbOptions
|
||||
* @param {AudioEffectOptions} options
|
||||
* @param {AudioEffectOptions} options - The reverberation options.
|
||||
*/
|
||||
Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options);
|
||||
|
||||
/**jsdoc
|
||||
* Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format.
|
||||
* @function Audio.startRecording
|
||||
* @param {string} filename
|
||||
* @returns {boolean}
|
||||
* @param {string} filename - The path and name of the file to make the recording in. Should have a <code>.wav</code>
|
||||
* extension. The file is overwritten if it already exists.
|
||||
* @returns {boolean} <code>true</code> if the specified file could be opened and audio recording has started, otherwise
|
||||
* <code>false</code>.
|
||||
* @example <caption>Make a 10 second audio recording.</caption>
|
||||
* var filename = File.getTempDir() + "/audio.wav";
|
||||
* if (Audio.startRecording(filename)) {
|
||||
* Script.setTimeout(function () {
|
||||
* Audio.stopRecording();
|
||||
* print("Audio recording made in: " + filename);
|
||||
* }, 10000);
|
||||
*
|
||||
* } else {
|
||||
* print("Could not make an audio recording in: " + filename);
|
||||
* }
|
||||
*/
|
||||
Q_INVOKABLE bool startRecording(const QString& filename);
|
||||
|
||||
/**jsdoc
|
||||
* Finish making an audio recording started with {@link Audio.startRecording|startRecording}.
|
||||
* @function Audio.stopRecording
|
||||
*/
|
||||
Q_INVOKABLE void stopRecording();
|
||||
|
||||
/**jsdoc
|
||||
* Check whether an audio recording is currently being made.
|
||||
* @function Audio.getRecording
|
||||
* @returns {boolean}
|
||||
* @returns {boolean} <code>true</code> if an audio recording is currently being made, otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE bool getRecording();
|
||||
|
||||
|
@ -116,40 +171,54 @@ signals:
|
|||
/**jsdoc
|
||||
* @function Audio.nop
|
||||
* @returns {Signal}
|
||||
* @deprecated This signal is deprecated and will be removed.
|
||||
*/
|
||||
void nop();
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the audio input is muted or unmuted.
|
||||
* @function Audio.mutedChanged
|
||||
* @param {boolean} isMuted
|
||||
* @param {boolean} isMuted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||
* @returns {Signal}
|
||||
* @example <caption>Report when audio input is muted or unmuted</caption>
|
||||
* Audio.mutedChanged.connect(function (isMuted) {
|
||||
* print("Audio muted: " + isMuted);
|
||||
* });
|
||||
*/
|
||||
void mutedChanged(bool isMuted);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the audio input noise reduction is enabled or disabled.
|
||||
* @function Audio.noiseReductionChanged
|
||||
* @param {boolean} isEnabled
|
||||
* @param {boolean} isEnabled - <code>true</code> if audio input noise reduction is enabled, otherwise <code>false</code>.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void noiseReductionChanged(bool isEnabled);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the input audio volume changes.
|
||||
* @function Audio.inputVolumeChanged
|
||||
* @param {number} volume
|
||||
* @param {number} volume - The requested volume to be applied to the audio input, range <code>0.0</code> –
|
||||
* <code>1.0</code>. The resulting value of <code>Audio.inputVolume</code> depends on the capabilities of the device:
|
||||
* for example, the volume can't be changed on some devices, and others might only support values of <code>0.0</code>
|
||||
* and <code>1.0</code>.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void inputVolumeChanged(float volume);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the input audio level changes.
|
||||
* @function Audio.inputLevelChanged
|
||||
* @param {number} level
|
||||
* @param {number} level - The loudness of the input audio, range <code>0.0</code> (no sound) – <code>1.0</code> (the
|
||||
* onset of clipping).
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void inputLevelChanged(float level);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the current context of the audio changes.
|
||||
* @function Audio.contextChanged
|
||||
* @param {string} context
|
||||
* @param {string} context - The current context of the audio: either <code>"Desktop"</code> or <code>"HMD"</code>.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void contextChanged(const QString& context);
|
||||
|
@ -158,7 +227,7 @@ public slots:
|
|||
|
||||
/**jsdoc
|
||||
* @function Audio.onContextChanged
|
||||
* @returns {Signal}
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
void onContextChanged();
|
||||
|
||||
|
|
|
@ -266,42 +266,6 @@ void setupPreferences() {
|
|||
preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Deflection", getter, setter));
|
||||
}
|
||||
|
||||
static const QString MOVEMENT{ "Movement" };
|
||||
{
|
||||
|
||||
static const QString movementsControlChannel = QStringLiteral("Hifi-Advanced-Movement-Disabler");
|
||||
auto getter = [=]()->bool { return myAvatar->useAdvancedMovementControls(); };
|
||||
auto setter = [=](bool value) { myAvatar->setUseAdvancedMovementControls(value); };
|
||||
preferences->addPreference(new CheckPreference(MOVEMENT,
|
||||
QStringLiteral("Advanced movement for hand controllers"),
|
||||
getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
|
||||
auto setter = [=](int value) { myAvatar->setSnapTurn(value == 0); };
|
||||
auto preference = new RadioButtonsPreference(MOVEMENT, "Snap turn / Smooth turn", getter, setter);
|
||||
QStringList items;
|
||||
items << "Snap turn" << "Smooth turn";
|
||||
preference->setItems(items);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getUserHeight(); };
|
||||
auto setter = [=](float value) { myAvatar->setUserHeight(value); };
|
||||
auto preference = new SpinnerPreference(MOVEMENT, "User real-world height (meters)", getter, setter);
|
||||
preference->setMin(1.0f);
|
||||
preference->setMax(2.2f);
|
||||
preference->setDecimals(3);
|
||||
preference->setStep(0.001f);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto preference = new ButtonPreference(MOVEMENT, "RESET SENSORS", [] {
|
||||
qApp->resetSensors();
|
||||
});
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
static const QString VR_MOVEMENT{ "VR Movement" };
|
||||
{
|
||||
|
||||
|
@ -315,7 +279,7 @@ void setupPreferences() {
|
|||
{
|
||||
auto getter = [=]()->bool { return myAvatar->getFlyingHMDPref(); };
|
||||
auto setter = [=](bool value) { myAvatar->setFlyingHMDPref(value); };
|
||||
preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping", getter, setter));
|
||||
preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping (HMD)", getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
|
||||
|
|
|
@ -59,28 +59,29 @@ static void setOption(QScriptValue arguments, const QString name, float defaultV
|
|||
}
|
||||
|
||||
/**jsdoc
|
||||
* Reverberation options that can be used to initialize an {@link AudioEffectOptions} object when created.
|
||||
* @typedef {object} AudioEffectOptions.ReverbOptions
|
||||
* @property {number} bandwidth
|
||||
* @property {number} preDelay
|
||||
* @property {number} lateDelay
|
||||
* @property {number} reverbTime
|
||||
* @property {number} earlyDiffusion
|
||||
* @property {number} lateDiffusion
|
||||
* @property {number} roomSize
|
||||
* @property {number} density
|
||||
* @property {number} bassMult
|
||||
* @property {number} bassFreq
|
||||
* @property {number} highGain
|
||||
* @property {number} highFreq
|
||||
* @property {number} modRate
|
||||
* @property {number} modDepth
|
||||
* @property {number} earlyGain
|
||||
* @property {number} lateGain
|
||||
* @property {number} earlyMixLeft
|
||||
* @property {number} earlyMixRight
|
||||
* @property {number} lateMixLeft
|
||||
* @property {number} lateMixRight
|
||||
* @property {number} wetDryMix
|
||||
* @property {number} bandwidth=10000 - The corner frequency (Hz) of the low-pass filter at reverb input.
|
||||
* @property {number} preDelay=20 - The delay (milliseconds) between dry signal and the onset of early reflections.
|
||||
* @property {number} lateDelay=0 - The delay (milliseconds) between early reflections and the onset of reverb tail.
|
||||
* @property {number} reverbTime=2 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
|
||||
* @property {number} earlyDiffusion=100 - Adjusts the buildup of echo density in the early reflections, normally 100%.
|
||||
* @property {number} lateDiffusion=100 - Adjusts the buildup of echo density in the reverb tail, normally 100%.
|
||||
* @property {number} roomSize=50 - The apparent room size, from small (0%) to large (100%).
|
||||
* @property {number} density=100 - Adjusts the echo density in the reverb tail, normally 100%.
|
||||
* @property {number} bassMult=1.5 - Adjusts the bass-frequency reverb time, as multiple of reverbTime.
|
||||
* @property {number} bassFreq=250 - The crossover frequency (Hz) for the onset of bassMult.
|
||||
* @property {number} highGain=-6 - Reduces the high-frequency reverb time, as attenuation (dB).
|
||||
* @property {number} highFreq=3000 - The crossover frequency (Hz) for the onset of highGain.
|
||||
* @property {number} modRate=2.3 - The rate of modulation (Hz) of the LFO-modulated delay lines.
|
||||
* @property {number} modDepth=50 - The depth of modulation (percent) of the LFO-modulated delay lines.
|
||||
* @property {number} earlyGain=0 - Adjusts the relative level (dB) of the early reflections.
|
||||
* @property {number} lateGain=0 - Adjusts the relative level (dB) of the reverb tail.
|
||||
* @property {number} earlyMixLeft=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} earlyMixRight=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} lateMixLeft=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%).
|
||||
*/
|
||||
AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) {
|
||||
setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth);
|
||||
|
|
|
@ -16,35 +16,39 @@
|
|||
#include <QtScript/QScriptEngine>
|
||||
|
||||
/**jsdoc
|
||||
* Audio effect options used by the {@link Audio} API.
|
||||
*
|
||||
* <p>Create using <code>new AudioEffectOptions(reverbOptions)</code>.</p>
|
||||
*
|
||||
* @class AudioEffectOptions
|
||||
* @param {AudioEffectOptions.ReverbOptions} [reverbOptions=null]
|
||||
* @param {AudioEffectOptions.ReverbOptions} [reverbOptions=null] - Reverberation options.
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {number} bandwidth=10000
|
||||
* @property {number} preDelay=20
|
||||
* @property {number} lateDelay=0
|
||||
* @property {number} reverbTime=2
|
||||
* @property {number} earlyDiffusion=100
|
||||
* @property {number} lateDiffusion=100
|
||||
* @property {number} roomSize=50
|
||||
* @property {number} density=100
|
||||
* @property {number} bassMult=1.5
|
||||
* @property {number} bassFreq=250
|
||||
* @property {number} highGain=-6
|
||||
* @property {number} highFreq=3000
|
||||
* @property {number} modRate=2.3
|
||||
* @property {number} modDepth=50
|
||||
* @property {number} earlyGain=0
|
||||
* @property {number} lateGain=0
|
||||
* @property {number} earlyMixLeft=20
|
||||
* @property {number} earlyMixRight=20
|
||||
* @property {number} lateMixLeft=90
|
||||
* @property {number} lateMixRight=90
|
||||
* @property {number} wetDryMix=50
|
||||
* @property {number} bandwidth=10000 - The corner frequency (Hz) of the low-pass filter at reverb input.
|
||||
* @property {number} preDelay=20 - The delay (milliseconds) between dry signal and the onset of early reflections.
|
||||
* @property {number} lateDelay=0 - The delay (milliseconds) between early reflections and the onset of reverb tail.
|
||||
* @property {number} reverbTime=2 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
|
||||
* @property {number} earlyDiffusion=100 - Adjusts the buildup of echo density in the early reflections, normally 100%.
|
||||
* @property {number} lateDiffusion=100 - Adjusts the buildup of echo density in the reverb tail, normally 100%.
|
||||
* @property {number} roomSize=50 - The apparent room size, from small (0%) to large (100%).
|
||||
* @property {number} density=100 - Adjusts the echo density in the reverb tail, normally 100%.
|
||||
* @property {number} bassMult=1.5 - Adjusts the bass-frequency reverb time, as multiple of reverbTime.
|
||||
* @property {number} bassFreq=250 - The crossover frequency (Hz) for the onset of bassMult.
|
||||
* @property {number} highGain=-6 - Reduces the high-frequency reverb time, as attenuation (dB).
|
||||
* @property {number} highFreq=3000 - The crossover frequency (Hz) for the onset of highGain.
|
||||
* @property {number} modRate=2.3 - The rate of modulation (Hz) of the LFO-modulated delay lines.
|
||||
* @property {number} modDepth=50 - The depth of modulation (percent) of the LFO-modulated delay lines.
|
||||
* @property {number} earlyGain=0 - Adjusts the relative level (dB) of the early reflections.
|
||||
* @property {number} lateGain=0 - Adjusts the relative level (dB) of the reverb tail.
|
||||
* @property {number} earlyMixLeft=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} earlyMixRight=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} lateMixLeft=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%).
|
||||
*/
|
||||
|
||||
class AudioEffectOptions : public QObject {
|
||||
|
|
|
@ -45,6 +45,23 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje
|
|||
return obj;
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Configures how an audio injector plays its audio.
|
||||
* @typedef {object} AudioInjector.AudioInjectorOptions
|
||||
* @property {Vec3} position=Vec3.ZERO - The position in the domain to play the sound.
|
||||
* @property {Quat} orientation=Quat.IDENTITY - The orientation in the domain to play the sound in.
|
||||
* @property {number} volume=1.0 - Playback volume, between <code>0.0</code> and <code>1.0</code>.
|
||||
* @property {number} pitch=1.0 - Alter the pitch of the sound, within +/- 2 octaves. The value is the relative sample rate to
|
||||
* resample the sound at, range <code>0.0625</code> – <code>16.0</code>. A value of <code>0.0625</code> lowers the
|
||||
* pitch by 2 octaves; <code>1.0</code> is no change in pitch; <code>16.0</code> raises the pitch by 2 octaves.
|
||||
* @property {boolean} loop=false - If <code>true</code>, the sound is played repeatedly until playback is stopped.
|
||||
* @property {number} secondOffset=0 - Starts playback from a specified time (seconds) within the sound file, ≥
|
||||
* <code>0</code>.
|
||||
* @property {boolean} localOnly=false - IF <code>true</code>, the sound is played back locally on the client rather than to
|
||||
* others via the audio mixer.
|
||||
* @property {boolean} ignorePenumbra=false - <strong>Deprecated:</strong> This property is deprecated and will be
|
||||
* removed.
|
||||
*/
|
||||
void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) {
|
||||
if (!object.isObject()) {
|
||||
qWarning() << "Audio injector options is not an object.";
|
||||
|
|
|
@ -79,6 +79,14 @@ private:
|
|||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||
|
||||
/**jsdoc
|
||||
* An audio resource, created by {@link SoundCache.getSound}, to be played back using {@link Audio.playSound}.
|
||||
* <p>Supported formats:</p>
|
||||
* <ul>
|
||||
* <li>WAV: 16-bit uncompressed WAV at any sample rate, with 1 (mono), 2(stereo), or 4 (ambisonic) channels.</li>
|
||||
* <li>MP3: Mono or stereo, at any sample rate.</li>
|
||||
* <li>RAW: 48khz 16-bit mono or stereo. Filename must include <code>".stereo"</code> to be interpreted as stereo.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @class SoundObject
|
||||
*
|
||||
* @hifi-interface
|
||||
|
@ -86,8 +94,9 @@ typedef QSharedPointer<Sound> SharedSoundPointer;
|
|||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {boolean} downloaded
|
||||
* @property {number} duration
|
||||
* @property {boolean} downloaded - <code>true</code> if the sound has been downloaded and is ready to be played, otherwise
|
||||
* <code>false</code>.
|
||||
* @property {number} duration - The duration of the sound, in seconds.
|
||||
*/
|
||||
class SoundScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -103,6 +112,7 @@ public:
|
|||
float getDuration() { return _sound->getDuration(); }
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the sound has been downloaded and is ready to be played.
|
||||
* @function SoundObject.ready
|
||||
* @returns {Signal}
|
||||
*/
|
||||
|
|
|
@ -48,9 +48,11 @@ public:
|
|||
SoundCacheScriptingInterface();
|
||||
|
||||
/**jsdoc
|
||||
* Loads the content of an audio file into a {@link SoundObject}, ready for playback by {@link Audio.playSound}.
|
||||
* @function SoundCache.getSound
|
||||
* @param {string} url
|
||||
* @returns {SoundObject}
|
||||
* @param {string} url - The URL of the audio file to load — Web, ATP, or file. See {@link SoundObject} for supported
|
||||
* formats.
|
||||
* @returns {SoundObject} The sound ready for playback.
|
||||
*/
|
||||
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
||||
};
|
||||
|
|
|
@ -328,9 +328,10 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
|||
|
||||
if (sourceNode) {
|
||||
bool verifiedPacket = !PacketTypeEnum::getNonVerifiedPackets().contains(headerType);
|
||||
bool ignoreVerification = isDomainServer() && PacketTypeEnum::getDomainIgnoredVerificationPackets().contains(headerType);
|
||||
bool verificationEnabled = !(isDomainServer() && PacketTypeEnum::getDomainIgnoredVerificationPackets().contains(headerType))
|
||||
&& _useAuthentication;
|
||||
|
||||
if (verifiedPacket && !ignoreVerification) {
|
||||
if (verifiedPacket && verificationEnabled) {
|
||||
|
||||
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
||||
QByteArray expectedHash;
|
||||
|
@ -383,7 +384,7 @@ void LimitedNodeList::fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAut
|
|||
packet.writeSourceID(getSessionLocalID());
|
||||
}
|
||||
|
||||
if (hmacAuth
|
||||
if (_useAuthentication && hmacAuth
|
||||
&& !PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())
|
||||
&& !PacketTypeEnum::getNonVerifiedPackets().contains(packet.getType())) {
|
||||
packet.writeVerificationHash(*hmacAuth);
|
||||
|
|
|
@ -307,6 +307,8 @@ public:
|
|||
|
||||
bool isPacketVerifiedWithSource(const udt::Packet& packet, Node* sourceNode = nullptr);
|
||||
bool isPacketVerified(const udt::Packet& packet) { return isPacketVerifiedWithSource(packet); }
|
||||
void setAuthenticatePackets(bool useAuthentication) { _useAuthentication = useAuthentication; }
|
||||
bool getAuthenticatePackets() const { return _useAuthentication; }
|
||||
|
||||
static void makeSTUNRequestPacket(char* stunRequestPacket);
|
||||
|
||||
|
@ -394,6 +396,7 @@ protected:
|
|||
HifiSockAddr _publicSockAddr;
|
||||
HifiSockAddr _stunSockAddr { STUN_SERVER_HOSTNAME, STUN_SERVER_PORT };
|
||||
bool _hasTCPCheckedLocalSocket { false };
|
||||
bool _useAuthentication { true };
|
||||
|
||||
PacketReceiver* _packetReceiver;
|
||||
|
||||
|
|
|
@ -665,6 +665,10 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
NodePermissions newPermissions;
|
||||
packetStream >> newPermissions;
|
||||
setPermissions(newPermissions);
|
||||
// Is packet authentication enabled?
|
||||
bool isAuthenticated;
|
||||
packetStream >> isAuthenticated;
|
||||
setAuthenticatePackets(isAuthenticated);
|
||||
|
||||
// pull each node in the packet
|
||||
while (packetStream.device()->pos() < message->getSize()) {
|
||||
|
|
|
@ -120,7 +120,7 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
|||
if (_numQueuedCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||
qCDebug(networking) << "At least" << MAX_SILENT_DOMAIN_SERVER_CHECK_INS << "have been queued without a response from domain-server"
|
||||
<< "Stopping the current assignment";
|
||||
setFinished(true);
|
||||
stop();
|
||||
} else {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QMetaObject::invokeMethod(nodeList.data(), "sendDomainServerCheckIn");
|
||||
|
@ -132,5 +132,5 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
|||
|
||||
void ThreadedAssignment::domainSettingsRequestFailed() {
|
||||
qCDebug(networking) << "Failed to retreive settings object from domain-server. Bailing on assignment.";
|
||||
setFinished(true);
|
||||
stop();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ public:
|
|||
ThreadedAssignment(ReceivedMessage& message);
|
||||
~ThreadedAssignment() { stop(); }
|
||||
|
||||
void setFinished(bool isFinished);
|
||||
virtual void aboutToFinish() { };
|
||||
void addPacketStatsAndSendStatsPacket(QJsonObject statsObject);
|
||||
|
||||
|
@ -43,6 +42,7 @@ signals:
|
|||
|
||||
protected:
|
||||
void commonInit(const QString& targetName, NodeType_t nodeType);
|
||||
void setFinished(bool isFinished);
|
||||
|
||||
bool _isFinished;
|
||||
QTimer _domainServerTimer;
|
||||
|
|
|
@ -27,7 +27,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::StunResponse:
|
||||
return 17;
|
||||
case PacketType::DomainList:
|
||||
return static_cast<PacketVersion>(DomainListVersion::GetMachineFingerprintFromUUIDSupport);
|
||||
return static_cast<PacketVersion>(DomainListVersion::AuthenticationOptional);
|
||||
case PacketType::EntityAdd:
|
||||
case PacketType::EntityClone:
|
||||
case PacketType::EntityEdit:
|
||||
|
|
|
@ -315,7 +315,8 @@ enum class DomainListVersion : PacketVersion {
|
|||
PrePermissionsGrid = 18,
|
||||
PermissionsGrid,
|
||||
GetUsernameFromUUIDSupport,
|
||||
GetMachineFingerprintFromUUIDSupport
|
||||
GetMachineFingerprintFromUUIDSupport,
|
||||
AuthenticationOptional
|
||||
};
|
||||
|
||||
enum class AudioVersion : PacketVersion {
|
||||
|
|
|
@ -64,9 +64,9 @@ ShapeManager* ObjectMotionState::getShapeManager() {
|
|||
}
|
||||
|
||||
ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) :
|
||||
_shape(shape),
|
||||
_lastKinematicStep(worldSimulationStep)
|
||||
{
|
||||
setShape(shape);
|
||||
}
|
||||
|
||||
ObjectMotionState::~ObjectMotionState() {
|
||||
|
|
|
@ -175,13 +175,13 @@ protected:
|
|||
virtual void setMotionType(PhysicsMotionType motionType);
|
||||
void updateCCDConfiguration();
|
||||
|
||||
void setRigidBody(btRigidBody* body);
|
||||
virtual void setRigidBody(btRigidBody* body);
|
||||
virtual void setShape(const btCollisionShape* shape);
|
||||
|
||||
MotionStateType _type { MOTIONSTATE_TYPE_INVALID }; // type of MotionState
|
||||
PhysicsMotionType _motionType { MOTION_TYPE_STATIC }; // type of motion: KINEMATIC, DYNAMIC, or STATIC
|
||||
|
||||
const btCollisionShape* _shape;
|
||||
const btCollisionShape* _shape { nullptr };
|
||||
btRigidBody* _body { nullptr };
|
||||
float _density { 1.0f };
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ static QSize clampSize(const QSize& qsize, uint32_t maxDimension) {
|
|||
return fromGlm(clampSize(toGlm(qsize), maxDimension));
|
||||
}
|
||||
|
||||
const QmlContextObjectCallback OffscreenSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QQuickItem*) {};
|
||||
const QmlContextObjectCallback OffscreenSurface::DEFAULT_CONTEXT_OBJECT_CALLBACK = [](QQmlContext*, QQuickItem*) {};
|
||||
const QmlContextCallback OffscreenSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*) {};
|
||||
|
||||
void OffscreenSurface::initializeEngine(QQmlEngine* engine) {
|
||||
}
|
||||
|
@ -266,8 +267,8 @@ void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const
|
|||
loadInternal(qmlSource, createNewContext, nullptr, callback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback) {
|
||||
load(qmlSource, true, callback);
|
||||
void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) {
|
||||
loadInternal(qmlSource, true, nullptr, callback, contextCallback);
|
||||
}
|
||||
|
||||
void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) {
|
||||
|
@ -281,7 +282,8 @@ void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObject
|
|||
void OffscreenSurface::loadInternal(const QUrl& qmlSource,
|
||||
bool createNewContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& callback) {
|
||||
const QmlContextObjectCallback& callback,
|
||||
const QmlContextCallback& contextCallback) {
|
||||
PROFILE_RANGE_EX(app, "OffscreenSurface::loadInternal", 0xffff00ff, 0, { std::make_pair("url", qmlSource.toDisplayString()) });
|
||||
if (QThread::currentThread() != thread()) {
|
||||
qFatal("Called load on a non-surface thread");
|
||||
|
@ -310,6 +312,7 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource,
|
|||
}
|
||||
|
||||
auto targetContext = contextForUrl(finalQmlSource, parent, createNewContext);
|
||||
contextCallback(targetContext);
|
||||
QQmlComponent* qmlComponent;
|
||||
{
|
||||
PROFILE_RANGE(app, "new QQmlComponent");
|
||||
|
|
|
@ -37,13 +37,15 @@ namespace impl {
|
|||
class SharedObject;
|
||||
}
|
||||
|
||||
using QmlContextCallback = ::std::function<void(QQmlContext*)>;
|
||||
using QmlContextObjectCallback = ::std::function<void(QQmlContext*, QQuickItem*)>;
|
||||
|
||||
class OffscreenSurface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const QmlContextObjectCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
static const QmlContextObjectCallback DEFAULT_CONTEXT_OBJECT_CALLBACK;
|
||||
static const QmlContextCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
|
||||
using TextureAndFence = std::pair<uint32_t, void*>;
|
||||
using MouseTranslator = std::function<QPoint(const QPointF&)>;
|
||||
|
@ -85,10 +87,15 @@ public:
|
|||
Q_INVOKABLE void load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback);
|
||||
|
||||
// For use from C++
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource,
|
||||
bool createNewContext,
|
||||
const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile,
|
||||
const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource,
|
||||
const QmlContextObjectCallback& callback = DEFAULT_CONTEXT_OBJECT_CALLBACK,
|
||||
const QmlContextCallback& contextCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
|
||||
public slots:
|
||||
virtual void onFocusObjectChanged(QObject* newFocus) {}
|
||||
|
@ -103,19 +110,21 @@ protected:
|
|||
|
||||
virtual void initializeEngine(QQmlEngine* engine);
|
||||
virtual void loadInternal(const QUrl& qmlSource,
|
||||
bool createNewContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& callback) final;
|
||||
bool createNewContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& callback,
|
||||
const QmlContextCallback& contextCallback = DEFAULT_CONTEXT_CALLBACK) final;
|
||||
virtual void finishQmlLoad(QQmlComponent* qmlComponent,
|
||||
QQmlContext* qmlContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& onQmlLoadedCallback) final;
|
||||
QQmlContext* qmlContext,
|
||||
QQuickItem* parent,
|
||||
const QmlContextObjectCallback& onQmlLoadedCallback) final;
|
||||
|
||||
virtual void onRootCreated() {}
|
||||
virtual void onItemCreated(QQmlContext* context, QQuickItem* newItem) {}
|
||||
virtual void onRootContextCreated(QQmlContext* qmlContext) {}
|
||||
|
||||
virtual QQmlContext* contextForUrl(const QUrl& qmlSource, QQuickItem* parent, bool forceNewContext);
|
||||
|
||||
private:
|
||||
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } };
|
||||
friend class hifi::qml::impl::SharedObject;
|
||||
|
|
|
@ -23,6 +23,7 @@ class AudioScriptingInterface : public QObject, public Dependency {
|
|||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
// JSDoc for property is in Audio.h.
|
||||
Q_PROPERTY(bool isStereoInput READ isStereoInput WRITE setStereoInput NOTIFY isStereoInputChanged)
|
||||
|
||||
public:
|
||||
|
@ -35,91 +36,121 @@ protected:
|
|||
// these methods are protected to stop C++ callers from calling, but invokable from script
|
||||
|
||||
/**jsdoc
|
||||
* Starts playing — "injecting" — the content of an audio file. The sound is played globally (sent to the audio
|
||||
* mixer) so that everyone hears it, unless the <code>injectorOptions</code> has <code>localOnly</code> set to
|
||||
* <code>true</code> in which case only the client hears the sound played. No sound is played if sent to the audio mixer
|
||||
* but the client is not connected to an audio mixer. The {@link AudioInjector} object returned by the function can be used
|
||||
* to control the playback and get information about its current state.
|
||||
* @function Audio.playSound
|
||||
* @param {} sound
|
||||
* @param {} [injectorOptions=null]
|
||||
* @returns {object}
|
||||
* @param {SoundObject} sound - The content of an audio file, loaded using {@link SoundCache.getSound}. See
|
||||
* {@link SoundObject} for supported formats.
|
||||
* @param {AudioInjector.AudioInjectorOptions} [injectorOptions={}] - Audio injector configuration.
|
||||
* @returns {AudioInjector} The audio injector that plays the audio file.
|
||||
* @example <caption>Play a sound.</caption>
|
||||
* var sound = SoundCache.getSound(Script.resourcesPath() + "sounds/sample.wav");
|
||||
* var injector;
|
||||
* var injectorOptions = {
|
||||
* position: MyAvatar.position
|
||||
* };
|
||||
*
|
||||
* Script.setTimeout(function () { // Give the sound time to load.
|
||||
* injector = Audio.playSound(sound, injectorOptions);
|
||||
* }, 1000);
|
||||
*/
|
||||
Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||
|
||||
/**jsdoc
|
||||
* Start playing the content of an audio file, locally (isn't sent to the audio mixer). This is the same as calling
|
||||
* {@link Audio.playSound} with {@link AudioInjector.AudioInjectorOptions} <code>localOnly</code> set <code>true</code> and
|
||||
* the specified <code>position</code>.
|
||||
* @function Audio.playSystemSound
|
||||
* @param {} sound
|
||||
* @param {} position
|
||||
* @returns {object}
|
||||
* @param {SoundObject} sound - The content of an audio file, loaded using {@link SoundCache.getSound}. See
|
||||
* {@link SoundObject} for supported formats.
|
||||
* @param {Vec3} position - The position in the domain to play the sound.
|
||||
* @returns {AudioInjector} The audio injector that plays the audio file.
|
||||
*/
|
||||
// FIXME: there is no way to play a positionless sound
|
||||
Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound, const QVector3D& position);
|
||||
|
||||
/**jsdoc
|
||||
* Set whether or not the audio input should be used in stereo. If the audio input does not support stereo then setting a
|
||||
* value of <code>true</code> has no effect.
|
||||
* @function Audio.setStereoInput
|
||||
* @param {boolean} stereo
|
||||
* @param {boolean} stereo - <code>true</code> if the audio input should be used in stereo, otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE void setStereoInput(bool stereo);
|
||||
|
||||
/**jsdoc
|
||||
* Get whether or not the audio input is used in stereo.
|
||||
* @function Audio.isStereoInput
|
||||
* @returns {boolean}
|
||||
* @returns {boolean} <code>true</code> if the audio input is used in stereo, otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE bool isStereoInput();
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
* The client has been muted by the mixer.
|
||||
* Triggered when the client is muted by the mixer because their loudness value for the noise background has reached the
|
||||
* threshold set for the domain in the server settings.
|
||||
* @function Audio.mutedByMixer
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void mutedByMixer();
|
||||
|
||||
/**jsdoc
|
||||
* The entire environment has been muted by the mixer.
|
||||
* Triggered when the client is muted by the mixer because they're within a certain radius (50m) of someone who requested
|
||||
* the mute through Developer > Audio > Mute Environment.
|
||||
* @function Audio.environmentMuted
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void environmentMuted();
|
||||
|
||||
/**jsdoc
|
||||
* The client has received its first packet from the audio mixer.
|
||||
* Triggered when the client receives its first packet from the audio mixer.
|
||||
* @function Audio.receivedFirstPacket
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void receivedFirstPacket();
|
||||
|
||||
/**jsdoc
|
||||
* The client has been disconnected from the audio mixer.
|
||||
* Triggered when the client is disconnected from the audio mixer.
|
||||
* @function Audio.disconnected
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void disconnected();
|
||||
|
||||
/**jsdoc
|
||||
* The noise gate has opened.
|
||||
* Triggered when the noise gate is opened: the input audio signal is no longer blocked (fully attenuated) because it has
|
||||
* risen above an adaptive threshold set just above the noise floor. Only occurs if <code>Audio.noiseReduction</code> is
|
||||
* <code>true</code>.
|
||||
* @function Audio.noiseGateOpened
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void noiseGateOpened();
|
||||
|
||||
/**jsdoc
|
||||
* The noise gate has closed.
|
||||
* Triggered when the noise gate is closed: the input audio signal is blocked (fully attenuated) because it has fallen
|
||||
* below an adaptive threshold set just above the noise floor. Only occurs if <code>Audio.noiseReduction</code> is
|
||||
* <code>true</code>.
|
||||
* @function Audio.noiseGateClosed
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void noiseGateClosed();
|
||||
|
||||
/**jsdoc
|
||||
* A frame of mic input audio has been received and processed.
|
||||
* Triggered when a frame of audio input is processed.
|
||||
* @function Audio.inputReceived
|
||||
* @param {} inputSamples
|
||||
* @param {Int16Array} inputSamples - The audio input processed.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void inputReceived(const QByteArray& inputSamples);
|
||||
|
||||
/**jsdoc
|
||||
* @function Audio.isStereoInputChanged
|
||||
* @param {boolean} isStereo
|
||||
* @returns {Signal}
|
||||
*/
|
||||
* Triggered when the input audio use changes between mono and stereo.
|
||||
* @function Audio.isStereoInputChanged
|
||||
* @param {boolean} isStereo - <code>true</code> if the input audio is stereo, otherwise <code>false</code>.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void isStereoInputChanged(bool isStereo);
|
||||
|
||||
private:
|
||||
|
|
|
@ -16,6 +16,22 @@
|
|||
|
||||
#include <AudioInjector.h>
|
||||
|
||||
/**jsdoc
|
||||
* Plays — "injects" — the content of an audio file. Used in the {@link Audio} API.
|
||||
*
|
||||
* @class AudioInjector
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {boolean} playing - <code>true</code> if the audio is currently playing, otherwise <code>false</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {number} loudness - The loudness in the last frame of audio, range <code>0.0</code> – <code>1.0</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {AudioInjector.AudioInjectorOptions} options - Configures how the injector plays the audio.
|
||||
*/
|
||||
class ScriptAudioInjector : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -26,19 +42,103 @@ public:
|
|||
ScriptAudioInjector(const AudioInjectorPointer& injector);
|
||||
~ScriptAudioInjector();
|
||||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
* Stop current playback, if any, and start playing from the beginning.
|
||||
* @function AudioInjector.restart
|
||||
*/
|
||||
void restart() { _injector->restart(); }
|
||||
|
||||
/**jsdoc
|
||||
* Stop audio playback.
|
||||
* @function AudioInjector.stop
|
||||
* @example <caption>Stop playing a sound before it finishes.</caption>
|
||||
* var sound = SoundCache.getSound(Script.resourcesPath() + "sounds/sample.wav");
|
||||
* var injector;
|
||||
* var injectorOptions = {
|
||||
* position: MyAvatar.position
|
||||
* };
|
||||
*
|
||||
* Script.setTimeout(function () { // Give the sound time to load.
|
||||
* injector = Audio.playSound(sound, injectorOptions);
|
||||
* }, 1000);
|
||||
*
|
||||
* Script.setTimeout(function () {
|
||||
* injector.stop();
|
||||
* }, 2000);
|
||||
*/
|
||||
void stop() { _injector->stop(); }
|
||||
|
||||
/**jsdoc
|
||||
* Get the current configuration of the audio injector.
|
||||
* @function AudioInjector.getOptions
|
||||
* @returns {AudioInjector.AudioInjectorOptions} Configuration of how the injector plays the audio.
|
||||
*/
|
||||
const AudioInjectorOptions& getOptions() const { return _injector->getOptions(); }
|
||||
|
||||
/**jsdoc
|
||||
* Configure how the injector plays the audio.
|
||||
* @function AudioInjector.setOptions
|
||||
* @param {AudioInjector.AudioInjectorOptions} options - Configuration of how the injector plays the audio.
|
||||
*/
|
||||
void setOptions(const AudioInjectorOptions& options) { _injector->setOptions(options); }
|
||||
|
||||
/**jsdoc
|
||||
* Get the loudness of the most recent frame of audio played.
|
||||
* @function AudioInjector.getLoudness
|
||||
* @returns {number} The loudness of the most recent frame of audio played, range <code>0.0</code> – <code>1.0</code>.
|
||||
*/
|
||||
float getLoudness() const { return _injector->getLoudness(); }
|
||||
|
||||
/**jsdoc
|
||||
* Get whether or not the audio is currently playing.
|
||||
* @function AudioInjector.isPlaying
|
||||
* @returns {boolean} <code>true</code> if the audio is currently playing, otherwise <code>false</code>.
|
||||
* @example <caption>See if a sound is playing.</caption>
|
||||
* var sound = SoundCache.getSound(Script.resourcesPath() + "sounds/sample.wav");
|
||||
* var injector;
|
||||
* var injectorOptions = {
|
||||
* position: MyAvatar.position
|
||||
* };
|
||||
*
|
||||
* Script.setTimeout(function () { // Give the sound time to load.
|
||||
* injector = Audio.playSound(sound, injectorOptions);
|
||||
* }, 1000);
|
||||
*
|
||||
* Script.setTimeout(function () {
|
||||
* print("Sound is playing: " + injector.isPlaying());
|
||||
* }, 2000);
|
||||
*/
|
||||
bool isPlaying() const { return _injector->isPlaying(); }
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the audio has finished playing.
|
||||
* @function AudioInjector.finished
|
||||
* @returns {Signal}
|
||||
* @example <caption>Report when a sound has finished playing.</caption>
|
||||
* var sound = SoundCache.getSound(Script.resourcesPath() + "sounds/sample.wav");
|
||||
* var injector;
|
||||
* var injectorOptions = {
|
||||
* position: MyAvatar.position
|
||||
* };
|
||||
*
|
||||
* Script.setTimeout(function () { // Give the sound time to load.
|
||||
* injector = Audio.playSound(sound, injectorOptions);
|
||||
* injector.finished.connect(function () {
|
||||
* print("Finished playing sound");
|
||||
* });
|
||||
* }, 1000);
|
||||
*/
|
||||
void finished();
|
||||
|
||||
protected slots:
|
||||
|
||||
/**jsdoc
|
||||
* Stop audio playback. (Synonym of {@link AudioInjector.stop|stop}.)
|
||||
* @function AudioInjector.stopInjectorImmediately
|
||||
*/
|
||||
void stopInjectorImmediately();
|
||||
private:
|
||||
AudioInjectorPointer _injector;
|
||||
|
|
|
@ -59,7 +59,11 @@ const int32_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_STATIC;
|
|||
// MY_AVATAR does not collide with itself
|
||||
const int32_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR);
|
||||
|
||||
const int32_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_MASK_DEFAULT;
|
||||
// OTHER_AVATARs are dynamic, but are slammed to whatever the avatar-mixer says, which means
|
||||
// their motion can't actually be affected by the local physics simulation -- we rely on the remote simulation
|
||||
// to move its avatar around correctly and to communicate its motion through the avatar-mixer.
|
||||
// Therefore, they only need to collide against things that can be affected by their motion: dynamic and MyAvatar
|
||||
const int32_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_GROUP_DYNAMIC | BULLET_COLLISION_GROUP_MY_AVATAR;
|
||||
|
||||
// COLLISIONLESS gets an empty mask.
|
||||
const int32_t BULLET_COLLISION_MASK_COLLISIONLESS = 0;
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
std::mutex QmlFragmentClass::_mutex;
|
||||
std::map<QString, QScriptValue> QmlFragmentClass::_fragments;
|
||||
|
||||
QmlFragmentClass::QmlFragmentClass(QString id) : qml(id) { }
|
||||
QmlFragmentClass::QmlFragmentClass(bool restricted, QString id) : QmlWindowClass(restricted), qml(id) { }
|
||||
|
||||
// Method called by Qt scripts to create a new bottom menu bar in Android
|
||||
QScriptValue QmlFragmentClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) {
|
||||
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
auto qml = context->argument(0).toVariant().toMap().value("qml");
|
||||
|
@ -41,7 +41,7 @@ QScriptValue QmlFragmentClass::constructor(QScriptContext* context, QScriptEngin
|
|||
|
||||
auto properties = parseArguments(context);
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QmlFragmentClass* retVal = new QmlFragmentClass(qml.toString());
|
||||
QmlFragmentClass* retVal = new QmlFragmentClass(restricted, qml.toString());
|
||||
Q_ASSERT(retVal);
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
retVal->moveToThread(qApp->thread());
|
||||
|
|
|
@ -13,9 +13,19 @@
|
|||
|
||||
class QmlFragmentClass : public QmlWindowClass {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted);
|
||||
public:
|
||||
QmlFragmentClass(QString id);
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
return internal_constructor(context, engine, false);
|
||||
}
|
||||
|
||||
static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){
|
||||
return internal_constructor(context, engine, true);
|
||||
}
|
||||
|
||||
QmlFragmentClass(bool restricted, QString id);
|
||||
|
||||
/**jsdoc
|
||||
* Creates a new button, adds it to this and returns it.
|
||||
|
|
|
@ -20,10 +20,10 @@ static const char* const URL_PROPERTY = "source";
|
|||
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) {
|
||||
QScriptValue QmlWebWindowClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) {
|
||||
auto properties = parseArguments(context);
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QmlWebWindowClass* retVal = new QmlWebWindowClass();
|
||||
QmlWebWindowClass* retVal = new QmlWebWindowClass(restricted);
|
||||
Q_ASSERT(retVal);
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
retVal->moveToThread(qApp->thread());
|
||||
|
|
|
@ -57,8 +57,18 @@ class QmlWebWindowClass : public QmlWindowClass {
|
|||
Q_OBJECT
|
||||
Q_PROPERTY(QString url READ getURL CONSTANT)
|
||||
|
||||
private:
|
||||
static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted);
|
||||
public:
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
QmlWebWindowClass(bool restricted) : QmlWindowClass(restricted) {}
|
||||
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
return internal_constructor(context, engine, false);
|
||||
}
|
||||
|
||||
static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){
|
||||
return internal_constructor(context, engine, true);
|
||||
}
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <shared/QtHelpers.h>
|
||||
#include "OffscreenUi.h"
|
||||
#include "ui/types/HFWebEngineProfile.h"
|
||||
#include "ui/types/FileTypeProfile.h"
|
||||
|
||||
static const char* const SOURCE_PROPERTY = "source";
|
||||
static const char* const TITLE_PROPERTY = "title";
|
||||
|
@ -68,10 +70,10 @@ 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) {
|
||||
QScriptValue QmlWindowClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) {
|
||||
auto properties = parseArguments(context);
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QmlWindowClass* retVal = new QmlWindowClass();
|
||||
QmlWindowClass* retVal = new QmlWindowClass(restricted);
|
||||
Q_ASSERT(retVal);
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
retVal->moveToThread(qApp->thread());
|
||||
|
@ -83,7 +85,7 @@ QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine*
|
|||
return engine->newQObject(retVal);
|
||||
}
|
||||
|
||||
QmlWindowClass::QmlWindowClass() {
|
||||
QmlWindowClass::QmlWindowClass(bool restricted) : _restricted(restricted) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -99,8 +101,7 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
|||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
_source = properties[SOURCE_PROPERTY].toString();
|
||||
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
offscreenUi->loadInNewContext(qmlSource(), [&](QQmlContext* context, QObject* object) {
|
||||
auto objectInitLambda = [&](QQmlContext* context, QObject* object) {
|
||||
_qmlWindow = object;
|
||||
context->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
|
||||
context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
|
@ -128,7 +129,24 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
|||
if (metaObject->indexOfSignal("moved") >= 0)
|
||||
connect(_qmlWindow, SIGNAL(moved(QVector2D)), this, SLOT(hasMoved(QVector2D)), Qt::QueuedConnection);
|
||||
connect(_qmlWindow, SIGNAL(windowClosed()), this, SLOT(hasClosed()), Qt::QueuedConnection);
|
||||
});
|
||||
};
|
||||
|
||||
auto contextInitLambda = [&](QQmlContext* context) {
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
// If the restricted flag is on, override the FileTypeProfile and HFWebEngineProfile objects in the
|
||||
// QML surface root context with local ones
|
||||
qDebug() << "Context initialization lambda";
|
||||
if (_restricted) {
|
||||
qDebug() << "Restricting web content";
|
||||
ContextAwareProfile::restrictContext(context);
|
||||
FileTypeProfile::registerWithContext(context);
|
||||
HFWebEngineProfile::registerWithContext(context);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
offscreenUi->loadInNewContext(qmlSource(), objectInitLambda, contextInitLambda);
|
||||
|
||||
Q_ASSERT(_qmlWindow);
|
||||
Q_ASSERT(dynamic_cast<const QQuickItem*>(_qmlWindow.data()));
|
||||
|
|
|
@ -38,9 +38,18 @@ class QmlWindowClass : public QObject {
|
|||
Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged)
|
||||
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
|
||||
|
||||
private:
|
||||
static QScriptValue internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted);
|
||||
public:
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
QmlWindowClass();
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
return internal_constructor(context, engine, false);
|
||||
}
|
||||
|
||||
static QScriptValue restricted_constructor(QScriptContext* context, QScriptEngine* engine ){
|
||||
return internal_constructor(context, engine, true);
|
||||
}
|
||||
|
||||
QmlWindowClass(bool restricted);
|
||||
~QmlWindowClass();
|
||||
|
||||
/**jsdoc
|
||||
|
@ -51,6 +60,8 @@ public:
|
|||
|
||||
QQuickItem* asQuickItem() const;
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -250,10 +261,12 @@ protected:
|
|||
|
||||
QPointer<QObject> _qmlWindow;
|
||||
QString _source;
|
||||
const bool _restricted;
|
||||
|
||||
private:
|
||||
// QmlWindow content may include WebView requiring EventBridge.
|
||||
void setKeyboardRaised(QObject* object, bool raised, bool numeric = false);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -265,19 +265,6 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) {
|
|||
if (!javaScriptToInject.isEmpty()) {
|
||||
rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
|
||||
}
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||
{
|
||||
PROFILE_RANGE(startup, "FileTypeProfile");
|
||||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||
}
|
||||
{
|
||||
PROFILE_RANGE(startup, "HFWebEngineProfile");
|
||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||
|
||||
}
|
||||
#endif
|
||||
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
|
||||
rootContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
rootContext->setContextProperty("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||
|
@ -300,6 +287,17 @@ void OffscreenQmlSurface::onRootContextCreated(QQmlContext* qmlContext) {
|
|||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, qmlContext));
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
{
|
||||
PROFILE_RANGE(startup, "FileTypeProfile");
|
||||
FileTypeProfile::registerWithContext(qmlContext);
|
||||
}
|
||||
{
|
||||
PROFILE_RANGE(startup, "HFWebEngineProfile");
|
||||
HFWebEngineProfile::registerWithContext(qmlContext);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, QQuickItem* parent, bool forceNewContext) {
|
||||
|
|
|
@ -334,6 +334,8 @@ static const char* VRMENU_SOURCE_URL = "hifi/tablet/TabletMenu.qml";
|
|||
|
||||
class TabletRootWindow : public QmlWindowClass {
|
||||
virtual QString qmlSource() const override { return "hifi/tablet/WindowRoot.qml"; }
|
||||
public:
|
||||
TabletRootWindow() : QmlWindowClass(false) {}
|
||||
};
|
||||
|
||||
TabletProxy::TabletProxy(QObject* parent, const QString& name) : QObject(parent), _name(name) {
|
||||
|
|
32
libraries/ui/src/ui/types/ContextAwareProfile.cpp
Normal file
32
libraries/ui/src/ui/types/ContextAwareProfile.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// FileTypeProfile.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Kunal Gosar on 2017-03-10.
|
||||
// Copyright 2017 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 "ContextAwareProfile.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess";
|
||||
|
||||
ContextAwareProfile::ContextAwareProfile(QQmlContext* parent) :
|
||||
QQuickWebEngineProfile(parent), _context(parent) { }
|
||||
|
||||
|
||||
void ContextAwareProfile::restrictContext(QQmlContext* context) {
|
||||
context->setContextProperty(RESTRICTED_FLAG_PROPERTY, true);
|
||||
}
|
||||
|
||||
bool ContextAwareProfile::isRestricted(QQmlContext* context) {
|
||||
return context->contextProperty(RESTRICTED_FLAG_PROPERTY).toBool();
|
||||
}
|
||||
|
||||
#endif
|
42
libraries/ui/src/ui/types/ContextAwareProfile.h
Normal file
42
libraries/ui/src/ui/types/ContextAwareProfile.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/07/27
|
||||
// Copyright 2013-2018 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_ContextAwareProfile_h
|
||||
#define hifi_ContextAwareProfile_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
#include <QtWebEngineCore/QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class QQmlContext;
|
||||
|
||||
class ContextAwareProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
static void restrictContext(QQmlContext* context);
|
||||
static bool isRestricted(QQmlContext* context);
|
||||
QQmlContext* getContext() const { return _context; }
|
||||
protected:
|
||||
|
||||
class RequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
RequestInterceptor(ContextAwareProfile* parent) : QWebEngineUrlRequestInterceptor(parent), _profile(parent) {}
|
||||
QQmlContext* getContext() const { return _profile->getContext(); }
|
||||
protected:
|
||||
ContextAwareProfile* _profile;
|
||||
};
|
||||
|
||||
ContextAwareProfile(QQmlContext* parent);
|
||||
QQmlContext* _context;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_FileTypeProfile_h
|
|
@ -11,18 +11,31 @@
|
|||
|
||||
#include "FileTypeProfile.h"
|
||||
|
||||
#include "FileTypeRequestInterceptor.h"
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
|
||||
|
||||
FileTypeProfile::FileTypeProfile(QObject* parent) :
|
||||
QQuickWebEngineProfile(parent)
|
||||
FileTypeProfile::FileTypeProfile(QQmlContext* parent) :
|
||||
ContextAwareProfile(parent)
|
||||
{
|
||||
static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
|
||||
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
|
||||
|
||||
auto requestInterceptor = new FileTypeRequestInterceptor(this);
|
||||
auto requestInterceptor = new RequestInterceptor(this);
|
||||
setRequestInterceptor(requestInterceptor);
|
||||
}
|
||||
|
||||
void FileTypeProfile::RequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info, getContext());
|
||||
RequestFilters::interceptFileType(info, getContext());
|
||||
}
|
||||
|
||||
void FileTypeProfile::registerWithContext(QQmlContext* context) {
|
||||
context->setContextProperty("FileTypeProfile", new FileTypeProfile(context));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -17,12 +17,23 @@
|
|||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
#include "ContextAwareProfile.h"
|
||||
|
||||
class FileTypeProfile : public ContextAwareProfile {
|
||||
using Parent = ContextAwareProfile;
|
||||
|
||||
class FileTypeProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
FileTypeProfile(QObject* parent = Q_NULLPTR);
|
||||
static void registerWithContext(QQmlContext* parent);
|
||||
|
||||
protected:
|
||||
FileTypeProfile(QQmlContext* parent);
|
||||
class RequestInterceptor : public Parent::RequestInterceptor {
|
||||
public:
|
||||
RequestInterceptor(ContextAwareProfile* parent) : Parent::RequestInterceptor(parent) {}
|
||||
void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // hifi_FileTypeProfile_h
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// FileTypeRequestInterceptor.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Kunal Gosar on 2017-03-10.
|
||||
// Copyright 2017 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 "FileTypeRequestInterceptor.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
void FileTypeRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info);
|
||||
RequestFilters::interceptFileType(info);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// FileTypeRequestInterceptor.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Kunal Gosar on 2017-03-10.
|
||||
// Copyright 2017 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_FileTypeRequestInterceptor_h
|
||||
#define hifi_FileTypeRequestInterceptor_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class FileTypeRequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
FileTypeRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
|
||||
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_FileTypeRequestInterceptor_h
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// HFTabletWebEngineProfile.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Dante Ruiz on 2017-03-31.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_HFTabletWebEngineProfile_h
|
||||
#define hifi_HFTabletWebEngineProfile_h
|
||||
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
|
||||
class HFTabletWebEngineProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
HFTabletWebEngineProfile(QObject* parent = Q_NULLPTR);
|
||||
};
|
||||
|
||||
#endif // hifi_HFTabletWebEngineProfile_h
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// HFTabletWebEngineRequestInterceptor.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Dante Ruiz on 2017-3-31.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
#ifndef hifi_HFTabletWebEngineRequestInterceptor_h
|
||||
#define hifi_HFTabletWebEngineRequestInterceptor_h
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class HFTabletWebEngineRequestInterceptor
|
||||
: public QWebEngineUrlRequestInterceptor
|
||||
{
|
||||
public:
|
||||
HFTabletWebEngineRequestInterceptor(QObject* parent)
|
||||
: QWebEngineUrlRequestInterceptor(parent)
|
||||
{};
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_HFWebEngineRequestInterceptor_h
|
|
@ -11,20 +11,28 @@
|
|||
|
||||
#include "HFWebEngineProfile.h"
|
||||
|
||||
#include "HFWebEngineRequestInterceptor.h"
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
|
||||
|
||||
HFWebEngineProfile::HFWebEngineProfile(QObject* parent) :
|
||||
QQuickWebEngineProfile(parent)
|
||||
HFWebEngineProfile::HFWebEngineProfile(QQmlContext* parent) : Parent(parent)
|
||||
{
|
||||
setStorageName(QML_WEB_ENGINE_STORAGE_NAME);
|
||||
|
||||
// we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
|
||||
auto requestInterceptor = new HFWebEngineRequestInterceptor(this);
|
||||
setRequestInterceptor(requestInterceptor);
|
||||
setRequestInterceptor(new RequestInterceptor(this));
|
||||
}
|
||||
|
||||
#endif
|
||||
void HFWebEngineProfile::RequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info, getContext());
|
||||
}
|
||||
|
||||
void HFWebEngineProfile::registerWithContext(QQmlContext* context) {
|
||||
context->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(context));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,15 +14,24 @@
|
|||
#ifndef hifi_HFWebEngineProfile_h
|
||||
#define hifi_HFWebEngineProfile_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include "ContextAwareProfile.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
|
||||
class HFWebEngineProfile : public QQuickWebEngineProfile {
|
||||
class HFWebEngineProfile : public ContextAwareProfile {
|
||||
using Parent = ContextAwareProfile;
|
||||
public:
|
||||
HFWebEngineProfile(QObject* parent = Q_NULLPTR);
|
||||
static void registerWithContext(QQmlContext* parent);
|
||||
|
||||
protected:
|
||||
HFWebEngineProfile(QQmlContext* parent);
|
||||
class RequestInterceptor : public Parent::RequestInterceptor {
|
||||
public:
|
||||
RequestInterceptor(ContextAwareProfile* parent) : Parent::RequestInterceptor(parent) {}
|
||||
void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // hifi_HFWebEngineProfile_h
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// HFWebEngineRequestInterceptor.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-10-14.
|
||||
// Copyright 2016 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 "HFWebEngineRequestInterceptor.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include "RequestFilters.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
RequestFilters::interceptHFWebEngineRequest(info);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// HFWebEngineRequestInterceptor.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-10-14.
|
||||
// Copyright 2016 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_HFWebEngineRequestInterceptor_h
|
||||
#define hifi_HFWebEngineRequestInterceptor_h
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class HFWebEngineRequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
HFWebEngineRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
|
||||
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // hifi_HFWebEngineRequestInterceptor_h
|
|
@ -10,12 +10,15 @@
|
|||
//
|
||||
|
||||
#include "RequestFilters.h"
|
||||
#include "NetworkingConstants.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <SettingHandle.h>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include <SettingHandle.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <AccountManager.h>
|
||||
|
||||
#include "ContextAwareProfile.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
|
||||
|
@ -42,9 +45,29 @@ namespace {
|
|||
return filename.endsWith(".json", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool blockLocalFiles(QWebEngineUrlRequestInfo& info) {
|
||||
auto requestUrl = info.requestUrl();
|
||||
if (!requestUrl.isLocalFile()) {
|
||||
// Not a local file, do not block
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can potentially add whitelisting logic or development environment variables that
|
||||
// will allow people to override this setting on a per-client basis here.
|
||||
QString targetFilePath = QFileInfo(requestUrl.toLocalFile()).canonicalFilePath();
|
||||
|
||||
// If we get here, we've determined it's a local file and we have no reason not to block it
|
||||
qWarning() << "Blocking web access to local file path" << targetFilePath;
|
||||
info.block(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) {
|
||||
void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info, QQmlContext* context) {
|
||||
if (ContextAwareProfile::isRestricted(context) && blockLocalFiles(info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if this is a request to a highfidelity URL
|
||||
bool isAuthable = isAuthableHighFidelityURL(info.requestUrl());
|
||||
if (isAuthable) {
|
||||
|
@ -71,7 +94,7 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info)
|
|||
info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
|
||||
}
|
||||
|
||||
void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) {
|
||||
void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info, QQmlContext* context) {
|
||||
QString filename = info.requestUrl().fileName();
|
||||
if (isScript(filename) || isJSON(filename)) {
|
||||
static const QString CONTENT_HEADER = "Accept";
|
||||
|
@ -79,4 +102,4 @@ void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) {
|
|||
info.setHttpHeader(CONTENT_HEADER.toLocal8Bit(), TYPE_VALUE.toLocal8Bit());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
#include <QObject>
|
||||
#include <QWebEngineUrlRequestInfo>
|
||||
|
||||
class QQmlContext;
|
||||
|
||||
class RequestFilters : public QObject {
|
||||
public:
|
||||
static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info);
|
||||
static void interceptFileType(QWebEngineUrlRequestInfo& info);
|
||||
static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info, QQmlContext* context);
|
||||
static void interceptFileType(QWebEngineUrlRequestInfo& info, QQmlContext* context);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue