Skip to content
This repository has been archived by the owner on Nov 20, 2022. It is now read-only.

Commit

Permalink
Initial import of new OS X launcher.
Browse files Browse the repository at this point in the history
- Fixes dialogs hijacking Finder.
- Fixes dock icon being lost when restarting.
- Adds openra:// url handling.
- Adds .orarep file handling.
- Minimum OS X version is now 10.6.
  • Loading branch information
pchote committed Apr 12, 2015
0 parents commit 60ccb98
Show file tree
Hide file tree
Showing 10 changed files with 464 additions and 0 deletions.
86 changes: 86 additions & 0 deletions Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?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>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>orarep</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>OpenRA.icns</string>
<key>CFBundleTypeName</key>
<string>OpenRA Replay</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSItemContentTypes</key>
<array>
<string>net.openra.replay</string>
</array>
<key>LSTypeIsPackage</key>
<integer>0</integer>
</dict>
</array>
<key>CFBundleDisplayName</key>
<string>OpenRA</string>
<key>CFBundleExecutable</key>
<string>OpenRA</string>
<key>CFBundleIconFile</key>
<string>OpenRA.icns</string>
<key>CFBundleIdentifier</key>
<string>net.openra.launcher</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>OpenRA</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>{DEV_VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>{DEV_VERSION}</string>
<key>LSMinimumSystemVersion</key>
<string>10.6</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>OpenRA Server</string>
<key>CFBundleURLSchemes</key>
<array>
<string>openra</string>
</array>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>OpenRA Replay</string>
<key>UTTypeIconFile</key>
<string>OpenRA.icns</string>
<key>UTTypeIdentifier</key>
<string>net.openra.replay</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>orarep</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
all: OpenRA launchgame

launcher: all
mkdir -p OpenRA.app/Contents/MacOS
mkdir -p OpenRA.app/Contents/Resources
mv OpenRA launchgame OpenRA.app/Contents/MacOS
echo "APPL????" > OpenRA.app/Contents/PkgInfo
cp Info.plist OpenRA.app/Contents
cp OpenRA.icns fonts.conf dependencies/* OpenRA.app/Contents/Resources
ln -s /Library/Frameworks/Mono.framework/Libraries/libgdiplus.dylib OpenRA.app/Contents/Resources/libgdiplus.dylib
zip launcher -r -9 OpenRA.app --quiet --symlinks
rm -rf OpenRA.app

OpenRA: OpenRA.m
clang -m32 OpenRA.m -o OpenRA -framework AppKit -mmacosx-version-min=10.6

launchgame: launchgame.m
clang -m32 launchgame.m -o launchgame -framework AppKit -mmacosx-version-min=10.6

clean:
rm OpenRA launchgame
rm -rf OpenRA.app
Binary file added OpenRA.icns
Binary file not shown.
220 changes: 220 additions & 0 deletions OpenRA.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* Copyright 2007-2015 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 COPYING.
*/

#import <Cocoa/Cocoa.h>

#define RET_MONO_NOT_FOUND 131
#define RET_MONO_INIT_ERROR 132
#define RET_MONO_VERSION_OUTDATED 133
#define RET_OPENRA_RESTARTING 1

@interface ORALauncher : NSObject <NSApplicationDelegate>
- (void)launchGameWithArgs: (NSArray *)gameArgs;
@end

@implementation ORALauncher

BOOL launched = NO;
NSTask *gameTask;

- (void)showMonoPromptWithMinimumVersion: (NSString *)monoMinVersion
{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Cannot launch OpenRA"];
NSString *msg = [NSString stringWithFormat: @"OpenRA requires Mono %@ or later. Please install the Mono MDK package and try again.", monoMinVersion];
[alert setInformativeText:msg];
[alert addButtonWithTitle:@"Download Mono"];
[alert addButtonWithTitle:@"Quit"];
NSInteger answer = [alert runModal];
[alert release];

if (answer == NSAlertFirstButtonReturn)
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:@"http://www.mono-project.com/download/"]];
}

- (void)showCrashPrompt
{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Fatal Error"];
[alert setInformativeText:@"OpenRA has encountered a fatal error and must close.\nPlease refer to the crash logs and FAQ for more information."];
[alert addButtonWithTitle:@"View Logs"];
[alert addButtonWithTitle:@"View FAQ"];
[alert addButtonWithTitle:@"Quit"];

NSInteger answer = [alert runModal];
[alert release];

if (answer == NSAlertFirstButtonReturn)
{
NSString *logDir = [@"~/Library/Application Support/OpenRA/Logs/" stringByExpandingTildeInPath];
NSString *logFile = [logDir stringByAppendingPathComponent: @"exception.log"];
[[NSWorkspace sharedWorkspace] selectFile: logFile inFileViewerRootedAtPath: logDir];
}
else if (answer == NSAlertSecondButtonReturn)
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:@"http://wiki.openra.net/FAQ"]];
}

