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