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 <dlfcn.h> 27 #import <JavaNativeFoundation/JavaNativeFoundation.h> 28 29 #include "jni_util.h" 30 #import "CMenuBar.h" 31 #import "InitIDs.h" 32 #import "LWCToolkit.h" 33 #import "ThreadUtilities.h" 34 #import "AWT_debug.h" 35 #import "CSystemColors.h" 36 37 #import "sun_lwawt_macosx_LWCToolkit.h" 38 39 int gNumberOfButtons; 40 jint* gButtonDownMasks; 41 42 @implementation AWTToolkit 43 44 static long eventCount; 45 46 + (long) getEventCount{ 47 return eventCount; 48 } 49 50 + (void) eventCountPlusPlus{ 51 eventCount++; 52 } 53 54 @end 55 56 57 @interface AWTRunLoopObject : NSObject { 58 BOOL _shouldEndRunLoop; 59 } 60 @end 61 62 @implementation AWTRunLoopObject 63 64 - (id) init { 65 self = [super init]; 66 if (self != nil) { 67 _shouldEndRunLoop = NO; 68 } 69 return self; 70 } 71 72 - (BOOL) shouldEndRunLoop { 73 return _shouldEndRunLoop; 74 } 75 76 - (void) endRunLoop { 77 _shouldEndRunLoop = YES; 78 } 79 80 @end 81 82 83 /* 84 * Class: sun_lwawt_macosx_LWCToolkit 85 * Method: nativeSyncQueue 86 * Signature: (J)Z 87 */ 88 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue 89 (JNIEnv *env, jobject self, jlong timeout) 90 { 91 int currentEventNum = [AWTToolkit getEventCount]; 92 93 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){}]; 94 95 if (([AWTToolkit getEventCount] - currentEventNum) != 0) { 96 return JNI_TRUE; 97 } 98 99 return JNI_FALSE; 100 } 101 102 103 static JNF_CLASS_CACHE(jc_Component, "java/awt/Component"); 104 static JNF_MEMBER_CACHE(jf_Component_appContext, jc_Component, "appContext", "Lsun/awt/AppContext;"); 105 static JNF_CLASS_CACHE(jc_MenuComponent, "java/awt/MenuComponent"); 106 static JNF_MEMBER_CACHE(jf_MenuComponent_appContext, jc_MenuComponent, "appContext", "Lsun/awt/AppContext;"); 107 108 /* 109 * Class: sun_awt_SunToolkit 110 * Method: getAppContext 111 * Signature: (Ljava/awt/Object;)Lsun/awt/AppContext; 112 */ 113 JNIEXPORT jobject JNICALL 114 Java_sun_awt_SunToolkit_getAppContext 115 (JNIEnv *env, jclass cls, jobject obj) 116 { 117 jobject appContext = NULL; 118 119 JNF_COCOA_ENTER(env); 120 121 if (JNFIsInstanceOf(env, obj, &jc_Component)) { 122 appContext = JNFGetObjectField(env, obj, jf_Component_appContext); 123 } else if (JNFIsInstanceOf(env, obj, &jc_MenuComponent)) { 124 appContext = JNFGetObjectField(env, obj, jf_MenuComponent_appContext); 125 } 126 127 JNF_COCOA_EXIT(env); 128 129 return appContext; 130 } 131 132 /* 133 * Class: sun_awt_SunToolkit 134 * Method: setAppContext 135 * Signature: (Ljava/lang/Object;Lsun/awt/AppContext;)Z 136 */ 137 JNIEXPORT jboolean JNICALL 138 Java_sun_awt_SunToolkit_setAppContext 139 (JNIEnv *env, jclass cls, jobject obj, jobject appContext) 140 { 141 jboolean isComponent; 142 143 JNF_COCOA_ENTER(env); 144 145 if (JNFIsInstanceOf(env, obj, &jc_Component)) { 146 JNFSetObjectField(env, obj, jf_Component_appContext, appContext); 147 isComponent = JNI_TRUE; 148 } else if (JNFIsInstanceOf(env, obj, &jc_MenuComponent)) { 149 JNFSetObjectField(env, obj, jf_MenuComponent_appContext, appContext); 150 isComponent = JNI_FALSE; 151 } 152 153 JNF_COCOA_EXIT(env); 154 155 return isComponent; 156 } 157 158 /* 159 * Class: sun_lwawt_macosx_LWCToolkit 160 * Method: beep 161 * Signature: ()V 162 */ 163 JNIEXPORT void JNICALL 164 Java_sun_lwawt_macosx_LWCToolkit_beep 165 (JNIEnv *env, jobject self) 166 { 167 NSBeep(); // produces both sound and visual flash, if configured in System Preferences 168 } 169 170 CGDirectDisplayID 171 FindCGDirectDisplayIDForScreenIndex(jint screenIndex) 172 { 173 // most common case - just one monitor 174 CGDirectDisplayID screenID = CGMainDisplayID(); 175 176 CGDisplayCount displayCount = 0; 177 CGGetOnlineDisplayList(0, NULL, &displayCount); 178 179 if ((displayCount > 1) && 180 (screenIndex >= 0) && 181 (screenIndex < (jint)displayCount)) 182 { 183 if (displayCount < 10) { 184 // stack allocated optimization for less than 10 monitors 185 CGDirectDisplayID onlineDisplays[displayCount]; 186 CGGetOnlineDisplayList(displayCount, onlineDisplays, &displayCount); 187 screenID = (CGDirectDisplayID)onlineDisplays[screenIndex]; 188 } else { 189 CGDirectDisplayID *onlineDisplays = 190 malloc(displayCount*sizeof(CGDirectDisplayID)); 191 if (onlineDisplays != NULL) { 192 CGGetOnlineDisplayList(displayCount, onlineDisplays, 193 &displayCount); 194 screenID = (CGDirectDisplayID)onlineDisplays[screenIndex]; 195 free(onlineDisplays); 196 } 197 } 198 } 199 200 return screenID; 201 } 202 203 /* 204 * Class: sun_lwawt_macosx_LWCToolkit 205 * Method: initIDs 206 * Signature: ()V 207 */ 208 JNIEXPORT void JNICALL 209 Java_sun_lwawt_macosx_LWCToolkit_initIDs 210 (JNIEnv *env, jclass klass) { 211 // set thread names 212 dispatch_async(dispatch_get_main_queue(), ^(void){ 213 [[NSThread currentThread] setName:@"AppKit Thread"]; 214 215 JNIEnv *env = [ThreadUtilities getJNIEnv]; 216 static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit"); 217 static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadNameInJava, jc_LWCToolkit, "installToolkitThreadNameInJava", "()V"); 218 JNFCallStaticVoidMethod(env, jsm_installToolkitThreadNameInJava); 219 }); 220 221 gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS; 222 223 jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent"); 224 jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I"); 225 jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID); 226 jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE); 227 228 gButtonDownMasks = (jint*)malloc(sizeof(jint) * gNumberOfButtons); 229 if (gButtonDownMasks == NULL) { 230 gNumberOfButtons = 0; 231 JNU_ThrowOutOfMemoryError(env, NULL); 232 return; 233 } 234 235 int i; 236 for (i = 0; i < gNumberOfButtons; i++) { 237 gButtonDownMasks[i] = tmp[i]; 238 } 239 240 (*env)->ReleaseIntArrayElements(env, obj, tmp, 0); 241 (*env)->DeleteLocalRef(env, obj); 242 } 243 244 static UInt32 RGB(NSColor *c) { 245 c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; 246 if (c == nil) 247 { 248 return -1; // opaque white 249 } 250 251 CGFloat r, g, b, a; 252 [c getRed:&r green:&g blue:&b alpha:&a]; 253 254 UInt32 ir = (UInt32) (r*255+0.5), 255 ig = (UInt32) (g*255+0.5), 256 ib = (UInt32) (b*255+0.5), 257 ia = (UInt32) (a*255+0.5); 258 259 // NSLog(@"%@ %d, %d, %d", c, ir, ig, ib); 260 261 return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0); 262 } 263 264 void doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) { 265 jint len = (*env)->GetArrayLength(env, jColors); 266 267 UInt32 colorsArray[len]; 268 UInt32 *colors = colorsArray; 269 270 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ 271 NSUInteger i; 272 for (i = 0; i < len; i++) { 273 colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]); 274 } 275 }]; 276 277 jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0); 278 memcpy(_colors, colors, len * sizeof(UInt32)); 279 (*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0); 280 } 281 282 /** 283 * Class: sun_lwawt_macosx_LWCToolkit 284 * Method: loadNativeColors 285 * Signature: ([I[I)V 286 */ 287 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors 288 (JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors) 289 { 290 JNF_COCOA_ENTER(env); 291 doLoadNativeColors(env, jSystemColors, NO); 292 doLoadNativeColors(env, jAppleColors, YES); 293 JNF_COCOA_EXIT(env); 294 } 295 296 /* 297 * Class: sun_lwawt_macosx_LWCToolkit 298 * Method: createAWTRunLoopMediator 299 * Signature: ()J 300 */ 301 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator 302 (JNIEnv *env, jclass clz) 303 { 304 AWT_ASSERT_APPKIT_THREAD; 305 306 AWTRunLoopObject *o = nil; 307 308 // We double retain because this object is owned by both main thread and "other" thread 309 // We release in both doAWTRunLoop and stopAWTRunLoop 310 o = [[AWTRunLoopObject alloc] init]; 311 if (o) { 312 CFRetain(o); // GC 313 CFRetain(o); // GC 314 [o release]; 315 } 316 return ptr_to_jlong(o); 317 } 318 319 /* 320 * Class: sun_lwawt_macosx_LWCToolkit 321 * Method: doAWTRunLoop 322 * Signature: (JZZ)V 323 */ 324 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoop 325 (JNIEnv *env, jclass clz, jlong mediator, jboolean awtMode, jboolean detectDeadlocks) 326 { 327 AWT_ASSERT_APPKIT_THREAD; 328 JNF_COCOA_ENTER(env); 329 330 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); 331 332 if (mediatorObject == nil) return; 333 334 if (!sInPerformFromJava || !detectDeadlocks) { 335 336 NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; 337 NSDate *distantFuture = [NSDate distantFuture]; 338 NSString *mode = (awtMode) ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode; 339 340 BOOL isRunning = YES; 341 while (isRunning && ![mediatorObject shouldEndRunLoop]) { 342 // Don't use acceptInputForMode because that doesn't setup autorelease pools properly 343 isRunning = [currentRunLoop runMode:mode beforeDate:distantFuture]; 344 } 345 346 } 347 #ifndef PRODUCT_BUILD 348 if (sInPerformFromJava) { 349 NSLog(@"Apple AWT: Short-circuiting CToolkit.invokeAndWait trampoline deadlock!!!!!"); 350 NSLog(@"\tPlease file a bug report with this message and a reproducible test case."); 351 } 352 #endif 353 354 CFRelease(mediatorObject); 355 356 JNF_COCOA_EXIT(env); 357 } 358 359 /* 360 * Class: sun_lwawt_macosx_LWCToolkit 361 * Method: stopAWTRunLoop 362 * Signature: (J)V 363 */ 364 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop 365 (JNIEnv *env, jclass clz, jlong mediator) 366 { 367 AWT_ASSERT_NOT_APPKIT_THREAD; 368 JNF_COCOA_ENTER(env); 369 370 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); 371 372 [ThreadUtilities performOnMainThread:@selector(endRunLoop) onObject:mediatorObject withObject:nil waitUntilDone:NO awtMode:YES]; 373 374 CFRelease(mediatorObject); 375 376 JNF_COCOA_EXIT(env); 377 } 378 379 /* 380 * Class: sun_lwawt_macosx_LWCToolkit 381 * Method: isCapsLockOn 382 * Signature: ()Z 383 */ 384 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn 385 (JNIEnv *env, jobject self) 386 { 387 __block jboolean isOn = JNI_FALSE; 388 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ 389 NSUInteger modifiers = [NSEvent modifierFlags]; 390 isOn = (modifiers & NSAlphaShiftKeyMask) != 0; 391 }]; 392 393 return isOn; 394 } 395 396 /* 397 * Class: sun_lwawt_macosx_LWCToolkit 398 * Method: isApplicationActive 399 * Signature: ()Z 400 */ 401 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive 402 (JNIEnv *env, jclass clazz) 403 { 404 __block jboolean active = JNI_FALSE; 405 406 JNF_COCOA_ENTER(env); 407 408 if ([NSThread isMainThread]) { 409 active = (jboolean)[NSRunningApplication currentApplication].active; 410 } else { 411 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^() { 412 active = (jboolean)[NSRunningApplication currentApplication].active; 413 }]; 414 } 415 416 JNF_COCOA_EXIT(env); 417 418 return active; 419 } 420 421 422 /* 423 * Class: sun_awt_SunToolkit 424 * Method: closeSplashScreen 425 * Signature: ()V 426 */ 427 JNIEXPORT void JNICALL 428 Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls) 429 { 430 void *hSplashLib = dlopen(0, RTLD_LAZY); 431 if (!hSplashLib) return; 432 433 void (*splashClose)() = dlsym(hSplashLib, "SplashClose"); 434 if (splashClose) { 435 splashClose(); 436 } 437 dlclose(hSplashLib); 438 } 439 440 441 // TODO: definitely doesn't belong here (copied from fontpath.c in the 442 // solaris tree)... 443 444 JNIEXPORT jstring JNICALL 445 Java_sun_font_FontManager_getFontPath 446 (JNIEnv *env, jclass obj, jboolean noType1) 447 { 448 return JNFNSToJavaString(env, @"/Library/Fonts"); 449 } 450 451 // This isn't yet used on unix, the implementation is added since shared 452 // code calls this method in preparation for future use. 453 JNIEXPORT void JNICALL 454 Java_sun_font_FontManager_populateFontFileNameMap 455 (JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 456 { 457 458 } 459 460 /* 461 * Class: sun_lwawt_macosx_LWCToolkit 462 * Method: startNativeNestedEventLoop 463 * Signature: ()V 464 */ 465 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_startNativeNestedEventLoop 466 (JNIEnv *env, jclass cls) 467 { 468 // Simply get the next event in native loop and pass it to execution 469 // We'll be called repeatedly so there's no need to block here 470 NSRunLoop *theRL = [NSRunLoop currentRunLoop]; 471 NSApplication * app = [NSApplication sharedApplication]; 472 NSEvent * event = [app nextEventMatchingMask: 0xFFFFFFFF untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; 473 if (event != nil) { 474 [app sendEvent: event]; 475 } 476 } 477 478 /* 479 * Class: sun_lwawt_macosx_LWCToolkit 480 * Method: stopNativeNestedEventLoop 481 * Signature: ()V 482 */ 483 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopNativeNestedEventLoop 484 (JNIEnv *env, jclass cls) 485 { 486 // At this moment it seems that this method should be no-op 487 }