OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/chromeos/input_method/input_method_engine_ibus.h" |
| 6 |
| 7 #include <map> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/string_number_conversions.h" |
| 12 #include "base/string_util.h" |
| 13 #include "chrome/browser/chromeos/input_method/ibus_keymap.h" |
| 14 #include "chrome/browser/chromeos/input_method/input_method_manager.h" |
| 15 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
| 16 #include "chromeos/dbus/dbus_thread_manager.h" |
| 17 #include "chromeos/dbus/ibus/ibus_client.h" |
| 18 #include "chromeos/dbus/ibus/ibus_component.h" |
| 19 #include "chromeos/dbus/ibus/ibus_engine_factory_service.h" |
| 20 #include "chromeos/dbus/ibus/ibus_engine_service.h" |
| 21 #include "chromeos/dbus/ibus/ibus_lookup_table.h" |
| 22 #include "chromeos/dbus/ibus/ibus_property.h" |
| 23 #include "chromeos/dbus/ibus/ibus_text.h" |
| 24 #include "dbus/object_path.h" |
| 25 |
| 26 namespace chromeos { |
| 27 const char* kExtensionImePrefix = "_ext_ime_"; |
| 28 const char* kErrorNotActive = "IME is not active"; |
| 29 const char* kErrorWrongContext = "Context is not active"; |
| 30 const char* kCandidateNotFound = "Candidate not found"; |
| 31 const char* kEngineBusPrefix = "org.freedesktop.IBus."; |
| 32 const char* kObjectPathPrefix = "/org/freedesktop/IBus/Engine/"; |
| 33 |
| 34 namespace { |
| 35 const uint32 kIBusAltKeyMask = 1 << 3; |
| 36 const uint32 kIBusCtrlKeyMask = 1 << 2; |
| 37 const uint32 kIBusShiftKeyMask = 1 << 0; |
| 38 const uint32 kIBusKeyReleaseMask = 1 << 30; |
| 39 } |
| 40 |
| 41 InputMethodEngineIBus::InputMethodEngineIBus() |
| 42 : focused_(false), |
| 43 active_(false), |
| 44 context_id_(0), |
| 45 next_context_id_(1), |
| 46 current_object_path_(0), |
| 47 aux_text_(new ibus::IBusText()), |
| 48 aux_text_visible_(false), |
| 49 observer_(NULL), |
| 50 preedit_text_(new ibus::IBusText()), |
| 51 preedit_cursor_(0), |
| 52 component_(new ibus::IBusComponent()), |
| 53 table_(new ibus::IBusLookupTable()), |
| 54 table_visible_(false), |
| 55 weak_ptr_factory_(this) { |
| 56 } |
| 57 |
| 58 void InputMethodEngineIBus::Initialize( |
| 59 InputMethodEngine::Observer* observer, |
| 60 const char* engine_name, |
| 61 const char* extension_id, |
| 62 const char* engine_id, |
| 63 const char* description, |
| 64 const char* language, |
| 65 const std::vector<std::string>& layouts, |
| 66 std::string* error) { |
| 67 DCHECK(observer) << "Observer must not be null."; |
| 68 |
| 69 observer_ = observer; |
| 70 engine_id_ = engine_id; |
| 71 ibus_id_ = kExtensionImePrefix; |
| 72 ibus_id_ += extension_id; |
| 73 ibus_id_ += engine_id; |
| 74 |
| 75 input_method::InputMethodManager* manager = |
| 76 input_method::InputMethodManager::GetInstance(); |
| 77 std::string layout; |
| 78 if (!layouts.empty()) { |
| 79 layout = JoinString(layouts, ','); |
| 80 } else { |
| 81 input_method::InputMethodManager* manager = |
| 82 input_method::InputMethodManager::GetInstance(); |
| 83 const std::string fallback_id = |
| 84 manager->GetInputMethodUtil()->GetHardwareInputMethodId(); |
| 85 const input_method::InputMethodDescriptor* fallback_desc = |
| 86 manager->GetInputMethodUtil()->GetInputMethodDescriptorFromId( |
| 87 fallback_id); |
| 88 layout = fallback_desc->keyboard_layout(); |
| 89 } |
| 90 |
| 91 component_.reset(new ibus::IBusComponent()); |
| 92 component_->set_name(std::string(kEngineBusPrefix) + std::string(engine_id)); |
| 93 component_->set_description(description); |
| 94 component_->set_author(engine_name); |
| 95 |
| 96 chromeos::ibus::IBusComponent::EngineDescription engine_desc; |
| 97 engine_desc.engine_id = ibus_id_; |
| 98 engine_desc.display_name = description; |
| 99 engine_desc.description = description; |
| 100 engine_desc.language_code = language; |
| 101 engine_desc.author = ibus_id_; |
| 102 engine_desc.layout = layout.c_str(); |
| 103 |
| 104 component_->mutable_engine_description()->push_back(engine_desc); |
| 105 manager->AddInputMethodExtension(ibus_id_, engine_name, layouts, language, |
| 106 this); |
| 107 // If connection is avaiable, register component. If there are no connection |
| 108 // to ibus-daemon, OnConnected callback will register component instead. |
| 109 if (IsConnected()) |
| 110 RegisterComponent(); |
| 111 } |
| 112 |
| 113 InputMethodEngineIBus::~InputMethodEngineIBus() { |
| 114 } |
| 115 |
| 116 bool InputMethodEngineIBus::SetComposition( |
| 117 int context_id, |
| 118 const char* text, |
| 119 int selection_start, |
| 120 int selection_end, |
| 121 int cursor, |
| 122 const std::vector<SegmentInfo>& segments, |
| 123 std::string* error) { |
| 124 if (!active_) { |
| 125 *error = kErrorNotActive; |
| 126 return false; |
| 127 } |
| 128 if (context_id != context_id_ || context_id_ == -1) { |
| 129 *error = kErrorWrongContext; |
| 130 return false; |
| 131 } |
| 132 |
| 133 preedit_cursor_ = cursor; |
| 134 preedit_text_.reset(new ibus::IBusText()); |
| 135 preedit_text_->set_text(text); |
| 136 |
| 137 // TODO: Add support for displaying selected text in the composition string. |
| 138 for (std::vector<SegmentInfo>::const_iterator segment = segments.begin(); |
| 139 segment != segments.end(); ++segment) { |
| 140 ibus::IBusText::UnderlineAttribute underline; |
| 141 |
| 142 switch (segment->style) { |
| 143 case SEGMENT_STYLE_UNDERLINE: |
| 144 underline.type = ibus::IBusText::IBUS_TEXT_UNDERLINE_SINGLE; |
| 145 break; |
| 146 case SEGMENT_STYLE_DOUBLE_UNDERLINE: |
| 147 underline.type = ibus::IBusText::IBUS_TEXT_UNDERLINE_DOUBLE; |
| 148 break; |
| 149 default: |
| 150 continue; |
| 151 } |
| 152 |
| 153 underline.start_index = segment->start; |
| 154 underline.end_index = segment->end; |
| 155 preedit_text_->mutable_underline_attributes()->push_back(underline); |
| 156 } |
| 157 |
| 158 // TODO(nona): Makes focus out mode configuable, if necessary. |
| 159 GetCurrentService()->UpdatePreedit( |
| 160 *preedit_text_.get(), |
| 161 preedit_cursor_, |
| 162 true, |
| 163 chromeos::IBusEngineService::IBUS_ENGINE_PREEEDIT_FOCUS_OUT_MODE_COMMIT); |
| 164 return true; |
| 165 } |
| 166 |
| 167 bool InputMethodEngineIBus::ClearComposition(int context_id, |
| 168 std::string* error) { |
| 169 if (!active_) { |
| 170 *error = kErrorNotActive; |
| 171 return false; |
| 172 } |
| 173 if (context_id != context_id_ || context_id_ == -1) { |
| 174 *error = kErrorWrongContext; |
| 175 return false; |
| 176 } |
| 177 |
| 178 preedit_cursor_ = 0; |
| 179 preedit_text_.reset(new ibus::IBusText()); |
| 180 GetCurrentService()->UpdatePreedit( |
| 181 *preedit_text_.get(), |
| 182 0, |
| 183 true, |
| 184 chromeos::IBusEngineService::IBUS_ENGINE_PREEEDIT_FOCUS_OUT_MODE_COMMIT); |
| 185 return true; |
| 186 } |
| 187 |
| 188 bool InputMethodEngineIBus::CommitText(int context_id, const char* text, |
| 189 std::string* error) { |
| 190 if (!active_) { |
| 191 // TODO: Commit the text anyways. |
| 192 *error = kErrorNotActive; |
| 193 return false; |
| 194 } |
| 195 if (context_id != context_id_ || context_id_ == -1) { |
| 196 *error = kErrorWrongContext; |
| 197 return false; |
| 198 } |
| 199 |
| 200 GetCurrentService()->CommitText(text); |
| 201 return true; |
| 202 } |
| 203 |
| 204 bool InputMethodEngineIBus::SetCandidateWindowVisible(bool visible, |
| 205 std::string* error) { |
| 206 if (!active_) { |
| 207 *error = kErrorNotActive; |
| 208 return false; |
| 209 } |
| 210 |
| 211 table_visible_ = visible; |
| 212 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_); |
| 213 return true; |
| 214 } |
| 215 |
| 216 void InputMethodEngineIBus::SetCandidateWindowCursorVisible(bool visible) { |
| 217 if (!active_) |
| 218 return; |
| 219 table_->set_is_cursor_visible(visible); |
| 220 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_); |
| 221 } |
| 222 |
| 223 void InputMethodEngineIBus::SetCandidateWindowVertical(bool vertical) { |
| 224 if (!active_) |
| 225 return; |
| 226 table_->set_orientation( |
| 227 vertical ? ibus::IBusLookupTable::IBUS_LOOKUP_TABLE_ORIENTATION_VERTICAL : |
| 228 ibus::IBusLookupTable::IBUS_LOOKUP_TABLE_ORIENTATION_HORIZONTAL); |
| 229 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_); |
| 230 } |
| 231 |
| 232 void InputMethodEngineIBus::SetCandidateWindowPageSize(int size) { |
| 233 if (!active_) |
| 234 return; |
| 235 table_->set_page_size(size); |
| 236 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_); |
| 237 } |
| 238 |
| 239 void InputMethodEngineIBus::SetCandidateWindowAuxText(const char* text) { |
| 240 if (!active_) |
| 241 return; |
| 242 aux_text_->set_text(text); |
| 243 GetCurrentService()->UpdateAuxiliaryText(*aux_text_.get(), aux_text_visible_); |
| 244 } |
| 245 |
| 246 void InputMethodEngineIBus::SetCandidateWindowAuxTextVisible(bool visible) { |
| 247 if (!active_) |
| 248 return; |
| 249 aux_text_visible_ = visible; |
| 250 GetCurrentService()->UpdateAuxiliaryText(*aux_text_.get(), aux_text_visible_); |
| 251 } |
| 252 |
| 253 bool InputMethodEngineIBus::SetCandidates( |
| 254 int context_id, |
| 255 const std::vector<Candidate>& candidates, |
| 256 std::string* error) { |
| 257 if (!active_) { |
| 258 *error = kErrorNotActive; |
| 259 return false; |
| 260 } |
| 261 if (context_id != context_id_ || context_id_ == -1) { |
| 262 *error = kErrorWrongContext; |
| 263 return false; |
| 264 } |
| 265 |
| 266 // TODO: Nested candidates |
| 267 candidate_ids_.clear(); |
| 268 candidate_indexes_.clear(); |
| 269 table_->mutable_candidates()->clear(); |
| 270 for (std::vector<Candidate>::const_iterator ix = candidates.begin(); |
| 271 ix != candidates.end(); ++ix) { |
| 272 ibus::IBusLookupTable::Entry entry; |
| 273 // TODO(nona): support annotation(crbug.com/140186). |
| 274 entry.value = ix->value + " " + ix->annotation; |
| 275 entry.label = ix->label; |
| 276 |
| 277 // Store a mapping from the user defined ID to the candidate index. |
| 278 candidate_indexes_[ix->id] = candidate_ids_.size(); |
| 279 candidate_ids_.push_back(ix->id); |
| 280 |
| 281 table_->mutable_candidates()->push_back(entry); |
| 282 } |
| 283 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_); |
| 284 return true; |
| 285 } |
| 286 |
| 287 bool InputMethodEngineIBus::SetCursorPosition(int context_id, int candidate_id, |
| 288 std::string* error) { |
| 289 if (!active_) { |
| 290 *error = kErrorNotActive; |
| 291 return false; |
| 292 } |
| 293 if (context_id != context_id_ || context_id_ == -1) { |
| 294 *error = kErrorWrongContext; |
| 295 return false; |
| 296 } |
| 297 |
| 298 std::map<int, int>::const_iterator position = |
| 299 candidate_indexes_.find(candidate_id); |
| 300 if (position == candidate_indexes_.end()) { |
| 301 *error = kCandidateNotFound; |
| 302 return false; |
| 303 } |
| 304 |
| 305 table_->set_cursor_position(position->second); |
| 306 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_); |
| 307 return true; |
| 308 } |
| 309 |
| 310 bool InputMethodEngineIBus::SetMenuItems(const std::vector<MenuItem>& items) { |
| 311 if (!active_) |
| 312 return false; |
| 313 |
| 314 ibus::IBusPropertyList properties; |
| 315 for (std::vector<MenuItem>::const_iterator item = items.begin(); |
| 316 item != items.end(); ++item) { |
| 317 ibus::IBusProperty* property = new ibus::IBusProperty(); |
| 318 if (!MenuItemToProperty(*item, property)) { |
| 319 delete property; |
| 320 DVLOG(1) << "Bad menu item"; |
| 321 return false; |
| 322 } |
| 323 properties.push_back(property); |
| 324 } |
| 325 GetCurrentService()->RegisterProperties(properties); |
| 326 return true; |
| 327 } |
| 328 |
| 329 bool InputMethodEngineIBus::UpdateMenuItems( |
| 330 const std::vector<MenuItem>& items) { |
| 331 if (!active_) |
| 332 return false; |
| 333 |
| 334 ibus::IBusPropertyList properties; |
| 335 for (std::vector<MenuItem>::const_iterator item = items.begin(); |
| 336 item != items.end(); ++item) { |
| 337 ibus::IBusProperty* property = new ibus::IBusProperty(); |
| 338 if (!MenuItemToProperty(*item, property)) { |
| 339 delete property; |
| 340 DVLOG(1) << "Bad menu item"; |
| 341 return false; |
| 342 } |
| 343 properties.push_back(property); |
| 344 } |
| 345 GetCurrentService()->RegisterProperties(properties); |
| 346 return true; |
| 347 } |
| 348 |
| 349 bool InputMethodEngineIBus::IsActive() const { |
| 350 return active_; |
| 351 } |
| 352 |
| 353 void InputMethodEngineIBus::KeyEventDone(input_method::KeyEventHandle* key_data, |
| 354 bool handled) { |
| 355 KeyEventDoneCallback* callback = |
| 356 reinterpret_cast<KeyEventDoneCallback*>(key_data); |
| 357 callback->Run(handled); |
| 358 delete callback; |
| 359 } |
| 360 |
| 361 void InputMethodEngineIBus::FocusIn() { |
| 362 focused_ = true; |
| 363 if (!active_) |
| 364 return; |
| 365 context_id_ = next_context_id_; |
| 366 ++next_context_id_; |
| 367 |
| 368 InputContext context; |
| 369 context.id = context_id_; |
| 370 // TODO: Other types |
| 371 context.type = "text"; |
| 372 |
| 373 observer_->OnFocus(context); |
| 374 } |
| 375 |
| 376 void InputMethodEngineIBus::FocusOut() { |
| 377 focused_ = false; |
| 378 if (!active_) |
| 379 return; |
| 380 int context_id = context_id_; |
| 381 context_id_ = -1; |
| 382 observer_->OnBlur(context_id); |
| 383 } |
| 384 |
| 385 void InputMethodEngineIBus::Enable() { |
| 386 active_ = true; |
| 387 observer_->OnActivate(engine_id_); |
| 388 FocusIn(); |
| 389 } |
| 390 |
| 391 void InputMethodEngineIBus::Disable() { |
| 392 active_ = false; |
| 393 observer_->OnDeactivated(engine_id_); |
| 394 } |
| 395 |
| 396 void InputMethodEngineIBus::PropertyActivate( |
| 397 const std::string& property_name, |
| 398 IBusPropertyState property_state) { |
| 399 observer_->OnMenuItemActivated(engine_id_, property_name); |
| 400 } |
| 401 |
| 402 void InputMethodEngineIBus::PropertyShow( |
| 403 const std::string& property_name) { |
| 404 } |
| 405 |
| 406 void InputMethodEngineIBus::PropertyHide( |
| 407 const std::string& property_name) { |
| 408 } |
| 409 |
| 410 void InputMethodEngineIBus::SetCapability( |
| 411 IBusCapability capability) { |
| 412 } |
| 413 |
| 414 void InputMethodEngineIBus::Reset() { |
| 415 } |
| 416 |
| 417 void InputMethodEngineIBus::ProcessKeyEvent( |
| 418 uint32 keysym, |
| 419 uint32 keycode, |
| 420 uint32 state, |
| 421 const KeyEventDoneCallback& callback) { |
| 422 |
| 423 KeyEventDoneCallback *handler = new KeyEventDoneCallback(); |
| 424 *handler = callback; |
| 425 |
| 426 KeyboardEvent event; |
| 427 event.type = !(state & kIBusKeyReleaseMask) ? "keydown" : "keyup"; |
| 428 event.key = input_method::GetIBusKey(keysym); |
| 429 event.alt_key = state & kIBusAltKeyMask; |
| 430 event.ctrl_key = state & kIBusCtrlKeyMask; |
| 431 event.shift_key = state & kIBusShiftKeyMask; |
| 432 observer_->OnKeyEvent( |
| 433 engine_id_, |
| 434 event, |
| 435 reinterpret_cast<input_method::KeyEventHandle*>(handler)); |
| 436 } |
| 437 |
| 438 void InputMethodEngineIBus::CandidateClicked( |
| 439 uint32 index, |
| 440 IBusMouseButton button, |
| 441 uint32 state) { |
| 442 if (index > candidate_ids_.size()) { |
| 443 return; |
| 444 } |
| 445 |
| 446 MouseButtonEvent pressed_button; |
| 447 switch (button) { |
| 448 case IBusEngineHandlerInterface::IBUS_MOUSE_BUTTON_LEFT: |
| 449 pressed_button = MOUSE_BUTTON_LEFT; |
| 450 break; |
| 451 case IBusEngineHandlerInterface::IBUS_MOUSE_BUTTON_MIDDLE: |
| 452 pressed_button = MOUSE_BUTTON_MIDDLE; |
| 453 break; |
| 454 case IBusEngineHandlerInterface::IBUS_MOUSE_BUTTON_RIGHT: |
| 455 pressed_button = MOUSE_BUTTON_RIGHT; |
| 456 break; |
| 457 default: |
| 458 DVLOG(1) << "Unknown button: " << button; |
| 459 pressed_button = MOUSE_BUTTON_LEFT; |
| 460 break; |
| 461 } |
| 462 |
| 463 observer_->OnCandidateClicked( |
| 464 engine_id_, candidate_ids_.at(index), pressed_button); |
| 465 } |
| 466 |
| 467 void InputMethodEngineIBus::SetSurroundingText( |
| 468 const std::string& text, |
| 469 uint32 cursor_pos, |
| 470 uint32 anchor_pos) { |
| 471 } |
| 472 |
| 473 IBusEngineService* InputMethodEngineIBus::GetCurrentService() { |
| 474 return DBusThreadManager::Get()->GetIBusEngineService(object_path_); |
| 475 } |
| 476 |
| 477 bool InputMethodEngineIBus::MenuItemToProperty( |
| 478 const MenuItem& item, |
| 479 ibus::IBusProperty* property) { |
| 480 property->set_key(item.id); |
| 481 |
| 482 if (item.modified & MENU_ITEM_MODIFIED_LABEL) { |
| 483 property->set_label(item.label); |
| 484 } |
| 485 if (item.modified & MENU_ITEM_MODIFIED_VISIBLE) { |
| 486 property->set_visible(item.visible); |
| 487 } |
| 488 if (item.modified & MENU_ITEM_MODIFIED_CHECKED) { |
| 489 property->set_checked(item.checked); |
| 490 } |
| 491 if (item.modified & MENU_ITEM_MODIFIED_ENABLED) { |
| 492 // TODO(nona): implement sensitive entry(crbug.com/140192). |
| 493 } |
| 494 if (item.modified & MENU_ITEM_MODIFIED_STYLE) { |
| 495 ibus::IBusProperty::IBusPropertyType type = |
| 496 ibus::IBusProperty::IBUS_PROPERTY_TYPE_NORMAL; |
| 497 if (!item.children.empty()) { |
| 498 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_MENU; |
| 499 } else { |
| 500 switch (item.style) { |
| 501 case MENU_ITEM_STYLE_NONE: |
| 502 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_NORMAL; |
| 503 break; |
| 504 case MENU_ITEM_STYLE_CHECK: |
| 505 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_TOGGLE; |
| 506 break; |
| 507 case MENU_ITEM_STYLE_RADIO: |
| 508 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_RADIO; |
| 509 break; |
| 510 case MENU_ITEM_STYLE_SEPARATOR: |
| 511 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_SEPARATOR; |
| 512 break; |
| 513 } |
| 514 } |
| 515 property->set_type(type); |
| 516 } |
| 517 |
| 518 for (std::vector<MenuItem>::const_iterator child = item.children.begin(); |
| 519 child != item.children.end(); ++child) { |
| 520 ibus::IBusProperty* new_property = new ibus::IBusProperty(); |
| 521 if (!MenuItemToProperty(*child, new_property)) { |
| 522 delete new_property; |
| 523 DVLOG(1) << "Bad menu item child"; |
| 524 return false; |
| 525 } |
| 526 property->mutable_sub_properties()->push_back(new_property); |
| 527 } |
| 528 |
| 529 return true; |
| 530 } |
| 531 |
| 532 void InputMethodEngineIBus::OnConnected() { |
| 533 RegisterComponent(); |
| 534 } |
| 535 |
| 536 void InputMethodEngineIBus::OnDisconnected() { |
| 537 } |
| 538 |
| 539 bool InputMethodEngineIBus::IsConnected() { |
| 540 return DBusThreadManager::Get()->GetIBusClient() != NULL; |
| 541 } |
| 542 |
| 543 void InputMethodEngineIBus::RegisterComponent() { |
| 544 chromeos::IBusClient* client = |
| 545 chromeos::DBusThreadManager::Get()->GetIBusClient(); |
| 546 client->RegisterComponent( |
| 547 *component_.get(), |
| 548 base::Bind(&InputMethodEngineIBus::OnComponentRegistered, |
| 549 weak_ptr_factory_.GetWeakPtr()), |
| 550 base::Bind(&InputMethodEngineIBus::OnComponentRegistrationFailed, |
| 551 weak_ptr_factory_.GetWeakPtr())); |
| 552 } |
| 553 |
| 554 void InputMethodEngineIBus::OnComponentRegistered() { |
| 555 DBusThreadManager::Get()->GetIBusEngineFactoryService()-> |
| 556 SetCreateEngineHandler(ibus_id_, |
| 557 base::Bind( |
| 558 &InputMethodEngineIBus::CreateEngineHandler, |
| 559 weak_ptr_factory_.GetWeakPtr())); |
| 560 } |
| 561 |
| 562 void InputMethodEngineIBus::OnComponentRegistrationFailed() { |
| 563 DVLOG(1) << "Failed to register input method components."; |
| 564 // TODO(nona): Implement error handling. |
| 565 } |
| 566 |
| 567 void InputMethodEngineIBus::CreateEngineHandler( |
| 568 const IBusEngineFactoryService::CreateEngineResponseSender& sender) { |
| 569 DBusThreadManager::Get()->RemoveIBusEngineService(object_path_); |
| 570 |
| 571 current_object_path_++; |
| 572 object_path_ = dbus::ObjectPath(kObjectPathPrefix + |
| 573 base::IntToString(current_object_path_)); |
| 574 GetCurrentService()->Initialize(this); |
| 575 sender.Run(object_path_); |
| 576 } |
| 577 |
| 578 } // namespace chromeos |
OLD | NEW |