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