8033367: [macosx] Appletviewer was broken in jdk8 b124
Reviewed-by: anthony, serb
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import <dlfcn.h>
#import <pthread.h>
#import <objc/runtime.h>
#import <Cocoa/Cocoa.h>
#import <Security/AuthSession.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
#include "jni_util.h"
#import "CMenuBar.h"
#import "InitIDs.h"
#import "LWCToolkit.h"
#import "ThreadUtilities.h"
#import "AWT_debug.h"
#import "CSystemColors.h"
#import "NSApplicationAWT.h"
#import "PropertiesUtilities.h"
#import "ApplicationDelegate.h"
#import "sun_lwawt_macosx_LWCToolkit.h"
#import "sizecalc.h"
int gNumberOfButtons;
jint* gButtonDownMasks;
// Indicates that the app has been started with -XstartOnFirstThread
// (directly or via WebStart settings), and AWT should not run its
// own event loop in this mode. Even if a loop isn't running yet,
// we expect an embedder (e.g. SWT) to start it some time later.
static BOOL forceEmbeddedMode = NO;
// This is the data necessary to have JNI_OnLoad wait for AppKit to start.
static BOOL sAppKitStarted = NO;
static pthread_mutex_t sAppKitStarted_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t sAppKitStarted_cv = PTHREAD_COND_INITIALIZER;
@implementation AWTToolkit
static long eventCount;
+ (long) getEventCount{
return eventCount;
}
+ (void) eventCountPlusPlus{
eventCount++;
}
@end
@interface AWTRunLoopObject : NSObject {
BOOL _shouldEndRunLoop;
}
@end
@implementation AWTRunLoopObject
- (id) init {
self = [super init];
if (self != nil) {
_shouldEndRunLoop = NO;
}
return self;
}
- (BOOL) shouldEndRunLoop {
return _shouldEndRunLoop;
}
- (void) endRunLoop {
_shouldEndRunLoop = YES;
}
@end
@interface JavaRunnable : NSObject { }
@property jobject runnable;
- (id)initWithRunnable:(jobject)gRunnable;
- (void)perform;
@end
@implementation JavaRunnable
@synthesize runnable = _runnable;
- (id)initWithRunnable:(jobject)gRunnable {
if (self = [super init]) {
self.runnable = gRunnable;
}
return self;
}
- (void)dealloc {
JNIEnv *env = [ThreadUtilities getJNIEnv];
if (self.runnable) {
(*env)->DeleteGlobalRef(env, self.runnable);
}
[super dealloc];
}
- (void)perform {
JNIEnv* env = [ThreadUtilities getJNIEnv];
static JNF_CLASS_CACHE(sjc_Runnable, "java/lang/Runnable");
static JNF_MEMBER_CACHE(jm_Runnable_run, sjc_Runnable, "run", "()V");
JNFCallVoidMethod(env, self.runnable, jm_Runnable_run);
[self release];
}
@end
void setBusy(BOOL busy) {
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
static JNF_CLASS_CACHE(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
if (busy) {
static JNF_STATIC_MEMBER_CACHE(jm_notifyBusyMethod, jc_AWTAutoShutdown, "notifyToolkitThreadBusy", "()V");
JNFCallStaticVoidMethod(env, jm_notifyBusyMethod);
} else {
static JNF_STATIC_MEMBER_CACHE(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
JNFCallStaticVoidMethod(env, jm_notifyFreeMethod);
}
}
static void setUpAWTAppKit(BOOL installObservers)
{
if (installObservers) {
AWT_STARTUP_LOG(@"Setting up busy observers");
// Add CFRunLoopObservers to call into AWT so that AWT knows that the
// AWT thread (which is the AppKit main thread) is alive. This way AWT
// will not automatically shutdown.
CFRunLoopObserverRef busyObserver = CFRunLoopObserverCreateWithHandler(
NULL, // CFAllocator
kCFRunLoopAfterWaiting, // CFOptionFlags
true, // repeats
NSIntegerMax, // order
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
setBusy(YES);
});
CFRunLoopObserverRef notBusyObserver = CFRunLoopObserverCreateWithHandler(
NULL, // CFAllocator
kCFRunLoopBeforeWaiting, // CFOptionFlags
true, // repeats
NSIntegerMin, // order
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
setBusy(NO);
});
CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
CFRelease(busyObserver);
CFRelease(notBusyObserver);
setBusy(YES);
}
JNIEnv* env = [ThreadUtilities getJNIEnv];
static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit");
static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V");
JNFCallStaticVoidMethod(env, jsm_installToolkitThreadInJava);
}
BOOL isSWTInWebStart(JNIEnv* env) {
NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env];
return [@"true" isCaseInsensitiveLike:swtWebStart];
}
static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
}
@interface AWTStarter : NSObject
+ (void)start:(BOOL)headless;
+ (void)starter:(BOOL)onMainThread headless:(BOOL)headless;
+ (void)appKitIsRunning:(id)arg;
@end
@implementation AWTStarter
+ (BOOL) isConnectedToWindowServer {
SecuritySessionId session_id;
SessionAttributeBits session_info;
OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info);
if (status != noErr) return NO;
if (!(session_info & sessionHasGraphicAccess)) return NO;
return YES;
}
+ (BOOL) markAppAsDaemon {
id jrsAppKitAWTClass = objc_getClass("JRSAppKitAWT");
SEL markAppSel = @selector(markAppIsDaemon);
if (![jrsAppKitAWTClass respondsToSelector:markAppSel]) return NO;
return [jrsAppKitAWTClass performSelector:markAppSel] ? YES : NO;
}
+ (void)appKitIsRunning:(id)arg {
AWT_ASSERT_APPKIT_THREAD;
AWT_STARTUP_LOG(@"About to message AppKit started");
// Signal that AppKit has started (or is already running).
pthread_mutex_lock(&sAppKitStarted_mutex);
sAppKitStarted = YES;
pthread_cond_signal(&sAppKitStarted_cv);
pthread_mutex_unlock(&sAppKitStarted_mutex);
AWT_STARTUP_LOG(@"Finished messaging AppKit started");
}
+ (void)start:(BOOL)headless
{
// onMainThread is NOT the same at SWT mode!
// If the JVM was started on the first thread for SWT, but the SWT loads the AWT on a secondary thread,
// onMainThread here will be false but SWT mode will be true. If we are currently on the main thread, we don't
// need to throw AWT startup over to another thread.
BOOL onMainThread = [NSThread isMainThread];
NSString* msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d] { onMainThread:%d }", headless, onMainThread];
AWT_STARTUP_LOG(msg);
if (!headless)
{
// Listen for the NSApp to start. This indicates that JNI_OnLoad can proceed.
// It must wait because there is a chance that another java thread will grab
// the AppKit lock before the +[NSApplication sharedApplication] returns.
// See <rdar://problem/3492666> for an example.
[[NSNotificationCenter defaultCenter] addObserver:[AWTStarter class]
selector:@selector(appKitIsRunning:)
name:NSApplicationDidFinishLaunchingNotification
object:nil];
AWT_STARTUP_LOG(@"+[AWTStarter start:::]: registered NSApplicationDidFinishLaunchingNotification");
}
[ThreadUtilities performOnMainThreadWaiting:NO block:^() {
[AWTStarter starter:onMainThread headless:headless];
}];
if (!headless && !onMainThread) {
AWT_STARTUP_LOG(@"about to wait on AppKit startup mutex");
// Wait here for AppKit to have started (or for AWT to have been loaded into
// an already running NSApplication).
pthread_mutex_lock(&sAppKitStarted_mutex);
while (sAppKitStarted == NO) {
pthread_cond_wait(&sAppKitStarted_cv, &sAppKitStarted_mutex);
}
pthread_mutex_unlock(&sAppKitStarted_mutex);
// AWT gets here AFTER +[AWTStarter appKitIsRunning:] is called.
AWT_STARTUP_LOG(@"got out of the AppKit startup mutex");
}
if (!headless) {
// Don't set the delegate until the NSApplication has been created and
// its finishLaunching has initialized it.
// ApplicationDelegate is the support code for com.apple.eawt.
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
id<NSApplicationDelegate> delegate = [ApplicationDelegate sharedDelegate];
if (delegate != nil) {
OSXAPP_SetApplicationDelegate(delegate);
}
}];
}
}
+ (void)starter:(BOOL)wasOnMainThread headless:(BOOL)headless {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// Add the exception handler of last resort
NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler);
// Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return.
if (headless) {
// Note that we don't install run loop observers in headless mode
// because we don't need them (see 7174704)
if (!forceEmbeddedMode) {
setUpAWTAppKit(false);
}
[AWTStarter markAppAsDaemon];
return;
}
if (forceEmbeddedMode) {
AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode");
// Init a default NSApplication instance instead of the NSApplicationAWT.
// Note that [NSApp isRunning] will return YES after that, though
// this behavior isn't specified anywhere. We rely on that.
NSApplicationLoad();
}
// This will create a NSApplicationAWT for standalone AWT programs, unless there is
// already a NSApplication instance. If there is already a NSApplication instance,
// and -[NSApplication isRunning] returns YES, AWT is embedded inside another
// AppKit Application.
NSApplication *app = [NSApplicationAWT sharedApplication];
BOOL isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]];
[ThreadUtilities setAWTEmbedded:isEmbedded];
if (!isEmbedded) {
// Install run loop observers and set the AppKit Java thread name
setUpAWTAppKit(true);
}
// AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
if (![app isRunning]) {
AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
// This is where the AWT AppKit thread parks itself to process events.
[NSApplicationAWT runAWTLoopWithApp: app];
} else {
// We're either embedded, or showing a splash screen
if (isEmbedded) {
AWT_STARTUP_LOG(@"running embedded");
// We don't track if the runloop is busy, so set it free to let AWT finish when it needs
setBusy(NO);
} else {
AWT_STARTUP_LOG(@"running after showing a splash screen");
}
// Signal so that JNI_OnLoad can proceed.
if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
// Proceed to exit this call as there is no reason to run the NSApplication event loop.
}
[pool drain];
}
@end
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: nativeSyncQueue
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue
(JNIEnv *env, jobject self, jlong timeout)
{
int currentEventNum = [AWTToolkit getEventCount];
NSApplication* sharedApp = [NSApplication sharedApplication];
if ([sharedApp isKindOfClass:[NSApplicationAWT class]]) {
NSApplicationAWT* theApp = (NSApplicationAWT*)sharedApp;
[theApp postDummyEvent];
[theApp waitForDummyEvent];
} else {
// could happen if we are embedded inside SWT application,
// in this case just spin a single empty block through
// the event loop to give it a chance to process pending events
[JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){}];
}
if (([AWTToolkit getEventCount] - currentEventNum) != 0) {
return JNI_TRUE;
}
return JNI_FALSE;
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: flushNativeSelectors
* Signature: ()J
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors
(JNIEnv *env, jclass clz)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: beep
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_LWCToolkit_beep
(JNIEnv *env, jobject self)
{
NSBeep(); // produces both sound and visual flash, if configured in System Preferences
}
static UInt32 RGB(NSColor *c) {
c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
if (c == nil)
{
return -1; // opaque white
}
CGFloat r, g, b, a;
[c getRed:&r green:&g blue:&b alpha:&a];
UInt32 ir = (UInt32) (r*255+0.5),
ig = (UInt32) (g*255+0.5),
ib = (UInt32) (b*255+0.5),
ia = (UInt32) (a*255+0.5);
// NSLog(@"%@ %d, %d, %d", c, ir, ig, ib);
return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0);
}
BOOL doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) {
jint len = (*env)->GetArrayLength(env, jColors);
UInt32 colorsArray[len];
UInt32 *colors = colorsArray;
[JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
NSUInteger i;
for (i = 0; i < len; i++) {
colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]);
}
}];
jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0);
if (_colors == NULL) {
return NO;
}
memcpy(_colors, colors, len * sizeof(UInt32));
(*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0);
return YES;
}
/**
* Class: sun_lwawt_macosx_LWCToolkit
* Method: loadNativeColors
* Signature: ([I[I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors
(JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors)
{
JNF_COCOA_ENTER(env);
if (doLoadNativeColors(env, jSystemColors, NO)) {
doLoadNativeColors(env, jAppleColors, YES);
}
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: createAWTRunLoopMediator
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator
(JNIEnv *env, jclass clz)
{
AWT_ASSERT_APPKIT_THREAD;
jlong result;
JNF_COCOA_ENTER(env);
// We double retain because this object is owned by both main thread and "other" thread
// We release in both doAWTRunLoop and stopAWTRunLoop
result = ptr_to_jlong([[[AWTRunLoopObject alloc] init] retain]);
JNF_COCOA_EXIT(env);
return result;
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: doAWTRunLoopImpl
* Signature: (JZZ)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl
(JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents, jboolean inAWT)
{
AWT_ASSERT_APPKIT_THREAD;
JNF_COCOA_ENTER(env);
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
if (mediatorObject == nil) return;
// Don't use acceptInputForMode because that doesn't setup autorelease pools properly
BOOL isRunning = true;
while (![mediatorObject shouldEndRunLoop] && isRunning) {
isRunning = [[NSRunLoop currentRunLoop] runMode:(inAWT ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode)
beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]];
if (processEvents) {
//We do not spin a runloop here as date is nil, so does not matter which mode to use
NSEvent *event;
if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES]) != nil) {
[NSApp sendEvent:event];
}
}
}
[mediatorObject release];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: stopAWTRunLoop
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop
(JNIEnv *env, jclass clz, jlong mediator)
{
JNF_COCOA_ENTER(env);
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
[ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
[mediatorObject release];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: performOnMainThreadAfterDelay
* Signature: (Ljava/lang/Runnable;J)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAfterDelay
(JNIEnv *env, jclass clz, jobject runnable, jlong delay)
{
JNF_COCOA_ENTER(env);
jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
CHECK_NULL(gRunnable);
[ThreadUtilities performOnMainThreadWaiting:NO block:^() {
JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
[performer performSelector:@selector(perform) withObject:nil afterDelay:(delay/1000.0)];
}];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: isCapsLockOn
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn
(JNIEnv *env, jobject self)
{
__block jboolean isOn = JNI_FALSE;
[JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
NSUInteger modifiers = [NSEvent modifierFlags];
isOn = (modifiers & NSAlphaShiftKeyMask) != 0;
}];
return isOn;
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: isApplicationActive
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive
(JNIEnv *env, jclass clazz)
{
__block jboolean active = JNI_FALSE;
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
active = (jboolean)[NSRunningApplication currentApplication].active;
}];
JNF_COCOA_EXIT(env);
return active;
}
/*
* Class: sun_awt_SunToolkit
* Method: closeSplashScreen
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls)
{
void *hSplashLib = dlopen(0, RTLD_LAZY);
if (!hSplashLib) return;
void (*splashClose)() = dlsym(hSplashLib, "SplashClose");
if (splashClose) {
splashClose();
}
dlclose(hSplashLib);
}
// TODO: definitely doesn't belong here (copied from fontpath.c in the
// solaris tree)...
JNIEXPORT jstring JNICALL
Java_sun_font_FontManager_getFontPath
(JNIEnv *env, jclass obj, jboolean noType1)
{
return JNFNSToJavaString(env, @"/Library/Fonts");
}
// This isn't yet used on unix, the implementation is added since shared
// code calls this method in preparation for future use.
JNIEXPORT void JNICALL
Java_sun_font_FontManager_populateFontFileNameMap
(JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale)
{
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: initIDs
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_LWCToolkit_initIDs
(JNIEnv *env, jclass klass) {
JNF_COCOA_ENTER(env)
gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS;
jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent");
CHECK_NULL(inputEventClazz);
jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I");
CHECK_NULL(getButtonDownMasksID);
jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID);
jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE);
CHECK_NULL(tmp);
gButtonDownMasks = (jint*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), gNumberOfButtons);
if (gButtonDownMasks == NULL) {
gNumberOfButtons = 0;
(*env)->ReleaseIntArrayElements(env, obj, tmp, JNI_ABORT);
JNU_ThrowOutOfMemoryError(env, NULL);
return;
}
int i;
for (i = 0; i < gNumberOfButtons; i++) {
gButtonDownMasks[i] = tmp[i];
}
(*env)->ReleaseIntArrayElements(env, obj, tmp, 0);
(*env)->DeleteLocalRef(env, obj);
JNF_COCOA_EXIT(env)
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: initAppkit
* Signature: (Ljava/lang/ThreadGroup;)V
*/
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_LWCToolkit_initAppkit
(JNIEnv *env, jclass klass, jobject appkitThreadGroup, jboolean headless) {
JNF_COCOA_ENTER(env)
[ThreadUtilities setAppkitThreadGroup:(*env)->NewGlobalRef(env, appkitThreadGroup)];
// Launcher sets this env variable if -XstartOnFirstThread is specified
char envVar[80];
snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
if (getenv(envVar) != NULL) {
forceEmbeddedMode = YES;
unsetenv(envVar);
}
if (isSWTInWebStart(env)) {
forceEmbeddedMode = YES;
}
[AWTStarter start:headless ? YES : NO];
JNF_COCOA_EXIT(env)
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
OSXAPP_SetJavaVM(vm);
// We need to let Foundation know that this is a multithreaded application, if it isn't already.
if (![NSThread isMultiThreaded]) {
[NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil];
}
return JNI_VERSION_1_4;
}