open-source the new Mac launcher

This commit is contained in:
Dmitry Jemerov
2012-11-28 12:40:04 +01:00
parent fb3e6d7a29
commit 5f89cced90
22 changed files with 966 additions and 0 deletions

1
native/MacLauncher/.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
MacLauncher

11
native/MacLauncher/.idea/AppLauncher.iml generated Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CIDR_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="max" />
</component>

5
native/MacLauncher/.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

5
native/MacLauncher/.idea/find.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="OCFindUsagesOptions" text="true" ivars="false" properties="true" derivedClasses="false" />
</project>

8
native/MacLauncher/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectResources">
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
</component>
<component name="ProjectRootManager" version="2" />
</project>

9
native/MacLauncher/.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/AppLauncher.iml" filepath="$PROJECT_DIR$/.idea/AppLauncher.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,5 @@
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>

7
native/MacLauncher/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

5
native/MacLauncher/.idea/xcode.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="XcodeMetaData" PROJECT_FILE="$PROJECT_DIR$/MacLauncher.xcodeproj" />
</project>

View File

@@ -0,0 +1,72 @@
<?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>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>JetBrains.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>Java</key>
<dict>
<key>ClassPath</key>
<string>$APP_PACKAGE</string>
<key>MainClass</key>
<string>com.intellij.idea.Main</string>
<key>Properties</key>
<dict>
<key>CVS_PASSFILE</key>
<string>~/.cvspass</string>
<key>apple.laf.useScreenMenuBar</key>
<string>true</string>
<key>com.apple.mrj.application.live-resize</key>
<string>false</string>
<key>idea.config.path</key>
<string>~/Library/Preferences/IntelliJIdea10CE/</string>
<key>idea.is.internal</key>
<string>true</string>
<key>idea.log.path</key>
<string>~/Library/Logs/IntelliJIdea10CE/</string>
<key>idea.platform.prefix</key>
<string>Idea</string>
<key>idea.plugins.path</key>
<string>~/Library/Application Support/IntelliJIdea10CE/</string>
<key>idea.system.path</key>
<string>~/Library/Caches/IntelliJIdea10CE/</string>
<key>idea.use.default.antialiasing.in.editor</key>
<string>true</string>
</dict>
<key>VMOptions</key>
<string>-ea</string>
<key>VMOptions.i386</key>
<string>-Xms128m -Xmx512m -XX:MaxPermSize=250m</string>
<key>VMOptions.x86_64</key>
<string>-Xms128m -Xmx800m -XX:MaxPermSize=350m -XX:+UseCompressedOops -XX:ReservedCodeCacheSize=256m</string>
<key>WorkingDirectory</key>
<string>$APP_PACKAGE/bin</string>
</dict>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2012 JetBrains inc. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@@ -0,0 +1,17 @@
//
// Created by max on 5/4/12.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import <Foundation/Foundation.h>
#import <JavaVM/jni.h>
@interface Launcher : NSObject
- (id)initWithArgc:(int)anArgc argv:(char **)anArgv;
- (void) launch;
@end

View File