// Application was launched via a file association
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
NSArray *gameArgs = [NSArray array];
if ([[filename pathExtension] isEqualToString:@"orarep"])
gameArgs = [NSArray arrayWithObject: [NSString stringWithFormat: @"Launch.Replay=%@", filename]];

[self launchGameWithArgs: gameArgs];

return YES;
}

// Application was launched via a URL handler
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSArray *gameArgs = [NSArray array];

NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
if ([url hasPrefix:@"openra://"])
{
NSString *trimmed = [url substringFromIndex:9];
NSArray *parts = [trimmed componentsSeparatedByString:@":"];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];

if ([parts count] == 2 && [formatter numberFromString: [parts objectAtIndex:1]] != nil)
gameArgs = [NSArray arrayWithObject: [NSString stringWithFormat: @"Launch.Connect=%@", trimmed]];

[formatter release];
}

[self launchGameWithArgs: gameArgs];
}

- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
// Register for url and file events
LSSetDefaultHandlerForURLScheme((CFStringRef)@"openra", (CFStringRef)@"net.openra.launcher");
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self launchGameWithArgs: [NSArray array]];
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)theApplication
{
return YES;
}

- (void)launchGameWithArgs: (NSArray *)gameArgs
{
if (launched)
{
NSLog(@"launchgame is already running... ignoring request.");
return;
}

launched = YES;

// Default values - can be overriden by setting MonoMinVersion and MonoGameExe in Info.plist
NSString *gameName = @"OpenRA.Game.exe";

NSDictionary *plist = [[NSBundle mainBundle] infoDictionary];
if (plist)
{
NSString *exeValue = [plist objectForKey:@"MonoGameExe"];
if (exeValue && [exeValue length] > 0)
gameName = exeValue;
}

NSString *exePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/MacOS/"];
NSString *gamePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/Resources/"];

NSString *launchPath = [exePath stringByAppendingPathComponent: @"launchgame"];
NSMutableArray *launchArgs = [NSMutableArray arrayWithCapacity: [gameArgs count] + 2];
[launchArgs addObject: @"--debug"];
[launchArgs addObject: [gamePath stringByAppendingPathComponent: gameName]];
[launchArgs addObjectsFromArray: gameArgs];

NSLog(@"Running launchgame with arguments:");
for (size_t i = 0; i < [launchArgs count]; i++)
NSLog(@"%@", [launchArgs objectAtIndex: i]);

gameTask = [[NSTask alloc] init];
[gameTask setCurrentDirectoryPath: gamePath];
[gameTask setLaunchPath: launchPath];
[gameTask setArguments: launchArgs];

[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(taskExited:)
name: NSTaskDidTerminateNotification
object: gameTask
];

[gameTask launch];
}

- (void)taskExited:(NSNotification *)note
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:NSTaskDidTerminateNotification
object:gameTask
];

int ret = [gameTask terminationStatus];

NSLog(@"launchgame exited with code %d", ret);
[gameTask release];
gameTask = nil;

// We're done here
if (ret == 0)
exit(0);

// Make the error dialog visible
[NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];

if (ret == RET_MONO_NOT_FOUND || ret == RET_MONO_INIT_ERROR || ret == RET_MONO_VERSION_OUTDATED)
{
NSString *monoMinVersion = @"3.2";
NSDictionary *plist = [[NSBundle mainBundle] infoDictionary];
if (plist)
{
NSString *versionValue = [plist objectForKey:@"MonoMinVersion"];
if (versionValue && [versionValue length] > 0)
monoMinVersion = versionValue;
}

[self showMonoPromptWithMinimumVersion: monoMinVersion];
}
else if (ret != RET_OPENRA_RESTARTING)
{
[self showCrashPrompt];
}

exit(1);
}

@end

int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSApplication *application = [NSApplication sharedApplication];
ORALauncher *launcher = [[ORALauncher alloc] init];
[NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited];

[application setDelegate:launcher];
[application run];

[launcher release];
[pool drain];

return EXIT_SUCCESS;
}
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This repository holds the native OSX components of OpenRA.

After updating the launcher code or dependencies you must:

1. Use `make launcher` to build a zip containing the launcher app template.
2. Upload the template as a new release.
3. Update `packaging/osx/buildpackage.sh` in the main OpenRA repository to use the new release package.
3 changes: 3 additions & 0 deletions dependencies/Eluant.dll.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<configuration>
<dllmap os="osx" dll="lua51.dll" target="liblua.5.1.dylib" />
</configuration>
Binary file added dependencies/libSDL2.dylib
Binary file not shown.
Binary file added dependencies/liblua.5.1.dylib
Binary file not shown.
4 changes: 4 additions & 0 deletions fonts.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- dummy fonts.conf file that removed unwanted system overhead -->
<fontconfig/>
Loading

0 comments on commit 60ccb98

Please sign in to comment.