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
26package sun.awt.im;
27
28import java.awt.AWTException;
29import java.awt.CheckboxMenuItem;
30import java.awt.Component;
31import java.awt.Dialog;
32import java.awt.EventQueue;
33import java.awt.Frame;
34import java.awt.PopupMenu;
35import java.awt.Menu;
36import java.awt.MenuItem;
37import java.awt.Toolkit;
38import sun.awt.AppContext;
39import java.awt.event.ActionEvent;
40import java.awt.event.ActionListener;
41import java.awt.event.InvocationEvent;
42import java.awt.im.spi.InputMethodDescriptor;
43import java.lang.reflect.InvocationTargetException;
44import java.security.AccessController;
45import java.security.PrivilegedAction;
46import java.security.PrivilegedActionException;
47import java.security.PrivilegedExceptionAction;
48import java.util.Hashtable;
49import java.util.Iterator;
50import java.util.Locale;
51import java.util.ServiceLoader;
52import java.util.Vector;
53import java.util.Set;
54import java.util.prefs.BackingStoreException;
55import java.util.prefs.Preferences;
56import sun.awt.InputMethodSupport;
57import sun.awt.SunToolkit;
58
59/**
60 * {@code InputMethodManager} is an abstract class that manages the input
61 * method environment of JVM. There is only one {@code InputMethodManager}
62 * instance in JVM that is executed under a separate daemon thread.
63 * {@code InputMethodManager} performs the following:
64 * <UL>
65 * <LI>
66 * Keeps track of the current input context.</LI>
67 *
68 * <LI>
69 * Provides a user interface to switch input methods and notifies the current
70 * input context about changes made from the user interface.</LI>
71 * </UL>
72 *
73 * The mechanism for supporting input method switch is as follows. (Note that
74 * this may change in future releases.)
75 *
76 * <UL>
77 * <LI>
78 * One way is to use platform-dependent window manager's menu (known as the <I>Window
79 * menu </I>in Motif and the <I>System menu</I> or <I>Control menu</I> in
80 * Win32) on each window which is popped up by clicking the left top box of
81 * a window (known as <I>Window menu button</I> in Motif and <I>System menu
82 * button</I> in Win32). This happens to be common in both Motif and Win32.</LI>
83 *
84 * <LI>
85 * When more than one input method descriptor can be found or the only input
86 * method descriptor found supports multiple locales, a menu item
87 * is added to the window (manager) menu. This item label is obtained invoking
88 * {@code getTriggerMenuString()}. If null is returned by this method, it
89 * means that there is only input method or none in the environment. Frame and Dialog
90 * invoke this method.</LI>
91 *
92 * <LI>
93 * This menu item means a trigger switch to the user to pop up a selection
94 * menu.</LI>
95 *
96 * <LI>
97 * When the menu item of the window (manager) menu has been selected by the
98 * user, Frame/Dialog invokes {@code notifyChangeRequest()} to notify
99 * {@code InputMethodManager} that the user wants to switch input methods.</LI>
100 *
101 * <LI>
102 * {@code InputMethodManager} displays a pop-up menu to choose an input method.</LI>
103 *
104 * <LI>
105 * {@code InputMethodManager} notifies the current {@code InputContext} of
106 * the selected {@code InputMethod}.</LI>
107 * </UL>
108 *
109 * <UL>
110 * <LI>
111 * The other way is to use user-defined hot key combination to show the pop-up menu to
112 * choose an input method.  This is useful for the platforms which do not provide a
113 * way to add a menu item in the window (manager) menu.</LI>
114 *
115 * <LI>
116 * When the hot key combination is typed by the user, the component which has the input
117 * focus invokes {@code notifyChangeRequestByHotKey()} to notify
118 * {@code InputMethodManager} that the user wants to switch input methods.</LI>
119 *
120 * <LI>
121 * This results in a popup menu and notification to the current input context,
122 * as above.</LI>
123 * </UL>
124 *
125 * @see java.awt.im.spi.InputMethod
126 * @see sun.awt.im.InputContext
127 * @see sun.awt.im.InputMethodAdapter
128 * @author JavaSoft International
129 */
130
131public abstract class InputMethodManager {
132
133    /**
134     * InputMethodManager thread name
135     */
136    private static final String threadName = "AWT-InputMethodManager";
137
138    /**
139     * Object for global locking
140     */
141    private static final Object LOCK = new Object();
142
143    /**
144     * The InputMethodManager instance
145     */
146    private static InputMethodManager inputMethodManager;
147
148    /**
149     * Returns the instance of InputMethodManager. This method creates
150     * the instance that is unique in the Java VM if it has not been
151     * created yet.
152     *
153     * @return the InputMethodManager instance
154     */
155    public static final InputMethodManager getInstance() {
156        if (inputMethodManager != null) {
157            return inputMethodManager;
158        }
159        synchronized(LOCK) {
160            if (inputMethodManager == null) {
161                ExecutableInputMethodManager imm = new ExecutableInputMethodManager();
162
163                // Initialize the input method manager and start a
164                // daemon thread if the user has multiple input methods
165                // to choose from. Otherwise, just keep the instance.
166                if (imm.hasMultipleInputMethods()) {
167                    imm.initialize();
168                    Thread immThread =
169                        new Thread(null, imm, threadName, 0, false);
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}
233