Light Launchers
104
launchers/darwin/CMakeLists.txt
Normal file
|
@ -0,0 +1,104 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project(HQLauncher)
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
|
||||
set(src_files
|
||||
src/Launcher.h
|
||||
src/Launcher.m
|
||||
src/SplashScreen.h
|
||||
src/SplashScreen.m
|
||||
src/LoginScreen.h
|
||||
src/LoginScreen.m
|
||||
src/DisplayNameScreen.h
|
||||
src/DisplayNameScreen.m
|
||||
src/ProcessScreen.h
|
||||
src/ProcessScreen.m
|
||||
src/Window.h
|
||||
src/Window.m
|
||||
src/DownloadInterface.h
|
||||
src/DownloadInterface.m
|
||||
src/DownloadDomainContent.h
|
||||
src/DownloadDomainContent.m
|
||||
src/DownloadScripts.h
|
||||
src/DownloadScripts.m
|
||||
src/CredentialsRequest.h
|
||||
src/CredentialsRequest.m
|
||||
src/LatestBuildRequest.h
|
||||
src/LatestBuildRequest.m
|
||||
src/OrganizationRequest.m
|
||||
src/OrganizationRequest.h
|
||||
src/ErrorViewController.h
|
||||
src/ErrorViewController.m
|
||||
src/Settings.h
|
||||
src/Settings.m
|
||||
src/LaunchInterface.h
|
||||
src/CustomUI.h
|
||||
src/CustomUI.m
|
||||
src/main.mm
|
||||
nib/Window.xib
|
||||
nib/SplashScreen.xib
|
||||
nib/ErrorScreen.xib
|
||||
nib/LoginScreen.xib
|
||||
nib/ProcessScreen.xib
|
||||
nib/DisplayNameScreen.xib)
|
||||
|
||||
set(APP_NAME "HQ Launcher")
|
||||
|
||||
set(CMAKE_C_FLAGS "-x objective-c")
|
||||
set(CMAKE_CXX_FLAGS "-x objective-c++")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-framework Cocoa -framework AppKit -framework QuartzCore")
|
||||
|
||||
set_target_properties(${this_target} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
||||
|
||||
|
||||
set(MACOSX_BUNDLE_ICON_FILE "interface.icns")
|
||||
|
||||
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME})
|
||||
|
||||
|
||||
|
||||
file(GLOB NIB_FILES "nib/*.xib")
|
||||
|
||||
find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
|
||||
foreach (nibFile ${NIB_FILES})
|
||||
get_filename_component(fileWithExtension ${nibFile} NAME)
|
||||
string(REGEX REPLACE "\\.[^.]*$" "" file ${fileWithExtension})
|
||||
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${IBTOOL} --errors --warnings --notices
|
||||
--output-format human-readable-text
|
||||
--compile
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/${file}.nib"
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/nib/${file}.xib)
|
||||
endforeach()
|
||||
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/images "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/")
|
||||
|
||||
install(
|
||||
TARGETS HQLauncher
|
||||
BUNDLE DESTINATION "."
|
||||
COMPONENT applications
|
||||
)
|
||||
|
||||
|
||||
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR})
|
||||
|
||||
include(CPackComponent)
|
||||
|
||||
set(CPACK_PACKAGE_NAME "HQ Launcher")
|
||||
set(CPACK_PACKAGE_VENDOR "High Fidelity")
|
||||
set(CPACK_PACKAGE_VERSION ${BUILD_VERSION})
|
||||
set(CPACK_PACKAGE_FILE_NAME "HQ Launcher")
|
||||
|
||||
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
|
||||
|
||||
set(DMG_SUBFOLDER_NAME "High Fidelity")
|
||||
set(ESCAPED_DMG_SUBFOLDER_NAME "")
|
||||
set(DMG_SUBFOLDER_ICON "${CMAKE_SOURCE_DIR}/cmake/installer/install-folder.rsrc")
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
include(CPack)
|
BIN
launchers/darwin/cmake/installer/Thumbs.db
Normal file
1634
launchers/darwin/cmake/installer/install-folder.rsrc
Normal file
BIN
launchers/darwin/cmake/installer/installer-header.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
launchers/darwin/cmake/installer/installer.ico
Normal file
After Width: | Height: | Size: 299 KiB |
BIN
launchers/darwin/cmake/installer/uninstaller-header.bmp
Normal file
After Width: | Height: | Size: 100 KiB |
35
launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.highfidelity.launcher</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>Window</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>HQ Launcher</string>
|
||||
</dict>
|
||||
</plist>
|
BIN
launchers/darwin/images/HiFi_Logo_Large.png
Normal file
After Width: | Height: | Size: 5 KiB |
BIN
launchers/darwin/images/HiFi_Logo_Small.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
launchers/darwin/images/HiFi_Voxel.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
launchers/darwin/images/HiFi_Window.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
14
launchers/darwin/images/Hifi_Logo.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<svg width="100" height="18" viewBox="0 0 100 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.27077 0.0930176V6.06095H2.98187V0.0930176H0V13.8509H2.98187V8.41861H8.27077V13.8509H11.2526V0.0930176H8.27077Z" fill="white"/>
|
||||
<path d="M12.982 4.21763H15.6348V13.8507H12.982V4.21763ZM12.7753 1.45509C12.7753 0.628432 13.4374 0 14.2852 0C15.1498 0 15.8162 0.628432 15.8162 1.45509C15.8162 2.28174 15.154 2.91018 14.2852 2.91018C13.4417 2.91018 12.7753 2.28596 12.7753 1.45509Z" fill="white"/>
|
||||
<path d="M23.8844 8.78563V8.65488C23.8844 7.01422 23.0198 6.01886 21.5647 6.01886C20.0716 6.01886 19.2408 7.08591 19.2408 8.67174V8.81937C19.2408 10.4221 20.1813 11.4174 21.5056 11.4174C22.9059 11.4216 23.8844 10.4263 23.8844 8.78563ZM16.5879 14.0534H19.2408C19.4052 14.9012 20.0168 15.4537 21.3791 15.4537C22.9987 15.4537 23.8085 14.6059 23.8085 13.096V11.641C23.2728 12.5815 22.134 13.4292 20.7127 13.4292C18.3719 13.4292 16.512 11.6789 16.512 8.82357V8.69705C16.512 5.9345 18.3551 3.99863 20.7507 3.99863C22.3154 3.99863 23.2559 4.67766 23.8085 5.65615V4.21793H26.4613V13.096C26.4445 15.9514 24.5465 17.4065 21.3791 17.4065C18.2665 17.4065 16.8494 16.0442 16.5879 14.0534Z" fill="white"/>
|
||||
<path d="M27.8997 0.092804H30.5694V5.74441C31.046 4.78701 32.1004 3.99411 33.7031 3.99411C35.601 3.99411 36.9423 5.13709 36.9423 7.71406V13.8465H34.2725V8.09786C34.2725 6.79039 33.7579 6.16618 32.577 6.16618C31.434 6.16618 30.5694 6.86631 30.5694 8.28343V13.8465H27.8997V0.092804V0.092804Z" fill="white"/>
|
||||
<path d="M41.8979 0.0930176H50.3501V2.4338H44.8798V6.50379H49.8693V8.74758H44.8798V13.8509H41.8979V0.0930176Z" fill="white"/>
|
||||
<path d="M51.5437 4.21763H54.1965V13.8507H51.5437V4.21763ZM51.3412 1.45509C51.3412 0.628432 52.0034 0 52.8511 0C53.7157 0 54.3821 0.628432 54.3821 1.45509C54.3821 2.28174 53.7199 2.91018 52.8511 2.91018C52.0034 2.91018 51.3412 2.28596 51.3412 1.45509Z" fill="white"/>
|
||||
<path d="M62.4757 9.08057V8.93294C62.4757 7.01814 61.628 6.03965 60.1729 6.03965C58.6798 6.03965 57.8532 7.05188 57.8532 8.96669V9.11429C57.8532 11.0291 58.7726 11.9696 60.1012 11.9696C61.4972 11.9739 62.4757 11.0333 62.4757 9.08057ZM55.1244 9.17335V9.02574C55.1244 5.8583 56.9464 3.99833 59.3589 3.99833C60.9068 3.99833 61.8642 4.67737 62.3998 5.65586V0.092804H65.0527V13.8507H62.3998V12.248C61.9021 13.2223 60.7254 14.0531 59.304 14.0531C56.9675 14.0531 55.1244 12.3787 55.1244 9.17335Z" fill="white"/>
|
||||
<path d="M73.0239 7.99693C72.9311 6.54185 72.1972 5.84173 70.9235 5.84173C69.7257 5.84173 68.9159 6.63464 68.7135 7.99693H73.0239ZM65.9678 9.15678V9.00915C65.9678 5.96824 68.123 3.99863 70.9235 3.99863C73.4077 3.99863 75.6219 5.4537 75.6219 8.89529V9.63337H68.6797C68.7556 11.2361 69.6203 12.1555 71.0753 12.1555C72.3111 12.1555 72.9185 11.6199 73.0829 10.8101H75.6051C75.293 12.8936 73.6354 14.0534 70.9994 14.0534C68.085 14.0534 65.9678 12.2314 65.9678 9.15678Z" fill="white"/>
|
||||
<path d="M79.2661 0.0930176H76.6133V13.8509H79.2661V0.0930176Z" fill="white"/>
|
||||
<path d="M80.7464 4.21763H83.3993V13.8507H80.7464V4.21763ZM80.5439 1.45509C80.5439 0.628432 81.2061 0 82.0539 0C82.9185 0 83.5849 0.628432 83.5849 1.45509C83.5849 2.28174 82.9227 2.91018 82.0539 2.91018C81.2104 2.91018 80.5439 2.28596 80.5439 1.45509Z" fill="white"/>
|
||||
<path d="M84.8165 10.9618V2.10059H87.4694V4.17987H89.4939V6.07781H87.4694V10.7172C87.4694 11.4932 87.8575 11.8602 88.5365 11.8602C88.9414 11.8602 89.2366 11.8053 89.5487 11.6746V13.737C89.1818 13.8678 88.6461 13.9943 87.9291 13.9943C85.9047 13.9985 84.8165 12.9652 84.8165 10.9618Z" fill="white"/>
|
||||
<path d="M97.4398 4.17957L95.2846 9.96614L92.9481 4.17957H90.0717L93.9055 12.8383L92.21 17.0939H94.7869L99.9999 4.17957H97.4398Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
BIN
launchers/darwin/images/hifi_logo_large@2x.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
launchers/darwin/images/hifi_logo_small@2x.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
launchers/darwin/images/hifi_window@2x.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
launchers/darwin/images/interface.icns
Normal file
95
launchers/darwin/nib/DisplayNameScreen.xib
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="DisplayNameScreen">
|
||||
<connections>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="nCZ-J3-wG5"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aus-lo-eVi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="MYh-TA-w2A"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iAf-Ee-jJL">
|
||||
<rect key="frame" x="95" y="344" width="325" height="33"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Choose a display name" id="GzZ-0d-2JH">
|
||||
<font key="font" metaFont="systemBold" size="28"/>
|
||||
<color key="textColor" name="selectedMenuItemTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7dU-5o-Huh">
|
||||
<rect key="frame" x="45" y="314" width="425" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="This is the name that your teammates will see." id="wNS-nK-rVp">
|
||||
<font key="font" metaFont="system" size="14"/>
|
||||
<color key="textColor" red="0.76862745098039209" green="0.76862745098039209" blue="0.76862745098039209" alpha="0.84705882352941175" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vhg-rq-xUH" customClass="TextField">
|
||||
<rect key="frame" x="104" y="187" width="306" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" focusRingType="none" baseWritingDirection="leftToRight" placeholderString="Display name" id="4ET-nT-5pD">
|
||||
<font key="font" metaFont="system" size="18"/>
|
||||
<color key="textColor" red="0.99999600649999998" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box appearanceType="darkAqua" verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="wHR-wz-Fbe">
|
||||
<rect key="frame" x="104" y="186" width="306" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="j8K-TD-h7e">
|
||||
<rect key="frame" x="381" y="0.0" width="134" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="0XM-bX-guC"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZRz-hZ-qj0" customClass="Hyperlink">
|
||||
<rect key="frame" x="182" y="8" width="150" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Having trouble?" id="j4G-UG-IvP">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="linkColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="linkColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="hyperLink:" target="YVh-OH-vU8" id="JfS-ot-wAP"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xeX-qc-ccB" customClass="HFButton">
|
||||
<rect key="frame" x="205" y="84" width="104" height="42"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="square" title="LOG IN" bezelStyle="shadowlessSquare" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6Ba-S9-5qW">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="18"/>
|
||||
</buttonCell>
|
||||
<color key="contentTintColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<action selector="login:" target="YVh-OH-vU8" id="uzF-yC-tu1"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="138.5" y="154"/>
|
||||
</customView>
|
||||
<customObject id="YVh-OH-vU8" customClass="DisplayNameScreen">
|
||||
<connections>
|
||||
<outlet property="backgroundImage" destination="aus-lo-eVi" id="SRc-pV-lXG"/>
|
||||
<outlet property="displayName" destination="Vhg-rq-xUH" id="Fb5-im-2hx"/>
|
||||
<outlet property="smallLogo" destination="j8K-TD-h7e" id="OVd-p3-nu6"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
</document>
|
83
launchers/darwin/nib/ErrorScreen.xib
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="ErrorViewController">
|
||||
<connections>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="gAZ-dU-ax1"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eih-a8-Pqa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="SuI-2T-YhQ"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jmW-5q-Mf3">
|
||||
<rect key="frame" x="181" y="195" width="152" height="122"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="CG4-WN-GsV"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rv7-io-Gy8">
|
||||
<rect key="frame" x="209" y="122" width="93" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Uh oh." id="juz-EO-k3v">
|
||||
<font key="font" metaFont="systemBold" size="28"/>
|
||||
<color key="textColor" name="selectedTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FkC-xi-3UI">
|
||||
<rect key="frame" x="156" y="105" width="192" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="We seem to have a problem." id="bX3-v1-LLM">
|
||||
<font key="font" metaFont="system" size="15"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tV0-Su-eLX">
|
||||
<rect key="frame" x="156" y="80" width="192" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Please restart Launcher" id="aBw-o2-xZE">
|
||||
<font key="font" metaFont="system" size="15"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Sds-MZ-qhT" customClass="HFButton">
|
||||
<rect key="frame" x="200" y="21" width="110" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="squareTextured" title="Restart" bezelStyle="texturedSquare" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="x7d-uv-o8h">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="resartLauncher:" target="nWn-x7-LxT" id="IDF-qy-N8P"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ugn-Hk-gWL">
|
||||
<rect key="frame" x="381" y="0.0" width="134" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="CBD-Vk-Xd4"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="138.5" y="152"/>
|
||||
</customView>
|
||||
<customObject id="nWn-x7-LxT" customClass="ErrorViewController">
|
||||
<connections>
|
||||
<outlet property="backgroundImage" destination="eih-a8-Pqa" id="2xh-8r-1Qu"/>
|
||||
<outlet property="smallLogo" destination="ugn-Hk-gWL" id="EVI-d3-mf5"/>
|
||||
<outlet property="voxelImage" destination="jmW-5q-Mf3" id="NiI-cY-tAf"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
</document>
|
139
launchers/darwin/nib/LoginScreen.xib
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="LoginScreen">
|
||||
<connections>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="QBq-uY-czz"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView wantsLayer="YES" id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="L56-Jv-0N8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" focusRingType="none" alignment="left" imageScaling="proportionallyDown" id="ONf-d4-EDr"/>
|
||||
<color key="contentTintColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="L7W-3n-OKy" customClass="TextField">
|
||||
<rect key="frame" x="79" y="254" width="353" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" focusRingType="none" baseWritingDirection="leftToRight" alignment="left" placeholderString="Organization name" id="Uiu-RX-Rp5">
|
||||
<font key="font" metaFont="system" size="18"/>
|
||||
<color key="textColor" red="0.99999600649999998" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box focusRingType="none" appearanceType="darkAqua" verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="P9T-5L-LJf">
|
||||
<rect key="frame" x="81" y="253" width="353" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="b9S-wR-tuB" customClass="TextField">
|
||||
<rect key="frame" x="79" y="201" width="357" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" focusRingType="none" baseWritingDirection="leftToRight" alignment="left" placeholderString="Username" id="wju-XU-YvL">
|
||||
<font key="font" metaFont="system" size="18"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box appearanceType="darkAqua" verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="bW2-hT-DSz">
|
||||
<rect key="frame" x="79" y="200" width="353" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<secureTextField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T2i-im-3ID" customClass="SecureTextField">
|
||||
<rect key="frame" x="79" y="145" width="357" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" focusRingType="none" baseWritingDirection="leftToRight" alignment="left" placeholderString="Password" usesSingleLineMode="YES" id="JRs-bw-waZ">
|
||||
<font key="font" metaFont="system" size="18"/>
|
||||
<color key="textColor" red="0.99999600649999998" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</secureTextFieldCell>
|
||||
</secureTextField>
|
||||
<box appearanceType="darkAqua" verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="4y1-Ud-HrR">
|
||||
<rect key="frame" x="82" y="144" width="353" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TRA-Dd-qej">
|
||||
<rect key="frame" x="38" y="307" width="425" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Be sure you've uploaded your Avatar before signing in." id="3q0-ys-GTR">
|
||||
<font key="font" metaFont="system" size="14"/>
|
||||
<color key="textColor" red="0.76862745098039209" green="0.76862745098039209" blue="0.76862745098039209" alpha="0.84705882352941175" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button focusRingType="exterior" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jKE-fV-Tjv" customClass="HFButton">
|
||||
<rect key="frame" x="197" y="57" width="110" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="square" title="NEXT" bezelStyle="shadowlessSquare" alignment="center" state="on" borderStyle="border" focusRingType="exterior" imageScaling="proportionallyUpOrDown" inset="2" id="RZM-vz-5eS">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="systemBold" size="18"/>
|
||||
</buttonCell>
|
||||
<color key="contentTintColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="CornerRadius">
|
||||
<real key="value" value="1"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="TextColorHover">
|
||||
<color key="value" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="goToLogin:" target="NkF-nk-81S" id="e50-vF-R8Y"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hIC-qf-Abj">
|
||||
<rect key="frame" x="63" y="337" width="384" height="33"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Please log in" id="YuE-2K-HLT">
|
||||
<font key="font" metaFont="systemBold" size="28"/>
|
||||
<color key="textColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="A59-kY-Mq3">
|
||||
<rect key="frame" x="381" y="0.0" width="134" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="kZV-oM-dmS"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qCS-xH-551" customClass="Hyperlink">
|
||||
<rect key="frame" x="188" y="20" width="140" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Having trouble?" id="HA3-gC-CiL">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="linkColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="linkColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="havingTrouble:" target="NkF-nk-81S" id="tsf-tC-aqq"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="138.5" y="154"/>
|
||||
</customView>
|
||||
<customObject id="NkF-nk-81S" customClass="LoginScreen">
|
||||
<connections>
|
||||
<outlet property="backgroundImage" destination="L56-Jv-0N8" id="INT-rB-YtG"/>
|
||||
<outlet property="button" destination="jKE-fV-Tjv" id="or6-tG-r6R"/>
|
||||
<outlet property="header" destination="hIC-qf-Abj" id="sVQ-rl-cvR"/>
|
||||
<outlet property="orginization" destination="L7W-3n-OKy" id="TiL-wn-Z2b"/>
|
||||
<outlet property="password" destination="T2i-im-3ID" id="uV1-RG-gfy"/>
|
||||
<outlet property="smallHeader" destination="TRA-Dd-qej" id="9s6-gK-XCw"/>
|
||||
<outlet property="smallLogo" destination="A59-kY-Mq3" id="XgD-NH-16J"/>
|
||||
<outlet property="trouble" destination="qCS-xH-551" id="bQr-eg-dqc"/>
|
||||
<outlet property="username" destination="b9S-wR-tuB" id="91a-SY-AL4"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
</document>
|
65
launchers/darwin/nib/ProcessScreen.xib
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="ProcessScreen">
|
||||
<connections>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="Kzc-tu-LGt"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kuY-e2-Hqb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="Abr-HV-cKq"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Nrc-t3-PSh">
|
||||
<rect key="frame" x="192" y="190" width="131" height="112"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="LNv-HQ-3gb"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EMF-E4-qLL">
|
||||
<rect key="frame" x="30" y="109" width="454" height="41"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Setup will take a moment" id="y9y-tH-HjJ">
|
||||
<font key="font" metaFont="systemBold" size="28"/>
|
||||
<color key="textColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BSg-lp-njL">
|
||||
<rect key="frame" x="33" y="84" width="448" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="We're getting your headquaters ready" id="HeV-5p-9FI">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="alternateSelectedControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uh2-4K-n56">
|
||||
<rect key="frame" x="381" y="0.0" width="134" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="6NP-7q-Mhj"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="138.5" y="154"/>
|
||||
</customView>
|
||||
<customObject id="utv-Iz-V5C" customClass="ProcessScreen">
|
||||
<connections>
|
||||
<outlet property="background" destination="kuY-e2-Hqb" id="CBc-bD-ux7"/>
|
||||
<outlet property="boldStatus" destination="EMF-E4-qLL" id="udm-8B-7lt"/>
|
||||
<outlet property="smallLogo" destination="uh2-4K-n56" id="pYg-hP-nr5"/>
|
||||
<outlet property="smallStatus" destination="BSg-lp-njL" id="ziz-ek-Lq4"/>
|
||||
<outlet property="voxelImage" destination="Nrc-t3-PSh" id="J81-ex-qbE"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
</document>
|
39
launchers/darwin/nib/SplashScreen.xib
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="SplashScreen">
|
||||
<connections>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="dKB-Pi-vXA"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qtD-mb-qqq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="ixM-5m-vi6"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2i5-Zw-nH7">
|
||||
<rect key="frame" x="145" y="72" width="225" height="225"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="qC6-tI-Uwf"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="119.5" y="134"/>
|
||||
</customView>
|
||||
<customObject id="iJ0-FI-XIf" customClass="SplashScreen">
|
||||
<connections>
|
||||
<outlet property="imageView" destination="qtD-mb-qqq" id="rCt-Gd-Uux"/>
|
||||
<outlet property="logoImage" destination="2i5-Zw-nH7" id="7tM-sX-cvR"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
</document>
|
30
launchers/darwin/nib/Window.xib
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner"/>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="Window">
|
||||
<windowStyleMask key="styleMask" closable="YES"/>
|
||||
<rect key="contentRect" x="505" y="583" width="515" height="390"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="515" height="390"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="PE9-qZ-I60" id="YL3-KK-gRc"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="456.5" y="-138"/>
|
||||
</window>
|
||||
<customObject id="PE9-qZ-I60" userLabel="Launcher" customClass="Launcher">
|
||||
<connections>
|
||||
<outlet property="window" destination="QvC-M9-y7g" id="BJP-3M-XAB"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
</document>
|
10
launchers/darwin/src/CredentialsRequest.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface CredentialsRequest : NSObject <NSURLConnectionDelegate> {
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSMutableData* webData;
|
||||
@property (nonatomic, retain) NSString* jsonString;
|
||||
|
||||
- (void) confirmCredentials:(NSString*)username :(NSString*)password;
|
||||
@end
|
95
launchers/darwin/src/CredentialsRequest.m
Normal file
|
@ -0,0 +1,95 @@
|
|||
#import "CredentialsRequest.h"
|
||||
#import "Launcher.h"
|
||||
#import "Settings.h"
|
||||
|
||||
@implementation CredentialsRequest
|
||||
|
||||
- (void) confirmCredentials:(NSString*)username :(NSString*)password {
|
||||
|
||||
NSLog(@"web request started");
|
||||
NSString *post = [NSString stringWithFormat:@"grant_type=password&username=%@&password=%@&scope=owner", username, password];
|
||||
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *postLength = [NSString stringWithFormat:@"%ld", (unsigned long)[postData length]];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest new];
|
||||
[request setURL:[NSURL URLWithString:@"https://metaverse.highfidelity.com/oauth/token"]];
|
||||
[request setHTTPMethod:@"POST"];
|
||||
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
|
||||
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
|
||||
[request setHTTPBody:postData];
|
||||
|
||||
//NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
|
||||
NSURLSession* session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
|
||||
NSLog(@"credentials request finished");
|
||||
NSMutableData* webData = [NSMutableData data];
|
||||
[webData appendData:data];
|
||||
NSString* jsonString = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[data length] encoding:NSUTF8StringEncoding];
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
|
||||
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
if (json[@"error"] != nil) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[Settings sharedSettings] login:FALSE];
|
||||
[sharedLauncher setLoginErrorState: CREDENTIALS];
|
||||
[sharedLauncher credentialsAccepted:FALSE];
|
||||
});
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[Settings sharedSettings] login:TRUE];
|
||||
[sharedLauncher setTokenString:jsonString];
|
||||
[sharedLauncher credentialsAccepted:TRUE];
|
||||
});
|
||||
}
|
||||
|
||||
NSLog(@"credentials: connectionDidFinished completed");
|
||||
|
||||
}];
|
||||
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
[self.webData appendData:data];
|
||||
NSLog(@"credentials connection received data");
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSLog(@"credentials connection received response");
|
||||
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
|
||||
if([ne statusCode] == 200) {
|
||||
NSLog(@"connection state is 200 - all okay");
|
||||
} else {
|
||||
NSLog(@"connection state is NOT 200");
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"Conn Err: %@", [error localizedDescription]);
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
NSLog(@"credentials request finished");
|
||||
NSString* jsonString = [[NSString alloc] initWithBytes: [self.webData mutableBytes] length:[self.webData length] encoding:NSUTF8StringEncoding];
|
||||
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
if (json[@"error"] != nil) {
|
||||
[[Settings sharedSettings] login:FALSE];
|
||||
[sharedLauncher setLoginErrorState: CREDENTIALS];
|
||||
[sharedLauncher credentialsAccepted:FALSE];
|
||||
} else {
|
||||
[[Settings sharedSettings] login:TRUE];
|
||||
[sharedLauncher setTokenString:jsonString];
|
||||
[sharedLauncher credentialsAccepted:TRUE];
|
||||
}
|
||||
|
||||
NSLog(@"credentials: connectionDidFinished completed");
|
||||
}
|
||||
|
||||
@end
|
30
launchers/darwin/src/CustomUI.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import <Quartz/Quartz.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
extern NSString* hifiSmallLogoFilename;
|
||||
extern NSString* hifiLargeLogoFilename;
|
||||
extern NSString* hifiVoxelFilename;
|
||||
extern NSString* hifiBackgroundFilename;
|
||||
|
||||
@interface TextField : NSTextField {
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface SecureTextField : NSSecureTextField {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface HFButton : NSButton
|
||||
|
||||
@property (nonatomic, strong) CATextLayer *titleLayer;
|
||||
|
||||
@end
|
||||
|
||||
@interface Hyperlink : NSTextField {
|
||||
|
||||
}
|
||||
@end
|
118
launchers/darwin/src/CustomUI.m
Normal file
|
@ -0,0 +1,118 @@
|
|||
#import "CustomUI.h"
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
NSString* hifiSmallLogoFilename = @"hifi_logo_small";
|
||||
NSString* hifiLargeLogoFilename = @"hifi_logo_large";
|
||||
NSString* hifiVoxelFilename = @"HiFi_Voxel";
|
||||
NSString* hifiBackgroundFilename = @"hifi_window";
|
||||
|
||||
@implementation TextField
|
||||
- (void) textDidBeginEditing:(NSNotification *)notification
|
||||
{
|
||||
NSColor *insertionPointColor = [NSColor whiteColor];
|
||||
NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
|
||||
forObject:self];
|
||||
fieldEditor.insertionPointColor = insertionPointColor;
|
||||
}
|
||||
- (void) mouseDown:(NSEvent *)event
|
||||
{
|
||||
NSColor *insertionPointColor = [NSColor whiteColor];
|
||||
NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
|
||||
forObject:self];
|
||||
fieldEditor.insertionPointColor = insertionPointColor;
|
||||
|
||||
}
|
||||
|
||||
-(BOOL)becomeFirstResponder
|
||||
{
|
||||
BOOL status = [super becomeFirstResponder];
|
||||
NSColor *insertionPointColor = [NSColor whiteColor];
|
||||
NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
|
||||
forObject:self];
|
||||
fieldEditor.insertionPointColor = insertionPointColor;
|
||||
return status;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SecureTextField
|
||||
|
||||
- (void) textDidBeginEditing:(NSNotification *)notification
|
||||
{
|
||||
NSColor *insertionPointColor = [NSColor whiteColor];
|
||||
NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
|
||||
forObject:self];
|
||||
fieldEditor.insertionPointColor = insertionPointColor;
|
||||
}
|
||||
- (void) mouseDown:(NSEvent *)event
|
||||
{
|
||||
NSColor *insertionPointColor = [NSColor whiteColor];
|
||||
NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
|
||||
forObject:self];
|
||||
fieldEditor.insertionPointColor = insertionPointColor;
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(BOOL)becomeFirstResponder
|
||||
{
|
||||
BOOL status = [super becomeFirstResponder];
|
||||
NSColor *insertionPointColor = [NSColor whiteColor];
|
||||
NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
|
||||
forObject:self];
|
||||
fieldEditor.insertionPointColor = insertionPointColor;
|
||||
return status;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation HFButton
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
// The UI layers implemented in awakeFromNib will handle drawing
|
||||
}
|
||||
|
||||
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
|
||||
self.wantsLayer = YES;
|
||||
self.layer.backgroundColor = [NSColor blackColor].CGColor;
|
||||
self.layer.borderColor = [NSColor whiteColor].CGColor;
|
||||
self.layer.borderWidth = 2.0f;
|
||||
self.layer.masksToBounds = YES;
|
||||
|
||||
_titleLayer = [[CATextLayer alloc] init];
|
||||
|
||||
CGSize buttonSize = self.frame.size;
|
||||
CGSize titleSize = [self.title sizeWithAttributes:@{NSFontAttributeName: self.font}];
|
||||
CGFloat x = (buttonSize.width - titleSize.width) / 2.0; // Title's origin x
|
||||
CGFloat y = (buttonSize.height - titleSize.height) / 2.0; // Title's origin y
|
||||
|
||||
self.titleLayer.frame = NSMakeRect(round(x), round(y), ceil(titleSize.width), ceil(titleSize.height));
|
||||
self.titleLayer.string = self.title;
|
||||
self.titleLayer.foregroundColor = [NSColor whiteColor].CGColor;
|
||||
|
||||
// TODO(huffman) Fix this to be dynamic based on screen?
|
||||
self.titleLayer.contentsScale = 2.0;
|
||||
|
||||
self.titleLayer.font = (__bridge CFTypeRef _Nullable)(self.font);
|
||||
self.titleLayer.fontSize = self.font.pointSize;
|
||||
//self.titleLayer.allowsEdgeAntialiasing = YES;
|
||||
//self.titleLayer.allowsFontSubpixelQuantization = YES;
|
||||
|
||||
[self.layer addSublayer:self.titleLayer];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation Hyperlink
|
||||
|
||||
- (void) mouseDown:(NSEvent *)event
|
||||
{
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
@end
|
5
launchers/darwin/src/DisplayNameScreen.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface DisplayNameScreen : NSViewController {
|
||||
}
|
||||
@end
|
34
launchers/darwin/src/DisplayNameScreen.m
Normal file
|
@ -0,0 +1,34 @@
|
|||
#import "DisplayNameScreen.h"
|
||||
#import "Launcher.h"
|
||||
#import "CustomUI.h"
|
||||
|
||||
@interface DisplayNameScreen ()
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* displayName;
|
||||
@end
|
||||
|
||||
@implementation DisplayNameScreen
|
||||
- (void) awakeFromNib {
|
||||
[self.backgroundImage setImage: [NSImage imageNamed:hifiBackgroundFilename]];
|
||||
[self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]];
|
||||
NSMutableAttributedString* displayNameString = [[NSMutableAttributedString alloc] initWithString:@"Display Name"];
|
||||
|
||||
[displayNameString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0, displayNameString.length)];
|
||||
[displayNameString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,displayNameString.length)];
|
||||
|
||||
[self.displayName setPlaceholderAttributedString:displayNameString];
|
||||
[self.displayName setTarget:self];
|
||||
[self.displayName setAction:@selector(login:)];
|
||||
}
|
||||
|
||||
- (IBAction)login:(id)sender {
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
[sharedLauncher displayNameEntered: [self.displayName stringValue]];
|
||||
}
|
||||
|
||||
- (IBAction)hyperLink:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.highfidelity.com/hq-support"]];
|
||||
}
|
||||
@end
|
8
launchers/darwin/src/DownloadDomainContent.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface DownloadDomainContent : NSObject<NSURLDownloadDelegate> {
|
||||
}
|
||||
|
||||
- (void) downloadDomainContent:(NSString*) domainContentUrl;
|
||||
|
||||
@end
|
84
launchers/darwin/src/DownloadDomainContent.m
Normal file
|
@ -0,0 +1,84 @@
|
|||
#import "DownloadDomainContent.h"
|
||||
#import "Launcher.h"
|
||||
|
||||
@implementation DownloadDomainContent
|
||||
|
||||
- (void) downloadDomainContent:(NSString *)domainContentUrl
|
||||
{
|
||||
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:domainContentUrl]
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:60.0];
|
||||
NSURLDownload* theDownload = [[NSURLDownload alloc] initWithRequest:request delegate:self];
|
||||
|
||||
/*NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
|
||||
completionHandler:
|
||||
^(NSURL *location, NSURLResponse *response,NSError *error) {
|
||||
NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:[response suggestedFilename]];
|
||||
[[NSFileManager defaultManager] moveItemAtURL:location
|
||||
toURL:[NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]
|
||||
error:nil];
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
[sharedLauncher setDownloadContextFilename:[response suggestedFilename]];
|
||||
NSLog(@"extracting domain content file");
|
||||
[sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"content"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadContentFilename]]];
|
||||
|
||||
NSLog(@"finished extracting content file");
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[sharedLauncher domainContentDownloadFinished];
|
||||
});
|
||||
|
||||
}];*/
|
||||
|
||||
//[downloadTask resume];
|
||||
|
||||
if (!theDownload) {
|
||||
NSLog(@"Download Failed");
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
NSLog(@"download domain content: data received");
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
|
||||
if([ne statusCode] == 200) {
|
||||
NSLog(@"connection state is 200 - all okay");
|
||||
} else {
|
||||
NSLog(@"connection state is NOT 200");
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"download domain content - Conn Err: %@", [error localizedDescription]);
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
|
||||
- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
|
||||
{
|
||||
NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:filename];
|
||||
[download setDestination:finalFilePath allowOverwrite:YES];
|
||||
|
||||
[[Launcher sharedLauncher] setDownloadContextFilename:filename];
|
||||
}
|
||||
|
||||
- (void)downloadDidFinish:(NSURLDownload*)download
|
||||
{
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSLog(@"extracting domain content file");
|
||||
[sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"content"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadContentFilename]]];
|
||||
|
||||
NSLog(@"finished extracting content file");
|
||||
|
||||
[sharedLauncher domainContentDownloadFinished];
|
||||
}
|
||||
|
||||
- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response
|
||||
{
|
||||
NSLog(@"Download content set response");
|
||||
}
|
||||
|
||||
@end
|
8
launchers/darwin/src/DownloadInterface.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface DownloadInterface : NSObject <NSURLDownloadDelegate> {
|
||||
}
|
||||
@property (nonatomic, assign) NSString* finalFilePath;
|
||||
|
||||
- (void) downloadInterface:(NSString*) downloadUrl;
|
||||
@end
|
109
launchers/darwin/src/DownloadInterface.m
Normal file
|
@ -0,0 +1,109 @@
|
|||
#import "DownloadInterface.h"
|
||||
#import "Launcher.h"
|
||||
#import "Settings.h"
|
||||
|
||||
@implementation DownloadInterface
|
||||
|
||||
- (void) downloadInterface:(NSString*) downloadUrl
|
||||
{
|
||||
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl]
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:60.0];
|
||||
|
||||
NSURLDownload* theDownload = [[NSURLDownload alloc] initWithRequest:request delegate:self];
|
||||
|
||||
/*NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
|
||||
completionHandler:
|
||||
^(NSURL *location, NSURLResponse *response,NSError *error) {
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSString* finalFilePath = [[sharedLauncher getAppPath] stringByAppendingPathComponent:[response suggestedFilename]];
|
||||
[[Launcher sharedLauncher] setDownloadFilename:[response suggestedFilename]];
|
||||
|
||||
NSLog(@"----------->%@", location);
|
||||
[[NSFileManager defaultManager] moveItemAtURL:location
|
||||
toURL:[NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]
|
||||
error:nil];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString* downloadFileName = [sharedLauncher getDownloadFilename];
|
||||
NSLog(@"!!!!!!%@", downloadFileName);
|
||||
NSLog(@"extract interface zip");
|
||||
[sharedLauncher extractZipFileAtDestination:appPath :[appPath stringByAppendingString:downloadFileName]];
|
||||
NSLog(@"finished extracting interface zip");
|
||||
|
||||
NSLog(@"starting xattr");
|
||||
NSTask* quaratineTask = [[NSTask alloc] init];
|
||||
quaratineTask.launchPath = @"/usr/bin/xattr";
|
||||
quaratineTask.arguments = @[@"-d", @"com.apple.quarantine", [appPath stringByAppendingString:@"interface.app"]];
|
||||
|
||||
[quaratineTask launch];
|
||||
[quaratineTask waitUntilExit];
|
||||
NSLog(@"finished xattr");
|
||||
|
||||
NSString* launcherPath = [appPath stringByAppendingString:@"Launcher"];
|
||||
|
||||
[[Settings sharedSettings] setLauncherPath:launcherPath];
|
||||
[sharedLauncher interfaceFinishedDownloading];
|
||||
|
||||
});
|
||||
}];
|
||||
|
||||
[downloadTask resume];*/
|
||||
}
|
||||
|
||||
- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
|
||||
{
|
||||
self.finalFilePath = [[[Launcher sharedLauncher] getAppPath] stringByAppendingPathComponent:filename];
|
||||
[download setDestination:self.finalFilePath allowOverwrite:YES];
|
||||
|
||||
[[Launcher sharedLauncher] setDownloadFilename:filename];
|
||||
}
|
||||
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
|
||||
if([ne statusCode] == 200) {
|
||||
NSLog(@"download interface connection state is 200 - all okay");
|
||||
} else {
|
||||
NSLog(@"download interface connection state is NOT 200");
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"download interface content - Conn Err: %@", [error localizedDescription]);
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
|
||||
- (void)downloadDidFinish:(NSURLDownload*)download
|
||||
{
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString* downloadFileName = [sharedLauncher getDownloadFilename];
|
||||
|
||||
NSLog(@"extract interface zip");
|
||||
[sharedLauncher extractZipFileAtDestination:appPath :[appPath stringByAppendingString:downloadFileName]];
|
||||
NSLog(@"finished extracting interface zip");
|
||||
|
||||
NSLog(@"starting xattr");
|
||||
NSTask* quaratineTask = [[NSTask alloc] init];
|
||||
quaratineTask.launchPath = @"/usr/bin/xattr";
|
||||
quaratineTask.arguments = @[@"-d", @"com.apple.quarantine", [appPath stringByAppendingString:@"interface.app"]];
|
||||
|
||||
[quaratineTask launch];
|
||||
[quaratineTask waitUntilExit];
|
||||
NSLog(@"finished xattr");
|
||||
|
||||
NSString* launcherPath = [appPath stringByAppendingString:@"Launcher"];
|
||||
|
||||
[[Settings sharedSettings] setLauncherPath:launcherPath];
|
||||
[sharedLauncher interfaceFinishedDownloading];
|
||||
}
|
||||
|
||||
- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response
|
||||
{
|
||||
NSLog(@"Download interface response");
|
||||
}
|
||||
@end
|
8
launchers/darwin/src/DownloadScripts.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface DownloadScripts : NSObject <NSURLDownloadDelegate> {
|
||||
}
|
||||
@property (nonatomic, assign) NSString* finalFilePath;
|
||||
|
||||
- (void) downloadScripts:(NSString*) scriptUrl;
|
||||
@end
|
39
launchers/darwin/src/DownloadScripts.m
Normal file
|
@ -0,0 +1,39 @@
|
|||
#import "DownloadScripts.h"
|
||||
#import "Launcher.h"
|
||||
|
||||
@implementation DownloadScripts
|
||||
|
||||
- (void) downloadScripts:(NSString*) scriptsUrl
|
||||
{
|
||||
/*NSURLRequest* theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:scriptsUrl]
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:6000.0];
|
||||
NSURLDownload *theDownload = [[NSURLDownload alloc] initWithRequest:theRequest delegate:self];
|
||||
|
||||
if (!theDownload) {
|
||||
NSLog(@"Download Failed");
|
||||
}*/
|
||||
}
|
||||
|
||||
- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
|
||||
{
|
||||
NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:filename];
|
||||
[download setDestination:finalFilePath allowOverwrite:YES];
|
||||
|
||||
[[Launcher sharedLauncher] setDownloadScriptsFilename:filename];
|
||||
}
|
||||
|
||||
- (void)downloadDidFinish:(NSURLDownload*)download
|
||||
{
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
[sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"scripts"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadScriptsFilename]]];
|
||||
|
||||
[sharedLauncher domainScriptsDownloadFinished];
|
||||
|
||||
}
|
||||
|
||||
- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response
|
||||
{
|
||||
NSLog(@"DownloadScripts received a response");
|
||||
}
|
||||
@end
|
7
launchers/darwin/src/ErrorViewController.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface ErrorViewController : NSViewController {
|
||||
}
|
||||
|
||||
@end
|
||||
|
26
launchers/darwin/src/ErrorViewController.m
Normal file
|
@ -0,0 +1,26 @@
|
|||
#import "ErrorViewController.h"
|
||||
#import "Launcher.h"
|
||||
#import "CustomUI.h"
|
||||
|
||||
@interface ErrorViewController()
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* voxelImage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ErrorViewController
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
[self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]];
|
||||
[self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]];
|
||||
[self.voxelImage setImage:[NSImage imageNamed:hifiVoxelFilename]];
|
||||
}
|
||||
|
||||
-(IBAction)resartLauncher:(id)sender
|
||||
{
|
||||
[[Launcher sharedLauncher] showLoginScreen];
|
||||
}
|
||||
|
||||
@end
|
10
launchers/darwin/src/LatestBuildRequest.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface LatestBuildRequest : NSObject <NSURLConnectionDelegate> {
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSMutableData* webData;
|
||||
@property (nonatomic, retain) NSString* jsonString;
|
||||
|
||||
- (void) requestLatestBuildInfo;
|
||||
@end
|
104
launchers/darwin/src/LatestBuildRequest.m
Normal file
|
@ -0,0 +1,104 @@
|
|||
#import "LatestBuildRequest.h"
|
||||
#import "Launcher.h"
|
||||
#import "Settings.h"
|
||||
|
||||
@implementation LatestBuildRequest
|
||||
|
||||
- (void) requestLatestBuildInfo {
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest new];
|
||||
[request setURL:[NSURL URLWithString:@"https://thunder.highfidelity.com/builds/api/tags/latest?format=json"]];
|
||||
[request setHTTPMethod:@"GET"];
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
|
||||
NSURLSession* session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSLog(@"credentials request finished");
|
||||
NSMutableData* webData = [NSMutableData data];
|
||||
[webData appendData:data];
|
||||
NSString* jsonString = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[data length] encoding:NSUTF8StringEncoding];
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
|
||||
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSArray *values = [json valueForKey:@"results"];
|
||||
NSDictionary *value = [values objectAtIndex:0];
|
||||
|
||||
|
||||
NSString* buildNumber = [value valueForKey:@"latest_version"];
|
||||
NSDictionary* installers = [value objectForKey:@"installers"];
|
||||
NSDictionary* macInstallerObject = [installers objectForKey:@"mac"];
|
||||
NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"];
|
||||
|
||||
BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
Settings* settings = [Settings sharedSettings];
|
||||
NSInteger currentVersion = [settings latestBuildVersion];
|
||||
BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue);
|
||||
[[Settings sharedSettings] buildVersion:buildNumber.integerValue];
|
||||
|
||||
BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist);
|
||||
[sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl];
|
||||
});
|
||||
}];
|
||||
|
||||
[dataTask resume];
|
||||
|
||||
//NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
|
||||
|
||||
/*if(theConnection) {
|
||||
self.webData = [NSMutableData data];
|
||||
NSLog(@"connection initiated");
|
||||
}*/
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
[self.webData appendData:data];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
|
||||
if([ne statusCode] == 200) {
|
||||
NSLog(@"connection state is 200 - all okay");
|
||||
} else {
|
||||
NSLog(@"connection state is NOT 200");
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"Conn Err: %@", [error localizedDescription]);
|
||||
[[Launcher sharedLauncher] displayErrorPage];
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
self.jsonString = [[NSString alloc] initWithBytes: [self.webData mutableBytes] length:[self.webData length] encoding:NSUTF8StringEncoding];
|
||||
NSData *data = [self.jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
||||
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSArray *values = [json valueForKey:@"results"];
|
||||
NSDictionary *value = [values objectAtIndex:0];
|
||||
|
||||
|
||||
NSString* buildNumber = [value valueForKey:@"latest_version"];
|
||||
NSDictionary* installers = [value objectForKey:@"installers"];
|
||||
NSDictionary* macInstallerObject = [installers objectForKey:@"mac"];
|
||||
NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"];
|
||||
|
||||
BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]];
|
||||
|
||||
Settings* settings = [Settings sharedSettings];
|
||||
NSInteger currentVersion = [settings latestBuildVersion];
|
||||
BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue);
|
||||
[[Settings sharedSettings] buildVersion:buildNumber.integerValue];
|
||||
|
||||
BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist);
|
||||
[sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl];
|
||||
}
|
||||
|
||||
@end
|
5
launchers/darwin/src/LaunchInterface.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
void launchInterface() {
|
||||
}
|
83
launchers/darwin/src/Launcher.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "DownloadInterface.h"
|
||||
#import "CredentialsRequest.h"
|
||||
#import "DownloadDomainContent.h"
|
||||
#import "LatestBuildRequest.h"
|
||||
#import "OrganizationRequest.h"
|
||||
#import "DownloadScripts.h"
|
||||
|
||||
typedef enum processStateTypes
|
||||
{
|
||||
DOWNLOADING_INTERFACE = 0,
|
||||
RUNNING_INTERFACE_AFTER_DOWNLOAD,
|
||||
CHECKING_UPDATE,
|
||||
RUNNING_INTERFACE_AFTER_UPDATE
|
||||
} ProcessState;
|
||||
|
||||
typedef enum LoginErrorTypes
|
||||
{
|
||||
NONE = 0,
|
||||
ORGANIZATION,
|
||||
CREDENTIALS
|
||||
} LoginError;
|
||||
|
||||
@interface Launcher : NSObject <NSApplicationDelegate, NSWindowDelegate, NSURLDownloadDelegate> {
|
||||
}
|
||||
@property (nonatomic, retain) NSString* password;
|
||||
@property (nonatomic, retain) NSString* username;
|
||||
@property (nonatomic, retain) NSString* organization;
|
||||
@property (nonatomic, retain) NSString* userToken;
|
||||
@property (nonatomic, retain) NSString* displayName;
|
||||
@property (nonatomic, retain) NSString* filename;
|
||||
@property (nonatomic, retain) NSString* scriptsFilename;
|
||||
@property (nonatomic, retain) NSString* contentFilename;
|
||||
@property (nonatomic, retain) NSString* domainURL;
|
||||
@property (nonatomic, retain) NSString* domainContentUrl;
|
||||
@property (nonatomic, retain) NSString* domainScriptsUrl;
|
||||
@property (nonatomic, retain) DownloadInterface* downloadInterface;
|
||||
@property (nonatomic, retain) CredentialsRequest* credentialsRequest;
|
||||
@property (nonatomic, retain) DownloadDomainContent* downloadDomainContent;
|
||||
@property (nonatomic, retain) DownloadScripts* downloadScripts;
|
||||
@property (nonatomic, retain) LatestBuildRequest* latestBuildRequest;
|
||||
@property (nonatomic, retain) OrganizationRequest* organizationRequest;
|
||||
@property (nonatomic) BOOL credentialsAccepted;
|
||||
@property (nonatomic) BOOL waitingForCredentialReponse;
|
||||
@property (nonatomic) BOOL gotCredentialResponse;
|
||||
@property (nonatomic) BOOL waitingForInterfaceToTerminate;
|
||||
@property (nonatomic, assign, readwrite) ProcessState processState;
|
||||
@property (nonatomic, assign, readwrite) LoginError loginError;
|
||||
|
||||
- (void) displayNameEntered:(NSString*)aDisplayName;
|
||||
- (void) credentialsEntered:(NSString*)aOrginization :(NSString*)aUsername :(NSString*)aPassword;
|
||||
- (void) credentialsAccepted:(BOOL) aCredentialsAccepted;
|
||||
- (void) domainContentDownloadFinished;
|
||||
- (void) domainScriptsDownloadFinished;
|
||||
- (void) setDomainURLInfo:(NSString*) aDomainURL :(NSString*) aDomainContentUrl :(NSString*) aDomainScriptsUrl;
|
||||
- (void) organizationRequestFinished:(BOOL) aOriginzationAccepted;
|
||||
- (BOOL) loginShouldSetErrorState;
|
||||
- (void) displayErrorPage;
|
||||
- (void) showLoginScreen;
|
||||
- (ProcessState) currentProccessState;
|
||||
- (void) setCurrentProcessState:(ProcessState) aProcessState;
|
||||
- (void) setLoginErrorState:(LoginError) aLoginError;
|
||||
- (LoginError) getLoginErrorState;
|
||||
- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl;
|
||||
- (void) interfaceFinishedDownloading;
|
||||
- (NSString*) getDownloadPathForContentAndScripts;
|
||||
- (void) launchInterface;
|
||||
- (void) extractZipFileAtDestination:(NSString*) destination :(NSString*) file;
|
||||
- (BOOL) isWaitingForInterfaceToTerminate;
|
||||
- (void) setDownloadFilename:(NSString*) aFilename;
|
||||
- (void) setDownloadContextFilename:(NSString*) aFilename;
|
||||
- (void) setDownloadScriptsFilename:(NSString*) aFilename;
|
||||
- (void) setTokenString:(NSString*) aToken;
|
||||
- (NSString*) getTokenString;
|
||||
- (NSString*) getDownloadContentFilename;
|
||||
- (NSString*) getDownloadScriptsFilename;
|
||||
- (NSString*) getDownloadFilename;
|
||||
- (BOOL) isLoadedIn;
|
||||
- (NSString*) getAppPath;
|
||||
|
||||
+ (id) sharedLauncher;
|
||||
@end
|
||||
|
364
launchers/darwin/src/Launcher.m
Normal file
|
@ -0,0 +1,364 @@
|
|||
#import "Launcher.h"
|
||||
#import "Window.h"
|
||||
#import "SplashScreen.h"
|
||||
#import "LoginScreen.h"
|
||||
#import "DisplayNameScreen.h"
|
||||
#import "ProcessScreen.h"
|
||||
#import "ErrorViewController.h"
|
||||
#import "Settings.h"
|
||||
|
||||
@interface Launcher ()
|
||||
|
||||
@property (strong) IBOutlet Window* window;
|
||||
@property (nonatomic, assign) NSString* finalFilePath;
|
||||
@property (nonatomic, assign) NSButton* button;
|
||||
@end
|
||||
|
||||
|
||||
static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||
@implementation Launcher
|
||||
+ (id) sharedLauncher {
|
||||
static Launcher* sharedLauncher = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedLauncher = [[self alloc]init];
|
||||
});
|
||||
return sharedLauncher;
|
||||
}
|
||||
|
||||
-(id)init {
|
||||
if (self = [super init]) {
|
||||
self.username = [[NSString alloc] initWithString:@"Default Property Value"];
|
||||
self.downloadInterface = [DownloadInterface alloc];
|
||||
self.downloadDomainContent = [DownloadDomainContent alloc];
|
||||
self.credentialsRequest = [CredentialsRequest alloc];
|
||||
self.latestBuildRequest = [LatestBuildRequest alloc];
|
||||
self.organizationRequest = [OrganizationRequest alloc];
|
||||
self.downloadScripts = [DownloadScripts alloc];
|
||||
self.credentialsAccepted = TRUE;
|
||||
self.gotCredentialResponse = FALSE;
|
||||
self.waitingForCredentialReponse = FALSE;
|
||||
self.waitingForInterfaceToTerminate = FALSE;
|
||||
self.userToken = nil;
|
||||
self.processState = DOWNLOADING_INTERFACE;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)awakeFromNib {
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||
selector:@selector(didTerminateApp:)
|
||||
name:NSWorkspaceDidTerminateApplicationNotification
|
||||
object:nil];
|
||||
|
||||
SplashScreen* splashScreen = [[SplashScreen alloc] initWithNibName:@"SplashScreen" bundle:nil];
|
||||
[self.window setContentViewController: splashScreen];
|
||||
[self closeInterfaceIfRunning];
|
||||
|
||||
if (!self.waitingForInterfaceToTerminate) {
|
||||
[self checkLoginStatus];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString*) getDownloadPathForContentAndScripts
|
||||
{
|
||||
NSString* filePath = [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]
|
||||
stringByAppendingString:@"/Launcher/"];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
|
||||
NSError * error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:TRUE attributes:nil error:&error];
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
- (void) extractZipFileAtDestination:(NSString *)destination :(NSString*)file
|
||||
{
|
||||
NSTask* task = [[NSTask alloc] init];
|
||||
task.launchPath = @"/usr/bin/unzip";
|
||||
task.arguments = @[@"-o", @"-d", destination, file];
|
||||
|
||||
[task launch];
|
||||
[task waitUntilExit];
|
||||
|
||||
if (DELETE_ZIP_FILES) {
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
[fileManager removeItemAtPath:file error:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) displayErrorPage
|
||||
{
|
||||
ErrorViewController* errorPage = [[ErrorViewController alloc] initWithNibName:@"ErrorScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: errorPage];
|
||||
}
|
||||
|
||||
- (void) checkLoginStatus
|
||||
{
|
||||
if ([self isLoadedIn]) {
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
[sharedLauncher setCurrentProcessState:CHECKING_UPDATE];
|
||||
ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
|
||||
[self.latestBuildRequest requestLatestBuildInfo];
|
||||
} else {
|
||||
[NSTimer scheduledTimerWithTimeInterval:2.0
|
||||
target:self
|
||||
selector:@selector(onSplashScreenTimerFinished:)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setDownloadContextFilename:(NSString *)aFilename
|
||||
{
|
||||
self.contentFilename = aFilename;
|
||||
}
|
||||
|
||||
- (void) setDownloadScriptsFilename:(NSString*)aFilename
|
||||
{
|
||||
self.scriptsFilename = aFilename;
|
||||
}
|
||||
|
||||
- (NSString*) getDownloadContentFilename
|
||||
{
|
||||
return self.contentFilename;
|
||||
}
|
||||
|
||||
- (NSString*) getDownloadScriptsFilename
|
||||
{
|
||||
return self.scriptsFilename;
|
||||
}
|
||||
|
||||
- (void)didTerminateApp:(NSNotification *)notification {
|
||||
if (self.waitingForInterfaceToTerminate) {
|
||||
NSString* appName = [notification.userInfo valueForKey:@"NSApplicationName"];
|
||||
if ([appName isEqualToString:@"interface"]) {
|
||||
self.waitingForInterfaceToTerminate = FALSE;
|
||||
[self checkLoginStatus];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) closeInterfaceIfRunning
|
||||
{
|
||||
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
||||
NSArray* apps = [workspace runningApplications];
|
||||
for (NSRunningApplication* app in apps) {
|
||||
if ([[app bundleIdentifier] isEqualToString:@"com.highfidelity.interface"] ||
|
||||
[[app bundleIdentifier] isEqualToString:@"com.highfidelity.interface-pr"]) {
|
||||
[app terminate];
|
||||
self.waitingForInterfaceToTerminate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) isWaitingForInterfaceToTerminate {
|
||||
return self.waitingForInterfaceToTerminate;
|
||||
}
|
||||
|
||||
- (BOOL) isLoadedIn
|
||||
{
|
||||
return [[Settings sharedSettings] isLoggedIn];
|
||||
}
|
||||
|
||||
- (void) setDomainURLInfo:(NSString *)aDomainURL :(NSString *)aDomainContentUrl :(NSString *)aDomainScriptsUrl
|
||||
{
|
||||
self.domainURL = aDomainURL;
|
||||
self.domainContentUrl = aDomainContentUrl;
|
||||
self.domainScriptsUrl = aDomainScriptsUrl;
|
||||
|
||||
[[Settings sharedSettings] setDomainUrl:aDomainURL];
|
||||
}
|
||||
|
||||
- (NSString*) getAppPath
|
||||
{
|
||||
return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/Contents/MacOS/"];
|
||||
}
|
||||
|
||||
- (BOOL) loginShouldSetErrorState
|
||||
{
|
||||
return !self.credentialsAccepted;
|
||||
}
|
||||
|
||||
- (void) displayNameEntered:(NSString*)aDiplayName
|
||||
{
|
||||
self.processState = DOWNLOADING_INTERFACE;
|
||||
ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
|
||||
[self.downloadDomainContent downloadDomainContent:self.domainContentUrl];
|
||||
self.displayName = aDiplayName;
|
||||
}
|
||||
|
||||
- (void) domainContentDownloadFinished
|
||||
{
|
||||
//.[self.downloadScripts downloadScripts:self.domainScriptsUrl];
|
||||
[self.latestBuildRequest requestLatestBuildInfo];
|
||||
}
|
||||
|
||||
- (void) domainScriptsDownloadFinished
|
||||
{
|
||||
[self.latestBuildRequest requestLatestBuildInfo];
|
||||
}
|
||||
|
||||
- (void) saveCredentialsAccepted:(BOOL)aCredentialsAccepted
|
||||
{
|
||||
self.credentialsAccepted = aCredentialsAccepted;
|
||||
}
|
||||
|
||||
- (void) credentialsAccepted:(BOOL)aCredentialsAccepted
|
||||
{
|
||||
self.credentialsAccepted = aCredentialsAccepted;
|
||||
if (aCredentialsAccepted) {
|
||||
DisplayNameScreen* displayNameScreen = [[DisplayNameScreen alloc] initWithNibName:@"DisplayNameScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: displayNameScreen];
|
||||
} else {
|
||||
LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) interfaceFinishedDownloading
|
||||
{
|
||||
if (self.processState == DOWNLOADING_INTERFACE) {
|
||||
self.processState = RUNNING_INTERFACE_AFTER_DOWNLOAD;
|
||||
} else {
|
||||
self.processState = RUNNING_INTERFACE_AFTER_UPDATE;
|
||||
}
|
||||
ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
|
||||
[self launchInterface];
|
||||
}
|
||||
|
||||
- (void) credentialsEntered:(NSString*)aOrginization :(NSString*)aUsername :(NSString*)aPassword
|
||||
{
|
||||
self.organization = aOrginization;
|
||||
self.username = aUsername;
|
||||
self.password = aPassword;
|
||||
[self.organizationRequest confirmOrganization:aOrginization :aUsername];
|
||||
}
|
||||
|
||||
- (void) organizationRequestFinished:(BOOL)aOriginzationAccepted
|
||||
{
|
||||
self.credentialsAccepted = aOriginzationAccepted;
|
||||
if (aOriginzationAccepted) {
|
||||
[self.credentialsRequest confirmCredentials:self.username : self.password];
|
||||
} else {
|
||||
LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void) showLoginScreen
|
||||
{
|
||||
LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
|
||||
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
|
||||
}
|
||||
|
||||
- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl
|
||||
{
|
||||
if (shouldDownload) {
|
||||
[self.downloadInterface downloadInterface: downloadUrl];
|
||||
return;
|
||||
}
|
||||
[self launchInterface];
|
||||
}
|
||||
|
||||
-(void)onSplashScreenTimerFinished:(NSTimer *)timer
|
||||
{
|
||||
[self showLoginScreen];
|
||||
}
|
||||
|
||||
-(void)setCurrentProcessState:(ProcessState)aProcessState
|
||||
{
|
||||
self.processState = aProcessState;
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
[self.window makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
||||
- (void) setDownloadFilename:(NSString *)aFilename
|
||||
{
|
||||
self.filename = aFilename;
|
||||
}
|
||||
|
||||
- (NSString*) getDownloadFilename
|
||||
{
|
||||
return self.filename;
|
||||
}
|
||||
|
||||
- (void) setTokenString:(NSString *)aToken
|
||||
{
|
||||
self.userToken = aToken;
|
||||
}
|
||||
|
||||
- (NSString*) getTokenString
|
||||
{
|
||||
return self.userToken;
|
||||
}
|
||||
|
||||
- (void) setLoginErrorState:(LoginError)aLoginError
|
||||
{
|
||||
self.loginError = aLoginError;
|
||||
}
|
||||
|
||||
- (LoginError) getLoginErrorState
|
||||
{
|
||||
return self.loginError;
|
||||
}
|
||||
|
||||
- (void) launchInterface
|
||||
{
|
||||
NSString* launcherPath = [[self getAppPath] stringByAppendingString:@"HQ Launcher"];
|
||||
|
||||
[[Settings sharedSettings] setLauncherPath:launcherPath];
|
||||
[[Settings sharedSettings] save];
|
||||
NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
|
||||
NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:[[self getAppPath] stringByAppendingString:@"interface.app/Contents/MacOS/interface"]]];
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
NSString* contentPath = [[self getDownloadPathForContentAndScripts] stringByAppendingString:@"content"];
|
||||
NSString* displayName = [ self displayName];
|
||||
NSString* scriptsPath = [[self getAppPath] stringByAppendingString:@"interface.app/Contents/Resources/scripts/simplifiedUI/"];
|
||||
NSString* domainUrl = [[Settings sharedSettings] getDomainUrl];
|
||||
NSString* userToken = [[Launcher sharedLauncher] getTokenString];
|
||||
NSArray* arguments;
|
||||
if (userToken != nil) {
|
||||
arguments = [NSArray arrayWithObjects:
|
||||
@"--url" , domainUrl ,
|
||||
@"--tokens", userToken,
|
||||
@"--cache", contentPath,
|
||||
@"--displayName", displayName,
|
||||
@"--script", scriptsPath,
|
||||
@"--no-updater",
|
||||
@"--no-launcher", nil];
|
||||
} else {
|
||||
arguments = [NSArray arrayWithObjects:
|
||||
@"--url" , domainUrl,
|
||||
@"--cache", contentPath,
|
||||
@"--script", scriptsPath,
|
||||
@"--no-updater",
|
||||
@"--no-launcher", nil];
|
||||
}
|
||||
[workspace launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error];
|
||||
|
||||
//NSLog(@"arguments %@", [NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments]);
|
||||
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
|
||||
- (ProcessState) currentProccessState
|
||||
{
|
||||
return self.processState;
|
||||
}
|
||||
|
||||
@end
|
5
launchers/darwin/src/LoginScreen.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface LoginScreen : NSViewController {
|
||||
}
|
||||
@end
|
76
launchers/darwin/src/LoginScreen.m
Normal file
|
@ -0,0 +1,76 @@
|
|||
#import "LoginScreen.h"
|
||||
#import "Launcher.h"
|
||||
#import "CustomUI.h"
|
||||
|
||||
@interface LoginScreen ()
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* username;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* password;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* orginization;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* header;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* smallHeader;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* trouble;
|
||||
@property (nonatomic, assign) IBOutlet NSButton* button;
|
||||
@end
|
||||
|
||||
@implementation LoginScreen
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
if ([sharedLauncher loginShouldSetErrorState]) {
|
||||
[self.header setStringValue:@"Uh-oh, we have a problem"];
|
||||
switch ([sharedLauncher getLoginErrorState]) {
|
||||
case CREDENTIALS:
|
||||
[self.smallHeader setStringValue:@"There is a problem with your credentials, please try again"];
|
||||
break;
|
||||
case ORGANIZATION:
|
||||
[self.smallHeader setStringValue:@"There is a problem with your organization name, please try again"];
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[self.button setTitle:@"TRY AGAIN"];
|
||||
}
|
||||
|
||||
[self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]];
|
||||
[self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]];
|
||||
|
||||
NSMutableAttributedString* usernameString = [[NSMutableAttributedString alloc] initWithString:@"Username"];
|
||||
|
||||
[usernameString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,8)];
|
||||
[usernameString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,8)];
|
||||
|
||||
NSMutableAttributedString* orgName = [[NSMutableAttributedString alloc] initWithString:@"Organization Name"];
|
||||
[orgName addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,17)];
|
||||
[orgName addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,17)];
|
||||
|
||||
NSMutableAttributedString* passwordString = [[NSMutableAttributedString alloc] initWithString:@"Password"];
|
||||
|
||||
[passwordString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,8)];
|
||||
[passwordString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,8)];
|
||||
|
||||
[self.username setPlaceholderAttributedString:usernameString];
|
||||
[self.orginization setPlaceholderAttributedString:orgName];
|
||||
[self.password setPlaceholderAttributedString:passwordString];
|
||||
|
||||
[self.password setTarget:self];
|
||||
[self.password setAction:@selector(goToLogin:)];
|
||||
}
|
||||
|
||||
- (IBAction)goToLogin:(id)sender
|
||||
{
|
||||
printf("In gotologin");
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
[sharedLauncher credentialsEntered:[self.orginization stringValue] :[self.username stringValue] :[self.password stringValue]];
|
||||
}
|
||||
|
||||
- (IBAction)havingTrouble:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.highfidelity.com/hq-support"]];
|
||||
}
|
||||
|
||||
@end
|
11
launchers/darwin/src/OrganizationRequest.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface OrganizationRequest : NSObject <NSURLConnectionDelegate> {
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSMutableData* webData;
|
||||
@property (nonatomic, retain) NSString* jsonString;
|
||||
@property (nonatomic, retain) NSString* username;
|
||||
|
||||
- (void) confirmOrganization:(NSString*) aOrganization :(NSString*) aUsername;
|
||||
@end
|
96
launchers/darwin/src/OrganizationRequest.m
Normal file
|
@ -0,0 +1,96 @@
|
|||
#import "OrganizationRequest.h"
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#include <CommonCrypto/CommonHMAC.h>
|
||||
#import "Launcher.h"
|
||||
|
||||
|
||||
static NSString* const organizationURL = @"https://s3.amazonaws.com/hifi-public/huffman/organizations/";
|
||||
|
||||
#define str(s) #s
|
||||
#define LAUNCHER_HMAC_SECRET_STRING str(LAUNCHER_HMAC_SECRET)
|
||||
|
||||
@implementation OrganizationRequest
|
||||
|
||||
- (void) confirmOrganization:(NSString*)aOrganization :(NSString*)aUsername {
|
||||
self.username = aUsername;
|
||||
|
||||
const char *cKey = LAUNCHER_HMAC_SECRET_STRING;
|
||||
const char *cData = [aOrganization cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
|
||||
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
|
||||
NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
|
||||
const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
|
||||
NSMutableString *hash = [NSMutableString stringWithCapacity:HMACData.length * 2];
|
||||
for (int i = 0; i < HMACData.length; ++i){
|
||||
[hash appendFormat:@"%02x", buffer[i]];
|
||||
}
|
||||
|
||||
NSString* jsonFile = [hash stringByAppendingString:@".json"];
|
||||
NSError *error;
|
||||
NSData *data = [NSData dataWithContentsOfURL: [NSURL URLWithString:[organizationURL stringByAppendingString:jsonFile]]];
|
||||
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
if (data) {
|
||||
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
|
||||
[sharedLauncher setDomainURLInfo:[json valueForKey:@"domain"] :[json valueForKey:@"content_set_url"] :[json valueForKey:@"scripts_url"]];
|
||||
[sharedLauncher setLoginErrorState: NONE];
|
||||
return [sharedLauncher organizationRequestFinished:TRUE];
|
||||
}
|
||||
NSLog(@"FAAAAILLLLLLLEEEEEEEDDDDDD");
|
||||
[sharedLauncher setLoginErrorState: ORGANIZATION];
|
||||
return [sharedLauncher organizationRequestFinished:FALSE];
|
||||
/*NSLog(@"URL: %@", [organizationURL stringByAppendingString:jsonFile]);
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest new];
|
||||
[request setURL:[NSURL URLWithString: [organizationURL stringByAppendingString:@"High%20Fidelity"]]];
|
||||
[request setHTTPMethod:@"GET"];
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
|
||||
|
||||
if(theConnection) {
|
||||
self.webData = [NSMutableData data];
|
||||
NSLog(@"connection initiated");
|
||||
}*/
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
[self.webData appendData:data];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
|
||||
if([ne statusCode] == 200) {
|
||||
NSLog(@"connection state is 200 - all okay");
|
||||
} else {
|
||||
NSLog(@"connection state is NOT 200");
|
||||
}
|
||||
}
|
||||
|
||||
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
NSLog(@"Conn Err: %@", [error localizedDescription]);
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
/*NSString* jsonString = [[NSString alloc] initWithBytes: [self.webData mutableBytes] length:[self.webData length] encoding:NSUTF8StringEncoding];
|
||||
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];*/
|
||||
|
||||
/*Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
if (json[@"error"] != nil) {
|
||||
NSLog(@"Login in failed");
|
||||
NSString* accessToken = [json objectForKey:@"access_token"];
|
||||
NSLog(@"access token %@", accessToken);
|
||||
[sharedLauncher credentialsAccepted:FALSE];
|
||||
} else {
|
||||
NSLog(@"Login successful");
|
||||
NSString* accessToken = [json objectForKey:@"access_token"];
|
||||
NSLog(@"access token %@", accessToken);
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setValue:accessToken forKey:@"access_token"];
|
||||
[defaults synchronize];
|
||||
[sharedLauncher credentialsAccepted:TRUE];
|
||||
}*/
|
||||
//NSLog(@"OUTPUT:: %@", self.jsonString);
|
||||
}
|
||||
|
||||
@end
|
7
launchers/darwin/src/ProcessScreen.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface ProcessScreen : NSViewController {
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) NSInteger imageRotation;
|
||||
@end
|
55
launchers/darwin/src/ProcessScreen.m
Normal file
|
@ -0,0 +1,55 @@
|
|||
#import "ProcessScreen.h"
|
||||
#import "Launcher.h"
|
||||
#import "CustomUI.h"
|
||||
|
||||
@interface ProcessScreen ()
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* background;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* voxelImage;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* boldStatus;
|
||||
@property (nonatomic, assign) IBOutlet NSTextField* smallStatus;
|
||||
@end
|
||||
|
||||
@implementation ProcessScreen
|
||||
|
||||
- (void) awakeFromNib {
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
switch ([sharedLauncher currentProccessState]) {
|
||||
case DOWNLOADING_INTERFACE:
|
||||
[self.boldStatus setStringValue:@"We're building your virtual HQ"];
|
||||
[self.smallStatus setStringValue:@"Set up may take several minutes."];
|
||||
break;
|
||||
case RUNNING_INTERFACE_AFTER_DOWNLOAD:
|
||||
[self.boldStatus setStringValue:@"Your new HQ is all setup"];
|
||||
[self.smallStatus setStringValue:@"Thanks for being patient."];
|
||||
break;
|
||||
case CHECKING_UPDATE:
|
||||
[self.boldStatus setStringValue:@"Getting updates..."];
|
||||
[self.smallStatus setStringValue:@"We're getting the lastest and greatest for you, one sec."];
|
||||
break;
|
||||
case RUNNING_INTERFACE_AFTER_UPDATE:
|
||||
[self.boldStatus setStringValue:@"You're good to go!"];
|
||||
[self.smallStatus setStringValue:@"Thanks for being patient."];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[self.background setImage: [NSImage imageNamed:hifiBackgroundFilename]];
|
||||
[self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]];
|
||||
[self.voxelImage setImage: [NSImage imageNamed:hifiVoxelFilename]];
|
||||
|
||||
self.imageRotation = 0;
|
||||
//[self.voxelImage setFrameCenterRotation:90];
|
||||
|
||||
[NSTimer scheduledTimerWithTimeInterval:0.016
|
||||
target:self
|
||||
selector:@selector(rotateView:)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
|
||||
- (void) rotateView:(NSTimer *)timer{
|
||||
self.imageRotation += 1;
|
||||
[self.voxelImage setFrameCenterRotation:self.imageRotation];
|
||||
}
|
||||
@end
|
20
launchers/darwin/src/Settings.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
@interface Settings : NSObject {
|
||||
}
|
||||
@property (nonatomic, assign) NSInteger build;
|
||||
@property (nonatomic, assign) BOOL loggedIn;
|
||||
@property (nonatomic, assign) NSString* domain;
|
||||
@property (nonatomic, assign) NSString* launcher;
|
||||
- (NSInteger) latestBuildVersion;
|
||||
- (BOOL) isLoggedIn;
|
||||
- (void) login:(BOOL)aLoggedIn;
|
||||
- (void) buildVersion:(NSInteger) aBuildVersion;
|
||||
- (void) setLauncherPath:(NSString*) aLauncherPath;
|
||||
- (NSString*) getLaucnherPath;
|
||||
- (void) setDomainUrl:(NSString*) aDomainUrl;
|
||||
- (NSString*) getDomainUrl;
|
||||
- (void) save;
|
||||
+ (id) sharedSettings;
|
||||
@end
|
127
launchers/darwin/src/Settings.m
Normal file
|
@ -0,0 +1,127 @@
|
|||
#import "Settings.h"
|
||||
#import "Launcher.h"
|
||||
|
||||
|
||||
@implementation Settings
|
||||
|
||||
+ (id) sharedSettings
|
||||
{
|
||||
static Settings* sharedSettings = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedSettings = [[self alloc]init];
|
||||
});
|
||||
return sharedSettings;
|
||||
}
|
||||
|
||||
- (NSString*) getFilePath
|
||||
{
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
NSString* appPath = [sharedLauncher getAppPath];
|
||||
NSString* filePath = [appPath stringByAppendingString:@"interface.app/Contents/MacOS/"];
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
- (void) readDataFromJsonFile
|
||||
{
|
||||
NSString* filePath = [self getFilePath];
|
||||
NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||
NSString* jsonString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];
|
||||
NSError * err;
|
||||
NSData *data =[jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary * json;
|
||||
if(data!=nil){
|
||||
json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
|
||||
|
||||
self.loggedIn = [[json valueForKey:@"loggedIn"] boolValue];
|
||||
self.build = [[json valueForKey:@"build_version"] integerValue];
|
||||
self.launcher = [json valueForKey:@"luancherPath"];
|
||||
self.domain = [json valueForKey:@"domain"];
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.loggedIn = false;
|
||||
self.build = 0;
|
||||
self.launcher = nil;
|
||||
self.domain = nil;
|
||||
}
|
||||
|
||||
- (void) writeDataToFile {
|
||||
NSDictionary* json = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSString stringWithFormat:@"%ld", self.build], @"build_version",
|
||||
self.loggedIn ? @"TRUE" : @"FALSE", @"loggedIn",
|
||||
self.domain, @"domain",
|
||||
self.launcher, @"launcherPath", nil];
|
||||
NSError * err;
|
||||
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json options:0 error:&err];
|
||||
NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
|
||||
NSString* filePath = [self getFilePath];
|
||||
NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||
NSError * error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:FALSE attributes:nil error:&error];
|
||||
[[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
|
||||
|
||||
}
|
||||
[[jsonString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
|
||||
|
||||
}
|
||||
|
||||
-(id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self readDataFromJsonFile];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL) isLoggedIn
|
||||
{
|
||||
return self.loggedIn;
|
||||
}
|
||||
|
||||
- (NSInteger) latestBuildVersion
|
||||
{
|
||||
return self.build;
|
||||
}
|
||||
|
||||
- (void) buildVersion:(NSInteger)aBuildVersion
|
||||
{
|
||||
self.build = aBuildVersion;
|
||||
}
|
||||
|
||||
- (void) login:(BOOL)aLoggedIn
|
||||
{
|
||||
self.loggedIn = aLoggedIn;
|
||||
}
|
||||
|
||||
- (void) setLauncherPath:(NSString *)aLauncherPath
|
||||
{
|
||||
self.launcher = aLauncherPath;
|
||||
}
|
||||
|
||||
- (void) setDomainUrl:(NSString *)aDomainUrl
|
||||
{
|
||||
self.domain = aDomainUrl;
|
||||
}
|
||||
|
||||
- (NSString*) getDomainUrl
|
||||
{
|
||||
return self.domain;
|
||||
}
|
||||
|
||||
- (NSString*) getLaucnherPath
|
||||
{
|
||||
return self.launcher;
|
||||
}
|
||||
|
||||
- (void) save
|
||||
{
|
||||
[self writeDataToFile];
|
||||
}
|
||||
|
||||
@end
|
6
launchers/darwin/src/SplashScreen.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "LoginScreen.h"
|
||||
@interface SplashScreen: NSViewController {
|
||||
}
|
||||
|
||||
@end
|
19
launchers/darwin/src/SplashScreen.m
Normal file
|
@ -0,0 +1,19 @@
|
|||
#import "SplashScreen.h"
|
||||
#import "Launcher.h"
|
||||
#import "CustomUI.h"
|
||||
|
||||
@interface SplashScreen ()
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* imageView;
|
||||
@property (nonatomic, assign) IBOutlet NSImageView* logoImage;
|
||||
@property (nonatomic, assign) IBOutlet NSButton* button;
|
||||
@end
|
||||
|
||||
@implementation SplashScreen
|
||||
- (void) viewDidLoad {
|
||||
}
|
||||
|
||||
-(void)awakeFromNib {
|
||||
[self.imageView setImage:[NSImage imageNamed:hifiBackgroundFilename]];
|
||||
[self.logoImage setImage:[NSImage imageNamed:hifiLargeLogoFilename]];
|
||||
}
|
||||
@end
|
6
launchers/darwin/src/Window.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface Window : NSWindow {
|
||||
|
||||
}
|
||||
@end
|
7
launchers/darwin/src/Window.m
Normal file
|
@ -0,0 +1,7 @@
|
|||
#import "Window.h"
|
||||
|
||||
@implementation Window
|
||||
-(BOOL)canBecomeKeyWindow {
|
||||
return YES;
|
||||
}
|
||||
@end
|
45
launchers/darwin/src/main.mm
Normal file
|
@ -0,0 +1,45 @@
|
|||
#import "Launcher.h"
|
||||
#import "Settings.h"
|
||||
|
||||
void redirectLogToDocuments()
|
||||
{
|
||||
NSString* filePath = [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]
|
||||
stringByAppendingString:@"/Launcher/"];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
|
||||
NSError * error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:TRUE attributes:nil error:&error];
|
||||
}
|
||||
NSString *pathForLog = [filePath stringByAppendingPathComponent:@"log.txt"];
|
||||
|
||||
freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
//NSApp.appearance = [NSAppearance appearanceNamed: NSAppearanceNameAqua];
|
||||
//redirectLogToDocuments();
|
||||
NSArray* apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.highfidelity.launcher"];
|
||||
if ([apps count] > 1) {
|
||||
NSLog(@"launcher is already running");
|
||||
return 0;
|
||||
}
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||
[Settings sharedSettings];
|
||||
[NSApp setDelegate: sharedLauncher];
|
||||
|
||||
// Referenced from https://stackoverflow.com/questions/9155015/handle-cmd-q-in-cocoa-application-and-menu-item-quit-application-programmatic
|
||||
id menubar = [[NSMenu new] autorelease];
|
||||
id appMenuItem = [[NSMenuItem new] autorelease];
|
||||
[menubar addItem:appMenuItem];
|
||||
[NSApp setMainMenu:menubar];
|
||||
id appMenu = [[NSMenu new] autorelease];
|
||||
id appName = [[NSProcessInfo processInfo] processName];
|
||||
id quitTitle = [@"Quit " stringByAppendingString:appName];
|
||||
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
|
||||
[appMenu addItem:quitMenuItem];
|
||||
[appMenuItem setSubmenu:appMenu];
|
||||
|
||||
return NSApplicationMain(argc, argv);
|
||||
}
|
33
launchers/win32/BUILD.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
## Windows Build Guide
|
||||
|
||||
To build the launcher we need:
|
||||
|
||||
- Visual Studio Community 2017.
|
||||
- CMake.
|
||||
|
||||
|
||||
### Installing Visual Studio 2017
|
||||
|
||||
If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/).
|
||||
|
||||
When selecting components, check "Desktop development with C++". Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)".
|
||||
|
||||
If you already have Visual Studio installed and need to add python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer".
|
||||
|
||||
### Installing CMake
|
||||
|
||||
Download and install the latest version of CMake 3.9.
|
||||
|
||||
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.9 Version page](https://cmake.org/files/v3.9/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
|
||||
|
||||
### Running CMake to Generate Build Files
|
||||
|
||||
Run Command Prompt from Start and run the following commands:
|
||||
```
|
||||
cd "%LAUNCHER_DIR%"
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 15 Win64" -T v140
|
||||
```
|
||||
|
||||
Where `%LAUNCHER_DIR%` is the directory for the PC light launcher repository.
|
68
launchers/win32/CMakeLists.txt
Normal file
|
@ -0,0 +1,68 @@
|
|||
cmake_minimum_required(VERSION 3.9.2)
|
||||
|
||||
project(HQLauncher)
|
||||
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Release"
|
||||
CACHE STRING "Configuration types" FORCE)
|
||||
|
||||
# Use of MFC
|
||||
set(CMAKE_MFC_FLAG 1)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
|
||||
add_executable(HQLauncher
|
||||
WIN32
|
||||
libs/json/json.h
|
||||
libs/json/json-forwards.h
|
||||
libs/jsoncpp.cpp
|
||||
LauncherApp.cpp
|
||||
LauncherApp.h
|
||||
Launcher.rc
|
||||
LauncherDlg.cpp
|
||||
LauncherDlg.h
|
||||
LauncherManager.cpp
|
||||
LauncherManager.h
|
||||
LauncherUtils.cpp
|
||||
LauncherUtils.h
|
||||
libs/miniz.cpp
|
||||
libs/miniz.h
|
||||
res/HiFi_Logo_Large.png
|
||||
res/HiFi_Logo_Small.png
|
||||
res/HiFi_Voxel.png
|
||||
res/HiFi_Window.png
|
||||
res/interface.ico
|
||||
res/Launcher.rc2
|
||||
Resource.h
|
||||
stdafx.cpp
|
||||
stdafx.h
|
||||
targetver.h
|
||||
)
|
||||
|
||||
target_compile_definitions(HQLauncher PRIVATE LAUNCHER_HMAC_SECRET=$ENV{LAUNCHER_HMAC_SECRET})
|
||||
|
||||
# Preprocessor definitions
|
||||
target_compile_definitions(HQLauncher PRIVATE
|
||||
$<$<CONFIG:Debug>:_UNICODE;_WINDOWS;_DEBUG>
|
||||
$<$<CONFIG:Release>:_UNICODE;_WINDOWS;NDEBUG>
|
||||
)
|
||||
|
||||
# Minimal rebuild
|
||||
if (MSVC)
|
||||
target_compile_options(HQLauncher PRIVATE
|
||||
"$<$<CONFIG:Debug>:/Gm->"
|
||||
"$<$<CONFIG:Release>:/Gm->"
|
||||
)
|
||||
endif ()
|
||||
|
||||
# Precompiled header files
|
||||
if (MSVC)
|
||||
target_compile_options(HQLauncher PRIVATE
|
||||
"$<$<CONFIG:Debug>:/Yu>"
|
||||
"$<$<CONFIG:Release>:/Yu>"
|
||||
)
|
||||
set_property(SOURCE stdafx.cpp
|
||||
APPEND_STRING PROPERTY COMPILE_FLAGS
|
||||
"$<$<CONFIG:Debug>:/Yc> \
|
||||
$<$<CONFIG:Release>:/Yc>")
|
||||
endif ()
|
214
launchers/win32/Launcher.rc
Normal file
|
@ -0,0 +1,214 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
#include "targetver.h"
|
||||
#endif
|
||||
#include "afxres.h"
|
||||
#include "verrsrc.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#ifndef APSTUDIO_INVOKED\r\n"
|
||||
"#include ""targetver.h""\r\n"
|
||||
"#endif\r\n"
|
||||
"#include ""afxres.h""\r\n"
|
||||
"#include ""verrsrc.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
|
||||
"#define _AFX_NO_OLE_RESOURCES\r\n"
|
||||
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
|
||||
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
|
||||
"\r\n"
|
||||
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
|
||||
"LANGUAGE 9, 1\r\n"
|
||||
"#include ""res\\Launcher.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
|
||||
"#include ""afxres.rc"" // Standard components\r\n"
|
||||
"#endif\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDR_MAINFRAME ICON "res\\interface.ico"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BINARY
|
||||
//
|
||||
|
||||
IDR_FONT_REGULAR BINARY "res\\Graphikregular.ttf"
|
||||
|
||||
IDR_FONT_BOLD BINARY "res\\Graphikbold.ttf"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_LAUNCHER_DIALOG DIALOGEX 0, 0, 300, 196
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION
|
||||
EXSTYLE WS_EX_APPWINDOW
|
||||
FONT 10, "MS Shell Dlg", 400, 0, 0x0
|
||||
BEGIN
|
||||
CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,27,174,123
|
||||
EDITTEXT IDC_ORGNAME,44,68,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
|
||||
EDITTEXT IDC_USERNAME,44,95,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
|
||||
EDITTEXT IDC_PASSWORD,44,122,219,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
|
||||
LTEXT "Organization name",IDC_ORGNAME_BANNER,48,68,219,12,NOT WS_VISIBLE
|
||||
LTEXT "Username",IDC_USERNAME_BANNER,48,95,219,12,NOT WS_VISIBLE
|
||||
LTEXT "Password",IDC_PASSWORD_BANNER,48,122,219,12,NOT WS_VISIBLE
|
||||
CTEXT "",IDC_MESSAGE_LABEL,5,39,299,23,NOT WS_VISIBLE
|
||||
CTEXT "",IDC_ACTION_LABEL,10,15,286,25,NOT WS_VISIBLE
|
||||
CTEXT "",IDC_MESSAGE2_LABEL,35,172,239,15,NOT WS_VISIBLE
|
||||
CTEXT "",IDC_ACTION2_LABEL,15,147,278,25,NOT WS_VISIBLE
|
||||
RTEXT "",IDC_TERMS,15,172,180,15,NOT WS_VISIBLE
|
||||
LTEXT "",IDC_TERMS2,197,172,80,15,NOT WS_VISIBLE
|
||||
CTEXT "",IDC_TROUBLE,65,203,174,15,NOT WS_VISIBLE
|
||||
CONTROL "NEXT",IDC_BUTTON_NEXT,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,107,158,94,16
|
||||
CONTROL "Having Trouble?",IDC_TROUBLE_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,126,203,56,11
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x1L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "High Fidelity Inc."
|
||||
VALUE "FileDescription", "HQ Launcher"
|
||||
VALUE "FileVersion", "1.0.0.1"
|
||||
VALUE "InternalName", "HQ Launcher"
|
||||
VALUE "LegalCopyright", "High Fidelity Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "HQ Launcher.exe"
|
||||
VALUE "ProductName", "HQ Launcher"
|
||||
VALUE "ProductVersion", "0.0.8.5"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_LAUNCHER_DIALOG, DIALOG
|
||||
BEGIN
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AFX_DIALOG_LAYOUT
|
||||
//
|
||||
|
||||
IDD_LAUNCHER_DIALOG AFX_DIALOG_LAYOUT
|
||||
BEGIN
|
||||
0
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PNG
|
||||
//
|
||||
|
||||
IDB_PNG1 PNG "res\\HiFi_Window.png"
|
||||
|
||||
IDB_PNG2 PNG "res\\HiFi_Logo_Large.png"
|
||||
|
||||
IDB_PNG4 PNG "res\\HiFi_Voxel.png"
|
||||
|
||||
IDB_PNG5 PNG "res\\HiFi_Logo_Small.png"
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#define _AFX_NO_SPLITTER_RESOURCES
|
||||
#define _AFX_NO_OLE_RESOURCES
|
||||
#define _AFX_NO_TRACKER_RESOURCES
|
||||
#define _AFX_NO_PROPERTY_RESOURCES
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE 9, 1
|
||||
#include "res\Launcher.rc2" // non-Microsoft Visual C++ edited resources
|
||||
#include "afxres.rc" // Standard components
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
91
launchers/win32/LauncherApp.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// LauncherApp.cpp
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 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 "stdafx.h"
|
||||
#include "LauncherApp.h"
|
||||
#include "LauncherDlg.h"
|
||||
#include "LauncherManager.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
// CLauncherApp
|
||||
|
||||
BEGIN_MESSAGE_MAP(CLauncherApp, CWinApp)
|
||||
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
CLauncherApp::CLauncherApp(){}
|
||||
|
||||
// The one and only CLauncherApp object
|
||||
|
||||
CLauncherApp theApp;
|
||||
|
||||
// CLauncherApp initialization
|
||||
|
||||
BOOL CLauncherApp::InitInstance() {
|
||||
// don't launch if already running
|
||||
CreateMutex(NULL, TRUE, _T("HQ_Launcher_Mutex"));
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
return FALSE;
|
||||
}
|
||||
int iNumOfArgs;
|
||||
LPWSTR* pArgs = CommandLineToArgvW(GetCommandLine(), &iNumOfArgs);
|
||||
if (iNumOfArgs > 1 && CString(pArgs[1]).Compare(_T("--uninstall")) == 0) {
|
||||
_manager.uninstall();
|
||||
} else {
|
||||
_manager.init();
|
||||
}
|
||||
if (!_manager.installLauncher()) {
|
||||
return FALSE;
|
||||
}
|
||||
installFont(IDR_FONT_REGULAR);
|
||||
installFont(IDR_FONT_BOLD);
|
||||
CWinApp::InitInstance();
|
||||
|
||||
SetRegistryKey(_T("HQ High Fidelity"));
|
||||
|
||||
CLauncherDlg dlg;
|
||||
m_pMainWnd = &dlg;
|
||||
INT_PTR nResponse = dlg.DoModal();
|
||||
|
||||
#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
|
||||
ControlBarCleanUp();
|
||||
#endif
|
||||
|
||||
// Since the dialog has been closed, return FALSE so that we exit the
|
||||
// application, rather than start the application's message pump.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL CLauncherApp::installFont(int fontID) {
|
||||
HINSTANCE hResInstance = AfxGetResourceHandle();
|
||||
HRSRC res = FindResource(hResInstance,
|
||||
MAKEINTRESOURCE(fontID), L"BINARY");
|
||||
if (res) {
|
||||
HGLOBAL mem = LoadResource(hResInstance, res);
|
||||
void *data = LockResource(mem);
|
||||
DWORD len = (DWORD)SizeofResource(hResInstance, res);
|
||||
|
||||
DWORD nFonts;
|
||||
auto m_fonthandle = AddFontMemResourceEx(
|
||||
data, // font resource
|
||||
len, // number of bytes in font resource
|
||||
NULL, // Reserved. Must be 0.
|
||||
&nFonts // number of fonts installed
|
||||
);
|
||||
|
||||
return (m_fonthandle != 0);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
32
launchers/win32/LauncherApp.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// LauncherApp.h
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __AFXWIN_H__
|
||||
#error "include 'stdafx.h' before including this file for PCH"
|
||||
#endif
|
||||
|
||||
#include "resource.h" // main symbols
|
||||
#include "LauncherManager.h"
|
||||
|
||||
class CLauncherApp : public CWinApp
|
||||
{
|
||||
public:
|
||||
CLauncherApp();
|
||||
virtual BOOL InitInstance();
|
||||
void setDialogOnFront() { SetWindowPos(m_pMainWnd->GetSafeHwnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); }
|
||||
LauncherManager _manager;
|
||||
private:
|
||||
BOOL installFont(int fontID);
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
extern CLauncherApp theApp;
|
624
launchers/win32/LauncherDlg.cpp
Normal file
|
@ -0,0 +1,624 @@
|
|||
//
|
||||
// LauncherDlg.cpp
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 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 "stdafx.h"
|
||||
#include "LauncherApp.h"
|
||||
#include "LauncherDlg.h"
|
||||
|
||||
#include <d2d1.h>
|
||||
#pragma comment(lib, "d2d1")
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
static int ACTION_FONT_SIZE = 40;
|
||||
static int MESSAGE_FONT_SIZE = 19;
|
||||
static int FIELDS_FONT_SIZE = 24;
|
||||
static int BUTTON_FONT_SIZE = 25;
|
||||
static int TERMS_FONT_SIZE = 17;
|
||||
static int TROUBLE_FONT_SIZE = 14;
|
||||
|
||||
static COLORREF COLOR_GREY = RGB(120, 120, 120);
|
||||
static COLORREF COLOR_BLACK= RGB(0, 0, 0);
|
||||
static COLORREF COLOR_WHITE = RGB(255, 255, 255);
|
||||
static COLORREF COLOR_LIGHTER_GREY = RGB(230, 230, 230);
|
||||
static COLORREF COLOR_LIGHT_GREY = RGB(200, 200, 200);
|
||||
static COLORREF COLOR_BLUE = RGB(50, 160, 200);
|
||||
|
||||
static CString GRAPHIK_REGULAR = _T("Graphik-Regular");
|
||||
static CString GRAPHIK_SEMIBOLD = _T("Graphik-Semibold");
|
||||
|
||||
static CString TROUBLE_URL = _T("https://www.highfidelity.com/hq-support");
|
||||
|
||||
|
||||
CLauncherDlg::CLauncherDlg(CWnd* pParent)
|
||||
: CDialog(IDD_LAUNCHER_DIALOG, pParent)
|
||||
{
|
||||
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
|
||||
EnableD2DSupport();
|
||||
}
|
||||
|
||||
void CLauncherDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
DDX_Control(pDX, IDC_BUTTON_NEXT, m_btnNext);
|
||||
DDX_Control(pDX, IDC_TROUBLE_LINK, m_trouble_link);
|
||||
DDX_Control(pDX, IDC_ORGNAME, m_orgname);
|
||||
DDX_Control(pDX, IDC_USERNAME, m_username);
|
||||
DDX_Control(pDX, IDC_PASSWORD, m_password);
|
||||
CDialog::DoDataExchange(pDX);
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(CLauncherDlg, CDialog)
|
||||
ON_WM_PAINT()
|
||||
ON_WM_QUERYDRAGICON()
|
||||
ON_WM_TIMER()
|
||||
ON_EN_SETFOCUS(IDC_ORGNAME, &CLauncherDlg::OnOrgEditChangeFocus)
|
||||
ON_EN_SETFOCUS(IDC_USERNAME, &CLauncherDlg::OnUserEditChangeFocus)
|
||||
ON_EN_SETFOCUS(IDC_PASSWORD, &CLauncherDlg::OnPassEditChangeFocus)
|
||||
ON_BN_CLICKED(IDC_BUTTON_NEXT, &CLauncherDlg::OnNextClicked)
|
||||
ON_BN_CLICKED(IDC_TROUBLE_LINK, &CLauncherDlg::OnTroubleClicked)
|
||||
ON_WM_CTLCOLOR()
|
||||
ON_WM_DRAWITEM()
|
||||
ON_WM_SETCURSOR()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
// CLauncherDlg message handlers
|
||||
|
||||
BOOL CLauncherDlg::OnInitDialog() {
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
SetIcon(m_hIcon, TRUE); // Set big icon
|
||||
SetIcon(m_hIcon, FALSE); // Set small icon
|
||||
|
||||
CFont editFont;
|
||||
if (LauncherUtils::getFont(GRAPHIK_REGULAR, FIELDS_FONT_SIZE, true, editFont)) {
|
||||
m_orgname.SetFont(&editFont);
|
||||
m_username.SetFont(&editFont);
|
||||
m_password.SetFont(&editFont);
|
||||
}
|
||||
CFont buttonFont;
|
||||
if (LauncherUtils::getFont(_T("Graphik-Bold"), BUTTON_FONT_SIZE, true, buttonFont)) {
|
||||
m_btnNext.SetFont(&editFont);
|
||||
}
|
||||
|
||||
m_message_label = (CStatic *)GetDlgItem(IDC_MESSAGE_LABEL);
|
||||
m_action_label = (CStatic *)GetDlgItem(IDC_ACTION_LABEL);
|
||||
m_message2_label = (CStatic *)GetDlgItem(IDC_MESSAGE2_LABEL);
|
||||
m_action2_label = (CStatic *)GetDlgItem(IDC_ACTION2_LABEL);
|
||||
|
||||
m_orgname_banner = (CStatic *)GetDlgItem(IDC_ORGNAME_BANNER);
|
||||
m_username_banner = (CStatic *)GetDlgItem(IDC_USERNAME_BANNER);
|
||||
m_password_banner = (CStatic *)GetDlgItem(IDC_PASSWORD_BANNER);
|
||||
|
||||
m_terms = (CStatic *)GetDlgItem(IDC_TERMS);
|
||||
m_terms2 = (CStatic *)GetDlgItem(IDC_TERMS2);
|
||||
m_trouble = (CStatic *)GetDlgItem(IDC_TROUBLE);
|
||||
|
||||
m_voxel = (CStatic *)GetDlgItem(IDC_VOXEL);
|
||||
|
||||
m_voxel->EnableD2DSupport();
|
||||
|
||||
m_pRenderTarget = GetRenderTarget();
|
||||
|
||||
SetTimer(1, 2, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CLauncherDlg::PreTranslateMessage(MSG* pMsg) {
|
||||
if ((pMsg->message == WM_KEYDOWN))
|
||||
{
|
||||
if (pMsg->wParam == VK_RETURN)
|
||||
{
|
||||
OnNextClicked();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return CDialog::PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
void CLauncherDlg::setCustomDialog() {
|
||||
|
||||
LONG lStyle = GetWindowLong(GetSafeHwnd(), GWL_STYLE);
|
||||
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
|
||||
SetWindowLong(GetSafeHwnd(), GWL_STYLE, lStyle);
|
||||
|
||||
LONG lExStyle = GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
|
||||
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
|
||||
SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, lExStyle);
|
||||
|
||||
SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
// theApp.setDialogOnFront();
|
||||
}
|
||||
|
||||
void CLauncherDlg::OnPaint()
|
||||
{
|
||||
CPaintDC dc(this);
|
||||
setCustomDialog();
|
||||
CDialog::OnPaint();
|
||||
}
|
||||
|
||||
// The system calls this function to obtain the cursor to display while the user drags
|
||||
// the minimized window.
|
||||
HCURSOR CLauncherDlg::OnQueryDragIcon()
|
||||
{
|
||||
return static_cast<HCURSOR>(m_hIcon);
|
||||
}
|
||||
|
||||
void CLauncherDlg::startProcess() {
|
||||
if (theApp._manager.needsUpdate()) {
|
||||
setDrawDialog(DrawStep::DrawProcessUpdate);
|
||||
} else {
|
||||
setDrawDialog(DrawStep::DrawProcessSetup);
|
||||
}
|
||||
|
||||
CString installDir;
|
||||
theApp._manager.getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installDir);
|
||||
CString interfaceExe = installDir += "\\interface.exe";
|
||||
if (!theApp._manager.isLoggedIn()) {
|
||||
theApp._manager.downloadContent();
|
||||
} else {
|
||||
theApp._manager.downloadApplication();
|
||||
}
|
||||
}
|
||||
|
||||
#define str(s) #s
|
||||
#define LAUNCHER_HMAC_SECRET_STRING str(LAUNCHER_HMAC_SECRET)
|
||||
|
||||
BOOL CLauncherDlg::getHQInfo(const CString& orgname) {
|
||||
CString hash;
|
||||
LauncherUtils::hMac256(orgname, LAUNCHER_HMAC_SECRET_STRING, hash);
|
||||
return theApp._manager.readOrganizationJSON(hash) == LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
|
||||
afx_msg void CLauncherDlg::OnTroubleClicked() {
|
||||
ShellExecute(0, NULL, TROUBLE_URL, NULL, NULL, SW_SHOWDEFAULT);
|
||||
}
|
||||
|
||||
afx_msg void CLauncherDlg::OnNextClicked() {
|
||||
if (_drawStep != DrawStep::DrawChoose) {
|
||||
CString token;
|
||||
CString username, password, orgname;
|
||||
m_orgname.GetWindowTextW(orgname);
|
||||
m_username.GetWindowTextW(username);
|
||||
m_password.GetWindowTextW(password);
|
||||
LauncherUtils::ResponseError error;
|
||||
if (orgname.GetLength() > 0 && username.GetLength() > 0 && password.GetLength() > 0) {
|
||||
if (getHQInfo(orgname)) {
|
||||
error = theApp._manager.getAccessTokenForCredentials(username, password);
|
||||
if (error == LauncherUtils::ResponseError::NoError) {
|
||||
setDrawDialog(DrawStep::DrawChoose);
|
||||
} else if (error == LauncherUtils::ResponseError::BadCredentials) {
|
||||
setDrawDialog(DrawStep::DrawLoginErrorCred);
|
||||
} else {
|
||||
MessageBox(L"Error Reading or retreaving response.", L"Network Error", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
} else {
|
||||
setDrawDialog(DrawStep::DrawLoginErrorOrg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CString displayName;
|
||||
m_username.GetWindowTextW(displayName);
|
||||
theApp._manager.setDisplayName(displayName);
|
||||
startProcess();
|
||||
}
|
||||
}
|
||||
|
||||
void CLauncherDlg::drawBackground(CHwndRenderTarget* pRenderTarget) {
|
||||
CD2DBitmap m_pBitmamBackground(pRenderTarget, IDB_PNG1, _T("PNG"));
|
||||
auto size = pRenderTarget->GetSize();
|
||||
CD2DRectF backRec(0.0f, 0.0f, size.width, size.height);
|
||||
pRenderTarget->DrawBitmap(&m_pBitmamBackground, backRec);
|
||||
}
|
||||
|
||||
void CLauncherDlg::drawLogo(CHwndRenderTarget* pRenderTarget) {
|
||||
CD2DBitmap m_pBitmamLogo(pRenderTarget, IDB_PNG2, _T("PNG"));
|
||||
auto size = pRenderTarget->GetSize();
|
||||
int logoWidth = 231;
|
||||
int logoHeight = 181;
|
||||
float logoPosX = 0.5f * (size.width - logoWidth);
|
||||
float logoPosY = 0.95f * (size.height - logoHeight);
|
||||
CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight);
|
||||
pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec);
|
||||
}
|
||||
|
||||
void CLauncherDlg::drawSmallLogo(CHwndRenderTarget* pRenderTarget) {
|
||||
CD2DBitmap m_pBitmamLogo(pRenderTarget, IDB_PNG5, _T("PNG"));
|
||||
auto size = pRenderTarget->GetSize();
|
||||
int padding = 6;
|
||||
int logoWidth = 100;
|
||||
int logoHeight = 18;
|
||||
float logoPosX = size.width - logoWidth - padding;
|
||||
float logoPosY = size.height - logoHeight - padding;
|
||||
CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight);
|
||||
pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec);
|
||||
}
|
||||
|
||||
void CLauncherDlg::drawVoxel(CHwndRenderTarget* pRenderTarget) {
|
||||
CD2DBitmap m_pBitmamVoxel(pRenderTarget, IDB_PNG4, _T("PNG"));
|
||||
auto size = pRenderTarget->GetSize();
|
||||
int logoWidth = 132;
|
||||
int logoHeight = 134;
|
||||
float voxelPosX = 0.5f * (size.width - logoWidth);
|
||||
float voxelPosY = 0.5f * (size.height - logoHeight);
|
||||
CD2DRectF voxelRec(voxelPosX, voxelPosY, voxelPosX + logoWidth, voxelPosY + logoHeight);
|
||||
auto midPoint = D2D1::Point2F(0.5f * size.width, 0.5f * size.height);
|
||||
_logoRotation += 2.0f;
|
||||
CD2DSolidColorBrush brush(pRenderTarget, D2D1::ColorF(0.0f, 0.0f, 0.0f));
|
||||
pRenderTarget->SetTransform(D2D1::Matrix3x2F::Rotation(_logoRotation - 2.0f, midPoint));
|
||||
pRenderTarget->FillRectangle(voxelRec, &brush);
|
||||
pRenderTarget->SetTransform(D2D1::Matrix3x2F::Rotation(_logoRotation, midPoint));
|
||||
pRenderTarget->DrawBitmap(&m_pBitmamVoxel, voxelRec);
|
||||
pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
|
||||
}
|
||||
|
||||
|
||||
void CLauncherDlg::showWindows(std::vector<CStatic*> windows, bool show) {
|
||||
for (auto window : windows) {
|
||||
window->ShowWindow(show ? SW_SHOW : SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
void CLauncherDlg::prepareLogin(DrawStep step) {
|
||||
m_voxel->ShowWindow(SW_HIDE);
|
||||
m_orgname_banner->SetWindowTextW(_T("Organization Name"));
|
||||
m_username_banner->SetWindowTextW(_T("Username"));
|
||||
m_password_banner->SetWindowTextW(_T("Password"));
|
||||
CString editText;
|
||||
m_orgname.GetWindowTextW(editText);
|
||||
m_orgname_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
|
||||
m_username.GetWindowTextW(editText);
|
||||
m_username_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
|
||||
m_password.GetWindowTextW(editText);
|
||||
m_password_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
|
||||
m_orgname.ShowWindow(SW_SHOW);
|
||||
m_username.ShowWindow(SW_SHOW);
|
||||
m_password.ShowWindow(SW_SHOW);
|
||||
CString actionText = step == DrawStep::DrawLoginLogin ? _T("Please log in") : _T("Uh-oh, we have a problem");
|
||||
CString messageText = step == DrawStep::DrawLoginLogin ? _T("Be sure you've uploaded your Avatar before signing in.") :
|
||||
step == DrawStep::DrawLoginErrorCred ? _T("There is a problem with your credentials\n please try again.") : _T("There is a problem with your Organization name\n please try again.");
|
||||
m_action_label->SetWindowTextW(actionText);
|
||||
m_message_label->SetWindowTextW(messageText);
|
||||
m_action_label->ShowWindow(SW_SHOW);
|
||||
m_message_label->ShowWindow(SW_SHOW);
|
||||
m_btnNext.ShowWindow(SW_SHOW);
|
||||
m_trouble->SetWindowTextW(_T("Having Trouble?"));
|
||||
m_trouble->ShowWindow(SW_SHOW);
|
||||
m_trouble_link.ShowWindow(SW_SHOW);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CLauncherDlg::prepareChoose() {
|
||||
m_orgname.ShowWindow(SW_HIDE);
|
||||
m_username.SetWindowTextW(_T(""));
|
||||
m_username_banner->SetWindowTextW(_T("Display Name"));
|
||||
CString editText;
|
||||
m_username.GetWindowTextW(editText);
|
||||
m_username_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
|
||||
m_password.ShowWindow(SW_HIDE);
|
||||
m_orgname_banner->ShowWindow(SW_HIDE);
|
||||
m_password_banner->ShowWindow(SW_HIDE);
|
||||
m_action_label->SetWindowTextW(_T("Choose a display name"));
|
||||
m_message_label->SetWindowTextW(_T("This is the name that your teammates will see."));
|
||||
m_terms->ShowWindow(SW_SHOW);
|
||||
m_terms2->ShowWindow(SW_SHOW);
|
||||
m_terms->SetWindowTextW(_T("By signing in, you agree to the High Fidelity"));
|
||||
m_terms2->SetWindowTextW(_T("Terms of Service"));
|
||||
CRect rec;
|
||||
m_btnNext.GetWindowRect(&rec);
|
||||
ScreenToClient(&rec);
|
||||
if (rec.top > 281) {
|
||||
rec.bottom -= 35;
|
||||
rec.top -= 35;
|
||||
m_btnNext.MoveWindow(rec, FALSE);
|
||||
}
|
||||
m_btnNext.ShowWindow(SW_SHOW);
|
||||
}
|
||||
|
||||
void CLauncherDlg::prepareProcess(DrawStep step) {
|
||||
m_trouble->ShowWindow(SW_HIDE);
|
||||
m_trouble_link.ShowWindow(SW_HIDE);
|
||||
m_terms->ShowWindow(SW_HIDE);
|
||||
m_terms2->ShowWindow(SW_HIDE);
|
||||
m_orgname_banner->ShowWindow(SW_HIDE);
|
||||
m_username_banner->ShowWindow(SW_HIDE);
|
||||
m_password_banner->ShowWindow(SW_HIDE);
|
||||
m_orgname.ShowWindow(SW_HIDE);
|
||||
m_username.ShowWindow(SW_HIDE);
|
||||
m_password.ShowWindow(SW_HIDE);
|
||||
m_action_label->SetWindowTextW(_T(""));
|
||||
m_message_label->SetWindowTextW(_T(""));
|
||||
m_btnNext.ShowWindow(SW_HIDE);
|
||||
m_action_label->ShowWindow(SW_HIDE);
|
||||
m_message_label->ShowWindow(SW_HIDE);
|
||||
m_voxel->ShowWindow(SW_SHOW);
|
||||
CString actionText = _T("");
|
||||
CString messageText = _T("");
|
||||
switch (step) {
|
||||
case DrawStep::DrawProcessSetup:
|
||||
actionText = _T("We're building your virtual HQ");
|
||||
messageText = _T("Set up may take several minutes.");
|
||||
break;
|
||||
case DrawStep::DrawProcessUpdate:
|
||||
actionText = _T("Getting updates...");
|
||||
messageText = _T("We're getting the latest and greatest for you, one sec.");
|
||||
break;
|
||||
case DrawStep::DrawProcessFinishHq:
|
||||
actionText = _T("Your new HQ is all setup");
|
||||
messageText = _T("Thanks for being patient.");
|
||||
break;
|
||||
case DrawStep::DrawProcessFinishUpdate:
|
||||
actionText = _T("You're good to go!");
|
||||
messageText = _T("Thanks for being patient.");
|
||||
break;
|
||||
case DrawStep::DrawProcessUninstall:
|
||||
actionText = _T("Uninstalling...");
|
||||
messageText = _T("It'll take one sec.");
|
||||
break;
|
||||
}
|
||||
m_action2_label->SetWindowTextW(actionText);
|
||||
m_message2_label->SetWindowTextW(messageText);
|
||||
m_action2_label->ShowWindow(SW_SHOW);
|
||||
m_message2_label->ShowWindow(SW_SHOW);
|
||||
}
|
||||
|
||||
void CLauncherDlg::prepareError() {
|
||||
}
|
||||
|
||||
BOOL CLauncherDlg::getTextFormat(int resID, TextFormat& formatOut) {
|
||||
// Set default values for message
|
||||
BOOL isText = TRUE;
|
||||
formatOut.color = COLOR_LIGHT_GREY;
|
||||
formatOut.isBold = false;
|
||||
formatOut.isButton = false;
|
||||
formatOut.size = MESSAGE_FONT_SIZE;
|
||||
formatOut.underlined = false;
|
||||
|
||||
switch (resID) {
|
||||
case IDC_VOXEL:
|
||||
case IDD_LAUNCHER_DIALOG:
|
||||
isText = FALSE;
|
||||
case IDC_MESSAGE_LABEL:
|
||||
case IDC_MESSAGE2_LABEL:
|
||||
// Default values
|
||||
break;
|
||||
case IDC_ACTION_LABEL:
|
||||
case IDC_ACTION2_LABEL:
|
||||
formatOut.size = ACTION_FONT_SIZE;
|
||||
formatOut.isBold = true;
|
||||
formatOut.color = COLOR_LIGHTER_GREY;
|
||||
break;
|
||||
case IDC_USERNAME:
|
||||
case IDC_PASSWORD:
|
||||
case IDC_ORGNAME:
|
||||
formatOut.color = COLOR_WHITE;
|
||||
formatOut.size = FIELDS_FONT_SIZE;
|
||||
formatOut.underlined = true;
|
||||
break;
|
||||
case IDC_USERNAME_BANNER:
|
||||
case IDC_PASSWORD_BANNER:
|
||||
case IDC_ORGNAME_BANNER:
|
||||
formatOut.size = FIELDS_FONT_SIZE;
|
||||
formatOut.color = COLOR_GREY;
|
||||
break;
|
||||
case IDC_TERMS:
|
||||
formatOut.size = TERMS_FONT_SIZE;
|
||||
break;
|
||||
case IDC_TERMS2:
|
||||
formatOut.size = TERMS_FONT_SIZE;
|
||||
formatOut.isBold = true;
|
||||
break;
|
||||
case IDC_TROUBLE:
|
||||
formatOut.size = TROUBLE_FONT_SIZE;
|
||||
formatOut.color = COLOR_BLUE;
|
||||
break;
|
||||
}
|
||||
return isText;
|
||||
}
|
||||
|
||||
HBRUSH CLauncherDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
|
||||
{
|
||||
|
||||
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
|
||||
TextFormat textFormat;
|
||||
int resId = pWnd->GetDlgCtrlID();
|
||||
if (getTextFormat(resId, textFormat)) {
|
||||
pDC->SetTextColor(textFormat.color);
|
||||
pDC->SetBkMode(TRANSPARENT);
|
||||
CFont textFont;
|
||||
CString fontFamily = textFormat.isBold ? GRAPHIK_SEMIBOLD : GRAPHIK_REGULAR;
|
||||
if (LauncherUtils::getFont(fontFamily, textFormat.size, textFormat.isBold, textFont)) {
|
||||
pDC->SelectObject(&textFont);
|
||||
}
|
||||
if (textFormat.underlined) {
|
||||
CRect rect;
|
||||
pWnd->GetClientRect(&rect);
|
||||
int borderThick = 1;
|
||||
int padding = 4;
|
||||
CRect lineRect = CRect(rect.left + padding, rect.bottom, rect.right - padding, rect.bottom + borderThick);
|
||||
lineRect.MoveToY(lineRect.bottom + 1);
|
||||
pDC->FillSolidRect(lineRect, COLOR_GREY);
|
||||
}
|
||||
}
|
||||
return (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
}
|
||||
|
||||
void CLauncherDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
|
||||
{
|
||||
CDC dc;
|
||||
dc.Attach(lpDrawItemStruct->hDC);
|
||||
CRect rect = lpDrawItemStruct->rcItem;
|
||||
CRect defrect = rect;
|
||||
CString btnName = _T("");
|
||||
int xpan = 0;
|
||||
if (nIDCtl == IDC_BUTTON_NEXT) {
|
||||
if (_drawStep == DrawStep::DrawChoose || _drawStep == DrawStep::DrawLoginLogin) {
|
||||
btnName += _drawStep == DrawStep::DrawLoginLogin ? _T("NEXT") : _T("LOG IN");
|
||||
int xpan = -20;
|
||||
defrect = CRect(rect.left - xpan, rect.top, rect.right + xpan, rect.bottom);
|
||||
} else {
|
||||
btnName += _T("TRY AGAIN");
|
||||
}
|
||||
int borderThick = 2;
|
||||
dc.FillSolidRect(rect, COLOR_BLACK);
|
||||
dc.FillSolidRect(defrect, COLOR_WHITE);
|
||||
defrect.DeflateRect(borderThick, borderThick, borderThick, borderThick);
|
||||
dc.FillSolidRect(defrect, COLOR_BLACK);
|
||||
UINT state = lpDrawItemStruct->itemState;
|
||||
dc.SetTextColor(COLOR_WHITE);
|
||||
|
||||
CFont buttonFont;
|
||||
if (LauncherUtils::getFont(GRAPHIK_SEMIBOLD, BUTTON_FONT_SIZE, true, buttonFont)) {
|
||||
dc.SelectObject(buttonFont);
|
||||
}
|
||||
dc.DrawText(btnName, CRect(rect.left, rect.top + 4, rect.right, rect.bottom - 8), DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||||
dc.Detach();
|
||||
} else if (nIDCtl == IDC_TROUBLE_LINK) {
|
||||
dc.FillSolidRect(rect, COLOR_BLACK);
|
||||
dc.SetTextColor(COLOR_BLUE);
|
||||
CFont buttonFont;
|
||||
if (LauncherUtils::getFont(GRAPHIK_SEMIBOLD, TROUBLE_FONT_SIZE, true, buttonFont)) {
|
||||
dc.SelectObject(buttonFont);
|
||||
}
|
||||
dc.DrawText(_T("Having Trouble"), CRect(rect.left, rect.top, rect.right, rect.bottom), DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CLauncherDlg::redrawBanner(const CEdit& edit, CStatic* banner) {
|
||||
CString editText;
|
||||
edit.GetWindowTextW(editText);
|
||||
if (editText.GetLength() == 0) {
|
||||
banner->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void CLauncherDlg::OnOrgEditChangeFocus() {
|
||||
redrawBanner(m_username, m_username_banner);
|
||||
redrawBanner(m_password, m_password_banner);
|
||||
}
|
||||
|
||||
void CLauncherDlg::OnUserEditChangeFocus() {
|
||||
redrawBanner(m_orgname, m_orgname_banner);
|
||||
redrawBanner(m_password, m_password_banner);
|
||||
}
|
||||
|
||||
void CLauncherDlg::OnPassEditChangeFocus() {
|
||||
redrawBanner(m_orgname, m_orgname_banner);
|
||||
redrawBanner(m_username, m_username_banner);
|
||||
}
|
||||
BOOL CLauncherDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
||||
{
|
||||
if (pWnd->IsKindOf(RUNTIME_CLASS(CButton))) {
|
||||
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HAND));
|
||||
return TRUE;
|
||||
}
|
||||
return CDialog::OnSetCursor(pWnd, nHitTest, message);
|
||||
}
|
||||
|
||||
void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
|
||||
const int CONSOLE_MAX_SHUTDOWN_TRY_COUNT = 10;
|
||||
const int CONSOLE_DELTATIME_BETWEEN_TRYS = 10;
|
||||
if (_drawStep == DrawStep::DrawProcessSetup ||
|
||||
_drawStep == DrawStep::DrawProcessUpdate ||
|
||||
_drawStep == DrawStep::DrawProcessUninstall) {
|
||||
// Refresh
|
||||
setDrawDialog(_drawStep, true);
|
||||
}
|
||||
if (_showSplash) {
|
||||
if (_splashStep == 0){
|
||||
if (theApp._manager.needsUninstall()) {
|
||||
setDrawDialog(DrawStep::DrawProcessUninstall);
|
||||
} else {
|
||||
setDrawDialog(DrawStep::DrawLogo);
|
||||
}
|
||||
} else if (_splashStep > 100) {
|
||||
_showSplash = false;
|
||||
if (theApp._manager.shouldShutDown()) {
|
||||
if (LauncherUtils::IsProcessRunning(L"interface.exe")) {
|
||||
exit(0);
|
||||
}
|
||||
} else if (theApp._manager.needsUpdate()) {
|
||||
startProcess();
|
||||
} else if (theApp._manager.needsUninstall()) {
|
||||
theApp._manager.uninstallApplication();
|
||||
exit(0);
|
||||
} else {
|
||||
setDrawDialog(DrawStep::DrawLoginLogin);
|
||||
}
|
||||
}
|
||||
_splashStep++;
|
||||
} else if (theApp._manager.shouldShutDown()) {
|
||||
if (LauncherUtils::IsProcessRunning(L"interface.exe")) {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) {
|
||||
_drawStep = step;
|
||||
auto m_pRenderTarget = GetRenderTarget();
|
||||
auto m_voxelRenderTarget = m_voxel->GetRenderTarget();
|
||||
switch (_drawStep) {
|
||||
case DrawStep::DrawLogo:
|
||||
m_pRenderTarget->BeginDraw();
|
||||
drawBackground(m_pRenderTarget);
|
||||
m_pRenderTarget->EndDraw();
|
||||
m_voxelRenderTarget->BeginDraw();
|
||||
drawLogo(m_voxelRenderTarget);
|
||||
m_voxelRenderTarget->EndDraw();
|
||||
break;
|
||||
case DrawStep::DrawLoginLogin:
|
||||
case DrawStep::DrawLoginErrorOrg:
|
||||
case DrawStep::DrawLoginErrorCred:
|
||||
prepareLogin(_drawStep);
|
||||
m_pRenderTarget->BeginDraw();
|
||||
drawBackground(m_pRenderTarget);
|
||||
drawSmallLogo(m_pRenderTarget);
|
||||
m_pRenderTarget->EndDraw();
|
||||
RedrawWindow();
|
||||
break;
|
||||
case DrawStep::DrawChoose:
|
||||
prepareChoose();
|
||||
m_pRenderTarget->BeginDraw();
|
||||
drawBackground(m_pRenderTarget);
|
||||
drawSmallLogo(m_pRenderTarget);
|
||||
m_pRenderTarget->EndDraw();
|
||||
RedrawWindow();
|
||||
break;
|
||||
case DrawStep::DrawProcessFinishHq:
|
||||
case DrawStep::DrawProcessFinishUpdate:
|
||||
case DrawStep::DrawProcessUpdate:
|
||||
case DrawStep::DrawProcessUninstall:
|
||||
case DrawStep::DrawProcessSetup:
|
||||
if (!isUpdate) {
|
||||
m_voxelRenderTarget->BeginDraw();
|
||||
m_voxelRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
m_voxelRenderTarget->EndDraw();
|
||||
m_pRenderTarget->BeginDraw();
|
||||
prepareProcess(_drawStep);
|
||||
drawBackground(m_pRenderTarget);
|
||||
drawSmallLogo(m_pRenderTarget);
|
||||
m_pRenderTarget->EndDraw();
|
||||
RedrawWindow();
|
||||
}
|
||||
m_voxelRenderTarget->BeginDraw();
|
||||
drawVoxel(m_voxelRenderTarget);
|
||||
m_voxelRenderTarget->EndDraw();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
120
launchers/win32/LauncherDlg.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
//
|
||||
// LauncherDlg.h
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// CLauncherDlg dialog
|
||||
class CLauncherDlg : public CDialog
|
||||
{
|
||||
// Construction
|
||||
public:
|
||||
enum DrawStep {
|
||||
DrawLogo = 0,
|
||||
DrawLoginLogin,
|
||||
DrawLoginErrorOrg,
|
||||
DrawLoginErrorCred,
|
||||
DrawChoose,
|
||||
DrawProcessSetup,
|
||||
DrawProcessUpdate,
|
||||
DrawProcessFinishHq,
|
||||
DrawProcessFinishUpdate,
|
||||
DrawProcessUninstall,
|
||||
DrawError
|
||||
};
|
||||
|
||||
struct TextFormat {
|
||||
int size;
|
||||
COLORREF color;
|
||||
bool isButton;
|
||||
bool isBold;
|
||||
bool underlined;
|
||||
};
|
||||
|
||||
CLauncherDlg(CWnd* pParent = nullptr);
|
||||
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||||
|
||||
void setDrawDialog(DrawStep step, BOOL isUpdate = FALSE);
|
||||
|
||||
|
||||
// Dialog Data
|
||||
#ifdef AFX_DESIGN_TIME
|
||||
enum { IDD = IDD_LAUNCHER_DIALOG };
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
void startProcess();
|
||||
void setCustomDialog();
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
|
||||
BOOL getHQInfo(const CString& orgname);
|
||||
DrawStep _drawStep { DrawStep::DrawLogo };
|
||||
BOOL getTextFormat(int ResID, TextFormat& formatOut);
|
||||
void showWindows(std::vector<CStatic*> windows, bool show);
|
||||
|
||||
bool _isConsoleRunning{ false };
|
||||
bool _isInstalling{ false };
|
||||
bool _isFirstDraw{ false };
|
||||
bool _showSplash{ true };
|
||||
int _splashStep{ 0 };
|
||||
float _logoRotation { 0.0f };
|
||||
|
||||
HICON m_hIcon;
|
||||
CButton m_btnNext;
|
||||
CButton m_trouble_link;
|
||||
|
||||
CStatic* m_message_label;
|
||||
CStatic* m_action_label;
|
||||
CStatic* m_message2_label;
|
||||
CStatic* m_action2_label;
|
||||
CStatic* m_terms;
|
||||
CStatic* m_terms2;
|
||||
CStatic* m_trouble;
|
||||
CStatic* m_voxel;
|
||||
|
||||
CEdit m_orgname;
|
||||
CEdit m_username;
|
||||
CEdit m_password;
|
||||
|
||||
CStatic* m_orgname_banner;
|
||||
CStatic* m_username_banner;
|
||||
CStatic* m_password_banner;
|
||||
|
||||
void drawBackground(CHwndRenderTarget* pRenderTarget);
|
||||
void drawLogo(CHwndRenderTarget* pRenderTarget);
|
||||
void drawSmallLogo(CHwndRenderTarget* pRenderTarget);
|
||||
void drawVoxel(CHwndRenderTarget* pRenderTarget);
|
||||
|
||||
void prepareLogin(DrawStep step);
|
||||
void prepareProcess(DrawStep step);
|
||||
void prepareChoose();
|
||||
void prepareError();
|
||||
|
||||
void redrawBanner(const CEdit& edit, CStatic* banner);
|
||||
|
||||
// Generated message map functions
|
||||
virtual BOOL OnInitDialog();
|
||||
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
|
||||
afx_msg void OnPaint();
|
||||
afx_msg HCURSOR OnQueryDragIcon();
|
||||
afx_msg void OnNextClicked();
|
||||
afx_msg void OnTroubleClicked();
|
||||
afx_msg void OnOrgEditChangeFocus();
|
||||
afx_msg void OnUserEditChangeFocus();
|
||||
afx_msg void OnPassEditChangeFocus();
|
||||
afx_msg void OnTimer(UINT_PTR nIDEvent);
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
|
||||
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
|
||||
};
|
422
launchers/win32/LauncherManager.cpp
Normal file
|
@ -0,0 +1,422 @@
|
|||
//
|
||||
// LauncherManager.cpp
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 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 "stdafx.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "LauncherManager.h"
|
||||
|
||||
|
||||
LauncherManager::LauncherManager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LauncherManager::~LauncherManager()
|
||||
{
|
||||
}
|
||||
|
||||
void LauncherManager::init() {
|
||||
getMostRecentBuild(_latestApplicationURL, _latestVersion);
|
||||
CString currentVersion;
|
||||
if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) {
|
||||
if (_latestVersion.Compare(currentVersion) == 0) {
|
||||
launchApplication();
|
||||
_shouldShutdown = TRUE;
|
||||
} else {
|
||||
_shouldUpdate = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LauncherManager::installLauncher() {
|
||||
CString appPath;
|
||||
BOOL result = getAndCreatePaths(PathType::Running_Path, appPath);
|
||||
if (!result) {
|
||||
MessageBox(NULL, L"Error getting app directory", L"Path Error", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
CString installDirectory;
|
||||
CString appDirectory = appPath.Left(appPath.ReverseFind('\\') + 1);
|
||||
result = getAndCreatePaths(PathType::Launcher_Directory, installDirectory);
|
||||
if (!result) {
|
||||
MessageBox(NULL, L"Error getting app desired directory", L"Path Error", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
CString instalationPath = installDirectory + LAUNCHER_EXE_FILENAME;
|
||||
if (!installDirectory.Compare(appDirectory) == 0) {
|
||||
if (!_shouldUninstall) {
|
||||
// The installer is not running on the desired location and has to be installed
|
||||
// Kill of running before self-copy
|
||||
if (LauncherUtils::IsProcessRunning(LAUNCHER_EXE_FILENAME)) {
|
||||
::ShellExecute(NULL, NULL, L"taskkill", L"/F /T /IM " + LAUNCHER_EXE_FILENAME, NULL, SW_HIDE);
|
||||
}
|
||||
CopyFile(appPath, instalationPath, FALSE);
|
||||
}
|
||||
} else if (_shouldUninstall) {
|
||||
CString tempPath;
|
||||
if (getAndCreatePaths(PathType::Temp_Directory, tempPath)) {
|
||||
tempPath += _T("\\HQ_uninstaller_tmp.exe");
|
||||
CopyFile(instalationPath, tempPath, false);
|
||||
LauncherUtils::launchApplication(tempPath, _T(" --uninstall"));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::createShortcuts() {
|
||||
CString desktopLnkPath;
|
||||
getAndCreatePaths(PathType::Desktop_Directory, desktopLnkPath);
|
||||
desktopLnkPath += _T("\\HQ Launcher.lnk");
|
||||
CString installDir;
|
||||
getAndCreatePaths(PathType::Launcher_Directory, installDir);
|
||||
CString installPath = installDir + LAUNCHER_EXE_FILENAME;
|
||||
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(desktopLnkPath), _T("CLick to Setup and Launch HQ."))) {
|
||||
return FALSE;
|
||||
}
|
||||
CString startLinkPath;
|
||||
getAndCreatePaths(PathType::StartMenu_Directory, startLinkPath);
|
||||
CString appStartLinkPath = startLinkPath + _T("HQ Launcher.lnk");
|
||||
CString uniStartLinkPath = startLinkPath + _T("Uninstall HQ.lnk");
|
||||
CString uniLinkPath = installDir + _T("Uninstall HQ.lnk");
|
||||
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(appStartLinkPath), _T("CLick to Setup and Launch HQ."))) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(uniStartLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(uniLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::deleteShortcuts() {
|
||||
CString desktopLnkPath;
|
||||
getAndCreatePaths(PathType::Desktop_Directory, desktopLnkPath);
|
||||
desktopLnkPath += _T("\\HQ Launcher.lnk");
|
||||
BOOL success = LauncherUtils::deleteFileOrDirectory(desktopLnkPath);
|
||||
CString startLinkPath;
|
||||
getAndCreatePaths(PathType::StartMenu_Directory, startLinkPath);
|
||||
return success && LauncherUtils::deleteFileOrDirectory(startLinkPath);
|
||||
}
|
||||
|
||||
BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn) {
|
||||
CString applicationDir;
|
||||
getAndCreatePaths(PathType::Launcher_Directory, applicationDir);
|
||||
CString applicationPath = applicationDir + "interface\\interface.exe";
|
||||
BOOL isApplicationInstalled = PathFileExistsW(applicationPath);
|
||||
BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json"));
|
||||
if (isApplicationInstalled && configFileExist) {
|
||||
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn);
|
||||
return status == LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::getAndCreatePaths(PathType type, CString& outPath) {
|
||||
|
||||
if (type == PathType::Running_Path) {
|
||||
char appPath[MAX_PATH];
|
||||
DWORD size = GetModuleFileNameA(NULL, appPath, MAX_PATH);
|
||||
if (size) {
|
||||
outPath = CString(appPath);
|
||||
return TRUE;
|
||||
}
|
||||
} else if (type == PathType::Desktop_Directory) {
|
||||
TCHAR desktopPath[MAX_PATH];
|
||||
auto success = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath));
|
||||
outPath = CString(desktopPath);
|
||||
return success;
|
||||
} else if (type == PathType::Temp_Directory) {
|
||||
TCHAR tempPath[MAX_PATH];
|
||||
auto success = GetTempPath(MAX_PATH, tempPath);
|
||||
outPath = CString(tempPath);
|
||||
return success;
|
||||
} else {
|
||||
TCHAR localDataPath[MAX_PATH];
|
||||
if (type == PathType::StartMenu_Directory) {
|
||||
TCHAR startMenuPath[MAX_PATH];
|
||||
auto success = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, startMenuPath));
|
||||
outPath = CString(startMenuPath) + _T("\\Programs\\HQ\\");
|
||||
success = SHCreateDirectoryEx(NULL, outPath, NULL) || ERROR_ALREADY_EXISTS == GetLastError();
|
||||
return success;
|
||||
} else if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, localDataPath))) {
|
||||
_tcscat_s(localDataPath, _T("\\") + DIRECTORY_NAME_APP + _T("\\"));
|
||||
outPath = CString(localDataPath);
|
||||
if (type == PathType::Download_Directory) {
|
||||
outPath += DIRECTORY_NAME_DOWNLOADS + _T("\\");
|
||||
} else if (type == PathType::Interface_Directory) {
|
||||
outPath += DIRECTORY_NAME_INTERFACE;
|
||||
} else if (type == PathType::Content_Directory) {
|
||||
outPath += DIRECTORY_NAME_CONTENT;
|
||||
}
|
||||
return (CreateDirectory(outPath, NULL) || ERROR_ALREADY_EXISTS == GetLastError());
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::getInstalledVersion(const CString& path, CString& version) {
|
||||
CStdioFile cfile;
|
||||
BOOL success = cfile.Open(path, CFile::modeRead);
|
||||
if (success) {
|
||||
cfile.ReadString(version);
|
||||
cfile.Close();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
BOOL LauncherManager::launchApplication(const CString& tokensJSON) {
|
||||
CString installDir;
|
||||
LauncherManager::getAndCreatePaths(PathType::Interface_Directory, installDir);
|
||||
CString interfaceExe = installDir + _T("\\interface.exe");
|
||||
CString params1 = _T("--url \"") + _domainURL + ("\" ");
|
||||
CString cacheDir;
|
||||
LauncherManager::getAndCreatePaths(PathType::Content_Directory, cacheDir);
|
||||
CString params3 = _T("--cache \"") + cacheDir + ("\" ");
|
||||
CString params4 = !_displayName.IsEmpty() ? _T("--displayName \"") + _displayName + ("\" ") : _T("");
|
||||
CString parsedTokens = tokensJSON;
|
||||
parsedTokens.Replace(_T("\""), _T("\\\""));
|
||||
CString params5 = !tokensJSON.IsEmpty() ? _T("--tokens \"") + parsedTokens + ("\"") : _T("");
|
||||
CString params = params1 + params3 + params4 + params5 + EXTRA_PARAMETERS;
|
||||
auto rs = ShellExecute(NULL, L"open", interfaceExe, params, NULL, SW_SHOW);
|
||||
return (rs != NULL);
|
||||
}
|
||||
|
||||
BOOL LauncherManager::createConfigJSON() {
|
||||
CString configPath;
|
||||
LauncherManager::getAndCreatePaths(PathType::Interface_Directory, configPath);
|
||||
configPath += "\\config.json";
|
||||
std::ofstream configFile(configPath, std::ofstream::binary);
|
||||
if (configFile.fail()) {
|
||||
return FALSE;
|
||||
}
|
||||
Json::Value config;
|
||||
CString applicationPath;
|
||||
LauncherManager::getAndCreatePaths(PathType::Launcher_Directory, applicationPath);
|
||||
applicationPath += LAUNCHER_EXE_FILENAME;
|
||||
config["loggedIn"] = _loggedIn;
|
||||
config["launcherPath"] = LauncherUtils::cStringToStd(applicationPath);
|
||||
config["version"] = LauncherUtils::cStringToStd(_latestVersion);
|
||||
config["domain"] = LauncherUtils::cStringToStd(_domainURL);
|
||||
CString content;
|
||||
getAndCreatePaths(PathType::Content_Directory, content);
|
||||
config["content"] = LauncherUtils::cStringToStd(content);
|
||||
configFile << config;
|
||||
configFile.close();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn) {
|
||||
CString configPath;
|
||||
getAndCreatePaths(PathType::Interface_Directory, configPath);
|
||||
configPath += "\\config.json";
|
||||
std::ifstream configFile(configPath, std::ifstream::binary);
|
||||
if (configFile.fail()) {
|
||||
return LauncherUtils::ResponseError::Open;
|
||||
}
|
||||
Json::Value config;
|
||||
configFile >> config;
|
||||
if (config["version"].isString() && config["domain"].isString() &&
|
||||
config["content"].isString()) {
|
||||
loggedIn = config["loggedIn"].asBool();
|
||||
version = config["version"].asCString();
|
||||
domain = config["domain"].asCString();
|
||||
content = config["content"].asCString();
|
||||
configFile.close();
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
configFile.close();
|
||||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString& hash) {
|
||||
CString contentTypeJson = L"content-type:application/json";
|
||||
CString response;
|
||||
CString url = _T("/hifi-public/huffman/organizations/") + hash + _T(".json");
|
||||
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"s3.amazonaws.com", url,
|
||||
contentTypeJson, CStringA(), response, false);
|
||||
if (error != LauncherUtils::ResponseError::NoError) {
|
||||
return error;
|
||||
}
|
||||
Json::Value json;
|
||||
if (LauncherUtils::parseJSON(response, json)) {
|
||||
if (json["content_set_url"].isString() && json["domain"].isString()) {
|
||||
_contentURL = json["content_set_url"].asCString();
|
||||
_domainURL = json["domain"].asCString();
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
}
|
||||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
|
||||
CString contentTypeJson = L"content-type:application/json";
|
||||
CString response;
|
||||
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"thunder.highfidelity.com", L"/builds/api/tags/latest?format=json",
|
||||
contentTypeJson, CStringA(), response, false);
|
||||
if (error != LauncherUtils::ResponseError::NoError) {
|
||||
return error;
|
||||
}
|
||||
Json::Value json;
|
||||
if (LauncherUtils::parseJSON(response, json)) {
|
||||
int count = json["count"].isInt() ? json["count"].asInt() : 0;
|
||||
if (count > 0 && json["results"].isArray()) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (json["results"][i].isObject()) {
|
||||
Json::Value result = json["results"][i];
|
||||
if (result["latest_version"].isInt()) {
|
||||
std::string version = std::to_string(result["latest_version"].asInt());
|
||||
versionOut = CString(version.c_str());
|
||||
}
|
||||
if (result["installers"].isObject() &&
|
||||
result["installers"]["windows"].isObject() &&
|
||||
result["installers"]["windows"]["zip_url"].isString()) {
|
||||
urlOut = result["installers"]["windows"]["zip_url"].asCString();
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, const CString& password) {
|
||||
CStringA post = "grant_type=password&username=";
|
||||
post += username;
|
||||
post += "&password=";
|
||||
post += password;
|
||||
post += "&scope=owner";
|
||||
|
||||
CString contentTypeText = L"content-type:application/x-www-form-urlencoded";
|
||||
CString response;
|
||||
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"metaverse.highfidelity.com", L"/oauth/token",
|
||||
contentTypeText, post, response, true);
|
||||
if (error != LauncherUtils::ResponseError::NoError) {
|
||||
return error;
|
||||
}
|
||||
Json::Value json;
|
||||
if (LauncherUtils::parseJSON(response, json)) {
|
||||
if (json["error"].isString()) {
|
||||
return LauncherUtils::ResponseError::BadCredentials;
|
||||
} else if (json["access_token"].isString()) {
|
||||
_tokensJSON = response;
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
}
|
||||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::createApplicationRegistryKeys(int size) {
|
||||
const std::string REGISTRY_PATH = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\HQ";
|
||||
BOOL success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayName", "HQ");
|
||||
CString installDir;
|
||||
getAndCreatePaths(PathType::Launcher_Directory, installDir);
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "InstallLocation", LauncherUtils::cStringToStd(installDir));
|
||||
std::string applicationExe = LauncherUtils::cStringToStd(installDir + LAUNCHER_EXE_FILENAME);
|
||||
std::string uninstallPath = '"' + applicationExe + '"' + " --uninstall";
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "UninstallString", uninstallPath);
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayVersion", LauncherUtils::cStringToStd(_latestVersion));
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayIcon", applicationExe);
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "Publisher", "High Fidelity");
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "InstallDate", LauncherUtils::cStringToStd(CTime::GetCurrentTime().Format("%Y%m%d")));
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "EstimatedSize", (DWORD)size);
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "NoModify", (DWORD)1);
|
||||
success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "NoRepair", (DWORD)1);
|
||||
return success;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::deleteApplicationRegistryKeys() {
|
||||
const CString REGISTRY_PATH = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\HQ");
|
||||
return LauncherUtils::deleteRegistryKey(REGISTRY_PATH);
|
||||
}
|
||||
|
||||
BOOL LauncherManager::uninstallApplication() {
|
||||
CString installDir;
|
||||
getAndCreatePaths(PathType::Launcher_Directory, installDir);
|
||||
BOOL success = LauncherUtils::deleteFileOrDirectory(installDir);
|
||||
success = success && (deleteShortcuts());
|
||||
success = success && (deleteApplicationRegistryKeys());
|
||||
return success;
|
||||
}
|
||||
|
||||
void LauncherManager::onZipExtracted(ZipType type, int size) {
|
||||
if (type == ZipType::ZipContent) {
|
||||
downloadApplication();
|
||||
} else if (type == ZipType::ZipApplication) {
|
||||
createShortcuts();
|
||||
CString versionPath;
|
||||
getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, versionPath);
|
||||
createConfigJSON();
|
||||
launchApplication(_tokensJSON);
|
||||
createApplicationRegistryKeys(size);
|
||||
_shouldShutdown = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LauncherManager::extractApplication() {
|
||||
CString installPath;
|
||||
getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installPath);
|
||||
BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipApplication, LauncherUtils::cStringToStd(_applicationZipPath),
|
||||
LauncherUtils::cStringToStd(installPath), [&](int type, int size) {
|
||||
onZipExtracted((ZipType)type, size);
|
||||
});
|
||||
return success;
|
||||
}
|
||||
|
||||
void LauncherManager::onFileDownloaded(DownloadType type) {
|
||||
if (type == DownloadType::DownloadContent) {
|
||||
installContent();
|
||||
} else if (type == DownloadType::DownloadApplication) {
|
||||
extractApplication();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL LauncherManager::installContent() {
|
||||
std::string contentZipFile = LauncherUtils::cStringToStd(_contentZipPath);
|
||||
CString contentPath;
|
||||
getAndCreatePaths(LauncherManager::PathType::Content_Directory, contentPath);
|
||||
BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipContent, contentZipFile,
|
||||
LauncherUtils::cStringToStd(contentPath), [&](int type, int size) {
|
||||
onZipExtracted((ZipType)type, size);
|
||||
});
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CString& outPath) {
|
||||
CString fileName = url.Mid(url.ReverseFind('/') + 1);
|
||||
CString downloadDirectory;
|
||||
BOOL success = getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDirectory);
|
||||
outPath = downloadDirectory + fileName;
|
||||
if (success) {
|
||||
if (!LauncherUtils::downloadFileOnThread(type, url, outPath, [&](int type) {
|
||||
onFileDownloaded((DownloadType)type);
|
||||
})) {
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
BOOL LauncherManager::downloadContent() {
|
||||
CString contentURL = getContentURL();
|
||||
return downloadFile(DownloadType::DownloadContent, contentURL, _contentZipPath);
|
||||
}
|
||||
|
||||
BOOL LauncherManager::downloadApplication() {
|
||||
CString applicationURL = getLatestInterfaceURL();
|
||||
return downloadFile(DownloadType::DownloadApplication, applicationURL, _applicationZipPath);
|
||||
}
|
109
launchers/win32/LauncherManager.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// LauncherManager.h
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LauncherUtils.h"
|
||||
|
||||
const CString DIRECTORY_NAME_APP = _T("HQ");
|
||||
const CString DIRECTORY_NAME_DOWNLOADS = _T("downloads");
|
||||
const CString DIRECTORY_NAME_INTERFACE = _T("interface");
|
||||
const CString DIRECTORY_NAME_CONTENT = _T("content");
|
||||
const CString EXTRA_PARAMETERS = _T(" --suppress-settings-reset --no-launcher --no-updater");
|
||||
const CString LAUNCHER_EXE_FILENAME = _T("HQ Launcher.exe");
|
||||
const bool INSTALL_ZIP = true;
|
||||
|
||||
class LauncherManager
|
||||
{
|
||||
public:
|
||||
enum PathType {
|
||||
Running_Path = 0,
|
||||
Launcher_Directory,
|
||||
Download_Directory,
|
||||
Interface_Directory,
|
||||
Desktop_Directory,
|
||||
Content_Directory,
|
||||
StartMenu_Directory,
|
||||
Temp_Directory
|
||||
};
|
||||
enum ZipType {
|
||||
ZipContent = 0,
|
||||
ZipApplication
|
||||
};
|
||||
enum DownloadType {
|
||||
DownloadContent = 0,
|
||||
DownloadApplication
|
||||
};
|
||||
enum ErrorType {
|
||||
ErrorNetworkAuth,
|
||||
ErrorNetworkUpdate,
|
||||
ErrorNetworkHq,
|
||||
ErrorDownloading,
|
||||
ErrorUpdating,
|
||||
ErrorInstall,
|
||||
ErrorIOFiles
|
||||
};
|
||||
LauncherManager();
|
||||
~LauncherManager();
|
||||
void init();
|
||||
BOOL getAndCreatePaths(PathType type, CString& outPath);
|
||||
BOOL getInstalledVersion(const CString& path, CString& version);
|
||||
BOOL isApplicationInstalled(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn);
|
||||
LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
|
||||
LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut);
|
||||
LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
|
||||
LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn);
|
||||
BOOL createConfigJSON();
|
||||
BOOL createApplicationRegistryKeys(int size);
|
||||
BOOL deleteApplicationRegistryKeys();
|
||||
BOOL createShortcuts();
|
||||
BOOL deleteShortcuts();
|
||||
BOOL launchApplication(const CString& tokensJSON = _T(""));
|
||||
BOOL uninstallApplication();
|
||||
BOOL installLauncher();
|
||||
|
||||
// getters
|
||||
const CString& getContentURL() const { return _contentURL; }
|
||||
const CString& getdomainURL() const { return _domainURL; }
|
||||
const CString& getVersion() const { return _version; }
|
||||
BOOL shouldShutDown() const { return _shouldShutdown; }
|
||||
BOOL needsUpdate() { return _shouldUpdate; }
|
||||
BOOL needsUninstall() { return _shouldUninstall; }
|
||||
void setDisplayName(const CString& displayName) { _displayName = displayName; }
|
||||
bool isLoggedIn() { return _loggedIn; }
|
||||
const CString& getLatestInterfaceURL() const { return _latestApplicationURL; }
|
||||
void uninstall() { _shouldUninstall = true; };
|
||||
|
||||
BOOL downloadFile(DownloadType type, const CString& url, CString& localPath);
|
||||
BOOL downloadContent();
|
||||
BOOL downloadApplication();
|
||||
BOOL installContent();
|
||||
BOOL extractApplication();
|
||||
void onZipExtracted(ZipType type, int size);
|
||||
void onFileDownloaded(DownloadType type);
|
||||
|
||||
private:
|
||||
CString _latestApplicationURL;
|
||||
CString _latestVersion;
|
||||
CString _contentURL;
|
||||
CString _domainURL;
|
||||
CString _version;
|
||||
CString _displayName;
|
||||
CString _tokensJSON;
|
||||
CString _applicationZipPath;
|
||||
CString _contentZipPath;
|
||||
bool _loggedIn{ false };
|
||||
BOOL _shouldUpdate{ FALSE };
|
||||
BOOL _shouldUninstall{ FALSE };
|
||||
BOOL _shouldShutdown{ FALSE };
|
||||
};
|
||||
|
405
launchers/win32/LauncherUtils.cpp
Normal file
|
@ -0,0 +1,405 @@
|
|||
//
|
||||
// LauncherUtils.cpp
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 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 "stdafx.h"
|
||||
#include <wincrypt.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <strsafe.h>
|
||||
#include <winhttp.h>
|
||||
#pragma comment(lib, "winhttp")
|
||||
|
||||
#include "LauncherUtils.h"
|
||||
|
||||
BOOL LauncherUtils::IsProcessRunning(const wchar_t *processName) {
|
||||
bool exists = false;
|
||||
PROCESSENTRY32 entry;
|
||||
entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
||||
|
||||
if (Process32First(snapshot, &entry)) {
|
||||
while (Process32Next(snapshot, &entry)) {
|
||||
if (!_wcsicmp(entry.szExeFile, processName)) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
return exists;
|
||||
}
|
||||
|
||||
HRESULT LauncherUtils::CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs) {
|
||||
IShellLink* psl;
|
||||
|
||||
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
|
||||
// has already been called.
|
||||
CoInitialize(NULL);
|
||||
HRESULT hres = E_INVALIDARG;
|
||||
if ((lpszPathObj != NULL) && (wcslen(lpszPathObj) > 0) &&
|
||||
(lpszDesc != NULL) &&
|
||||
(lpszPathLink != NULL) && (strlen(lpszPathLink) > 0)) {
|
||||
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
|
||||
if (SUCCEEDED(hres)) {
|
||||
IPersistFile* ppf;
|
||||
|
||||
// Set the path to the shortcut target and add the description.
|
||||
psl->SetPath(lpszPathObj);
|
||||
psl->SetDescription(lpszDesc);
|
||||
psl->SetArguments(lpszArgs);
|
||||
|
||||
// Query IShellLink for the IPersistFile interface, used for saving the
|
||||
// shortcut in persistent storage.
|
||||
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
|
||||
|
||||
if (SUCCEEDED(hres)) {
|
||||
WCHAR wsz[MAX_PATH];
|
||||
|
||||
// Ensure that the string is Unicode.
|
||||
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
|
||||
|
||||
// Add code here to check return value from MultiByteWideChar
|
||||
// for success.
|
||||
|
||||
// Save the link by calling IPersistFile::Save.
|
||||
hres = ppf->Save(wsz, TRUE);
|
||||
ppf->Release();
|
||||
}
|
||||
psl->Release();
|
||||
}
|
||||
}
|
||||
CoUninitialize();
|
||||
return SUCCEEDED(hres);
|
||||
}
|
||||
|
||||
std::string LauncherUtils::cStringToStd(CString cstring) {
|
||||
CT2CA convertedString(cstring);
|
||||
std::string strStd(convertedString);
|
||||
return strStd;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::launchApplication(LPCWSTR lpApplicationName, LPTSTR cmdArgs) {
|
||||
// additional information
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
// set the size of the structures
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
// start the program up
|
||||
BOOL success = CreateProcess(
|
||||
lpApplicationName, // the path
|
||||
cmdArgs, // Command line
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // Set handle inheritance to FALSE
|
||||
CREATE_NEW_CONSOLE, // Opens file in a separate console
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi // Pointer to PROCESS_INFORMATION structure
|
||||
);
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return success;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::deleteRegistryKey(const CString& registryPath) {
|
||||
TCHAR szDelKey[MAX_PATH * 2];
|
||||
StringCchCopy(szDelKey, MAX_PATH * 2, registryPath);
|
||||
auto status = RegDeleteKey(HKEY_CURRENT_USER, szDelKey);
|
||||
if (status == ERROR_SUCCESS) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerName,
|
||||
const CString& mainUrl, const CString& dirUrl,
|
||||
const CString& contentType, CStringA& postData,
|
||||
CString& response, bool isPost = false) {
|
||||
|
||||
HINTERNET hopen = WinHttpOpen(callerName, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
if (!hopen) {
|
||||
return ResponseError::Open;
|
||||
}
|
||||
HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, INTERNET_DEFAULT_HTTPS_PORT, 0);
|
||||
if (!hconnect) {
|
||||
return ResponseError::Connect;
|
||||
}
|
||||
HINTERNET hrequest = WinHttpOpenRequest(hconnect, isPost ? L"POST" : L"GET", dirUrl,
|
||||
NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
|
||||
if (!hrequest) {
|
||||
return ResponseError::OpenRequest;
|
||||
}
|
||||
if (isPost) {
|
||||
if (!WinHttpSendRequest(hrequest, contentType, -1,
|
||||
postData.GetBuffer(postData.GetLength()), (DWORD)strlen(postData), (DWORD)strlen(postData), NULL)) {
|
||||
return ResponseError::SendRequest;
|
||||
}
|
||||
} else {
|
||||
if (!WinHttpSendRequest(hrequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
|
||||
return ResponseError::SendRequest;
|
||||
}
|
||||
}
|
||||
if (!WinHttpReceiveResponse(hrequest, 0)) {
|
||||
return ResponseError::ReceiveRequest;
|
||||
}
|
||||
// query remote file size, set haveContentLength on success and dwContentLength to the length
|
||||
wchar_t szContentLength[32];
|
||||
DWORD bufferBytes = 4096;
|
||||
DWORD dwHeaderIndex = WINHTTP_NO_HEADER_INDEX;
|
||||
|
||||
BOOL haveContentLength = WinHttpQueryHeaders(hrequest, WINHTTP_QUERY_CONTENT_LENGTH, NULL,
|
||||
&szContentLength, &bufferBytes, &dwHeaderIndex);
|
||||
|
||||
DWORD dwContentLength;
|
||||
if (haveContentLength) {
|
||||
dwContentLength = _wtoi(szContentLength);
|
||||
}
|
||||
byte p[4096];
|
||||
if (!WinHttpQueryDataAvailable(hrequest, &bufferBytes)) {
|
||||
return ResponseError::ReadResponse;
|
||||
}
|
||||
WinHttpReadData(hrequest, p, bufferBytes, &bufferBytes);
|
||||
response = CString((const char*)p, (int)bufferBytes);
|
||||
return ResponseError::NoError;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::parseJSON(const CString& jsonTxt, Json::Value& root) {
|
||||
Json::CharReaderBuilder CharBuilder;
|
||||
std::string jsonString = cStringToStd(jsonTxt);
|
||||
std::string errs;
|
||||
Json::CharReader* nreader = CharBuilder.newCharReader();
|
||||
bool parsingSuccessful = false;
|
||||
if (nreader != NULL) {
|
||||
parsingSuccessful = nreader->parse(jsonString.c_str(), jsonString.c_str() + jsonString.length(), &root, &errs);
|
||||
delete nreader;
|
||||
}
|
||||
return parsingSuccessful;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::getFont(const CString& fontName, int fontSize, bool isBold, CFont& fontOut) {
|
||||
LOGFONT lf;
|
||||
memset(&lf, 0, sizeof(lf));
|
||||
lf.lfHeight = fontSize;
|
||||
lf.lfWeight = isBold ? FW_BOLD : FW_NORMAL;
|
||||
lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
|
||||
lf.lfQuality = ANTIALIASED_QUALITY;
|
||||
|
||||
wcscpy_s(lf.lfFaceName, fontName);
|
||||
if (!fontOut.CreateFontIndirect(&lf)) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string& path, std::vector<std::string>& files) {
|
||||
mz_zip_archive zip_archive;
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
|
||||
auto status = mz_zip_reader_init_file(&zip_archive, zipFile.c_str(), 0);
|
||||
|
||||
if (!status) return 0;
|
||||
int fileCount = (int)mz_zip_reader_get_num_files(&zip_archive);
|
||||
if (fileCount == 0) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return 0;
|
||||
}
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
if (!mz_zip_reader_file_stat(&zip_archive, 0, &file_stat)) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return 0;
|
||||
}
|
||||
// Get root folder
|
||||
CString lastDir = _T("");
|
||||
uint64_t totalSize = 0;
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) continue;
|
||||
std::string filename = file_stat.m_filename;
|
||||
std::replace(filename.begin(), filename.end(), '/', '\\');
|
||||
CString fullFilename = CString(path.c_str()) + "\\" + CString(filename.c_str());
|
||||
if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) {
|
||||
if (SHCreateDirectoryEx(NULL, fullFilename, NULL) || ERROR_ALREADY_EXISTS == GetLastError()) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CT2A destFile(fullFilename);
|
||||
if (mz_zip_reader_extract_to_file(&zip_archive, i, destFile, 0)) {
|
||||
totalSize += (uint64_t)file_stat.m_uncomp_size;
|
||||
files.emplace_back(destFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the archive, freeing any resources it was using
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::insertRegistryKey(const std::string& regPath, const std::string& name, const std::string& value) {
|
||||
HKEY key;
|
||||
auto status = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &key, NULL);
|
||||
if (status == ERROR_SUCCESS) {
|
||||
status = RegSetValueExA(key, name.c_str(), 0, REG_SZ, (const BYTE*)value.c_str(), (DWORD)(value.size() + 1));
|
||||
return status == ERROR_SUCCESS;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::insertRegistryKey(const std::string& regPath, const std::string& name, DWORD value) {
|
||||
HKEY key;
|
||||
auto status = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &key, NULL);
|
||||
if (status == ERROR_SUCCESS) {
|
||||
status = RegSetValueExA(key, name.c_str(), 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
|
||||
return TRUE;
|
||||
}
|
||||
RegCloseKey(key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::deleteFileOrDirectory(const CString& dirPath, bool noRecycleBin) {
|
||||
CString dir = dirPath;
|
||||
// Add extra null to string
|
||||
dir.AppendChar(0);
|
||||
SHFILEOPSTRUCT fileop;
|
||||
fileop.hwnd = NULL; // no status display
|
||||
fileop.wFunc = FO_DELETE; // delete operation
|
||||
fileop.pFrom = dir; // source file name as double null terminated string
|
||||
fileop.pTo = NULL; // no destination needed
|
||||
fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user
|
||||
|
||||
if (!noRecycleBin) {
|
||||
fileop.fFlags |= FOF_ALLOWUNDO;
|
||||
}
|
||||
|
||||
fileop.fAnyOperationsAborted = FALSE;
|
||||
fileop.lpszProgressTitle = NULL;
|
||||
fileop.hNameMappings = NULL;
|
||||
|
||||
int ret = SHFileOperation(&fileop);
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString& hashOut) {
|
||||
char message[256];
|
||||
strcpy_s(message, CStringA(cmessage).GetString());
|
||||
char key[256];
|
||||
strcpy_s(key, keystr);
|
||||
HCRYPTPROV hProv = 0;
|
||||
HCRYPTHASH hHash = 0;
|
||||
HCRYPTKEY hKey = 0;
|
||||
HCRYPTHASH hHmacHash = 0;
|
||||
BYTE pbHash[32];
|
||||
HMAC_INFO HmacInfo;
|
||||
int err = 0;
|
||||
typedef struct blob {
|
||||
BLOBHEADER header;
|
||||
DWORD len;
|
||||
BYTE key[1];
|
||||
} m_blob;
|
||||
|
||||
ZeroMemory(&HmacInfo, sizeof(HmacInfo));
|
||||
HmacInfo.HashAlgid = CALG_SHA_256;
|
||||
ZeroMemory(&pbHash, 32);
|
||||
m_blob* kb = NULL;
|
||||
DWORD kbSize = DWORD(sizeof(m_blob) + strlen(key));
|
||||
|
||||
kb = (m_blob*)malloc(kbSize);
|
||||
kb->header.bType = PLAINTEXTKEYBLOB;
|
||||
kb->header.bVersion = CUR_BLOB_VERSION;
|
||||
kb->header.reserved = 0;
|
||||
kb->header.aiKeyAlg = CALG_RC2;
|
||||
memcpy(&kb->key, key, strlen(key));
|
||||
kb->len = (DWORD)strlen(key);
|
||||
BOOL success = false;
|
||||
DWORD datalen = (DWORD)32;
|
||||
if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)
|
||||
&& CryptImportKey(hProv, (BYTE*)kb, kbSize, 0, CRYPT_IPSEC_HMAC_KEY, &hKey)
|
||||
&& CryptCreateHash(hProv, CALG_HMAC, hKey, 0, &hHmacHash)
|
||||
&& CryptSetHashParam(hHmacHash, HP_HMAC_INFO, (BYTE*)&HmacInfo, 0)
|
||||
&& CryptHashData(hHmacHash, (BYTE*)message, (DWORD)strlen(message), 0)
|
||||
&& CryptGetHashParam(hHmacHash, HP_HASHVAL, pbHash, &datalen, 0)) {
|
||||
char *Hex = "0123456789abcdef";
|
||||
char HashString[65] = { 0 };
|
||||
for (int Count = 0; Count < 32; Count++)
|
||||
{
|
||||
HashString[Count * 2] = Hex[pbHash[Count] >> 4];
|
||||
HashString[(Count * 2) + 1] = Hex[pbHash[Count] & 0xF];
|
||||
}
|
||||
hashOut = CString(HashString);
|
||||
success = true;
|
||||
}
|
||||
|
||||
free(kb);
|
||||
if (hHmacHash)
|
||||
CryptDestroyHash(hHmacHash);
|
||||
if (hKey)
|
||||
CryptDestroyKey(hKey);
|
||||
if (hHash)
|
||||
CryptDestroyHash(hHash);
|
||||
if (hProv)
|
||||
CryptReleaseContext(hProv, 0);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
|
||||
UnzipThreadData& data = *((UnzipThreadData*)lpParameter);
|
||||
uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>());
|
||||
int mb_size = (int)(size * 0.001f);
|
||||
data.callback(data._type, mb_size);
|
||||
delete &data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter)
|
||||
{
|
||||
DownloadThreadData& data = *((DownloadThreadData*)lpParameter);
|
||||
auto hr = URLDownloadToFile(0, data._url, data._file, 0, NULL);
|
||||
data.callback(data._type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function<void(int, int)> callback) {
|
||||
DWORD myThreadID;
|
||||
UnzipThreadData* unzipThreadData = new UnzipThreadData();
|
||||
unzipThreadData->_type = type;
|
||||
unzipThreadData->_zipFile = zipFile;
|
||||
unzipThreadData->_path = path;
|
||||
unzipThreadData->setCallback(callback);
|
||||
HANDLE myHandle = CreateThread(0, 0, unzipThread, unzipThreadData, 0, &myThreadID);
|
||||
if (myHandle) {
|
||||
CloseHandle(myHandle);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CString& file, std::function<void(int)> callback) {
|
||||
DWORD myThreadID;
|
||||
DownloadThreadData* downloadThreadData = new DownloadThreadData();
|
||||
downloadThreadData->_type = type;
|
||||
downloadThreadData->_url = url;
|
||||
downloadThreadData->_file = file;
|
||||
downloadThreadData->setCallback(callback);
|
||||
HANDLE myHandle = CreateThread(0, 0, downloadThread, downloadThreadData, 0, &myThreadID);
|
||||
if (myHandle) {
|
||||
CloseHandle(myHandle);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
77
launchers/win32/LauncherUtils.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// LauncherUtils.h
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "libs/json/json.h"
|
||||
#include "libs/miniz.h"
|
||||
|
||||
class LauncherUtils
|
||||
{
|
||||
public:
|
||||
enum ResponseError {
|
||||
Open = 0,
|
||||
Connect,
|
||||
OpenRequest,
|
||||
SendRequest,
|
||||
ReceiveRequest,
|
||||
ReadResponse,
|
||||
ParsingJSON,
|
||||
BadCredentials,
|
||||
NoError
|
||||
};
|
||||
|
||||
struct DownloadThreadData {
|
||||
int _type;
|
||||
CString _url;
|
||||
CString _file;
|
||||
std::function<void(int)> callback;
|
||||
// function(type)
|
||||
void setCallback(std::function<void(int)> fn) {
|
||||
callback = std::bind(fn, std::placeholders::_1);
|
||||
}
|
||||
};
|
||||
|
||||
struct UnzipThreadData {
|
||||
int _type;
|
||||
std::string _zipFile;
|
||||
std::string _path;
|
||||
// function(type, size)
|
||||
std::function<void(int, int)> callback;
|
||||
void setCallback(std::function<void(int, int)> fn) {
|
||||
callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
|
||||
}
|
||||
};
|
||||
|
||||
static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject);
|
||||
static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl,
|
||||
const CString& dirUrl, const CString& contentType,
|
||||
CStringA& postData, CString& response, bool isPost);
|
||||
static std::string cStringToStd(CString cstring);
|
||||
static BOOL getFont(const CString& fontName, int fontSize, bool isBold, CFont& fontOut);
|
||||
static BOOL launchApplication(LPCWSTR lpApplicationName, LPTSTR cmdArgs = _T(""));
|
||||
static BOOL IsProcessRunning(const wchar_t *processName);
|
||||
static BOOL insertRegistryKey(const std::string& regPath, const std::string& name, const std::string& value);
|
||||
static BOOL insertRegistryKey(const std::string& regPath, const std::string& name, DWORD value);
|
||||
static BOOL deleteFileOrDirectory(const CString& dirPath, bool noRecycleBin = true);
|
||||
static HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs = _T(""));
|
||||
static BOOL hMac256(const CString& message, const char* key, CString& hashOut);
|
||||
static uint64_t extractZip(const std::string& zipFile, const std::string& path, std::vector<std::string>& files);
|
||||
static BOOL deleteRegistryKey(const CString& registryPath);
|
||||
static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function<void(int, int)> callback);
|
||||
static BOOL downloadFileOnThread(int type, const CString& url, const CString& file, std::function<void(int)> callback);
|
||||
|
||||
private:
|
||||
// Threads
|
||||
static DWORD WINAPI unzipThread(LPVOID lpParameter);
|
||||
static DWORD WINAPI downloadThread(LPVOID lpParameter);
|
||||
};
|
320
launchers/win32/libs/json/json-forwards.h
Normal file
|
@ -0,0 +1,320 @@
|
|||
/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).
|
||||
/// It is intended to be used with #include "json/json-forwards.h"
|
||||
/// This header provides forward declaration for all JsonCpp types.
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// Beginning of content of file: LICENSE
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
========================================================================
|
||||
(END LICENSE TEXT)
|
||||
|
||||
The MIT license is compatible with both the GPL and commercial
|
||||
software, affording one all of the rights of Public Domain with the
|
||||
minor nuisance of being required to keep the above copyright notice
|
||||
and license text in the source code. Note also that by accepting the
|
||||
Public Domain "license" you can re-license your copy using whatever
|
||||
license you like.
|
||||
|
||||
*/
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// End of content of file: LICENSE
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED
|
||||
# define JSON_FORWARD_AMALGAMATED_H_INCLUDED
|
||||
/// If defined, indicates that the source file is amalgamated
|
||||
/// to prevent private header inclusion.
|
||||
#define JSON_IS_AMALGAMATION
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// Beginning of content of file: include/json/config.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
#define JSON_CONFIG_H_INCLUDED
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
/// If defined, indicates that json library is embedded in CppTL library.
|
||||
//# define JSON_IN_CPPTL 1
|
||||
|
||||
/// If defined, indicates that json may leverage CppTL library
|
||||
//# define JSON_USE_CPPTL 1
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of
|
||||
/// std::map
|
||||
/// as Value container.
|
||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||
|
||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||
// assertion macros. The default is to use exceptions.
|
||||
#ifndef JSON_USE_EXCEPTION
|
||||
#define JSON_USE_EXCEPTION 1
|
||||
#endif
|
||||
|
||||
/// If defined, indicates that the source file is amalgamated
|
||||
/// to prevent private header inclusion.
|
||||
/// Remarks: it is automatically defined in the generated amalgamated header.
|
||||
// #define JSON_IS_AMALGAMATION
|
||||
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#include <cpptl/config.h>
|
||||
#ifndef JSON_USE_CPPTL
|
||||
#define JSON_USE_CPPTL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#define JSON_API CPPTL_API
|
||||
#elif defined(JSON_DLL_BUILD)
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define JSON_API __declspec(dllexport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define JSON_API __attribute__((visibility("default")))
|
||||
#endif // if defined(_MSC_VER)
|
||||
#elif defined(JSON_DLL)
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define JSON_API __declspec(dllimport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#endif // if defined(_MSC_VER)
|
||||
#endif // ifdef JSON_IN_CPPTL
|
||||
#if !defined(JSON_API)
|
||||
#define JSON_API
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#error \
|
||||
"ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
// As recommended at
|
||||
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
|
||||
extern JSON_API int
|
||||
msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
|
||||
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
|
||||
#else
|
||||
#define jsoncpp_snprintf std::snprintf
|
||||
#endif
|
||||
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
|
||||
// integer
|
||||
// Storages, and 64 bits integer support is disabled.
|
||||
// #define JSON_NO_INT64 1
|
||||
|
||||
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
|
||||
// C++11 should be used directly in JSONCPP.
|
||||
#define JSONCPP_OVERRIDE override
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define JSONCPP_NOEXCEPT noexcept
|
||||
#define JSONCPP_OP_EXPLICIT explicit
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define JSONCPP_NOEXCEPT throw()
|
||||
#define JSONCPP_OP_EXPLICIT explicit
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#define JSONCPP_NOEXCEPT noexcept
|
||||
#define JSONCPP_OP_EXPLICIT explicit
|
||||
#else
|
||||
#define JSONCPP_NOEXCEPT throw()
|
||||
#define JSONCPP_OP_EXPLICIT
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if __has_extension(attribute_deprecated_with_message)
|
||||
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#endif
|
||||
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
|
||||
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
||||
#endif // GNUC version
|
||||
#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates MSVC)
|
||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||
#endif // __clang__ || __GNUC__ || _MSC_VER
|
||||
|
||||
#if !defined(JSONCPP_DEPRECATED)
|
||||
#define JSONCPP_DEPRECATED(message)
|
||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||
|
||||
#if __GNUC__ >= 6
|
||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||
#endif
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
#include "allocator.h"
|
||||
#include "version.h"
|
||||
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
#if defined(JSON_NO_INT64)
|
||||
typedef int LargestInt;
|
||||
typedef unsigned int LargestUInt;
|
||||
#undef JSON_HAS_INT64
|
||||
#else // if defined(JSON_NO_INT64)
|
||||
// For Microsoft Visual use specific types as long long is not supported
|
||||
#if defined(_MSC_VER) // Microsoft Visual Studio
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
typedef int64_t Int64;
|
||||
typedef uint64_t UInt64;
|
||||
#endif // if defined(_MSC_VER)
|
||||
typedef Int64 LargestInt;
|
||||
typedef UInt64 LargestUInt;
|
||||
#define JSON_HAS_INT64
|
||||
#endif // if defined(JSON_NO_INT64)
|
||||
|
||||
template <typename T>
|
||||
using Allocator = typename std::conditional<JSONCPP_USING_SECURE_MEMORY,
|
||||
SecureAllocator<T>,
|
||||
std::allocator<T>>::type;
|
||||
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
||||
using IStringStream = std::basic_istringstream<String::value_type,
|
||||
String::traits_type,
|
||||
String::allocator_type>;
|
||||
using OStringStream = std::basic_ostringstream<String::value_type,
|
||||
String::traits_type,
|
||||
String::allocator_type>;
|
||||
using IStream = std::istream;
|
||||
using OStream = std::ostream;
|
||||
} // namespace Json
|
||||
|
||||
// Legacy names (formerly macros).
|
||||
using JSONCPP_STRING = Json::String;
|
||||
using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
|
||||
using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
|
||||
using JSONCPP_ISTREAM = Json::IStream;
|
||||
using JSONCPP_OSTREAM = Json::OStream;
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// End of content of file: include/json/config.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// Beginning of content of file: include/json/forwards.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||
#define JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
// writer.h
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
|
||||
// reader.h
|
||||
class Reader;
|
||||
|
||||
// features.h
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
typedef unsigned int ArrayIndex;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// End of content of file: include/json/forwards.h
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED
|
2346
launchers/win32/libs/json/json.h
Normal file
5407
launchers/win32/libs/jsoncpp.cpp
Normal file
7657
launchers/win32/libs/miniz.cpp
Normal file
1338
launchers/win32/libs/miniz.h
Normal file
BIN
launchers/win32/res/Graphikbold.ttf
Normal file
BIN
launchers/win32/res/Graphikregular.ttf
Normal file
BIN
launchers/win32/res/HiFi_Logo_Large.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
launchers/win32/res/HiFi_Logo_Small.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
launchers/win32/res/HiFi_Voxel.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
launchers/win32/res/HiFi_Window.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
13
launchers/win32/res/Launcher.rc2
Normal file
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Launcher.rc2 - resources Microsoft Visual C++ does not edit directly
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#error this file is not editable by Microsoft Visual C++
|
||||
#endif //APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Add manually edited resources here...
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
BIN
launchers/win32/res/button.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
launchers/win32/res/interface.ico
Normal file
After Width: | Height: | Size: 30 KiB |
40
launchers/win32/resource.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Launcher.rc
|
||||
//
|
||||
#define IDD_LAUNCHER_DIALOG 102
|
||||
#define IDR_MAINFRAME 128
|
||||
#define IDB_PNG1 133
|
||||
#define IDB_PNG2 134
|
||||
#define IDB_PNG4 136
|
||||
#define IDR_FONT_REGULAR 140
|
||||
#define IDR_FONT_BOLD 141
|
||||
#define IDB_PNG5 144
|
||||
#define IDC_BACKGROUND 1009
|
||||
#define IDC_ORGNAME 1010
|
||||
#define IDC_USERNAME 1011
|
||||
#define IDC_PASSWORD 1012
|
||||
#define IDC_MESSAGE_LABEL 1013
|
||||
#define IDC_ACTION_LABEL 1014
|
||||
#define IDC_BUTTON_NEXT 1015
|
||||
#define IDC_MESSAGE2_LABEL 1016
|
||||
#define IDC_ACTION2_LABEL 1017
|
||||
#define IDC_ORGNAME_BANNER 1018
|
||||
#define IDC_USERNAME_BANNER 1019
|
||||
#define IDC_PASSWORD_BANNER 1020
|
||||
#define IDC_TERMS 1021
|
||||
#define IDC_TERMS2 1022
|
||||
#define IDC_TROUBLE 1023
|
||||
#define IDC_VOXEL 1024
|
||||
#define IDC_TROUBLE_LINK 1027
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 147
|
||||
#define _APS_NEXT_COMMAND_VALUE 32771
|
||||
#define _APS_NEXT_CONTROL_VALUE 1028
|
||||
#define _APS_NEXT_SYMED_VALUE 103
|
||||
#endif
|
||||
#endif
|
13
launchers/win32/stdafx.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// stdafx.cpp
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 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 "stdafx.h"
|
||||
|
||||
|
35
launchers/win32/stdafx.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// stdafx.h
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef VC_EXTRALEAN
|
||||
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
|
||||
#endif
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
|
||||
#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // remove support for MFC controls in dialogs
|
||||
|
||||
// turns off MFC's hiding of some common and often safely ignored warning messages
|
||||
#define _AFX_ALL_WARNINGS
|
||||
|
||||
#include <afxwin.h> // MFC core and standard components
|
||||
#include <afxext.h> // MFC extensions
|
||||
|
||||
#ifndef _AFX_NO_OLE_SUPPORT
|
||||
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
|
||||
#endif
|
||||
#ifndef _AFX_NO_AFXCMN_SUPPORT
|
||||
#include <afxcmn.h> // MFC support for Windows Common Controls
|
||||
#endif // _AFX_NO_AFXCMN_SUPPORT
|
||||
|
||||
#include <afxcontrolbars.h> // MFC support for ribbons and control bars
|
18
launchers/win32/targetver.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// targetver.h
|
||||
//
|
||||
// Created by Luis Cuenca on 6/5/2019.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
|
@ -29,10 +29,12 @@ elif sys.platform == "darwin":
|
|||
|
||||
|
||||
# Customize the output filename
|
||||
def computeArchiveName():
|
||||
def computeArchiveName(prefix):
|
||||
RELEASE_TYPE = os.getenv("RELEASE_TYPE", "DEV")
|
||||
RELEASE_NUMBER = os.getenv("RELEASE_NUMBER", "")
|
||||
GIT_PR_COMMIT_SHORT = os.getenv("SHA7", "")
|
||||
if GIT_PR_COMMIT_SHORT == '':
|
||||
GIT_PR_COMMIT_SHORT = os.getenv("GIT_PR_COMMIT_SHORT", "")
|
||||
|
||||
if RELEASE_TYPE == "PRODUCTION":
|
||||
BUILD_VERSION = "{}-{}".format(RELEASE_NUMBER, GIT_PR_COMMIT_SHORT)
|
||||
|
@ -48,7 +50,7 @@ def computeArchiveName():
|
|||
else:
|
||||
PLATFORM = "other"
|
||||
|
||||
ARCHIVE_NAME = "HighFidelity-Beta-Interface-{}-{}".format(BUILD_VERSION, PLATFORM)
|
||||
ARCHIVE_NAME = "{}-{}-{}".format(prefix, BUILD_VERSION, PLATFORM)
|
||||
return ARCHIVE_NAME
|
||||
|
||||
def wipeClientBuildPath(relativePath):
|
||||
|
@ -109,12 +111,48 @@ def fixupWinZip(filename):
|
|||
print("Replacing {} with fixed {}".format(fullPath, outFullPath))
|
||||
shutil.move(outFullPath, fullPath)
|
||||
|
||||
def buildLightLauncher():
|
||||
launcherSourcePath = os.path.join(SOURCE_PATH, 'launchers', sys.platform)
|
||||
launcherBuildPath = os.path.join(BUILD_PATH, 'launcher')
|
||||
if not os.path.exists(launcherBuildPath):
|
||||
os.makedirs(launcherBuildPath)
|
||||
# configure launcher build
|
||||
cmakeArgs = [ 'cmake', '-S', launcherSourcePath ]
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
cmakeArgs.append('-G')
|
||||
cmakeArgs.append('Xcode')
|
||||
elif sys.platform == 'win32':
|
||||
cmakeArgs.append('-A')
|
||||
cmakeArgs.append('x64')
|
||||
|
||||
hifi_utils.executeSubprocess(cmakeArgs, folder=launcherBuildPath)
|
||||
|
||||
buildTarget = 'package'
|
||||
if sys.platform == 'win32':
|
||||
buildTarget = 'ALL_BUILD'
|
||||
hifi_utils.executeSubprocess([
|
||||
'cmake',
|
||||
'--build', launcherBuildPath,
|
||||
'--config', 'Release',
|
||||
'--target', buildTarget
|
||||
], folder=launcherBuildPath)
|
||||
if sys.platform == 'darwin':
|
||||
launcherDestFile = os.path.join(BUILD_PATH, "{}.dmg".format(computeArchiveName('Launcher')))
|
||||
launcherSourceFile = os.path.join(launcherBuildPath, "HQ Launcher.dmg")
|
||||
elif sys.platform == 'win32':
|
||||
# FIXME
|
||||
launcherDestFile = os.path.join(BUILD_PATH, "{}.exe".format(computeArchiveName('Launcher')))
|
||||
launcherSourceFile = os.path.join(launcherBuildPath, "Launcher.exe")
|
||||
print("Moving {} to {}".format(launcherSourceFile, launcherDestFile))
|
||||
shutil.move(launcherSourceFile, launcherDestFile)
|
||||
|
||||
|
||||
for wipePath in WIPE_PATHS:
|
||||
wipeClientBuildPath(wipePath)
|
||||
|
||||
# Need the archive name for ad-hoc zip file manipulation
|
||||
archiveName = computeArchiveName()
|
||||
archiveName = computeArchiveName('HighFidelity-Beta-Interface')
|
||||
|
||||
cpackCommand = [
|
||||
'cpack',
|
||||
|
@ -132,3 +170,5 @@ if sys.platform == "win32":
|
|||
elif sys.platform == "darwin":
|
||||
fixupMacZip(archiveName)
|
||||
|
||||
# FIXME enable when MFC is on the Windows build hosts
|
||||
# buildLightLauncher()
|
||||
|
|