mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 18:16:45 +02:00
Merge branch 'master' of github.com:highfidelity/hifi
This commit is contained in:
commit
cb4e0c798f
25 changed files with 143 additions and 51 deletions
|
@ -57,7 +57,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
||||||
if (message->getSize() == 0) {
|
if (message->getSize() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
|
|
||||||
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
|
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
|
||||||
|
@ -88,11 +88,10 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
||||||
auto pendingAssignment = _pendingAssignedNodes.find(nodeConnection.connectUUID);
|
auto pendingAssignment = _pendingAssignedNodes.find(nodeConnection.connectUUID);
|
||||||
|
|
||||||
SharedNodePointer node;
|
SharedNodePointer node;
|
||||||
|
QString username;
|
||||||
if (pendingAssignment != _pendingAssignedNodes.end()) {
|
if (pendingAssignment != _pendingAssignedNodes.end()) {
|
||||||
node = processAssignmentConnectRequest(nodeConnection, pendingAssignment->second);
|
node = processAssignmentConnectRequest(nodeConnection, pendingAssignment->second);
|
||||||
} else if (!STATICALLY_ASSIGNED_NODES.contains(nodeConnection.nodeType)) {
|
} else if (!STATICALLY_ASSIGNED_NODES.contains(nodeConnection.nodeType)) {
|
||||||
QString username;
|
|
||||||
QByteArray usernameSignature;
|
QByteArray usernameSignature;
|
||||||
|
|
||||||
if (message->getBytesLeftToRead() > 0) {
|
if (message->getBytesLeftToRead() > 0) {
|
||||||
|
@ -122,9 +121,13 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
||||||
nodeData->setNodeInterestSet(safeInterestSet);
|
nodeData->setNodeInterestSet(safeInterestSet);
|
||||||
nodeData->setPlaceName(nodeConnection.placeName);
|
nodeData->setPlaceName(nodeConnection.placeName);
|
||||||
|
|
||||||
qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID())
|
qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID())
|
||||||
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress
|
<< "on" << message->getSenderSockAddr()
|
||||||
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
|
<< "with MAC" << nodeConnection.hardwareAddress
|
||||||
|
<< "and machine fingerprint" << nodeConnection.machineFingerprint
|
||||||
|
<< "user" << username
|
||||||
|
<< "reason" << QString(nodeConnection.connectReason ? "SilentDomainDisconnect" : "Connect")
|
||||||
|
<< "previous connection uptime" << nodeConnection.previousConnectionUpTime/USECS_PER_MSEC << "msec";
|
||||||
|
|
||||||
// signal that we just connected a node so the DomainServer can get it a list
|
// signal that we just connected a node so the DomainServer can get it a list
|
||||||
// and broadcast its presence right away
|
// and broadcast its presence right away
|
||||||
|
@ -468,7 +471,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) {
|
if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) {
|
||||||
// we have a node that already has these exact sockets
|
// we have a node that already has these exact sockets
|
||||||
// this can occur if a node is failing to connect to the domain
|
// this can occur if a node is failing to connect to the domain
|
||||||
|
|
||||||
// remove the old node before adding the new node
|
// remove the old node before adding the new node
|
||||||
qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID();
|
qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID();
|
||||||
existingNodeID = node->getUUID();
|
existingNodeID = node->getUUID();
|
||||||
|
@ -842,7 +845,7 @@ void DomainGatekeeper::processICEPingPacket(QSharedPointer<ReceivedMessage> mess
|
||||||
|
|
||||||
// before we respond to this ICE ping packet, make sure we have a peer in the list that matches
|
// before we respond to this ICE ping packet, make sure we have a peer in the list that matches
|
||||||
QUuid icePeerID = QUuid::fromRfc4122({ message->getRawMessage(), NUM_BYTES_RFC4122_UUID });
|
QUuid icePeerID = QUuid::fromRfc4122({ message->getRawMessage(), NUM_BYTES_RFC4122_UUID });
|
||||||
|
|
||||||
if (_icePeers.contains(icePeerID)) {
|
if (_icePeers.contains(icePeerID)) {
|
||||||
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID());
|
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID());
|
||||||
|
|
||||||
|
@ -882,7 +885,6 @@ void DomainGatekeeper::getGroupMemberships(const QString& username) {
|
||||||
QJsonArray groupIDs = QJsonArray::fromStringList(groupIDSet.toList());
|
QJsonArray groupIDs = QJsonArray::fromStringList(groupIDSet.toList());
|
||||||
json["groups"] = groupIDs;
|
json["groups"] = groupIDs;
|
||||||
|
|
||||||
|
|
||||||
// if we've already asked, wait for the answer before asking again
|
// if we've already asked, wait for the answer before asking again
|
||||||
QString lowerUsername = username.toLower();
|
QString lowerUsername = username.toLower();
|
||||||
if (_inFlightGroupMembershipsRequests.contains(lowerUsername)) {
|
if (_inFlightGroupMembershipsRequests.contains(lowerUsername)) {
|
||||||
|
@ -969,7 +971,7 @@ void DomainGatekeeper::getDomainOwnerFriendsList() {
|
||||||
QNetworkAccessManager::GetOperation, callbackParams, QByteArray(),
|
QNetworkAccessManager::GetOperation, callbackParams, QByteArray(),
|
||||||
NULL, QVariantMap());
|
NULL, QVariantMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply* requestReply) {
|
void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply* requestReply) {
|
||||||
|
|
|
@ -1079,7 +1079,7 @@ void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> mess
|
||||||
// client-side send time of last connect/domain list request
|
// client-side send time of last connect/domain list request
|
||||||
nodeData->setLastDomainCheckinTimestamp(nodeRequestData.lastPingTimestamp);
|
nodeData->setLastDomainCheckinTimestamp(nodeRequestData.lastPingTimestamp);
|
||||||
|
|
||||||
sendDomainListToNode(sendingNode, message->getFirstPacketReceiveTime(), message->getSenderSockAddr());
|
sendDomainListToNode(sendingNode, message->getFirstPacketReceiveTime(), message->getSenderSockAddr(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServer::isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB) {
|
bool DomainServer::isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB) {
|
||||||
|
@ -1145,7 +1145,7 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode, quint64 reques
|
||||||
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(newNode->getLinkedData());
|
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(newNode->getLinkedData());
|
||||||
|
|
||||||
// reply back to the user with a PacketType::DomainList
|
// reply back to the user with a PacketType::DomainList
|
||||||
sendDomainListToNode(newNode, requestReceiveTime, nodeData->getSendingSockAddr());
|
sendDomainListToNode(newNode, requestReceiveTime, nodeData->getSendingSockAddr(), true);
|
||||||
|
|
||||||
// if this node is a user (unassigned Agent), signal
|
// if this node is a user (unassigned Agent), signal
|
||||||
if (newNode->getType() == NodeType::Agent && !nodeData->wasAssigned()) {
|
if (newNode->getType() == NodeType::Agent && !nodeData->wasAssigned()) {
|
||||||
|
@ -1161,7 +1161,7 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode, quint64 reques
|
||||||
broadcastNewNode(newNode);
|
broadcastNewNode(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, quint64 requestPacketReceiveTime, const HifiSockAddr &senderSockAddr) {
|
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, quint64 requestPacketReceiveTime, const HifiSockAddr &senderSockAddr, bool newConnection) {
|
||||||
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID +
|
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID +
|
||||||
NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID + 4;
|
NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID + 4;
|
||||||
|
|
||||||
|
@ -1181,6 +1181,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, quint64 r
|
||||||
extendedHeaderStream << nodeData->getLastDomainCheckinTimestamp();
|
extendedHeaderStream << nodeData->getLastDomainCheckinTimestamp();
|
||||||
extendedHeaderStream << quint64(duration_cast<microseconds>(system_clock::now().time_since_epoch()).count());
|
extendedHeaderStream << quint64(duration_cast<microseconds>(system_clock::now().time_since_epoch()).count());
|
||||||
extendedHeaderStream << quint64(duration_cast<microseconds>(p_high_resolution_clock::now().time_since_epoch()).count()) - requestPacketReceiveTime;
|
extendedHeaderStream << quint64(duration_cast<microseconds>(p_high_resolution_clock::now().time_since_epoch()).count()) - requestPacketReceiveTime;
|
||||||
|
extendedHeaderStream << newConnection;
|
||||||
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
||||||
|
|
||||||
// always send the node their own UUID back
|
// always send the node their own UUID back
|
||||||
|
|
|
@ -173,7 +173,7 @@ private:
|
||||||
void handleKillNode(SharedNodePointer nodeToKill);
|
void handleKillNode(SharedNodePointer nodeToKill);
|
||||||
void broadcastNodeDisconnect(const SharedNodePointer& disconnnectedNode);
|
void broadcastNodeDisconnect(const SharedNodePointer& disconnnectedNode);
|
||||||
|
|
||||||
void sendDomainListToNode(const SharedNodePointer& node, quint64 requestPacketReceiveTime, const HifiSockAddr& senderSockAddr);
|
void sendDomainListToNode(const SharedNodePointer& node, quint64 requestPacketReceiveTime, const HifiSockAddr& senderSockAddr, bool newConnection);
|
||||||
|
|
||||||
bool isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB);
|
bool isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
|
||||||
|
|
||||||
// now the machine fingerprint
|
// now the machine fingerprint
|
||||||
dataStream >> newHeader.machineFingerprint;
|
dataStream >> newHeader.machineFingerprint;
|
||||||
|
|
||||||
|
dataStream >> newHeader.connectReason;
|
||||||
|
|
||||||
|
dataStream >> newHeader.previousConnectionUpTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataStream >> newHeader.lastPingTimestamp;
|
dataStream >> newHeader.lastPingTimestamp;
|
||||||
|
|
|
@ -31,6 +31,8 @@ public:
|
||||||
QString placeName;
|
QString placeName;
|
||||||
QString hardwareAddress;
|
QString hardwareAddress;
|
||||||
QUuid machineFingerprint;
|
QUuid machineFingerprint;
|
||||||
|
quint32 connectReason;
|
||||||
|
quint64 previousConnectionUpTime;
|
||||||
|
|
||||||
QByteArray protocolVersion;
|
QByteArray protocolVersion;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,8 @@ import controlsUit 1.0
|
||||||
OriginalDesktop.Desktop {
|
OriginalDesktop.Desktop {
|
||||||
id: desktop
|
id: desktop
|
||||||
|
|
||||||
|
property alias toolbarObjectName: sysToolbar.objectName
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: hoverWatch
|
id: hoverWatch
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -70,7 +72,12 @@ OriginalDesktop.Desktop {
|
||||||
x: sysToolbar.x
|
x: sysToolbar.x
|
||||||
buttonModel: tablet ? tablet.buttons : null;
|
buttonModel: tablet ? tablet.buttons : null;
|
||||||
shown: tablet ? tablet.toolbarMode : false;
|
shown: tablet ? tablet.toolbarMode : false;
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
desktop.toolbarVisibleChanged(visible, sysToolbar.objectName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
signal toolbarVisibleChanged(bool isVisible, string toolbarName);
|
||||||
|
|
||||||
QtSettings.Settings {
|
QtSettings.Settings {
|
||||||
id: settings;
|
id: settings;
|
||||||
|
|
|
@ -122,7 +122,7 @@ Rectangle {
|
||||||
Tablet.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
// Can't use `Window.location` in QML, so just use what setting `Window.location` actually calls under the hood:
|
// Can't use `Window.location` in QML, so just use what setting `Window.location` actually calls under the hood:
|
||||||
// AddressManager.handleLookupString().
|
// AddressManager.handleLookupString().
|
||||||
AddressManager.handleLookupString(LocationBookmarks.getHomeLocationAddress());
|
AddressManager.handleLookupString(LocationBookmarks.getAddress("hqhome"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,11 @@ Rectangle {
|
||||||
|
|
||||||
onSkeletonModelURLChanged: {
|
onSkeletonModelURLChanged: {
|
||||||
root.updatePreviewUrl();
|
root.updatePreviewUrl();
|
||||||
|
|
||||||
|
if (MyAvatar.skeletonModelURL.indexOf("defaultAvatar" > -1) && topBarInventoryModel.count > 0) {
|
||||||
|
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true);
|
||||||
|
MyAvatar.skeletonModelURL = topBarInventoryModel.get(0).download_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2708,6 +2708,7 @@ void Application::cleanupBeforeQuit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
||||||
|
getEntities()->clear();
|
||||||
|
|
||||||
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
|
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
|
||||||
QThreadPool::globalInstance()->clear();
|
QThreadPool::globalInstance()->clear();
|
||||||
|
|
|
@ -490,7 +490,7 @@ void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transact
|
||||||
_myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
|
_myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
|
||||||
for (auto avatar : _otherAvatarsToChangeInPhysics) {
|
for (auto avatar : _otherAvatarsToChangeInPhysics) {
|
||||||
bool isInPhysics = avatar->isInPhysicsSimulation();
|
bool isInPhysics = avatar->isInPhysicsSimulation();
|
||||||
if (isInPhysics != avatar->shouldBeInPhysicsSimulation()) {
|
if (isInPhysics != avatar->shouldBeInPhysicsSimulation() || avatar->_needsReinsertion) {
|
||||||
if (isInPhysics) {
|
if (isInPhysics) {
|
||||||
transaction.objectsToRemove.push_back(avatar->_motionState);
|
transaction.objectsToRemove.push_back(avatar->_motionState);
|
||||||
avatar->_motionState = nullptr;
|
avatar->_motionState = nullptr;
|
||||||
|
|
|
@ -46,6 +46,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)awakeFromNib {
|
-(void)awakeFromNib {
|
||||||
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE];
|
||||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||||
selector:@selector(didTerminateApp:)
|
selector:@selector(didTerminateApp:)
|
||||||
name:NSWorkspaceDidTerminateApplicationNotification
|
name:NSWorkspaceDidTerminateApplicationNotification
|
||||||
|
@ -114,6 +115,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
userInfo:nil
|
userInfo:nil
|
||||||
repeats:NO];
|
repeats:NO];
|
||||||
}
|
}
|
||||||
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setDownloadContextFilename:(NSString *)aFilename
|
- (void) setDownloadContextFilename:(NSString *)aFilename
|
||||||
|
@ -277,6 +279,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
|
|
||||||
-(void)onSplashScreenTimerFinished:(NSTimer *)timer
|
-(void)onSplashScreenTimerFinished:(NSTimer *)timer
|
||||||
{
|
{
|
||||||
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE];
|
||||||
[self showLoginScreen];
|
[self showLoginScreen];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +339,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
NSString* scriptsPath = [[self getAppPath] stringByAppendingString:@"interface.app/Contents/Resources/scripts/simplifiedUI/"];
|
NSString* scriptsPath = [[self getAppPath] stringByAppendingString:@"interface.app/Contents/Resources/scripts/simplifiedUI/"];
|
||||||
NSString* domainUrl = [[Settings sharedSettings] getDomainUrl];
|
NSString* domainUrl = [[Settings sharedSettings] getDomainUrl];
|
||||||
NSString* userToken = [[Launcher sharedLauncher] getTokenString];
|
NSString* userToken = [[Launcher sharedLauncher] getTokenString];
|
||||||
|
NSString* homeBookmark = [[NSString stringWithFormat:@"hqhome="] stringByAppendingString:domainUrl];
|
||||||
NSArray* arguments;
|
NSArray* arguments;
|
||||||
if (userToken != nil) {
|
if (userToken != nil) {
|
||||||
arguments = [NSArray arrayWithObjects:
|
arguments = [NSArray arrayWithObjects:
|
||||||
|
@ -344,6 +348,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
@"--cache", contentPath,
|
@"--cache", contentPath,
|
||||||
@"--displayName", displayName,
|
@"--displayName", displayName,
|
||||||
@"--scripts", scriptsPath,
|
@"--scripts", scriptsPath,
|
||||||
|
@"--setBookmark", homeBookmark,
|
||||||
@"--no-updater",
|
@"--no-updater",
|
||||||
@"--no-launcher", nil];
|
@"--no-launcher", nil];
|
||||||
} else {
|
} else {
|
||||||
|
@ -351,6 +356,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
@"--url" , domainUrl,
|
@"--url" , domainUrl,
|
||||||
@"--cache", contentPath,
|
@"--cache", contentPath,
|
||||||
@"--scripts", scriptsPath,
|
@"--scripts", scriptsPath,
|
||||||
|
@"--setBookmark", homeBookmark,
|
||||||
@"--no-updater",
|
@"--no-updater",
|
||||||
@"--no-launcher", nil];
|
@"--no-launcher", nil];
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,9 +234,10 @@ HWND LauncherManager::launchApplication() {
|
||||||
CString parsedTokens = _tokensJSON;
|
CString parsedTokens = _tokensJSON;
|
||||||
parsedTokens.Replace(_T("\""), _T("\\\""));
|
parsedTokens.Replace(_T("\""), _T("\\\""));
|
||||||
tokensParam = _T("--tokens \"");
|
tokensParam = _T("--tokens \"");
|
||||||
tokensParam += parsedTokens + _T("\"");
|
tokensParam += parsedTokens + _T("\" ");
|
||||||
}
|
}
|
||||||
CString params = urlParam + scriptsParam + cacheParam + nameParam + tokensParam + EXTRA_PARAMETERS;
|
CString bookmarkParam = _T("--setBookmark hqhome=\"") + _domainURL + ("\" ");
|
||||||
|
CString params = urlParam + scriptsParam + cacheParam + nameParam + tokensParam + bookmarkParam + EXTRA_PARAMETERS;
|
||||||
_shouldLaunch = FALSE;
|
_shouldLaunch = FALSE;
|
||||||
return LauncherUtils::executeOnForeground(interfaceExe, params);
|
return LauncherUtils::executeOnForeground(interfaceExe, params);
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,18 +256,28 @@ void EntityTreeRenderer::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the engine
|
// reset the engine
|
||||||
if (_wantScripts && !_shuttingDown) {
|
|
||||||
resetEntitiesScriptEngine();
|
|
||||||
}
|
|
||||||
// remove all entities from the scene
|
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
if (scene) {
|
if (_shuttingDown) {
|
||||||
for (const auto& entry : _entitiesInScene) {
|
if (scene) {
|
||||||
const auto& renderer = entry.second;
|
render::Transaction transaction;
|
||||||
fadeOutRenderable(renderer);
|
for (const auto& entry : _entitiesInScene) {
|
||||||
|
const auto& renderer = entry.second;
|
||||||
|
renderer->removeFromScene(scene, transaction);
|
||||||
|
}
|
||||||
|
scene->enqueueTransaction(transaction);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown";
|
if (_wantScripts) {
|
||||||
|
resetEntitiesScriptEngine();
|
||||||
|
}
|
||||||
|
if (scene) {
|
||||||
|
for (const auto& entry : _entitiesInScene) {
|
||||||
|
const auto& renderer = entry.second;
|
||||||
|
fadeOutRenderable(renderer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_entitiesInScene.clear();
|
_entitiesInScene.clear();
|
||||||
_renderablesToUpdate.clear();
|
_renderablesToUpdate.clear();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "RenderableWebEntityItem.h"
|
#include "RenderableWebEntityItem.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtGui/QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
|
@ -46,7 +47,7 @@ static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND;
|
||||||
static uint8_t YOUTUBE_MAX_FPS = 30;
|
static uint8_t YOUTUBE_MAX_FPS = 30;
|
||||||
|
|
||||||
// Don't allow more than 20 concurrent web views
|
// Don't allow more than 20 concurrent web views
|
||||||
static uint32_t _currentWebCount { 0 };
|
static std::atomic<uint32_t> _currentWebCount(0);
|
||||||
static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 20;
|
static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 20;
|
||||||
|
|
||||||
static QTouchDevice _touchDevice;
|
static QTouchDevice _touchDevice;
|
||||||
|
@ -356,16 +357,15 @@ void WebEntityRenderer::buildWebSurface(const EntityItemPointer& entity, const Q
|
||||||
|
|
||||||
void WebEntityRenderer::destroyWebSurface() {
|
void WebEntityRenderer::destroyWebSurface() {
|
||||||
QSharedPointer<OffscreenQmlSurface> webSurface;
|
QSharedPointer<OffscreenQmlSurface> webSurface;
|
||||||
ContentType contentType = ContentType::NoContent;
|
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
webSurface.swap(_webSurface);
|
webSurface.swap(_webSurface);
|
||||||
_contentType = contentType;
|
_contentType = ContentType::NoContent;
|
||||||
});
|
|
||||||
|
|
||||||
if (webSurface) {
|
if (webSurface) {
|
||||||
--_currentWebCount;
|
--_currentWebCount;
|
||||||
WebEntityRenderer::releaseWebSurface(webSurface, _cachedWebSurface, _connections);
|
WebEntityRenderer::releaseWebSurface(webSurface, _cachedWebSurface, _connections);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 WebEntityRenderer::getWindowSize(const TypedEntityPointer& entity) const {
|
glm::vec2 WebEntityRenderer::getWindowSize(const TypedEntityPointer& entity) const {
|
||||||
|
@ -469,6 +469,12 @@ void WebEntityRenderer::handlePointerEventAsMouse(const PointerEvent& event) {
|
||||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity) {
|
||||||
|
// HACK: destroyWebSurface() here to avoid a crash on shutdown.
|
||||||
|
// TODO: fix the real problem: EntityRenderer<>::dtor never called on shutdown for smart-pointer resource leak.
|
||||||
|
destroyWebSurface();
|
||||||
|
}
|
||||||
|
|
||||||
void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) {
|
void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) {
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
if (_webSurface) {
|
if (_webSurface) {
|
||||||
|
|
|
@ -64,6 +64,7 @@ protected:
|
||||||
void handlePointerEventAsTouch(const PointerEvent& event);
|
void handlePointerEventAsTouch(const PointerEvent& event);
|
||||||
void handlePointerEventAsMouse(const PointerEvent& event);
|
void handlePointerEventAsMouse(const PointerEvent& event);
|
||||||
|
|
||||||
|
void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
||||||
private:
|
private:
|
||||||
void onTimeout();
|
void onTimeout();
|
||||||
void buildWebSurface(const EntityItemPointer& entity, const QString& newSourceURL);
|
void buildWebSurface(const EntityItemPointer& entity, const QString& newSourceURL);
|
||||||
|
|
|
@ -343,4 +343,4 @@ PulsePropertyGroup WebEntityItem::getPulseProperties() const {
|
||||||
return resultWithReadLock<PulsePropertyGroup>([&] {
|
return resultWithReadLock<PulsePropertyGroup>([&] {
|
||||||
return _pulseProperties;
|
return _pulseProperties;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -632,6 +632,7 @@ void LimitedNodeList::processKillNode(ReceivedMessage& message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::handleNodeKill(const SharedNodePointer& node, ConnectionID nextConnectionID) {
|
void LimitedNodeList::handleNodeKill(const SharedNodePointer& node, ConnectionID nextConnectionID) {
|
||||||
|
_nodeDisconnectTimestamp = usecTimestampNow();
|
||||||
qCDebug(networking) << "Killed" << *node;
|
qCDebug(networking) << "Killed" << *node;
|
||||||
node->stopPingTimer();
|
node->stopPingTimer();
|
||||||
emit nodeKilled(node);
|
emit nodeKilled(node);
|
||||||
|
|
|
@ -108,6 +108,13 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_ENUM(ConnectionStep);
|
Q_ENUM(ConnectionStep);
|
||||||
|
|
||||||
|
enum ConnectReason : quint32 {
|
||||||
|
Connect = 0,
|
||||||
|
SilentDomainDisconnect
|
||||||
|
};
|
||||||
|
Q_ENUM(ConnectReason);
|
||||||
|
|
||||||
QUuid getSessionUUID() const;
|
QUuid getSessionUUID() const;
|
||||||
void setSessionUUID(const QUuid& sessionUUID);
|
void setSessionUUID(const QUuid& sessionUUID);
|
||||||
Node::LocalID getSessionLocalID() const;
|
Node::LocalID getSessionLocalID() const;
|
||||||
|
@ -461,6 +468,9 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<QUuid, ConnectionID> _connectionIDs;
|
std::unordered_map<QUuid, ConnectionID> _connectionIDs;
|
||||||
|
quint64 _nodeConnectTimestamp{ 0 };
|
||||||
|
quint64 _nodeDisconnectTimestamp{ 0 };
|
||||||
|
ConnectReason _connectReason { Connect };
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp);
|
void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp);
|
||||||
|
|
|
@ -113,6 +113,8 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
|
||||||
connect(&_domainHandler, SIGNAL(connectedToDomain(QUrl)), &_keepAlivePingTimer, SLOT(start()));
|
connect(&_domainHandler, SIGNAL(connectedToDomain(QUrl)), &_keepAlivePingTimer, SLOT(start()));
|
||||||
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop);
|
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop);
|
||||||
|
|
||||||
|
connect(&_domainHandler, &DomainHandler::limitOfSilentDomainCheckInsReached, this, [this]() { _connectReason = LimitedNodeList::SilentDomainDisconnect; });
|
||||||
|
|
||||||
// set our sockAddrBelongsToDomainOrNode method as the connection creation filter for the udt::Socket
|
// set our sockAddrBelongsToDomainOrNode method as the connection creation filter for the udt::Socket
|
||||||
using std::placeholders::_1;
|
using std::placeholders::_1;
|
||||||
_nodeSocket.setConnectionCreationFilterOperator(std::bind(&NodeList::sockAddrBelongsToDomainOrNode, this, _1));
|
_nodeSocket.setConnectionCreationFilterOperator(std::bind(&NodeList::sockAddrBelongsToDomainOrNode, this, _1));
|
||||||
|
@ -414,6 +416,16 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
// now add the machine fingerprint
|
// now add the machine fingerprint
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
packetStream << FingerprintUtils::getMachineFingerprint();
|
packetStream << FingerprintUtils::getMachineFingerprint();
|
||||||
|
|
||||||
|
packetStream << _connectReason;
|
||||||
|
|
||||||
|
if (_nodeDisconnectTimestamp < _nodeConnectTimestamp) {
|
||||||
|
_nodeDisconnectTimestamp = usecTimestampNow();
|
||||||
|
}
|
||||||
|
quint64 previousConnectionUptime = _nodeConnectTimestamp ? _nodeDisconnectTimestamp - _nodeConnectTimestamp : 0;
|
||||||
|
|
||||||
|
packetStream << previousConnectionUptime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
packetStream << quint64(duration_cast<microseconds>(system_clock::now().time_since_epoch()).count());
|
packetStream << quint64(duration_cast<microseconds>(system_clock::now().time_since_epoch()).count());
|
||||||
|
@ -666,6 +678,14 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
||||||
quint64 domainServerCheckinProcessingTime;
|
quint64 domainServerCheckinProcessingTime;
|
||||||
packetStream >> domainServerCheckinProcessingTime;
|
packetStream >> domainServerCheckinProcessingTime;
|
||||||
|
|
||||||
|
bool newConnection;
|
||||||
|
packetStream >> newConnection;
|
||||||
|
|
||||||
|
if (newConnection) {
|
||||||
|
_nodeConnectTimestamp = usecTimestampNow();
|
||||||
|
_connectReason = Connect;
|
||||||
|
}
|
||||||
|
|
||||||
qint64 pingLagTime = (now - qint64(connectRequestTimestamp)) / qint64(USECS_PER_MSEC);
|
qint64 pingLagTime = (now - qint64(connectRequestTimestamp)) / qint64(USECS_PER_MSEC);
|
||||||
|
|
||||||
qint64 domainServerRequestLag = (qint64(domainServerPingSendTime - domainServerCheckinProcessingTime) - qint64(connectRequestTimestamp)) / qint64(USECS_PER_MSEC);;
|
qint64 domainServerRequestLag = (qint64(domainServerPingSendTime - domainServerCheckinProcessingTime) - qint64(connectRequestTimestamp)) / qint64(USECS_PER_MSEC);;
|
||||||
|
|
|
@ -27,7 +27,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::StunResponse:
|
case PacketType::StunResponse:
|
||||||
return 17;
|
return 17;
|
||||||
case PacketType::DomainList:
|
case PacketType::DomainList:
|
||||||
return static_cast<PacketVersion>(DomainListVersion::HasTimestamp);
|
return static_cast<PacketVersion>(DomainListVersion::HasConnectReason);
|
||||||
case PacketType::EntityAdd:
|
case PacketType::EntityAdd:
|
||||||
case PacketType::EntityClone:
|
case PacketType::EntityClone:
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
|
@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
return static_cast<PacketVersion>(DomainConnectionDeniedVersion::IncludesExtraInfo);
|
return static_cast<PacketVersion>(DomainConnectionDeniedVersion::IncludesExtraInfo);
|
||||||
|
|
||||||
case PacketType::DomainConnectRequest:
|
case PacketType::DomainConnectRequest:
|
||||||
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasTimestamp);
|
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasReason);
|
||||||
|
|
||||||
case PacketType::DomainServerAddedNode:
|
case PacketType::DomainServerAddedNode:
|
||||||
return static_cast<PacketVersion>(DomainServerAddedNodeVersion::PermissionsGrid);
|
return static_cast<PacketVersion>(DomainServerAddedNodeVersion::PermissionsGrid);
|
||||||
|
|
|
@ -345,7 +345,8 @@ enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
HasMACAddress,
|
HasMACAddress,
|
||||||
HasMachineFingerprint,
|
HasMachineFingerprint,
|
||||||
AlwaysHasMachineFingerprint,
|
AlwaysHasMachineFingerprint,
|
||||||
HasTimestamp
|
HasTimestamp,
|
||||||
|
HasReason
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DomainConnectionDeniedVersion : PacketVersion {
|
enum class DomainConnectionDeniedVersion : PacketVersion {
|
||||||
|
@ -365,7 +366,8 @@ enum class DomainListVersion : PacketVersion {
|
||||||
GetUsernameFromUUIDSupport,
|
GetUsernameFromUUIDSupport,
|
||||||
GetMachineFingerprintFromUUIDSupport,
|
GetMachineFingerprintFromUUIDSupport,
|
||||||
AuthenticationOptional,
|
AuthenticationOptional,
|
||||||
HasTimestamp
|
HasTimestamp,
|
||||||
|
HasConnectReason
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AudioVersion : PacketVersion {
|
enum class AudioVersion : PacketVersion {
|
||||||
|
|
|
@ -63,8 +63,8 @@ void Socket::bind(const QHostAddress& address, quint16 port) {
|
||||||
auto sd = _udpSocket.socketDescriptor();
|
auto sd = _udpSocket.socketDescriptor();
|
||||||
int val = 0; // false
|
int val = 0; // false
|
||||||
if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAGMENT, (const char *)&val, sizeof(val))) {
|
if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAGMENT, (const char *)&val, sizeof(val))) {
|
||||||
int wsaError = WSAGetLastError();
|
auto wsaErr = WSAGetLastError();
|
||||||
qCWarning(networking) << "Socket::bind Cannot setsockopt IP_DONTFRAGMENT" << wsaError;
|
qCWarning(networking) << "Socket::bind Cannot setsockopt IP_DONTFRAGMENT" << wsaErr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,6 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc
|
||||||
#endif
|
#endif
|
||||||
qCDebug(networking) << "udt::writeDatagram (" << _udpSocket.state() << ") error - " << wsaError << _udpSocket.error() << "(" << _udpSocket.errorString() << ")"
|
qCDebug(networking) << "udt::writeDatagram (" << _udpSocket.state() << ") error - " << wsaError << _udpSocket.error() << "(" << _udpSocket.errorString() << ")"
|
||||||
<< (pending ? "pending bytes:" : "pending:") << pending;
|
<< (pending ? "pending bytes:" : "pending:") << pending;
|
||||||
|
|
||||||
#ifdef DEBUG_EVENT_QUEUE
|
#ifdef DEBUG_EVENT_QUEUE
|
||||||
int nodeListQueueSize = ::hifi::qt::getEventQueueSize(thread());
|
int nodeListQueueSize = ::hifi::qt::getEventQueueSize(thread());
|
||||||
qCDebug(networking) << "Networking queue size - " << nodeListQueueSize;
|
qCDebug(networking) << "Networking queue size - " << nodeListQueueSize;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "VrMenu.h"
|
#include "VrMenu.h"
|
||||||
|
|
||||||
#include "ui/Logging.h"
|
#include "ui/Logging.h"
|
||||||
|
#include "ui/ToolbarScriptingInterface.h"
|
||||||
|
|
||||||
#include <PointerManager.h>
|
#include <PointerManager.h>
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
@ -688,6 +689,10 @@ void OffscreenUi::createDesktop(const QUrl& url) {
|
||||||
menuInitializer(_vrMenu);
|
menuInitializer(_vrMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>();
|
||||||
|
connect(_desktop, SIGNAL(toolbarVisibleChanged(bool, QString)), toolbarScriptingInterface.data(), SIGNAL(toolbarVisibleChanged(bool, QString)));
|
||||||
|
|
||||||
auto keyboardFocus = new KeyboardFocusHack();
|
auto keyboardFocus = new KeyboardFocusHack();
|
||||||
connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
|
connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
|
||||||
emit desktopReady();
|
emit desktopReady();
|
||||||
|
|
|
@ -150,6 +150,9 @@ public:
|
||||||
* @returns {ToolbarProxy}
|
* @returns {ToolbarProxy}
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE ToolbarProxy* getToolbar(const QString& toolbarId);
|
Q_INVOKABLE ToolbarProxy* getToolbar(const QString& toolbarId);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void toolbarVisibleChanged(bool isVisible, QString toolbarName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -457,16 +457,18 @@ function onGeometryChanged(rect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var TIMEOUT_BEFORE_REHIDE_TOOLBAR_MS = 700;
|
|
||||||
function onDisplayModeChanged(isHMDMode) {
|
function onDisplayModeChanged(isHMDMode) {
|
||||||
if (isHMDMode) {
|
if (isHMDMode) {
|
||||||
Camera.setModeString("first person");
|
Camera.setModeString("first person");
|
||||||
} else if (Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false)) {
|
}
|
||||||
// works for now, but not a permanent fix by any means.
|
}
|
||||||
Script.setTimeout(function () {
|
|
||||||
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
|
function onToolbarVisibleChanged(isVisible, toolbarName) {
|
||||||
|
if (isVisible && toolbarName == TOOLBAR_NAME && !Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false)) {
|
||||||
|
var toolbar = Toolbars.getToolbar(toolbarName);
|
||||||
|
if (toolbar) {
|
||||||
toolbar.writeProperty("visible", false);
|
toolbar.writeProperty("visible", false);
|
||||||
}, TIMEOUT_BEFORE_REHIDE_TOOLBAR_MS);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +499,9 @@ function startup() {
|
||||||
|
|
||||||
if (!HMD.active) {
|
if (!HMD.active) {
|
||||||
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
|
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
|
||||||
toolbar.writeProperty("visible", false);
|
if (toolbar) {
|
||||||
|
toolbar.writeProperty("visible", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +521,7 @@ function startup() {
|
||||||
Audio.localInjectorGainChanged.connect(maybeUpdateOutputDeviceMutedOverlay);
|
Audio.localInjectorGainChanged.connect(maybeUpdateOutputDeviceMutedOverlay);
|
||||||
Audio.serverInjectorGainChanged.connect(maybeUpdateOutputDeviceMutedOverlay);
|
Audio.serverInjectorGainChanged.connect(maybeUpdateOutputDeviceMutedOverlay);
|
||||||
Audio.systemInjectorGainChanged.connect(maybeUpdateOutputDeviceMutedOverlay);
|
Audio.systemInjectorGainChanged.connect(maybeUpdateOutputDeviceMutedOverlay);
|
||||||
|
Toolbars.toolbarVisibleChanged.connect(onToolbarVisibleChanged);
|
||||||
|
|
||||||
oldShowAudioTools = AvatarInputs.showAudioTools;
|
oldShowAudioTools = AvatarInputs.showAudioTools;
|
||||||
AvatarInputs.showAudioTools = false;
|
AvatarInputs.showAudioTools = false;
|
||||||
|
@ -544,7 +549,7 @@ function shutdown() {
|
||||||
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
|
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
|
||||||
if (toolbar) {
|
if (toolbar) {
|
||||||
toolbar.writeProperty("visible", true);
|
toolbar.writeProperty("visible", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,6 +578,7 @@ function shutdown() {
|
||||||
Audio.localInjectorGainChanged.disconnect(maybeUpdateOutputDeviceMutedOverlay);
|
Audio.localInjectorGainChanged.disconnect(maybeUpdateOutputDeviceMutedOverlay);
|
||||||
Audio.serverInjectorGainChanged.disconnect(maybeUpdateOutputDeviceMutedOverlay);
|
Audio.serverInjectorGainChanged.disconnect(maybeUpdateOutputDeviceMutedOverlay);
|
||||||
Audio.systemInjectorGainChanged.disconnect(maybeUpdateOutputDeviceMutedOverlay);
|
Audio.systemInjectorGainChanged.disconnect(maybeUpdateOutputDeviceMutedOverlay);
|
||||||
|
Toolbars.toolbarVisibleChanged.disconnect(onToolbarVisibleChanged);
|
||||||
|
|
||||||
AvatarInputs.showAudioTools = oldShowAudioTools;
|
AvatarInputs.showAudioTools = oldShowAudioTools;
|
||||||
AvatarInputs.showBubbleTools = oldShowBubbleTools;
|
AvatarInputs.showBubbleTools = oldShowBubbleTools;
|
||||||
|
|
Loading…
Reference in a new issue