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