blob: f4c3e7f1854600a5c6ef2e65a67ca6107ba8e7c9 [file] [log] [blame]
/*
* 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;
}