diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 177a7722e5..fe7f4298ce 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -20,6 +20,8 @@ set(src_files src/DownloadInterface.m src/DownloadDomainContent.h src/DownloadDomainContent.m + src/DownloadLauncher.h + src/DownloadLauncher.m src/DownloadScripts.h src/DownloadScripts.m src/CredentialsRequest.h @@ -34,6 +36,8 @@ set(src_files src/Interface.m src/ErrorViewController.h src/ErrorViewController.m + src/LauncherCommandlineArgs.h + src/LauncherCommandlineArgs.m src/Settings.h src/Settings.m src/LaunchInterface.h @@ -47,6 +51,9 @@ set(src_files nib/ProcessScreen.xib nib/DisplayNameScreen.xib) +set(updater_src_files + src/updater/main.m) + set(APP_NAME "HQ Launcher") set(CMAKE_C_FLAGS "-x objective-c") @@ -72,6 +79,7 @@ endfunction() set_packaging_parameters() add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files}) +add_executable("updater" ${updater_src_files}) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME} MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME}) set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "") @@ -102,6 +110,10 @@ 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/") +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND updater + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/updater" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/") + install( TARGETS HQLauncher BUNDLE DESTINATION "." diff --git a/launchers/darwin/src/DownloadLauncher.h b/launchers/darwin/src/DownloadLauncher.h new file mode 100644 index 0000000000..2f97910cd8 --- /dev/null +++ b/launchers/darwin/src/DownloadLauncher.h @@ -0,0 +1,8 @@ +#import + +@interface DownloadLauncher : NSObject { +} + +- (void) downloadLauncher:(NSString*) launcherUrl; + +@end diff --git a/launchers/darwin/src/DownloadLauncher.m b/launchers/darwin/src/DownloadLauncher.m new file mode 100644 index 0000000000..e7d293be43 --- /dev/null +++ b/launchers/darwin/src/DownloadLauncher.m @@ -0,0 +1,68 @@ +#import "DownloadLauncher.h" +#import "Launcher.h" + + +@implementation DownloadLauncher + +- (void) downloadLauncher:(NSString*)launcherUrl { + NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:launcherUrl] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:60.0]; + + NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration]; + NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]]; + NSURLSessionDownloadTask *downloadTask = [defaultSession downloadTaskWithRequest:request]; + [downloadTask resume]; +} + +-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + CGFloat prog = (float)totalBytesWritten/totalBytesExpectedToWrite; + NSLog(@"Launcher downloaded %f", (100.0*prog)); + +} + +-(void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location { + NSLog(@"Did finish downloading to url"); + NSError* error = nil; + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSString* destinationFileName = downloadTask.originalRequest.URL.lastPathComponent; + NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:destinationFileName]; + NSURL *destinationURL = [NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]]; + NSLog(@"desintation %@", destinationURL); + if([fileManager fileExistsAtPath:[destinationURL path]]) { + [fileManager removeItemAtURL:destinationURL error:nil]; + } + + NSLog(@"location: %@", location.path); + NSLog(@"destination: %@", destinationURL); + BOOL success = [fileManager moveItemAtURL:location toURL:destinationURL error:&error]; + + + NSLog(success ? @"TRUE" : @"FALSE"); + Launcher* sharedLauncher = [Launcher sharedLauncher]; + + if (error) { + NSLog(@"Download Launcher: failed to move file to destintation -> error: %@", error); + [sharedLauncher displayErrorPage]; + return; + } + NSLog(@"extracting Launcher file"); + BOOL extractionSuccessful = [sharedLauncher extractZipFileAtDestination:[sharedLauncher getDownloadPathForContentAndScripts] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"HQ Launcher.zip"]]; + + if (!extractionSuccessful) { + [sharedLauncher displayErrorPage]; + return; + } + NSLog(@"finished extracting Launcher file"); + + + [[Launcher sharedLauncher] runAutoupdater]; +} + +- (void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error { + NSLog(@"completed; error: %@", error); + if (error) { + [[Launcher sharedLauncher] displayErrorPage]; + } +} +@end diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m index deb6d9795b..a663200089 100644 --- a/launchers/darwin/src/LatestBuildRequest.m +++ b/launchers/darwin/src/LatestBuildRequest.m @@ -9,8 +9,8 @@ NSInteger currentVersion; @try { NSString* interfaceAppPath = [[Launcher.sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]; - NSError * error = nil; - Interface * interface = [[Interface alloc] initWith:interfaceAppPath]; + NSError* error = nil; + Interface* interface = [[Interface alloc] initWith:interfaceAppPath]; currentVersion = [interface getVersion:&error]; if (currentVersion == 0 && error != nil) { NSLog(@"can't get version from interface, falling back to settings: %@", error); @@ -24,17 +24,17 @@ } - (void) requestLatestBuildInfo { - NSMutableURLRequest *request = [NSMutableURLRequest new]; + 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"]; // We're using an ephermeral session here to ensure the tags api response is never cached. - NSURLSession * session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; + NSURLSession* session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"Latest Build Request error: %@", error); NSLog(@"Latest Build Request Data: %@", data); - NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response; + NSHTTPURLResponse* ne = (NSHTTPURLResponse *)response; NSLog(@"Latest Build Request Response: %ld", [ne statusCode]); Launcher* sharedLauncher = [Launcher sharedLauncher]; @@ -47,9 +47,9 @@ NSMutableData* webData = [NSMutableData data]; [webData appendData:data]; NSString* jsonString = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[data length] encoding:NSUTF8StringEncoding]; - NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; + NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"Latest Build Request -> json string: %@", jsonString); - NSError *jsonError = nil; + NSError* jsonError = nil; id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError]; if (jsonError) { @@ -57,10 +57,12 @@ } NSFileManager* fileManager = [NSFileManager defaultManager]; - NSArray *values = [json valueForKey:@"results"]; - NSDictionary *value = [values objectAtIndex:0]; - + NSArray* values = [json valueForKey:@"results"]; + NSDictionary* launcherValues = [json valueForKey:@"launcher"]; + NSDictionary* value = [values objectAtIndex:0]; + NSString* launcherVersion = [launcherValues valueForKey:@"version"]; + NSString* launcherUrl = [[launcherValues valueForKey:@"mac"] valueForKey:@"url"]; NSString* buildNumber = [value valueForKey:@"latest_version"]; NSDictionary* installers = [value objectForKey:@"installers"]; NSDictionary* macInstallerObject = [installers objectForKey:@"mac"]; @@ -71,16 +73,22 @@ dispatch_async(dispatch_get_main_queue(), ^{ NSInteger currentVersion = [self getCurrentVersion]; + NSInteger currentLauncherVersion = atoi(LAUNCHER_BUILD_VERSION); + NSLog(@"Latest Build Request -> current launcher version %ld", currentLauncherVersion); + NSLog(@"Latest Build Request -> latest launcher version %ld", launcherVersion.integerValue); + NSLog(@"Latest Build Request -> launcher url %@", launcherUrl); NSLog(@"Latest Build Request -> does build directory exist: %@", appDirectoryExist ? @"TRUE" : @"FALSE"); NSLog(@"Latest Build Request -> current version: %ld", currentVersion); NSLog(@"Latest Build Request -> latest version: %ld", buildNumber.integerValue); NSLog(@"Latest Build Request -> mac url: %@", macInstallerUrl); BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue); + BOOL latestLauncherVersionAvailable = (currentLauncherVersion != launcherVersion.integerValue); [[Settings sharedSettings] buildVersion:buildNumber.integerValue]; BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist); NSLog(@"Latest Build Request -> SHOULD DOWNLOAD: %@", shouldDownloadInterface ? @"TRUE" : @"FALSE"); - [sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl]; + [sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl + :latestLauncherVersionAvailable :launcherUrl]; }); }]; diff --git a/launchers/darwin/src/Launcher.h b/launchers/darwin/src/Launcher.h index de67850bfe..d20f58dee7 100644 --- a/launchers/darwin/src/Launcher.h +++ b/launchers/darwin/src/Launcher.h @@ -2,6 +2,7 @@ #import "DownloadInterface.h" #import "CredentialsRequest.h" #import "DownloadDomainContent.h" +#import "DownloadLauncher.h" #import "LatestBuildRequest.h" #import "OrganizationRequest.h" #import "DownloadScripts.h" @@ -44,6 +45,7 @@ struct LatestBuildInfo { @property (nonatomic, retain) DownloadInterface* downloadInterface; @property (nonatomic, retain) CredentialsRequest* credentialsRequest; @property (nonatomic, retain) DownloadDomainContent* downloadDomainContent; +@property (nonatomic, retain) DownloadLauncher* downloadLauncher; @property (nonatomic, retain) DownloadScripts* downloadScripts; @property (nonatomic, retain) LatestBuildRequest* latestBuildRequest; @property (nonatomic, retain) OrganizationRequest* organizationRequest; @@ -74,11 +76,12 @@ struct LatestBuildInfo { - (void) showLoginScreen; - (void) restart; - (NSString*) getLauncherPath; +- (void) runAutoupdater; - (ProcessState) currentProccessState; - (void) setCurrentProcessState:(ProcessState) aProcessState; - (void) setLoginErrorState:(LoginError) aLoginError; - (LoginError) getLoginErrorState; -- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl; +- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl :(BOOL) newLauncherAvailable :(NSString*) launcherUrl; - (void) interfaceFinishedDownloading; - (NSString*) getDownloadPathForContentAndScripts; - (void) launchInterface; diff --git a/launchers/darwin/src/Launcher.m b/launchers/darwin/src/Launcher.m index 1a84e9143d..38027d6fd3 100644 --- a/launchers/darwin/src/Launcher.m +++ b/launchers/darwin/src/Launcher.m @@ -3,6 +3,7 @@ #import "SplashScreen.h" #import "LoginScreen.h" #import "DisplayNameScreen.h" +#import "LauncherCommandlineArgs.h" #import "ProcessScreen.h" #import "ErrorViewController.h" #import "Settings.h" @@ -32,6 +33,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE; self.username = [[NSString alloc] initWithString:@"Default Property Value"]; self.downloadInterface = [DownloadInterface alloc]; self.downloadDomainContent = [DownloadDomainContent alloc]; + self.downloadLauncher = [DownloadLauncher alloc]; self.credentialsRequest = [CredentialsRequest alloc]; self.latestBuildRequest = [LatestBuildRequest alloc]; self.organizationRequest = [OrganizationRequest alloc]; @@ -362,28 +364,44 @@ static BOOL const DELETE_ZIP_FILES = TRUE; [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen]; } -- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl +- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl :(BOOL) newLauncherAvailable :(NSString*) launcherUrl { - self.shouldDownloadInterface = shouldDownload; - self.interfaceDownloadUrl = downloadUrl; - self.latestBuildRequestFinished = TRUE; - if ([self isLoadedIn]) { - Launcher* sharedLauncher = [Launcher sharedLauncher]; - [sharedLauncher setCurrentProcessState:CHECKING_UPDATE]; - if (shouldDownload) { - ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; - [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; - [self startUpdateProgressIndicatorTimer]; - [self.downloadInterface downloadInterface: downloadUrl]; - return; - } - [self interfaceFinishedDownloading]; + NSDictionary* launcherArguments = [LauncherCommandlineArgs arguments]; + if (newLauncherAvailable && ![launcherArguments valueForKey: @"--noUpdate"]) { + [self.downloadLauncher downloadLauncher: launcherUrl]; } else { - [[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE]; - [self showLoginScreen]; + self.shouldDownloadInterface = shouldDownload; + self.interfaceDownloadUrl = downloadUrl; + self.latestBuildRequestFinished = TRUE; + if ([self isLoadedIn]) { + Launcher* sharedLauncher = [Launcher sharedLauncher]; + [sharedLauncher setCurrentProcessState:CHECKING_UPDATE]; + if (shouldDownload) { + ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; + [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; + [self startUpdateProgressIndicatorTimer]; + [self.downloadInterface downloadInterface: downloadUrl]; + return; + } + [self interfaceFinishedDownloading]; + } else { + [[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE]; + [self showLoginScreen]; + } } } +-(void)runAutoupdater +{ + NSTask* task = [[NSTask alloc] init]; + NSString* newLauncher = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent: @"HQ Launcher.app"]; + task.launchPath = [newLauncher stringByAppendingString:@"/Contents/Resources/updater"]; + task.arguments = @[[[NSBundle mainBundle] bundlePath], newLauncher]; + [task launch]; + + [NSApp terminate:self]; +} + -(void)onSplashScreenTimerFinished:(NSTimer *)timer { [self.latestBuildRequest requestLatestBuildInfo]; diff --git a/launchers/darwin/src/LauncherCommandlineArgs.h b/launchers/darwin/src/LauncherCommandlineArgs.h new file mode 100644 index 0000000000..c348e50987 --- /dev/null +++ b/launchers/darwin/src/LauncherCommandlineArgs.h @@ -0,0 +1,8 @@ +#import +#import + +@interface LauncherCommandlineArgs : NSObject { +} ++(NSDictionary*) arguments; +@end + diff --git a/launchers/darwin/src/LauncherCommandlineArgs.m b/launchers/darwin/src/LauncherCommandlineArgs.m new file mode 100644 index 0000000000..4229c91205 --- /dev/null +++ b/launchers/darwin/src/LauncherCommandlineArgs.m @@ -0,0 +1,29 @@ +#import "LauncherCommandlineArgs.h" + +@implementation LauncherCommandlineArgs ++(NSDictionary*) arguments { + + NSArray* arguments = [[NSProcessInfo processInfo] arguments]; + if (arguments.count < 2) + { + return nil; + } + + NSMutableDictionary* argsDict = [[NSMutableDictionary alloc] init]; + NSMutableArray* args = [arguments mutableCopy]; + + for (NSString* arg in args) + { + if ([arg rangeOfString:@"="].location != NSNotFound && [arg rangeOfString:@"--"].location != NSNotFound) { + NSArray* components = [arg componentsSeparatedByString:@"="]; + NSString* key = [components objectAtIndex:0]; + NSString* value = [components objectAtIndex:1]; + [argsDict setObject:value forKey:key]; + } else if ([arg rangeOfString:@"--"].location != NSNotFound) { + [argsDict setObject:@TRUE forKey:arg]; + } + } + NSLog(@"AGS: %@", argsDict); + return argsDict; +} +@end diff --git a/launchers/darwin/src/main.mm b/launchers/darwin/src/main.mm index b6555aad87..8651ffe3ff 100644 --- a/launchers/darwin/src/main.mm +++ b/launchers/darwin/src/main.mm @@ -1,5 +1,6 @@ #import "Launcher.h" #import "Settings.h" +#import "LauncherCommandlineArgs.h" void redirectLogToDocuments() { diff --git a/launchers/darwin/src/updater/main.m b/launchers/darwin/src/updater/main.m new file mode 100644 index 0000000000..7c7ace6f70 --- /dev/null +++ b/launchers/darwin/src/updater/main.m @@ -0,0 +1,35 @@ +#import +#import + +@interface UpdaterHelper : NSObject ++(NSURL*) NSStringToNSURL: (NSString*) path; +@end + +@implementation UpdaterHelper ++(NSURL*) NSStringToNSURL: (NSString*) path +{ + return [NSURL URLWithString: [path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]]; +} +@end + +int main(int argc, char const* argv[]) { + if (argc < 3) { + NSLog(@"Error: wrong number of arguments"); + return 0; + } + + for (int index = 0; index < argc; index++) { + NSLog(@"argv at index %d = %s", index, argv[index]); + } + NSString* oldLauncher = [NSString stringWithUTF8String:argv[1]]; + NSString* newLauncher = [NSString stringWithUTF8String:argv[2]]; + NSURL* destinationUrl = [UpdaterHelper NSStringToNSURL:newLauncher]; + NSFileManager* fileManager = [NSFileManager defaultManager]; + [fileManager replaceItemAtURL:[UpdaterHelper NSStringToNSURL:oldLauncher] withItemAtURL:[UpdaterHelper NSStringToNSURL:newLauncher] backupItemName:nil options:NSFileManagerItemReplacementUsingNewMetadataOnly resultingItemURL:&destinationUrl error:nil]; + NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; + NSURL* applicationURL = [UpdaterHelper NSStringToNSURL: [oldLauncher stringByAppendingString: @"/Contents/MacOS/HQ Launcher"]]; + NSArray* arguments =@[]; + NSLog(@"Launcher agruments: %@", arguments); + [workspace launchApplicationAtURL:applicationURL options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:nil]; + return 0; +} diff --git a/libraries/platform/src/platform/backend/WINPlatform.cpp b/libraries/platform/src/platform/backend/WINPlatform.cpp index 8c0bb1b9aa..2958374451 100644 --- a/libraries/platform/src/platform/backend/WINPlatform.cpp +++ b/libraries/platform/src/platform/backend/WINPlatform.cpp @@ -27,7 +27,6 @@ #include #pragma comment(lib, "dxgi.lib") #include -#pragma comment(lib, "Shcore.lib") #endif @@ -118,10 +117,19 @@ void WINInstance::enumerateGpusAndDisplays() { // Grab the dpi info for the monitor UINT dpiX{ 0 }; UINT dpiY{ 0 }; - GetDpiForMonitor(outputDesc.Monitor, MDT_RAW_DPI, &dpiX, &dpiY); UINT dpiXScaled{ 0 }; UINT dpiYScaled{ 0 }; - GetDpiForMonitor(outputDesc.Monitor, MDT_EFFECTIVE_DPI, &dpiXScaled, &dpiYScaled); + + // SHCore.dll is not available prior to Windows 8.1 + HMODULE SHCoreDLL = LoadLibraryW(L"SHCore.dll"); + if (SHCoreDLL) { + auto _GetDpiForMonitor = reinterpret_cast(GetProcAddress(SHCoreDLL, "GetDpiForMonitor")); + if (_GetDpiForMonitor) { + _GetDpiForMonitor(outputDesc.Monitor, MDT_RAW_DPI, &dpiX, &dpiY); + _GetDpiForMonitor(outputDesc.Monitor, MDT_EFFECTIVE_DPI, &dpiXScaled, &dpiYScaled); + } + FreeLibrary(SHCoreDLL); + } // Current display mode DEVMODEW devMode; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 381377c9f4..69455294d6 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -352,6 +352,7 @@ void ScriptEngines::saveScripts() { // the scripts that the user expects to be there when launched without the // --scripts override. if (_defaultScriptsLocationOverridden) { + runningScriptsHandle.set(QVariantList{ DEFAULT_SCRIPTS_LOCATION }); return; }