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