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