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 <dlfcn.h>
27 #import <pthread.h>
28 #import <objc/runtime.h>
29 #import <Cocoa/Cocoa.h>
30 #import <Security/AuthSession.h>
31
32 #include "jni_util.h"
33 #import "LWCToolkit.h"
34 #import "ThreadUtilities.h"
35 #import "CSystemColors.h"
36 #import "NSApplicationAWT.h"
37 #import "PropertiesUtilities.h"
38 #import "ApplicationDelegate.h"
39
40 #import "sun_lwawt_macosx_LWCToolkit.h"
41
42 #import "sizecalc.h"
43
44 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
45
46 // SCROLL PHASE STATE
47 #define SCROLL_PHASE_UNSUPPORTED 1
48 #define SCROLL_PHASE_BEGAN 2
49 #define SCROLL_PHASE_CONTINUED 3
50 #define SCROLL_PHASE_MOMENTUM_BEGAN 4
51 #define SCROLL_PHASE_ENDED 5
52
167 @implementation JavaRunnable
168 @synthesize runnable = _runnable;
169
170 - (id)initWithRunnable:(jobject)gRunnable {
171 if (self = [super init]) {
172 self.runnable = gRunnable;
173 }
174 return self;
175 }
176
177 - (void)dealloc {
178 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
179 if (self.runnable) {
180 (*env)->DeleteGlobalRef(env, self.runnable);
181 }
182 [super dealloc];
183 }
184
185 - (void)perform {
186 JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
187 static JNF_CLASS_CACHE(sjc_Runnable, "java/lang/Runnable");
188 static JNF_MEMBER_CACHE(jm_Runnable_run, sjc_Runnable, "run", "()V");
189 JNFCallVoidMethod(env, self.runnable, jm_Runnable_run);
190 [self release];
191 }
192 @end
193
194 void setBusy(BOOL busy) {
195 AWT_ASSERT_APPKIT_THREAD;
196
197 JNIEnv *env = [ThreadUtilities getJNIEnv];
198 static JNF_CLASS_CACHE(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
199
200 if (busy) {
201 static JNF_STATIC_MEMBER_CACHE(jm_notifyBusyMethod, jc_AWTAutoShutdown, "notifyToolkitThreadBusy", "()V");
202 JNFCallStaticVoidMethod(env, jm_notifyBusyMethod);
203 } else {
204 static JNF_STATIC_MEMBER_CACHE(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
205 JNFCallStaticVoidMethod(env, jm_notifyFreeMethod);
206 }
207 }
208
209 static void setUpAWTAppKit(BOOL installObservers)
210 {
211 if (installObservers) {
212 AWT_STARTUP_LOG(@"Setting up busy observers");
213
214 // Add CFRunLoopObservers to call into AWT so that AWT knows that the
215 // AWT thread (which is the AppKit main thread) is alive. This way AWT
216 // will not automatically shutdown.
217 CFRunLoopObserverRef busyObserver = CFRunLoopObserverCreateWithHandler(
218 NULL, // CFAllocator
219 kCFRunLoopAfterWaiting, // CFOptionFlags
220 true, // repeats
221 NSIntegerMax, // order
222 ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
223 setBusy(YES);
224 });
225
226 CFRunLoopObserverRef notBusyObserver = CFRunLoopObserverCreateWithHandler(
227 NULL, // CFAllocator
228 kCFRunLoopBeforeWaiting, // CFOptionFlags
229 true, // repeats
230 NSIntegerMin, // order
231 ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
232 setBusy(NO);
233 });
234
235 CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
236 CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
237 CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
238
239 CFRelease(busyObserver);
240 CFRelease(notBusyObserver);
241
242 setBusy(YES);
243 }
244
245 JNIEnv* env = [ThreadUtilities getJNIEnv];
246 static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit");
247 static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V");
248 JNFCallStaticVoidMethod(env, jsm_installToolkitThreadInJava);
249 }
250
251 BOOL isSWTInWebStart(JNIEnv* env) {
252 NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env];
253 return [@"true" isCaseInsensitiveLike:swtWebStart];
254 }
255
256 static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
257 NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
258 }
259
260 @interface AWTStarter : NSObject
261 + (void)start:(BOOL)headless;
262 + (void)starter:(BOOL)onMainThread headless:(BOOL)headless;
263 + (void)appKitIsRunning:(id)arg;
264 @end
265
266 @implementation AWTStarter
267
268 + (BOOL) isConnectedToWindowServer {
435 // - CGEventPost(), see CRobot.m
436 // It was found that if we post an event via CGEventPost in robot and
437 // immediately after this we will post the second event via
438 // [NSApp postEvent] then sometimes the second event will be handled
439 // first. The opposite isn't proved, but we use both here to be safer.
440
441 // If the native drag is in progress, skip native sync.
442 if (!AWTToolkit.inDoDragDropLoop) {
443 [theApp postDummyEvent:false];
444 [theApp waitForDummyEvent:timeout / 2.0];
445 }
446 if (!AWTToolkit.inDoDragDropLoop) {
447 [theApp postDummyEvent:true];
448 [theApp waitForDummyEvent:timeout / 2.0];
449 }
450
451 } else {
452 // could happen if we are embedded inside SWT application,
453 // in this case just spin a single empty block through
454 // the event loop to give it a chance to process pending events
455 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){}];
456 }
457
458 if (([AWTToolkit getEventCount] - currentEventNum) != 0) {
459 return JNI_TRUE;
460 }
461
462 return JNI_FALSE;
463 }
464
465 /*
466 * Class: sun_lwawt_macosx_LWCToolkit
467 * Method: flushNativeSelectors
468 * Signature: ()J
469 */
470 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors
471 (JNIEnv *env, jclass clz)
472 {
473 JNF_COCOA_ENTER(env);
474 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
475 JNF_COCOA_EXIT(env);
476 }
477
478 /*
479 * Class: sun_lwawt_macosx_LWCToolkit
480 * Method: beep
481 * Signature: ()V
482 */
483 JNIEXPORT void JNICALL
484 Java_sun_lwawt_macosx_LWCToolkit_beep
485 (JNIEnv *env, jobject self)
486 {
487 NSBeep(); // produces both sound and visual flash, if configured in System Preferences
488 }
489
490 static UInt32 RGB(NSColor *c) {
491 c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
492 if (c == nil)
493 {
494 return -1; // opaque white
495 }
496
497 CGFloat r, g, b, a;
498 [c getRed:&r green:&g blue:&b alpha:&a];
499
500 UInt32 ir = (UInt32) (r*255+0.5),
501 ig = (UInt32) (g*255+0.5),
502 ib = (UInt32) (b*255+0.5),
503 ia = (UInt32) (a*255+0.5);
504
505 // NSLog(@"%@ %d, %d, %d", c, ir, ig, ib);
506
507 return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0);
508 }
509
510 BOOL doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) {
511 jint len = (*env)->GetArrayLength(env, jColors);
512
513 UInt32 colorsArray[len];
514 UInt32 *colors = colorsArray;
515
516 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
517 NSUInteger i;
518 for (i = 0; i < len; i++) {
519 colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]);
520 }
521 }];
522
523 jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0);
524 if (_colors == NULL) {
525 return NO;
526 }
527 memcpy(_colors, colors, len * sizeof(UInt32));
528 (*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0);
529 return YES;
530 }
531
532 /**
533 * Class: sun_lwawt_macosx_LWCToolkit
534 * Method: loadNativeColors
535 * Signature: ([I[I)V
536 */
537 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors
538 (JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors)
539 {
540 JNF_COCOA_ENTER(env);
541 if (doLoadNativeColors(env, jSystemColors, NO)) {
542 doLoadNativeColors(env, jAppleColors, YES);
543 }
544 JNF_COCOA_EXIT(env);
545 }
546
547 /*
548 * Class: sun_lwawt_macosx_LWCToolkit
549 * Method: createAWTRunLoopMediator
550 * Signature: ()J
551 */
552 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator
553 (JNIEnv *env, jclass clz)
554 {
555 AWT_ASSERT_APPKIT_THREAD;
556
557 jlong result;
558
559 JNF_COCOA_ENTER(env);
560 // We double retain because this object is owned by both main thread and "other" thread
561 // We release in both doAWTRunLoop and stopAWTRunLoop
562 result = ptr_to_jlong([[[AWTRunLoopObject alloc] init] retain]);
563 JNF_COCOA_EXIT(env);
564
565 return result;
566 }
567
568 /*
569 * Class: sun_lwawt_macosx_LWCToolkit
570 * Method: doAWTRunLoopImpl
571 * Signature: (JZZ)V
572 */
573 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl
574 (JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents, jboolean inAWT)
575 {
576 AWT_ASSERT_APPKIT_THREAD;
577 JNF_COCOA_ENTER(env);
578
579 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
580
581 if (mediatorObject == nil) return;
582
583 // Don't use acceptInputForMode because that doesn't setup autorelease pools properly
584 BOOL isRunning = true;
585 while (![mediatorObject shouldEndRunLoop] && isRunning) {
586 isRunning = [[NSRunLoop currentRunLoop] runMode:(inAWT ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode)
587 beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]];
588 if (processEvents) {
589 //We do not spin a runloop here as date is nil, so does not matter which mode to use
590 // Processing all events excluding NSApplicationDefined which need to be processed
591 // on the main loop only (those events are intended for disposing resources)
592 NSEvent *event;
593 if ((event = [NSApp nextEventMatchingMask:(NSAnyEventMask & ~NSApplicationDefinedMask)
594 untilDate:nil
595 inMode:NSDefaultRunLoopMode
596 dequeue:YES]) != nil) {
597 [NSApp sendEvent:event];
598 }
599
600 }
601 }
602 [mediatorObject release];
603 JNF_COCOA_EXIT(env);
604 }
605
606 /*
607 * Class: sun_lwawt_macosx_LWCToolkit
608 * Method: stopAWTRunLoop
609 * Signature: (J)V
610 */
611 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop
612 (JNIEnv *env, jclass clz, jlong mediator)
613 {
614 JNF_COCOA_ENTER(env);
615
616 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
617
618 [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
619
620 [mediatorObject release];
621
622 JNF_COCOA_EXIT(env);
623 }
624
625 /*
626 * Class: sun_lwawt_macosx_LWCToolkit
627 * Method: performOnMainThreadAfterDelay
628 * Signature: (Ljava/lang/Runnable;J)V
629 */
630 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAfterDelay
631 (JNIEnv *env, jclass clz, jobject runnable, jlong delay)
632 {
633 JNF_COCOA_ENTER(env);
634 jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
635 CHECK_NULL(gRunnable);
636 [ThreadUtilities performOnMainThreadWaiting:NO block:^() {
637 JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
638 [performer performSelector:@selector(perform) withObject:nil afterDelay:(delay/1000.0)];
639 }];
640 JNF_COCOA_EXIT(env);
641 }
642
643
644 /*
645 * Class: sun_lwawt_macosx_LWCToolkit
646 * Method: isCapsLockOn
647 * Signature: ()Z
648 */
649 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn
650 (JNIEnv *env, jobject self)
651 {
652 __block jboolean isOn = JNI_FALSE;
653 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
654 NSUInteger modifiers = [NSEvent modifierFlags];
655 isOn = (modifiers & NSAlphaShiftKeyMask) != 0;
656 }];
657
658 return isOn;
659 }
660
661 /*
662 * Class: sun_lwawt_macosx_LWCToolkit
663 * Method: isApplicationActive
664 * Signature: ()Z
665 */
666 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive
667 (JNIEnv *env, jclass clazz)
668 {
669 __block jboolean active = JNI_FALSE;
670
671 JNF_COCOA_ENTER(env);
672
673 [ThreadUtilities performOnMainThreadWaiting:YES block:^() {
674 active = (jboolean)[NSRunningApplication currentApplication].active;
675 }];
676
677 JNF_COCOA_EXIT(env);
678
679 return active;
680 }
681
682 /*
683 * Class: sun_lwawt_macosx_LWCToolkit
684 * Method: activateApplicationIgnoringOtherApps
685 * Signature: ()V
686 */
687 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_activateApplicationIgnoringOtherApps
688 (JNIEnv *env, jclass clazz)
689 {
690 JNF_COCOA_ENTER(env);
691 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
692 if(![NSApp isActive]){
693 [NSApp activateIgnoringOtherApps:YES];
694 }
695 }];
696 JNF_COCOA_EXIT(env);
697 }
698
699
700 /*
701 * Class: sun_awt_SunToolkit
702 * Method: closeSplashScreen
703 * Signature: ()V
704 */
705 JNIEXPORT void JNICALL
706 Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls)
707 {
708 void *hSplashLib = dlopen(0, RTLD_LAZY);
709 if (!hSplashLib) return;
710
711 void (*splashClose)() = dlsym(hSplashLib, "SplashClose");
712 if (splashClose) {
713 splashClose();
714 }
715 dlclose(hSplashLib);
716 }
717
718
719 // TODO: definitely doesn't belong here (copied from fontpath.c in the
720 // solaris tree)...
721
722 JNIEXPORT jstring JNICALL
723 Java_sun_font_FontManager_getFontPath
724 (JNIEnv *env, jclass obj, jboolean noType1)
725 {
726 return JNFNSToJavaString(env, @"/Library/Fonts");
727 }
728
729 // This isn't yet used on unix, the implementation is added since shared
730 // code calls this method in preparation for future use.
731 JNIEXPORT void JNICALL
732 Java_sun_font_FontManager_populateFontFileNameMap
733 (JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale)
734 {
735
736 }
737
738 /*
739 * Class: sun_lwawt_macosx_LWCToolkit
740 * Method: initIDs
741 * Signature: ()V
742 */
743 JNIEXPORT void JNICALL
744 Java_sun_lwawt_macosx_LWCToolkit_initIDs
745 (JNIEnv *env, jclass klass) {
746
747 JNF_COCOA_ENTER(env)
748
749 gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS;
750
751 jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent");
752 CHECK_NULL(inputEventClazz);
753 jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I");
754 CHECK_NULL(getButtonDownMasksID);
755 jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID);
756 jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE);
757 CHECK_NULL(tmp);
758
759 gButtonDownMasks = (jint*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), gNumberOfButtons);
760 if (gButtonDownMasks == NULL) {
761 gNumberOfButtons = 0;
762 (*env)->ReleaseIntArrayElements(env, obj, tmp, JNI_ABORT);
763 JNU_ThrowOutOfMemoryError(env, NULL);
764 return;
765 }
766
767 int i;
768 for (i = 0; i < gNumberOfButtons; i++) {
769 gButtonDownMasks[i] = tmp[i];
770 }
771
772 (*env)->ReleaseIntArrayElements(env, obj, tmp, 0);
773 (*env)->DeleteLocalRef(env, obj);
774
775 JNF_COCOA_EXIT(env)
776 }
777
778 /*
779 * Class: sun_lwawt_macosx_LWCToolkit
780 * Method: initAppkit
781 * Signature: (Ljava/lang/ThreadGroup;)V
782 */
783 JNIEXPORT void JNICALL
784 Java_sun_lwawt_macosx_LWCToolkit_initAppkit
785 (JNIEnv *env, jclass klass, jobject appkitThreadGroup, jboolean headless) {
786 JNF_COCOA_ENTER(env)
787
788 [ThreadUtilities setAppkitThreadGroup:(*env)->NewGlobalRef(env, appkitThreadGroup)];
789
790 // Launcher sets this env variable if -XstartOnFirstThread is specified
791 char envVar[80];
792 snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
793 if (getenv(envVar) != NULL) {
794 forceEmbeddedMode = YES;
795 unsetenv(envVar);
796 }
797
798 if (isSWTInWebStart(env)) {
799 forceEmbeddedMode = YES;
800 }
801
802 [AWTStarter start:headless ? YES : NO];
803
804 JNF_COCOA_EXIT(env)
805 }
806
807 JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) {
808 OSXAPP_SetJavaVM(vm);
809
810 // We need to let Foundation know that this is a multithreaded application,
811 // if it isn't already.
812 if (![NSThread isMultiThreaded]) {
813 [[[[NSThread alloc] init] autorelease] start];
814 }
815
816 return JNI_VERSION_1_4;
817 }
818
819 /*
820 * Class: sun_lwawt_macosx_LWCToolkit
821 * Method: isEmbedded
822 * Signature: ()Z
823 */
824 JNIEXPORT jboolean JNICALL
|
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 <dlfcn.h>
27 #import <pthread.h>
28 #import <objc/runtime.h>
29 #import <Cocoa/Cocoa.h>
30 #import <Security/AuthSession.h>
31
32 #import "JNIUtilities.h"
33 #import "LWCToolkit.h"
34 #import "ThreadUtilities.h"
35 #import "CSystemColors.h"
36 #import "NSApplicationAWT.h"
37 #import "PropertiesUtilities.h"
38 #import "ApplicationDelegate.h"
39
40 #import "sun_lwawt_macosx_LWCToolkit.h"
41
42 #import "sizecalc.h"
43
44 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
45
46 // SCROLL PHASE STATE
47 #define SCROLL_PHASE_UNSUPPORTED 1
48 #define SCROLL_PHASE_BEGAN 2
49 #define SCROLL_PHASE_CONTINUED 3
50 #define SCROLL_PHASE_MOMENTUM_BEGAN 4
51 #define SCROLL_PHASE_ENDED 5
52
167 @implementation JavaRunnable
168 @synthesize runnable = _runnable;
169
170 - (id)initWithRunnable:(jobject)gRunnable {
171 if (self = [super init]) {
172 self.runnable = gRunnable;
173 }
174 return self;
175 }
176
177 - (void)dealloc {
178 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
179 if (self.runnable) {
180 (*env)->DeleteGlobalRef(env, self.runnable);
181 }
182 [super dealloc];
183 }
184
185 - (void)perform {
186 JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
187 DECLARE_CLASS(sjc_Runnable, "java/lang/Runnable");
188 DECLARE_METHOD(jm_Runnable_run, sjc_Runnable, "run", "()V");
189 (*env)->CallVoidMethod(env, self.runnable, jm_Runnable_run);
190 CHECK_EXCEPTION();
191 [self release];
192 }
193 @end
194
195 void setBusy(BOOL busy) {
196 AWT_ASSERT_APPKIT_THREAD;
197
198 JNIEnv *env = [ThreadUtilities getJNIEnv];
199 DECLARE_CLASS(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
200
201 if (busy) {
202 DECLARE_STATIC_METHOD(jm_notifyBusyMethod, jc_AWTAutoShutdown, "notifyToolkitThreadBusy", "()V");
203 (*env)->CallStaticVoidMethod(env, jc_AWTAutoShutdown, jm_notifyBusyMethod);
204 } else {
205 DECLARE_STATIC_METHOD(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
206 (*env)->CallStaticVoidMethod(env, jc_AWTAutoShutdown, jm_notifyFreeMethod);
207 }
208 CHECK_EXCEPTION();
209 }
210
211 static void setUpAWTAppKit(BOOL installObservers)
212 {
213 if (installObservers) {
214 AWT_STARTUP_LOG(@"Setting up busy observers");
215
216 // Add CFRunLoopObservers to call into AWT so that AWT knows that the
217 // AWT thread (which is the AppKit main thread) is alive. This way AWT
218 // will not automatically shutdown.
219 CFRunLoopObserverRef busyObserver = CFRunLoopObserverCreateWithHandler(
220 NULL, // CFAllocator
221 kCFRunLoopAfterWaiting, // CFOptionFlags
222 true, // repeats
223 NSIntegerMax, // order
224 ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
225 setBusy(YES);
226 });
227
228 CFRunLoopObserverRef notBusyObserver = CFRunLoopObserverCreateWithHandler(
229 NULL, // CFAllocator
230 kCFRunLoopBeforeWaiting, // CFOptionFlags
231 true, // repeats
232 NSIntegerMin, // order
233 ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
234 setBusy(NO);
235 });
236
237 CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
238 CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
239 CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
240
241 CFRelease(busyObserver);
242 CFRelease(notBusyObserver);
243
244 setBusy(YES);
245 }
246
247 JNIEnv* env = [ThreadUtilities getJNIEnv];
248 DECLARE_CLASS(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit");
249 DECLARE_STATIC_METHOD(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V");
250 (*env)->CallStaticVoidMethod(env, jc_LWCToolkit, jsm_installToolkitThreadInJava);
251 CHECK_EXCEPTION();
252
253 }
254
255 BOOL isSWTInWebStart(JNIEnv* env) {
256 NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env];
257 return [@"true" isCaseInsensitiveLike:swtWebStart];
258 }
259
260 static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
261 NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
262 }
263
264 @interface AWTStarter : NSObject
265 + (void)start:(BOOL)headless;
266 + (void)starter:(BOOL)onMainThread headless:(BOOL)headless;
267 + (void)appKitIsRunning:(id)arg;
268 @end
269
270 @implementation AWTStarter
271
272 + (BOOL) isConnectedToWindowServer {
439 // - CGEventPost(), see CRobot.m
440 // It was found that if we post an event via CGEventPost in robot and
441 // immediately after this we will post the second event via
442 // [NSApp postEvent] then sometimes the second event will be handled
443 // first. The opposite isn't proved, but we use both here to be safer.
444
445 // If the native drag is in progress, skip native sync.
446 if (!AWTToolkit.inDoDragDropLoop) {
447 [theApp postDummyEvent:false];
448 [theApp waitForDummyEvent:timeout / 2.0];
449 }
450 if (!AWTToolkit.inDoDragDropLoop) {
451 [theApp postDummyEvent:true];
452 [theApp waitForDummyEvent:timeout / 2.0];
453 }
454
455 } else {
456 // could happen if we are embedded inside SWT application,
457 // in this case just spin a single empty block through
458 // the event loop to give it a chance to process pending events
459 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
460 }
461
462 if (([AWTToolkit getEventCount] - currentEventNum) != 0) {
463 return JNI_TRUE;
464 }
465
466 return JNI_FALSE;
467 }
468
469 /*
470 * Class: sun_lwawt_macosx_LWCToolkit
471 * Method: flushNativeSelectors
472 * Signature: ()J
473 */
474 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors
475 (JNIEnv *env, jclass clz)
476 {
477 JNI_COCOA_ENTER(env);
478 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
479 JNI_COCOA_EXIT(env);
480 }
481
482 /*
483 * Class: sun_lwawt_macosx_LWCToolkit
484 * Method: beep
485 * Signature: ()V
486 */
487 JNIEXPORT void JNICALL
488 Java_sun_lwawt_macosx_LWCToolkit_beep
489 (JNIEnv *env, jobject self)
490 {
491 NSBeep(); // produces both sound and visual flash, if configured in System Preferences
492 }
493
494 static UInt32 RGB(NSColor *c) {
495 c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
496 if (c == nil)
497 {
498 return -1; // opaque white
499 }
500
501 CGFloat r, g, b, a;
502 [c getRed:&r green:&g blue:&b alpha:&a];
503
504 UInt32 ir = (UInt32) (r*255+0.5),
505 ig = (UInt32) (g*255+0.5),
506 ib = (UInt32) (b*255+0.5),
507 ia = (UInt32) (a*255+0.5);
508
509 // NSLog(@"%@ %d, %d, %d", c, ir, ig, ib);
510
511 return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0);
512 }
513
514 BOOL doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) {
515 jint len = (*env)->GetArrayLength(env, jColors);
516
517 UInt32 colorsArray[len];
518 UInt32 *colors = colorsArray;
519
520 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
521 NSUInteger i;
522 for (i = 0; i < len; i++) {
523 colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]);
524 }
525 }];
526
527 jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0);
528 if (_colors == NULL) {
529 return NO;
530 }
531 memcpy(_colors, colors, len * sizeof(UInt32));
532 (*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0);
533 return YES;
534 }
535
536 /**
537 * Class: sun_lwawt_macosx_LWCToolkit
538 * Method: loadNativeColors
539 * Signature: ([I[I)V
540 */
541 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors
542 (JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors)
543 {
544 JNI_COCOA_ENTER(env);
545 if (doLoadNativeColors(env, jSystemColors, NO)) {
546 doLoadNativeColors(env, jAppleColors, YES);
547 }
548 JNI_COCOA_EXIT(env);
549 }
550
551 /*
552 * Class: sun_lwawt_macosx_LWCToolkit
553 * Method: createAWTRunLoopMediator
554 * Signature: ()J
555 */
556 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator
557 (JNIEnv *env, jclass clz)
558 {
559 AWT_ASSERT_APPKIT_THREAD;
560
561 jlong result;
562
563 JNI_COCOA_ENTER(env);
564 // We double retain because this object is owned by both main thread and "other" thread
565 // We release in both doAWTRunLoop and stopAWTRunLoop
566 result = ptr_to_jlong([[[AWTRunLoopObject alloc] init] retain]);
567 JNI_COCOA_EXIT(env);
568
569 return result;
570 }
571
572 /*
573 * Class: sun_lwawt_macosx_LWCToolkit
574 * Method: doAWTRunLoopImpl
575 * Signature: (JZZ)V
576 */
577 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl
578 (JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents, jboolean inAWT)
579 {
580 AWT_ASSERT_APPKIT_THREAD;
581 JNI_COCOA_ENTER(env);
582
583 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
584
585 if (mediatorObject == nil) return;
586
587 // Don't use acceptInputForMode because that doesn't setup autorelease pools properly
588 BOOL isRunning = true;
589 while (![mediatorObject shouldEndRunLoop] && isRunning) {
590 isRunning = [[NSRunLoop currentRunLoop] runMode:(inAWT ? [ThreadUtilities javaRunLoopMode] : NSDefaultRunLoopMode)
591 beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]];
592 if (processEvents) {
593 //We do not spin a runloop here as date is nil, so does not matter which mode to use
594 // Processing all events excluding NSApplicationDefined which need to be processed
595 // on the main loop only (those events are intended for disposing resources)
596 NSEvent *event;
597 if ((event = [NSApp nextEventMatchingMask:(NSAnyEventMask & ~NSApplicationDefinedMask)
598 untilDate:nil
599 inMode:NSDefaultRunLoopMode
600 dequeue:YES]) != nil) {
601 [NSApp sendEvent:event];
602 }
603
604 }
605 }
606 [mediatorObject release];
607 JNI_COCOA_EXIT(env);
608 }
609
610 /*
611 * Class: sun_lwawt_macosx_LWCToolkit
612 * Method: stopAWTRunLoop
613 * Signature: (J)V
614 */
615 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop
616 (JNIEnv *env, jclass clz, jlong mediator)
617 {
618 JNI_COCOA_ENTER(env);
619
620 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
621
622 [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
623
624 [mediatorObject release];
625
626 JNI_COCOA_EXIT(env);
627 }
628
629 /*
630 * Class: sun_lwawt_macosx_LWCToolkit
631 * Method: performOnMainThreadAfterDelay
632 * Signature: (Ljava/lang/Runnable;J)V
633 */
634 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAfterDelay
635 (JNIEnv *env, jclass clz, jobject runnable, jlong delay)
636 {
637 JNI_COCOA_ENTER(env);
638 jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
639 CHECK_NULL(gRunnable);
640 [ThreadUtilities performOnMainThreadWaiting:NO block:^() {
641 JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
642 [performer performSelector:@selector(perform) withObject:nil afterDelay:(delay/1000.0)];
643 }];
644 JNI_COCOA_EXIT(env);
645 }
646
647
648 /*
649 * Class: sun_lwawt_macosx_LWCToolkit
650 * Method: isCapsLockOn
651 * Signature: ()Z
652 */
653 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn
654 (JNIEnv *env, jobject self)
655 {
656 __block jboolean isOn = JNI_FALSE;
657 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
658 NSUInteger modifiers = [NSEvent modifierFlags];
659 isOn = (modifiers & NSAlphaShiftKeyMask) != 0;
660 }];
661
662 return isOn;
663 }
664
665 /*
666 * Class: sun_lwawt_macosx_LWCToolkit
667 * Method: isApplicationActive
668 * Signature: ()Z
669 */
670 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive
671 (JNIEnv *env, jclass clazz)
672 {
673 __block jboolean active = JNI_FALSE;
674
675 JNI_COCOA_ENTER(env);
676
677 [ThreadUtilities performOnMainThreadWaiting:YES block:^() {
678 active = (jboolean)[NSRunningApplication currentApplication].active;
679 }];
680
681 JNI_COCOA_EXIT(env);
682
683 return active;
684 }
685
686 /*
687 * Class: sun_lwawt_macosx_LWCToolkit
688 * Method: activateApplicationIgnoringOtherApps
689 * Signature: ()V
690 */
691 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_activateApplicationIgnoringOtherApps
692 (JNIEnv *env, jclass clazz)
693 {
694 JNI_COCOA_ENTER(env);
695 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
696 if(![NSApp isActive]){
697 [NSApp activateIgnoringOtherApps:YES];
698 }
699 }];
700 JNI_COCOA_EXIT(env);
701 }
702
703
704 /*
705 * Class: sun_awt_SunToolkit
706 * Method: closeSplashScreen
707 * Signature: ()V
708 */
709 JNIEXPORT void JNICALL
710 Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls)
711 {
712 void *hSplashLib = dlopen(0, RTLD_LAZY);
713 if (!hSplashLib) return;
714
715 void (*splashClose)() = dlsym(hSplashLib, "SplashClose");
716 if (splashClose) {
717 splashClose();
718 }
719 dlclose(hSplashLib);
720 }
721
722
723 // TODO: definitely doesn't belong here (copied from fontpath.c in the
724 // solaris tree)...
725
726 JNIEXPORT jstring JNICALL
727 Java_sun_font_FontManager_getFontPath
728 (JNIEnv *env, jclass obj, jboolean noType1)
729 {
730 return NSStringToJavaString(env, @"/Library/Fonts");
731 }
732
733 // This isn't yet used on unix, the implementation is added since shared
734 // code calls this method in preparation for future use.
735 JNIEXPORT void JNICALL
736 Java_sun_font_FontManager_populateFontFileNameMap
737 (JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale)
738 {
739
740 }
741
742 /*
743 * Class: sun_lwawt_macosx_LWCToolkit
744 * Method: initIDs
745 * Signature: ()V
746 */
747 JNIEXPORT void JNICALL
748 Java_sun_lwawt_macosx_LWCToolkit_initIDs
749 (JNIEnv *env, jclass klass) {
750
751 JNI_COCOA_ENTER(env);
752
753 gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS;
754
755 jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent");
756 CHECK_NULL(inputEventClazz);
757 jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I");
758 CHECK_NULL(getButtonDownMasksID);
759 jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID);
760 CHECK_EXCEPTION();
761 jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE);
762 CHECK_NULL(tmp);
763
764 gButtonDownMasks = (jint*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), gNumberOfButtons);
765 if (gButtonDownMasks == NULL) {
766 gNumberOfButtons = 0;
767 (*env)->ReleaseIntArrayElements(env, obj, tmp, JNI_ABORT);
768 JNU_ThrowOutOfMemoryError(env, NULL);
769 return;
770 }
771
772 int i;
773 for (i = 0; i < gNumberOfButtons; i++) {
774 gButtonDownMasks[i] = tmp[i];
775 }
776
777 (*env)->ReleaseIntArrayElements(env, obj, tmp, 0);
778 (*env)->DeleteLocalRef(env, obj);
779
780 JNI_COCOA_EXIT(env);
781 }
782
783 /*
784 * Class: sun_lwawt_macosx_LWCToolkit
785 * Method: initAppkit
786 * Signature: (Ljava/lang/ThreadGroup;)V
787 */
788 JNIEXPORT void JNICALL
789 Java_sun_lwawt_macosx_LWCToolkit_initAppkit
790 (JNIEnv *env, jclass klass, jobject appkitThreadGroup, jboolean headless) {
791 JNI_COCOA_ENTER(env);
792
793 [ThreadUtilities setAppkitThreadGroup:(*env)->NewGlobalRef(env, appkitThreadGroup)];
794
795 // Launcher sets this env variable if -XstartOnFirstThread is specified
796 char envVar[80];
797 snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
798 if (getenv(envVar) != NULL) {
799 forceEmbeddedMode = YES;
800 unsetenv(envVar);
801 }
802
803 if (isSWTInWebStart(env)) {
804 forceEmbeddedMode = YES;
805 }
806
807 [AWTStarter start:headless ? YES : NO];
808
809 JNI_COCOA_EXIT(env);
810 }
811
812 JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) {
813 OSXAPP_SetJavaVM(vm);
814
815 // We need to let Foundation know that this is a multithreaded application,
816 // if it isn't already.
817 if (![NSThread isMultiThreaded]) {
818 [[[[NSThread alloc] init] autorelease] start];
819 }
820
821 return JNI_VERSION_1_4;
822 }
823
824 /*
825 * Class: sun_lwawt_macosx_LWCToolkit
826 * Method: isEmbedded
827 * Signature: ()Z
828 */
829 JNIEXPORT jboolean JNICALL
|