| /* |
| * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #import <Cocoa/Cocoa.h> |
| #include <objc/objc-runtime.h> |
| |
| #import "sun_lwawt_macosx_CInputMethod.h" |
| #import "sun_lwawt_macosx_CInputMethodDescriptor.h" |
| #import "ThreadUtilities.h" |
| #import "AWTView.h" |
| |
| #import <JavaNativeFoundation/JavaNativeFoundation.h> |
| #import <JavaRuntimeSupport/JavaRuntimeSupport.h> |
| |
| #define JAVA_LIST @"JAVA_LIST" |
| #define CURRENT_KB_DESCRIPTION @"CURRENT_KB_DESCRIPTION" |
| |
| static JNF_CLASS_CACHE(jc_localeClass, "java/util/Locale"); |
| static JNF_CTOR_CACHE(jm_localeCons, jc_localeClass, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); |
| static JNF_CLASS_CACHE(jc_arrayListClass, "java/util/ArrayList"); |
| static JNF_CTOR_CACHE(jm_arrayListCons, jc_arrayListClass, "()V"); |
| static JNF_MEMBER_CACHE(jm_listAdd, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z"); |
| static JNF_MEMBER_CACHE(jm_listContains, jc_arrayListClass, "contains", "(Ljava/lang/Object;)Z"); |
| |
| |
| |
| // |
| // NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value. |
| // |
| static jobject CreateLocaleObjectFromNSString(JNIEnv *env, NSString *name) |
| { |
| // Break apart the string into its components. |
| // First, duplicate the NSString into a C string, since we're going to modify it. |
| char * language = strdup([name UTF8String]); |
| char * country; |
| char * variant; |
| |
| // Convert _ to NULL -- this gives us three null terminated strings in place. |
| for (country = language; *country != '_' && *country != '\0'; country++); |
| if (*country == '_') { |
| *country++ = '\0'; |
| for (variant = country; *variant != '_' && *variant != '\0'; variant++); |
| if (*variant == '_') { |
| *variant++ = '\0'; |
| } |
| } else { |
| variant = country; |
| } |
| |
| // Create the java.util.Locale object |
| jobject localeObj = NULL; |
| jobject langObj = (*env)->NewStringUTF(env, language); |
| if (langObj != NULL) { |
| jobject ctryObj = (*env)->NewStringUTF(env, country); |
| if(ctryObj != NULL) { |
| jobject vrntObj = (*env)->NewStringUTF(env, variant); |
| if (vrntObj != NULL) { |
| localeObj = JNFNewObject(env, jm_localeCons,langObj, ctryObj, |
| vrntObj); |
| (*env)->DeleteLocalRef(env, vrntObj); |
| } |
| (*env)->DeleteLocalRef(env, ctryObj); |
| } |
| (*env)->DeleteLocalRef(env, langObj); |
| } |
| // Clean up and return. |
| free(language); |
| return localeObj; |
| } |
| |
| static id inputMethodController = nil; |
| |
| static void initializeInputMethodController() { |
| static BOOL checkedJRSInputMethodController = NO; |
| if (!checkedJRSInputMethodController && (inputMethodController == nil)) { |
| id jrsInputMethodController = objc_lookUpClass("JRSInputMethodController"); |
| if (jrsInputMethodController != nil) { |
| inputMethodController = [jrsInputMethodController performSelector:@selector(controller)]; |
| } |
| checkedJRSInputMethodController = YES; |
| } |
| } |
| |
| |
| @interface CInputMethod : NSObject {} |
| @end |
| |
| @implementation CInputMethod |
| |
| + (void) setKeyboardLayout:(NSString *)theLocale |
| { |
| AWT_ASSERT_APPKIT_THREAD; |
| if (!inputMethodController) return; |
| |
| [inputMethodController performSelector:@selector(setCurrentInputMethodForLocale) withObject:theLocale]; |
| } |
| |
| + (void) _nativeNotifyPeerWithView:(AWTView *)view inputMethod:(JNFJObjectWrapper *) inputMethod { |
| AWT_ASSERT_APPKIT_THREAD; |
| |
| if (!view) return; |
| if (!inputMethod) return; |
| |
| [view setInputMethod:[inputMethod jObject]]; |
| } |
| |
| + (void) _nativeEndComposition:(AWTView *)view { |
| if (view == nil) return; |
| |
| [view abandonInput]; |
| } |
| |
| |
| @end |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethod |
| * Method: nativeInit |
| * Signature: (); |
| */ |
| JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeInit |
| (JNIEnv *env, jclass klass) |
| { |
| initializeInputMethodController(); |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethod |
| * Method: nativeGetCurrentInputMethodInfo |
| * Signature: ()Ljava/lang/String; |
| */ |
| JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeGetCurrentInputMethodInfo |
| (JNIEnv *env, jclass klass) |
| { |
| if (!inputMethodController) return NULL; |
| jobject returnValue = 0; |
| __block NSString *keyboardInfo = NULL; |
| JNF_COCOA_ENTER(env); |
| |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| keyboardInfo = [inputMethodController performSelector:@selector(currentInputMethodName)]; |
| [keyboardInfo retain]; |
| }]; |
| |
| if (keyboardInfo == nil) return NULL; |
| returnValue = JNFNSToJavaString(env, keyboardInfo); |
| [keyboardInfo release]; |
| |
| JNF_COCOA_EXIT(env); |
| return returnValue; |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethod |
| * Method: nativeActivate |
| * Signature: (JLsun/lwawt/macosx/CInputMethod;)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeNotifyPeer |
| (JNIEnv *env, jobject this, jlong nativePeer, jobject inputMethod) |
| { |
| JNF_COCOA_ENTER(env); |
| AWTView *view = (AWTView *)jlong_to_ptr(nativePeer); |
| JNFJObjectWrapper *inputMethodWrapper = [[JNFJObjectWrapper alloc] initWithJObject:inputMethod withEnv:env]; |
| [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ |
| [CInputMethod _nativeNotifyPeerWithView:view inputMethod:inputMethodWrapper]; |
| }]; |
| |
| JNF_COCOA_EXIT(env); |
| |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethod |
| * Method: nativeEndComposition |
| * Signature: (J)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeEndComposition |
| (JNIEnv *env, jobject this, jlong nativePeer) |
| { |
| JNF_COCOA_ENTER(env); |
| AWTView *view = (AWTView *)jlong_to_ptr(nativePeer); |
| |
| [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ |
| [CInputMethod _nativeEndComposition:view]; |
| }]; |
| |
| JNF_COCOA_EXIT(env); |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethod |
| * Method: getNativeLocale |
| * Signature: ()Ljava/util/Locale; |
| */ |
| JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CInputMethod_getNativeLocale |
| (JNIEnv *env, jobject this) |
| { |
| if (!inputMethodController) return NULL; |
| jobject returnValue = 0; |
| __block NSString *isoAbbreviation; |
| JNF_COCOA_ENTER(env); |
| |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| isoAbbreviation = (NSString *) [inputMethodController performSelector:@selector(currentInputMethodLocale)]; |
| [isoAbbreviation retain]; |
| }]; |
| |
| if (isoAbbreviation == nil) return NULL; |
| |
| static NSString *sLastKeyboardStr = nil; |
| static jobject sLastKeyboardLocaleObj = NULL; |
| |
| if (![isoAbbreviation isEqualTo:sLastKeyboardStr]) { |
| [sLastKeyboardStr release]; |
| sLastKeyboardStr = [isoAbbreviation retain]; |
| jobject localObj = CreateLocaleObjectFromNSString(env, isoAbbreviation); |
| [isoAbbreviation release]; |
| |
| if (sLastKeyboardLocaleObj) { |
| JNFDeleteGlobalRef(env, sLastKeyboardLocaleObj); |
| sLastKeyboardLocaleObj = NULL; |
| } |
| if (localObj != NULL) { |
| sLastKeyboardLocaleObj = JNFNewGlobalRef(env, localObj); |
| (*env)->DeleteLocalRef(env, localObj); |
| } |
| } |
| |
| returnValue = sLastKeyboardLocaleObj; |
| |
| JNF_COCOA_EXIT(env); |
| return returnValue; |
| } |
| |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethod |
| * Method: setNativeLocale |
| * Signature: (Ljava/lang/String;Z)Z |
| */ |
| JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CInputMethod_setNativeLocale |
| (JNIEnv *env, jobject this, jstring locale, jboolean isActivating) |
| { |
| JNF_COCOA_ENTER(env); |
| NSString *localeStr = JNFJavaToNSString(env, locale); |
| [localeStr retain]; |
| |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| [CInputMethod setKeyboardLayout:localeStr]; |
| }]; |
| |
| [localeStr release]; |
| JNF_COCOA_EXIT(env); |
| return JNI_TRUE; |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethodDescriptor |
| * Method: nativeInit |
| * Signature: (); |
| */ |
| JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethodDescriptor_nativeInit |
| (JNIEnv *env, jclass klass) |
| { |
| initializeInputMethodController(); |
| } |
| |
| /* |
| * Class: sun_lwawt_macosx_CInputMethodDescriptor |
| * Method: nativeGetAvailableLocales |
| * Signature: ()[Ljava/util/Locale; |
| */ |
| JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CInputMethodDescriptor_nativeGetAvailableLocales |
| (JNIEnv *env, jclass klass) |
| { |
| if (!inputMethodController) return NULL; |
| jobject returnValue = 0; |
| |
| __block NSArray *selectableArray = nil; |
| JNF_COCOA_ENTER(env); |
| |
| [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ |
| selectableArray = (NSArray *)[inputMethodController performSelector:@selector(availableInputMethodLocales)]; |
| [selectableArray retain]; |
| }]; |
| |
| if (selectableArray == nil) return NULL; |
| |
| // Create an ArrayList to return back to the caller. |
| returnValue = JNFNewObject(env, jm_arrayListCons); |
| |
| for(NSString *locale in selectableArray) { |
| jobject localeObj = CreateLocaleObjectFromNSString(env, locale); |
| if (localeObj == NULL) { |
| break; |
| } |
| |
| if (JNFCallBooleanMethod(env, returnValue, jm_listContains, localeObj) == JNI_FALSE) { |
| JNFCallBooleanMethod(env, returnValue, jm_listAdd, localeObj); |
| } |
| |
| (*env)->DeleteLocalRef(env, localeObj); |
| } |
| [selectableArray release]; |
| JNF_COCOA_EXIT(env); |
| return returnValue; |
| } |
| |