< prev index next >

src/java.desktop/aix/classes/sun/awt/X11InputMethod.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,267 +23,45 @@
  * 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.peer.ComponentPeer;
-import java.lang.Character.Subset;
 import java.text.AttributedString;
-import java.text.AttributedCharacterIterator;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.lang.ref.WeakReference;
 import sun.util.logging.PlatformLogger;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-
 
 /**
- * Input Method Adapter for XIM
+ * Input Method Adapter for XIM for AIX
  *
  * @author JavaSoft International
  */
-public abstract class X11InputMethod extends InputMethodAdapter {
-    private 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);
-    private static final int XIMUnderline = (1<<1);
-    private static final int XIMHighlight = (1<<2);
-    private static final int XIMPrimary = (1<<5);
-    private static final int XIMSecondary = (1<<6);
-    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);
-
-    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;
-    private static Map<TextAttribute, ?>[] highlightStyles;
-    private boolean disposed = false;
-
-    //reset the XIC if necessary
-    private 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;
-    // 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;
-
-    // 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;
-
-    // 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
-
-    // Initialize highlight mapping table
-    static {
-        @SuppressWarnings({"unchecked", "rawtypes"})
-        Map<TextAttribute, ?> styles[] = new Map[4];
-        HashMap<TextAttribute, Object> map;
-
-        // UNSELECTED_RAW_TEXT_HIGHLIGHT
-        map = new HashMap<>(1);
-        map.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
-        styles[0] = Collections.unmodifiableMap(map);
-
-        // SELECTED_RAW_TEXT_HIGHLIGHT
-        map = new HashMap<>(1);
-        map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON);
-        styles[1] = Collections.unmodifiableMap(map);
-
-        // UNSELECTED_CONVERTED_TEXT_HIGHLIGHT
-        map = new HashMap<>(1);
-        map.put(TextAttribute.INPUT_METHOD_UNDERLINE,
-                TextAttribute.UNDERLINE_LOW_ONE_PIXEL);
-        styles[2] = Collections.unmodifiableMap(map);
-
-        // SELECTED_CONVERTED_TEXT_HIGHLIGHT
-        map = new HashMap<>(1);
-        map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON);
-        styles[3] = Collections.unmodifiableMap(map);
-
-        highlightStyles = styles;
-    }
-
-    static {
-        initIDs();
-    }
+public abstract class X11InputMethod extends X11InputMethodBase {
 
-    /**
-     * Initialize JNI field and method IDs for fields that may be
-       accessed from C.
-     */
-    private static native void initIDs();
+    // to keep the instance of activating if IM resumed
+    static protected X11InputMethod activatedInstance = null;
 
     /**
      * Constructs an X11InputMethod instance. It initializes the XIM
      * environment if it's not done yet.
      *
      * @exception AWTException if XOpenIM() failed.
      */
     public X11InputMethod() 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");
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    protected void finalize() throws Throwable {
-        dispose();
-        super.finalize();
-    }
-
-    /**
-     * Invokes openIM() that invokes XOpenIM() if it's not opened yet.
-     * @return  true if openXIM() is successful or it's already been opened.
-     */
-    private synchronized boolean initXIM() {
-        if (isXIMOpened == false)
-            isXIMOpened = openXIM();
-        return isXIMOpened;
-    }
-
-    protected abstract boolean openXIM();
-
-    protected boolean isDisposed() {
-        return disposed;
-    }
-
-    protected abstract void setXICFocus(ComponentPeer peer,
-                                    boolean value, boolean active);
-
-    /**
-     * Does nothing - this adapter doesn't use the input method context.
-     *
-     * @see java.awt.im.spi.InputMethod#setInputMethodContext
-     */
-    public void setInputMethodContext(InputMethodContext context) {
-    }
-
-    /**
-     * Set locale to input. If input method doesn't support specified locale,
-     * false will be returned and its behavior is not changed.
-     *
-     * @param lang locale to input
-     * @return the true is returned when specified locale is supported.
-     */
-    public boolean setLocale(Locale lang) {
-        if (lang.equals(locale)) {
-            return true;
-        }
-        // special compatibility rule for Japanese and Korean
-        if (locale.equals(Locale.JAPAN) && lang.equals(Locale.JAPANESE) ||
-                locale.equals(Locale.KOREA) && lang.equals(Locale.KOREAN)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns current input locale.
-     */
-    public Locale getLocale() {
-        return locale;
-    }
-
-    /**
-     * Does nothing - XIM doesn't let you specify which characters you expect.
-     *
-     * @see java.awt.im.spi.InputMethod#setCharacterSubsets
-     */
-    public void setCharacterSubsets(Subset[] subsets) {
-    }
-
-    /**
-     * Dispatch event to input method. InputContext dispatch event with this
-     * method. Input method set consume flag if event is consumed in
-     * input method.
-     *
-     * @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.
-        */
-        if (needResetXIC && haveActiveClient() &&
-            getClientComponent() != needResetXICClient.get()){
-            resetXIC();
-
-            // needs to reset the last xic focussed component.
-            lastXICFocussedComponent = null;
-            isLastXICActive = false;
-
-            needResetXICClient.clear();
-            needResetXIC = false;
-        }
+        super();
     }
 
     /**
      * Reset the composition state to the current composition state.
      */
-    private void resetCompositionState() {
-        if (compositionEnableSupported) {
+    protected void resetCompositionState() {
+        if (compositionEnableSupported && haveActiveClient()) {
             try {
                 /* Restore the composition mode to the last saved composition
                    mode. */
                 setCompositionEnabled(savedCompositionState);
             } catch (UnsupportedOperationException e) {

@@ -291,39 +69,30 @@
             }
         }
     }
 
     /**
-     * Query and then return the current composition state.
-     * @return the composition state if isCompositionEnabled call
-     * is successful. Otherwise, it returns false.
-     */
-    private boolean getCompositionState() {
-        boolean compositionState = false;
-        if (compositionEnableSupported) {
-            try {
-                compositionState = isCompositionEnabled();
-            } catch (UnsupportedOperationException e) {
-                compositionEnableSupported = false;
-            }
-        }
-        return compositionState;
-    }
-
-    /**
      * Activate input method.
      */
     public synchronized void activate() {
+        activatedInstance = this;
         clientComponentWindow = getClientComponentWindow();
         if (clientComponentWindow == null)
             return;
 
-        if (lastXICFocussedComponent != null){
+        if (lastXICFocussedComponent != null) {
             if (log.isLoggable(PlatformLogger.Level.FINE)) {
                 log.fine("XICFocused {0}, AWTFocused {1}",
                          lastXICFocussedComponent, awtFocussedComponent);
             }
+            if (lastXICFocussedComponent != awtFocussedComponent) {
+                ComponentPeer lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent);
+                if (lastXICFocussedComponentPeer != null) {
+                    setXICFocus(lastXICFocussedComponentPeer, false, isLastXICActive);
+                }
+            }
+            lastXICFocussedComponent = null;
         }
 
         if (pData == 0) {
             if (!createXIC()) {
                 return;

@@ -332,38 +101,24 @@
         }
 
         /*  reset input context if necessary and set the XIC focus
         */
         resetXICifneeded();
-        ComponentPeer lastXICFocussedComponentPeer = null;
         ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent);
+        setStatusAreaVisible(true, pData);
 
-        if (lastXICFocussedComponent != null) {
-           lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent);
+        if (awtFocussedComponentPeer != null) {
+            setXICFocus(awtFocussedComponentPeer, true, haveActiveClient());
         }
-
-        /* 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();
+        lastXICFocussedComponent = awtFocussedComponent;
+        isLastXICActive = haveActiveClient();
         isActive = true;
+        if (savedCompositionState) {
+            resetCompositionState();
+        }
     }
 
-    protected abstract boolean createXIC();
-
     /**
      * Deactivate input method.
      */
     public synchronized void deactivate(boolean isTemporary) {
         boolean   isAc =  haveActiveClient();

@@ -383,203 +138,44 @@
            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.
         */
+        activatedInstance = null;
         savedCompositionState = getCompositionState();
 
-        if (isTemporary){
+        if (isTemporary) {
             //turn the status window off...
             turnoffStatusWindow();
+            /* Delay resetting the XIC focus until activate is called and the newly
+             * Focused component has a different peer as the last focused component.
+             */
+            lastXICFocussedComponent = awtFocussedComponent;
+        } else {
+            if (awtFocussedComponent != null ) {
+                ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent);
+                if (awtFocussedComponentPeer != null) {
+                    setXICFocus(awtFocussedComponentPeer, false, isAc);
+                }
+            }
+            lastXICFocussedComponent = null;
         }
 
-        /* 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;
-    }
-
-    /**
-     * Explicitly disable the native IME. Native IME is not disabled when
-     * deactivate is called.
-     */
-    public void disableInputMethod() {
-        if (lastXICFocussedComponent != null) {
-            setXICFocus(getPeer(lastXICFocussedComponent), false, isLastXICActive);
-            lastXICFocussedComponent = null;
-            isLastXICActive = false;
-
-            resetXIC();
-            needResetXICClient.clear();
-            needResetXIC = false;
-        }
+        setStatusAreaVisible(false, pData);
     }
 
     // implements java.awt.im.spi.InputMethod.hideWindows
     public void hideWindows() {
-        // ??? need real implementation
-    }
-
-    /**
-     * @see java.awt.Toolkit#mapInputMethodHighlight
-     */
-    public static Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) {
-        int index;
-        int state = highlight.getState();
-        if (state == InputMethodHighlight.RAW_TEXT) {
-            index = 0;
-        } else if (state == InputMethodHighlight.CONVERTED_TEXT) {
-            index = 2;
-        } else {
-            return null;
-        }
-        if (highlight.isSelected()) {
-            index += 1;
-        }
-        return highlightStyles[index];
-    }
-
-    /**
-     * @see sun.awt.im.InputMethodAdapter#setAWTFocussedComponent
-     */
-    protected void setAWTFocussedComponent(Component component) {
-        if (component == null) {
-            return;
-        }
-        if (isActive) {
-            // deactivate/activate are being suppressed during a focus change -
-            // this may happen when an input method window is made visible
-            boolean ac = haveActiveClient();
-            setXICFocus(getPeer(awtFocussedComponent), false, ac);
-            setXICFocus(getPeer(component), true, ac);
-        }
-        awtFocussedComponent = component;
-    }
-
-    /**
-     * @see sun.awt.im.InputMethodAdapter#stopListening
-     */
-    protected void stopListening() {
-        // It is desirable to disable XIM by calling XSetICValues with
-        // XNPreeditState == XIMPreeditDisable.  But Solaris 2.6 and
-        // Solaris 7 do not implement this correctly without a patch,
-        // so just call resetXIC here.  Prior endComposition call commits
-        // the existing composed text.
-        endComposition();
-        // disable the native input method so that the other input
-        // method could get the input focus.
-        disableInputMethod();
-        if (needResetXIC) {
-            resetXIC();
-            needResetXICClient.clear();
-            needResetXIC = false;
-        }
-    }
-
-    /**
-     * 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() {
-        Component client = getClientComponent();
-        Container container;
-
-        if (client instanceof Container) {
-            container = (Container) client;
-        } else {
-            container = getParent(client);
-        }
-
-        while (container != null && !(container instanceof java.awt.Window)) {
-            container = getParent(container);
-        }
-        return (Window) container;
-    }
-
-    protected abstract Container getParent(Component client);
-
-    /**
-     * Returns peer of the given client component. If the given client component
-     * doesn't have peer, peer of the native container of the client is returned.
-     */
-    protected abstract ComponentPeer getPeer(Component client);
-
-    /**
-     * Used to protect preedit data
-     */
-    protected abstract void awtLock();
-    protected abstract void awtUnlock();
-
-    /**
-     * Creates an input method event from the arguments given
-     * 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,
-                                      AttributedCharacterIterator text,
-                                      int committedCharacterCount,
-                                      TextHitInfo caret,
-                                      TextHitInfo visiblePosition,
-                                      long when) {
-        Component source = getClientComponent();
-        if (source != null) {
-            InputMethodEvent event = new InputMethodEvent(source,
-                id, when, text, committedCharacterCount, caret, visiblePosition);
-            SunToolkit.postEvent(SunToolkit.targetToAppContext(source), (AWTEvent)event);
-        }
-    }
-
-    private void postInputMethodEvent(int id,
-                                      AttributedCharacterIterator text,
-                                      int committedCharacterCount,
-                                      TextHitInfo caret,
-                                      TextHitInfo visiblePosition) {
-        postInputMethodEvent(id, text, committedCharacterCount,
-                             caret, visiblePosition, EventQueue.getMostRecentEventTime());
-    }
-
-    /**
-     * Dispatches committed text from XIM to the awt event queue. This
-     * method is invoked from the event handler in canvas.c in the
-     * AWT Toolkit thread context and thus inside the AWT Lock.
-     * @param   str     committed text
-     * @param   when    when
-     */
-    // 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 dispatchCommittedText(String str, long when) {
-        if (str == null)
-            return;
-
-        if (composedText == null) {
-            AttributedString attrstr = new AttributedString(str);
-            postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
-                                 attrstr.getIterator(),
-                                 str.length(),
-                                 null,
-                                 null,
-                                 when);
-        } else {
-            // if there is composed text, wait until the preedit
-            // callback is invoked.
-            committedText = str;
+        if (pData != 0) {
+            setStatusAreaVisible(false, pData);
+            turnoffStatusWindow();
         }
     }
 
-    private void dispatchCommittedText(String str) {
-        dispatchCommittedText(str, EventQueue.getMostRecentEventTime());
-    }
-
     /**
      * Updates composed text with XIM preedit information and
      * posts composed text to the awt event queue. The args of
      * this method correspond to the XIM preedit callback
      * information. The XIM highlight attributes are translated via

@@ -599,20 +195,55 @@
                                            long when) {
         if (disposed) {
             return;
         }
 
-        //Workaround for deadlock bug on solaris2.6_zh bug#4170760
+        // 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;
 
+        // Recalculate chgOffset and chgLength for supplementary char
+        if (composedText != null) {
+            int tmpChgOffset=chgOffset;
+            int tmpChgLength=chgLength;
+            int index = 0;
+            for (int i=0;i < tmpChgOffset; i++,index++){
+                if (index < composedText.length()
+                    && Character.charCount(composedText.codePointAt(index))==2){
+                    index++;
+                    chgOffset++;
+                }
+            }
+            // The index keeps value
+            for (int i=0;i < tmpChgLength; i++,index++){
+                if (index < composedText.length()
+                    && Character.charCount(composedText.codePointAt(index))==2){
+                    index++;
+                    chgLength++;
+                }
+            }
+        }
+
+        // Replace control character with a square box
+        if (chgText != null) {
+            StringBuffer newChgText = new StringBuffer();
+            for (int i=0; i < chgText.length(); i++){
+                char c = chgText.charAt(i);
+                if (Character.isISOControl(c)){
+                    c = '\u25A1';
+                }
+                newChgText.append(c);
+            }
+            chgText = new String(newChgText);
+        }
+
         if (composedText == null) {
             // TODO: avoid reallocation of those buffers
             composedText = new StringBuffer(INITIAL_SIZE);
             rawFeedbacks = new IntBuffer(INITIAL_SIZE);
         }

@@ -643,12 +274,51 @@
                 }
             }
         }
         if (chgText != null) {
             composedText.insert(chgOffset, chgText);
-            if (chgStyles != null)
+            if (chgStyles != null) {
+                // Recalculate chgStyles for supplementary char
+                if (chgText.length() > chgStyles.length){
+                    int index=0;
+                    int[] newStyles = new int[chgText.length()];
+                    for (int i=0; i < chgStyles.length; i++, index++){
+                        newStyles[index]=chgStyles[i];
+                        if (index < chgText.length()
+                            && Character.charCount(chgText.codePointAt(index))==2){
+                            newStyles[++index]=chgStyles[i];
+                        }
+                    }
+                    chgStyles=newStyles;
+                }
                 rawFeedbacks.insert(chgOffset, chgStyles);
+            }
+
+        }
+
+        else if (chgStyles != null) {
+            // Recalculate chgStyles to support supplementary char
+            int count=0;
+            for (int i=0; i < chgStyles.length; i++){
+                if (composedText.length() > chgOffset+i+count
+                    && Character.charCount(composedText.codePointAt(chgOffset+i+count))==2){
+                    count++;
+                }
+            }
+            if (count>0){
+                int index=0;
+                int[] newStyles = new int[chgStyles.length+count];
+                for (int i=0; i < chgStyles.length; i++, index++){
+                    newStyles[index]=chgStyles[i];
+                    if (composedText.length() > chgOffset+index
+                        && Character.charCount(composedText.codePointAt(chgOffset+index))==2){
+                        newStyles[++index]=chgStyles[i];
+                    }
+                }
+                chgStyles=newStyles;
+            }
+            rawFeedbacks.replace(chgOffset, chgStyles);
         }
 
         if (composedText.length() == 0) {
             composedText = null;
             rawFeedbacks = null;

@@ -672,10 +342,19 @@
                                  when);
 
             return;
         }
 
+        // Adjust caretPosition for supplementary char
+        for (int i=0; i< caretPosition; i++){
+            if (i < composedText.length()
+                && Character.charCount(composedText.codePointAt(i))==2){
+                caretPosition++;
+                i++;
+            }
+        }
+
         // Now sending the composed text to the client
         int composedOffset;
         AttributedString inputText;
 
         // if there is any partially committed text, concatenate it to

@@ -737,88 +416,47 @@
                              TextHitInfo.leading(caretPosition),
                              visiblePositionInfo,
                              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.
-     */
-    // 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 flushText() {
-        String flush = (committedText != null ? committedText : "");
-        if (composedText != null) {
-            flush += composedText.toString();
+    /* Some IMs need forced Text clear */
+    void clearComposedText(long when) {
+        composedText = null;
+        postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
+                             null, 0, null, null,
+                             when);
+        if (committedText != null && committedText.length() > 0) {
+            dispatchCommittedText(committedText, when);
         }
+        committedText = null;
+        rawFeedbacks = null;
+    }
 
-        if (!flush.equals("")) {
-            AttributedString attrstr = new AttributedString(flush);
-            postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
-                                 attrstr.getIterator(),
-                                 flush.length(),
-                                 null,
-                                 null,
-                                 EventQueue.getMostRecentEventTime());
-            composedText = null;
-            committedText = null;
+    void clearComposedText() {
+        if (EventQueue.isDispatchThread()) {
+            clearComposedText(EventQueue.getMostRecentEventTime());
         }
     }
 
     /*
      * 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();
+        try {
+            clearComposedText();
+        } finally {
+            // Put awtUnlock into finally block in case an exception is thrown in clearComposedText.
+            awtUnlock();
+        }
         awtFocussedComponent = null;
         lastXICFocussedComponent = null;
-    }
-
-    /**
-     * Frees all X Window resources associated with this object.
-     *
-     * @see java.awt.im.spi.InputMethod#dispose
-     */
-    public final void dispose() {
-        boolean call_disposeImpl = false;
-
-        if (!disposed) {
-            synchronized (this) {
-                if (!disposed) {
-                    disposed = call_disposeImpl = true;
-                }
-            }
-        }
-
-        if (call_disposeImpl) {
-            disposeImpl();
-        }
-    }
-
-    /**
-     * Returns null.
-     *
-     * @see java.awt.im.spi.InputMethod#getControlObject
-     */
-    public Object getControlObject() {
-        return null;
-    }
-
-    /**
-     * @see java.awt.im.spi.InputMethod#removeNotify
-     */
-    public synchronized void removeNotify() {
-        dispose();
+        needResetXIC = false;
+        savedCompositionState = false;
+        compositionEnableSupported = true;
     }
 
     /**
      * @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean)
      */

@@ -829,269 +467,24 @@
            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.
         */
+        boolean pre, post;
+        pre=getCompositionState();
+
         if (setCompositionEnabledNative(enable)) {
             savedCompositionState = enable;
         }
-    }
-
-    /**
-     * @see java.awt.im.spi.InputMethod#isCompositionEnabled
-     */
-    public boolean isCompositionEnabled() {
-        /* isCompositionEnabledNative may throw UnsupportedOperationException.
-           Don't try to catch it since this method may be called by clients.
-           Use package private method 'getCompositionState' if you want the
-           exception to be caught.
-        */
-        return isCompositionEnabledNative();
-    }
-
-    /**
-     * Ends any input composition that may currently be going on in this
-     * context. Depending on the platform and possibly user preferences,
-     * this may commit or delete uncommitted text. Any changes to the text
-     * are communicated to the active component using an input method event.
-     *
-     * <p>
-     * A text editing component may call this in a variety of situations,
-     * for example, when the user moves the insertion point within the text
-     * (but outside the composed text), or when the component's text is
-     * saved to a file or copied to the clipboard.
-     *
-     */
-    public void endComposition() {
-        if (disposed) {
-            return;
-        }
-
-        /* Before calling resetXIC, record the current composition mode
-           so that it can be restored later. */
-        savedCompositionState = getCompositionState();
-        boolean active = haveActiveClient();
-        if (active && composedText == null && committedText == null){
-            needResetXIC = true;
-            needResetXICClient = new WeakReference<>(getClientComponent());
-            return;
-        }
-
-        String text = resetXIC();
-        /* needResetXIC is only set to true for active client. So passive
-           client should not reset the flag to false. */
-        if (active) {
-            needResetXIC = false;
-        }
 
-        // Remove any existing composed text by posting an InputMethodEvent
-        // with null composed text.  It would be desirable to wait for a
-        // 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);
-
-        if (text != null && text.length() > 0) {
-            dispatchCommittedText(text);
-        }
-        awtUnlock();
-
-        // Restore the preedit state if it was enabled
-        if (savedCompositionState) {
-            resetCompositionState();
-        }
-    }
-
-    /**
-     * Returns a string with information about the current input method server, or null.
-     * On both Linux & SunOS, the value of environment variable XMODIFIERS is
-     * returned if set. Otherwise, on SunOS, $HOME/.dtprofile will be parsed
-     * to find out the language service engine (atok or wnn) since there is
-     * no API in Xlib which returns the information of native
-     * IM server or language service and we want to try our best to return as much
-     * information as possible.
-     *
-     * Note: This method could return null on Linux if XMODIFIERS is not set properly or
-     * if any IOException is thrown.
-     * See man page of XSetLocaleModifiers(3X11) for the usgae of XMODIFIERS,
-     * atok12setup(1) and wnn6setup(1) for the information written to
-     * $HOME/.dtprofile when you run these two commands.
-     *
-     */
-    public String getNativeInputMethodInfo() {
-        String xmodifiers = System.getenv("XMODIFIERS");
-        String imInfo = null;
-
-        // If XMODIFIERS is set, return the value
-        if (xmodifiers != null) {
-            int imIndex = xmodifiers.indexOf("@im=");
-            if (imIndex != -1) {
-                imInfo = xmodifiers.substring(imIndex + 4);
+        post=getCompositionState();
+        if (pre != post && post == enable){
+            if (enable == false) flushText();
+            if (awtFocussedComponent != null && isActive){
+                setXICFocus(getPeer(awtFocussedComponent),
+                            true, haveActiveClient());
             }
-        } else if (System.getProperty("os.name").startsWith("SunOS")) {
-            File dtprofile = new File(System.getProperty("user.home") +
-                                      "/.dtprofile");
-            String languageEngineInfo = null;
-            try {
-                BufferedReader br = new BufferedReader(new FileReader(dtprofile));
-                String line = null;
-
-                while ( languageEngineInfo == null && (line = br.readLine()) != null) {
-                    if (line.contains("atok") || line.contains("wnn")) {
-                        StringTokenizer tokens =  new StringTokenizer(line);
-                        while (tokens.hasMoreTokens()) {
-                            String token = tokens.nextToken();
-                            if (Pattern.matches("atok.*setup", token) ||
-                                Pattern.matches("wnn.*setup", token)){
-                                languageEngineInfo = token.substring(0, token.indexOf("setup"));
-                                break;
-                            }
-                        }
-                    }
-                }
-
-                br.close();
-            } catch(IOException ioex) {
-                // Since this method is provided for internal testing only,
-                // we dump the stack trace for the ease of debugging.
-                ioex.printStackTrace();
-            }
-
-            imInfo = "htt " + languageEngineInfo;
-        }
-
-        return imInfo;
-    }
-
-
-    /**
-     * Performs mapping from an XIM visible feedback value to Java IM highlight.
-     * @return Java input method highlight
-     */
-    private InputMethodHighlight convertVisualFeedbackToHighlight(int feedback) {
-        InputMethodHighlight highlight;
-
-        switch (feedback) {
-        case XIMUnderline:
-            highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
-            break;
-        case XIMReverse:
-            highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
-            break;
-        case XIMHighlight:
-            highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
-            break;
-        case XIMPrimary:
-            highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
-            break;
-        case XIMSecondary:
-            highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
-            break;
-        case XIMTertiary:
-            highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
-            break;
-        default:
-            highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
-            break;
-        }
-        return highlight;
-    }
-
-    // initial capacity size for string buffer, etc.
-    private 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 {
-        private int[] intArray;
-        private int size;
-        private int index;
-
-        IntBuffer(int initialCapacity) {
-            intArray = new int[initialCapacity];
-            size = 0;
-            index = 0;
-        }
-
-        void insert(int offset, int[] values) {
-            int newSize = size + values.length;
-            if (intArray.length < newSize) {
-                int[] newIntArray = new int[newSize * 2];
-                System.arraycopy(intArray, 0, newIntArray, 0, size);
-                intArray = newIntArray;
-            }
-            System.arraycopy(intArray, offset, intArray, offset+values.length,
-                             size - offset);
-            System.arraycopy(values, 0, intArray, offset, values.length);
-            size += values.length;
-            if (index > offset)
-                index = offset;
-        }
-
-        void remove(int offset, int length) {
-            if (offset + length != size)
-                System.arraycopy(intArray, offset+length, intArray, offset,
-                                 size - offset - length);
-            size -= length;
-            if (index > offset)
-                index = offset;
-        }
-
-        void replace(int offset, int[] values) {
-            System.arraycopy(values, 0, intArray, offset, values.length);
-        }
-
-        void removeAll() {
-            size = 0;
-            index = 0;
-        }
-
-        void rewind() {
-            index = 0;
-        }
-
-        int getNext() {
-            if (index == size)
-                return -1;
-            return intArray[index++];
-        }
-
-        void unget() {
-            if (index != 0)
-                index--;
-        }
-
-        int getOffset() {
-            return index;
-        }
-
-        public String toString() {
-            StringBuffer s = new StringBuffer();
-            for (int i = 0; i < size;) {
-                s.append(intArray[i++]);
-                if (i < size)
-                    s.append(",");
-            }
-            return s.toString();
         }
     }
 
-    /*
-     * Native methods
-     */
-    private native String resetXIC();
-    private native void disposeXIC();
-    private native boolean setCompositionEnabledNative(boolean enable);
-    private native boolean isCompositionEnabledNative();
-    private native void turnoffStatusWindow();
+    private native void setStatusAreaVisible(boolean value, long data);
 }
< prev index next >