| Index: chrome/browser/chromeos/cros/input_method_library.cc
|
| diff --git a/chrome/browser/chromeos/cros/input_method_library.cc b/chrome/browser/chromeos/cros/input_method_library.cc
|
| index 29818e9a1c942e5717f8c9bf0376ebf6ba5fd1f5..4e173747e4fcd7fea4bce422f0a2001af4f33f87 100644
|
| --- a/chrome/browser/chromeos/cros/input_method_library.cc
|
| +++ b/chrome/browser/chromeos/cros/input_method_library.cc
|
| @@ -16,10 +16,6 @@
|
| #include <glib.h>
|
| #include <signal.h>
|
|
|
| -// Allows InvokeLater without adding refcounting. This class is a Singleton and
|
| -// won't be deleted until it's last InvokeLater is run.
|
| -DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::InputMethodLibraryImpl);
|
| -
|
| namespace {
|
|
|
| // Finds a property which has |new_prop.key| from |prop_list|, and replaces the
|
| @@ -47,412 +43,562 @@ const char kDefaultKeyboardLayout[] = "us";
|
|
|
| namespace chromeos {
|
|
|
| -InputMethodLibraryImpl::InputMethodLibraryImpl()
|
| - : input_method_status_connection_(NULL),
|
| - previous_input_method_("", "", "", ""),
|
| - current_input_method_("", "", "", ""),
|
| - ime_running_(false),
|
| - ime_connected_(false),
|
| - defer_ime_startup_(false),
|
| - active_input_method_(kHardwareKeyboardLayout),
|
| - need_input_method_set_(false),
|
| - ime_handle_(0),
|
| - candidate_window_handle_(0) {
|
| - scoped_ptr<InputMethodDescriptors> input_method_descriptors(
|
| - CreateFallbackInputMethodDescriptors());
|
| - current_input_method_ = input_method_descriptors->at(0);
|
| -}
|
| -
|
| -InputMethodLibraryImpl::~InputMethodLibraryImpl() {
|
| - StopInputMethodProcesses();
|
| -}
|
| +// This class handles the interaction with the ChromeOS language library APIs.
|
| +// Classes can add themselves as observers. Users can get an instance of this
|
| +// library class like this: InputMethodLibrary::Get()
|
| +class InputMethodLibraryImpl : public InputMethodLibrary {
|
| + public:
|
| + InputMethodLibraryImpl()
|
| + : input_method_status_connection_(NULL),
|
| + previous_input_method_("", "", "", ""),
|
| + current_input_method_("", "", "", ""),
|
| + ime_running_(false),
|
| + ime_connected_(false),
|
| + defer_ime_startup_(false),
|
| + active_input_method_(kHardwareKeyboardLayout),
|
| + need_input_method_set_(false),
|
| + ime_handle_(0),
|
| + candidate_window_handle_(0) {
|
| + scoped_ptr<InputMethodDescriptors> input_method_descriptors(
|
| + CreateFallbackInputMethodDescriptors());
|
| + current_input_method_ = input_method_descriptors->at(0);
|
| + }
|
|
|
| -InputMethodLibraryImpl::Observer::~Observer() {
|
| -}
|
| + ~InputMethodLibraryImpl() {
|
| + StopInputMethodProcesses();
|
| + }
|
|
|
| -void InputMethodLibraryImpl::AddObserver(Observer* observer) {
|
| - observers_.AddObserver(observer);
|
| -}
|
| + void AddObserver(Observer* observer) {
|
| + observers_.AddObserver(observer);
|
| + }
|
|
|
| -void InputMethodLibraryImpl::RemoveObserver(Observer* observer) {
|
| - observers_.RemoveObserver(observer);
|
| -}
|
| + void RemoveObserver(Observer* observer) {
|
| + observers_.RemoveObserver(observer);
|
| + }
|
|
|
| -chromeos::InputMethodDescriptors*
|
| -InputMethodLibraryImpl::GetActiveInputMethods() {
|
| - chromeos::InputMethodDescriptors* result = NULL;
|
| - // The connection does not need to be alive, but it does need to be created.
|
| - if (EnsureLoadedAndStarted()) {
|
| - result = chromeos::GetActiveInputMethods(input_method_status_connection_);
|
| + InputMethodDescriptors* GetActiveInputMethods() {
|
| + chromeos::InputMethodDescriptors* result = NULL;
|
| + // The connection does not need to be alive, but it does need to be created.
|
| + if (EnsureLoadedAndStarted()) {
|
| + result = chromeos::GetActiveInputMethods(input_method_status_connection_);
|
| + }
|
| + if (!result || result->empty()) {
|
| + result = CreateFallbackInputMethodDescriptors();
|
| + }
|
| + return result;
|
| }
|
| - if (!result || result->empty()) {
|
| - result = CreateFallbackInputMethodDescriptors();
|
| +
|
| + size_t GetNumActiveInputMethods() {
|
| + scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
|
| + return input_methods->size();
|
| }
|
| - return result;
|
| -}
|
|
|
| -size_t InputMethodLibraryImpl::GetNumActiveInputMethods() {
|
| - scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
|
| - return input_methods->size();
|
| -}
|
| + InputMethodDescriptors* GetSupportedInputMethods() {
|
| + InputMethodDescriptors* result = NULL;
|
| + // The connection does not need to be alive, but it does need to be created.
|
| + if (EnsureLoadedAndStarted()) {
|
| + result = chromeos::GetSupportedInputMethods(
|
| + input_method_status_connection_);
|
| + }
|
| + if (!result || result->empty()) {
|
| + result = CreateFallbackInputMethodDescriptors();
|
| + }
|
| + return result;
|
| + }
|
|
|
| -chromeos::InputMethodDescriptors*
|
| -InputMethodLibraryImpl::GetSupportedInputMethods() {
|
| - chromeos::InputMethodDescriptors* result = NULL;
|
| - // The connection does not need to be alive, but it does need to be created.
|
| - if (EnsureLoadedAndStarted()) {
|
| - result = chromeos::GetSupportedInputMethods(
|
| - input_method_status_connection_);
|
| + void ChangeInputMethod(const std::string& input_method_id) {
|
| + if (EnsureLoadedAndStarted()) {
|
| + if (input_method_id != kHardwareKeyboardLayout) {
|
| + StartInputMethodProcesses();
|
| + }
|
| + chromeos::ChangeInputMethod(
|
| + input_method_status_connection_, input_method_id.c_str());
|
| + }
|
| }
|
| - if (!result || result->empty()) {
|
| - result = CreateFallbackInputMethodDescriptors();
|
| +
|
| + void SetImePropertyActivated(const std::string& key,
|
| + bool activated) {
|
| + DCHECK(!key.empty());
|
| + if (EnsureLoadedAndStarted()) {
|
| + chromeos::SetImePropertyActivated(
|
| + input_method_status_connection_, key.c_str(), activated);
|
| + }
|
| }
|
| - return result;
|
| -}
|
|
|
| -void InputMethodLibraryImpl::ChangeInputMethod(
|
| - const std::string& input_method_id) {
|
| - active_input_method_ = input_method_id;
|
| - if (EnsureLoadedAndStarted()) {
|
| - if (input_method_id != kHardwareKeyboardLayout) {
|
| - StartInputMethodProcesses();
|
| + bool InputMethodIsActivated(
|
| + const std::string& input_method_id) {
|
| + scoped_ptr<InputMethodDescriptors> active_input_method_descriptors(
|
| + CrosLibrary::Get()->GetInputMethodLibrary()->GetActiveInputMethods());
|
| + for (size_t i = 0; i < active_input_method_descriptors->size(); ++i) {
|
| + if (active_input_method_descriptors->at(i).id == input_method_id) {
|
| + return true;
|
| + }
|
| }
|
| - chromeos::ChangeInputMethod(
|
| - input_method_status_connection_, input_method_id.c_str());
|
| + return false;
|
| }
|
| -}
|
|
|
| -void InputMethodLibraryImpl::SetImePropertyActivated(const std::string& key,
|
| - bool activated) {
|
| - DCHECK(!key.empty());
|
| - if (EnsureLoadedAndStarted()) {
|
| - chromeos::SetImePropertyActivated(
|
| - input_method_status_connection_, key.c_str(), activated);
|
| + bool GetImeConfig(
|
| + const char* section,
|
| + const char* config_name,
|
| + ImeConfigValue* out_value) {
|
| + bool success = false;
|
| + if (EnsureLoadedAndStarted()) {
|
| + success = chromeos::GetImeConfig(
|
| + input_method_status_connection_, section, config_name, out_value);
|
| + }
|
| + return success;
|
| }
|
| -}
|
|
|
| -bool InputMethodLibraryImpl::InputMethodIsActivated(
|
| - const std::string& input_method_id) {
|
| - scoped_ptr<InputMethodDescriptors> active_input_method_descriptors(
|
| - CrosLibrary::Get()->GetInputMethodLibrary()->GetActiveInputMethods());
|
| - for (size_t i = 0; i < active_input_method_descriptors->size(); ++i) {
|
| - if (active_input_method_descriptors->at(i).id == input_method_id) {
|
| - return true;
|
| + bool SetImeConfig(
|
| + const char* section,
|
| + const char* config_name,
|
| + const ImeConfigValue& value) {
|
| + MaybeUpdateImeState(section, config_name, value);
|
| +
|
| + const ConfigKeyType key = std::make_pair(section, config_name);
|
| + current_config_values_[key] = value;
|
| + if (ime_connected_) {
|
| + pending_config_requests_[key] = value;
|
| + FlushImeConfig();
|
| }
|
| + return pending_config_requests_.empty();
|
| }
|
| - return false;
|
| -}
|
|
|
| -bool InputMethodLibraryImpl::GetImeConfig(
|
| - const char* section, const char* config_name, ImeConfigValue* out_value) {
|
| - bool success = false;
|
| - if (EnsureLoadedAndStarted()) {
|
| - success = chromeos::GetImeConfig(
|
| - input_method_status_connection_, section, config_name, out_value);
|
| + virtual const InputMethodDescriptor& previous_input_method() const {
|
| + return previous_input_method_;
|
| + }
|
| + virtual const InputMethodDescriptor& current_input_method() const {
|
| + return current_input_method_;
|
| }
|
| - return success;
|
| -}
|
|
|
| -bool InputMethodLibraryImpl::SetImeConfig(
|
| - const char* section, const char* config_name, const ImeConfigValue& value) {
|
| - MaybeUpdateImeState(section, config_name, value);
|
| + virtual const ImePropertyList& current_ime_properties() const {
|
| + return current_ime_properties_;
|
| + }
|
|
|
| - const ConfigKeyType key = std::make_pair(section, config_name);
|
| - current_config_values_[key] = value;
|
| - if (ime_connected_) {
|
| - pending_config_requests_[key] = value;
|
| - FlushImeConfig();
|
| + void StartIme() {
|
| + ime_running_ = true;
|
| + MaybeLaunchIme();
|
| }
|
| - return pending_config_requests_.empty();
|
| -}
|
|
|
| -void InputMethodLibraryImpl::MaybeUpdateImeState(
|
| - const char* section, const char* config_name, const ImeConfigValue& value) {
|
| - if (!strcmp(kGeneralSectionName, section) &&
|
| - !strcmp(kPreloadEnginesConfigName, config_name)) {
|
| - if (EnsureLoadedAndStarted()) {
|
| - if (value.type == ImeConfigValue::kValueTypeStringList &&
|
| - value.string_list_value.size() == 1 &&
|
| - value.string_list_value[0] == kHardwareKeyboardLayout) {
|
| - StopInputMethodProcesses();
|
| - } else if (!defer_ime_startup_) {
|
| - StartInputMethodProcesses();
|
| - }
|
| - chromeos::SetActiveInputMethods(input_method_status_connection_, value);
|
| + void StopIme() {
|
| + ime_running_ = false;
|
| + if (ime_handle_) {
|
| + kill(ime_handle_, SIGTERM);
|
| + ime_handle_ = 0;
|
| + }
|
| + if (candidate_window_handle_) {
|
| + kill(candidate_window_handle_, SIGTERM);
|
| + candidate_window_handle_ = 0;
|
| }
|
| }
|
| -}
|
|
|
| -void InputMethodLibraryImpl::FlushImeConfig() {
|
| - bool active_input_methods_are_changed = false;
|
| - bool completed = false;
|
| - if (EnsureLoadedAndStarted()) {
|
| - InputMethodConfigRequests::iterator iter = pending_config_requests_.begin();
|
| - while (iter != pending_config_requests_.end()) {
|
| - const std::string& section = iter->first.first;
|
| - const std::string& config_name = iter->first.second;
|
| - const ImeConfigValue& value = iter->second;
|
| - if (chromeos::SetImeConfig(input_method_status_connection_,
|
| - section.c_str(), config_name.c_str(), value)) {
|
| - // Check if it's a change in active input methods.
|
| - if (config_name == kPreloadEnginesConfigName) {
|
| - active_input_methods_are_changed = true;
|
| + private:
|
| + void MaybeUpdateImeState(
|
| + const char* section,
|
| + const char* config_name,
|
| + const ImeConfigValue& value) {
|
| + if (!strcmp(kGeneralSectionName, section) &&
|
| + !strcmp(kPreloadEnginesConfigName, config_name)) {
|
| + if (EnsureLoadedAndStarted()) {
|
| + if (value.type == ImeConfigValue::kValueTypeStringList &&
|
| + value.string_list_value.size() == 1 &&
|
| + value.string_list_value[0] == kHardwareKeyboardLayout) {
|
| + StopInputMethodProcesses();
|
| + } else if (!defer_ime_startup_) {
|
| + StartInputMethodProcesses();
|
| }
|
| - // Successfully sent. Remove the command and proceed to the next one.
|
| - pending_config_requests_.erase(iter++);
|
| - } else {
|
| - // If SetImeConfig() fails, subsequent calls will likely fail.
|
| - break;
|
| + chromeos::SetActiveInputMethods(input_method_status_connection_, value);
|
| }
|
| }
|
| - if (pending_config_requests_.empty()) {
|
| - // Calls to ChangeInputMethod() will fail if the input method has not yet
|
| - // been added to preload_engines. As such, the call is deferred until
|
| - // after all config values have been sent to the IME process.
|
| - if (need_input_method_set_) {
|
| - if (chromeos::ChangeInputMethod(input_method_status_connection_,
|
| - active_input_method_.c_str())) {
|
| - need_input_method_set_ = false;
|
| + }
|
| +
|
| + void FlushImeConfig() {
|
| + bool active_input_methods_are_changed = false;
|
| + bool completed = false;
|
| + if (EnsureLoadedAndStarted()) {
|
| + InputMethodConfigRequests::iterator iter =
|
| + pending_config_requests_.begin();
|
| + while (iter != pending_config_requests_.end()) {
|
| + const std::string& section = iter->first.first;
|
| + const std::string& config_name = iter->first.second;
|
| + const ImeConfigValue& value = iter->second;
|
| + if (chromeos::SetImeConfig(input_method_status_connection_,
|
| + section.c_str(),
|
| + config_name.c_str(),
|
| + value)) {
|
| + // Check if it's a change in active input methods.
|
| + if (config_name == kPreloadEnginesConfigName) {
|
| + active_input_methods_are_changed = true;
|
| + }
|
| + // Successfully sent. Remove the command and proceed to the next one.
|
| + pending_config_requests_.erase(iter++);
|
| + } else {
|
| + // If SetImeConfig() fails, subsequent calls will likely fail.
|
| + break;
|
| + }
|
| + }
|
| + if (pending_config_requests_.empty()) {
|
| + // Calls to ChangeInputMethod() will fail if the input method has not
|
| + // yet been added to preload_engines. As such, the call is deferred
|
| + // until after all config values have been sent to the IME process.
|
| + if (need_input_method_set_) {
|
| + if (chromeos::ChangeInputMethod(input_method_status_connection_,
|
| + active_input_method_.c_str())) {
|
| + need_input_method_set_ = false;
|
| + completed = true;
|
| + active_input_methods_are_changed = true;
|
| + }
|
| + } else {
|
| completed = true;
|
| - active_input_methods_are_changed = true;
|
| }
|
| - } else {
|
| - completed = true;
|
| }
|
| }
|
| - }
|
|
|
| - if (completed) {
|
| - timer_.Stop(); // no-op if it's not running.
|
| - } else {
|
| - if (!timer_.IsRunning()) {
|
| - static const int64 kTimerIntervalInMsec = 100;
|
| - timer_.Start(base::TimeDelta::FromMilliseconds(kTimerIntervalInMsec),
|
| - this, &InputMethodLibraryImpl::FlushImeConfig);
|
| + if (completed) {
|
| + timer_.Stop(); // no-op if it's not running.
|
| + } else {
|
| + if (!timer_.IsRunning()) {
|
| + static const int64 kTimerIntervalInMsec = 100;
|
| + timer_.Start(base::TimeDelta::FromMilliseconds(kTimerIntervalInMsec),
|
| + this, &InputMethodLibraryImpl::FlushImeConfig);
|
| + }
|
| + }
|
| + if (active_input_methods_are_changed) {
|
| + FOR_EACH_OBSERVER(Observer, observers_, ActiveInputMethodsChanged(this));
|
| }
|
| }
|
| - if (active_input_methods_are_changed) {
|
| - FOR_EACH_OBSERVER(Observer, observers_, ActiveInputMethodsChanged(this));
|
| +
|
| + static void InputMethodChangedHandler(
|
| + void* object,
|
| + const chromeos::InputMethodDescriptor& current_input_method) {
|
| + InputMethodLibraryImpl* input_method_library =
|
| + static_cast<InputMethodLibraryImpl*>(object);
|
| + input_method_library->UpdateCurrentInputMethod(current_input_method);
|
| }
|
| -}
|
|
|
| -// static
|
| -void InputMethodLibraryImpl::InputMethodChangedHandler(
|
| - void* object, const chromeos::InputMethodDescriptor& current_input_method) {
|
| - InputMethodLibraryImpl* input_method_library =
|
| - static_cast<InputMethodLibraryImpl*>(object);
|
| - input_method_library->UpdateCurrentInputMethod(current_input_method);
|
| -}
|
| + static void RegisterPropertiesHandler(
|
| + void* object, const ImePropertyList& prop_list) {
|
| + InputMethodLibraryImpl* input_method_library =
|
| + static_cast<InputMethodLibraryImpl*>(object);
|
| + input_method_library->RegisterProperties(prop_list);
|
| + }
|
|
|
| -// static
|
| -void InputMethodLibraryImpl::RegisterPropertiesHandler(
|
| - void* object, const ImePropertyList& prop_list) {
|
| - InputMethodLibraryImpl* input_method_library =
|
| - static_cast<InputMethodLibraryImpl*>(object);
|
| - input_method_library->RegisterProperties(prop_list);
|
| -}
|
| + static void UpdatePropertyHandler(
|
| + void* object, const ImePropertyList& prop_list) {
|
| + InputMethodLibraryImpl* input_method_library =
|
| + static_cast<InputMethodLibraryImpl*>(object);
|
| + input_method_library->UpdateProperty(prop_list);
|
| + }
|
|
|
| -// static
|
| -void InputMethodLibraryImpl::UpdatePropertyHandler(
|
| - void* object, const ImePropertyList& prop_list) {
|
| - InputMethodLibraryImpl* input_method_library =
|
| - static_cast<InputMethodLibraryImpl*>(object);
|
| - input_method_library->UpdateProperty(prop_list);
|
| -}
|
| + static void ConnectionChangeHandler(void* object, bool connected) {
|
| + InputMethodLibraryImpl* input_method_library =
|
| + static_cast<InputMethodLibraryImpl*>(object);
|
| + input_method_library->ime_connected_ = connected;
|
| + if (connected) {
|
| + input_method_library->pending_config_requests_.clear();
|
| + input_method_library->pending_config_requests_.insert(
|
| + input_method_library->current_config_values_.begin(),
|
| + input_method_library->current_config_values_.end());
|
| + // When the IME process starts up, the hardware layout will be the current
|
| + // method. If this is not correct, we'll need to explicitly change it.
|
| + if (input_method_library->active_input_method_ !=
|
| + kHardwareKeyboardLayout) {
|
| + input_method_library->need_input_method_set_ = true;
|
| + }
|
| + input_method_library->FlushImeConfig();
|
| + } else {
|
| + // Stop attempting to resend config data, since it will continue to fail.
|
| + input_method_library->timer_.Stop(); // no-op if it's not running.
|
| + }
|
| + }
|
|
|
| -// static
|
| -void InputMethodLibraryImpl::ConnectionChangeHandler(void* object,
|
| - bool connected) {
|
| - InputMethodLibraryImpl* input_method_library =
|
| - static_cast<InputMethodLibraryImpl*>(object);
|
| - input_method_library->ime_connected_ = connected;
|
| - if (connected) {
|
| - input_method_library->pending_config_requests_.clear();
|
| - input_method_library->pending_config_requests_.insert(
|
| - input_method_library->current_config_values_.begin(),
|
| - input_method_library->current_config_values_.end());
|
| - // When the IME process starts up, the hardware layout will be the current
|
| - // method. If this is not correct, we'll need to explicitly change it.
|
| - if (input_method_library->active_input_method_ != kHardwareKeyboardLayout) {
|
| - input_method_library->need_input_method_set_ = true;
|
| + bool EnsureStarted() {
|
| + if (!input_method_status_connection_) {
|
| + input_method_status_connection_ = chromeos::MonitorInputMethodStatus(
|
| + this,
|
| + &InputMethodChangedHandler,
|
| + &RegisterPropertiesHandler,
|
| + &UpdatePropertyHandler,
|
| + &ConnectionChangeHandler);
|
| }
|
| - input_method_library->FlushImeConfig();
|
| - } else {
|
| - // Stop attempting to resend config data, since it will continue to fail.
|
| - input_method_library->timer_.Stop(); // no-op if it's not running.
|
| + return true;
|
| }
|
| -}
|
|
|
| -bool InputMethodLibraryImpl::EnsureStarted() {
|
| - if (!input_method_status_connection_) {
|
| - input_method_status_connection_ = chromeos::MonitorInputMethodStatus(
|
| - this,
|
| - &InputMethodChangedHandler,
|
| - &RegisterPropertiesHandler,
|
| - &UpdatePropertyHandler,
|
| - &ConnectionChangeHandler);
|
| + bool EnsureLoadedAndStarted() {
|
| + return CrosLibrary::Get()->EnsureLoaded() &&
|
| + EnsureStarted();
|
| }
|
| - return true;
|
| -}
|
|
|
| -bool InputMethodLibraryImpl::EnsureLoadedAndStarted() {
|
| - return CrosLibrary::Get()->EnsureLoaded() &&
|
| - EnsureStarted();
|
| -}
|
| + void UpdateCurrentInputMethod(const InputMethodDescriptor& new_input_method) {
|
| + // Make sure we run on UI thread.
|
| + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
|
| + DLOG(INFO) << "UpdateCurrentInputMethod (Background thread)";
|
| + ChromeThread::PostTask(
|
| + ChromeThread::UI, FROM_HERE,
|
| + // NewRunnableMethod() copies |new_input_method| by value.
|
| + NewRunnableMethod(
|
| + this, &InputMethodLibraryImpl::UpdateCurrentInputMethod,
|
| + new_input_method));
|
| + return;
|
| + }
|
|
|
| -void InputMethodLibraryImpl::UpdateCurrentInputMethod(
|
| - const chromeos::InputMethodDescriptor& new_input_method) {
|
| - // Make sure we run on UI thread.
|
| - if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
|
| - DLOG(INFO) << "UpdateCurrentInputMethod (Background thread)";
|
| - ChromeThread::PostTask(
|
| - ChromeThread::UI, FROM_HERE,
|
| - // NewRunnableMethod() copies |new_input_method| by value.
|
| - NewRunnableMethod(
|
| - this, &InputMethodLibraryImpl::UpdateCurrentInputMethod,
|
| - new_input_method));
|
| - return;
|
| - }
|
| -
|
| - DLOG(INFO) << "UpdateCurrentInputMethod (UI thread)";
|
| - // Change the keyboard layout to a preferred layout for the input method.
|
| - CrosLibrary::Get()->GetKeyboardLibrary()->SetCurrentKeyboardLayoutByName(
|
| - new_input_method.keyboard_layout);
|
| -
|
| - if (current_input_method_.id != new_input_method.id) {
|
| - previous_input_method_ = current_input_method_;
|
| - current_input_method_ = new_input_method;
|
| - }
|
| - FOR_EACH_OBSERVER(Observer, observers_, InputMethodChanged(this));
|
| -}
|
| + DLOG(INFO) << "UpdateCurrentInputMethod (UI thread)";
|
| + // Change the keyboard layout to a preferred layout for the input method.
|
| + CrosLibrary::Get()->GetKeyboardLibrary()->SetCurrentKeyboardLayoutByName(
|
| + new_input_method.keyboard_layout);
|
|
|
| -void InputMethodLibraryImpl::RegisterProperties(
|
| - const ImePropertyList& prop_list) {
|
| - if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
|
| - ChromeThread::PostTask(
|
| - ChromeThread::UI, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this, &InputMethodLibraryImpl::RegisterProperties, prop_list));
|
| - return;
|
| + if (current_input_method_.id != new_input_method.id) {
|
| + previous_input_method_ = current_input_method_;
|
| + current_input_method_ = new_input_method;
|
| + }
|
| + FOR_EACH_OBSERVER(Observer, observers_, InputMethodChanged(this));
|
| }
|
|
|
| - // |prop_list| might be empty. This means "clear all properties."
|
| - current_ime_properties_ = prop_list;
|
| - FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
|
| -}
|
| + void RegisterProperties(const ImePropertyList& prop_list) {
|
| + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
|
| + ChromeThread::PostTask(
|
| + ChromeThread::UI, FROM_HERE,
|
| + NewRunnableMethod(
|
| + this, &InputMethodLibraryImpl::RegisterProperties, prop_list));
|
| + return;
|
| + }
|
|
|
| -void InputMethodLibraryImpl::UpdateProperty(const ImePropertyList& prop_list) {
|
| - if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
|
| - ChromeThread::PostTask(
|
| - ChromeThread::UI, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this, &InputMethodLibraryImpl::UpdateProperty, prop_list));
|
| - return;
|
| + // |prop_list| might be empty. This means "clear all properties."
|
| + current_ime_properties_ = prop_list;
|
| + FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
|
| }
|
|
|
| - for (size_t i = 0; i < prop_list.size(); ++i) {
|
| - FindAndUpdateProperty(prop_list[i], ¤t_ime_properties_);
|
| + void StartInputMethodProcesses() {
|
| + ime_running_ = true;
|
| + MaybeLaunchIme();
|
| }
|
| - FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
|
| -}
|
|
|
| -void InputMethodLibraryImpl::StartInputMethodProcesses() {
|
| - ime_running_ = true;
|
| - MaybeLaunchIme();
|
| -}
|
| + void UpdateProperty(const ImePropertyList& prop_list) {
|
| + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
|
| + ChromeThread::PostTask(
|
| + ChromeThread::UI, FROM_HERE,
|
| + NewRunnableMethod(
|
| + this, &InputMethodLibraryImpl::UpdateProperty, prop_list));
|
| + return;
|
| + }
|
|
|
| -void InputMethodLibraryImpl::MaybeLaunchIme() {
|
| - if (!ime_running_) {
|
| - return;
|
| + for (size_t i = 0; i < prop_list.size(); ++i) {
|
| + FindAndUpdateProperty(prop_list[i], ¤t_ime_properties_);
|
| + }
|
| + FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
|
| }
|
|
|
| - // TODO(zork): export "LD_PRELOAD=/usr/lib/libcrash.so"
|
| - GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD;
|
| - if (ime_handle_ == 0) {
|
| - GError *error = NULL;
|
| - gchar **argv;
|
| - gint argc;
|
| -
|
| - if (!g_shell_parse_argv(
|
| - "/usr/bin/ibus-daemon --panel=disable --cache=none --restart",
|
| - &argc, &argv, &error)) {
|
| - LOG(ERROR) << "Could not parse command: " << error->message;
|
| - g_error_free(error);
|
| + void MaybeLaunchIme() {
|
| + if (!ime_running_) {
|
| return;
|
| }
|
|
|
| - error = NULL;
|
| - int handle;
|
| - // TODO(zork): Send output to /var/log/ibus.log
|
| - gboolean result = g_spawn_async(NULL, argv, NULL,
|
| - flags, NULL, NULL,
|
| - &handle, &error);
|
| - g_strfreev(argv);
|
| - if (!result) {
|
| - LOG(ERROR) << "Could not launch ime: " << error->message;
|
| - g_error_free(error);
|
| - return;
|
| + // TODO(zork): export "LD_PRELOAD=/usr/lib/libcrash.so"
|
| + GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD;
|
| + if (ime_handle_ == 0) {
|
| + GError *error = NULL;
|
| + gchar **argv;
|
| + gint argc;
|
| +
|
| + if (!g_shell_parse_argv(
|
| + "/usr/bin/ibus-daemon --panel=disable --cache=none --restart",
|
| + &argc, &argv, &error)) {
|
| + LOG(ERROR) << "Could not parse command: " << error->message;
|
| + g_error_free(error);
|
| + return;
|
| + }
|
| +
|
| + error = NULL;
|
| + int handle;
|
| + // TODO(zork): Send output to /var/log/ibus.log
|
| + gboolean result = g_spawn_async(NULL, argv, NULL,
|
| + flags, NULL, NULL,
|
| + &handle, &error);
|
| + g_strfreev(argv);
|
| + if (!result) {
|
| + LOG(ERROR) << "Could not launch ime: " << error->message;
|
| + g_error_free(error);
|
| + return;
|
| + }
|
| + ime_handle_ = handle;
|
| + g_child_watch_add(ime_handle_, (GChildWatchFunc)OnImeShutdown, this);
|
| }
|
| - ime_handle_ = handle;
|
| - g_child_watch_add(ime_handle_, (GChildWatchFunc)OnImeShutdown, this);
|
| - }
|
|
|
| - if (candidate_window_handle_ == 0) {
|
| - GError *error = NULL;
|
| - gchar **argv;
|
| - gint argc;
|
| + if (candidate_window_handle_ == 0) {
|
| + GError *error = NULL;
|
| + gchar **argv;
|
| + gint argc;
|
|
|
| - if (!g_shell_parse_argv("/opt/google/chrome/candidate_window",
|
| - &argc, &argv, &error)) {
|
| - LOG(ERROR) << "Could not parse command: " << error->message;
|
| - g_error_free(error);
|
| - return;
|
| + if (!g_shell_parse_argv("/opt/google/chrome/candidate_window",
|
| + &argc, &argv, &error)) {
|
| + LOG(ERROR) << "Could not parse command: " << error->message;
|
| + g_error_free(error);
|
| + return;
|
| + }
|
| +
|
| + error = NULL;
|
| + int handle;
|
| + gboolean result = g_spawn_async(NULL, argv, NULL,
|
| + flags, NULL, NULL,
|
| + &handle, &error);
|
| + g_strfreev(argv);
|
| + if (!result) {
|
| + LOG(ERROR) << "Could not launch ime candidate window" << error->message;
|
| + g_error_free(error);
|
| + return;
|
| + }
|
| + candidate_window_handle_ = handle;
|
| + g_child_watch_add(candidate_window_handle_,
|
| + (GChildWatchFunc)OnImeShutdown, this);
|
| }
|
| + }
|
|
|
| - error = NULL;
|
| - int handle;
|
| - gboolean result = g_spawn_async(NULL, argv, NULL,
|
| - flags, NULL, NULL,
|
| - &handle, &error);
|
| - g_strfreev(argv);
|
| - if (!result) {
|
| - LOG(ERROR) << "Could not launch ime candidate window" << error->message;
|
| - g_error_free(error);
|
| - return;
|
| + static void OnImeShutdown(int pid,
|
| + int status,
|
| + InputMethodLibraryImpl* library) {
|
| + g_spawn_close_pid(pid);
|
| + if (library->ime_handle_ == pid) {
|
| + library->ime_handle_ = 0;
|
| + } else if (library->candidate_window_handle_ == pid) {
|
| + library->candidate_window_handle_ = 0;
|
| }
|
| - candidate_window_handle_ = handle;
|
| - g_child_watch_add(candidate_window_handle_,
|
| - (GChildWatchFunc)OnImeShutdown, this);
|
| +
|
| + library->MaybeLaunchIme();
|
| }
|
| -}
|
|
|
| -void InputMethodLibraryImpl::StopInputMethodProcesses() {
|
| - ime_running_ = false;
|
| - if (ime_handle_) {
|
| - kill(ime_handle_, SIGTERM);
|
| - ime_handle_ = 0;
|
| + void StopInputMethodProcesses() {
|
| + ime_running_ = false;
|
| + if (ime_handle_) {
|
| + kill(ime_handle_, SIGTERM);
|
| + ime_handle_ = 0;
|
| + }
|
| }
|
| - if (candidate_window_handle_) {
|
| - kill(candidate_window_handle_, SIGTERM);
|
| - candidate_window_handle_ = 0;
|
| +
|
| + void SetDeferImeStartup(bool defer) {
|
| + defer_ime_startup_ = defer;
|
| + }
|
| + // A reference to the language api, to allow callbacks when the input method
|
| + // status changes.
|
| + InputMethodStatusConnection* input_method_status_connection_;
|
| + ObserverList<Observer> observers_;
|
| +
|
| + // The input method which was/is selected.
|
| + InputMethodDescriptor previous_input_method_;
|
| + InputMethodDescriptor current_input_method_;
|
| +
|
| + // The input method properties which the current input method uses. The list
|
| + // might be empty when no input method is used.
|
| + ImePropertyList current_ime_properties_;
|
| +
|
| + typedef std::pair<std::string, std::string> ConfigKeyType;
|
| + typedef std::map<ConfigKeyType, ImeConfigValue> InputMethodConfigRequests;
|
| + // SetImeConfig requests that are not yet completed.
|
| + // Use a map to queue config requests, so we only send the last request for
|
| + // the same config key (i.e. we'll discard ealier requests for the same
|
| + // config key). As we discard old requests for the same config key, the order
|
| + // of requests doesn't matter, so it's safe to use a map.
|
| + InputMethodConfigRequests pending_config_requests_;
|
| +
|
| + // Values that have been set via SetImeConfig(). We keep a copy available to
|
| + // resend if the ime restarts and loses its state.
|
| + InputMethodConfigRequests current_config_values_;
|
| +
|
| + // A timer for retrying to send |pendning_config_commands_| to the input
|
| + // method config daemon.
|
| + base::OneShotTimer<InputMethodLibraryImpl> timer_;
|
| +
|
| + bool ime_running_;
|
| + bool ime_connected_;
|
| + bool defer_ime_startup_;
|
| + std::string active_input_method_;
|
| + bool need_input_method_set_;
|
| +
|
| + int ime_handle_;
|
| + int candidate_window_handle_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(InputMethodLibraryImpl);
|
| +};
|
| +
|
| +InputMethodLibraryImpl::Observer::~Observer() {}
|
| +
|
| +class InputMethodLibraryStubImpl : public InputMethodLibrary {
|
| + public:
|
| + InputMethodLibraryStubImpl()
|
| + : previous_input_method_("", "", "", ""),
|
| + current_input_method_("", "", "", "") {
|
| }
|
| -}
|
|
|
| -void InputMethodLibraryImpl::SetDeferImeStartup(bool defer) {
|
| - defer_ime_startup_ = defer;
|
| -}
|
| + ~InputMethodLibraryStubImpl() {}
|
| + void AddObserver(Observer* observer) {}
|
| + void RemoveObserver(Observer* observer) {}
|
|
|
| -// static
|
| -void InputMethodLibraryImpl::OnImeShutdown(int pid, int status,
|
| - InputMethodLibraryImpl* library) {
|
| - g_spawn_close_pid(pid);
|
| - if (library->ime_handle_ == pid) {
|
| - library->ime_handle_ = 0;
|
| - } else if (library->candidate_window_handle_ == pid) {
|
| - library->candidate_window_handle_ = 0;
|
| + InputMethodDescriptors* GetActiveInputMethods() {
|
| + return CreateFallbackInputMethodDescriptors();
|
| + }
|
| +
|
| +
|
| + size_t GetNumActiveInputMethods() {
|
| + return CreateFallbackInputMethodDescriptors()->size();
|
| }
|
|
|
| - library->MaybeLaunchIme();
|
| + InputMethodDescriptors* GetSupportedInputMethods() {
|
| + return CreateFallbackInputMethodDescriptors();
|
| + }
|
| +
|
| + void ChangeInputMethod(const std::string& input_method_id) {}
|
| + void SetImePropertyActivated(const std::string& key, bool activated) {}
|
| +
|
| + bool InputMethodIsActivated(const std::string& input_method_id) {
|
| + return true;
|
| + }
|
| +
|
| + bool GetImeConfig(const char* section,
|
| + const char* config_name,
|
| + ImeConfigValue* out_value) {
|
| + return false;
|
| + }
|
| +
|
| + bool SetImeConfig(const char* section,
|
| + const char* config_name,
|
| + const ImeConfigValue& value) {
|
| + return false;
|
| + }
|
| +
|
| + virtual const InputMethodDescriptor& previous_input_method() const {
|
| + return previous_input_method_;
|
| + }
|
| +
|
| + virtual const InputMethodDescriptor& current_input_method() const {
|
| + return current_input_method_;
|
| + }
|
| +
|
| + virtual const ImePropertyList& current_ime_properties() const {
|
| + return current_ime_properties_;
|
| + }
|
| +
|
| + virtual void StartInputMethodProcesses() {}
|
| + virtual void StopInputMethodProcesses() {}
|
| + virtual void SetDeferImeStartup(bool defer) {}
|
| +
|
| + private:
|
| + InputMethodDescriptor previous_input_method_;
|
| + InputMethodDescriptor current_input_method_;
|
| + ImePropertyList current_ime_properties_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(InputMethodLibraryStubImpl);
|
| +};
|
| +
|
| +// static
|
| +InputMethodLibrary* InputMethodLibrary::GetImpl(bool stub) {
|
| + if (stub)
|
| + return new InputMethodLibraryStubImpl();
|
| + else
|
| + return new InputMethodLibraryImpl();
|
| }
|
|
|
| } // namespace chromeos
|
| +
|
| +// Allows InvokeLater without adding refcounting. This class is a Singleton and
|
| +// won't be deleted until it's last InvokeLater is run.
|
| +DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::InputMethodLibraryImpl);
|
| +
|
|
|