Chromium Code Reviews| 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 |