Merge branch 'master' into feature/ant-man

This commit is contained in:
Anthony J. Thibault 2017-09-08 14:08:26 -07:00
commit 72e0c844e4
48 changed files with 1000 additions and 713 deletions

View file

@ -27,11 +27,20 @@ Go to `Control Panel > System > Advanced System Settings > Environment Variables
* Set "Variable name": `QT_CMAKE_PREFIX_PATH` * Set "Variable name": `QT_CMAKE_PREFIX_PATH`
* Set "Variable value": `C:\Qt\5.9.1\msvc2017_64\lib\cmake` * Set "Variable value": `C:\Qt\5.9.1\msvc2017_64\lib\cmake`
### Step 5. Installing OpenSSL ### Step 5. Installing [vcpkg](https://github.com/Microsoft/vcpkg)
Download and install the Win64 OpenSSL v1.0.2 Installer[https://slproweb.com/products/Win32OpenSSL.html]. * Clone the VCPKG [repository](https://github.com/Microsoft/vcpkg)
* Follow the instructions in the [readme](https://github.com/Microsoft/vcpkg/blob/master/README.md) to bootstrap vcpkg
* Note, you may need to do these in a _Developer Command Prompt_
* Set an environment variable VCPKG_ROOT to the location of the cloned repository
* Close and re-open any command prompts after setting the environment variable so that they will pick up the change
### Step 6. Running CMake to Generate Build Files ### Step 6. Installing OpenSSL via vcpkg
* In the vcpkg directory, install the 64 bit OpenSSL package with the command `vcpkg install openssl:x64-windows`
* Once the build completes you should have a file `ssl.h` in `${VCPKG_ROOT}/installed/x64-windows/include/openssl`
### Step 7. Running CMake to Generate Build Files
Run Command Prompt from Start and run the following commands: Run Command Prompt from Start and run the following commands:
``` ```
@ -43,7 +52,7 @@ cmake .. -G "Visual Studio 15 Win64"
Where `%HIFI_DIR%` is the directory for the highfidelity repository. Where `%HIFI_DIR%` is the directory for the highfidelity repository.
### Step 7. Making a Build ### Step 8. Making a Build
Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio. Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
@ -51,7 +60,7 @@ Change the Solution Configuration (next to the green play button) from "Debug" t
Run `Build > Build Solution`. Run `Build > Build Solution`.
### Step 8. Testing Interface ### Step 9. Testing Interface
Create another environment variable (see Step #4) Create another environment variable (see Step #4)
* Set "Variable name": `_NO_DEBUG_HEAP` * Set "Variable name": `_NO_DEBUG_HEAP`
@ -65,16 +74,20 @@ Note: You can also run Interface by launching it from command line or File Explo
## Troubleshooting ## Troubleshooting
For any problems after Step #6, first try this: For any problems after Step #7, first try this:
* Delete your locally cloned copy of the highfidelity repository * Delete your locally cloned copy of the highfidelity repository
* Restart your computer * Restart your computer
* Redownload the [repository](https://github.com/highfidelity/hifi) * Redownload the [repository](https://github.com/highfidelity/hifi)
* Restart directions from Step #6 * Restart directions from Step #7
#### CMake gives you the same error message repeatedly after the build fails #### CMake gives you the same error message repeatedly after the build fails
Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory. Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory.
#### CMake can't find OpenSSL
Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory. Verify that your VCPKG_ROOT environment variable is set and pointing to the correct location. Verify that the file `${VCPKG_ROOT}/installed/x64-windows/include/openssl/ssl.h` exists.
#### Qt is throwing an error #### Qt is throwing an error
Make sure you have the correct version (5.9.1) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly. Make sure you have the correct version (5.9.1) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly.

Binary file not shown.

View file

@ -558,7 +558,7 @@ float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const Positio
// produce an oriented angle about the y-axis // produce an oriented angle about the y-axis
glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2)); glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2));
float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
return (direction.x < 0.0f) ? -angle : angle; return (direction.x < 0.0f) ? -angle : angle;
} else { } else {

View file

@ -458,84 +458,80 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode*
return _truePacketsSent; return _truePacketsSent;
} }
bool OctreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params) {
bool somethingToSend = false;
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(params.nodeData);
if (!nodeData->elementBag.isEmpty()) {
quint64 encodeStart = usecTimestampNow();
quint64 lockWaitStart = encodeStart;
_myServer->getOctree()->withReadLock([&]{
OctreeServer::trackTreeWaitTime((float)(usecTimestampNow() - lockWaitStart));
OctreeElementPointer subTree = nodeData->elementBag.extract();
if (subTree) {
// NOTE: this is where the tree "contents" are actually packed
nodeData->stats.encodeStarted();
_myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->elementBag, params);
nodeData->stats.encodeStopped();
somethingToSend = true;
}
});
OctreeServer::trackEncodeTime((float)(usecTimestampNow() - encodeStart));
} else {
OctreeServer::trackTreeWaitTime(OctreeServer::SKIP_TIME);
OctreeServer::trackEncodeTime(OctreeServer::SKIP_TIME);
}
return somethingToSend;
}
void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) { void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) {
// calculate max number of packets that can be sent during this interval // calculate max number of packets that can be sent during this interval
int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND)); int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND));
int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval());
int extraPackingAttempts = 0; int extraPackingAttempts = 0;
bool completedScene = false;
// init params once outside the while loop
int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust();
int boundaryLevelAdjust = boundaryLevelAdjustClient +
(viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
float octreeSizeScale = nodeData->getOctreeSizeScale();
EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP,
viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale,
isFullScene, _myServer->getJurisdiction(), nodeData);
// Our trackSend() function is implemented by the server subclass, and will be called back
// during the encodeTreeBitstream() as new entities/data elements are sent
params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) {
_myServer->trackSend(dataID, dataEdited, _nodeUuid);
};
nodeData->copyCurrentViewFrustum(params.viewFrustum);
if (viewFrustumChanged) {
nodeData->copyLastKnownViewFrustum(params.lastViewFrustum);
}
bool somethingToSend = true; // assume we have something bool somethingToSend = true; // assume we have something
bool bagHadSomething = !nodeData->elementBag.isEmpty();
while (somethingToSend && _packetsSentThisInterval < maxPacketsPerInterval && !nodeData->isShuttingDown()) { while (somethingToSend && _packetsSentThisInterval < maxPacketsPerInterval && !nodeData->isShuttingDown()) {
float lockWaitElapsedUsec = OctreeServer::SKIP_TIME;
float encodeElapsedUsec = OctreeServer::SKIP_TIME;
float compressAndWriteElapsedUsec = OctreeServer::SKIP_TIME; float compressAndWriteElapsedUsec = OctreeServer::SKIP_TIME;
float packetSendingElapsedUsec = OctreeServer::SKIP_TIME; float packetSendingElapsedUsec = OctreeServer::SKIP_TIME;
quint64 startInside = usecTimestampNow(); quint64 startInside = usecTimestampNow();
bool lastNodeDidntFit = false; // assume each node fits bool lastNodeDidntFit = false; // assume each node fits
if (!nodeData->elementBag.isEmpty()) { params.stopReason = EncodeBitstreamParams::UNKNOWN; // reset params.stopReason before traversal
quint64 lockWaitStart = usecTimestampNow(); somethingToSend = traverseTreeAndBuildNextPacketPayload(params);
_myServer->getOctree()->withReadLock([&]{
quint64 lockWaitEnd = usecTimestampNow();
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
quint64 encodeStart = usecTimestampNow();
OctreeElementPointer subTree = nodeData->elementBag.extract(); if (params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
if (!subTree) { lastNodeDidntFit = true;
return; extraPackingAttempts++;
}
float octreeSizeScale = nodeData->getOctreeSizeScale();
int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust();
int boundaryLevelAdjust = boundaryLevelAdjustClient +
(viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP,
viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale,
isFullScene, _myServer->getJurisdiction(), nodeData);
nodeData->copyCurrentViewFrustum(params.viewFrustum);
if (viewFrustumChanged) {
nodeData->copyLastKnownViewFrustum(params.lastViewFrustum);
}
// Our trackSend() function is implemented by the server subclass, and will be called back
// during the encodeTreeBitstream() as new entities/data elements are sent
params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) {
_myServer->trackSend(dataID, dataEdited, _nodeUuid);
};
// TODO: should this include the lock time or not? This stat is sent down to the client,
// it seems like it may be a good idea to include the lock time as part of the encode time
// are reported to client. Since you can encode without the lock
nodeData->stats.encodeStarted();
// NOTE: this is where the tree "contents" are actaully packed
_myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->elementBag, params);
quint64 encodeEnd = usecTimestampNow();
encodeElapsedUsec = (float)(encodeEnd - encodeStart);
// If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've
// sent the entire scene. We want to know this below so we'll actually write this content into
// the packet and send it
completedScene = nodeData->elementBag.isEmpty();
if (params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
lastNodeDidntFit = true;
extraPackingAttempts++;
}
nodeData->stats.encodeStopped();
});
} else {
somethingToSend = false; // this will cause us to drop out of the loop...
} }
// If the bag had contents but is now empty then we know we've sent the entire scene.
bool completedScene = bagHadSomething && nodeData->elementBag.isEmpty();
if (completedScene || lastNodeDidntFit) { if (completedScene || lastNodeDidntFit) {
// we probably want to flush what has accumulated in nodeData but: // we probably want to flush what has accumulated in nodeData but:
// do we have more data to send? and is there room? // do we have more data to send? and is there room?
@ -562,8 +558,7 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre
if (sendNow) { if (sendNow) {
quint64 packetSendingStart = usecTimestampNow(); quint64 packetSendingStart = usecTimestampNow();
_packetsSentThisInterval += handlePacketSend(node, nodeData); _packetsSentThisInterval += handlePacketSend(node, nodeData);
quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(usecTimestampNow() - packetSendingStart);
packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart);
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
extraPackingAttempts = 0; extraPackingAttempts = 0;
@ -576,14 +571,9 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre
} }
_packetData.changeSettings(true, targetSize); // will do reset - NOTE: Always compressed _packetData.changeSettings(true, targetSize); // will do reset - NOTE: Always compressed
} }
OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec);
OctreeServer::trackEncodeTime(encodeElapsedUsec);
OctreeServer::trackCompressAndWriteTime(compressAndWriteElapsedUsec); OctreeServer::trackCompressAndWriteTime(compressAndWriteElapsedUsec);
OctreeServer::trackPacketSendingTime(packetSendingElapsedUsec); OctreeServer::trackPacketSendingTime(packetSendingElapsedUsec);
OctreeServer::trackInsideTime((float)(usecTimestampNow() - startInside));
quint64 endInside = usecTimestampNow();
quint64 elapsedInsideUsecs = endInside - startInside;
OctreeServer::trackInsideTime((float)elapsedInsideUsecs);
} }
if (somethingToSend && _myServer->wantsVerboseDebug()) { if (somethingToSend && _myServer->wantsVerboseDebug()) {

View file

@ -53,7 +53,9 @@ protected:
/// Called before a packetDistributor pass to allow for pre-distribution processing /// Called before a packetDistributor pass to allow for pre-distribution processing
virtual void preDistributionProcessing() {}; virtual void preDistributionProcessing() {};
virtual void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene); virtual void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
bool viewFrustumChanged, bool isFullScene);
virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params);
OctreeServer* _myServer { nullptr }; OctreeServer* _myServer { nullptr };
QWeakPointer<Node> _node; QWeakPointer<Node> _node;

View file

@ -35,7 +35,7 @@
#include <QtCore/QDir> #include <QtCore/QDir>
int OctreeServer::_clientCount = 0; int OctreeServer::_clientCount = 0;
const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000;
float OctreeServer::SKIP_TIME = -1.0f; // use this for trackXXXTime() calls for non-times float OctreeServer::SKIP_TIME = -1.0f; // use this for trackXXXTime() calls for non-times
@ -136,18 +136,19 @@ void OctreeServer::trackEncodeTime(float time) {
if (time == SKIP_TIME) { if (time == SKIP_TIME) {
_noEncode++; _noEncode++;
time = 0.0f;
} else if (time <= MAX_SHORT_TIME) {
_shortEncode++;
_averageShortEncodeTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longEncode++;
_averageLongEncodeTime.updateAverage(time);
} else { } else {
_extraLongEncode++; if (time <= MAX_SHORT_TIME) {
_averageExtraLongEncodeTime.updateAverage(time); _shortEncode++;
_averageShortEncodeTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longEncode++;
_averageLongEncodeTime.updateAverage(time);
} else {
_extraLongEncode++;
_averageExtraLongEncodeTime.updateAverage(time);
}
_averageEncodeTime.updateAverage(time);
} }
_averageEncodeTime.updateAverage(time);
} }
void OctreeServer::trackTreeWaitTime(float time) { void OctreeServer::trackTreeWaitTime(float time) {
@ -155,18 +156,19 @@ void OctreeServer::trackTreeWaitTime(float time) {
const float MAX_LONG_TIME = 100.0f; const float MAX_LONG_TIME = 100.0f;
if (time == SKIP_TIME) { if (time == SKIP_TIME) {
_noTreeWait++; _noTreeWait++;
time = 0.0f;
} else if (time <= MAX_SHORT_TIME) {
_shortTreeWait++;
_averageTreeShortWaitTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longTreeWait++;
_averageTreeLongWaitTime.updateAverage(time);
} else { } else {
_extraLongTreeWait++; if (time <= MAX_SHORT_TIME) {
_averageTreeExtraLongWaitTime.updateAverage(time); _shortTreeWait++;
_averageTreeShortWaitTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longTreeWait++;
_averageTreeLongWaitTime.updateAverage(time);
} else {
_extraLongTreeWait++;
_averageTreeExtraLongWaitTime.updateAverage(time);
}
_averageTreeWaitTime.updateAverage(time);
} }
_averageTreeWaitTime.updateAverage(time);
} }
void OctreeServer::trackCompressAndWriteTime(float time) { void OctreeServer::trackCompressAndWriteTime(float time) {
@ -174,26 +176,27 @@ void OctreeServer::trackCompressAndWriteTime(float time) {
const float MAX_LONG_TIME = 100.0f; const float MAX_LONG_TIME = 100.0f;
if (time == SKIP_TIME) { if (time == SKIP_TIME) {
_noCompress++; _noCompress++;
time = 0.0f;
} else if (time <= MAX_SHORT_TIME) {
_shortCompress++;
_averageShortCompressTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longCompress++;
_averageLongCompressTime.updateAverage(time);
} else { } else {
_extraLongCompress++; if (time <= MAX_SHORT_TIME) {
_averageExtraLongCompressTime.updateAverage(time); _shortCompress++;
_averageShortCompressTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longCompress++;
_averageLongCompressTime.updateAverage(time);
} else {
_extraLongCompress++;
_averageExtraLongCompressTime.updateAverage(time);
}
_averageCompressAndWriteTime.updateAverage(time);
} }
_averageCompressAndWriteTime.updateAverage(time);
} }
void OctreeServer::trackPacketSendingTime(float time) { void OctreeServer::trackPacketSendingTime(float time) {
if (time == SKIP_TIME) { if (time == SKIP_TIME) {
_noSend++; _noSend++;
time = 0.0f; } else {
_averagePacketSendingTime.updateAverage(time);
} }
_averagePacketSendingTime.updateAverage(time);
} }
@ -202,18 +205,19 @@ void OctreeServer::trackProcessWaitTime(float time) {
const float MAX_LONG_TIME = 100.0f; const float MAX_LONG_TIME = 100.0f;
if (time == SKIP_TIME) { if (time == SKIP_TIME) {
_noProcessWait++; _noProcessWait++;
time = 0.0f;
} else if (time <= MAX_SHORT_TIME) {
_shortProcessWait++;
_averageProcessShortWaitTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longProcessWait++;
_averageProcessLongWaitTime.updateAverage(time);
} else { } else {
_extraLongProcessWait++; if (time <= MAX_SHORT_TIME) {
_averageProcessExtraLongWaitTime.updateAverage(time); _shortProcessWait++;
_averageProcessShortWaitTime.updateAverage(time);
} else if (time <= MAX_LONG_TIME) {
_longProcessWait++;
_averageProcessLongWaitTime.updateAverage(time);
} else {
_extraLongProcessWait++;
_averageProcessExtraLongWaitTime.updateAverage(time);
}
_averageProcessWaitTime.updateAverage(time);
} }
_averageProcessWaitTime.updateAverage(time);
} }
OctreeServer::OctreeServer(ReceivedMessage& message) : OctreeServer::OctreeServer(ReceivedMessage& message) :

View file

@ -133,7 +133,7 @@ macro(SET_PACKAGING_PARAMETERS)
else() else()
message( FATAL_ERROR "Visual Studio 2013 or higher required." ) message( FATAL_ERROR "Visual Studio 2013 or higher required." )
endif() endif()
if (NOT SIGNTOOL_EXECUTABLE) if (NOT SIGNTOOL_EXECUTABLE)
message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.")
endif () endif ()
@ -147,6 +147,7 @@ macro(SET_PACKAGING_PARAMETERS)
set(CONSOLE_STARTUP_REG_KEY "ConsoleStartupShortcut") set(CONSOLE_STARTUP_REG_KEY "ConsoleStartupShortcut")
set(CLIENT_LAUNCH_NOW_REG_KEY "ClientLaunchAfterInstall") set(CLIENT_LAUNCH_NOW_REG_KEY "ClientLaunchAfterInstall")
set(SERVER_LAUNCH_NOW_REG_KEY "ServerLaunchAfterInstall") set(SERVER_LAUNCH_NOW_REG_KEY "ServerLaunchAfterInstall")
set(CUSTOM_INSTALL_REG_KEY "CustomInstall")
endif () endif ()
# setup component categories for installer # setup component categories for installer

View file

@ -34,26 +34,11 @@ if (UNIX)
endif () endif ()
if (WIN32) if (WIN32)
if (("${CMAKE_SIZEOF_VOID_P}" EQUAL "8"))
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) set(_OPENSSL_ROOT_HINTS_AND_PATHS $ENV{VCPKG_ROOT}/installed/x64-windows)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
# http://www.slproweb.com/products/Win32OpenSSL.html
set(_OPENSSL_ROOT_HINTS ${OPENSSL_ROOT_DIR} $ENV{OPENSSL_ROOT_DIR} $ENV{HIFI_LIB_DIR}/openssl
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
)
set(_OPENSSL_ROOT_PATHS "${_programfiles}/OpenSSL" "${_programfiles}/OpenSSL-Win64" "C:/OpenSSL/" "C:/OpenSSL-Win64/")
else() else()
# http://www.slproweb.com/products/Win32OpenSSL.html set(_OPENSSL_ROOT_HINTS_AND_PATHS $ENV{VCPKG_ROOT}/installed/x86-windows)
set(_OPENSSL_ROOT_HINTS ${OPENSSL_ROOT_DIR} $ENV{OPENSSL_ROOT_DIR} $ENV{HIFI_LIB_DIR}/openssl
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
)
set(_OPENSSL_ROOT_PATHS "${_programfiles}/OpenSSL" "${_programfiles}/OpenSSL-Win32" "C:/OpenSSL/" "C:/OpenSSL-Win32/")
endif() endif()
unset(_programfiles)
set(_OPENSSL_ROOT_HINTS_AND_PATHS HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS})
else () else ()
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("openssl") hifi_library_search_hints("openssl")
@ -67,47 +52,14 @@ find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AN
if (WIN32 AND NOT CYGWIN) if (WIN32 AND NOT CYGWIN)
if (MSVC) if (MSVC)
# Using vcpkg builds of openssl
# In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix: find_library(LIB_EAY_LIBRARY_RELEASE NAMES libeay32 HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib")
# * MD for dynamic-release find_library(SSL_EAY_LIBRARY_RELEASE NAMES ssleay32 HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib")
# * MDd for dynamic-debug
# * MT for static-release
# * MTd for static-debug
# Implementation details:
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
# libeay32MD.lib is identical to ../libeay32.lib, and
# ssleay32MD.lib is identical to ../ssleay32.lib
# The Kitware FindOpenSSL module has been modified here by High Fidelity to look specifically for static libraries
find_library(LIB_EAY_DEBUG NAMES libeay32MTd
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
find_library(LIB_EAY_RELEASE NAMES libeay32MT
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
find_library(SSL_EAY_DEBUG NAMES ssleay32MTd
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
find_library(SSL_EAY_RELEASE NAMES ssleay32MT
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}")
set(LIB_EAY_LIBRARY_RELEASE "${LIB_EAY_RELEASE}")
set(SSL_EAY_LIBRARY_DEBUG "${SSL_EAY_DEBUG}")
set(SSL_EAY_LIBRARY_RELEASE "${SSL_EAY_RELEASE}")
include(SelectLibraryConfigurations) include(SelectLibraryConfigurations)
select_library_configurations(LIB_EAY) select_library_configurations(LIB_EAY)
select_library_configurations(SSL_EAY) select_library_configurations(SSL_EAY)
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY}) set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS}) find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
endif() endif()
else() else()

View file

@ -40,6 +40,7 @@ set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@")
set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@") set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@")
set(SERVER_LAUNCH_NOW_REG_KEY "@SERVER_LAUNCH_NOW_REG_KEY@") set(SERVER_LAUNCH_NOW_REG_KEY "@SERVER_LAUNCH_NOW_REG_KEY@")
set(CLIENT_LAUNCH_NOW_REG_KEY "@CLIENT_LAUNCH_NOW_REG_KEY@") set(CLIENT_LAUNCH_NOW_REG_KEY "@CLIENT_LAUNCH_NOW_REG_KEY@")
set(CUSTOM_INSTALL_REG_KEY "@CUSTOM_INSTALL_REG_KEY@")
set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@") set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@")
set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@") set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@")
set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@") set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")

View file

@ -49,7 +49,7 @@
Var STR_CONTAINS_VAR_3 Var STR_CONTAINS_VAR_3
Var STR_CONTAINS_VAR_4 Var STR_CONTAINS_VAR_4
Var STR_RETURN_VAR Var STR_RETURN_VAR
Function StrContains Function StrContains
Exch $STR_NEEDLE Exch $STR_NEEDLE
Exch 1 Exch 1
@ -343,29 +343,29 @@ SectionEnd
;-------------------------------- ;--------------------------------
;Pages ;Pages
!insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
Page custom InstallTypesPage ReadInstallTypes Page custom InstallTypesPage ReadInstallTypes
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
!insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_DIRECTORY
;Start Menu Folder Page Configuration ;Start Menu Folder Page Configuration
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
!define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction !define MUI_PAGE_CUSTOMFUNCTION_PRE AbortFunction
@CPACK_NSIS_PAGE_COMPONENTS@ @CPACK_NSIS_PAGE_COMPONENTS@
Page custom PostInstallOptionsPage ReadPostInstallOptions Page custom PostInstallOptionsPage ReadPostInstallOptions
!insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_INSTFILES
@ -453,9 +453,10 @@ Var ExpressInstallRadioButton
Var CustomInstallRadioButton Var CustomInstallRadioButton
Var InstallTypeDialog Var InstallTypeDialog
Var Express Var Express
Var CustomInstallTemporaryState
!macro SetPostInstallOption Checkbox OptionName Default !macro SetInstallOption Checkbox OptionName Default
; reads the value for the given post install option to the registry ; reads the value for the given install option to the registry
ReadRegStr $0 HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ReadRegStr $0 HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}"
${If} $0 == "NO" ${If} $0 == "NO"
@ -472,31 +473,39 @@ Var Express
Function InstallTypesPage Function InstallTypesPage
!insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install" !insertmacro MUI_HEADER_TEXT "Choose Installation Type" "Express or Custom Install"
nsDialogs::Create 1018 nsDialogs::Create 1018
Pop $InstallTypeDialog Pop $InstallTypeDialog
${If} $InstallTypeDialog == error ${If} $InstallTypeDialog == error
Abort Abort
${EndIf} ${EndIf}
StrCpy $CurrentOffset 0 StrCpy $CurrentOffset 0
StrCpy $OffsetUnits u StrCpy $OffsetUnits u
StrCpy $Express "0" StrCpy $Express "0"
${NSD_CreateRadioButton} 30% $CurrentOffset$OffsetUnits 100% 10u "Express Install (Recommended)"; $\nInstalls High Fidelity Interface and High Fidelity Sandbox" ${NSD_CreateRadioButton} 30% $CurrentOffset$OffsetUnits 100% 10u "Express Install (Recommended)"; $\nInstalls High Fidelity Interface and High Fidelity Sandbox"
pop $ExpressInstallRadioButton pop $ExpressInstallRadioButton
${NSD_OnClick} $ExpressInstallRadioButton ChangeExpressLabel ${NSD_OnClick} $ExpressInstallRadioButton ChangeExpressLabel
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
${NSD_CreateRadiobutton} 30% $CurrentOffset$OffsetUnits 100% 10u "Custom Install (Advanced)" ${NSD_CreateRadiobutton} 30% $CurrentOffset$OffsetUnits 100% 10u "Custom Install (Advanced)"
pop $CustomInstallRadioButton pop $CustomInstallRadioButton
${NSD_OnClick} $CustomInstallRadioButton ChangeCustomLabel ${NSD_OnClick} $CustomInstallRadioButton ChangeCustomLabel
; Express Install selected by default ; check install type from the registry, express install by default
${NSD_Check} $ExpressInstallRadioButton !insertmacro SetInstallOption $CustomInstallRadioButton @CUSTOM_INSTALL_REG_KEY@ ${BST_UNCHECKED}
; set the express install value based on the custom install value from registry
${NSD_GetState} $CustomInstallRadioButton $CustomInstallTemporaryState
${If} $CustomInstallTemporaryState == ${BST_UNCHECKED}
${NSD_Check} $ExpressInstallRadioButton
${EndIf}
Call ChangeExpressLabel Call ChangeExpressLabel
nsDialogs::Show nsDialogs::Show
FunctionEnd FunctionEnd
@ -519,18 +528,18 @@ Function AbortFunction
StrCmp $Express "1" 0 end StrCmp $Express "1" 0 end
Abort Abort
end: end:
FunctionEnd FunctionEnd
Function PostInstallOptionsPage Function PostInstallOptionsPage
!insertmacro MUI_HEADER_TEXT "Setup Options" "" !insertmacro MUI_HEADER_TEXT "Setup Options" ""
nsDialogs::Create 1018 nsDialogs::Create 1018
Pop $PostInstallDialog Pop $PostInstallDialog
${If} $PostInstallDialog == error ${If} $PostInstallDialog == error
Abort Abort
${EndIf} ${EndIf}
; Check if Express is set, if so, abort the post install options page ; Check if Express is set, if so, abort the post install options page
StrCmp $Express "1" 0 end StrCmp $Express "1" 0 end
Abort Abort
@ -543,18 +552,18 @@ Function PostInstallOptionsPage
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@"
Pop $DesktopClientCheckbox Pop $DesktopClientCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
; set the checkbox state depending on what is present in the registry ; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} !insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
Pop $DesktopServerCheckbox Pop $DesktopServerCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
; set the checkbox state depending on what is present in the registry ; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} !insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
@ -562,7 +571,7 @@ Function PostInstallOptionsPage
Pop $LaunchServerNowCheckbox Pop $LaunchServerNowCheckbox
; set the checkbox state depending on what is present in the registry ; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $LaunchServerNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} !insertmacro SetInstallOption $LaunchServerNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED}
${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE
${IfNot} $substringResult == "" ${IfNot} $substringResult == ""
${NSD_SetState} $LaunchServerNowCheckbox ${BST_UNCHECKED} ${NSD_SetState} $LaunchServerNowCheckbox ${BST_UNCHECKED}
@ -570,29 +579,29 @@ Function PostInstallOptionsPage
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
Pop $LaunchClientNowCheckbox Pop $LaunchClientNowCheckbox
IntOp $CurrentOffset $CurrentOffset + 30 IntOp $CurrentOffset $CurrentOffset + 30
; set the checkbox state depending on what is present in the registry ; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $LaunchClientNowCheckbox @CLIENT_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} !insertmacro SetInstallOption $LaunchClientNowCheckbox @CLIENT_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED}
${StrContains} $substringResult "/forceNoLaunchClient" $CMDLINE ${StrContains} $substringResult "/forceNoLaunchClient" $CMDLINE
${IfNot} $substringResult == "" ${IfNot} $substringResult == ""
${NSD_SetState} $LaunchClientNowCheckbox ${BST_UNCHECKED} ${NSD_SetState} $LaunchClientNowCheckbox ${BST_UNCHECKED}
${EndIf} ${EndIf}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
Pop $ServerStartupCheckbox Pop $ServerStartupCheckbox
IntOp $CurrentOffset $CurrentOffset + 15 IntOp $CurrentOffset $CurrentOffset + 15
; set the checkbox state depending on what is present in the registry ; set the checkbox state depending on what is present in the registry
!insertmacro SetPostInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} !insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)" ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
Pop $CleanInstallCheckbox Pop $CleanInstallCheckbox
@ -618,12 +627,12 @@ Function PostInstallOptionsPage
${NSD_SetState} $CopyFromProductionCheckbox ${BST_UNCHECKED} ${NSD_SetState} $CopyFromProductionCheckbox ${BST_UNCHECKED}
${EndIf} ${EndIf}
nsDialogs::Show nsDialogs::Show
FunctionEnd FunctionEnd
!macro WritePostInstallOption OptionName Option !macro WriteInstallOption OptionName Option
; writes the value for the given post install option to the registry ; writes the value for the given install option to the registry
WriteRegStr HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ${Option} WriteRegStr HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ${Option}
!macroend !macroend
@ -641,12 +650,12 @@ Function ReadInstallTypes
; check if the user asked for express/custom install ; check if the user asked for express/custom install
${NSD_GetState} $ExpressInstallRadioButton $ExpressInstallState ${NSD_GetState} $ExpressInstallRadioButton $ExpressInstallState
${NSD_GetState} $CustomInstallRadioButton $CustomInstallState ${NSD_GetState} $CustomInstallRadioButton $CustomInstallState
${If} $ExpressInstallState == ${BST_CHECKED} ${If} $ExpressInstallState == ${BST_CHECKED}
StrCpy $Express "1" StrCpy $Express "1"
StrCpy $DesktopClientState ${BST_CHECKED} StrCpy $DesktopClientState ${BST_CHECKED}
StrCpy $ServerStartupState ${BST_CHECKED} StrCpy $ServerStartupState ${BST_CHECKED}
StrCpy $LaunchServerNowState ${BST_CHECKED} StrCpy $LaunchServerNowState ${BST_CHECKED}
StrCpy $LaunchClientNowState ${BST_CHECKED} StrCpy $LaunchClientNowState ${BST_CHECKED}
StrCpy $CleanInstallState ${BST_UNCHECKED} StrCpy $CleanInstallState ${BST_UNCHECKED}
@ -655,9 +664,12 @@ Function ReadInstallTypes
${If} @PR_BUILD@ == 1 ${If} @PR_BUILD@ == 1
StrCpy $CopyFromProductionState ${BST_UNCHECKED} StrCpy $CopyFromProductionState ${BST_UNCHECKED}
${EndIf} ${EndIf}
!insertmacro WriteInstallOption "@CUSTOM_INSTALL_REG_KEY@" NO
${Else}
!insertmacro WriteInstallOption "@CUSTOM_INSTALL_REG_KEY@" YES
${EndIf} ${EndIf}
FunctionEnd FunctionEnd
Function ReadPostInstallOptions Function ReadPostInstallOptions
@ -683,12 +695,12 @@ Function ReadPostInstallOptions
; check if we need to launch the server post-install ; check if we need to launch the server post-install
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState ${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
; check if we need to launch the client post-install ; check if we need to launch the client post-install
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState ${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
; check if the user asked for a clean install ; check if the user asked for a clean install
${NSD_GetState} $CleanInstallCheckbox $CleanInstallState ${NSD_GetState} $CleanInstallCheckbox $CleanInstallState
@ -700,9 +712,9 @@ Function HandlePostInstallOptions
; check if the user asked for a desktop shortcut to High Fidelity ; check if the user asked for a desktop shortcut to High Fidelity
${If} $DesktopClientState == ${BST_CHECKED} ${If} $DesktopClientState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
!insertmacro WritePostInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" YES !insertmacro WriteInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" YES
${Else} ${Else}
!insertmacro WritePostInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ NO !insertmacro WriteInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ NO
${EndIf} ${EndIf}
${EndIf} ${EndIf}
@ -711,12 +723,12 @@ Function HandlePostInstallOptions
; check if the user asked for a desktop shortcut to Sandbox ; check if the user asked for a desktop shortcut to Sandbox
${If} $DesktopServerState == ${BST_CHECKED} ${If} $DesktopServerState == ${BST_CHECKED}
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
!insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES
${Else} ${Else}
!insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO
${EndIf} ${EndIf}
; check if the user asked to have Sandbox launched every startup ; check if the user asked to have Sandbox launched every startup
${If} $ServerStartupState == ${BST_CHECKED} ${If} $ServerStartupState == ${BST_CHECKED}
; in case we added a shortcut in the global context, pull that now ; in case we added a shortcut in the global context, pull that now
@ -730,12 +742,12 @@ Function HandlePostInstallOptions
; reset the shell var context back ; reset the shell var context back
SetShellVarContext all SetShellVarContext all
!insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ YES !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ YES
${Else} ${Else}
!insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ NO !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ NO
${EndIf} ${EndIf}
${EndIf} ${EndIf}
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
; check if the user asked for a clean install ; check if the user asked for a clean install
${If} $CleanInstallState == ${BST_CHECKED} ${If} $CleanInstallState == ${BST_CHECKED}
@ -774,28 +786,28 @@ Function HandlePostInstallOptions
${EndIf} ${EndIf}
${If} $LaunchServerNowState == ${BST_CHECKED} ${If} $LaunchServerNowState == ${BST_CHECKED}
!insertmacro WritePostInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES !insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES
; both launches use the explorer trick in case the user has elevated permissions for the installer ; both launches use the explorer trick in case the user has elevated permissions for the installer
${If} $LaunchClientNowState == ${BST_CHECKED} ${If} $LaunchClientNowState == ${BST_CHECKED}
!insertmacro WritePostInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ YES !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ YES
; create shortcut with ARGUMENTS ; create shortcut with ARGUMENTS
CreateShortCut "$TEMP\SandboxShortcut.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "-- --launchInterface" CreateShortCut "$TEMP\SandboxShortcut.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "-- --launchInterface"
Exec '"$WINDIR\explorer.exe" "$TEMP\SandboxShortcut.lnk"' Exec '"$WINDIR\explorer.exe" "$TEMP\SandboxShortcut.lnk"'
${Else} ${Else}
!insertmacro WritePostInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ NO !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ NO
Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"' Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"'
${EndIf} ${EndIf}
${Else} ${Else}
!insertmacro WritePostInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO !insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO
; launch uses the explorer trick in case the user has elevated permissions for the installer ; launch uses the explorer trick in case the user has elevated permissions for the installer
${If} $LaunchClientNowState == ${BST_CHECKED} ${If} $LaunchClientNowState == ${BST_CHECKED}
!insertmacro WritePostInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ YES !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ YES
Exec '"$WINDIR\explorer.exe" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"' Exec '"$WINDIR\explorer.exe" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"'
${Else} ${Else}
!insertmacro WritePostInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ NO !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ NO
${EndIf} ${EndIf}
${EndIf} ${EndIf}
@ -843,7 +855,7 @@ Section "-Core installation"
Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml" Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml"
ExecWait "$INSTDIR\vcredist_x64.exe /install /q /norestart" ExecWait "$INSTDIR\vcredist_x64.exe /install /q /norestart"
; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console) ; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console)
RMDir /r "$INSTDIR\Interface" RMDir /r "$INSTDIR\Interface"
Delete "$INSTDIR\vcredist_x64.exe" Delete "$INSTDIR\vcredist_x64.exe"
@ -943,9 +955,9 @@ Section "-Core installation"
Call ConditionalAddToRegisty Call ConditionalAddToRegisty
!insertmacro MUI_STARTMENU_WRITE_END !insertmacro MUI_STARTMENU_WRITE_END
@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
; Handle whichever post install options were set ; Handle whichever post install options were set
Call HandlePostInstallOptions Call HandlePostInstallOptions
@ -963,9 +975,18 @@ SectionEnd
${If} $R0 == 0 ${If} $R0 == 0
; the process is running, ask the user to close it ; the process is running, ask the user to close it
${If} "${displayName}" == "@CONSOLE_DISPLAY_NAME@"
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION \ MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION \
"${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close it and click Retry to continue." \ "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close it in the system tray and click Retry to continue." \
/SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0 /SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0
${EndIf}
${If} "${displayName}" == "@INTERFACE_DISPLAY_NAME@"
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION \
"${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close it in the task bar and click Retry to continue." \
/SD IDCANCEL IDRETRY Prompt_${UniqueID} IDCANCEL 0
${EndIf}
; If the user decided to cancel, stop the current installer/uninstaller ; If the user decided to cancel, stop the current installer/uninstaller
Abort Abort

View file

@ -752,8 +752,28 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
} }
void DomainServer::updateICEServerAddresses() { void DomainServer::updateICEServerAddresses() {
if (_iceAddressLookupID == -1) { if (_iceAddressLookupID == INVALID_ICE_LOOKUP_ID) {
_iceAddressLookupID = QHostInfo::lookupHost(_iceServerAddr, this, SLOT(handleICEHostInfo(QHostInfo))); _iceAddressLookupID = QHostInfo::lookupHost(_iceServerAddr, this, SLOT(handleICEHostInfo(QHostInfo)));
// there seems to be a 5.9 bug where lookupHost never calls our slot
// so we add a single shot manual "timeout" to fire it off again if it hasn't called back yet
static const int ICE_ADDRESS_LOOKUP_TIMEOUT_MS = 5000;
QTimer::singleShot(ICE_ADDRESS_LOOKUP_TIMEOUT_MS, this, &DomainServer::timeoutICEAddressLookup);
}
}
void DomainServer::timeoutICEAddressLookup() {
if (_iceAddressLookupID != INVALID_ICE_LOOKUP_ID) {
// we waited 5s and didn't hear back for our ICE DNS lookup
// so time that one out and kick off another
qDebug() << "IP address lookup timed out for" << _iceServerAddr << "- retrying";
QHostInfo::abortHostLookup(_iceAddressLookupID);
_iceAddressLookupID = INVALID_ICE_LOOKUP_ID;
updateICEServerAddresses();
} }
} }

View file

@ -39,6 +39,8 @@ typedef QMultiHash<QUuid, WalletTransaction*> TransactionHash;
using Subnet = QPair<QHostAddress, int>; using Subnet = QPair<QHostAddress, int>;
using SubnetList = std::vector<Subnet>; using SubnetList = std::vector<Subnet>;
const int INVALID_ICE_LOOKUP_ID = -1;
enum ReplicationServerDirection { enum ReplicationServerDirection {
Upstream, Upstream,
Downstream Downstream
@ -114,6 +116,8 @@ private slots:
void tokenGrantFinished(); void tokenGrantFinished();
void profileRequestFinished(); void profileRequestFinished();
void timeoutICEAddressLookup();
signals: signals:
void iceServerChanged(); void iceServerChanged();
void userConnected(); void userConnected();
@ -223,7 +227,7 @@ private:
QList<QHostAddress> _iceServerAddresses; QList<QHostAddress> _iceServerAddresses;
QSet<QHostAddress> _failedIceServerAddresses; QSet<QHostAddress> _failedIceServerAddresses;
int _iceAddressLookupID { -1 }; int _iceAddressLookupID { INVALID_ICE_LOOKUP_ID };
int _noReplyICEHeartbeats { 0 }; int _noReplyICEHeartbeats { 0 };
int _numHeartbeatDenials { 0 }; int _numHeartbeatDenials { 0 };
bool _connectedToICEServer { false }; bool _connectedToICEServer { false };

View file

@ -1,7 +1,7 @@
import QtQuick 2.5 import QtQuick 2.5
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtWebChannel 1.0 import QtWebChannel 1.0
import QtWebEngine 1.2 import QtWebEngine 1.5
import "controls" import "controls"
import "controls-uit" as HifiControls import "controls-uit" as HifiControls
@ -13,11 +13,11 @@ Item {
id: root id: root
HifiConstants { id: hifi } HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifistyles } HifiStyles.HifiConstants { id: hifistyles }
//width: parent.width
height: 600 height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'} property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url property alias url: webview.url
property WebEngineView webView: webview
property bool canGoBack: webview.canGoBack property bool canGoBack: webview.canGoBack
property bool canGoForward: webview.canGoForward property bool canGoForward: webview.canGoForward
@ -123,5 +123,4 @@ Item {
break; break;
} }
} }
} }

View file

@ -9,7 +9,7 @@
// //
import QtQuick 2.5 import QtQuick 2.5
import QtWebEngine 1.2 import QtWebEngine 1.5
WebEngineView { WebEngineView {
id: root id: root

View file

@ -9,10 +9,13 @@
// //
import QtQuick 2.5 import QtQuick 2.5
import QtWebEngine 1.5
AnimatedImage { AnimatedImage {
property WebEngineView webview: parent
source: "../../icons/loader-snake-64-w.gif" source: "../../icons/loader-snake-64-w.gif"
visible: parent.loading && /^(http.*|)$/i.test(parent.url.toString()) visible: webview.loading && /^(http.*|)$/i.test(webview.url.toString())
playing: visible
z: 10000 z: 10000
anchors { anchors {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter

View file

@ -0,0 +1,170 @@
import QtQuick 2.7
import QtWebEngine 1.5
import QtWebChannel 1.0
import QtQuick.Controls 2.2
import "../styles-uit" as StylesUIt
Flickable {
id: flick
property alias url: _webview.url
property alias canGoBack: _webview.canGoBack
property alias webViewCore: _webview
property alias webViewCoreProfile: _webview.profile
property string userScriptUrl: ""
property string urlTag: "noDownload=false";
signal newViewRequestedCallback(var request)
signal loadingChangedCallback(var loadRequest)
boundsBehavior: Flickable.StopAtBounds
StylesUIt.HifiConstants {
id: hifi
}
onHeightChanged: {
if (height > 0) {
//reload page since window dimentions changed,
//so web engine should recalculate page render dimentions
reloadTimer.start()
}
}
ScrollBar.vertical: ScrollBar {
id: scrollBar
visible: flick.contentHeight > flick.height
contentItem: Rectangle {
opacity: 0.75
implicitWidth: hifi.dimensions.scrollbarHandleWidth
radius: height / 2
color: hifi.colors.tableScrollHandleDark
}
}
function onLoadingChanged(loadRequest) {
if (WebEngineView.LoadStartedStatus === loadRequest.status) {
flick.contentWidth = flick.width
flick.contentHeight = flick.height
// Required to support clicking on "hifi://" links
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
_webview.stop();
}
}
}
if (WebEngineView.LoadFailedStatus === loadRequest.status) {
console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
}
if (WebEngineView.LoadSucceededStatus === loadRequest.status) {
//disable Chromium's scroll bars
_webview.runJavaScript("document.body.style.overflow = 'hidden';");
//calculate page height
_webview.runJavaScript("document.body.scrollHeight;", function (i_actualPageHeight) {
if (i_actualPageHeight !== undefined) {
flick.contentHeight = i_actualPageHeight
} else {
flick.contentHeight = flick.height;
}
})
flick.contentWidth = flick.width
}
}
Timer {
id: reloadTimer
interval: 100
repeat: false
onTriggered: {
_webview.reload()
}
}
WebEngineView {
id: _webview
height: parent.height
profile: HFWebEngineProfile;
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: flick.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
width = Qt.binding(function() { return flick.width; });
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
_webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
_webview.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onContentsSizeChanged: {
flick.contentHeight = Math.max(contentsSize.height, flick.height);
flick.contentWidth = flick.width
}
//disable popup
onContextMenuRequested: {
request.accepted = true;
}
onNewViewRequested: {
newViewRequestedCallback(request)
}
onLoadingChanged: {
flick.onLoadingChanged(loadRequest)
loadingChangedCallback(loadRequest)
}
}
AnimatedImage {
//anchoring doesnt works here when changing content size
x: flick.width/2 - width/2
y: flick.height/2 - height/2
source: "../../icons/loader-snake-64-w.gif"
visible: _webview.loading && /^(http.*|)$/i.test(_webview.url.toString())
playing: visible
z: 10000
}
}

View file

@ -1,14 +1,13 @@
import QtQuick 2.5 import QtQuick 2.7
import QtWebEngine 1.1
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls import "../controls-uit" as HiFiControls
Item { Item {
property alias url: root.url id: root
property alias scriptURL: root.userScriptUrl property alias url: webroot.url
property alias canGoBack: root.canGoBack; property alias scriptURL: webroot.userScriptUrl
property var goBack: root.goBack; property alias canGoBack: webroot.canGoBack;
property alias urlTag: root.urlTag property var goBack: webroot.webViewCore.goBack;
property alias urlTag: webroot.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false property bool keyboardRaised: false
property bool punctuationMode: false property bool punctuationMode: false
@ -21,84 +20,20 @@ Item {
} }
*/ */
property alias viewProfile: root.profile property alias viewProfile: webroot.webViewCoreProfile
WebEngineView { FlickableWebViewCore {
id: root id: webroot
objectName: "webEngineView"
x: 0
y: 0
width: parent.width width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile; onLoadingChangedCallback: {
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: root.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
keyboardRaised = false; keyboardRaised = false;
punctuationMode = false; punctuationMode = false;
keyboard.resetShiftMode(false); keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
} }
onNewViewRequested:{ onNewViewRequestedCallback: {
// desktop is not defined for web-entities or tablet // desktop is not defined for web-entities or tablet
if (typeof desktop !== "undefined") { if (typeof desktop !== "undefined") {
desktop.openBrowserWindow(request, profile); desktop.openBrowserWindow(request, profile);
@ -107,7 +42,6 @@ Item {
} }
} }
HiFiControls.WebSpinner { }
} }
HiFiControls.Keyboard { HiFiControls.Keyboard {
@ -120,5 +54,4 @@ Item {
bottom: parent.bottom bottom: parent.bottom
} }
} }
} }

View file

@ -1,18 +1,14 @@
import QtQuick 2.5 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtWebEngine 1.5
import QtWebEngine 1.2
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls import "../controls-uit" as HiFiControls
import "../styles" as HifiStyles import "../styles" as HifiStyles
import "../styles-uit" import "../styles-uit"
import "../"
import "."
Item { Item {
id: web id: root
HifiConstants { id: hifi } HifiConstants { id: hifi }
width: parent.width width: parent !== null ? parent.width : undefined
height: parent.height height: parent !== null ? parent.height : undefined
property var parentStackItem: null property var parentStackItem: null
property int headerHeight: 70 property int headerHeight: 70
property string url property string url
@ -21,8 +17,8 @@ Item {
property bool keyboardRaised: false property bool keyboardRaised: false
property bool punctuationMode: false property bool punctuationMode: false
property bool isDesktop: false property bool isDesktop: false
property alias webView: webview property alias webView: web.webViewCore
property alias profile: webview.profile property alias profile: web.webViewCoreProfile
property bool remove: false property bool remove: false
property bool closeButtonVisible: true property bool closeButtonVisible: true
@ -79,7 +75,7 @@ Item {
color: hifi.colors.baseGray color: hifi.colors.baseGray
font.pixelSize: 12 font.pixelSize: 12
verticalAlignment: Text.AlignLeft verticalAlignment: Text.AlignLeft
text: webview.url text: root.url
anchors { anchors {
top: nav.bottom top: nav.bottom
horizontalCenter: parent.horizontalCenter; horizontalCenter: parent.horizontalCenter;
@ -104,13 +100,13 @@ Item {
function closeWebEngine() { function closeWebEngine() {
if (remove) { if (remove) {
web.destroy(); root.destroy();
return; return;
} }
if (parentStackItem) { if (parentStackItem) {
parentStackItem.pop(); parentStackItem.pop();
} else { } else {
web.visible = false; root.visible = false;
} }
} }
@ -128,67 +124,19 @@ Item {
} }
function loadUrl(url) { function loadUrl(url) {
webview.url = url web.webViewCore.url = url
web.url = webview.url; root.url = web.webViewCore.url;
} }
onUrlChanged: { onUrlChanged: {
loadUrl(url); loadUrl(url);
} }
WebEngineView { FlickableWebViewCore {
id: webview id: web
objectName: "webEngineView"
x: 0
y: 0
width: parent.width width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - web.headerHeight : parent.height - web.headerHeight height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - root.headerHeight : parent.height - root.headerHeight
anchors.top: buttons.bottom anchors.top: buttons.bottom
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onUrlChanged: { onUrlChanged: {
// Record history, skipping null and duplicate items. // Record history, skipping null and duplicate items.
@ -201,34 +149,16 @@ Item {
} }
} }
onLoadingChanged: { onLoadingChangedCallback: {
keyboardRaised = false; keyboardRaised = false;
punctuationMode = false; punctuationMode = false;
keyboard.resetShiftMode(false); keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links webViewCore.forceActiveFocus();
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
if (WebEngineView.LoadFailedStatus == loadRequest.status) {
console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
}
if (WebEngineView.LoadSucceededStatus == loadRequest.status) {
webview.forceActiveFocus();
}
}
onNewViewRequested: {
request.openIn(webview);
} }
HiFiControls.WebSpinner { } onNewViewRequestedCallback: {
request.openIn(webViewCore);
}
} }
HiFiControls.Keyboard { HiFiControls.Keyboard {
@ -244,7 +174,7 @@ Item {
} }
Component.onCompleted: { Component.onCompleted: {
web.isDesktop = (typeof desktop !== "undefined"); root.isDesktop = (typeof desktop !== "undefined");
keyboardEnabled = HMD.active; keyboardEnabled = HMD.active;
} }

View file

@ -1,17 +1,19 @@
import QtQuick 2.5 import QtQuick 2.7
import QtWebEngine 1.1
import QtWebChannel 1.0
import "../controls-uit" as HiFiControls import "../controls-uit" as HiFiControls
Item { Item {
property alias url: root.url width: parent !== null ? parent.width : undefined
property alias scriptURL: root.userScriptUrl height: parent !== null ? parent.height : undefined
property alias canGoBack: root.canGoBack;
property var goBack: root.goBack; property alias url: webroot.url
property alias urlTag: root.urlTag property alias scriptURL: webroot.userScriptUrl
property alias canGoBack: webroot.canGoBack;
property var goBack: webroot.webViewCore.goBack;
property alias urlTag: webroot.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false property bool keyboardRaised: false
property bool punctuationMode: false property bool punctuationMode: false
property alias flickable: webroot.interactive
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface // FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface
// or provide HMDinfo object to QML in RenderableWebEntityItem and do the following. // or provide HMDinfo object to QML in RenderableWebEntityItem and do the following.
@ -21,82 +23,20 @@ Item {
} }
*/ */
property alias viewProfile: root.profile property alias viewProfile: webroot.webViewCoreProfile
WebEngineView { FlickableWebViewCore {
id: root id: webroot
objectName: "webEngineView"
x: 0
y: 0
width: parent.width width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile; onLoadingChangedCallback: {
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: root.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
property string urlTag: "noDownload=false";
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
keyboardRaised = false; keyboardRaised = false;
punctuationMode = false; punctuationMode = false;
keyboard.resetShiftMode(false); keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
} }
onNewViewRequested:{ onNewViewRequestedCallback: {
// desktop is not defined for web-entities or tablet // desktop is not defined for web-entities or tablet
if (typeof desktop !== "undefined") { if (typeof desktop !== "undefined") {
desktop.openBrowserWindow(request, profile); desktop.openBrowserWindow(request, profile);
@ -104,8 +44,6 @@ Item {
tabletRoot.openBrowserWindow(request, profile); tabletRoot.openBrowserWindow(request, profile);
} }
} }
HiFiControls.WebSpinner { }
} }
HiFiControls.Keyboard { HiFiControls.Keyboard {
@ -118,5 +56,4 @@ Item {
bottom: parent.bottom bottom: parent.bottom
} }
} }
} }

View file

@ -36,6 +36,24 @@ Rectangle {
return (root.parent !== null) && root.parent.objectName == "loader"; return (root.parent !== null) && root.parent.objectName == "loader";
} }
property bool showPeaks: true;
function enablePeakValues() {
Audio.devices.input.peakValuesEnabled = true;
Audio.devices.input.peakValuesEnabledChanged.connect(function(enabled) {
if (!enabled && root.showPeaks) {
Audio.devices.input.peakValuesEnabled = true;
}
});
}
function disablePeakValues() {
root.showPeaks = false;
Audio.devices.input.peakValuesEnabled = false;
}
Component.onCompleted: enablePeakValues();
Component.onDestruction: disablePeakValues();
onVisibleChanged: visible ? enablePeakValues() : disablePeakValues();
Column { Column {
y: 16; // padding does not work y: 16; // padding does not work
spacing: 16; spacing: 16;
@ -133,12 +151,13 @@ Rectangle {
onClicked: Audio.setInputDevice(info); onClicked: Audio.setInputDevice(info);
} }
InputLevel { InputPeak {
id: level; id: inputPeak;
visible: Audio.devices.input.peakValuesAvailable;
peak: model.peak;
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 30 anchors.rightMargin: 30
visible: selected;
} }
} }
} }

View file

@ -1,5 +1,5 @@
// //
// InputLevel.qml // InputPeak.qml
// qml/hifi/audio // qml/hifi/audio
// //
// Created by Zach Pomerantz on 6/20/2017 // Created by Zach Pomerantz on 6/20/2017
@ -15,7 +15,7 @@ import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
Rectangle { Rectangle {
readonly property var level: Audio.inputLevel; property var peak;
width: 70; width: 70;
height: 8; height: 8;
@ -65,7 +65,7 @@ Rectangle {
Rectangle { // mask Rectangle { // mask
id: mask; id: mask;
width: parent.width * level; width: parent.width * peak;
radius: 5; radius: 5;
anchors { anchors {
bottom: parent.bottom; bottom: parent.bottom;

View file

@ -55,6 +55,7 @@ Item {
text: "DEBUG: Clear Cached Passphrase"; text: "DEBUG: Clear Cached Passphrase";
onClicked: { onClicked: {
commerce.setPassphrase(""); commerce.setPassphrase("");
sendSignalToWallet({method: 'passphraseReset'});
} }
} }
HifiControlsUit.Button { HifiControlsUit.Button {

View file

@ -33,12 +33,19 @@ Rectangle {
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
onAccountResult: {
if (result.status === "success") {
commerce.getKeyFilePathIfExists();
} else {
// unsure how to handle a failure here. We definitely cannot proceed.
}
}
onLoginStatusResult: { onLoginStatusResult: {
if (!isLoggedIn && root.activeView !== "needsLogIn") { if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) { } else if (isLoggedIn) {
root.activeView = "initialize"; root.activeView = "initialize";
commerce.getKeyFilePathIfExists(); commerce.account();
} }
} }
@ -318,7 +325,7 @@ Rectangle {
Connections { Connections {
onSendSignalToWallet: { onSendSignalToWallet: {
if (msg.method === 'walletReset') { if (msg.method === 'walletReset' || msg.method === 'passphraseReset') {
sendToScript(msg); sendToScript(msg);
} }
} }

View file

@ -325,7 +325,7 @@ Rectangle {
onClicked: { onClicked: {
if (passphraseSelection.validateAndSubmitPassphrase()) { if (passphraseSelection.validateAndSubmitPassphrase()) {
root.lastPage = "choosePassphrase"; root.lastPage = "choosePassphrase";
commerce.balance(); // Do this here so that keys are generated. Order might change as backend changes? commerce.generateKeyPair();
choosePassphraseContainer.visible = false; choosePassphraseContainer.visible = false;
privateKeysReadyContainer.visible = true; privateKeysReadyContainer.visible = true;
} }

View file

@ -3,6 +3,8 @@ import QtGraphicalEffects 1.0
Item { Item {
id: tabletButton id: tabletButton
property string captionColorOverride: ""
property var uuid; property var uuid;
property string icon: "icons/tablet-icons/edit-i.svg" property string icon: "icons/tablet-icons/edit-i.svg"
property string hoverIcon: tabletButton.icon property string hoverIcon: tabletButton.icon
@ -102,7 +104,7 @@ Item {
Text { Text {
id: text id: text
color: "#ffffff" color: captionColorOverride !== "" ? captionColorOverride: "#ffffff"
text: tabletButton.text text: tabletButton.text
font.bold: true font.bold: true
font.pixelSize: 18 font.pixelSize: 18

View file

@ -604,6 +604,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>(); DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();
// Set dependencies // Set dependencies
DependencyManager::set<Cursor::Manager>();
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp)); DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<StatTracker>(); DependencyManager::set<StatTracker>();
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT); DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
@ -2819,35 +2820,18 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
// Get controller availability // Get controller availability
bool hasHandControllers = false; bool hasHandControllers = false;
HandControllerType handControllerType = Vive; if (PluginUtils::isViveControllerAvailable() || PluginUtils::isOculusTouchControllerAvailable()) {
if (PluginUtils::isViveControllerAvailable()) {
hasHandControllers = true; hasHandControllers = true;
handControllerType = Vive;
} else if (PluginUtils::isOculusTouchControllerAvailable()) {
hasHandControllers = true;
handControllerType = Oculus;
} }
// Check tutorial content versioning
bool hasTutorialContent = contentVersion >= MIN_CONTENT_VERSION.at(handControllerType);
// Check HMD use (may be technically available without being in use) // Check HMD use (may be technically available without being in use)
bool hasHMD = PluginUtils::isHMDAvailable(); bool hasHMD = PluginUtils::isHMDAvailable();
bool isUsingHMD = _displayPlugin->isHmd(); bool isUsingHMD = _displayPlugin->isHmd();
bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD; bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD;
Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false };
Setting::Handle<bool> firstRun{ Settings::firstRun, true }; Setting::Handle<bool> firstRun{ Settings::firstRun, true };
const QString HIFI_SKIP_TUTORIAL_COMMAND_LINE_KEY = "--skipTutorial";
// Skips tutorial/help behavior, and does NOT clear firstRun setting.
bool skipTutorial = arguments().contains(HIFI_SKIP_TUTORIAL_COMMAND_LINE_KEY);
bool isTutorialComplete = tutorialComplete.get();
bool shouldGoToTutorial = isUsingHMDAndHandControllers && hasTutorialContent && !isTutorialComplete && !skipTutorial;
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers; qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers;
qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent <<
", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial;
// when --url in command line, teleport to location // when --url in command line, teleport to location
const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; const QString HIFI_URL_COMMAND_LINE_KEY = "--url";
@ -2857,58 +2841,31 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
addressLookupString = arguments().value(urlIndex + 1); addressLookupString = arguments().value(urlIndex + 1);
} }
const QString TUTORIAL_PATH = "/tutorial_begin";
static const QString SENT_TO_TUTORIAL = "tutorial";
static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location"; static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location";
static const QString SENT_TO_ENTRY = "entry"; static const QString SENT_TO_ENTRY = "entry";
static const QString SENT_TO_SANDBOX = "sandbox"; static const QString SENT_TO_SANDBOX = "sandbox";
QString sentTo; QString sentTo;
if (shouldGoToTutorial) {
if (sandboxIsRunning) {
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH);
sentTo = SENT_TO_TUTORIAL;
} else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
if (firstRun.get()) {
showHelp();
}
if (addressLookupString.isEmpty()) {
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} else {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
}
}
} else {
// If this is a first run we short-circuit the address passed in // If this is a first run we short-circuit the address passed in
if (firstRun.get() && !skipTutorial) { if (firstRun.get()) {
showHelp(); showHelp();
if (isUsingHMDAndHandControllers) { if (sandboxIsRunning) {
if (sandboxIsRunning) { qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; DependencyManager::get<AddressManager>()->goToLocalSandbox();
DependencyManager::get<AddressManager>()->goToLocalSandbox(); sentTo = SENT_TO_SANDBOX;
sentTo = SENT_TO_SANDBOX;
} else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
}
} else { } else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
DependencyManager::get<AddressManager>()->goToEntry(); DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY; sentTo = SENT_TO_ENTRY;
} }
firstRun.set(false);
} else { } else {
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION; sentTo = SENT_TO_PREVIOUS_LOCATION;
} }
}
UserActivityLogger::getInstance().logAction("startup_sent_to", { UserActivityLogger::getInstance().logAction("startup_sent_to", {
{ "sent_to", sentTo }, { "sent_to", sentTo },
@ -2917,18 +2874,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
{ "has_hand_controllers", hasHandControllers }, { "has_hand_controllers", hasHandControllers },
{ "is_using_hmd", isUsingHMD }, { "is_using_hmd", isUsingHMD },
{ "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers }, { "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers },
{ "content_version", contentVersion }, { "content_version", contentVersion }
{ "is_tutorial_complete", isTutorialComplete },
{ "has_tutorial_content", hasTutorialContent },
{ "should_go_to_tutorial", shouldGoToTutorial }
}); });
_connectionMonitor.init(); _connectionMonitor.init();
// After all of the constructor is completed, then set firstRun to false.
if (!skipTutorial) {
firstRun.set(false);
}
} }
bool Application::importJSONFromURL(const QString& urlString) { bool Application::importJSONFromURL(const QString& urlString) {
@ -7459,7 +7408,10 @@ void Application::updateDisplayMode() {
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
_displayPlugin = newDisplayPlugin; _displayPlugin = newDisplayPlugin;
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked); auto desktop = offscreenUi->getDesktop();
if (desktop) {
desktop->setProperty("repositionLocked", wasRepositionLocked);
}
} }
bool isHmd = _displayPlugin->isHmd(); bool isHmd = _displayPlugin->isHmd();

View file

@ -176,3 +176,28 @@ void Ledger::resetFailure(QNetworkReply& reply) { failResponse("reset", reply);
void Ledger::reset() { void Ledger::reset() {
send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, QJsonObject()); send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, QJsonObject());
} }
void Ledger::accountSuccess(QNetworkReply& reply) {
// lets set the appropriate stuff in the wallet now
auto wallet = DependencyManager::get<Wallet>();
QByteArray response = reply.readAll();
QJsonObject data = QJsonDocument::fromJson(response).object()["data"].toObject();
auto salt = QByteArray::fromBase64(data["salt"].toString().toUtf8());
auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8());
auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8());
wallet->setSalt(salt);
wallet->setIv(iv);
wallet->setCKey(ckey);
// none of the hfc account info should be emitted
emit accountResult(QJsonObject{ {"status", "success"} });
}
void Ledger::accountFailure(QNetworkReply& reply) {
failResponse("account", reply);
}
void Ledger::account() {
send("hfc_account", "accountSuccess", "accountFailure", QNetworkAccessManager::PutOperation, QJsonObject());
}

View file

@ -29,6 +29,7 @@ public:
void balance(const QStringList& keys); void balance(const QStringList& keys);
void inventory(const QStringList& keys); void inventory(const QStringList& keys);
void history(const QStringList& keys); void history(const QStringList& keys);
void account();
void reset(); void reset();
signals: signals:
@ -37,6 +38,7 @@ signals:
void balanceResult(QJsonObject result); void balanceResult(QJsonObject result);
void inventoryResult(QJsonObject result); void inventoryResult(QJsonObject result);
void historyResult(QJsonObject result); void historyResult(QJsonObject result);
void accountResult(QJsonObject result);
public slots: public slots:
void buySuccess(QNetworkReply& reply); void buySuccess(QNetworkReply& reply);
@ -51,6 +53,8 @@ public slots:
void historyFailure(QNetworkReply& reply); void historyFailure(QNetworkReply& reply);
void resetSuccess(QNetworkReply& reply); void resetSuccess(QNetworkReply& reply);
void resetFailure(QNetworkReply& reply); void resetFailure(QNetworkReply& reply);
void accountSuccess(QNetworkReply& reply);
void accountFailure(QNetworkReply& reply);
private: private:
QJsonObject apiResponse(const QString& label, QNetworkReply& reply); QJsonObject apiResponse(const QString& label, QNetworkReply& reply);

View file

@ -27,6 +27,7 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult); connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult);
connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult); connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult);
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult); connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult);
} }
void QmlCommerce::getLoginStatus() { void QmlCommerce::getLoginStatus() {
@ -86,7 +87,7 @@ void QmlCommerce::history() {
void QmlCommerce::setPassphrase(const QString& passphrase) { void QmlCommerce::setPassphrase(const QString& passphrase) {
auto wallet = DependencyManager::get<Wallet>(); auto wallet = DependencyManager::get<Wallet>();
if (wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty()) { if(wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty() && !passphrase.isEmpty()) {
wallet->changePassphrase(passphrase); wallet->changePassphrase(passphrase);
} else { } else {
wallet->setPassphrase(passphrase); wallet->setPassphrase(passphrase);
@ -94,9 +95,20 @@ void QmlCommerce::setPassphrase(const QString& passphrase) {
getWalletAuthenticatedStatus(); getWalletAuthenticatedStatus();
} }
void QmlCommerce::generateKeyPair() {
auto wallet = DependencyManager::get<Wallet>();
wallet->generateKeyPair();
getWalletAuthenticatedStatus();
}
void QmlCommerce::reset() { void QmlCommerce::reset() {
auto ledger = DependencyManager::get<Ledger>(); auto ledger = DependencyManager::get<Ledger>();
auto wallet = DependencyManager::get<Wallet>(); auto wallet = DependencyManager::get<Wallet>();
ledger->reset(); ledger->reset();
wallet->reset(); wallet->reset();
} }
void QmlCommerce::account() {
auto ledger = DependencyManager::get<Ledger>();
ledger->account();
}

View file

@ -39,6 +39,7 @@ signals:
void balanceResult(QJsonObject result); void balanceResult(QJsonObject result);
void inventoryResult(QJsonObject result); void inventoryResult(QJsonObject result);
void historyResult(QJsonObject result); void historyResult(QJsonObject result);
void accountResult(QJsonObject result);
protected: protected:
Q_INVOKABLE void getLoginStatus(); Q_INVOKABLE void getLoginStatus();
@ -53,8 +54,9 @@ protected:
Q_INVOKABLE void balance(); Q_INVOKABLE void balance();
Q_INVOKABLE void inventory(); Q_INVOKABLE void inventory();
Q_INVOKABLE void history(); Q_INVOKABLE void history();
Q_INVOKABLE void generateKeyPair();
Q_INVOKABLE void reset(); Q_INVOKABLE void reset();
Q_INVOKABLE void account();
}; };
#endif // hifi_QmlCommerce_h #endif // hifi_QmlCommerce_h

View file

@ -55,9 +55,12 @@ QString imageFilePath() {
// use the cached _passphrase if it exists, otherwise we need to prompt // use the cached _passphrase if it exists, otherwise we need to prompt
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) { int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
// just return a hardcoded pwd for now // just return a hardcoded pwd for now
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase(); auto wallet = DependencyManager::get<Wallet>();
auto passphrase = wallet->getPassphrase();
if (passphrase && !passphrase->isEmpty()) { if (passphrase && !passphrase->isEmpty()) {
strcpy(password, passphrase->toLocal8Bit().constData()); QString saltedPassphrase(*passphrase);
saltedPassphrase.append(wallet->getSalt());
strcpy(password, saltedPassphrase.toUtf8().constData());
return static_cast<int>(passphrase->size()); return static_cast<int>(passphrase->size());
} else { } else {
// this shouldn't happen - so lets log it to tell us we have // this shouldn't happen - so lets log it to tell us we have
@ -245,6 +248,8 @@ RSA* readPrivateKey(const char* filename) {
} else { } else {
qCDebug(commerce) << "couldn't parse" << filename; qCDebug(commerce) << "couldn't parse" << filename;
// if the passphrase is wrong, then let's not cache it
DependencyManager::get<Wallet>()->setPassphrase("");
} }
fclose(fp); fclose(fp);
} else { } else {
@ -252,13 +257,12 @@ RSA* readPrivateKey(const char* filename) {
} }
return key; return key;
} }
static const unsigned char IVEC[16] = "IAmAnIVecYay123";
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) { void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
// first ivec // use the ones in the wallet
memcpy(ivec, IVEC, 16); auto wallet = DependencyManager::get<Wallet>();
auto hash = QCryptographicHash::hash(salt, QCryptographicHash::Sha256); memcpy(ivec, wallet->getIv(), 16);
memcpy(ckey, hash.data(), 32); memcpy(ckey, wallet->getCKey(), 32);
} }
Wallet::~Wallet() { Wallet::~Wallet() {
@ -273,8 +277,6 @@ void Wallet::setPassphrase(const QString& passphrase) {
} }
_passphrase = new QString(passphrase); _passphrase = new QString(passphrase);
// no matter what, we now need to clear the keys as they
// need to be read using this passphrase
_publicKeys.clear(); _publicKeys.clear();
} }
@ -413,28 +415,10 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
return false; return false;
} }
bool Wallet::createIfNeeded() { bool Wallet::generateKeyPair() {
if (_publicKeys.count() > 0) return false;
// FIXME: initialize OpenSSL elsewhere soon // FIXME: initialize OpenSSL elsewhere soon
initialize(); initialize();
// try to read existing keys if they exist...
auto publicKey = readPublicKey(keyFilePath().toStdString().c_str());
if (publicKey.size() > 0) {
if (auto key = readPrivateKey(keyFilePath().toStdString().c_str()) ) {
qCDebug(commerce) << "read private key";
RSA_free(key);
// K -- add the public key since we have a legit private key associated with it
_publicKeys.push_back(publicKey.toBase64());
return false;
}
}
qCInfo(commerce) << "Creating wallet.";
return generateKeyPair();
}
bool Wallet::generateKeyPair() {
qCInfo(commerce) << "Generating keypair."; qCInfo(commerce) << "Generating keypair.";
auto keyPair = generateRSAKeypair(); auto keyPair = generateRSAKeypair();
sendKeyFilePathIfExists(); sendKeyFilePathIfExists();
@ -453,7 +437,6 @@ bool Wallet::generateKeyPair() {
QStringList Wallet::listPublicKeys() { QStringList Wallet::listPublicKeys() {
qCInfo(commerce) << "Enumerating public keys."; qCInfo(commerce) << "Enumerating public keys.";
createIfNeeded();
return _publicKeys; return _publicKeys;
} }
@ -572,12 +555,8 @@ void Wallet::reset() {
// tell the provider we got nothing // tell the provider we got nothing
updateImageProvider(); updateImageProvider();
delete _passphrase; _passphrase->clear();
// for now we need to maintain the hard-coded passphrase.
// FIXME: remove this line as part of wiring up the passphrase
// and probably set it to nullptr
_passphrase = new QString("pwd");
QFile keyFile(keyFilePath()); QFile keyFile(keyFilePath());
QFile imageFile(imageFilePath()); QFile imageFile(imageFilePath());
@ -608,6 +587,7 @@ bool Wallet::changePassphrase(const QString& newPassphrase) {
return false; return false;
} }
} }
qCDebug(commerce) << "couldn't read keys"; qCDebug(commerce) << "couldn't decrypt keys with current passphrase, clearing";
setPassphrase(QString(""));
return false; return false;
} }

View file

@ -26,7 +26,6 @@ public:
~Wallet(); ~Wallet();
// These are currently blocking calls, although they might take a moment. // These are currently blocking calls, although they might take a moment.
bool createIfNeeded();
bool generateKeyPair(); bool generateKeyPair();
QStringList listPublicKeys(); QStringList listPublicKeys();
QString signWithKey(const QByteArray& text, const QString& key); QString signWithKey(const QByteArray& text, const QString& key);
@ -36,6 +35,10 @@ public:
void setSalt(const QByteArray& salt) { _salt = salt; } void setSalt(const QByteArray& salt) { _salt = salt; }
QByteArray getSalt() { return _salt; } QByteArray getSalt() { return _salt; }
void setIv(const QByteArray& iv) { _iv = iv; }
QByteArray getIv() { return _iv; }
void setCKey(const QByteArray& ckey) { _ckey = ckey; }
QByteArray getCKey() { return _ckey; }
void setPassphrase(const QString& passphrase); void setPassphrase(const QString& passphrase);
QString* getPassphrase() { return _passphrase; } QString* getPassphrase() { return _passphrase; }
@ -53,6 +56,8 @@ private:
QStringList _publicKeys{}; QStringList _publicKeys{};
QPixmap* _securityImage { nullptr }; QPixmap* _securityImage { nullptr };
QByteArray _salt {"iamsalt!"}; QByteArray _salt {"iamsalt!"};
QByteArray _iv;
QByteArray _ckey;
QString* _passphrase { new QString("") }; QString* _passphrase { new QString("") };
void updateImageProvider(); void updateImageProvider();

View file

@ -37,6 +37,20 @@ Setting::Handle<QString>& getSetting(bool contextIsHMD, QAudio::Mode mode) {
} }
} }
enum AudioDeviceRole {
DisplayRole = Qt::DisplayRole,
CheckStateRole = Qt::CheckStateRole,
PeakRole = Qt::UserRole,
InfoRole = Qt::UserRole + 1
};
QHash<int, QByteArray> AudioDeviceList::_roles {
{ DisplayRole, "display" },
{ CheckStateRole, "selected" },
{ PeakRole, "peak" },
{ InfoRole, "info" }
};
static QString getTargetDevice(bool hmd, QAudio::Mode mode) { static QString getTargetDevice(bool hmd, QAudio::Mode mode) {
QString deviceName; QString deviceName;
auto& setting = getSetting(hmd, mode); auto& setting = getSetting(hmd, mode);
@ -52,29 +66,36 @@ static QString getTargetDevice(bool hmd, QAudio::Mode mode) {
return deviceName; return deviceName;
} }
QHash<int, QByteArray> AudioDeviceList::_roles {
{ Qt::DisplayRole, "display" },
{ Qt::CheckStateRole, "selected" },
{ Qt::UserRole, "info" }
};
Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled }; Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled };
QVariant AudioDeviceList::data(const QModelIndex& index, int role) const { QVariant AudioDeviceList::data(const QModelIndex& index, int role) const {
if (!index.isValid() || index.row() >= _devices.size()) { if (!index.isValid() || index.row() >= rowCount()) {
return QVariant(); return QVariant();
} }
if (role == Qt::DisplayRole) { if (role == DisplayRole) {
return _devices.at(index.row()).display; return _devices.at(index.row())->display;
} else if (role == Qt::CheckStateRole) { } else if (role == CheckStateRole) {
return _devices.at(index.row()).selected; return _devices.at(index.row())->selected;
} else if (role == Qt::UserRole) { } else if (role == InfoRole) {
return QVariant::fromValue<QAudioDeviceInfo>(_devices.at(index.row()).info); return QVariant::fromValue<QAudioDeviceInfo>(_devices.at(index.row())->info);
} else { } else {
return QVariant(); return QVariant();
} }
} }
QVariant AudioInputDeviceList::data(const QModelIndex& index, int role) const {
if (!index.isValid() || index.row() >= rowCount()) {
return QVariant();
}
if (role == PeakRole) {
return std::static_pointer_cast<AudioInputDevice>(_devices.at(index.row()))->peak;
} else {
return AudioDeviceList::data(index, role);
}
}
void AudioDeviceList::resetDevice(bool contextIsHMD) { void AudioDeviceList::resetDevice(bool contextIsHMD) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
QString deviceName = getTargetDevice(contextIsHMD, _mode); QString deviceName = getTargetDevice(contextIsHMD, _mode);
@ -113,8 +134,9 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) {
auto oldDevice = _selectedDevice; auto oldDevice = _selectedDevice;
_selectedDevice = device; _selectedDevice = device;
for (auto i = 0; i < _devices.size(); ++i) { for (auto i = 0; i < rowCount(); ++i) {
AudioDevice& device = _devices[i]; AudioDevice& device = *_devices[i];
if (device.selected && device.info != _selectedDevice) { if (device.selected && device.info != _selectedDevice) {
device.selected = false; device.selected = false;
} else if (device.info == _selectedDevice) { } else if (device.info == _selectedDevice) {
@ -139,17 +161,47 @@ void AudioDeviceList::onDevicesChanged(const QList<QAudioDeviceInfo>& devices) {
.remove("Device") .remove("Device")
.replace(" )", ")"); .replace(" )", ")");
device.selected = (device.info == _selectedDevice); device.selected = (device.info == _selectedDevice);
_devices.push_back(device); _devices.push_back(newDevice(device));
} }
endResetModel(); endResetModel();
} }
bool AudioInputDeviceList::peakValuesAvailable() {
std::call_once(_peakFlag, [&] {
_peakValuesAvailable = DependencyManager::get<AudioClient>()->peakValuesAvailable();
});
return _peakValuesAvailable;
}
void AudioInputDeviceList::setPeakValuesEnabled(bool enable) {
if (peakValuesAvailable() && (enable != _peakValuesEnabled)) {
DependencyManager::get<AudioClient>()->enablePeakValues(enable);
_peakValuesEnabled = enable;
emit peakValuesEnabledChanged(_peakValuesEnabled);
}
}
void AudioInputDeviceList::onPeakValueListChanged(const QList<float>& peakValueList) {
assert(_mode == QAudio::AudioInput);
if (peakValueList.length() != rowCount()) {
qWarning() << "AudioDeviceList" << __FUNCTION__ << "length mismatch";
}
for (auto i = 0; i < rowCount(); ++i) {
std::static_pointer_cast<AudioInputDevice>(_devices[i])->peak = peakValueList[i];
}
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0), { PeakRole });
}
AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) {
auto client = DependencyManager::get<AudioClient>(); auto client = DependencyManager::get<AudioClient>();
connect(client.data(), &AudioClient::deviceChanged, this, &AudioDevices::onDeviceChanged, Qt::QueuedConnection); connect(client.data(), &AudioClient::deviceChanged, this, &AudioDevices::onDeviceChanged, Qt::QueuedConnection);
connect(client.data(), &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection); connect(client.data(), &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection);
connect(client.data(), &AudioClient::peakValueListChanged, &_inputs, &AudioInputDeviceList::onPeakValueListChanged, Qt::QueuedConnection);
// connections are made after client is initialized, so we must also fetch the devices // connections are made after client is initialized, so we must also fetch the devices
_inputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioInput)); _inputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioInput));

View file

@ -12,6 +12,9 @@
#ifndef hifi_scripting_AudioDevices_h #ifndef hifi_scripting_AudioDevices_h
#define hifi_scripting_AudioDevices_h #define hifi_scripting_AudioDevices_h
#include <memory>
#include <mutex>
#include <QObject> #include <QObject>
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QAudioDeviceInfo> #include <QAudioDeviceInfo>
@ -29,7 +32,11 @@ class AudioDeviceList : public QAbstractListModel {
Q_OBJECT Q_OBJECT
public: public:
AudioDeviceList(QAudio::Mode mode) : _mode(mode) {} AudioDeviceList(QAudio::Mode mode = QAudio::AudioOutput) : _mode(mode) {}
~AudioDeviceList() = default;
virtual std::shared_ptr<AudioDevice> newDevice(const AudioDevice& device)
{ return std::make_shared<AudioDevice>(device); }
int rowCount(const QModelIndex& parent = QModelIndex()) const override { Q_UNUSED(parent); return _devices.size(); } int rowCount(const QModelIndex& parent = QModelIndex()) const override { Q_UNUSED(parent); return _devices.size(); }
QHash<int, QByteArray> roleNames() const override { return _roles; } QHash<int, QByteArray> roleNames() const override { return _roles; }
@ -44,25 +51,63 @@ public:
signals: signals:
void deviceChanged(const QAudioDeviceInfo& device); void deviceChanged(const QAudioDeviceInfo& device);
private slots: protected slots:
void onDeviceChanged(const QAudioDeviceInfo& device); void onDeviceChanged(const QAudioDeviceInfo& device);
void onDevicesChanged(const QList<QAudioDeviceInfo>& devices); void onDevicesChanged(const QList<QAudioDeviceInfo>& devices);
private: protected:
friend class AudioDevices; friend class AudioDevices;
static QHash<int, QByteArray> _roles; static QHash<int, QByteArray> _roles;
static Qt::ItemFlags _flags; static Qt::ItemFlags _flags;
const QAudio::Mode _mode; const QAudio::Mode _mode;
QAudioDeviceInfo _selectedDevice; QAudioDeviceInfo _selectedDevice;
QList<AudioDevice> _devices; QList<std::shared_ptr<AudioDevice>> _devices;
};
class AudioInputDevice : public AudioDevice {
public:
AudioInputDevice(const AudioDevice& device) : AudioDevice(device) {}
float peak { 0.0f };
};
class AudioInputDeviceList : public AudioDeviceList {
Q_OBJECT
Q_PROPERTY(bool peakValuesAvailable READ peakValuesAvailable)
Q_PROPERTY(bool peakValuesEnabled READ peakValuesEnabled WRITE setPeakValuesEnabled NOTIFY peakValuesEnabledChanged)
public:
AudioInputDeviceList() : AudioDeviceList(QAudio::AudioInput) {}
virtual ~AudioInputDeviceList() = default;
virtual std::shared_ptr<AudioDevice> newDevice(const AudioDevice& device) override
{ return std::make_shared<AudioInputDevice>(device); }
QVariant data(const QModelIndex& index, int role) const override;
signals:
void peakValuesEnabledChanged(bool enabled);
protected slots:
void onPeakValueListChanged(const QList<float>& peakValueList);
protected:
friend class AudioDevices;
bool peakValuesAvailable();
std::once_flag _peakFlag;
bool _peakValuesAvailable;
bool peakValuesEnabled() const { return _peakValuesEnabled; }
void setPeakValuesEnabled(bool enable);
bool _peakValuesEnabled { false };
}; };
class Audio; class Audio;
class AudioDevices : public QObject { class AudioDevices : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(AudioDeviceList* input READ getInputList NOTIFY nop) Q_PROPERTY(AudioInputDeviceList* input READ getInputList NOTIFY nop)
Q_PROPERTY(AudioDeviceList* output READ getOutputList NOTIFY nop) Q_PROPERTY(AudioDeviceList* output READ getOutputList NOTIFY nop)
public: public:
@ -82,10 +127,10 @@ private slots:
private: private:
friend class Audio; friend class Audio;
AudioDeviceList* getInputList() { return &_inputs; } AudioInputDeviceList* getInputList() { return &_inputs; }
AudioDeviceList* getOutputList() { return &_outputs; } AudioDeviceList* getOutputList() { return &_outputs; }
AudioDeviceList _inputs { QAudio::AudioInput }; AudioInputDeviceList _inputs;
AudioDeviceList _outputs { QAudio::AudioOutput }; AudioDeviceList _outputs { QAudio::AudioOutput };
QAudioDeviceInfo _requestedOutputDevice; QAudioDeviceInfo _requestedOutputDevice;
QAudioDeviceInfo _requestedInputDevice; QAudioDeviceInfo _requestedInputDevice;

View file

@ -169,12 +169,14 @@ void LoginDialog::openUrl(const QString& url) const {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (tablet->getToolbarMode()) { if (tablet->getToolbarMode()) {
auto browser = offscreenUi->load("Browser.qml"); offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
browser->setProperty("url", url); newObject->setProperty("url", url);
});
} else { } else {
if (!hmd->getShouldShowTablet() && !qApp->isHMDMode()) { if (!hmd->getShouldShowTablet() && !qApp->isHMDMode()) {
auto browser = offscreenUi->load("Browser.qml"); offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
browser->setProperty("url", url); newObject->setProperty("url", url);
});
} else { } else {
tablet->gotoWebScreen(url); tablet->gotoWebScreen(url);
} }

View file

@ -78,7 +78,7 @@ Setting::Handle<int> staticJitterBufferFrames("staticJitterBufferFrames",
// protect the Qt internal device list // protect the Qt internal device list
using Mutex = std::mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
static Mutex _deviceMutex; Mutex _deviceMutex;
// thread-safe // thread-safe
QList<QAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) { QList<QAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) {
@ -227,13 +227,18 @@ AudioClient::AudioClient() :
// start a thread to detect any device changes // start a thread to detect any device changes
_checkDevicesTimer = new QTimer(this); _checkDevicesTimer = new QTimer(this);
connect(_checkDevicesTimer, &QTimer::timeout, [this] { connect(_checkDevicesTimer, &QTimer::timeout, [this] {
QtConcurrent::run(QThreadPool::globalInstance(), [this] { QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkDevices(); });
checkDevices();
});
}); });
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000; const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
_checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS); _checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
// start a thread to detect peak value changes
_checkPeakValuesTimer = new QTimer(this);
connect(_checkPeakValuesTimer, &QTimer::timeout, [this] {
QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); });
});
const unsigned long PEAK_VALUES_CHECK_INTERVAL_MSECS = 50;
_checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_MSECS);
configureReverb(); configureReverb();
@ -275,6 +280,7 @@ void AudioClient::cleanupBeforeQuit() {
stop(); stop();
_checkDevicesTimer->stop(); _checkDevicesTimer->stop();
_checkPeakValuesTimer->stop();
guard.trigger(); guard.trigger();
} }
@ -316,8 +322,6 @@ QString getWinDeviceName(IMMDevice* pEndpoint) {
QString deviceName; QString deviceName;
IPropertyStore* pPropertyStore; IPropertyStore* pPropertyStore;
pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore);
pEndpoint->Release();
pEndpoint = nullptr;
PROPVARIANT pv; PROPVARIANT pv;
PropVariantInit(&pv); PropVariantInit(&pv);
HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
@ -346,6 +350,8 @@ QString AudioClient::getWinDeviceName(wchar_t* guid) {
deviceName = QString("NONE"); deviceName = QString("NONE");
} else { } else {
deviceName = ::getWinDeviceName(pEndpoint); deviceName = ::getWinDeviceName(pEndpoint);
pEndpoint->Release();
pEndpoint = nullptr;
} }
pMMDeviceEnumerator->Release(); pMMDeviceEnumerator->Release();
pMMDeviceEnumerator = nullptr; pMMDeviceEnumerator = nullptr;
@ -429,6 +435,8 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
deviceName = QString("NONE"); deviceName = QString("NONE");
} else { } else {
deviceName = getWinDeviceName(pEndpoint); deviceName = getWinDeviceName(pEndpoint);
pEndpoint->Release();
pEndpoint = nullptr;
} }
pMMDeviceEnumerator->Release(); pMMDeviceEnumerator->Release();
pMMDeviceEnumerator = NULL; pMMDeviceEnumerator = NULL;

View file

@ -148,6 +148,9 @@ public:
QAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const; QAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const;
QList<QAudioDeviceInfo> getAudioDevices(QAudio::Mode mode) const; QList<QAudioDeviceInfo> getAudioDevices(QAudio::Mode mode) const;
void enablePeakValues(bool enable) { _enablePeakValues = enable; }
bool peakValuesAvailable() const;
static const float CALLBACK_ACCELERATOR_RATIO; static const float CALLBACK_ACCELERATOR_RATIO;
bool getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName); bool getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName);
@ -224,6 +227,7 @@ signals:
void deviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device); void deviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device);
void devicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices); void devicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices);
void peakValueListChanged(const QList<float> peakValueList);
void receivedFirstPacket(); void receivedFirstPacket();
void disconnected(); void disconnected();
@ -242,9 +246,12 @@ private:
friend class CheckDevicesThread; friend class CheckDevicesThread;
friend class LocalInjectorsThread; friend class LocalInjectorsThread;
// background tasks
void checkDevices();
void checkPeakValues();
void outputFormatChanged(); void outputFormatChanged();
void handleAudioInput(QByteArray& audioBuffer); void handleAudioInput(QByteArray& audioBuffer);
void checkDevices();
void prepareLocalAudioInjectors(std::unique_ptr<Lock> localAudioLock = nullptr); void prepareLocalAudioInjectors(std::unique_ptr<Lock> localAudioLock = nullptr);
bool mixLocalAudioInjectors(float* mixBuffer); bool mixLocalAudioInjectors(float* mixBuffer);
float azimuthForSource(const glm::vec3& relativePosition); float azimuthForSource(const glm::vec3& relativePosition);
@ -298,6 +305,7 @@ private:
std::atomic<bool> _localInjectorsAvailable { false }; std::atomic<bool> _localInjectorsAvailable { false };
MixedProcessedAudioStream _receivedAudioStream; MixedProcessedAudioStream _receivedAudioStream;
bool _isStereoInput; bool _isStereoInput;
std::atomic<bool> _enablePeakValues { false };
quint64 _outputStarveDetectionStartTimeMsec; quint64 _outputStarveDetectionStartTimeMsec;
int _outputStarveDetectionCount; int _outputStarveDetectionCount;
@ -396,6 +404,7 @@ private:
RateCounter<> _audioInbound; RateCounter<> _audioInbound;
QTimer* _checkDevicesTimer { nullptr }; QTimer* _checkDevicesTimer { nullptr };
QTimer* _checkPeakValuesTimer { nullptr };
}; };

View file

@ -0,0 +1,176 @@
//
// AudioPeakValues.cpp
// interface/src
//
// Created by Zach Pomerantz on 6/26/2017
// Copyright 2013 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 "AudioClient.h"
#ifdef Q_OS_WIN
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <audioclient.h>
#include <QString>
#define RETURN_ON_FAIL(result) if (FAILED(result)) { return; }
#define CONTINUE_ON_FAIL(result) if (FAILED(result)) { continue; }
extern QString getWinDeviceName(IMMDevice* pEndpoint);
extern std::mutex _deviceMutex;
std::map<std::wstring, std::shared_ptr<IAudioClient>> activeClients;
template <class T>
void release(T* t) {
t->Release();
}
template <>
void release(IAudioClient* audioClient) {
audioClient->Stop();
audioClient->Release();
}
void AudioClient::checkPeakValues() {
// prepare the windows environment
CoInitialize(NULL);
// if disabled, clean up active clients
if (!_enablePeakValues) {
activeClients.clear();
return;
}
// lock the devices so the _inputDevices list is static
std::unique_lock<std::mutex> lock(_deviceMutex);
HRESULT result;
// initialize the payload
QList<float> peakValueList;
for (int i = 0; i < _inputDevices.size(); ++i) {
peakValueList.push_back(0.0f);
}
std::shared_ptr<IMMDeviceEnumerator> enumerator;
{
IMMDeviceEnumerator* pEnumerator;
result = CoCreateInstance(
__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
RETURN_ON_FAIL(result);
enumerator = std::shared_ptr<IMMDeviceEnumerator>(pEnumerator, &release<IMMDeviceEnumerator>);
}
std::shared_ptr<IMMDeviceCollection> endpoints;
{
IMMDeviceCollection* pEndpoints;
result = enumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &pEndpoints);
RETURN_ON_FAIL(result);
endpoints = std::shared_ptr<IMMDeviceCollection>(pEndpoints, &release<IMMDeviceCollection>);
}
UINT count;
{
result = endpoints->GetCount(&count);
RETURN_ON_FAIL(result);
}
IMMDevice* pDevice;
std::shared_ptr<IMMDevice> device;
IAudioMeterInformation* pMeterInfo;
std::shared_ptr<IAudioMeterInformation> meterInfo;
IAudioClient* pAudioClient;
std::shared_ptr<IAudioClient> audioClient;
DWORD hardwareSupport;
LPWSTR pDeviceId = NULL;
LPWAVEFORMATEX format;
float peakValue;
QString deviceName;
int deviceIndex;
for (UINT i = 0; i < count; ++i) {
result = endpoints->Item(i, &pDevice);
CONTINUE_ON_FAIL(result);
device = std::shared_ptr<IMMDevice>(pDevice, &release<IMMDevice>);
// if the device isn't listed through Qt, skip it
deviceName = ::getWinDeviceName(pDevice);
deviceIndex = 0;
for (; deviceIndex < _inputDevices.size(); ++deviceIndex) {
if (deviceName == _inputDevices[deviceIndex].deviceName()) {
break;
}
}
if (deviceIndex >= _inputDevices.size()) {
continue;
}
//continue;
result = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_ALL, NULL, (void**)&pMeterInfo);
CONTINUE_ON_FAIL(result);
meterInfo = std::shared_ptr<IAudioMeterInformation>(pMeterInfo, &release<IAudioMeterInformation>);
//continue;
hardwareSupport;
result = meterInfo->QueryHardwareSupport(&hardwareSupport);
CONTINUE_ON_FAIL(result);
//continue;
// if the device has no hardware support (USB)...
if (!(hardwareSupport & ENDPOINT_HARDWARE_SUPPORT_METER)) {
result = device->GetId(&pDeviceId);
CONTINUE_ON_FAIL(result);
std::wstring deviceId(pDeviceId);
CoTaskMemFree(pDeviceId);
//continue;
// ...and no active client...
if (activeClients.find(deviceId) == activeClients.end()) {
result = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
CONTINUE_ON_FAIL(result);
audioClient = std::shared_ptr<IAudioClient>(pAudioClient, &release<IAudioClient>);
//continue;
// ...activate a client
audioClient->GetMixFormat(&format);
audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, format, NULL);
audioClient->Start();
//continue;
activeClients[deviceId] = audioClient;
}
}
// get the peak value and put it in the payload
meterInfo->GetPeakValue(&peakValue);
peakValueList[deviceIndex] = peakValue;
}
emit peakValueListChanged(peakValueList);
}
bool AudioClient::peakValuesAvailable() const {
return true;
}
#else
void AudioClient::checkPeakValues() {
}
bool AudioClient::peakValuesAvailable() const {
return false;
}
#endif

View file

@ -431,7 +431,7 @@ int Octree::readElementData(const OctreeElementPointer& destinationElement, cons
return bytesRead; return bytesRead;
} }
void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int bufferSizeBytes, void Octree::readBitstreamToTree(const unsigned char * bitstream, uint64_t bufferSizeBytes,
ReadBitstreamToTreeParams& args) { ReadBitstreamToTreeParams& args) {
int bytesRead = 0; int bytesRead = 0;
const unsigned char* bitstreamAt = bitstream; const unsigned char* bitstreamAt = bitstream;
@ -925,8 +925,8 @@ int Octree::encodeTreeBitstream(const OctreeElementPointer& element,
roomForOctalCode = packetData->startSubTree(newCode); roomForOctalCode = packetData->startSubTree(newCode);
if (newCode) { if (newCode) {
delete[] newCode;
codeLength = numberOfThreeBitSectionsInCode(newCode); codeLength = numberOfThreeBitSectionsInCode(newCode);
delete[] newCode;
} else { } else {
codeLength = 1; codeLength = 1;
} }
@ -1152,7 +1152,6 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element,
OctreeElementPointer sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; OctreeElementPointer sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
float distancesToChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; float distancesToChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int indexOfChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int indexOfChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int currentCount = 0;
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
OctreeElementPointer childElement = element->getChildAtIndex(i); OctreeElementPointer childElement = element->getChildAtIndex(i);
@ -1174,7 +1173,6 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element,
sortedChildren[i] = childElement; sortedChildren[i] = childElement;
indexOfChildren[i] = i; indexOfChildren[i] = i;
distancesToChildren[i] = 0.0f; distancesToChildren[i] = 0.0f;
currentCount++;
// track stats // track stats
// must check childElement here, because it could be we got here with no childElement // must check childElement here, because it could be we got here with no childElement
@ -1185,7 +1183,7 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element,
// for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
// add them to our distance ordered array of children // add them to our distance ordered array of children
for (int i = 0; i < currentCount; i++) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
OctreeElementPointer childElement = sortedChildren[i]; OctreeElementPointer childElement = sortedChildren[i];
int originalIndex = indexOfChildren[i]; int originalIndex = indexOfChildren[i];
@ -1276,7 +1274,7 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element,
} }
// NOTE: the childrenDataBits indicates that there is an array of child element data included in this packet. // NOTE: the childrenDataBits indicates that there is an array of child element data included in this packet.
// We wil write this bit mask but we may come back later and update the bits that are actually included // We will write this bit mask but we may come back later and update the bits that are actually included
packetData->releaseReservedBytes(sizeof(childrenDataBits)); packetData->releaseReservedBytes(sizeof(childrenDataBits));
continueThisLevel = packetData->appendBitMask(childrenDataBits); continueThisLevel = packetData->appendBitMask(childrenDataBits);
@ -1441,7 +1439,7 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element,
// for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
// add them to our distance ordered array of children // add them to our distance ordered array of children
for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { for (int indexByDistance = 0; indexByDistance < NUMBER_OF_CHILDREN; indexByDistance++) {
OctreeElementPointer childElement = sortedChildren[indexByDistance]; OctreeElementPointer childElement = sortedChildren[indexByDistance];
int originalIndex = indexOfChildren[indexByDistance]; int originalIndex = indexOfChildren[indexByDistance];
@ -1638,7 +1636,7 @@ bool Octree::readFromFile(const char* fileName) {
QDataStream fileInputStream(&file); QDataStream fileInputStream(&file);
QFileInfo fileInfo(qFileName); QFileInfo fileInfo(qFileName);
unsigned long fileLength = fileInfo.size(); uint64_t fileLength = fileInfo.size();
emit importSize(1.0f, 1.0f, 1.0f); emit importSize(1.0f, 1.0f, 1.0f);
emit importProgress(0); emit importProgress(0);
@ -1715,7 +1713,7 @@ bool Octree::readFromURL(const QString& urlString) {
} }
bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream, const QString& marketplaceID) { bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID) {
// decide if this is binary SVO or JSON-formatted SVO // decide if this is binary SVO or JSON-formatted SVO
QIODevice *device = inputStream.device(); QIODevice *device = inputStream.device();
char firstChar; char firstChar;
@ -1732,14 +1730,14 @@ bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream
} }
bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStream) { bool Octree::readSVOFromStream(uint64_t streamLength, QDataStream& inputStream) {
qWarning() << "SVO file format depricated. Support for reading SVO files is no longer support and will be removed soon."; qWarning() << "SVO file format depricated. Support for reading SVO files is no longer support and will be removed soon.";
bool fileOk = false; bool fileOk = false;
PacketVersion gotVersion = 0; PacketVersion gotVersion = 0;
unsigned long headerLength = 0; // bytes in the header uint64_t headerLength = 0; // bytes in the header
bool wantImportProgress = true; bool wantImportProgress = true;
@ -1751,14 +1749,14 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr
if (getWantSVOfileVersions()) { if (getWantSVOfileVersions()) {
// read just enough of the file to parse the header... // read just enough of the file to parse the header...
const unsigned long HEADER_LENGTH = sizeof(int) + sizeof(PacketVersion); const uint64_t HEADER_LENGTH = sizeof(int) + sizeof(PacketVersion);
unsigned char fileHeader[HEADER_LENGTH]; unsigned char fileHeader[HEADER_LENGTH];
inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH);
headerLength = HEADER_LENGTH; // we need this later to skip to the data headerLength = HEADER_LENGTH; // we need this later to skip to the data
unsigned char* dataAt = (unsigned char*)&fileHeader; unsigned char* dataAt = (unsigned char*)&fileHeader;
unsigned long dataLength = HEADER_LENGTH; uint64_t dataLength = HEADER_LENGTH;
// if so, read the first byte of the file and see if it matches the expected version code // if so, read the first byte of the file and see if it matches the expected version code
int intPacketType; int intPacketType;
@ -1804,7 +1802,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr
if (!hasBufferBreaks) { if (!hasBufferBreaks) {
// read the entire file into a buffer, WHAT!? Why not. // read the entire file into a buffer, WHAT!? Why not.
unsigned long dataLength = streamLength - headerLength; uint64_t dataLength = streamLength - headerLength;
unsigned char* entireFileDataSection = new unsigned char[dataLength]; unsigned char* entireFileDataSection = new unsigned char[dataLength];
inputStream.readRawData((char*)entireFileDataSection, dataLength); inputStream.readRawData((char*)entireFileDataSection, dataLength);
@ -1819,9 +1817,9 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr
} else { } else {
unsigned long dataLength = streamLength - headerLength; uint64_t dataLength = streamLength - headerLength;
unsigned long remainingLength = dataLength; uint64_t remainingLength = dataLength;
const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2; const uint64_t MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2;
unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH]; unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH];
while (remainingLength > 0) { while (remainingLength > 0) {
@ -1847,7 +1845,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr
remainingLength -= chunkLength; remainingLength -= chunkLength;
unsigned char* dataAt = fileChunk; unsigned char* dataAt = fileChunk;
unsigned long dataLength = chunkLength; uint64_t dataLength = chunkLength;
ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0,
SharedNodePointer(), wantImportProgress, gotVersion); SharedNodePointer(), wantImportProgress, gotVersion);
@ -1887,7 +1885,7 @@ QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QStri
const int READ_JSON_BUFFER_SIZE = 2048; const int READ_JSON_BUFFER_SIZE = 2048;
bool Octree::readJSONFromStream(unsigned long streamLength, QDataStream& inputStream, const QString& marketplaceID /*=""*/) { bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID /*=""*/) {
// if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until
// we get an eof. Leave streamLength parameter for consistency. // we get an eof. Leave streamLength parameter for consistency.
@ -1982,14 +1980,14 @@ bool Octree::writeToJSONFile(const char* fileName, const OctreeElementPointer& e
return success; return success;
} }
unsigned long Octree::getOctreeElementsCount() { uint64_t Octree::getOctreeElementsCount() {
unsigned long nodeCount = 0; uint64_t nodeCount = 0;
recurseTreeWithOperation(countOctreeElementsOperation, &nodeCount); recurseTreeWithOperation(countOctreeElementsOperation, &nodeCount);
return nodeCount; return nodeCount;
} }
bool Octree::countOctreeElementsOperation(const OctreeElementPointer& element, void* extraData) { bool Octree::countOctreeElementsOperation(const OctreeElementPointer& element, void* extraData) {
(*(unsigned long*)extraData)++; (*(uint64_t*)extraData)++;
return true; // keep going return true; // keep going
} }

View file

@ -14,6 +14,7 @@
#include <memory> #include <memory>
#include <set> #include <set>
#include <stdint.h>
#include <QHash> #include <QHash>
#include <QObject> #include <QObject>
@ -231,7 +232,7 @@ public:
virtual void eraseAllOctreeElements(bool createNewRoot = true); virtual void eraseAllOctreeElements(bool createNewRoot = true);
void readBitstreamToTree(const unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args); void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args);
void deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE); void deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE);
void reaverageOctreeElements(OctreeElementPointer startElement = OctreeElementPointer()); void reaverageOctreeElements(OctreeElementPointer startElement = OctreeElementPointer());
@ -301,13 +302,13 @@ public:
// Octree importers // Octree importers
bool readFromFile(const char* filename); bool readFromFile(const char* filename);
bool readFromURL(const QString& url); // will support file urls as well... bool readFromURL(const QString& url); // will support file urls as well...
bool readFromStream(unsigned long streamLength, QDataStream& inputStream, const QString& marketplaceID=""); bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="");
bool readSVOFromStream(unsigned long streamLength, QDataStream& inputStream); bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream);
bool readJSONFromStream(unsigned long streamLength, QDataStream& inputStream, const QString& marketplaceID=""); bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="");
bool readJSONFromGzippedFile(QString qFileName); bool readJSONFromGzippedFile(QString qFileName);
virtual bool readFromMap(QVariantMap& entityDescription) = 0; virtual bool readFromMap(QVariantMap& entityDescription) = 0;
unsigned long getOctreeElementsCount(); uint64_t getOctreeElementsCount();
bool getShouldReaverage() const { return _shouldReaverage; } bool getShouldReaverage() const { return _shouldReaverage; }

View file

@ -24,13 +24,6 @@ namespace Cursor {
return _icon; return _icon;
} }
class MouseInstance : public Instance {
Source getType() const override {
return Source::MOUSE;
}
};
QMap<uint16_t, QString> Manager::ICON_NAMES { QMap<uint16_t, QString> Manager::ICON_NAMES {
{ Icon::SYSTEM, "SYSTEM", }, { Icon::SYSTEM, "SYSTEM", },
{ Icon::DEFAULT, "DEFAULT", }, { Icon::DEFAULT, "DEFAULT", },
@ -38,7 +31,7 @@ namespace Cursor {
{ Icon::ARROW, "ARROW", }, { Icon::ARROW, "ARROW", },
{ Icon::RETICLE, "RETICLE", }, { Icon::RETICLE, "RETICLE", },
}; };
QMap<uint16_t, QString> Manager::ICONS;
static uint16_t _customIconId = Icon::USER_BASE; static uint16_t _customIconId = Icon::USER_BASE;
Manager::Manager() { Manager::Manager() {
@ -62,8 +55,8 @@ namespace Cursor {
} }
Manager& Manager::instance() { Manager& Manager::instance() {
static Manager instance; static QSharedPointer<Manager> instance = DependencyManager::get<Cursor::Manager>();
return instance; return *instance;
} }
QList<uint16_t> Manager::registeredIcons() const { QList<uint16_t> Manager::registeredIcons() const {
@ -76,7 +69,6 @@ namespace Cursor {
Instance* Manager::getCursor(uint8_t index) { Instance* Manager::getCursor(uint8_t index) {
Q_ASSERT(index < getCount()); Q_ASSERT(index < getCount());
static MouseInstance mouseInstance;
if (index == 0) { if (index == 0) {
return &mouseInstance; return &mouseInstance;
} }

View file

@ -8,6 +8,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <DependencyManager.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
@ -39,7 +40,15 @@ namespace Cursor {
uint16_t _icon; uint16_t _icon;
}; };
class Manager { class MouseInstance : public Instance {
Source getType() const override {
return Source::MOUSE;
}
};
class Manager : public QObject, public Dependency {
SINGLETON_DEPENDENCY
Manager(); Manager();
Manager(const Manager& other) = delete; Manager(const Manager& other) = delete;
public: public:
@ -52,12 +61,13 @@ namespace Cursor {
QList<uint16_t> registeredIcons() const; QList<uint16_t> registeredIcons() const;
const QString& getIconImage(uint16_t icon); const QString& getIconImage(uint16_t icon);
static QMap<uint16_t, QString> ICONS;
static QMap<uint16_t, QString> ICON_NAMES; static QMap<uint16_t, QString> ICON_NAMES;
static Icon lookupIcon(const QString& name); static Icon lookupIcon(const QString& name);
static const QString& getIconName(const Icon& icon); static const QString& getIconName(const Icon& icon);
private: private:
MouseInstance mouseInstance;
float _scale{ 1.0f }; float _scale{ 1.0f };
QMap<uint16_t, QString> ICONS;
}; };
} }

View file

@ -554,20 +554,19 @@ void OffscreenUi::createDesktop(const QUrl& url) {
getSurfaceContext()->setContextProperty("DebugQML", QVariant(false)); getSurfaceContext()->setContextProperty("DebugQML", QVariant(false));
#endif #endif
_desktop = dynamic_cast<QQuickItem*>(load(url)); load(url, [=](QQmlContext* context, QObject* newObject) {
Q_ASSERT(_desktop); _desktop = static_cast<QQuickItem*>(newObject);
getSurfaceContext()->setContextProperty("desktop", _desktop); getSurfaceContext()->setContextProperty("desktop", _desktop);
_toolWindow = _desktop->findChild<QQuickItem*>("ToolWindow");
_toolWindow = _desktop->findChild<QQuickItem*>("ToolWindow"); _vrMenu = new VrMenu(this);
for (const auto& menuInitializer : _queuedMenuInitializers) {
menuInitializer(_vrMenu);
}
_vrMenu = new VrMenu(this); new KeyboardFocusHack();
for (const auto& menuInitializer : _queuedMenuInitializers) { connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
menuInitializer(_vrMenu); });
}
new KeyboardFocusHack();
connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
} }
QQuickItem* OffscreenUi::getDesktop() { QQuickItem* OffscreenUi::getDesktop() {

View file

@ -639,7 +639,7 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
_qmlContext->setBaseUrl(baseUrl); _qmlContext->setBaseUrl(baseUrl);
} }
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
qCWarning(uiLogging) << "Called load on a non-surface thread"; qCWarning(uiLogging) << "Called load on a non-surface thread";
} }
@ -662,32 +662,32 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext,
[this, qmlComponent, targetContext, f](QQmlComponent::Status) { [this, qmlComponent, targetContext, f](QQmlComponent::Status) {
finishQmlLoad(qmlComponent, targetContext, f); finishQmlLoad(qmlComponent, targetContext, f);
}); });
return nullptr; return;
} }
return finishQmlLoad(qmlComponent, targetContext, f); finishQmlLoad(qmlComponent, targetContext, f);
} }
QObject* OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
return load(qmlSource, true, f); load(qmlSource, true, f);
} }
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
return load(qmlSource, false, f); load(qmlSource, false, f);
} }
void OffscreenQmlSurface::clearCache() { void OffscreenQmlSurface::clearCache() {
_qmlContext->engine()->clearComponentCache(); _qmlContext->engine()->clearComponentCache();
} }
QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f) { void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f) {
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (qmlComponent->isError()) { if (qmlComponent->isError()) {
for (const auto& error : qmlComponent->errors()) { for (const auto& error : qmlComponent->errors()) {
qCWarning(uiLogging) << error.url() << error.line() << error; qCWarning(uiLogging) << error.url() << error.line() << error;
} }
qmlComponent->deleteLater(); qmlComponent->deleteLater();
return nullptr; return;
} }
@ -700,7 +700,7 @@ QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlCon
qFatal("Unable to finish loading QML root"); qFatal("Unable to finish loading QML root");
} }
qmlComponent->deleteLater(); qmlComponent->deleteLater();
return nullptr; return;
} }
qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
@ -726,19 +726,19 @@ QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlCon
} }
// If we already have a root, just set a couple of flags and the ancestry // If we already have a root, just set a couple of flags and the ancestry
if (_rootItem) { if (newItem && _rootItem) {
// Allow child windows to be destroyed from JS // Allow child windows to be destroyed from JS
QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership);
newObject->setParent(_rootItem); newObject->setParent(_rootItem);
if (newItem) { if (newItem) {
newItem->setParentItem(_rootItem); newItem->setParentItem(_rootItem);
} }
return newObject; return;
} }
if (!newItem) { if (!newItem) {
qFatal("Could not load object as root item"); qFatal("Could not load object as root item");
return nullptr; return;
} }
connect(newItem, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(QVariant))); connect(newItem, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(QVariant)));
@ -747,7 +747,6 @@ QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlCon
_rootItem = newItem; _rootItem = newItem;
_rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setParentItem(_quickWindow->contentItem());
_rootItem->setSize(_quickWindow->renderTargetSize()); _rootItem->setSize(_quickWindow->renderTargetSize());
return _rootItem;
} }
void OffscreenQmlSurface::updateQuick() { void OffscreenQmlSurface::updateQuick() {

View file

@ -50,10 +50,10 @@ public:
void resize(const QSize& size, bool forceResize = false); void resize(const QSize& size, bool forceResize = false);
QSize size() const; QSize size() const;
Q_INVOKABLE QObject* load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}); Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
Q_INVOKABLE QObject* loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}); Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}); Q_INVOKABLE void load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) { Q_INVOKABLE void load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) {
return load(QUrl(qmlSourceFile), f); return load(QUrl(qmlSourceFile), f);
} }
void clearCache(); void clearCache();
@ -120,7 +120,7 @@ protected:
private: private:
static QOpenGLContext* getSharedContext(); static QOpenGLContext* getSharedContext();
QObject* finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f); void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f);
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
void setupFbo(); void setupFbo();
bool allowNewFrame(uint8_t fps); bool allowNewFrame(uint8_t fps);

View file

@ -71,6 +71,10 @@
case 'maybeEnableHmdPreview': case 'maybeEnableHmdPreview':
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled); Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
break; break;
case 'passphraseReset':
onButtonClicked();
onButtonClicked();
break;
case 'walletReset': case 'walletReset':
onButtonClicked(); onButtonClicked();
onButtonClicked(); onButtonClicked();

View file

@ -539,7 +539,7 @@ clickMapping.from(Controller.Standard.Start).peek().to(function (clicked) {
if (clicked) { if (clicked) {
activeHudPoint2dGamePad(); activeHudPoint2dGamePad();
var noHands = -1; var noHands = -1;
Messages.sendLocalMessage("toggleHand", noHands); Messages.sendLocalMessage("toggleHand", Controller.Standard.LeftHand);
} }
wantsMenu = clicked; wantsMenu = clicked;

View file

@ -68,6 +68,9 @@ function onHmdChanged(isHmd) {
function onClicked() { function onClicked() {
var isDesktop = Menu.isOptionChecked(desktopMenuItemName); var isDesktop = Menu.isOptionChecked(desktopMenuItemName);
Menu.setIsOptionChecked(isDesktop ? headset : desktopMenuItemName, true); Menu.setIsOptionChecked(isDesktop ? headset : desktopMenuItemName, true);
if (!isDesktop) {
UserActivityLogger.logAction("exit_vr");
}
} }
if (headset) { if (headset) {