Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Side by Side Diff: chrome/browser/chromeos/input_method/input_method_manager.cc

Issue 9999018: chrome/browser/chromeos/input_method/ refactoring [part 6 of 6] (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review fix Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/input_method/input_method_manager.h" 5 #include "chrome/browser/chromeos/input_method/input_method_manager.h"
6 6
7 #include <algorithm> 7 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
8
9 #include <glib.h>
10
11 #include "base/basictypes.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/singleton.h"
14 #include "base/message_loop.h"
15 #include "base/process_util.h"
16 #include "base/string_split.h"
17 #include "base/string_util.h"
18 #include "base/stringprintf.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chromeos/input_method/browser_state_monitor.h"
21 #include "chrome/browser/chromeos/input_method/input_method_util.h"
22 #include "chrome/browser/chromeos/input_method/input_method_whitelist.h"
23 #include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h"
24 #include "chrome/browser/chromeos/input_method/xkeyboard.h"
25 #include "chrome/browser/chromeos/language_preferences.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_observer.h"
28 #include "content/public/browser/notification_registrar.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/notification_types.h"
31 #include "googleurl/src/gurl.h"
32 #include "ui/base/accelerators/accelerator.h"
33 #include "unicode/uloc.h"
34
35 #if !defined(USE_VIRTUAL_KEYBOARD)
36 #include "chrome/browser/chromeos/input_method/candidate_window.h"
37 #endif
38
39 using content::BrowserThread;
40
41 namespace {
42
43 const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
44
45 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the
46 // property with |new_prop|. Returns true if such a property is found.
47 bool FindAndUpdateProperty(
48 const chromeos::input_method::InputMethodProperty& new_prop,
49 chromeos::input_method::InputMethodPropertyList* prop_list) {
50 for (size_t i = 0; i < prop_list->size(); ++i) {
51 chromeos::input_method::InputMethodProperty& prop = prop_list->at(i);
52 if (prop.key == new_prop.key) {
53 const int saved_id = prop.selection_item_id;
54 // Update the list except the radio id. As written in
55 // chromeos_input_method.h, |prop.selection_item_id| is dummy.
56 prop = new_prop;
57 prop.selection_item_id = saved_id;
58 return true;
59 }
60 }
61 return false;
62 }
63
64 } // namespace
65 8
66 namespace chromeos { 9 namespace chromeos {
67 namespace input_method { 10 namespace input_method {
68 11
69 // The implementation of InputMethodManager. 12 namespace {
70 class InputMethodManagerImpl : public InputMethodManager, 13 InputMethodManager* g_input_method_manager = NULL;
71 public content::NotificationObserver, 14 } // namespace
72 #if !defined(USE_VIRTUAL_KEYBOARD)
73 public CandidateWindowController::Observer,
74 #endif
75 public IBusController::Observer {
76 public:
77 InputMethodManagerImpl()
78 : ibus_controller_(IBusController::Create()),
79 should_hide_properties_(true),
80 should_launch_ime_(false),
81 ime_connected_(false),
82 enable_auto_ime_shutdown_(false), // workaround for crosbug.com/27051.
83 enable_extension_imes_(true),
84 shutting_down_(false),
85 ibus_daemon_process_handle_(base::kNullProcessHandle),
86 util_(whitelist_.GetSupportedInputMethods()),
87 xkeyboard_(XKeyboard::Create(util_)),
88 ALLOW_THIS_IN_INITIALIZER_LIST(
89 browser_state_monitor_(new BrowserStateMonitor(this))),
90 ignore_hotkeys_(false) {
91 // Observe APP_TERMINATING to stop input method daemon gracefully.
92 // We should not use APP_EXITING here since logout might be canceled by
93 // JavaScript after APP_EXITING is sent (crosbug.com/11055).
94 // Note that even if we fail to stop input method daemon from
95 // Chrome in case of a sudden crash, we have a way to do it from an
96 // upstart script. See crosbug.com/6515 and crosbug.com/6995 for
97 // details.
98 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING,
99 content::NotificationService::AllSources());
100 15
101 // The observer should be added before Connect() so we can capture the 16 // static
102 // initial connection change. 17 void InputMethodManager::Initialize() {
103 ibus_controller_->AddObserver(this); 18 DCHECK(!g_input_method_manager);
104 ibus_controller_->Connect(); 19 InputMethodManagerImpl* impl = new InputMethodManagerImpl;
20 impl->Init();
21 g_input_method_manager = impl;
22 VLOG(1) << "InputMethodManager initialized";
23 }
105 24
106 EnableHotkeys(); 25 // static
107 } 26 void InputMethodManager::InitializeForTesting(
27 InputMethodManager* mock_manager) {
28 DCHECK(!g_input_method_manager);
29 g_input_method_manager = mock_manager;
30 VLOG(1) << "InputMethodManager for testing initialized";
31 }
108 32
109 virtual ~InputMethodManagerImpl() { 33 // static
110 ibus_controller_->RemoveObserver(this); 34 void InputMethodManager::Shutdown() {
111 #if !defined(USE_VIRTUAL_KEYBOARD) 35 // TODO(yusukes): The NULL check is needed for some unit_tests such as
112 if (candidate_window_controller_.get()) 36 // 'WarmConnectionFieldTrial_WarmestSocket' which seem to destruct a
113 candidate_window_controller_->RemoveObserver(this); 37 // ChromeBrowserMainPartsChromeos instance without calling
114 #endif 38 // ChromeBrowserMainPartsChromeos::PostMainMessageLoopStart(). It's probably
115 } 39 // better to fix the tests and remove the hack here.
116 40 if (!g_input_method_manager)
117 virtual void AddObserver(InputMethodManager::Observer* observer) { 41 LOG(WARNING) << "InputMethodManager:Shutdown() called with NULL manager";
118 observers_.AddObserver(observer); 42 else
119 } 43 delete g_input_method_manager;
120 44 g_input_method_manager = NULL;
121 virtual void RemoveObserver(InputMethodManager::Observer* observer) { 45 VLOG(1) << "InputMethodManager shutdown";
122 observers_.RemoveObserver(observer); 46 }
123 }
124
125 virtual void AddCandidateWindowObserver(
126 InputMethodManager::CandidateWindowObserver* observer) {
127 candidate_window_observers_.AddObserver(observer);
128 }
129
130 virtual void RemoveCandidateWindowObserver(
131 InputMethodManager::CandidateWindowObserver* observer) {
132 candidate_window_observers_.RemoveObserver(observer);
133 }
134
135 virtual void AddVirtualKeyboardObserver(VirtualKeyboardObserver* observer) {
136 virtual_keyboard_observers_.AddObserver(observer);
137 }
138
139 virtual void RemoveVirtualKeyboardObserver(
140 VirtualKeyboardObserver* observer) {
141 virtual_keyboard_observers_.RemoveObserver(observer);
142 }
143
144 virtual InputMethodDescriptors* GetActiveInputMethods() {
145 InputMethodDescriptors* result = new InputMethodDescriptors;
146 // Build the active input method descriptors from the active input
147 // methods cache |active_input_method_ids_|.
148 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
149 const std::string& input_method_id = active_input_method_ids_[i];
150 const InputMethodDescriptor* descriptor =
151 util_.GetInputMethodDescriptorFromId(input_method_id);
152 if (descriptor) {
153 result->push_back(*descriptor);
154 } else {
155 std::map<std::string, InputMethodDescriptor>::
156 const_iterator ix = extra_input_method_ids_.find(input_method_id);
157 if (ix != extra_input_method_ids_.end()) {
158 result->push_back(ix->second);
159 } else {
160 LOG(ERROR) << "Descriptor is not found for: " << input_method_id;
161 }
162 }
163 }
164 // Initially active_input_method_ids_ is empty. In this case, just
165 // returns the fallback input method descriptor.
166 if (result->empty()) {
167 // Since browser_tests call neither
168 // SetInputMethodConfig("preload_engines") nor EnableInputMethod(), this
169 // path might be taken.
170 result->push_back(
171 InputMethodDescriptor::GetFallbackInputMethodDescriptor());
172 }
173 return result;
174 }
175
176 virtual size_t GetNumActiveInputMethods() {
177 scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
178 return input_methods->size();
179 }
180
181 virtual InputMethodDescriptors* GetSupportedInputMethods() {
182 return whitelist_.GetSupportedInputMethods();
183 }
184
185 virtual void ChangeInputMethod(const std::string& input_method_id) {
186 // Changing the input method isn't guaranteed to succeed here, but we
187 // should remember the last one regardless. See comments in
188 // FlushImeConfig() for details.
189 tentative_current_input_method_id_ = input_method_id;
190
191 if (InputMethodUtil::IsKeyboardLayout(input_method_id)) {
192 // We shouldn't use SetCurrentKeyboardLayoutByName() here. See
193 // comments at ChangeCurrentInputMethod() for details.
194 ChangeCurrentInputMethodFromId(input_method_id);
195 OnRegisterImeProperties(InputMethodPropertyList()); // notify the button.
196 } else {
197 // Otherwise, start the input method daemon, and change the input
198 // method via the daemon.
199 StartInputMethodDaemon();
200 // ChangeInputMethodViaIBus() fails if the IBus daemon is not
201 // ready yet. In this case, we'll defer the input method change
202 // until the daemon is ready.
203 if (!ChangeInputMethodViaIBus(input_method_id)) {
204 VLOG(1) << "Failed to change the input method to " << input_method_id
205 << " (deferring)";
206 }
207 }
208 }
209
210 virtual void EnableLayouts(const std::string& language_code,
211 const std::string& initial_input_method_id) {
212 std::vector<std::string> candidates;
213 // Add input methods associated with the language.
214 util_.GetInputMethodIdsFromLanguageCode(language_code,
215 kKeyboardLayoutsOnly,
216 &candidates);
217 // Add the hardware keyboard as well. We should always add this so users
218 // can use the hardware keyboard on the login screen and the screen locker.
219 candidates.push_back(util_.GetHardwareInputMethodId());
220
221 std::vector<std::string> input_method_ids;
222 // First, add the initial input method ID, if it's requested, to
223 // input_method_ids, so it appears first on the list of active input
224 // methods at the input language status menu.
225 if (!initial_input_method_id.empty()) {
226 input_method_ids.push_back(initial_input_method_id);
227 }
228
229 // Add candidates to input_method_ids, while skipping duplicates.
230 for (size_t i = 0; i < candidates.size(); ++i) {
231 const std::string& candidate = candidates[i];
232 // Not efficient, but should be fine, as the two vectors are very
233 // short (2-5 items).
234 if (std::count(input_method_ids.begin(), input_method_ids.end(),
235 candidate) == 0) {
236 input_method_ids.push_back(candidate);
237 }
238 }
239
240 // Update ibus-daemon setting. Here, we don't save the input method list
241 // in the user's preferences.
242 InputMethodConfigValue value;
243 value.type = InputMethodConfigValue::kValueTypeStringList;
244 value.string_list_value = input_method_ids;
245 SetInputMethodConfig(language_prefs::kGeneralSectionName,
246 language_prefs::kPreloadEnginesConfigName,
247 value);
248
249 // Finaly, change to the initial input method, as needed.
250 if (!initial_input_method_id.empty()) {
251 ChangeInputMethod(initial_input_method_id);
252 }
253 }
254
255 virtual void SetImePropertyActivated(const std::string& key,
256 bool activated) {
257 DCHECK(!key.empty());
258 ibus_controller_->SetImePropertyActivated(key, activated);
259 }
260
261 virtual bool InputMethodIsActivated(const std::string& input_method_id) {
262 scoped_ptr<InputMethodDescriptors> active_input_method_descriptors(
263 GetActiveInputMethods());
264 for (size_t i = 0; i < active_input_method_descriptors->size(); ++i) {
265 if (active_input_method_descriptors->at(i).id() == input_method_id) {
266 return true;
267 }
268 }
269 return false;
270 }
271
272 virtual bool SetInputMethodConfig(const std::string& section,
273 const std::string& config_name,
274 const InputMethodConfigValue& value) {
275 // If the config change is for preload engines, update the active
276 // input methods cache |active_input_method_ids_| here. We need to
277 // update the cache before actually flushing the config. since we need
278 // to return active input methods from GetActiveInputMethods() before
279 // the input method daemon starts. For instance, we need to show the
280 // list of available input methods (keyboard layouts) on the login
281 // screen before the input method starts.
282 if (section == language_prefs::kGeneralSectionName &&
283 config_name == language_prefs::kPreloadEnginesConfigName &&
284 value.type == InputMethodConfigValue::kValueTypeStringList) {
285 active_input_method_ids_ = value.string_list_value;
286
287 if (enable_extension_imes_) {
288 std::map<std::string, InputMethodDescriptor>::const_iterator ix;
289 for (ix = extra_input_method_ids_.begin();
290 ix != extra_input_method_ids_.end(); ++ix) {
291 active_input_method_ids_.push_back(ix->first);
292 }
293 }
294 }
295
296 // Before calling FlushImeConfig(), start input method process if necessary.
297 MaybeStartInputMethodDaemon(section, config_name, value);
298
299 const ConfigKeyType key = std::make_pair(section, config_name);
300 current_config_values_[key] = value;
301 if (ime_connected_) {
302 pending_config_requests_[key] = value;
303 FlushImeConfig();
304 }
305
306 if (section == language_prefs::kGeneralSectionName &&
307 config_name == language_prefs::kPreloadEnginesConfigName) {
308 // Stop input method process if necessary.
309 MaybeStopInputMethodDaemon();
310 }
311 // Change the current keyboard layout if necessary.
312 MaybeChangeCurrentKeyboardLayout(section, config_name, value);
313 return pending_config_requests_.empty();
314 }
315
316 // TODO(yusukes): Support input method specific hotkeys.
317 virtual void AddActiveIme(const std::string& id,
318 const std::string& name,
319 const std::vector<std::string>& layouts,
320 const std::string& language) {
321 std::string virtual_layouts = JoinString(layouts, ',');
322
323 extra_input_method_ids_[id] = ibus_controller_->CreateInputMethodDescriptor(
324 id, name, virtual_layouts, language);
325 active_input_method_ids_.push_back(id);
326
327 // Ensure that the input method daemon is running.
328 StartInputMethodDaemon();
329 }
330
331 virtual void RemoveActiveIme(const std::string& id) {
332 std::vector<std::string>::iterator ix =
333 std::find(active_input_method_ids_.begin(),
334 active_input_method_ids_.end(),
335 id);
336 if (ix != active_input_method_ids_.end()) {
337 active_input_method_ids_.erase(ix);
338 // TODO(yusukes): this is a workaround for crosbug.com/27051. Uncomment
339 // this when the bug is fixed.
340 if (!active_input_method_ids_.empty()) {
341 ChangeInputMethod(active_input_method_ids_[0]);
342 }
343 }
344 extra_input_method_ids_.erase(id);
345
346 // Stop the IME daemon if needed.
347 MaybeStopInputMethodDaemon();
348 }
349
350 virtual bool GetExtraDescriptor(const std::string& id,
351 InputMethodDescriptor* descriptor) {
352 std::map<std::string, InputMethodDescriptor>::const_iterator ix =
353 extra_input_method_ids_.find(id);
354 if (ix != extra_input_method_ids_.end()) {
355 *descriptor = ix->second;
356 return true;
357 } else {
358 return false;
359 }
360 }
361
362 virtual InputMethodDescriptor GetPreviousInputMethod() const {
363 if (previous_input_method_.id().empty()) {
364 return InputMethodDescriptor::GetFallbackInputMethodDescriptor();
365 }
366 return previous_input_method_;
367 }
368
369 virtual InputMethodDescriptor GetCurrentInputMethod() const {
370 if (current_input_method_.id().empty()) {
371 return InputMethodDescriptor::GetFallbackInputMethodDescriptor();
372 }
373 return current_input_method_;
374 }
375
376 virtual InputMethodPropertyList GetCurrentInputMethodProperties() const {
377 if (should_hide_properties_ ||
378 InputMethodUtil::IsKeyboardLayout(GetCurrentInputMethod().id())) {
379 return InputMethodPropertyList();
380 }
381 return current_ime_properties_;
382 }
383
384 virtual void SendHandwritingStroke(const HandwritingStroke& stroke) {
385 ibus_controller_->SendHandwritingStroke(stroke);
386 }
387
388 virtual void CancelHandwritingStrokes(int stroke_count) {
389 // TODO(yusukes): Rename the function to CancelHandwritingStrokes.
390 ibus_controller_->CancelHandwriting(stroke_count);
391 }
392
393 virtual void RegisterVirtualKeyboard(const GURL& launch_url,
394 const std::string& name,
395 const std::set<std::string>& layouts,
396 bool is_system) {
397 virtual_keyboard_selector_.AddVirtualKeyboard(launch_url,
398 name,
399 layouts,
400 is_system);
401 }
402
403 virtual const std::map<GURL, const VirtualKeyboard*>&
404 GetUrlToKeyboardMapping() const {
405 return virtual_keyboard_selector_.url_to_keyboard();
406 }
407
408 virtual const std::multimap<std::string, const VirtualKeyboard*>&
409 GetLayoutNameToKeyboardMapping() const {
410 return virtual_keyboard_selector_.layout_to_keyboard();
411 }
412
413 virtual bool SetVirtualKeyboardPreference(const std::string& input_method_id,
414 const GURL& extention_url) {
415 const bool result = virtual_keyboard_selector_.SetUserPreference(
416 input_method_id, extention_url);
417 UpdateVirtualKeyboardUI();
418 return result;
419 }
420
421 virtual void ClearAllVirtualKeyboardPreferences() {
422 virtual_keyboard_selector_.ClearAllUserPreferences();
423 UpdateVirtualKeyboardUI();
424 }
425
426 virtual InputMethodUtil* GetInputMethodUtil() {
427 return &util_;
428 }
429
430 virtual XKeyboard* GetXKeyboard() {
431 return xkeyboard_.get();
432 }
433
434 virtual void CandidateWindowOpened() {
435 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
436 candidate_window_observers_,
437 CandidateWindowOpened(this));
438 }
439
440 virtual void CandidateWindowClosed() {
441 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
442 candidate_window_observers_,
443 CandidateWindowClosed(this));
444 }
445
446 virtual bool SwitchToNextInputMethod() {
447 if (ignore_hotkeys_) {
448 return false;
449 }
450
451 // Sanity checks.
452 if (active_input_method_ids_.empty()) {
453 LOG(ERROR) << "active input method is empty";
454 return false;
455 }
456 if (current_input_method_.id().empty()) {
457 LOG(ERROR) << "current_input_method_ is unknown";
458 return false;
459 }
460
461 // Find the next input method.
462 std::vector<std::string>::const_iterator iter =
463 std::find(active_input_method_ids_.begin(),
464 active_input_method_ids_.end(),
465 current_input_method_.id());
466 if (iter != active_input_method_ids_.end()) {
467 ++iter;
468 }
469 if (iter == active_input_method_ids_.end()) {
470 iter = active_input_method_ids_.begin();
471 }
472 ChangeInputMethod(*iter);
473 return true;
474 }
475
476 virtual bool SwitchToPreviousInputMethod() {
477 if (ignore_hotkeys_) {
478 return false;
479 }
480
481 // Sanity check.
482 if (active_input_method_ids_.empty()) {
483 LOG(ERROR) << "active input method is empty";
484 return false;
485 }
486
487 if (previous_input_method_.id().empty() ||
488 previous_input_method_.id() == current_input_method_.id()) {
489 return SwitchToNextInputMethod();
490 }
491
492 std::vector<std::string>::const_iterator iter =
493 std::find(active_input_method_ids_.begin(),
494 active_input_method_ids_.end(),
495 previous_input_method_.id());
496 if (iter == active_input_method_ids_.end()) {
497 // previous_input_method_ is not supported.
498 return SwitchToNextInputMethod();
499 }
500 ChangeInputMethod(*iter);
501 return true;
502 }
503
504 virtual bool SwitchInputMethod(const ui::Accelerator& accelerator) {
505 if (ignore_hotkeys_) {
506 return false;
507 }
508
509 // Sanity check.
510 if (active_input_method_ids_.empty()) {
511 LOG(ERROR) << "active input method is empty";
512 return false;
513 }
514
515 // Get the list of input method ids for the |accelerator|. For example, get
516 // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR.
517 std::vector<std::string> input_method_ids_to_switch;
518 switch (accelerator.key_code()) {
519 case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard
520 input_method_ids_to_switch.push_back("mozc-jp");
521 break;
522 case ui::VKEY_NONCONVERT: // Muhenkan key on JP106 keyboard
523 input_method_ids_to_switch.push_back("xkb:jp::jpn");
524 break;
525 case ui::VKEY_DBE_SBCSCHAR: // ZenkakuHankaku key on JP106 keyboard
526 case ui::VKEY_DBE_DBCSCHAR:
527 input_method_ids_to_switch.push_back("mozc-jp");
528 input_method_ids_to_switch.push_back("xkb:jp::jpn");
529 break;
530 case ui::VKEY_HANGUL: // Hangul (or right Alt) key on Korean keyboard
531 case ui::VKEY_SPACE: // Shift+Space
532 input_method_ids_to_switch.push_back("mozc-hangul");
533 input_method_ids_to_switch.push_back("xkb:kr:kr104:kor");
534 break;
535 default:
536 NOTREACHED();
537 break;
538 }
539 if (input_method_ids_to_switch.empty()) {
540 LOG(ERROR) << "Unexpected VKEY: " << accelerator.key_code();
541 return false;
542 }
543
544 // Obtain the intersection of input_method_ids_to_switch and
545 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is
546 // preserved.
547 std::vector<std::string> ids;
548 for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) {
549 const std::string& id = input_method_ids_to_switch[i];
550 if (std::find(active_input_method_ids_.begin(),
551 active_input_method_ids_.end(),
552 id) != active_input_method_ids_.end()) {
553 ids.push_back(id);
554 }
555 }
556 if (ids.empty()) {
557 // No input method for the accelerator is active. For example, we should
558 // just ignore VKEY_HANGUL when mozc-hangul is not active.
559 return false;
560 }
561
562 // If |current_input_method_| is not in ids, switch to ids[0]. If
563 // |current_input_method_| is ids[N], switch to ids[N+1].
564 std::vector<std::string>::const_iterator iter =
565 std::find(ids.begin(), ids.end(), current_input_method_.id());
566 if (iter != ids.end()) {
567 ++iter;
568 }
569 if (iter == ids.end()) {
570 iter = ids.begin();
571 }
572 ChangeInputMethod(*iter);
573 return true; // consume the accelerator.
574 }
575
576 virtual void EnableHotkeys() {
577 ignore_hotkeys_ = false;
578 }
579
580 virtual void DisableHotkeys() {
581 ignore_hotkeys_ = true;
582 }
583
584 static InputMethodManagerImpl* GetInstance() {
585 return Singleton<InputMethodManagerImpl,
586 DefaultSingletonTraits<InputMethodManagerImpl> >::get();
587 }
588
589 private:
590 friend struct DefaultSingletonTraits<InputMethodManagerImpl>;
591
592 // Returns true if the given input method config value is a string list
593 // that only contains an input method ID of a keyboard layout.
594 bool ContainOnlyKeyboardLayout(const std::vector<std::string>& value) {
595 for (size_t i = 0; i < value.size(); ++i) {
596 if (!InputMethodUtil::IsKeyboardLayout(value[i])) {
597 return false;
598 }
599 }
600 return true;
601 }
602
603 // Starts input method daemon based on the input method configuration being
604 // updated. |section| is a section name of the input method configuration
605 // (e.g. "general", "general/hotkey"). |config_name| is a name of the
606 // configuration (e.g. "preload_engines", "previous_engine"). |value| is the
607 // configuration value to be set.
608 void MaybeStartInputMethodDaemon(const std::string& section,
609 const std::string& config_name,
610 const InputMethodConfigValue& value) {
611 if (section == language_prefs::kGeneralSectionName &&
612 config_name == language_prefs::kPreloadEnginesConfigName &&
613 value.type == InputMethodConfigValue::kValueTypeStringList &&
614 !value.string_list_value.empty()) {
615 // If there is only one input method which is a keyboard layout,
616 // we don't start the input method processes.
617 if (ContainOnlyKeyboardLayout(value.string_list_value)) {
618 // Do not start the input method daemon.
619 return;
620 }
621
622 // Otherwise, start the input method daemon.
623 const bool just_started = StartInputMethodDaemon();
624 if (!just_started) {
625 // The daemon is already running.
626 // Do not |update tentative_current_input_method_id_|.
627 return;
628 }
629
630 // The daemon has just been started. To select the initial input method
631 // engine correctly, update |tentative_current_input_method_id_|.
632 if (tentative_current_input_method_id_.empty()) {
633 // Since the |current_input_method_| is in the preloaded engine list,
634 // switch to the engine. This is necessary ex. for the following case:
635 // 1. "xkb:jp::jpn" is enabled. ibus-daemon is not running.
636 // 2. A user enabled "mozc" via DOMUI as well. ibus-daemon is started
637 // and the preloaded engine list is set to "mozc,xkb:jp::jpn".
638 // 3. ibus-daemon selects "mozc" as its current engine since "mozc" is
639 // on top of the preloaded engine list.
640 // 4. Therefore, we have to change the current engine to "xkb:jp::jpn"
641 // explicitly to avoid unexpected engine switch.
642 tentative_current_input_method_id_ = current_input_method_.id();
643 }
644
645 if (std::find(value.string_list_value.begin(),
646 value.string_list_value.end(),
647 tentative_current_input_method_id_)
648 == value.string_list_value.end()) {
649 // The |current_input_method_| is NOT in the preloaded engine list.
650 // In this case, ibus-daemon will automatically select the first engine
651 // in the list, |value.string_list_value[0]|, and send global engine
652 // changed signal to Chrome. See crosbug.com/13406.
653 tentative_current_input_method_id_.clear();
654 }
655 }
656 }
657
658 // Stops input method daemon based on the |enable_auto_ime_shutdown_| flag
659 // and input method configuration being updated.
660 // See also: MaybeStartInputMethodDaemon().
661 void MaybeStopInputMethodDaemon() {
662 // If there is only one input method which is a keyboard layout,
663 // and |enable_auto_ime_shutdown_| is true, we'll stop the input
664 // method daemon.
665 if (ContainOnlyKeyboardLayout(active_input_method_ids_) &&
666 enable_auto_ime_shutdown_) {
667 if (StopInputMethodDaemon()) {
668 // The process is killed. Change the current keyboard layout.
669 // We shouldn't use SetCurrentKeyboardLayoutByName() here. See
670 // comments at ChangeCurrentInputMethod() for details.
671 ChangeCurrentInputMethodFromId(active_input_method_ids_[0]);
672 }
673 }
674 }
675
676 // Change the keyboard layout per input method configuration being
677 // updated, if necessary. See also: MaybeStartInputMethodDaemon().
678 void MaybeChangeCurrentKeyboardLayout(const std::string& section,
679 const std::string& config_name,
680 const InputMethodConfigValue& value) {
681 if (section == language_prefs::kGeneralSectionName &&
682 config_name == language_prefs::kPreloadEnginesConfigName) {
683 if (value.string_list_value.size() == 1 ||
684 (value.string_list_value.size() != 0 &&
685 std::find(value.string_list_value.begin(),
686 value.string_list_value.end(),
687 current_input_method_.id()) ==
688 value.string_list_value.end())) {
689 // This is necessary to initialize current_input_method_. This is also
690 // necessary when the current layout (e.g. INTL) out of two or more
691 // active ones (e.g. US, DV, and INTL) is disabled.
692 ChangeCurrentInputMethodFromId(value.string_list_value[0]);
693 }
694 DCHECK(!current_input_method_.id().empty());
695
696 // Update the indicator.
697 // TODO(yusukes): Remove ActiveInputMethodsChanged notification in
698 // FlushImeConfig().
699 const size_t num_active_input_methods = GetNumActiveInputMethods();
700 FOR_EACH_OBSERVER(InputMethodManager::Observer, observers_,
701 ActiveInputMethodsChanged(this,
702 GetCurrentInputMethod(),
703 num_active_input_methods));
704 }
705 }
706
707 // Changes the current input method to |input_method_id| via IBus
708 // daemon. If the id is not in the preload_engine list, this function
709 // changes the current method to the first preloaded engine. Returns
710 // true if the current engine is switched to |input_method_id| or the
711 // first one.
712 bool ChangeInputMethodViaIBus(const std::string& input_method_id) {
713 std::string input_method_id_to_switch = input_method_id;
714
715 if (!InputMethodIsActivated(input_method_id)) {
716 // This path might be taken if prefs::kLanguageCurrentInputMethod (NOT
717 // synced with cloud) and kLanguagePreloadEngines (synced with cloud) are
718 // mismatched. e.g. the former is 'xkb:us::eng' and the latter (on the
719 // sync server) is 'xkb:jp::jpn,mozc'.
720 scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
721 DCHECK(!input_methods->empty());
722 if (!input_methods->empty()) {
723 input_method_id_to_switch = input_methods->at(0).id();
724 LOG(INFO) << "Can't change the current input method to "
725 << input_method_id << " since the engine is not preloaded. "
726 << "Switch to " << input_method_id_to_switch << " instead.";
727 }
728 }
729
730 if (ibus_controller_->ChangeInputMethod(input_method_id_to_switch)) {
731 return true;
732 }
733
734 // ChangeInputMethod() fails if the IBus daemon is not yet ready.
735 LOG(ERROR) << "Can't switch input method to " << input_method_id_to_switch;
736 return false;
737 }
738
739 // Flushes the input method config data. The config data is queued up in
740 // |pending_config_requests_| until the config backend (ibus-memconf)
741 // starts.
742 void FlushImeConfig() {
743 bool active_input_methods_are_changed = false;
744 InputMethodConfigRequests::iterator iter = pending_config_requests_.begin();
745 while (iter != pending_config_requests_.end()) {
746 const std::string& section = iter->first.first;
747 const std::string& config_name = iter->first.second;
748 InputMethodConfigValue& value = iter->second;
749
750 if (config_name == language_prefs::kPreloadEnginesConfigName &&
751 !tentative_current_input_method_id_.empty()) {
752 // We should use |tentative_current_input_method_id_| as the initial
753 // active input method for the following reasons:
754 //
755 // 1) Calls to ChangeInputMethod() will fail if the input method has not
756 // yet been added to preload_engines. As such, the call is deferred
757 // until after all config values have been sent to the IME process.
758 //
759 // 2) We might have already changed the current input method to one
760 // of XKB layouts without going through the IBus daemon (we can do
761 // it without the IBus daemon started).
762 std::vector<std::string>::iterator engine_iter = std::find(
763 value.string_list_value.begin(),
764 value.string_list_value.end(),
765 tentative_current_input_method_id_);
766 if (engine_iter != value.string_list_value.end()) {
767 // Use std::rotate to keep the relative order of engines the same e.g.
768 // from "A,B,C" to "C,A,B".
769 // We don't have to |active_input_method_ids_|, which decides the
770 // order of engines in the switcher menu, since the relative order
771 // of |value.string_list_value| is not changed.
772 std::rotate(value.string_list_value.begin(),
773 engine_iter, // this becomes the new first element
774 value.string_list_value.end());
775 } else {
776 LOG(WARNING) << tentative_current_input_method_id_
777 << " is not in preload_engines: " << value.ToString();
778 }
779 tentative_current_input_method_id_.erase();
780 }
781
782 if (ibus_controller_->SetInputMethodConfig(section, config_name, value)) {
783 // Check if it's a change in active input methods.
784 if (config_name == language_prefs::kPreloadEnginesConfigName) {
785 active_input_methods_are_changed = true;
786 VLOG(1) << "Updated preload_engines: " << value.ToString();
787 }
788 // Successfully sent. Remove the command and proceed to the next one.
789 pending_config_requests_.erase(iter++);
790 } else {
791 // If SetInputMethodConfig() fails, subsequent calls will likely fail.
792 break;
793 }
794 }
795
796 // Notify the current input method and the number of active input methods to
797 // the UI so that the UI could determine e.g. if it should show/hide the
798 // input method indicator, etc. We have to call FOR_EACH_OBSERVER here since
799 // updating "preload_engine" does not necessarily trigger a DBus signal such
800 // as "global-engine-changed". For example,
801 // 1) If we change the preload_engine from "xkb:us:intl:eng" (i.e. the
802 // indicator is hidden) to "xkb:us:intl:eng,mozc", we have to update UI
803 // so it shows the indicator, but no signal is sent from ibus-daemon
804 // because the current input method is not changed.
805 // 2) If we change the preload_engine from "xkb:us::eng,mozc" (i.e. the
806 // indicator is shown and ibus-daemon is started) to "xkb:us::eng", we
807 // have to update UI so it hides the indicator, but we should not expect
808 // that ibus-daemon could send a DBus signal since the daemon is killed
809 // right after this FlushImeConfig() call.
810 if (active_input_methods_are_changed) {
811 // The |current_input_method_| member might be stale here as
812 // SetInputMethodConfig("preload_engine") call above might change the
813 // current input method in ibus-daemon (ex. this occurs when the
814 // input method currently in use is removed from the options
815 // page). However, it should be safe to use the member here,
816 // for the following reasons:
817 // 1. If ibus-daemon is to be killed, we'll switch to the only one
818 // keyboard layout, and observers are notified. See
819 // MaybeStopInputMethodDaemon() for details.
820 // 2. Otherwise, "global-engine-changed" signal is delivered from
821 // ibus-daemon, and observers are notified. See
822 // InputMethodChangedHandler() for details.
823 const size_t num_active_input_methods = GetNumActiveInputMethods();
824 FOR_EACH_OBSERVER(InputMethodManager::Observer, observers_,
825 ActiveInputMethodsChanged(this,
826 current_input_method_,
827 num_active_input_methods));
828 }
829 }
830
831 // IBusController override.
832 virtual void OnCurrentInputMethodChanged(
833 const InputMethodDescriptor& current_input_method) {
834 // The handler is called when the input method method change is
835 // notified via a DBus connection. Since the DBus notificatiosn are
836 // handled in the UI thread, we can assume that this function always
837 // runs on the UI thread, but just in case.
838 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
839 LOG(ERROR) << "Not on UI thread";
840 return;
841 }
842
843 ChangeCurrentInputMethod(current_input_method);
844 }
845
846 // IBusController override.
847 virtual void OnRegisterImeProperties(
848 const InputMethodPropertyList& prop_list) {
849 // See comments in InputMethodChangedHandler.
850 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
851 LOG(ERROR) << "Not on UI thread";
852 return;
853 }
854
855 RegisterProperties(prop_list);
856 }
857
858 // IBusController override.
859 virtual void OnUpdateImeProperty(
860 const InputMethodPropertyList& prop_list) {
861 // See comments in InputMethodChangedHandler.
862 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
863 LOG(ERROR) << "Not on UI thread";
864 return;
865 }
866
867 UpdateProperty(prop_list);
868 }
869
870 // IBusController override.
871 virtual void OnConnectionChange(bool connected) {
872 // See comments in InputMethodChangedHandler.
873 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
874 LOG(ERROR) << "Not on UI thread";
875 return;
876 }
877
878 ime_connected_ = connected;
879 if (connected) {
880 pending_config_requests_.clear();
881 pending_config_requests_.insert(current_config_values_.begin(),
882 current_config_values_.end());
883 FlushImeConfig();
884 }
885 }
886
887 // Changes the current input method from the given input method
888 // descriptor. This function updates states like current_input_method_
889 // and notifies observers about the change (that will update the
890 // preferences), hence this function should always be used even if you
891 // just need to change the current keyboard layout.
892 void ChangeCurrentInputMethod(const InputMethodDescriptor& new_input_method) {
893 if (current_input_method_.id() != new_input_method.id()) {
894 previous_input_method_ = current_input_method_;
895 current_input_method_ = new_input_method;
896
897 // Change the keyboard layout to a preferred layout for the input method.
898 if (!xkeyboard_->SetCurrentKeyboardLayoutByName(
899 current_input_method_.keyboard_layout())) {
900 LOG(ERROR) << "Failed to change keyboard layout to "
901 << current_input_method_.keyboard_layout();
902 }
903 }
904
905 // Update input method indicators (e.g. "US", "DV") in Chrome windows.
906 // For now, we have to do this every time to keep indicators updated. See
907 // comments near the FOR_EACH_OBSERVER call in FlushImeConfig() for details.
908 const size_t num_active_input_methods = GetNumActiveInputMethods();
909 FOR_EACH_OBSERVER(InputMethodManager::Observer, observers_,
910 InputMethodChanged(this,
911 current_input_method_,
912 num_active_input_methods));
913
914 UpdateVirtualKeyboardUI();
915 }
916
917 void UpdateVirtualKeyboardUI() {
918 #if defined(USE_VIRTUAL_KEYBOARD)
919 const VirtualKeyboard* virtual_keyboard = NULL;
920 std::string virtual_keyboard_layout = "";
921
922 const std::vector<std::string>& layouts_vector =
923 current_input_method_.virtual_keyboard_layouts();
924 std::vector<std::string>::const_iterator iter;
925 for (iter = layouts_vector.begin(); iter != layouts_vector.end(); ++iter) {
926 virtual_keyboard =
927 virtual_keyboard_selector_.SelectVirtualKeyboard(*iter);
928 if (virtual_keyboard) {
929 virtual_keyboard_layout = *iter;
930 break;
931 }
932 }
933
934 if (!virtual_keyboard) {
935 // The system virtual keyboard does not support some XKB layouts? or
936 // a third-party input method engine uses a wrong virtual keyboard
937 // layout name? Fallback to the default layout.
938 LOG(ERROR) << "Could not find a virtual keyboard for "
939 << current_input_method_.id();
940
941 // If the hardware is for US, show US Qwerty virtual keyboard.
942 // If it's for France, show Azerty one.
943 const std::string fallback_id = GetInputMethodUtil()->
944 GetHardwareInputMethodId();
945 const InputMethodDescriptor* fallback_desc =
946 GetInputMethodUtil()->GetInputMethodDescriptorFromId(fallback_id);
947
948 DCHECK(fallback_desc);
949 const std::vector<std::string>& fallback_layouts_vector =
950 fallback_desc->virtual_keyboard_layouts();
951
952 for (iter = fallback_layouts_vector.begin();
953 iter != fallback_layouts_vector.end();
954 ++iter) {
955 virtual_keyboard =
956 virtual_keyboard_selector_.SelectVirtualKeyboard(*iter);
957 if (virtual_keyboard) {
958 virtual_keyboard_layout = *iter;
959 LOG(ERROR) << "Fall back to '" << (*iter) << "' virtual keyboard";
960 break;
961 }
962 }
963 }
964
965 if (!virtual_keyboard) {
966 // kFallbackVirtualKeyboardLayout should always be supported by one of the
967 // system virtual keyboards.
968 static const char kFallbackVirtualKeyboardLayout[] = "us";
969
970 LOG(ERROR) << "Could not find a FALLBACK virtual keyboard for "
971 << current_input_method_.id()
972 << ". Use '" << kFallbackVirtualKeyboardLayout
973 << "' virtual keyboard";
974 virtual_keyboard = virtual_keyboard_selector_.SelectVirtualKeyboard(
975 kFallbackVirtualKeyboardLayout);
976 virtual_keyboard_layout = kFallbackVirtualKeyboardLayout;
977 }
978
979 if (virtual_keyboard) {
980 FOR_EACH_OBSERVER(VirtualKeyboardObserver, virtual_keyboard_observers_,
981 VirtualKeyboardChanged(this,
982 *virtual_keyboard,
983 virtual_keyboard_layout));
984 }
985 #endif // USE_VIRTUAL_KEYBOARD
986 }
987
988 // Changes the current input method from the given input method ID.
989 // This function is just a wrapper of ChangeCurrentInputMethod().
990 void ChangeCurrentInputMethodFromId(const std::string& input_method_id) {
991 const InputMethodDescriptor* descriptor =
992 util_.GetInputMethodDescriptorFromId(input_method_id);
993 if (descriptor) {
994 ChangeCurrentInputMethod(*descriptor);
995 } else {
996 LOG(ERROR) << "Descriptor is not found for: " << input_method_id;
997 }
998 }
999
1000 // Registers the properties used by the current input method.
1001 void RegisterProperties(const InputMethodPropertyList& prop_list) {
1002 // |prop_list| might be empty. This means "hide properties."
1003 if (prop_list.empty()) {
1004 should_hide_properties_ = true;
1005 } else {
1006 should_hide_properties_ = false;
1007 current_ime_properties_ = prop_list;
1008 }
1009 // Update input method menu
1010 FOR_EACH_OBSERVER(InputMethodManager::Observer, observers_,
1011 PropertyListChanged(this,
1012 GetCurrentInputMethodProperties()));
1013 }
1014
1015 // Starts the input method daemon. Unlike MaybeStopInputMethodDaemon(),
1016 // this function always starts the daemon. Returns true if the daemon is
1017 // started. Otherwise, e.g. the daemon is already started, returns false.
1018 bool StartInputMethodDaemon() {
1019 should_launch_ime_ = true;
1020 return MaybeLaunchInputMethodDaemon();
1021 }
1022
1023 // Updates the properties used by the current input method.
1024 void UpdateProperty(const InputMethodPropertyList& prop_list) {
1025 for (size_t i = 0; i < prop_list.size(); ++i) {
1026 FindAndUpdateProperty(prop_list[i], &current_ime_properties_);
1027 }
1028
1029 // Update input method menu
1030 FOR_EACH_OBSERVER(InputMethodManager::Observer, observers_,
1031 PropertyListChanged(this,
1032 GetCurrentInputMethodProperties()));
1033 }
1034
1035 // Launches an input method procsess specified by the given command
1036 // line. On success, returns true and stores the process handle in
1037 // |process_handle|. Otherwise, returns false, and the contents of
1038 // |process_handle| is untouched. OnImeShutdown will be called when the
1039 // process terminates.
1040 bool LaunchInputMethodProcess(const std::string& command_line,
1041 base::ProcessHandle* process_handle) {
1042 std::vector<std::string> argv;
1043 base::ProcessHandle handle = base::kNullProcessHandle;
1044
1045 // TODO(zork): export "LD_PRELOAD=/usr/lib/libcrash.so"
1046 base::SplitString(command_line, ' ', &argv);
1047
1048 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) {
1049 LOG(ERROR) << "Could not launch: " << command_line;
1050 return false;
1051 }
1052
1053 // g_child_watch_add is necessary to prevent the process from becoming a
1054 // zombie.
1055 // TODO(yusukes): port g_child_watch_add to base/process_utils_posix.cc.
1056 const base::ProcessId pid = base::GetProcId(handle);
1057 g_child_watch_add(pid,
1058 reinterpret_cast<GChildWatchFunc>(OnImeShutdown),
1059 this);
1060
1061 *process_handle = handle;
1062 VLOG(1) << command_line << " (PID=" << pid << ") is started";
1063 return true;
1064 }
1065
1066 // Launches input method daemon if these are not yet running. Returns true if
1067 // the daemon is started. Otherwise, e.g. the daemon is already started,
1068 // returns false.
1069 bool MaybeLaunchInputMethodDaemon() {
1070 if (!should_launch_ime_) {
1071 return false;
1072 }
1073
1074 if (shutting_down_) {
1075 NOTREACHED() << "Trying to launch input method while shutting down";
1076 return false;
1077 }
1078
1079 #if !defined(USE_VIRTUAL_KEYBOARD)
1080 if (!candidate_window_controller_.get()) {
1081 candidate_window_controller_.reset(
1082 CandidateWindowController::CreateCandidateWindowController());
1083 if (candidate_window_controller_->Init()) {
1084 candidate_window_controller_->AddObserver(this);
1085 } else {
1086 LOG(WARNING) << "Failed to initialize the candidate window controller";
1087 }
1088 }
1089 #endif
1090
1091 if (ibus_daemon_process_handle_ != base::kNullProcessHandle) {
1092 return false; // ibus-daemon is already running.
1093 }
1094
1095 // TODO(zork): Send output to /var/log/ibus.log
1096 const std::string ibus_daemon_command_line =
1097 base::StringPrintf(
1098 "%s --panel=disable --cache=none --restart --replace",
1099 kIBusDaemonPath);
1100 if (!LaunchInputMethodProcess(
1101 ibus_daemon_command_line, &ibus_daemon_process_handle_)) {
1102 LOG(ERROR) << "Failed to launch " << ibus_daemon_command_line;
1103 return false;
1104 }
1105 return true;
1106 }
1107
1108 // Called when the input method process is shut down.
1109 static void OnImeShutdown(GPid pid,
1110 gint status,
1111 InputMethodManagerImpl* library) {
1112 if (library->ibus_daemon_process_handle_ != base::kNullProcessHandle &&
1113 base::GetProcId(library->ibus_daemon_process_handle_) == pid) {
1114 library->ibus_daemon_process_handle_ = base::kNullProcessHandle;
1115 }
1116
1117 // Restart input method daemon if needed.
1118 library->MaybeLaunchInputMethodDaemon();
1119 }
1120
1121 // Stops the backend input method daemon. This function should also be
1122 // called from MaybeStopInputMethodDaemon(), except one case where we
1123 // stop the input method daemon at Chrome shutdown in Observe(). Returns true
1124 // if the daemon is stopped. Otherwise, e.g. the daemon is already stopped,
1125 // returns false.
1126 bool StopInputMethodDaemon() {
1127 should_launch_ime_ = false;
1128 if (ibus_daemon_process_handle_ != base::kNullProcessHandle) {
1129 const base::ProcessId pid = base::GetProcId(ibus_daemon_process_handle_);
1130 if (!ibus_controller_->StopInputMethodProcess()) {
1131 LOG(ERROR) << "StopInputMethodProcess IPC failed. Sending SIGTERM to "
1132 << "PID " << pid;
1133 base::KillProcess(ibus_daemon_process_handle_, -1, false /* wait */);
1134 }
1135 VLOG(1) << "ibus-daemon (PID=" << pid << ") is terminated";
1136 ibus_daemon_process_handle_ = base::kNullProcessHandle;
1137 return true;
1138 }
1139 return false;
1140 }
1141
1142 void SetEnableAutoImeShutdown(bool enable) {
1143 // TODO(yusukes): this is a workaround for crosbug.com/27051. Uncommen this
1144 // when the bug is fixed.
1145
1146 // enable_auto_ime_shutdown_ = enable;
1147 }
1148
1149 void SetEnableExtensionIMEs(bool enable) {
1150 enable_extension_imes_ = enable;
1151 }
1152
1153 // content::NotificationObserver implementation:
1154 void Observe(int type,
1155 const content::NotificationSource& source,
1156 const content::NotificationDetails& details) {
1157 // Stop the input method daemon on browser shutdown.
1158 if (type == content::NOTIFICATION_APP_TERMINATING) {
1159 shutting_down_ = true;
1160 notification_registrar_.RemoveAll();
1161 StopInputMethodDaemon();
1162 #if !defined(USE_VIRTUAL_KEYBOARD)
1163 if (candidate_window_controller_.get())
1164 candidate_window_controller_->RemoveObserver(this);
1165 candidate_window_controller_.reset(NULL);
1166 #endif
1167 // |browser_state_monitor_| has to be destructed while the PrefService
1168 // object associated with the monitor is alive. (crbug.com/120183)
1169 browser_state_monitor_.reset();
1170 }
1171 }
1172
1173 // The IBus controller is used to control the input method status and
1174 // allow allow callbacks when the input method status changes.
1175 scoped_ptr<IBusController> ibus_controller_;
1176 ObserverList<InputMethodManager::Observer> observers_;
1177 ObserverList<InputMethodManager::CandidateWindowObserver>
1178 candidate_window_observers_;
1179 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_;
1180
1181 // The input method which was/is selected.
1182 InputMethodDescriptor previous_input_method_;
1183 InputMethodDescriptor current_input_method_;
1184
1185 // The input method properties which the current input method uses. The list
1186 // might be empty when no input method is used.
1187 InputMethodPropertyList current_ime_properties_;
1188 bool should_hide_properties_;
1189
1190 typedef std::pair<std::string, std::string> ConfigKeyType;
1191 typedef std::map<
1192 ConfigKeyType, InputMethodConfigValue> InputMethodConfigRequests;
1193 // SetInputMethodConfig requests that are not yet completed.
1194 // Use a map to queue config requests, so we only send the last request for
1195 // the same config key (i.e. we'll discard ealier requests for the same
1196 // config key). As we discard old requests for the same config key, the order
1197 // of requests doesn't matter, so it's safe to use a map.
1198 InputMethodConfigRequests pending_config_requests_;
1199
1200 // Values that have been set via SetInputMethodConfig(). We keep a copy
1201 // available to resend if the ime restarts and loses its state.
1202 InputMethodConfigRequests current_config_values_;
1203
1204 // This is used to register this object to APP_TERMINATING notification.
1205 content::NotificationRegistrar notification_registrar_;
1206
1207 // True if we should launch the input method daemon.
1208 bool should_launch_ime_;
1209 // True if the connection to the IBus daemon is alive.
1210 bool ime_connected_;
1211 // True if we should stop input method daemon when there are no input
1212 // methods other than one for the hardware keyboard.
1213 bool enable_auto_ime_shutdown_;
1214 // True if extension IMEs can be enabled.
1215 bool enable_extension_imes_;
1216 // The ID of the tentative current input method (ex. "mozc"). This value
1217 // can be different from the actual current input method, if
1218 // ChangeInputMethod() fails.
1219 // TODO(yusukes): clear this variable when a user logs in.
1220 std::string tentative_current_input_method_id_;
1221
1222 // The candidate window. This will be deleted when the APP_TERMINATING
1223 // message is sent.
1224 #if !defined(USE_VIRTUAL_KEYBOARD)
1225 scoped_ptr<CandidateWindowController> candidate_window_controller_;
1226 #endif
1227
1228 // True if we've received the APP_TERMINATING notification.
1229 bool shutting_down_;
1230
1231 // The process handle of the IBus daemon. kNullProcessHandle if it's not
1232 // running.
1233 base::ProcessHandle ibus_daemon_process_handle_;
1234
1235 // An object which keeps a list of available virtual keyboards.
1236 VirtualKeyboardSelector virtual_keyboard_selector_;
1237
1238 // The active input method ids cache.
1239 std::vector<std::string> active_input_method_ids_;
1240
1241 // Extra input methods that have been explicitly added to the menu, such as
1242 // those created by extension.
1243 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_;
1244
1245 InputMethodWhitelist whitelist_;
1246
1247 // An object which provides miscellaneous input method utility functions. Note
1248 // that |util_| is required to initialize |xkeyboard_|.
1249 InputMethodUtil util_;
1250
1251 // An object for switching XKB layouts and keyboard status like caps lock and
1252 // auto-repeat interval.
1253 scoped_ptr<XKeyboard> xkeyboard_;
1254
1255 // An object which monitors a notification from the browser to keep track of
1256 // the browser state (not logged in, logged in, etc.).
1257 scoped_ptr<BrowserStateMonitor> browser_state_monitor_;
1258
1259 // true when DisableHotkeys() is called to temporarily disable IME hotkeys.
1260 // EnableHotkeys() resets the flag to the default value, false.
1261 bool ignore_hotkeys_;
1262
1263 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl);
1264 };
1265 47
1266 // static 48 // static
1267 InputMethodManager* InputMethodManager::GetInstance() { 49 InputMethodManager* InputMethodManager::GetInstance() {
1268 return InputMethodManagerImpl::GetInstance(); 50 DCHECK(g_input_method_manager);
51 return g_input_method_manager;
1269 } 52 }
1270 53
1271 } // namespace input_method 54 } // namespace input_method
1272 } // namespace chromeos 55 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698