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