Line 0
Link Here
|
|
|
1 |
#include <Cocoa/Cocoa.h> |
2 |
#include <JavaVM/jni.h> |
3 |
#include <dlfcn.h> |
4 |
#include <pthread.h> |
5 |
|
6 |
#define DEBUG_TRACE 1 |
7 |
#define TRACE(fmt, ...) \ |
8 |
do { if (DEBUG_TRACE) fprintf(err, "%s:%d:%s(): " fmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__); fflush(err); } while (0) |
9 |
|
10 |
// JNI_CreateJavaVM |
11 |
typedef jint (JNICALL CREATEVM)(JavaVM **pvm, void **env, void *args); |
12 |
|
13 |
void die(JNIEnv *env); |
14 |
|
15 |
@interface AppDelegate : NSObject <NSApplicationDelegate> |
16 |
|
17 |
@end |
18 |
|
19 |
FILE *err = NULL; |
20 |
JavaVM *jvm = NULL; |
21 |
|
22 |
static const char *JNI_CREATEJAVAVM = "JNI_CreateJavaVM"; |
23 |
void *jvm_lib = NULL; |
24 |
|
25 |
void *create_vm(const char *jvm_lib_path) |
26 |
{ |
27 |
void *sym = NULL; |
28 |
jvm_lib = dlopen(jvm_lib_path, RTLD_LAZY | RTLD_GLOBAL); |
29 |
if (jvm_lib) { |
30 |
TRACE("Found libjli.dylib%s", ""); |
31 |
sym = dlsym(jvm_lib, JNI_CREATEJAVAVM); |
32 |
} else { |
33 |
TRACE("Unable to find libjli.dylib%s", ""); |
34 |
} |
35 |
return sym; |
36 |
} |
37 |
|
38 |
static void *launchJava(void *ptr) |
39 |
{ |
40 |
int k = 0; |
41 |
|
42 |
JNIEnv *env = NULL; |
43 |
JNINativeMethod nm_activity[20]; |
44 |
jint res; |
45 |
jclass cls; |
46 |
jmethodID mid; |
47 |
jobject gui; |
48 |
jthrowable ex; |
49 |
// JDK > 1.5 |
50 |
JavaVMInitArgs vm_args; |
51 |
|
52 |
vm_args.nOptions = 3; |
53 |
JavaVMOption options[vm_args.nOptions]; |
54 |
options[0].optionString = "-Djava.class.path=.:../../../gluegen/build/gluegen-rt.jar:../../build/jar/jogl-all.jar"; |
55 |
// options[1].optionString = "-Djava.library.path=lib"; |
56 |
options[1].optionString = "-Dnativewindow.debug=all"; |
57 |
options[2].optionString = "-Djogl.debug=all"; |
58 |
|
59 |
vm_args.version = JNI_VERSION_1_4; |
60 |
vm_args.options = options; |
61 |
vm_args.ignoreUnrecognized = JNI_TRUE; |
62 |
|
63 |
/* Create the Java VM */ |
64 |
CREATEVM *CreateVM = create_vm((char *)ptr); |
65 |
TRACE("CreateVM:%lx env:%lx vm_args:%lx", (long unsigned int)CreateVM, (long unsigned int)&env, (long unsigned int)&vm_args); |
66 |
res = CreateVM(&jvm, (void**)&env, &vm_args); |
67 |
if (res < 0) { |
68 |
TRACE("Can't create Java VM%s", ""); |
69 |
exit(1); |
70 |
} else { |
71 |
TRACE("VM Created%s", ""); |
72 |
} |
73 |
|
74 |
cls = (*env)->FindClass(env, "Bug1398macOSContextOpsOnMainThread"); |
75 |
ex = (*env)->ExceptionOccurred(env); |
76 |
if (ex) { |
77 |
die(env); |
78 |
} |
79 |
|
80 |
mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); |
81 |
if (mid == NULL) |
82 |
goto destroy; |
83 |
|
84 |
gui = (*env)->NewObject(env, cls, mid); |
85 |
TRACE("Just passed NewObject()...%s", ""); |
86 |
|
87 |
destroy: |
88 |
if ((*env)->ExceptionOccurred(env)) { |
89 |
// handle exception |
90 |
} |
91 |
|
92 |
if (err) |
93 |
fclose(err); |
94 |
|
95 |
if (jvm_lib) { |
96 |
dlclose(jvm_lib); |
97 |
jvm_lib = NULL; |
98 |
} |
99 |
|
100 |
die(env); |
101 |
|
102 |
return 0; |
103 |
} |
104 |
|
105 |
void show_error_dialog(JNIEnv *env, jthrowable ex) |
106 |
{ |
107 |
jclass dialogClass = (*env)->FindClass(env, "javax/swing/JOptionPane"); |
108 |
jmethodID showMsg = (*env)->GetStaticMethodID(env, dialogClass, "showMessageDialog", "(Ljava/awt/Component;Ljava/lang/Object;Ljava/lang/String;I)V"); |
109 |
|
110 |
jstring msg = (*env)->NewStringUTF(env, "\nWe be dead...\n\n"); |
111 |
|
112 |
// extract message from exception |
113 |
jclass stringClass = (*env)->FindClass(env, "java/lang/String"); |
114 |
jclass exClass = (*env)->GetObjectClass(env, ex); |
115 |
jmethodID exGetMessage = (*env)->GetMethodID(env, exClass, "getMessage", "()Ljava/lang/String;"); |
116 |
jmethodID concat = (*env)->GetMethodID(env, stringClass, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); |
117 |
jstring exMsg = (*env)->CallObjectMethod(env, ex, exGetMessage); |
118 |
msg = (*env)->CallObjectMethod(env, msg, concat, exMsg); // append exception message to msg |
119 |
|
120 |
jstring title = (*env)->NewStringUTF(env, "Error"); |
121 |
(*env)->CallStaticVoidMethod(env, dialogClass, showMsg, NULL, msg, title, (jint)0); |
122 |
} |
123 |
|
124 |
void die(JNIEnv *env) |
125 |
{ |
126 |
TRACE("\n*\n*\n*\ndieing...\n%s", ""); |
127 |
|
128 |
jthrowable ex = (*env)->ExceptionOccurred(env); |
129 |
if (ex) { |
130 |
(*env)->ExceptionDescribe(env); |
131 |
show_error_dialog(env, ex); |
132 |
} |
133 |
|
134 |
// DestroyJavaVM hangs on Windows so just exit for now |
135 |
#ifndef WIN32 |
136 |
(*jvm)->DestroyJavaVM(jvm); |
137 |
#else |
138 |
if (jvm_lib) |
139 |
FreeLibrary(jvm_lib); |
140 |
if (c_lib) |
141 |
FreeLibrary(c_lib); |
142 |
#endif |
143 |
TRACE("VM = DEAD!%s\n", ""); |
144 |
exit(0); |
145 |
} |
146 |
|
147 |
void create_jvm_thread(const char *jvm_lib_path) |
148 |
{ |
149 |
pthread_t vmthread; |
150 |
|
151 |
struct rlimit limit; |
152 |
size_t stack_size = 0; |
153 |
int rc = getrlimit(RLIMIT_STACK, &limit); |
154 |
|
155 |
if (rc == 0) { |
156 |
if (limit.rlim_cur != 0LL) { |
157 |
stack_size = (size_t)limit.rlim_cur; |
158 |
} |
159 |
} |
160 |
|
161 |
pthread_attr_t thread_attr; |
162 |
pthread_attr_init(&thread_attr); |
163 |
pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM); |
164 |
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); |
165 |
if (stack_size > 0) { |
166 |
pthread_attr_setstacksize(&thread_attr, stack_size); |
167 |
} |
168 |
|
169 |
pthread_create(&vmthread, &thread_attr, launchJava, (void *)jvm_lib_path); |
170 |
pthread_attr_destroy(&thread_attr); |
171 |
} |
172 |
|
173 |
static AppDelegate* _appDelegate; |
174 |
|
175 |
int main(int argc, const char *argv[]) |
176 |
{ |
177 |
err = stderr; |
178 |
|
179 |
for (int k = 1; k < argc; k++) { |
180 |
TRACE("argv[%d]:%s", k, argv[k]); |
181 |
} |
182 |
if (argc < 2) { |
183 |
TRACE("Usage: Bug1398macOSContextOpsOnMainThread %s", "[libjli.dylib path]"); |
184 |
exit(1); |
185 |
} |
186 |
@autoreleasepool |
187 |
{ |
188 |
_appDelegate = [AppDelegate new]; |
189 |
[NSApplication sharedApplication]; |
190 |
[NSApp activateIgnoringOtherApps:YES]; |
191 |
[NSApp setDelegate:_appDelegate]; |
192 |
|
193 |
create_jvm_thread(argv[1]); |
194 |
|
195 |
return NSApplicationMain(argc, (const char **)argv); |
196 |
} |
197 |
} |
198 |
|
199 |
|
200 |
@interface AppDelegate () |
201 |
|
202 |
@property (strong) IBOutlet NSWindow *window; |
203 |
|
204 |
@end |
205 |
|
206 |
@implementation AppDelegate |
207 |
|
208 |
-(id) init |
209 |
{ |
210 |
self = [super init]; |
211 |
NSLog(@"init"); |
212 |
return self; |
213 |
} |
214 |
|
215 |
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { |
216 |
|
217 |
NSLog(@"App starting..."); |
218 |
|
219 |
//Create a new Block Operation and add it to the Operation Queue |
220 |
NSOperationQueue *operationQueue = [NSOperationQueue new]; |
221 |
|
222 |
NSBlockOperation *startUpCompletionOperation = [NSBlockOperation blockOperationWithBlock:^{ |
223 |
//The startup Object has been loaded now close the splash screen |
224 |
//This the completion block operation |
225 |
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ |
226 |
NSLog(@"startUpCompletionOperation main thread? ANS - %@",[NSThread isMainThread]? @"YES":@"NO"); |
227 |
// launchJava((void *)"jre/lib/jli/libjli.dylib"); |
228 |
}]; |
229 |
}]; |
230 |
|
231 |
NSBlockOperation *startUpOperation = [NSBlockOperation blockOperationWithBlock:^{ |
232 |
// wait for everything to load and JVM to power up |
233 |
sleep(3); // wait for a bit for NewObject to complete |
234 |
}]; |
235 |
|
236 |
[startUpCompletionOperation addDependency:startUpOperation]; |
237 |
[operationQueue addOperation:startUpCompletionOperation]; |
238 |
[operationQueue addOperation:startUpOperation]; |
239 |
} |
240 |
|
241 |
@end |