< prev index next >
src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java
Print this page
rev 50285 : 8201429: Support AIX Input Method Editor (IME) for AWT Input Method Framework (IMF)
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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
@@ -23,48 +23,47 @@
* questions.
*/
package sun.awt;
-import java.util.Collections;
-import java.util.Locale;
-import java.util.Map;
-import java.util.HashMap;
import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Window;
-import java.awt.im.InputMethodHighlight;
-import java.awt.im.spi.InputMethodContext;
-import sun.awt.im.InputMethodAdapter;
import java.awt.event.InputMethodEvent;
import java.awt.font.TextAttribute;
import java.awt.font.TextHitInfo;
+import java.awt.im.InputMethodHighlight;
+import java.awt.im.spi.InputMethodContext;
import java.awt.peer.ComponentPeer;
-import java.lang.Character.Subset;
-import java.text.AttributedString;
-import java.text.AttributedCharacterIterator;
-
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
-import java.io.BufferedReader;
import java.io.IOException;
+import java.lang.Character.Subset;
import java.lang.ref.WeakReference;
-import sun.util.logging.PlatformLogger;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
+import sun.awt.im.InputMethodAdapter;
+import sun.util.logging.PlatformLogger;
/**
* Input Method Adapter for XIM
*
* @author JavaSoft International
*/
-public abstract class X11InputMethod extends InputMethodAdapter {
- private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11InputMethod");
+public abstract class X11InputMethodBase extends InputMethodAdapter {
+ protected static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11InputMethod");
/*
* The following XIM* values must be the same as those defined in
* Xlib.h
*/
private static final int XIMReverse = (1<<0);
@@ -75,59 +74,57 @@
private static final int XIMTertiary = (1<<7);
/*
* visible position values
*/
- private static final int XIMVisibleToForward = (1<<8);
- private static final int XIMVisibleToBackward = (1<<9);
- private static final int XIMVisibleCenter = (1<<10);
- private static final int XIMVisibleMask = (XIMVisibleToForward|
- XIMVisibleToBackward|
- XIMVisibleCenter);
+ protected static final int XIMVisibleToForward = (1<<8);
+ protected static final int XIMVisibleToBackward = (1<<9);
+ protected static final int XIMVisibleCenter = (1<<10);
+ protected static final int XIMVisibleMask =
+ (XIMVisibleToForward | XIMVisibleToBackward | XIMVisibleCenter);
private Locale locale;
private static boolean isXIMOpened = false;
protected Container clientComponentWindow = null;
- private Component awtFocussedComponent = null;
- private Component lastXICFocussedComponent = null;
- private boolean isLastXICActive = false;
- private boolean isLastTemporary = false;
- private boolean isActive = false;
- private boolean isActiveClient = false;
+ protected Component awtFocussedComponent = null;
+ protected Component lastXICFocussedComponent = null;
+ protected boolean isLastXICActive = false;
+ protected boolean isLastTemporary = false;
+ protected boolean isActive = false;
private static Map<TextAttribute, ?>[] highlightStyles;
- private boolean disposed = false;
+ protected boolean disposed = false;
//reset the XIC if necessary
- private boolean needResetXIC = false;
+ protected boolean needResetXIC = false;
private WeakReference<Component> needResetXICClient = new WeakReference<>(null);
// The use of compositionEnableSupported is to reduce unnecessary
// native calls if set/isCompositionEnabled
// throws UnsupportedOperationException.
// It is set to false if that exception is thrown first time
// either of the two methods are called.
- private boolean compositionEnableSupported = true;
+ protected boolean compositionEnableSupported = true;
// The savedCompositionState indicates the composition mode when
// endComposition or setCompositionEnabled is called. It doesn't always
// reflect the actual composition state because it doesn't get updated
// when the user changes the composition state through direct interaction
// with the input method. It is used to save the composition mode when
// focus is traversed across different client components sharing the
// same java input context. Also if set/isCompositionEnabled are not
// supported, it remains false.
- private boolean savedCompositionState = false;
+ protected boolean savedCompositionState = false;
// variables to keep track of preedit context.
// these variables need to be accessed within AWT_LOCK/UNLOCK
- private String committedText = null;
- private StringBuffer composedText = null;
- private IntBuffer rawFeedbacks;
+ protected String committedText = null;
+ protected StringBuffer composedText = null;
+ protected IntBuffer rawFeedbacks;
// private data (X11InputMethodData structure defined in
// awt_InputMethod.c) for native methods
// this structure needs to be accessed within AWT_LOCK/UNLOCK
- private transient long pData = 0; // accessed by native
+ protected transient long pData = 0; // accessed by native
// Initialize highlight mapping table
static {
@SuppressWarnings({"unchecked", "rawtypes"})
Map<TextAttribute, ?> styles[] = new Map[4];
@@ -160,22 +157,16 @@
static {
initIDs();
}
/**
- * Initialize JNI field and method IDs for fields that may be
- accessed from C.
- */
- private static native void initIDs();
-
- /**
* Constructs an X11InputMethod instance. It initializes the XIM
* environment if it's not done yet.
*
* @exception AWTException if XOpenIM() failed.
*/
- public X11InputMethod() throws AWTException {
+ public X11InputMethodBase() throws AWTException {
// supports only the locale in which the VM is started
locale = X11InputMethodDescriptor.getSupportedLocale();
if (initXIM() == false) {
throw new AWTException("Cannot open X Input Method");
}
@@ -256,11 +247,10 @@
* @param e event
*/
public void dispatchEvent(AWTEvent e) {
}
-
protected final void resetXICifneeded(){
/* needResetXIC is used to indicate whether to call
resetXIC on the active client. resetXIC will always be
called on the passive client when endComposition is called.
*/
@@ -278,28 +268,18 @@
}
/**
* Reset the composition state to the current composition state.
*/
- private void resetCompositionState() {
- if (compositionEnableSupported) {
- try {
- /* Restore the composition mode to the last saved composition
- mode. */
- setCompositionEnabled(savedCompositionState);
- } catch (UnsupportedOperationException e) {
- compositionEnableSupported = false;
- }
- }
- }
+ protected abstract void resetCompositionState();
/**
* Query and then return the current composition state.
* @return the composition state if isCompositionEnabled call
* is successful. Otherwise, it returns false.
*/
- private boolean getCompositionState() {
+ protected boolean getCompositionState() {
boolean compositionState = false;
if (compositionEnableSupported) {
try {
compositionState = isCompositionEnabled();
} catch (UnsupportedOperationException e) {
@@ -310,98 +290,18 @@
}
/**
* Activate input method.
*/
- public synchronized void activate() {
- clientComponentWindow = getClientComponentWindow();
- if (clientComponentWindow == null)
- return;
-
- if (lastXICFocussedComponent != null){
- if (log.isLoggable(PlatformLogger.Level.FINE)) {
- log.fine("XICFocused {0}, AWTFocused {1}",
- lastXICFocussedComponent, awtFocussedComponent);
- }
- }
-
- if (pData == 0) {
- if (!createXIC()) {
- return;
- }
- disposed = false;
- }
-
- /* reset input context if necessary and set the XIC focus
- */
- resetXICifneeded();
- ComponentPeer lastXICFocussedComponentPeer = null;
- ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent);
-
- if (lastXICFocussedComponent != null) {
- lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent);
- }
-
- /* If the last XIC focussed component has a different peer as the
- current focussed component, change the XIC focus to the newly
- focussed component.
- */
- if (isLastTemporary || lastXICFocussedComponentPeer != awtFocussedComponentPeer ||
- isLastXICActive != haveActiveClient()) {
- if (lastXICFocussedComponentPeer != null) {
- setXICFocus(lastXICFocussedComponentPeer, false, isLastXICActive);
- }
- if (awtFocussedComponentPeer != null) {
- setXICFocus(awtFocussedComponentPeer, true, haveActiveClient());
- }
- lastXICFocussedComponent = awtFocussedComponent;
- isLastXICActive = haveActiveClient();
- }
- resetCompositionState();
- isActive = true;
- }
+ public abstract void activate();
protected abstract boolean createXIC();
/**
* Deactivate input method.
*/
- public synchronized void deactivate(boolean isTemporary) {
- boolean isAc = haveActiveClient();
- /* Usually as the client component, let's call it component A,
- loses the focus, this method is called. Then when another client
- component, let's call it component B, gets the focus, activate is first called on
- the previous focused compoent which is A, then endComposition is called on A,
- deactivate is called on A again. And finally activate is called on the newly
- focused component B. Here is the call sequence.
-
- A loses focus B gains focus
- -------------> deactivate A -------------> activate A -> endComposition A ->
- deactivate A -> activate B ----....
-
- So in order to carry the composition mode across the components sharing the same
- input context, we save it when deactivate is called so that when activate is
- called, it can be restored correctly till activate is called on the newly focused
- component. (See also sun/awt/im/InputContext and bug 6184471).
- Last note, getCompositionState should be called before setXICFocus since
- setXICFocus here sets the XIC to 0.
- */
- savedCompositionState = getCompositionState();
-
- if (isTemporary){
- //turn the status window off...
- turnoffStatusWindow();
- }
-
- /* Delay resetting the XIC focus until activate is called and the newly
- focussed component has a different peer as the last focussed component.
- */
- lastXICFocussedComponent = awtFocussedComponent;
- isLastXICActive = isAc;
- isLastTemporary = isTemporary;
- isActive = false;
- }
+ public abstract void deactivate(boolean isTemporary);
/**
* Explicitly disable the native IME. Native IME is not disabled when
* deactivate is called.
*/
@@ -416,13 +316,11 @@
needResetXIC = false;
}
}
// implements java.awt.im.spi.InputMethod.hideWindows
- public void hideWindows() {
- // ??? need real implementation
- }
+ public abstract void hideWindows();
/**
* @see java.awt.Toolkit#mapInputMethodHighlight
*/
public static Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) {
@@ -482,11 +380,11 @@
* Returns the Window instance in which the client component is
* contained. If not found, null is returned. (IS THIS POSSIBLE?)
*/
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
- private Window getClientComponentWindow() {
+ protected Window getClientComponentWindow() {
Component client = getClientComponent();
Container container;
if (client instanceof Container) {
container = (Container) client;
@@ -519,11 +417,11 @@
* and posts it on the AWT event queue. For arguments,
* see InputMethodEvent. Called by input method.
*
* @see java.awt.event.InputMethodEvent#InputMethodEvent
*/
- private void postInputMethodEvent(int id,
+ protected void postInputMethodEvent(int id,
AttributedCharacterIterator text,
int committedCharacterCount,
TextHitInfo caret,
TextHitInfo visiblePosition,
long when) {
@@ -589,157 +487,16 @@
*/
// NOTE: This method may be called by privileged threads.
// This functionality is implemented in a package-private method
// to insure that it cannot be overridden by client subclasses.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
- void dispatchComposedText(String chgText,
+ abstract void dispatchComposedText(String chgText,
int chgStyles[],
int chgOffset,
int chgLength,
int caretPosition,
- long when) {
- if (disposed) {
- return;
- }
-
- //Workaround for deadlock bug on solaris2.6_zh bug#4170760
- if (chgText == null
- && chgStyles == null
- && chgOffset == 0
- && chgLength == 0
- && caretPosition == 0
- && composedText == null
- && committedText == null)
- return;
-
- if (composedText == null) {
- // TODO: avoid reallocation of those buffers
- composedText = new StringBuffer(INITIAL_SIZE);
- rawFeedbacks = new IntBuffer(INITIAL_SIZE);
- }
- if (chgLength > 0) {
- if (chgText == null && chgStyles != null) {
- rawFeedbacks.replace(chgOffset, chgStyles);
- } else {
- if (chgLength == composedText.length()) {
- // optimization for the special case to replace the
- // entire previous text
- composedText = new StringBuffer(INITIAL_SIZE);
- rawFeedbacks = new IntBuffer(INITIAL_SIZE);
- } else {
- if (composedText.length() > 0) {
- if (chgOffset+chgLength < composedText.length()) {
- String text;
- text = composedText.toString().substring(chgOffset+chgLength,
- composedText.length());
- composedText.setLength(chgOffset);
- composedText.append(text);
- } else {
- // in case to remove substring from chgOffset
- // to the end
- composedText.setLength(chgOffset);
- }
- rawFeedbacks.remove(chgOffset, chgLength);
- }
- }
- }
- }
- if (chgText != null) {
- composedText.insert(chgOffset, chgText);
- if (chgStyles != null)
- rawFeedbacks.insert(chgOffset, chgStyles);
- }
-
- if (composedText.length() == 0) {
- composedText = null;
- rawFeedbacks = null;
-
- // if there is any outstanding committed text stored by
- // dispatchCommittedText(), it has to be sent to the
- // client component.
- if (committedText != null) {
- dispatchCommittedText(committedText, when);
- committedText = null;
- return;
- }
-
- // otherwise, send null text to delete client's composed
- // text.
- postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
- null,
- 0,
- null,
- null,
- when);
-
- return;
- }
-
- // Now sending the composed text to the client
- int composedOffset;
- AttributedString inputText;
-
- // if there is any partially committed text, concatenate it to
- // the composed text.
- if (committedText != null) {
- composedOffset = committedText.length();
- inputText = new AttributedString(committedText + composedText);
- committedText = null;
- } else {
- composedOffset = 0;
- inputText = new AttributedString(composedText.toString());
- }
-
- int currentFeedback;
- int nextFeedback;
- int startOffset = 0;
- int currentOffset;
- int visiblePosition = 0;
- TextHitInfo visiblePositionInfo = null;
-
- rawFeedbacks.rewind();
- currentFeedback = rawFeedbacks.getNext();
- rawFeedbacks.unget();
- while ((nextFeedback = rawFeedbacks.getNext()) != -1) {
- if (visiblePosition == 0) {
- visiblePosition = nextFeedback & XIMVisibleMask;
- if (visiblePosition != 0) {
- int index = rawFeedbacks.getOffset() - 1;
-
- if (visiblePosition == XIMVisibleToBackward)
- visiblePositionInfo = TextHitInfo.leading(index);
- else
- visiblePositionInfo = TextHitInfo.trailing(index);
- }
- }
- nextFeedback &= ~XIMVisibleMask;
- if (currentFeedback != nextFeedback) {
- rawFeedbacks.unget();
- currentOffset = rawFeedbacks.getOffset();
- inputText.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
- convertVisualFeedbackToHighlight(currentFeedback),
- composedOffset + startOffset,
- composedOffset + currentOffset);
- startOffset = currentOffset;
- currentFeedback = nextFeedback;
- }
- }
- currentOffset = rawFeedbacks.getOffset();
- if (currentOffset >= 0) {
- inputText.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
- convertVisualFeedbackToHighlight(currentFeedback),
- composedOffset + startOffset,
- composedOffset + currentOffset);
- }
-
- postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
- inputText.getIterator(),
- composedOffset,
- TextHitInfo.leading(caretPosition),
- visiblePositionInfo,
- when);
- }
+ long when);
/**
* Flushes composed and committed text held in this context.
* This method is invoked in the AWT Toolkit (X event loop) thread context
* and thus inside the AWT Lock.
@@ -769,20 +526,11 @@
/*
* Subclasses should override disposeImpl() instead of dispose(). Client
* code should always invoke dispose(), never disposeImpl().
*/
- protected synchronized void disposeImpl() {
- disposeXIC();
- awtLock();
- composedText = null;
- committedText = null;
- rawFeedbacks = null;
- awtUnlock();
- awtFocussedComponent = null;
- lastXICFocussedComponent = null;
- }
+ protected abstract void disposeImpl();
/**
* Frees all X Window resources associated with this object.
*
* @see java.awt.im.spi.InputMethod#dispose
@@ -820,23 +568,11 @@
}
/**
* @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean)
*/
- public void setCompositionEnabled(boolean enable) {
- /* If the composition state is successfully changed, set
- the savedCompositionState to 'enable'. Otherwise, simply
- return.
- setCompositionEnabledNative may throw UnsupportedOperationException.
- Don't try to catch it since the method may be called by clients.
- Use package private mthod 'resetCompositionState' if you want the
- exception to be caught.
- */
- if (setCompositionEnabledNative(enable)) {
- savedCompositionState = enable;
- }
- }
+ public abstract void setCompositionEnabled(boolean enable);
/**
* @see java.awt.im.spi.InputMethod#isCompositionEnabled
*/
public boolean isCompositionEnabled() {
@@ -888,21 +624,25 @@
// dispatchComposedText call from X input method engine, but some
// input method does not conform to the XIM specification and does
// not call the preedit callback to erase preedit text on calling
// XmbResetIC. To work around this problem, do it here by ourselves.
awtLock();
- composedText = null;
- postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
- null,
- 0,
- null,
- null);
+ try {
+ composedText = null;
+ postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
+ null,
+ 0,
+ null,
+ null);
- if (text != null && text.length() > 0) {
- dispatchCommittedText(text);
+ if (text != null && text.length() > 0) {
+ dispatchCommittedText(text);
+ }
+ } finally {
+ // Put awtUnlock into finally block in case an exception is thrown.
+ awtUnlock();
}
- awtUnlock();
// Restore the preedit state if it was enabled
if (savedCompositionState) {
resetCompositionState();
}
@@ -972,11 +712,11 @@
/**
* Performs mapping from an XIM visible feedback value to Java IM highlight.
* @return Java input method highlight
*/
- private InputMethodHighlight convertVisualFeedbackToHighlight(int feedback) {
+ protected InputMethodHighlight convertVisualFeedbackToHighlight(int feedback) {
InputMethodHighlight highlight;
switch (feedback) {
case XIMUnderline:
highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
@@ -985,10 +725,11 @@
highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
break;
case XIMHighlight:
highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
break;
+ case 0: //None of the values are set by Wnn
case XIMPrimary:
highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
break;
case XIMSecondary:
highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
@@ -1002,19 +743,19 @@
}
return highlight;
}
// initial capacity size for string buffer, etc.
- private static final int INITIAL_SIZE = 64;
+ protected static final int INITIAL_SIZE = 64;
/**
* IntBuffer is an inner class that manipulates an int array and
* provides UNIX file io stream-like programming interfaces to
* access it. (An alternative would be to use ArrayList which may
* be too expensive for the work.)
*/
- private final class IntBuffer {
+ protected final class IntBuffer {
private int[] intArray;
private int size;
private int index;
IntBuffer(int initialCapacity) {
@@ -1087,11 +828,22 @@
}
/*
* Native methods
*/
+
+ /**
+ * Initialize JNI field and method IDs for fields that may be
+ * accessed from C.
+ */
+ private static native void initIDs();
+
+ protected native void turnoffStatusWindow();
+
+ protected native void disposeXIC();
+
private native String resetXIC();
- private native void disposeXIC();
- private native boolean setCompositionEnabledNative(boolean enable);
+
+ protected native boolean setCompositionEnabledNative(boolean enable);
+
private native boolean isCompositionEnabledNative();
- private native void turnoffStatusWindow();
}
< prev index next >