@@ -0,0 +1,374 @@
//
// Created by max on 5/4/12.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import "Launcher.h"
#import "VMOptionsReader.h"
#import "PropertyFileReader.h"
#import "utils.h"
#import <dlfcn.h>
typedef jint (JNICALL *fun_ptr_t_CreateJavaVM)(JavaVM **pvm, void **env, void *args);
@implementation NSString (CustomReplacements)
- (NSString *)replaceAll:(NSString *)pattern to:(NSString *)replacement {
if ([self rangeOfString:pattern].length == 0) return self;
NSMutableString *answer = [self mutableCopy];
[answer replaceOccurrencesOfString:pattern withString:replacement options:0 range:NSMakeRange(0, [self length])];
return answer;
}
@end
@implementation NSDictionary (TypedGetters)
- (NSDictionary *)dictionaryForKey:(id)key {
id answer = [self objectForKey:key];
if ([answer isKindOfClass:[NSDictionary class]]) {
return answer;
}
return nil;
}
- (id)valueForKey:(NSString *)key inDictionary:(NSString *)dictKey default: (NSString*) defaultValue {
NSDictionary *dict = [self dictionaryForKey:dictKey];
if (dict == nil) return nil;
id answer = [dict valueForKey:key];
return answer != nil ? answer : defaultValue;
}
@end
@implementation Launcher {
int argc;
char **argv;
}
- (id)initWithArgc:(int)anArgc argv:(char **)anArgv {
self = [super init];
if (self) {
argc = anArgc;
argv = anArgv;
}
return self;
}
void appendJvmBundlesAt(NSString *path, NSMutableArray *sink) {
NSError *error;
NSArray *names = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
if (!error) {
for (NSString *name in names) {
if ([name hasSuffix:@".jdk"] || [name hasSuffix:@".jre"]) {
NSBundle *bundle = [NSBundle bundleWithPath:[path stringByAppendingPathComponent:name]];
if (bundle != nil) {
[sink addObject:bundle];
}
}
}
}
}
NSArray *allVms() {
NSMutableArray *jvmBundlePaths = [NSMutableArray array];
NSString *explicit = [[[NSProcessInfo processInfo] environment] objectForKey:@"IDEA_JDK"];
if (explicit != nil) {
appendJvmBundlesAt(explicit, jvmBundlePaths);
}
else {
NSBundle *bundle = [NSBundle mainBundle];
NSString *appDir = bundle.bundlePath;
appendJvmBundlesAt([appDir stringByAppendingPathComponent:@"jre"], jvmBundlePaths);
if (jvmBundlePaths.count > 0) return jvmBundlePaths;
appendJvmBundlesAt([NSHomeDirectory() stringByAppendingPathComponent:@"Library/Java/JavaVirtualMachines"], jvmBundlePaths);
appendJvmBundlesAt(@"/Library/Java/JavaVirtualMachines", jvmBundlePaths);
appendJvmBundlesAt(@"/System/Library/Java/JavaVirtualMachines", jvmBundlePaths);
}
return jvmBundlePaths;
}
NSString *jvmVersion(NSBundle *bundle) {
return [bundle.infoDictionary valueForKey:@"JVMVersion" inDictionary:@"JavaVM" default: @"0"];
}
NSString *requiredJvmVersion() {
return [[NSBundle mainBundle].infoDictionary valueForKey:@"JVMVersion" inDictionary:@"Java" default: @"1.7*"];
}
BOOL satisfies(NSString *vmVersion, NSString *requiredVersion) {
if ([requiredVersion hasSuffix:@"+"]) {
requiredVersion = [requiredVersion substringToIndex:[requiredVersion length] - 1];
return [requiredVersion compare:vmVersion options:NSNumericSearch] <= 0;
}
if ([requiredVersion hasSuffix:@"*"]) {
requiredVersion = [requiredVersion substringToIndex:[requiredVersion length] - 1];
}
return [vmVersion hasPrefix:requiredVersion];
}
NSBundle *findMatchingVm() {
NSArray *vmBundles = [allVms() sortedArrayUsingComparator:^NSComparisonResult(id b1, id b2) {
return [jvmVersion(b2) compare:jvmVersion(b1) options:NSNumericSearch];
}];
if (isDebugEnabled()) {
debugLog(@"Found Java Virtual Machines:");
for (NSBundle *vm in vmBundles) {
debugLog([vm bundlePath]);
}
}
NSString *required = requiredJvmVersion();
debugLog([NSString stringWithFormat:@"Required VM: %@", required]);
for (NSBundle *vm in vmBundles) {
if (satisfies(jvmVersion(vm), required)) {
debugLog(@"Chosen VM:");
debugLog([vm bundlePath]);
return vm;
}
}
debugLog(@"No matching VM found");
return nil;
}
CFBundleRef NSBundle2CFBundle(NSBundle *bundle) {
CFURLRef bundleURL = (__bridge CFURLRef) bundle.bundleURL;
return CFBundleCreate(kCFAllocatorDefault, bundleURL);
}
- (NSString *)expandMacros:(NSString *)str {
return [[str
replaceAll:@"$APP_PACKAGE" to:[[NSBundle mainBundle] bundlePath]]
replaceAll:@"$USER_HOME" to:NSHomeDirectory()];
}
- (NSMutableString *)buildClasspath:(NSBundle *)jvm {
NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"];
NSMutableString *classpathOption = [NSMutableString stringWithString:@"-Djava.class.path="];
[classpathOption appendString:[jvmInfo objectForKey:@"ClassPath"]];
NSString *toolsJar = [[jvm bundlePath] stringByAppendingString:@"/Contents/Home/lib/tools.jar"];
if ([[NSFileManager defaultManager] fileExistsAtPath:toolsJar]) {
[classpathOption appendString:@":"];
[classpathOption appendString:toolsJar];
}
return classpathOption;
}
NSString *getSelector() {
NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"];
NSDictionary *properties = [jvmInfo dictionaryForKey:@"Properties"];
if (properties != nil) {
return [properties objectForKey:@"idea.paths.selector"];
}
return nil;
}
NSString *getPreferencesFolderPath() {
return [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), getSelector()];
}
NSString *getPropertiesFilePath() {
return [getPreferencesFolderPath() stringByAppendingString:@"/idea.properites"];
}
NSString *getDefaultPropertiesFilePath() {
return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/bin/idea.properties"];
}
NSString *getDefaultVMOptionsFilePath() {
return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/bin/idea.vmoptions"];
}
NSString *getVMOptionsFilePath() {
return [getPreferencesFolderPath() stringByAppendingString:@"/idea.vmoptions"];
}
NSArray *parseVMOptions() {
NSArray *inConfig=[VMOptionsReader readFile:getVMOptionsFilePath()];
if (inConfig) return inConfig;
return [VMOptionsReader readFile:getDefaultVMOptionsFilePath()];
}
NSDictionary *parseProperties() {
NSDictionary *inConfig = [PropertyFileReader readFile:getPropertiesFilePath()];
if (inConfig) return inConfig;
return [PropertyFileReader readFile:getDefaultPropertiesFilePath()];
}
- (JavaVMInitArgs)buildArgsFor:(NSBundle *)jvm {
NSMutableString *classpathOption = [self buildClasspath:jvm];
NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"];
NSMutableArray *args_array = [NSMutableArray array];
[args_array addObject:classpathOption];
[args_array addObjectsFromArray:[[jvmInfo objectForKey:@"VMOptions"] componentsSeparatedByString:@" "]];
[args_array addObjectsFromArray:parseVMOptions()];
void (^propertySink)(id,id,BOOL *)=^(id key, id obj, BOOL *stop) {
[args_array addObject:[NSString stringWithFormat:@"-D%@=%@", key, obj]];
};
NSDictionary *properties = [jvmInfo dictionaryForKey:@"Properties"];
if (properties != nil) {
[properties enumerateKeysAndObjectsUsingBlock:propertySink];
}
[parseProperties() enumerateKeysAndObjectsUsingBlock:propertySink];
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.ignoreUnrecognized = JNI_TRUE;
args.nOptions = [args_array count];
args.options = calloc((size_t) args.nOptions, sizeof(JavaVMOption));
[args_array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
args.options[idx].optionString = strdup([[self expandMacros:[obj description]] UTF8String]);
}];
return args;
}
- (const char *)mainClassName {
NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"];
char *answer = strdup([[jvmInfo objectForKey:@"MainClass"] UTF8String]);
char *cur = answer;
while (*cur) {
if (*cur == '.') {
*cur = '/';
}
cur++;
}
return answer;
}
- (void)process_cwd {
NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"];
NSString *cwd = [jvmInfo objectForKey:@"WorkingDirectory"];
if (cwd != nil) {
cwd = [self expandMacros:cwd];
if (chdir([cwd UTF8String]) != 0) {
NSLog(@"Cannot chdir to working directory at %@", cwd);
}
}
}
- (void)launch {
NSBundle *vm = findMatchingVm();
if (vm == nil) {
NSString *old_launcher = [self expandMacros:@"$APP_PACKAGE/Contents/MacOS/idea_appLauncher"];
execv([old_launcher fileSystemRepresentation], self->argv);
NSLog(@"Cannot find matching VM, aborting");
exit(-1);
}
NSError *error;
BOOL ok = [vm loadAndReturnError:&error];
if (!ok || error != nil) {
NSLog(@"Cannot load JVM bundle: %@", error);
exit(-1);
}
CFBundleRef cfvm = NSBundle2CFBundle(vm);
fun_ptr_t_CreateJavaVM create_vm = CFBundleGetFunctionPointerForName(cfvm, CFSTR("JNI_CreateJavaVM"));
if (create_vm == NULL) {
// We have Apple VM chosen here...
/*
[self execCommandLineJava:vm];
return;
*/
NSString *serverLibUrl = [vm.bundlePath stringByAppendingPathComponent:@"Contents/Libraries/libserver.dylib"];
void *libHandle = dlopen(serverLibUrl.UTF8String, RTLD_NOW + RTLD_GLOBAL);
if (libHandle) {
create_vm = dlsym(libHandle, "JNI_CreateJavaVM_Impl");
}
}
if (create_vm == NULL) {
NSLog(@"Cannot find JNI_CreateJavaVM in chosen JVM bundle at %@", vm.bundlePath);
exit(-1);
}
[self process_cwd];
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs args = [self buildArgsFor:vm];
jint create_vm_rc = create_vm(&jvm, &env, &args);
if (create_vm_rc != JNI_OK || jvm == NULL) {
NSLog(@"JNI_CreateJavaVM (%@) failed: %d", vm.bundlePath, create_vm_rc);
exit(-1);
}
jclass string_class = (*env)->FindClass(env, "java/lang/String");
if (string_class == NULL) {
NSLog(@"No java.lang.String in classpath!");
exit(-1);
}
const char *mainClassName = [self mainClassName];
jclass mainClass = (*env)->FindClass(env, mainClassName);
if (mainClass == NULL || (*env)->ExceptionOccurred(env)) {
NSLog(@"Main class %s not found", mainClassName);
(*env)->ExceptionDescribe(env);
exit(-1);
}
jmethodID mainMethod = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V");
if (mainMethod == NULL || (*env)->ExceptionOccurred(env)) {
NSLog(@"Cant't find main() method");
(*env)->ExceptionDescribe(env);
exit(-1);
}
// See http://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder
// about psn_ stuff
int arg_count = 0;
for (int i = 1; i < argc; i++) {
if (memcmp(argv[i], "-psn_", 4) != 0) arg_count++;
}
jobject jni_args = (*env)->NewObjectArray(env, arg_count, string_class, NULL);
arg_count = 0;
for (int i = 1; i < argc; i++) {
if (memcmp(argv[i], "-psn_", 4) != 0) {
jstring jni_arg = (*env)->NewStringUTF(env, argv[i]);
(*env)->SetObjectArrayElement(env, jni_args, arg_count, jni_arg);
arg_count++;
}
}
(*env)->CallStaticVoidMethod(env, mainClass, mainMethod, jni_args);
(*jvm)->DetachCurrentThread(jvm);
(*jvm)->DestroyJavaVM(jvm);
}
@end

