1 /*
   2  * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.im;
  27 
  28 import java.awt.AWTException;
  29 import java.awt.CheckboxMenuItem;
  30 import java.awt.Component;
  31 import java.awt.Dialog;
  32 import java.awt.EventQueue;
  33 import java.awt.Frame;
  34 import java.awt.PopupMenu;
  35 import java.awt.Menu;
  36 import java.awt.MenuItem;
  37 import java.awt.Toolkit;
  38 import sun.awt.AppContext;
  39 import java.awt.event.ActionEvent;
  40 import java.awt.event.ActionListener;
  41 import java.awt.event.InvocationEvent;
  42 import java.awt.im.spi.InputMethodDescriptor;
  43 import java.lang.reflect.InvocationTargetException;
  44 import java.security.AccessController;
  45 import java.security.PrivilegedAction;
  46 import java.security.PrivilegedActionException;
  47 import java.security.PrivilegedExceptionAction;
  48 import java.util.Hashtable;
  49 import java.util.Iterator;
  50 import java.util.Locale;
  51 import java.util.ServiceLoader;
  52 import java.util.Vector;
  53 import java.util.Set;
  54 import java.util.prefs.BackingStoreException;
  55 import java.util.prefs.Preferences;
  56 import sun.awt.InputMethodSupport;
  57 import sun.awt.SunToolkit;
  58 import sun.misc.ManagedLocalsThread;
  59 
  60 /**
  61  * <code>InputMethodManager</code> is an abstract class that manages the input
  62  * method environment of JVM. There is only one <code>InputMethodManager</code>
  63  * instance in JVM that is executed under a separate daemon thread.
  64  * <code>InputMethodManager</code> performs the following:
  65  * <UL>
  66  * <LI>
  67  * Keeps track of the current input context.</LI>
  68  *
  69  * <LI>
  70  * Provides a user interface to switch input methods and notifies the current
  71  * input context about changes made from the user interface.</LI>
  72  * </UL>
  73  *
  74  * The mechanism for supporting input method switch is as follows. (Note that
  75  * this may change in future releases.)
  76  *
  77  * <UL>
  78  * <LI>
  79  * One way is to use platform-dependent window manager's menu (known as the <I>Window
  80  * menu </I>in Motif and the <I>System menu</I> or <I>Control menu</I> in
  81  * Win32) on each window which is popped up by clicking the left top box of
  82  * a window (known as <I>Window menu button</I> in Motif and <I>System menu
  83  * button</I> in Win32). This happens to be common in both Motif and Win32.</LI>
  84  *
  85  * <LI>
  86  * When more than one input method descriptor can be found or the only input
  87  * method descriptor found supports multiple locales, a menu item
  88  * is added to the window (manager) menu. This item label is obtained invoking
  89  * <code>getTriggerMenuString()</code>. If null is returned by this method, it
  90  * means that there is only input method or none in the environment. Frame and Dialog
  91  * invoke this method.</LI>
  92  *
  93  * <LI>
  94  * This menu item means a trigger switch to the user to pop up a selection
  95  * menu.</LI>
  96  *
  97  * <LI>
  98  * When the menu item of the window (manager) menu has been selected by the
  99  * user, Frame/Dialog invokes <code>notifyChangeRequest()</code> to notify
 100  * <code>InputMethodManager</code> that the user wants to switch input methods.</LI>
 101  *
 102  * <LI>
 103  * <code>InputMethodManager</code> displays a pop-up menu to choose an input method.</LI>
 104  *
 105  * <LI>
 106  * <code>InputMethodManager</code> notifies the current <code>InputContext</code> of
 107  * the selected <code>InputMethod</code>.</LI>
 108  * </UL>
 109  *
 110  * <UL>
 111  * <LI>
 112  * The other way is to use user-defined hot key combination to show the pop-up menu to
 113  * choose an input method.  This is useful for the platforms which do not provide a
 114  * way to add a menu item in the window (manager) menu.</LI>
 115  *
 116  * <LI>
 117  * When the hot key combination is typed by the user, the component which has the input
 118  * focus invokes <code>notifyChangeRequestByHotKey()</code> to notify
 119  * <code>InputMethodManager</code> that the user wants to switch input methods.</LI>
 120  *
 121  * <LI>
 122  * This results in a popup menu and notification to the current input context,
 123  * as above.</LI>
 124  * </UL>
 125  *
 126  * @see java.awt.im.spi.InputMethod
 127  * @see sun.awt.im.InputContext
 128  * @see sun.awt.im.InputMethodAdapter
 129  * @author JavaSoft International
 130  */
 131 
 132 public abstract class InputMethodManager {
 133 
 134     /**
 135      * InputMethodManager thread name
 136      */
 137     private static final String threadName = "AWT-InputMethodManager";
 138 
 139     /**
 140      * Object for global locking
 141      */
 142     private static final Object LOCK = new Object();
 143 
 144     /**
 145      * The InputMethodManager instance
 146      */
 147     private static InputMethodManager inputMethodManager;
 148 
 149     /**
 150      * Returns the instance of InputMethodManager. This method creates
 151      * the instance that is unique in the Java VM if it has not been
 152      * created yet.
 153      *
 154      * @return the InputMethodManager instance
 155      */
 156     public static final InputMethodManager getInstance() {
 157         if (inputMethodManager != null) {
 158             return inputMethodManager;
 159         }
 160         synchronized(LOCK) {
 161             if (inputMethodManager == null) {
 162                 ExecutableInputMethodManager imm = new ExecutableInputMethodManager();
 163 
 164                 // Initialize the input method manager and start a
 165                 // daemon thread if the user has multiple input methods
 166                 // to choose from. Otherwise, just keep the instance.
 167                 if (imm.hasMultipleInputMethods()) {
 168                     imm.initialize();
 169                     Thread immThread = new ManagedLocalsThread(imm, threadName);
 170                     immThread.setDaemon(true);
 171                     immThread.setPriority(Thread.NORM_PRIORITY + 1);
 172                     immThread.start();
 173                 }
 174                 inputMethodManager = imm;
 175             }
 176         }
 177         return inputMethodManager;
 178     }
 179 
 180     /**
 181      * Gets a string for the trigger menu item that should be added to
 182      * the window manager menu. If no need to display the trigger menu
 183      * item, null is returned.
 184      */
 185     public abstract String getTriggerMenuString();
 186 
 187     /**
 188      * Notifies InputMethodManager that input method change has been
 189      * requested by the user. This notification triggers a popup menu
 190      * for user selection.
 191      *
 192      * @param comp Component that has accepted the change
 193      * request. This component has to be a Frame or Dialog.
 194      */
 195     public abstract void notifyChangeRequest(Component comp);
 196 
 197     /**
 198      * Notifies InputMethodManager that input method change has been
 199      * requested by the user using the hot key combination. This
 200      * notification triggers a popup menu for user selection.
 201      *
 202      * @param comp Component that has accepted the change
 203      * request. This component has the input focus.
 204      */
 205     public abstract void notifyChangeRequestByHotKey(Component comp);
 206 
 207     /**
 208      * Sets the current input context so that it will be notified
 209      * of input method changes initiated from the user interface.
 210      * Set to real input context when activating; to null when
 211      * deactivating.
 212      */
 213     abstract void setInputContext(InputContext inputContext);
 214 
 215     /**
 216      * Tries to find an input method locator for the given locale.
 217      * Returns null if no available input method locator supports
 218      * the locale.
 219      */
 220     abstract InputMethodLocator findInputMethod(Locale forLocale);
 221 
 222     /**
 223      * Gets the default keyboard locale of the underlying operating system.
 224      */
 225     abstract Locale getDefaultKeyboardLocale();
 226 
 227     /**
 228      * Returns whether multiple input methods are available or not
 229      */
 230     abstract boolean hasMultipleInputMethods();
 231 
 232 }