OLD | NEW |
---|---|
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 "ui/base/ime/input_method_ibus.h" | 5 #include "ui/base/ime/input_method_ibus.h" |
6 | 6 |
7 #include <X11/X.h> | 7 #include <X11/X.h> |
8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
9 #include <X11/Xutil.h> | 9 #include <X11/Xutil.h> |
10 #undef FocusIn | 10 #undef FocusIn |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 ibus_keyval_, | 155 ibus_keyval_, |
156 handled); | 156 handled); |
157 return; | 157 return; |
158 } | 158 } |
159 | 159 |
160 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). | 160 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
161 // See views::InputMethodIBus for details. Never forget to set 'character_' | 161 // See views::InputMethodIBus for details. Never forget to set 'character_' |
162 // and 'unmodified_character_' to support i18n VKs like a French VK! | 162 // and 'unmodified_character_' to support i18n VKs like a French VK! |
163 } | 163 } |
164 | 164 |
165 // A class to hold information of a pending request for creating an ibus input | |
166 // context. | |
167 class InputMethodIBus::PendingCreateICRequest { | |
168 public: | |
169 PendingCreateICRequest(InputMethodIBus* input_method, | |
170 PendingCreateICRequest** request_ptr); | |
171 virtual ~PendingCreateICRequest(); | |
172 | |
173 // Set up signal handlers, or destroy object proxy if the input context is | |
174 // already abandoned. | |
175 void InitOrAbandonInputContext(); | |
176 | |
177 // Called if the create input context method call is failed. | |
178 void OnCreateInputContextFailed(); | |
179 | |
180 // Abandon this pending key event. Its result will just be discarded. | |
181 void Abandon() { | |
182 input_method_ = NULL; | |
183 request_ptr_ = NULL; | |
184 // Do not reset |ibus_client_| here. | |
185 } | |
186 | |
187 private: | |
188 InputMethodIBus* input_method_; | |
189 PendingCreateICRequest** request_ptr_; | |
190 | |
191 DISALLOW_COPY_AND_ASSIGN(PendingCreateICRequest); | |
192 }; | |
193 | |
194 InputMethodIBus::PendingCreateICRequest::PendingCreateICRequest( | |
195 InputMethodIBus* input_method, | |
196 PendingCreateICRequest** request_ptr) | |
197 : input_method_(input_method), | |
198 request_ptr_(request_ptr) { | |
199 } | |
200 | |
201 InputMethodIBus::PendingCreateICRequest::~PendingCreateICRequest() { | |
202 if (request_ptr_) { | |
203 DCHECK_EQ(*request_ptr_, this); | |
204 *request_ptr_ = NULL; | |
205 } | |
206 } | |
207 | |
208 void InputMethodIBus::PendingCreateICRequest::OnCreateInputContextFailed() { | |
209 // TODO(nona): If the connection between Chrome and ibus-daemon terminates | |
210 // for some reason, the create ic request will fail. We might want to call | |
211 // ibus_client_->CreateContext() again after some delay. | |
212 } | |
213 | |
214 void InputMethodIBus::PendingCreateICRequest::InitOrAbandonInputContext() { | |
215 if (input_method_) { | |
216 DCHECK(input_method_->IsContextReady()); | |
217 input_method_->SetUpSignalHandlers(); | |
218 } else { | |
219 GetInputContextClient()->ResetObjectProxy(); | |
220 } | |
221 } | |
222 | |
223 // InputMethodIBus implementation ----------------------------------------- | 165 // InputMethodIBus implementation ----------------------------------------- |
224 InputMethodIBus::InputMethodIBus( | 166 InputMethodIBus::InputMethodIBus( |
225 internal::InputMethodDelegate* delegate) | 167 internal::InputMethodDelegate* delegate) |
226 : ibus_client_(new internal::IBusClient), | 168 : ibus_client_(new internal::IBusClient), |
227 pending_create_ic_request_(NULL), | 169 input_context_state_(INPUT_CONTEXT_STOP), |
170 create_input_context_fail_count_(0), | |
228 context_focused_(false), | 171 context_focused_(false), |
229 composing_text_(false), | 172 composing_text_(false), |
230 composition_changed_(false), | 173 composition_changed_(false), |
231 suppress_next_result_(false), | 174 suppress_next_result_(false), |
232 weak_ptr_factory_(this) { | 175 weak_ptr_factory_(this) { |
233 SetDelegate(delegate); | 176 SetDelegate(delegate); |
234 } | 177 } |
235 | 178 |
236 InputMethodIBus::~InputMethodIBus() { | 179 InputMethodIBus::~InputMethodIBus() { |
237 AbandonAllPendingKeyEvents(); | 180 AbandonAllPendingKeyEvents(); |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 OnTextInputTypeChanged(focused); | 359 OnTextInputTypeChanged(focused); |
417 | 360 |
418 UpdateContextFocusState(); | 361 UpdateContextFocusState(); |
419 // Force to update caret bounds, in case the client thinks that the caret | 362 // Force to update caret bounds, in case the client thinks that the caret |
420 // bounds has not changed. | 363 // bounds has not changed. |
421 OnCaretBoundsChanged(focused); | 364 OnCaretBoundsChanged(focused); |
422 } | 365 } |
423 | 366 |
424 void InputMethodIBus::CreateContext() { | 367 void InputMethodIBus::CreateContext() { |
425 DCHECK(IsConnected()); | 368 DCHECK(IsConnected()); |
426 DCHECK(!pending_create_ic_request_); | |
427 | 369 |
428 pending_create_ic_request_ = new PendingCreateICRequest( | 370 if (input_context_state_ != INPUT_CONTEXT_STOP) { |
429 this, &pending_create_ic_request_); | 371 LOG(ERROR) << "Input context is already created or waiting ibus-daemon" |
Yusuke Sato
2012/08/06 17:48:35
no more LOG(ERROR) please. see my comment below.
Seigo Nonaka
2012/08/07 04:28:29
Done.
| |
372 << " response."; | |
373 return; | |
374 } | |
375 | |
376 input_context_state_ = | |
377 INPUT_CONTEXT_WAIT_CREATE_CREATE_INPUT_CONTEXT_RESPONSE; | |
430 | 378 |
431 // Creates the input context asynchronously. | 379 // Creates the input context asynchronously. |
432 chromeos::DBusThreadManager::Get()->GetIBusClient()->CreateInputContext( | 380 chromeos::DBusThreadManager::Get()->GetIBusClient()->CreateInputContext( |
433 kClientName, | 381 kClientName, |
434 base::Bind(&InputMethodIBus::CreateInputContextDone, | 382 base::Bind(&InputMethodIBus::CreateInputContextDone, |
435 weak_ptr_factory_.GetWeakPtr(), | 383 weak_ptr_factory_.GetWeakPtr()), |
436 base::Unretained(pending_create_ic_request_)), | |
437 base::Bind(&InputMethodIBus::CreateInputContextFail, | 384 base::Bind(&InputMethodIBus::CreateInputContextFail, |
438 weak_ptr_factory_.GetWeakPtr(), | 385 weak_ptr_factory_.GetWeakPtr())); |
439 base::Unretained(pending_create_ic_request_))); | |
440 } | 386 } |
441 | 387 |
442 void InputMethodIBus::SetUpSignalHandlers() { | 388 void InputMethodIBus::SetUpSignalHandlers() { |
443 DCHECK(IsContextReady()); | 389 DCHECK(IsContextReady()); |
444 | 390 |
445 // connect input context signals | 391 // connect input context signals |
446 chromeos::IBusInputContextClient* input_context_client = | 392 chromeos::IBusInputContextClient* input_context_client = |
447 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); | 393 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); |
448 input_context_client->SetCommitTextHandler( | 394 input_context_client->SetCommitTextHandler( |
449 base::Bind(&InputMethodIBus::OnCommitText, | 395 base::Bind(&InputMethodIBus::OnCommitText, |
(...skipping 21 matching lines...) Expand all Loading... | |
471 | 417 |
472 UpdateContextFocusState(); | 418 UpdateContextFocusState(); |
473 // Since ibus-daemon is launched in an on-demand basis on Chrome OS, RWHVA (or | 419 // Since ibus-daemon is launched in an on-demand basis on Chrome OS, RWHVA (or |
474 // equivalents) might call OnCaretBoundsChanged() before the daemon starts. To | 420 // equivalents) might call OnCaretBoundsChanged() before the daemon starts. To |
475 // save the case, call OnCaretBoundsChanged() here. | 421 // save the case, call OnCaretBoundsChanged() here. |
476 OnCaretBoundsChanged(GetTextInputClient()); | 422 OnCaretBoundsChanged(GetTextInputClient()); |
477 OnInputMethodChanged(); | 423 OnInputMethodChanged(); |
478 } | 424 } |
479 | 425 |
480 void InputMethodIBus::DestroyContext() { | 426 void InputMethodIBus::DestroyContext() { |
481 if (pending_create_ic_request_) { | 427 if (input_context_state_ == INPUT_CONTEXT_STOP) |
482 DCHECK(!IsContextReady()); | |
483 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). | |
484 pending_create_ic_request_->Abandon(); | |
485 pending_create_ic_request_ = NULL; | |
486 return; | 428 return; |
487 } | 429 input_context_state_ = INPUT_CONTEXT_STOP; |
488 const chromeos::IBusInputContextClient* input_context = | 430 const chromeos::IBusInputContextClient* input_context = |
489 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); | 431 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); |
490 if (input_context && input_context->IsObjectProxyReady()) { | 432 if (input_context && input_context->IsObjectProxyReady()) { |
491 // We can't use IsContextReady here because we want to destroy object proxy | 433 // We can't use IsContextReady here because we want to destroy object proxy |
492 // regardless of connection. The IsContextReady contains connection check. | 434 // regardless of connection. The IsContextReady contains connection check. |
493 ResetInputContext(); | 435 ResetInputContext(); |
494 DCHECK(!IsContextReady()); | 436 DCHECK(!IsContextReady()); |
495 } | 437 } |
496 } | 438 } |
497 | 439 |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
899 context_focused_ = false; | 841 context_focused_ = false; |
900 | 842 |
901 ConfirmCompositionText(); | 843 ConfirmCompositionText(); |
902 | 844 |
903 // We are dead, so we need to ask the client to stop relying on us. | 845 // We are dead, so we need to ask the client to stop relying on us. |
904 OnInputMethodChanged(); | 846 OnInputMethodChanged(); |
905 GetInputContextClient()->ResetObjectProxy(); | 847 GetInputContextClient()->ResetObjectProxy(); |
906 } | 848 } |
907 | 849 |
908 void InputMethodIBus::CreateInputContextDone( | 850 void InputMethodIBus::CreateInputContextDone( |
909 PendingCreateICRequest* ic_request, | |
910 const dbus::ObjectPath& object_path) { | 851 const dbus::ObjectPath& object_path) { |
852 DCHECK_NE(INPUT_CONTEXT_RUNNING, input_context_state_) | |
853 << "Already input context is created."; | |
854 | |
855 if (input_context_state_ == INPUT_CONTEXT_STOP) { | |
856 // Corresponding to cancel abandon input context under waiting | |
857 // CreateInputContext response from ibus-daemon. Do nothing. | |
858 return; | |
859 } | |
860 | |
911 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() | 861 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() |
912 ->Initialize(chromeos::DBusThreadManager::Get()->GetIBusBus(), | 862 ->Initialize(chromeos::DBusThreadManager::Get()->GetIBusBus(), |
913 object_path); | 863 object_path); |
914 ic_request->InitOrAbandonInputContext(); | 864 |
915 delete ic_request; | 865 input_context_state_ = INPUT_CONTEXT_RUNNING; |
866 DCHECK(IsContextReady()); | |
867 SetUpSignalHandlers(); | |
916 } | 868 } |
917 | 869 |
918 void InputMethodIBus::CreateInputContextFail( | 870 void InputMethodIBus::CreateInputContextFail() { |
919 PendingCreateICRequest* ic_request) { | 871 DCHECK_NE(INPUT_CONTEXT_RUNNING, input_context_state_) |
920 ic_request->OnCreateInputContextFailed(); | 872 << "Already input context is created."; |
921 delete ic_request; | 873 if (input_context_state_ == INPUT_CONTEXT_STOP) { |
874 // CreateInputContext is failed but the input context is no longer | |
875 // necessary, thus do nothing. | |
876 return; | |
877 } | |
878 | |
879 if (create_input_context_fail_count_++ >= 10) { | |
Yusuke Sato
2012/08/06 17:48:35
be consistent, prefer ++create_input_context_fail_
Yusuke Sato
2012/08/06 17:48:35
10 should be replaced with const int kXXX;
Seigo Nonaka
2012/08/07 04:28:29
Done.
Seigo Nonaka
2012/08/07 04:28:29
Done.
| |
880 LOG(ERROR) << "CreateInputContext is failed even tried 10 times, Give up."; | |
Yusuke Sato
2012/08/06 17:48:35
using LOG(ERROR) is highly discouraged (check out
Seigo Nonaka
2012/08/07 04:28:29
Done.
| |
881 return; | |
882 } | |
883 | |
884 // Try CreateInputContext again. | |
885 chromeos::DBusThreadManager::Get()->GetIBusClient()->CreateInputContext( | |
886 kClientName, | |
887 base::Bind(&InputMethodIBus::CreateInputContextDone, | |
888 weak_ptr_factory_.GetWeakPtr()), | |
889 base::Bind(&InputMethodIBus::CreateInputContextFail, | |
890 weak_ptr_factory_.GetWeakPtr())); | |
922 } | 891 } |
923 | 892 |
924 bool InputMethodIBus::IsConnected() { | 893 bool InputMethodIBus::IsConnected() { |
925 return chromeos::DBusThreadManager::Get()->GetIBusBus() != NULL; | 894 return chromeos::DBusThreadManager::Get()->GetIBusBus() != NULL; |
926 } | 895 } |
927 | 896 |
928 bool InputMethodIBus::IsContextReady() { | 897 bool InputMethodIBus::IsContextReady() { |
929 if (!IsConnected()) | 898 if (!IsConnected()) |
930 return false; | 899 return false; |
931 if (!GetInputContextClient()) | 900 if (!GetInputContextClient()) |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1026 } | 995 } |
1027 | 996 |
1028 // Use a black thin underline by default. | 997 // Use a black thin underline by default. |
1029 if (out_composition->underlines.empty()) { | 998 if (out_composition->underlines.empty()) { |
1030 out_composition->underlines.push_back(CompositionUnderline( | 999 out_composition->underlines.push_back(CompositionUnderline( |
1031 0, length, SK_ColorBLACK, false /* thick */)); | 1000 0, length, SK_ColorBLACK, false /* thick */)); |
1032 } | 1001 } |
1033 } | 1002 } |
1034 | 1003 |
1035 } // namespace ui | 1004 } // namespace ui |
OLD | NEW |