Files
OpenRA/OpenRA.Launcher.Mac/Controller.m

239 lines
7.3 KiB
Objective-C

/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#import "main.h"
#import "Controller.h"
@implementation Controller
+ (void)initialize
{
[[NSUserDefaults standardUserDefaults]
registerDefaults:[NSDictionary dictionaryWithObject:[[NSBundle mainBundle] resourcePath]
forKey:@"gamepath"]];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
gamePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"gamepath"];
NSArray *args = [[NSProcessInfo processInfo] arguments];
// Ingame requests for native dialogs
if ([args containsObject:@"--display-filepicker"])
[self launchFilePicker:args];
// Try and launch the game
if (![self initMono])
{
NSAlert *alert = [NSAlert alertWithMessageText:@"Mono Framework"
defaultButton:@"Download Mono"
alternateButton:@"Quit"
otherButton:nil
informativeTextWithFormat:@"OpenRA requires the Mono Framework version 2.6.7 or later."];
if ([alert runModal] == NSAlertDefaultReturn)
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.go-mono.com/mono-downloads/download.html"]];
[[NSApplication sharedApplication] terminate:self];
}
// Extract a zip file
if ([args containsObject:@"--extract-zip"])
[self extractZip:args];
// Install ra packages from cd
if ([args containsObject:@"--install-ra-packages"])
[self installRaPackages:args];
[self launchMod:@"cnc"];
[NSApp terminate: nil];
}
- (void)extractZip:(NSArray *)args
{
[self runUtilityWithArg:[NSString stringWithFormat:@"--extract-zip=%@,%@",[args objectAtIndex:2],[args objectAtIndex:3]]];
}
- (void)installRaPackages:(NSArray *)args
{
[self runUtilityWithArg:[NSString stringWithFormat:@"--install-ra-packages=%@",[args objectAtIndex:2]]];
}
- (void)launchFilePicker:(NSArray *)args
{
[NSApp activateIgnoringOtherApps:YES];
hide_menubar_if_necessary();
NSOpenPanel *op = [NSOpenPanel openPanel];
[op setLevel:CGShieldingWindowLevel()];
[op setAllowsMultipleSelection:NO];
NSUInteger a = [args indexOfObject:@"--title"];
if (a != NSNotFound)
[op setTitle:[args objectAtIndex:a+1]];
a = [args indexOfObject:@"--message"];
if (a != NSNotFound)
[op setMessage:[args objectAtIndex:a+1]];
a = [args indexOfObject:@"--directory"];
if (a != NSNotFound)
[op setDirectory:[[args objectAtIndex:a+1] stringByExpandingTildeInPath]];
a = [args indexOfObject:@"--require-directory"];
if (a != NSNotFound)
{
[op setCanChooseFiles:NO];
[op setCanChooseDirectories:YES];
}
a = [args indexOfObject:@"--button-text"];
if (a != NSNotFound)
[op setPrompt:[[args objectAtIndex:a+1] stringByExpandingTildeInPath]];
if ([op runModal] == NSFileHandlingPanelOKButton)
printf("%s\n", [[[op URL] path] UTF8String]);
[NSApp terminate: nil];
}
-(void)launchMod:(NSString *)mod
{
// Use LaunchServices because neither NSTask or NSWorkspace support Info.plist _and_ arguments pre-10.6
// First argument is the directory to run in
// Second...Nth arguments are passed to OpenRA.Game.exe
// Launcher wrapper sets mono --debug, gl renderer and support dir.
NSArray *args = [NSArray arrayWithObjects:@"--launch", gamePath, monoPath,
[NSString stringWithFormat:@"NativeUtilityPath=%@", [[[NSBundle mainBundle] executablePath] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]],
[NSString stringWithFormat:@"SupportDir=%@",[@"~/Library/Application Support/OpenRA" stringByExpandingTildeInPath]],
[NSString stringWithFormat:@"Game.Mods=%@",mod],
nil];
FSRef appRef;
CFURLGetFSRef((CFURLRef)[NSURL URLWithString:[[[NSBundle mainBundle] executablePath] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]], &appRef);
// Set the launch parameters
LSApplicationParameters params;
params.version = 0;
params.flags = kLSLaunchDefaults | kLSLaunchNewInstance;
params.application = &appRef;
params.asyncLaunchRefCon = NULL;
params.environment = NULL; // CFDictionaryRef of environment variables; could be useful
params.argv = (CFArrayRef)args;
params.initialEvent = NULL;
ProcessSerialNumber psn;
OSStatus err = LSOpenApplication(&params, &psn);
// Bring the game window to the front
if (err == noErr)
SetFrontProcess(&psn);
}
- (BOOL)initMono
{
// Find the users mono
NSPipe *outPipe = [NSPipe pipe];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/usr/bin/which"];
[task setArguments:[NSMutableArray arrayWithObject:@"mono"]];
[task setStandardOutput:outPipe];
[task setStandardError:[task standardOutput]];
[task launch];
NSData *data = [[outPipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *temp = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
// Remove whitespace and resolve symlinks
monoPath = [[[temp stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
stringByResolvingSymlinksInPath] retain];
if (![monoPath length])
return NO;
// Find the mono version
outPipe = [NSPipe pipe];
task = [[NSTask alloc] init];
[task setLaunchPath:monoPath];
[task setArguments:[NSMutableArray arrayWithObject:@"--version"]];
[task setStandardOutput:outPipe];
[task setStandardError:[task standardOutput]];
[task launch];
data = [[outPipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
[task release];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
int major = 0;
int minor = 0;
int point = 0;
sscanf([ret UTF8String], "Mono JIT compiler version %d.%d.%d", &major, &minor, &point);
[ret release];
return (major > 2 ||
(major == 2 && minor > 6) ||
(major == 2 && minor == 6 && point >= 7));
}
- (void)runUtilityWithArg:(NSString *)arg
{
NSTask *task = [[[NSTask alloc] init] autorelease];
NSPipe *pipe = [NSPipe pipe];
NSMutableArray *taskArgs = [NSMutableArray arrayWithObject:@"OpenRA.Utility.exe"];
[taskArgs addObject:arg];
[task setCurrentDirectoryPath:gamePath];
[task setLaunchPath:monoPath];
[task setArguments:taskArgs];
[task setStandardOutput:pipe];
NSFileHandle *readHandle = [pipe fileHandleForReading];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(utilityResponded:)
name:NSFileHandleReadCompletionNotification
object:readHandle];
[task launch];
[readHandle readInBackgroundAndNotify];
[task waitUntilExit];
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
}
- (void)utilityResponded:(NSNotification *)n
{
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
printf("%s", [response UTF8String]);
// Keep reading
if ([n object] != nil)
[[n object] readInBackgroundAndNotify];
}
- (void)dealloc
{
[monoPath release]; monoPath = nil;
[gamePath release]; gamePath = nil;
[super dealloc];
}
@end