View File

@@ -0,0 +1,7 @@
//
// Prefix header for all source files of the 'Launcher' target in the 'Launcher' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

View File

@@ -0,0 +1,257 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1A5645DB6F789D018FF4A4AF /* PropertyFileReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A5645FEAD4A0FF166644D97 /* PropertyFileReader.m */; };
1A564BCFE66693BF0B2DD4A9 /* VMOptionsReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EDDE28564EF1AEBCD13 /* VMOptionsReader.m */; };
1A564C27F0BA05F900F34907 /* utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EEF77B93DBD7FD23161 /* utils.m */; };
50E17738155444B900E97451 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50E17737155444B900E97451 /* Cocoa.framework */; };
50E1775715552D2900E97451 /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0B58A123544A15DA59B13E3 /* JavaVM.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
C0B58A123544A15DA59B13E4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0B58A123544A15DA59B13DC /* main.m */; };
C0B58A123544A15DA59B13E5 /* Launcher.m in Sources */ = {isa = PBXBuildFile; fileRef = C0B58A123544A15DA59B13E0 /* Launcher.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
1A5645FEAD4A0FF166644D97 /* PropertyFileReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PropertyFileReader.m; sourceTree = "<group>"; };
1A564A1031F4C91C464C1B75 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
1A564D7CEEAA02F14A6D4F20 /* VMOptionsReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMOptionsReader.h; sourceTree = "<group>"; };
1A564EDDE28564EF1AEBCD13 /* VMOptionsReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VMOptionsReader.m; sourceTree = "<group>"; };
1A564EEF77B93DBD7FD23161 /* utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utils.m; sourceTree = "<group>"; };
1A564F6D5833A0B9CE6E2839 /* PropertyFileReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyFileReader.h; sourceTree = "<group>"; };
50E17735155444B900E97451 /* Launcher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Launcher.app; sourceTree = BUILT_PRODUCTS_DIR; };
50E17737155444B900E97451 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
50E1773F155444B900E97451 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50E17745155444B900E97451 /* Launcher.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Launcher.pch; sourceTree = "<group>"; };
C0B58A123544A15DA59B13DC /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
C0B58A123544A15DA59B13DE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
C0B58A123544A15DA59B13E0 /* Launcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Launcher.m; sourceTree = "<group>"; };
C0B58A123544A15DA59B13E2 /* Launcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Launcher.h; sourceTree = "<group>"; };
C0B58A123544A15DA59B13E3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = System/Library/Frameworks/JavaVM.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50E17732155444B900E97451 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
50E1775715552D2900E97451 /* JavaVM.framework in Frameworks */,
50E17738155444B900E97451 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C0B58A123544A15DA59B13CA = {
isa = PBXGroup;
children = (
C0B58A123544A15DA59B13DC /* main.m */,
C0B58A123544A15DA59B13E0 /* Launcher.m */,
C0B58A123544A15DA59B13E2 /* Launcher.h */,
50E17745155444B900E97451 /* Launcher.pch */,
50E1773F155444B900E97451 /* Info.plist */,
C0B58A123544A15DA59B13CB /* Products */,
C0B58A123544A15DA59B13D6 /* Frameworks */,
1A5645FEAD4A0FF166644D97 /* PropertyFileReader.m */,
1A564F6D5833A0B9CE6E2839 /* PropertyFileReader.h */,
1A564EDDE28564EF1AEBCD13 /* VMOptionsReader.m */,
1A564D7CEEAA02F14A6D4F20 /* VMOptionsReader.h */,
1A564A1031F4C91C464C1B75 /* utils.h */,
1A564EEF77B93DBD7FD23161 /* utils.m */,
);
sourceTree = "<group>";
};
C0B58A123544A15DA59B13CB /* Products */ = {
isa = PBXGroup;
children = (
50E17735155444B900E97451 /* Launcher.app */,
);
name = Products;
sourceTree = "<group>";
};
C0B58A123544A15DA59B13D6 /* Frameworks */ = {
isa = PBXGroup;
children = (
C0B58A123544A15DA59B13E3 /* JavaVM.framework */,
C0B58A123544A15DA59B13DE /* Foundation.framework */,
50E17737155444B900E97451 /* Cocoa.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50E17734155444B900E97451 /* Launcher */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50E17751155444BA00E97451 /* Build configuration list for PBXNativeTarget "Launcher" */;
buildPhases = (
50E17731155444B900E97451 /* Sources */,
50E17732155444B900E97451 /* Frameworks */,
50E17733155444B900E97451 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Launcher;
productName = Launcher;
productReference = 50E17735155444B900E97451 /* Launcher.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C0B58A123544A15DA59B13C8 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0450;
};
buildConfigurationList = C0B58A123544A15DA59B13C9 /* Build configuration list for PBXProject "MacLauncher" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = C0B58A123544A15DA59B13CA;
productRefGroup = C0B58A123544A15DA59B13CB /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50E17734155444B900E97451 /* Launcher */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
50E17733155444B900E97451 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
50E17731155444B900E97451 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C0B58A123544A15DA59B13E4 /* main.m in Sources */,
C0B58A123544A15DA59B13E5 /* Launcher.m in Sources */,
1A5645DB6F789D018FF4A4AF /* PropertyFileReader.m in Sources */,
1A564BCFE66693BF0B2DD4A9 /* VMOptionsReader.m in Sources */,
1A564C27F0BA05F900F34907 /* utils.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50E1774F155444BA00E97451 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Launcher.pch;
INFOPLIST_FILE = Info.plist;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx10.7;
WRAPPER_EXTENSION = app;
};
name = Release;
};
50E17750155444BA00E97451 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Launcher.pch;
INFOPLIST_FILE = Info.plist;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx10.7;
WRAPPER_EXTENSION = app;
};
name = Debug;
};
C0B58A123544A15DA59B13CC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_OBJC_ARC = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = "";
SDKROOT = macosx;
};
name = Release;
};
C0B58A123544A15DA59B13CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_OBJC_ARC = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = "";
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50E17751155444BA00E97451 /* Build configuration list for PBXNativeTarget "Launcher" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50E1774F155444BA00E97451 /* Release */,
50E17750155444BA00E97451 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C0B58A123544A15DA59B13C9 /* Build configuration list for PBXProject "MacLauncher" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C0B58A123544A15DA59B13CC /* Release */,
C0B58A123544A15DA59B13CD /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C0B58A123544A15DA59B13C8 /* Project object */;
}

View File

@@ -0,0 +1,13 @@
//
// Created by max on 11/6/12.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import <Foundation/Foundation.h>
@interface PropertyFileReader : NSObject
+ (NSDictionary *)readFile:(NSString *)path;
@end

View File

@@ -0,0 +1,45 @@
//
// Created by max on 11/6/12.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import "PropertyFileReader.h"
#import "utils.h"
@implementation PropertyFileReader {
}
+ (NSDictionary *)readFile:(NSString *)path {
NSMutableDictionary *answer = [NSMutableDictionary dictionary];
NSString *contents = readFile(path);
if (contents) {
[contents enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
NSString *trimmedLine = trim(line);
if ([trimmedLine length] > 0) {
if ([trimmedLine characterAtIndex:0] != '#') {
[self parseProperty:trimmedLine to:answer];
}
}
}];
return answer;
}
return nil;
}
+ (void)parseProperty:(NSString *)string to:(NSMutableDictionary *)to {
NSRange delimiter = [string rangeOfString:@"="];
if (delimiter.length > 0 && delimiter.location + 1 <= string.length) {
NSString *key = [string substringToIndex:delimiter.location];
NSString *value=[string substringFromIndex:delimiter.location + 1];
[to setObject:value forKey:key];
}
}
@end

View File

@@ -0,0 +1,13 @@
//
// Created by max on 11/6/12.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import <Foundation/Foundation.h>
@interface VMOptionsReader : NSObject
+ (NSArray *) readFile: (NSString *)path;
@end

View File

@@ -0,0 +1,34 @@
//
// Created by max on 11/6/12.
//
// To change the template use AppCode | Preferences | File Templates.
//
#import "VMOptionsReader.h"
#import "utils.h"
@implementation VMOptionsReader {
}
+ (NSArray *)readFile:(NSString *)path {
NSMutableArray *answer = [NSMutableArray array];
NSString *contents = readFile(path);
if (contents) {
[contents enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
NSString *trimmedLine = trim(line);
if ([trimmedLine length] > 0) {
if ([trimmedLine characterAtIndex:0] != '#') {
[answer addObject:trimmedLine];
}
}
}];
return answer;
}
return nil;
}
@end

40
native/MacLauncher/main.m Normal file
View File

@@ -0,0 +1,40 @@
#import "Launcher.h"
#define FOREVER ((CFTimeInterval) 1e20)
static void timer_empty(CFRunLoopTimerRef timer, void *info) {
}
static void parkRunLoop() {
CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, FOREVER, (CFTimeInterval)0.0, 0, 0, timer_empty, NULL);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
CFRelease(t);
SInt32 result;
do {
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, FOREVER, false);
} while (result != kCFRunLoopRunFinished);
}
static void makeSameStackSize(NSThread *thread) {
struct rlimit l;
int err = getrlimit(RLIMIT_STACK, &l);
if (err == ERR_SUCCESS && l.rlim_cur > 0) {
thread.stackSize = (NSUInteger) l.rlim_cur;
}
}
static void launchInNewThread(Launcher *launcher) {
NSThread *thread = [[NSThread alloc] initWithTarget:launcher selector:@selector(launch) object:nil];
makeSameStackSize(thread);
[thread start];
}
int main(int argc, char *argv[]) {
@autoreleasepool {
launchInNewThread([[Launcher alloc] initWithArgc:argc argv:argv]);
parkRunLoop();
}
return 0;
}

View File

@@ -0,0 +1,5 @@
NSString *readFile(NSString *path);
NSString *trim(NSString *line);
void debugLog(NSString *message);
BOOL isDebugEnabled();

View File

@@ -0,0 +1,30 @@
#include "utils.h"
NSString *readFile(NSString *path) {
NSError *err = nil;
NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&err];
if (contents == nil) {
debugLog([NSString stringWithFormat:@"Reading at %@ failed, Error is: %@", path, err.localizedDescription]);
return nil;
}
debugLog([NSString stringWithFormat: @"Reading at %@ OK", path]);
return contents;
}
NSString *trim(NSString *line) {
return [line stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" \t"]];
}
BOOL isDebugEnabled() {
return getenv("IDEA_LAUNCHER_DEBUG") != NULL;
}
void debugLog(NSString *message) {
if (isDebugEnabled()) {
NSLog(@"%@", message);
}
}