1 /* 2 * Copyright (c) 2011, 2014, 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 /* 128 * Class: sun_lwawt_macosx_LWCToolkit 129 * Method: beep 130 * Signature: ()V 131 */ 132 JNIEXPORT void JNICALL 133 Java_sun_lwawt_macosx_LWCToolkit_beep 134 (JNIEnv *env, jobject self) 135 { 136 NSBeep(); // produces both sound and visual flash, if configured in System Preferences 137 } 138 139 /* 140 * Class: sun_lwawt_macosx_LWCToolkit 141 * Method: initIDs 142 * Signature: ()V 143 */ 144 JNIEXPORT void JNICALL 145 Java_sun_lwawt_macosx_LWCToolkit_initIDs 146 (JNIEnv *env, jclass klass) { 147 // set thread names 148 if (![ThreadUtilities isAWTEmbedded]) { 149 dispatch_async(dispatch_get_main_queue(), ^(void){ 150 [[NSThread currentThread] setName:@"AppKit Thread"]; 151 JNIEnv *env = [ThreadUtilities getJNIEnv]; 152 static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit"); 153 static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V"); 154 JNFCallStaticVoidMethod(env, jsm_installToolkitThreadInJava); 155 }); 156 } 157 158 gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS; 159 160 jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent"); 161 CHECK_NULL(inputEventClazz); 162 jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I"); 163 CHECK_NULL(getButtonDownMasksID); 164 jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID); 165 jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE); 166 CHECK_NULL(tmp); 167 168 gButtonDownMasks = (jint*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), gNumberOfButtons); 169 if (gButtonDownMasks == NULL) { 170 gNumberOfButtons = 0; 171 (*env)->ReleaseIntArrayElements(env, obj, tmp, JNI_ABORT); 172 JNU_ThrowOutOfMemoryError(env, NULL); 173 return; 174 } 175 176 int i; 177 for (i = 0; i < gNumberOfButtons; i++) { 178 gButtonDownMasks[i] = tmp[i]; 179 } 180 181 (*env)->ReleaseIntArrayElements(env, obj, tmp, 0); 182 (*env)->DeleteLocalRef(env, obj); 183 } 184 185 static UInt32 RGB(NSColor *c) { 186 c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; 187 if (c == nil) 188 { 189 return -1; // opaque white 190 } 191 192 CGFloat r, g, b, a; 193 [c getRed:&r green:&g blue:&b alpha:&a]; 194 195 UInt32 ir = (UInt32) (r*255+0.5), 196 ig = (UInt32) (g*255+0.5), 197 ib = (UInt32) (b*255+0.5), 198 ia = (UInt32) (a*255+0.5); 199 200 // NSLog(@"%@ %d, %d, %d", c, ir, ig, ib); 201 202 return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0); 203 } 204 205 BOOL doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) { 206 jint len = (*env)->GetArrayLength(env, jColors); 207 208 UInt32 colorsArray[len]; 209 UInt32 *colors = colorsArray; 210 211 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ 212 NSUInteger i; 213 for (i = 0; i < len; i++) { 214 colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]); 215 } 216 }]; 217 218 jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0); 219 if (_colors == NULL) { 220 return NO; 221 } 222 memcpy(_colors, colors, len * sizeof(UInt32)); 223 (*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0); 224 return YES; 225 } 226 227 /** 228 * Class: sun_lwawt_macosx_LWCToolkit 229 * Method: loadNativeColors 230 * Signature: ([I[I)V 231 */ 232 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors 233 (JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors) 234 { 235 JNF_COCOA_ENTER(env); 236 if (doLoadNativeColors(env, jSystemColors, NO)) { 237 doLoadNativeColors(env, jAppleColors, YES); 238 } 239 JNF_COCOA_EXIT(env); 240 } 241 242 /* 243 * Class: sun_lwawt_macosx_LWCToolkit 244 * Method: createAWTRunLoopMediator 245 * Signature: ()J 246 */ 247 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator 248 (JNIEnv *env, jclass clz) 249 { 250 AWT_ASSERT_APPKIT_THREAD; 251 252 AWTRunLoopObject *o = nil; 253 254 // We double retain because this object is owned by both main thread and "other" thread 255 // We release in both doAWTRunLoop and stopAWTRunLoop 256 o = [[AWTRunLoopObject alloc] init]; 257 if (o) { 258 CFRetain(o); // GC 259 CFRetain(o); // GC 260 [o release]; 261 } 262 return ptr_to_jlong(o); 263 } 264 265 /* 266 * Class: sun_lwawt_macosx_LWCToolkit 267 * Method: doAWTRunLoopImpl 268 * Signature: (JZZ)V 269 */ 270 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl 271 (JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents, jboolean inAWT) 272 { 273 AWT_ASSERT_APPKIT_THREAD; 274 JNF_COCOA_ENTER(env); 275 276 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); 277 278 if (mediatorObject == nil) return; 279 280 // Don't use acceptInputForMode because that doesn't setup autorelease pools properly 281 BOOL isRunning = true; 282 while (![mediatorObject shouldEndRunLoop] && isRunning) { 283 isRunning = [[NSRunLoop currentRunLoop] runMode:(inAWT ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode) 284 beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]]; 285 if (processEvents) { 286 //We do not spin a runloop here as date is nil, so does not matter which mode to use 287 // Processing all events excluding NSApplicationDefined which need to be processed 288 // on the main loop only (those events are intended for disposing resources) 289 NSEvent *event; 290 if ((event = [NSApp nextEventMatchingMask:(NSAnyEventMask & ~NSApplicationDefinedMask) 291 untilDate:nil 292 inMode:NSDefaultRunLoopMode 293 dequeue:YES]) != nil) { 294 [NSApp sendEvent:event]; 295 } 296 297 } 298 } 299 300 301 CFRelease(mediatorObject); 302 303 JNF_COCOA_EXIT(env); 304 } 305 306 /* 307 * Class: sun_lwawt_macosx_LWCToolkit 308 * Method: stopAWTRunLoop 309 * Signature: (J)V 310 */ 311 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop 312 (JNIEnv *env, jclass clz, jlong mediator) 313 { 314 JNF_COCOA_ENTER(env); 315 316 AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); 317 318 [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO]; 319 320 CFRelease(mediatorObject); 321 322 JNF_COCOA_EXIT(env); 323 } 324 325 /* 326 * Class: sun_lwawt_macosx_LWCToolkit 327 * Method: isCapsLockOn 328 * Signature: ()Z 329 */ 330 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn 331 (JNIEnv *env, jobject self) 332 { 333 __block jboolean isOn = JNI_FALSE; 334 [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ 335 NSUInteger modifiers = [NSEvent modifierFlags]; 336 isOn = (modifiers & NSAlphaShiftKeyMask) != 0; 337 }]; 338 339 return isOn; 340 } 341 342 /* 343 * Class: sun_lwawt_macosx_LWCToolkit 344 * Method: isApplicationActive 345 * Signature: ()Z 346 */ 347 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive 348 (JNIEnv *env, jclass clazz) 349 { 350 __block jboolean active = JNI_FALSE; 351 352 JNF_COCOA_ENTER(env); 353 354 [ThreadUtilities performOnMainThreadWaiting:YES block:^() { 355 active = (jboolean)[NSRunningApplication currentApplication].active; 356 }]; 357 358 JNF_COCOA_EXIT(env); 359 360 return active; 361 } 362 363 /* 364 * Class: sun_lwawt_macosx_LWCToolkit 365 * Method: activateApplicationIgnoringOtherApps 366 * Signature: ()V 367 */ 368 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_activateApplicationIgnoringOtherApps 369 (JNIEnv *env, jclass clazz) 370 { 371 JNF_COCOA_ENTER(env); 372 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ 373 if(![NSApp isActive]){ 374 [NSApp activateIgnoringOtherApps:YES]; 375 } 376 }]; 377 JNF_COCOA_EXIT(env); 378 } 379 380 381 /* 382 * Class: sun_awt_SunToolkit 383 * Method: closeSplashScreen 384 * Signature: ()V 385 */ 386 JNIEXPORT void JNICALL 387 Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls) 388 { 389 void *hSplashLib = dlopen(0, RTLD_LAZY); 390 if (!hSplashLib) return; 391 392 void (*splashClose)() = dlsym(hSplashLib, "SplashClose"); 393 if (splashClose) { 394 splashClose(); 395 } 396 dlclose(hSplashLib); 397 } 398 399 400 // TODO: definitely doesn't belong here (copied from fontpath.c in the 401 // solaris tree)... 402 403 JNIEXPORT jstring JNICALL 404 Java_sun_font_FontManager_getFontPath 405 (JNIEnv *env, jclass obj, jboolean noType1) 406 { 407 return JNFNSToJavaString(env, @"/Library/Fonts"); 408 } 409 410 // This isn't yet used on unix, the implementation is added since shared 411 // code calls this method in preparation for future use. 412 JNIEXPORT void JNICALL 413 Java_sun_font_FontManager_populateFontFileNameMap 414 (JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 415 { 416 417 } 418 419 /* 420 * Class: sun_lwawt_macosx_LWCToolkit 421 * Method: isEmbedded 422 * Signature: ()Z 423 */ 424 JNIEXPORT jboolean JNICALL 425 Java_sun_lwawt_macosx_LWCToolkit_isEmbedded 426 (JNIEnv *env, jclass klass) { 427 return [ThreadUtilities isAWTEmbedded] ? JNI_TRUE : JNI_FALSE; 428 } 429