< 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 >