12047
|
1 |
/*
|
|
2 |
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
|
23 |
* questions.
|
|
24 |
*/
|
|
25 |
|
|
26 |
#import <pthread.h>
|
|
27 |
#import <objc/runtime.h>
|
|
28 |
#import <Cocoa/Cocoa.h>
|
|
29 |
#import <Security/AuthSession.h>
|
|
30 |
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
|
31 |
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
|
|
32 |
|
|
33 |
#import "NSApplicationAWT.h"
|
|
34 |
#import "PropertiesUtilities.h"
|
|
35 |
#import "ThreadUtilities.h"
|
|
36 |
#import "AWT_debug.h"
|
|
37 |
#import "ApplicationDelegate.h"
|
|
38 |
|
|
39 |
#define DEBUG 0
|
|
40 |
|
|
41 |
|
|
42 |
// The symbol is defined in libosxapp.dylib (ThreadUtilities.m)
|
|
43 |
extern JavaVM *jvm;
|
|
44 |
|
|
45 |
static bool ShouldPrintVerboseDebugging() {
|
|
46 |
static int debug = -1;
|
|
47 |
if (debug == -1) {
|
|
48 |
debug = (int)(getenv("JAVA_AWT_VERBOSE") != NULL) || (DEBUG != 0);
|
|
49 |
}
|
|
50 |
return (bool)debug;
|
|
51 |
}
|
|
52 |
|
|
53 |
// This is the data necessary to have JNI_OnLoad wait for AppKit to start.
|
|
54 |
static BOOL sAppKitStarted = NO;
|
|
55 |
static pthread_mutex_t sAppKitStarted_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
56 |
static pthread_cond_t sAppKitStarted_cv = PTHREAD_COND_INITIALIZER;
|
|
57 |
|
|
58 |
void setBusy(BOOL isBusy);
|
|
59 |
static void BusyObserver(CFRunLoopObserverRef ref, CFRunLoopActivity what, void* arg);
|
|
60 |
static void NotBusyObserver(CFRunLoopObserverRef ref, CFRunLoopActivity what, void* arg);
|
|
61 |
static void AWT_NSUncaughtExceptionHandler(NSException *exception);
|
|
62 |
|
|
63 |
static CFRunLoopObserverRef busyObserver = NULL;
|
|
64 |
static CFRunLoopObserverRef notBusyObserver = NULL;
|
|
65 |
|
|
66 |
static void setUpAWTAppKit(BOOL swt_mode, BOOL headless) {
|
|
67 |
AWT_ASSERT_APPKIT_THREAD;
|
|
68 |
BOOL verbose = ShouldPrintVerboseDebugging();
|
|
69 |
if (verbose) AWT_DEBUG_LOG(@"setting up busy observers");
|
|
70 |
|
|
71 |
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
|
72 |
|
|
73 |
// Add CFRunLoopObservers to call into AWT so that AWT knows that the
|
|
74 |
// AWT thread (which is the AppKit main thread) is alive. This way AWT
|
|
75 |
// will not automatically shutdown.
|
|
76 |
busyObserver = CFRunLoopObserverCreate(
|
|
77 |
NULL, // CFAllocator
|
|
78 |
kCFRunLoopAfterWaiting, // CFOptionFlags
|
|
79 |
true, // repeats
|
|
80 |
NSIntegerMax, // order
|
|
81 |
&BusyObserver, // CFRunLoopObserverCallBack
|
|
82 |
NULL); // CFRunLoopObserverContext
|
|
83 |
|
|
84 |
notBusyObserver = CFRunLoopObserverCreate(
|
|
85 |
NULL, // CFAllocator
|
|
86 |
kCFRunLoopBeforeWaiting, // CFOptionFlags
|
|
87 |
true, // repeats
|
|
88 |
NSIntegerMin, // order
|
|
89 |
&NotBusyObserver, // CFRunLoopObserverCallBack
|
|
90 |
NULL); // CFRunLoopObserverContext
|
|
91 |
|
|
92 |
CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
|
|
93 |
CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
|
|
94 |
CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
|
|
95 |
|
|
96 |
CFRelease(busyObserver);
|
|
97 |
CFRelease(notBusyObserver);
|
|
98 |
|
|
99 |
if (!headless) setBusy(YES);
|
|
100 |
|
|
101 |
// Set the java name of the AppKit main thread appropriately.
|
|
102 |
jclass threadClass = NULL;
|
|
103 |
jstring name = NULL;
|
|
104 |
jobject curThread = NULL;
|
|
105 |
|
|
106 |
if (!swt_mode) {
|
|
107 |
threadClass = (*env)->FindClass(env, "java/lang/Thread");
|
|
108 |
if (threadClass == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
|
|
109 |
jmethodID currentThreadID = (*env)->GetStaticMethodID(env, threadClass, "currentThread", "()Ljava/lang/Thread;");
|
|
110 |
if (currentThreadID == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
|
|
111 |
jmethodID setName = (*env)->GetMethodID(env, threadClass, "setName", "(Ljava/lang/String;)V");
|
|
112 |
if (setName == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
|
|
113 |
|
|
114 |
curThread = (*env)->CallStaticObjectMethod(env, threadClass, currentThreadID); // AWT_THREADING Safe (known object)
|
|
115 |
if (curThread == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
|
|
116 |
name = (*env)->NewStringUTF(env, "AWT-AppKit");
|
|
117 |
if (name == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
|
|
118 |
(*env)->CallVoidMethod(env, curThread, setName, name); // AWT_THREADING Safe (known object)
|
|
119 |
if ((*env)->ExceptionCheck(env)) goto cleanup;
|
|
120 |
}
|
|
121 |
|
|
122 |
cleanup:
|
|
123 |
if (threadClass != NULL) {
|
|
124 |
(*env)->DeleteLocalRef(env, threadClass);
|
|
125 |
}
|
|
126 |
if (name != NULL) {
|
|
127 |
(*env)->DeleteLocalRef(env, name);
|
|
128 |
}
|
|
129 |
if (curThread != NULL) {
|
|
130 |
(*env)->DeleteLocalRef(env, curThread);
|
|
131 |
}
|
|
132 |
if ((*env)->ExceptionCheck(env)) {
|
|
133 |
(*env)->ExceptionDescribe(env);
|
|
134 |
(*env)->ExceptionClear(env);
|
|
135 |
}
|
|
136 |
|
|
137 |
// Add the exception handler of last resort
|
|
138 |
NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler);
|
|
139 |
|
|
140 |
if (verbose) AWT_DEBUG_LOG(@"finished setting thread name");
|
|
141 |
}
|
|
142 |
|
|
143 |
|
|
144 |
|
|
145 |
// Returns true if java believes it is running headless
|
|
146 |
BOOL isHeadless(JNIEnv *env) {
|
|
147 |
// Just access the property directly, instead of using GraphicsEnvironment.isHeadless.
|
|
148 |
// This is because this may be called while AWT is being loaded, and calling AWT
|
|
149 |
// while it is being loaded will deadlock.
|
|
150 |
static JNF_CLASS_CACHE(jc_Toolkit, "java/awt/GraphicsEnvironment");
|
|
151 |
static JNF_STATIC_MEMBER_CACHE(jm_isHeadless, jc_Toolkit, "isHeadless", "()Z");
|
|
152 |
return JNFCallStaticBooleanMethod(env, jm_isHeadless);
|
|
153 |
}
|
|
154 |
|
|
155 |
BOOL isSWTInWebStart(JNIEnv* env) {
|
|
156 |
NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env];
|
|
157 |
return [@"true" isCaseInsensitiveLike:swtWebStart];
|
|
158 |
}
|
|
159 |
|
|
160 |
void setBusy(BOOL busy) {
|
|
161 |
AWT_ASSERT_APPKIT_THREAD;
|
|
162 |
|
|
163 |
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
|
164 |
static JNF_CLASS_CACHE(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
|
|
165 |
|
|
166 |
if (busy) {
|
|
167 |
static JNF_STATIC_MEMBER_CACHE(jm_notifyBusyMethod, jc_AWTAutoShutdown, "notifyToolkitThreadBusy", "()V");
|
|
168 |
JNFCallStaticVoidMethod(env, jm_notifyBusyMethod);
|
|
169 |
} else {
|
|
170 |
static JNF_STATIC_MEMBER_CACHE(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
|
|
171 |
JNFCallStaticVoidMethod(env, jm_notifyFreeMethod);
|
|
172 |
}
|
|
173 |
}
|
|
174 |
|
|
175 |
static void BusyObserver(CFRunLoopObserverRef ref, CFRunLoopActivity what, void* arg) {
|
|
176 |
AWT_ASSERT_APPKIT_THREAD;
|
|
177 |
|
|
178 |
// This is only called with the selector kCFRunLoopAfterWaiting.
|
|
179 |
#ifndef PRODUCT_BUILD
|
|
180 |
assert(what == kCFRunLoopAfterWaiting);
|
|
181 |
#endif /* PRODUCT_BUILD */
|
|
182 |
|
|
183 |
setBusy(YES);
|
|
184 |
}
|
|
185 |
|
|
186 |
static void NotBusyObserver(CFRunLoopObserverRef ref, CFRunLoopActivity what, void* arg) {
|
|
187 |
AWT_ASSERT_APPKIT_THREAD;
|
|
188 |
|
|
189 |
// This is only called with the selector kCFRunLoopBeforeWaiting.
|
|
190 |
#ifndef PRODUCT_BUILD
|
|
191 |
assert(what == kCFRunLoopBeforeWaiting);
|
|
192 |
#endif /* PRODUCT_BUILD */
|
|
193 |
|
|
194 |
setBusy(NO);
|
|
195 |
}
|
|
196 |
|
|
197 |
static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
|
|
198 |
NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
|
|
199 |
}
|
|
200 |
|
|
201 |
// This is an empty Obj-C object just so that -peformSelectorOnMainThread can be used.
|
|
202 |
@interface AWTStarter : NSObject { }
|
|
203 |
+ (void)start:(BOOL)headless swtMode:(BOOL)swtMode swtModeForWebStart:(BOOL)swtModeForWebStart;
|
|
204 |
- (void)starter:(NSArray*)args;
|
|
205 |
+ (void)appKitIsRunning:(id)arg;
|
|
206 |
@end
|
|
207 |
|
|
208 |
@implementation AWTStarter
|
|
209 |
|
|
210 |
+ (BOOL) isConnectedToWindowServer {
|
|
211 |
SecuritySessionId session_id;
|
|
212 |
SessionAttributeBits session_info;
|
|
213 |
OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info);
|
|
214 |
if (status != noErr) return NO;
|
|
215 |
if (!(session_info & sessionHasGraphicAccess)) return NO;
|
|
216 |
return YES;
|
|
217 |
}
|
|
218 |
|
|
219 |
+ (BOOL) markAppAsDaemon {
|
|
220 |
id jrsAppKitAWTClass = objc_getClass("JRSAppKitAWT");
|
|
221 |
SEL markAppSel = @selector(markAppIsDaemon);
|
|
222 |
if (![jrsAppKitAWTClass respondsToSelector:markAppSel]) return NO;
|
|
223 |
return (BOOL)[jrsAppKitAWTClass performSelector:markAppSel];
|
|
224 |
}
|
|
225 |
|
|
226 |
+ (void)appKitIsRunning:(id)arg {
|
|
227 |
// Headless: NO
|
|
228 |
// Embedded: BOTH
|
|
229 |
// Multiple Calls: NO
|
|
230 |
// Callers: AppKit's NSApplicationDidFinishLaunchingNotification or +[AWTStarter startAWT:]
|
|
231 |
AWT_ASSERT_APPKIT_THREAD;
|
|
232 |
|
|
233 |
BOOL verbose = ShouldPrintVerboseDebugging();
|
|
234 |
if (verbose) AWT_DEBUG_LOG(@"about to message AppKit started");
|
|
235 |
|
|
236 |
// Signal that AppKit has started (or is already running).
|
|
237 |
pthread_mutex_lock(&sAppKitStarted_mutex);
|
|
238 |
sAppKitStarted = YES;
|
|
239 |
pthread_cond_signal(&sAppKitStarted_cv);
|
|
240 |
pthread_mutex_unlock(&sAppKitStarted_mutex);
|
|
241 |
|
|
242 |
if (verbose) AWT_DEBUG_LOG(@"finished messaging AppKit started");
|
|
243 |
}
|
|
244 |
|
|
245 |
+ (void)start:(BOOL)headless swtMode:(BOOL)swtMode swtModeForWebStart:(BOOL)swtModeForWebStart
|
|
246 |
{
|
|
247 |
BOOL verbose = ShouldPrintVerboseDebugging();
|
|
248 |
|
|
249 |
// Headless: BOTH
|
|
250 |
// Embedded: BOTH
|
|
251 |
// Multiple Calls: NO
|
|
252 |
// Caller: JNI_OnLoad
|
|
253 |
|
|
254 |
// onMainThread is NOT the same at SWT mode!
|
|
255 |
// If the JVM was started on the first thread for SWT, but the SWT loads the AWT on a secondary thread,
|
|
256 |
// onMainThread here will be false but SWT mode will be true. If we are currently on the main thread, we don't
|
|
257 |
// need to throw AWT startup over to another thread.
|
|
258 |
BOOL onMainThread = (pthread_main_np() != 0);
|
|
259 |
|
|
260 |
if (verbose) {
|
|
261 |
NSString *msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d swtMode:%d swtModeForWebStart:%d] { onMainThread:%d }", headless, swtMode, swtModeForWebStart, onMainThread];
|
|
262 |
AWT_DEBUG_LOG(msg);
|
|
263 |
}
|
|
264 |
|
|
265 |
if (!headless)
|
|
266 |
{
|
|
267 |
// Listen for the NSApp to start. This indicates that JNI_OnLoad can proceed.
|
|
268 |
// It must wait because there is a chance that another java thread will grab
|
|
269 |
// the AppKit lock before the +[NSApplication sharedApplication] returns.
|
|
270 |
// See <rdar://problem/3492666> for an example.
|
|
271 |
[[NSNotificationCenter defaultCenter] addObserver:[AWTStarter class]
|
|
272 |
selector:@selector(appKitIsRunning:)
|
|
273 |
name:NSApplicationDidFinishLaunchingNotification
|
|
274 |
object:nil];
|
|
275 |
|
|
276 |
if (verbose) NSLog(@"+[AWTStarter start:::]: registered NSApplicationDidFinishLaunchingNotification");
|
|
277 |
}
|
|
278 |
|
|
279 |
id st = [[AWTStarter alloc] init];
|
|
280 |
|
|
281 |
NSArray * args = [NSArray arrayWithObjects:
|
|
282 |
[NSNumber numberWithBool: onMainThread],
|
|
283 |
[NSNumber numberWithBool: swtMode],
|
|
284 |
[NSNumber numberWithBool: headless],
|
|
285 |
[NSNumber numberWithBool: swtModeForWebStart],
|
|
286 |
[NSNumber numberWithBool: verbose],
|
|
287 |
nil];
|
|
288 |
|
|
289 |
if (onMainThread) {
|
|
290 |
[st starter:args];
|
|
291 |
} else {
|
|
292 |
[st performSelectorOnMainThread: @selector(starter:) withObject:args waitUntilDone:NO];
|
|
293 |
}
|
|
294 |
|
|
295 |
if (!headless && !onMainThread) {
|
|
296 |
if (verbose) AWT_DEBUG_LOG(@"about to wait on AppKit startup mutex");
|
|
297 |
|
|
298 |
// Wait here for AppKit to have started (or for AWT to have been loaded into
|
|
299 |
// an already running NSApplication).
|
|
300 |
pthread_mutex_lock(&sAppKitStarted_mutex);
|
|
301 |
while (sAppKitStarted == NO) {
|
|
302 |
pthread_cond_wait(&sAppKitStarted_cv, &sAppKitStarted_mutex);
|
|
303 |
}
|
|
304 |
pthread_mutex_unlock(&sAppKitStarted_mutex);
|
|
305 |
|
|
306 |
// AWT gets here AFTER +[AWTStarter appKitIsRunning:] is called.
|
|
307 |
if (verbose) AWT_DEBUG_LOG(@"got out of the AppKit startup mutex");
|
|
308 |
}
|
|
309 |
}
|
|
310 |
|
|
311 |
- (void)starter:(NSArray*)args {
|
|
312 |
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
|
313 |
|
|
314 |
BOOL onMainThread = [[args objectAtIndex:0] boolValue];
|
|
315 |
BOOL swtMode = [[args objectAtIndex:1] boolValue];
|
|
316 |
BOOL headless = [[args objectAtIndex:2] boolValue];
|
|
317 |
BOOL swtModeForWebStart = [[args objectAtIndex:3] boolValue];
|
|
318 |
BOOL verbose = [[args objectAtIndex:4] boolValue];
|
|
319 |
|
|
320 |
BOOL wasOnMainThread = onMainThread;
|
|
321 |
|
|
322 |
setUpAWTAppKit(swtMode, headless);
|
|
323 |
|
|
324 |
// Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return.
|
|
325 |
if (headless) {
|
|
326 |
BOOL didBecomeDaemon = [AWTStarter markAppAsDaemon];
|
|
327 |
return;
|
|
328 |
}
|
|
329 |
|
|
330 |
if (swtMode || swtModeForWebStart) {
|
|
331 |
if (verbose) NSLog(@"in SWT or SWT/WebStart mode");
|
|
332 |
|
|
333 |
// The SWT should call NSApplicationLoad, but they don't know a priori that they will be using the AWT, so they don't.
|
|
334 |
NSApplicationLoad();
|
|
335 |
}
|
|
336 |
|
|
337 |
// This will create a NSApplicationAWT for standalone AWT programs, unless there is
|
|
338 |
// already a NSApplication instance. If there is already a NSApplication instance,
|
|
339 |
// and -[NSApplication isRunning] returns YES, AWT is embedded inside another
|
|
340 |
// AppKit Application.
|
|
341 |
NSApplication *app = [NSApplicationAWT sharedApplication];
|
|
342 |
|
|
343 |
// Don't set the delegate until the NSApplication has been created.
|
|
344 |
// ApplicationDelegate is the support code for com.apple.eawt.
|
|
345 |
OSXAPP_SetApplicationDelegate([ApplicationDelegate sharedDelegate]);
|
|
346 |
|
|
347 |
// AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
|
|
348 |
if (![app isRunning]) {
|
|
349 |
if (verbose) AWT_DEBUG_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
|
|
350 |
|
|
351 |
// This is where the AWT AppKit thread parks itself to process events.
|
|
352 |
[NSApplicationAWT runAWTLoopWithApp: app];
|
|
353 |
} else {
|
|
354 |
// We're either embedded, or showing a splash screen
|
|
355 |
if (![NSApp isKindOfClass:[NSApplicationAWT class]]) {
|
|
356 |
if (verbose) AWT_DEBUG_LOG(@"running embedded");
|
|
357 |
|
|
358 |
// Since we're embedded, no need to be swamping the runloop with the observers.
|
|
359 |
CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
|
|
360 |
CFRunLoopRemoveObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
|
|
361 |
CFRunLoopRemoveObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
|
|
362 |
|
|
363 |
busyObserver = NULL;
|
|
364 |
notBusyObserver = NULL;
|
|
365 |
} else {
|
|
366 |
if (verbose) AWT_DEBUG_LOG(@"running after showing a splash screen");
|
|
367 |
}
|
|
368 |
|
|
369 |
// Signal so that JNI_OnLoad can proceed.
|
|
370 |
if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
|
|
371 |
|
|
372 |
// Proceed to exit this call as there is no reason to run the NSApplication event loop.
|
|
373 |
}
|
|
374 |
|
|
375 |
[pool drain];
|
|
376 |
}
|
|
377 |
|
|
378 |
@end
|
|
379 |
|
|
380 |
|
|
381 |
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|
382 |
BOOL verbose = ShouldPrintVerboseDebugging();
|
|
383 |
if (verbose) AWT_DEBUG_LOG(@"entered JNI_OnLoad");
|
|
384 |
|
|
385 |
// Headless: BOTH
|
|
386 |
// Embedded: BOTH
|
|
387 |
// Multiple Calls: NO
|
|
388 |
// Caller: JavaVM classloader
|
|
389 |
|
|
390 |
// Keep a static reference for other archives.
|
|
391 |
OSXAPP_SetJavaVM(vm);
|
|
392 |
|
|
393 |
JNIEnv *env = NULL;
|
|
394 |
|
|
395 |
// Need JNIEnv for JNF_COCOA_ENTER(env); macro below
|
|
396 |
jint status = (*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4);
|
|
397 |
if (status != JNI_OK || env == NULL) {
|
|
398 |
AWT_DEBUG_LOG(@"Can't get JNIEnv");
|
|
399 |
return JNI_VERSION_1_4;
|
|
400 |
}
|
|
401 |
|
|
402 |
// The following is true when AWT is attempting to connect to the window server
|
|
403 |
// when it isn't set up properly to do so.
|
|
404 |
// BOOL AWTLoadFailure = YES; For now we are skipping this check so i'm commenting out this variable as unused
|
|
405 |
JNF_COCOA_ENTER(env);
|
|
406 |
|
|
407 |
// If -XstartOnFirstThread was used at invocation time, an environment variable will be set.
|
|
408 |
// (See java_md.c for the matching setenv call.) When that happens, we assume the SWT will be in use.
|
|
409 |
BOOL swt_compatible_mode = NO;
|
|
410 |
|
|
411 |
char envVar[80];
|
|
412 |
snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
|
|
413 |
if (getenv(envVar) != NULL) {
|
|
414 |
swt_compatible_mode = YES;
|
|
415 |
unsetenv(envVar);
|
|
416 |
}
|
|
417 |
|
|
418 |
BOOL swt_in_webstart = isSWTInWebStart(env);
|
|
419 |
BOOL headless = isHeadless(env);
|
|
420 |
|
|
421 |
// Make sure we're on the right thread. If not, we still need the JNIEnv to throw an exception.
|
|
422 |
if (pthread_main_np() != 0 && !swt_compatible_mode && !headless) {
|
|
423 |
AWT_DEBUG_LOG(@"Apple AWT Java VM was loaded on first thread -- can't start AWT.");
|
|
424 |
[JNFException raise:env as:kInternalError reason:"Can't start the AWT because Java was started on the first thread. Make sure StartOnFirstThread is "
|
|
425 |
"not specified in your application's Info.plist or on the command line"];
|
|
426 |
return JNI_VERSION_1_4;
|
|
427 |
}
|
|
428 |
|
|
429 |
// We need to let Foundation know that this is a multithreaded application, if it isn't already.
|
|
430 |
if (![NSThread isMultiThreaded]) {
|
|
431 |
[NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil];
|
|
432 |
}
|
|
433 |
|
|
434 |
// if (swt_compatible_mode || headless || [AWTStarter isConnectedToWindowServer] || [AWTStarter isRemoteSession]) {
|
|
435 |
// No need in this check - we will try to launch AWTStarter anyways - to be able to run GUI application remotely
|
|
436 |
// AWTLoadFailure = NO;
|
|
437 |
|
|
438 |
[AWTStarter start:headless swtMode:swt_compatible_mode swtModeForWebStart:swt_in_webstart];
|
|
439 |
|
|
440 |
// }
|
|
441 |
|
|
442 |
/* if (AWTLoadFailure) { // We will not reach this code anyways
|
|
443 |
[JNFException raise:env as:kInternalError reason:"Can't connect to window server - not enough permissions."];
|
|
444 |
} */
|
|
445 |
|
|
446 |
JNF_COCOA_EXIT(env);
|
|
447 |
|
|
448 |
if (verbose) AWT_DEBUG_LOG(@"exiting JNI_OnLoad");
|
|
449 |
|
|
450 |
return JNI_VERSION_1_4;
|
|
451 |
}
|