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 "chrome/browser/chromeos/input_method/ibus_controller_impl.h" | 5 #include "chrome/browser/chromeos/input_method/ibus_controller_impl.h" |
6 | 6 |
7 #include <algorithm> // for std::reverse. | 7 #include <algorithm> // for std::reverse. |
8 #include <cstdio> | 8 #include <cstdio> |
9 #include <cstring> // for std::strcmp. | 9 #include <cstring> // for std::strcmp. |
10 #include <set> | 10 #include <set> |
11 #include <sstream> | 11 #include <sstream> |
12 #include <stack> | 12 #include <stack> |
13 #include <utility> | 13 #include <utility> |
14 | 14 |
15 #include "ash/shell.h" | 15 #include "ash/shell.h" |
16 #include "base/bind.h" | 16 #include "base/bind.h" |
17 #include "base/environment.h" | 17 #include "base/environment.h" |
18 #include "base/files/file_path_watcher.h" | 18 #include "base/files/file_path_watcher.h" |
19 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
20 #include "base/message_loop.h" | 20 #include "base/message_loop.h" |
21 #include "base/rand_util.h" | 21 #include "base/rand_util.h" |
| 22 #include "base/string_split.h" |
22 #include "base/stringprintf.h" | 23 #include "base/stringprintf.h" |
23 #include "base/string_split.h" | |
24 #include "chrome/browser/chromeos/input_method/input_method_config.h" | 24 #include "chrome/browser/chromeos/input_method/input_method_config.h" |
25 #include "chrome/browser/chromeos/input_method/input_method_property.h" | 25 #include "chrome/browser/chromeos/input_method/input_method_property.h" |
26 #include "chrome/browser/chromeos/input_method/input_method_util.h" | 26 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
27 #include "chromeos/dbus/dbus_thread_manager.h" | 27 #include "chromeos/dbus/dbus_thread_manager.h" |
| 28 #include "chromeos/dbus/ibus/ibus_config_client.h" |
28 #include "chromeos/dbus/ibus/ibus_constants.h" | 29 #include "chromeos/dbus/ibus/ibus_constants.h" |
29 #include "chromeos/dbus/ibus/ibus_input_context_client.h" | 30 #include "chromeos/dbus/ibus/ibus_input_context_client.h" |
30 #include "content/public/browser/browser_thread.h" | 31 #include "content/public/browser/browser_thread.h" |
31 #include "ui/aura/client/aura_constants.h" | 32 #include "ui/aura/client/aura_constants.h" |
32 #include "ui/aura/root_window.h" | 33 #include "ui/aura/root_window.h" |
33 #include "ui/base/ime/input_method_ibus.h" | 34 #include "ui/base/ime/input_method_ibus.h" |
34 | 35 |
35 // TODO(nona): Remove libibus dependency from this file. Then, write unit tests | 36 // TODO(nona): Remove libibus dependency from this file. Then, write unit tests |
36 // for all functions in this file. crbug.com/26334 | 37 // for all functions in this file. crbug.com/26334 |
37 #if defined(HAVE_IBUS) | 38 #if defined(HAVE_IBUS) |
(...skipping 14 matching lines...) Expand all Loading... |
52 // Update the list except the radio id. As written in | 53 // Update the list except the radio id. As written in |
53 // chromeos_input_method.h, |prop.selection_item_id| is dummy. | 54 // chromeos_input_method.h, |prop.selection_item_id| is dummy. |
54 prop = new_prop; | 55 prop = new_prop; |
55 prop.selection_item_id = saved_id; | 56 prop.selection_item_id = saved_id; |
56 return true; | 57 return true; |
57 } | 58 } |
58 } | 59 } |
59 return false; | 60 return false; |
60 } | 61 } |
61 | 62 |
| 63 void ConfigSetValueErrorCallback() { |
| 64 DVLOG(1) << "IBusConfig: SetValue is failed."; |
| 65 } |
| 66 |
62 } // namespace | 67 } // namespace |
63 | 68 |
64 namespace chromeos { | 69 namespace chromeos { |
65 namespace input_method { | 70 namespace input_method { |
66 | 71 |
67 #if defined(HAVE_IBUS) | 72 #if defined(HAVE_IBUS) |
68 const char kPanelObjectKey[] = "panel-object"; | 73 const char kPanelObjectKey[] = "panel-object"; |
69 | 74 |
70 namespace { | 75 namespace { |
71 | 76 |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 : watcher_(NULL) {} | 449 : watcher_(NULL) {} |
445 base::files::FilePathWatcher* watcher_; | 450 base::files::FilePathWatcher* watcher_; |
446 | 451 |
447 DISALLOW_COPY_AND_ASSIGN(IBusAddressWatcher); | 452 DISALLOW_COPY_AND_ASSIGN(IBusAddressWatcher); |
448 }; | 453 }; |
449 | 454 |
450 } // namespace | 455 } // namespace |
451 | 456 |
452 IBusControllerImpl::IBusControllerImpl() | 457 IBusControllerImpl::IBusControllerImpl() |
453 : ibus_(NULL), | 458 : ibus_(NULL), |
454 ibus_config_(NULL), | |
455 process_handle_(base::kNullProcessHandle), | 459 process_handle_(base::kNullProcessHandle), |
456 ibus_daemon_status_(IBUS_DAEMON_STOP), | 460 ibus_daemon_status_(IBUS_DAEMON_STOP), |
457 input_method_(NULL), | 461 input_method_(NULL), |
458 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 462 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
459 } | 463 } |
460 | 464 |
461 IBusControllerImpl::~IBusControllerImpl() { | 465 IBusControllerImpl::~IBusControllerImpl() { |
462 // Disconnect signals so the handler functions will not be called with | 466 // Disconnect signals so the handler functions will not be called with |
463 // |this| which is already freed. | 467 // |this| which is already freed. |
464 if (ibus_) { | 468 if (ibus_) { |
465 g_signal_handlers_disconnect_by_func( | 469 g_signal_handlers_disconnect_by_func( |
466 ibus_, | 470 ibus_, |
467 reinterpret_cast<gpointer>(G_CALLBACK(BusConnectedThunk)), | 471 reinterpret_cast<gpointer>(G_CALLBACK(BusConnectedThunk)), |
468 this); | 472 this); |
469 g_signal_handlers_disconnect_by_func( | |
470 ibus_, | |
471 reinterpret_cast<gpointer>(G_CALLBACK(BusDisconnectedThunk)), | |
472 this); | |
473 g_signal_handlers_disconnect_by_func( | |
474 ibus_, | |
475 reinterpret_cast<gpointer>(G_CALLBACK(BusNameOwnerChangedThunk)), | |
476 this); | |
477 | |
478 // Disconnect signals for the panel service as well. | 473 // Disconnect signals for the panel service as well. |
479 // When Chrome is shutting down, g_object_get_data fails and returns NULL. | 474 // When Chrome is shutting down, g_object_get_data fails and returns NULL. |
480 // TODO(nona): Investigate the reason of failure(crosbug.com/129142). | 475 // TODO(nona): Investigate the reason of failure(crosbug.com/129142). |
481 void* attached_data = g_object_get_data(G_OBJECT(ibus_), kPanelObjectKey); | 476 void* attached_data = g_object_get_data(G_OBJECT(ibus_), kPanelObjectKey); |
482 if (!attached_data) | 477 if (!attached_data) |
483 return; | 478 return; |
484 if (!G_TYPE_CHECK_INSTANCE_TYPE(attached_data, IBUS_TYPE_PANEL_SERVICE)) | 479 if (!G_TYPE_CHECK_INSTANCE_TYPE(attached_data, IBUS_TYPE_PANEL_SERVICE)) |
485 return; | 480 return; |
486 IBusPanelService* ibus_panel_service = IBUS_PANEL_SERVICE(attached_data); | 481 IBusPanelService* ibus_panel_service = IBUS_PANEL_SERVICE(attached_data); |
487 if (ibus_panel_service) { | 482 if (ibus_panel_service) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 ibus_daemon_status_ = IBUS_DAEMON_SHUTTING_DOWN; | 521 ibus_daemon_status_ = IBUS_DAEMON_SHUTTING_DOWN; |
527 // TODO(nona): Shutdown ibus-bus connection. | 522 // TODO(nona): Shutdown ibus-bus connection. |
528 if (IBusConnectionsAreAlive()) { | 523 if (IBusConnectionsAreAlive()) { |
529 // Ask IBus to exit *asynchronously*. | 524 // Ask IBus to exit *asynchronously*. |
530 ibus_bus_exit_async(ibus_, | 525 ibus_bus_exit_async(ibus_, |
531 FALSE /* do not restart */, | 526 FALSE /* do not restart */, |
532 -1 /* timeout */, | 527 -1 /* timeout */, |
533 NULL /* cancellable */, | 528 NULL /* cancellable */, |
534 NULL /* callback */, | 529 NULL /* callback */, |
535 NULL /* user_data */); | 530 NULL /* user_data */); |
536 if (ibus_config_) { | |
537 // Release |ibus_config_| unconditionally to make sure next | |
538 // IBusConnectionsAreAlive() call will return false. | |
539 g_object_unref(ibus_config_); | |
540 ibus_config_ = NULL; | |
541 } | |
542 } else { | 531 } else { |
543 base::KillProcess(process_handle_, -1, false /* wait */); | 532 base::KillProcess(process_handle_, -1, false /* wait */); |
544 DVLOG(1) << "Killing ibus-daemon. PID=" | 533 DVLOG(1) << "Killing ibus-daemon. PID=" |
545 << base::GetProcId(process_handle_); | 534 << base::GetProcId(process_handle_); |
546 } | 535 } |
547 process_handle_ = base::kNullProcessHandle; | 536 process_handle_ = base::kNullProcessHandle; |
548 return true; | 537 return true; |
549 } | 538 } |
550 | 539 |
551 bool IBusControllerImpl::ChangeInputMethod(const std::string& id) { | 540 bool IBusControllerImpl::ChangeInputMethod(const std::string& id) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 IBusInputContextClient* client | 607 IBusInputContextClient* client |
619 = DBusThreadManager::Get()->GetIBusInputContextClient(); | 608 = DBusThreadManager::Get()->GetIBusInputContextClient(); |
620 if (client) | 609 if (client) |
621 client->PropertyActivate(key, | 610 client->PropertyActivate(key, |
622 static_cast<ibus::IBusPropertyState>(is_radio)); | 611 static_cast<ibus::IBusPropertyState>(is_radio)); |
623 return true; | 612 return true; |
624 } | 613 } |
625 | 614 |
626 bool IBusControllerImpl::IBusConnectionsAreAlive() { | 615 bool IBusControllerImpl::IBusConnectionsAreAlive() { |
627 return (ibus_daemon_status_ == IBUS_DAEMON_RUNNING) && | 616 return (ibus_daemon_status_ == IBUS_DAEMON_RUNNING) && |
628 ibus_ && ibus_bus_is_connected(ibus_) && ibus_config_; | 617 ibus_ && ibus_bus_is_connected(ibus_); |
629 } | 618 } |
630 | 619 |
631 void IBusControllerImpl::MaybeRestoreConnections() { | 620 void IBusControllerImpl::MaybeRestoreConnections() { |
632 if (IBusConnectionsAreAlive()) | 621 if (IBusConnectionsAreAlive()) |
633 return; | 622 return; |
634 MaybeRestoreIBusConfig(); | |
635 if (IBusConnectionsAreAlive()) { | 623 if (IBusConnectionsAreAlive()) { |
636 DVLOG(1) << "ibus-daemon and ibus-memconf processes are ready."; | 624 DVLOG(1) << "ibus-daemon and ibus-memconf processes are ready."; |
637 ConnectPanelServiceSignals(); | 625 ConnectPanelServiceSignals(); |
638 SendAllInputMethodConfigs(); | |
639 if (!current_input_method_id_.empty()) | 626 if (!current_input_method_id_.empty()) |
640 SendChangeInputMethodRequest(current_input_method_id_); | 627 SendChangeInputMethodRequest(current_input_method_id_); |
641 } | 628 } |
642 } | 629 } |
643 | 630 |
644 void IBusControllerImpl::MaybeInitializeIBusBus() { | 631 void IBusControllerImpl::MaybeInitializeIBusBus() { |
645 if (ibus_) | 632 if (ibus_) |
646 return; | 633 return; |
647 | 634 |
648 ibus_init(); | 635 ibus_init(); |
649 // Establish IBus connection between ibus-daemon to change the current input | 636 // Establish IBus connection between ibus-daemon to change the current input |
650 // method engine, properties, and so on. | 637 // method engine, properties, and so on. |
651 ibus_ = ibus_bus_new(); | 638 ibus_ = ibus_bus_new(); |
652 DCHECK(ibus_); | 639 DCHECK(ibus_); |
653 | 640 |
654 // Register callback functions for IBusBus signals. | 641 // Register callback functions for IBusBus signals. |
655 ConnectBusSignals(); | 642 ConnectBusSignals(); |
656 | 643 |
657 // Ask libibus to watch the NameOwnerChanged signal *asynchronously*. | 644 // Ask libibus to watch the NameOwnerChanged signal *asynchronously*. |
658 ibus_bus_set_watch_dbus_signal(ibus_, TRUE); | 645 ibus_bus_set_watch_dbus_signal(ibus_, TRUE); |
659 | 646 |
660 if (ibus_bus_is_connected(ibus_)) { | 647 if (ibus_bus_is_connected(ibus_)) { |
661 DVLOG(1) << "IBus connection is ready: ibus-daemon is already running?"; | 648 DVLOG(1) << "IBus connection is ready: ibus-daemon is already running?"; |
662 BusConnected(ibus_); | 649 BusConnected(ibus_); |
663 } | 650 } |
664 } | 651 } |
665 | 652 |
666 void IBusControllerImpl::MaybeRestoreIBusConfig() { | |
667 if (!ibus_) | |
668 return; | |
669 | |
670 // Destroy the current |ibus_config_| object. No-op if it's NULL. | |
671 MaybeDestroyIBusConfig(); | |
672 | |
673 if (ibus_config_) | |
674 return; | |
675 | |
676 GDBusConnection* ibus_connection = ibus_bus_get_connection(ibus_); | |
677 if (!ibus_connection) { | |
678 DVLOG(1) << "Couldn't create an ibus config object since " | |
679 << "IBus connection is not ready."; | |
680 return; | |
681 } | |
682 | |
683 const gboolean disconnected | |
684 = g_dbus_connection_is_closed(ibus_connection); | |
685 if (disconnected) { | |
686 // |ibus_| object is not NULL, but the connection between ibus-daemon | |
687 // is not yet established. In this case, we don't create |ibus_config_| | |
688 // object. | |
689 DVLOG(1) << "Couldn't create an ibus config object since " | |
690 << "IBus connection is closed."; | |
691 return; | |
692 } | |
693 // If memconf is not successfully started yet, ibus_config_new() will | |
694 // return NULL. Otherwise, it returns a transfer-none and non-floating | |
695 // object. ibus_config_new() sometimes issues a D-Bus *synchronous* IPC | |
696 // to check if the org.freedesktop.IBus.Config service is available. | |
697 ibus_config_ = ibus_config_new(ibus_connection, | |
698 NULL /* do not cancel the operation */, | |
699 NULL /* do not get error information */); | |
700 if (!ibus_config_) { | |
701 DVLOG(1) << "ibus_config_new() failed. ibus-memconf is not ready?"; | |
702 return; | |
703 } | |
704 | |
705 // TODO(yusukes): g_object_weak_ref might be better since it allows | |
706 // libcros to detect the delivery of the "destroy" glib signal the | |
707 // |ibus_config_| object. | |
708 g_object_ref(ibus_config_); | |
709 DVLOG(1) << "ibus_config_ is ready."; | |
710 } | |
711 | |
712 void IBusControllerImpl::MaybeDestroyIBusConfig() { | |
713 if (!ibus_) { | |
714 DVLOG(1) << "MaybeDestroyIBusConfig: ibus_ is NULL"; | |
715 return; | |
716 } | |
717 if (ibus_config_ && !ibus_bus_is_connected(ibus_)) { | |
718 g_object_unref(ibus_config_); | |
719 ibus_config_ = NULL; | |
720 } | |
721 } | |
722 | |
723 void IBusControllerImpl::SendChangeInputMethodRequest(const std::string& id) { | 653 void IBusControllerImpl::SendChangeInputMethodRequest(const std::string& id) { |
724 // Change the global engine *asynchronously*. | 654 // Change the global engine *asynchronously*. |
725 ibus_bus_set_global_engine_async(ibus_, | 655 ibus_bus_set_global_engine_async(ibus_, |
726 id.c_str(), | 656 id.c_str(), |
727 -1, // use the default ibus timeout | 657 -1, // use the default ibus timeout |
728 NULL, // cancellable | 658 NULL, // cancellable |
729 NULL, // callback | 659 NULL, // callback |
730 NULL); // user_data | 660 NULL); // user_data |
731 } | 661 } |
732 | 662 |
733 void IBusControllerImpl::SendAllInputMethodConfigs() { | |
734 DCHECK(IBusConnectionsAreAlive()); | |
735 | |
736 InputMethodConfigRequests::const_iterator iter = | |
737 current_config_values_.begin(); | |
738 for (; iter != current_config_values_.end(); ++iter) { | |
739 SetInputMethodConfigInternal(iter->first, iter->second); | |
740 } | |
741 } | |
742 | |
743 bool IBusControllerImpl::SetInputMethodConfigInternal( | 663 bool IBusControllerImpl::SetInputMethodConfigInternal( |
744 const ConfigKeyType& key, | 664 const ConfigKeyType& key, |
745 const InputMethodConfigValue& value) { | 665 const InputMethodConfigValue& value) { |
746 if (!IBusConnectionsAreAlive()) | 666 IBusConfigClient* client = DBusThreadManager::Get()->GetIBusConfigClient(); |
747 return true; | 667 if (!client) |
| 668 return false; |
748 | 669 |
749 // Convert the type of |value| from our structure to GVariant. | |
750 GVariant* variant = NULL; | |
751 switch (value.type) { | 670 switch (value.type) { |
752 case InputMethodConfigValue::kValueTypeString: | 671 case InputMethodConfigValue::kValueTypeString: |
753 variant = g_variant_new_string(value.string_value.c_str()); | 672 client->SetStringValue(key.first, |
754 break; | 673 key.second, |
| 674 value.string_value, |
| 675 base::Bind(&ConfigSetValueErrorCallback)); |
| 676 return true; |
755 case InputMethodConfigValue::kValueTypeInt: | 677 case InputMethodConfigValue::kValueTypeInt: |
756 variant = g_variant_new_int32(value.int_value); | 678 client->SetIntValue(key.first, |
757 break; | 679 key.second, |
| 680 value.int_value, |
| 681 base::Bind(&ConfigSetValueErrorCallback)); |
| 682 return true; |
758 case InputMethodConfigValue::kValueTypeBool: | 683 case InputMethodConfigValue::kValueTypeBool: |
759 variant = g_variant_new_boolean(value.bool_value); | 684 client->SetBoolValue(key.first, |
760 break; | 685 key.second, |
| 686 value.bool_value, |
| 687 base::Bind(&ConfigSetValueErrorCallback)); |
| 688 return true; |
761 case InputMethodConfigValue::kValueTypeStringList: | 689 case InputMethodConfigValue::kValueTypeStringList: |
762 GVariantBuilder variant_builder; | 690 client->SetStringListValue(key.first, |
763 g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("as")); | 691 key.second, |
764 const size_t size = value.string_list_value.size(); | 692 value.string_list_value, |
765 // |size| could be 0 for some special configurations such as IBus hotkeys. | 693 base::Bind(&ConfigSetValueErrorCallback)); |
766 for (size_t i = 0; i < size; ++i) { | 694 return true; |
767 g_variant_builder_add(&variant_builder, | 695 default: |
768 "s", | 696 DVLOG(1) << "SendInputMethodConfig: unknown value.type"; |
769 value.string_list_value[i].c_str()); | 697 return false; |
770 } | |
771 variant = g_variant_builder_end(&variant_builder); | |
772 break; | |
773 } | 698 } |
774 | |
775 if (!variant) { | |
776 DVLOG(1) << "SendInputMethodConfig: unknown value.type"; | |
777 return false; | |
778 } | |
779 DCHECK(g_variant_is_floating(variant)); | |
780 DCHECK(ibus_config_); | |
781 | |
782 // Set an ibus configuration value *asynchronously*. | |
783 ibus_config_set_value_async(ibus_config_, | |
784 key.first.c_str(), | |
785 key.second.c_str(), | |
786 variant, | |
787 -1, // use the default ibus timeout | |
788 NULL, // cancellable | |
789 SetInputMethodConfigCallback, | |
790 g_object_ref(ibus_config_)); | |
791 | |
792 // Since |variant| is floating, ibus_config_set_value_async consumes | |
793 // (takes ownership of) the variable. | |
794 return true; | |
795 } | 699 } |
796 | 700 |
797 void IBusControllerImpl::ConnectBusSignals() { | 701 void IBusControllerImpl::ConnectBusSignals() { |
798 if (!ibus_) | 702 if (!ibus_) |
799 return; | 703 return; |
800 | 704 |
801 // We use g_signal_connect_after here since the callback should be called | 705 // We use g_signal_connect_after here since the callback should be called |
802 // *after* the IBusBusDisconnectedCallback in chromeos_input_method_ui.cc | 706 // *after* the IBusBusDisconnectedCallback in chromeos_input_method_ui.cc |
803 // is called. chromeos_input_method_ui.cc attaches the panel service object | 707 // is called. chromeos_input_method_ui.cc attaches the panel service object |
804 // to |ibus_|, and the callback in this file use the attached object. | 708 // to |ibus_|, and the callback in this file use the attached object. |
805 g_signal_connect_after(ibus_, | 709 g_signal_connect_after(ibus_, |
806 "connected", | 710 "connected", |
807 G_CALLBACK(BusConnectedThunk), | 711 G_CALLBACK(BusConnectedThunk), |
808 this); | 712 this); |
809 | |
810 g_signal_connect(ibus_, | |
811 "disconnected", | |
812 G_CALLBACK(BusDisconnectedThunk), | |
813 this); | |
814 | |
815 g_signal_connect(ibus_, | |
816 "name-owner-changed", | |
817 G_CALLBACK(BusNameOwnerChangedThunk), | |
818 this); | |
819 } | 713 } |
820 | 714 |
821 void IBusControllerImpl::ConnectPanelServiceSignals() { | 715 void IBusControllerImpl::ConnectPanelServiceSignals() { |
822 if (!ibus_) | 716 if (!ibus_) |
823 return; | 717 return; |
824 | 718 |
825 IBusPanelService* ibus_panel_service = IBUS_PANEL_SERVICE( | 719 IBusPanelService* ibus_panel_service = IBUS_PANEL_SERVICE( |
826 g_object_get_data(G_OBJECT(ibus_), kPanelObjectKey)); | 720 g_object_get_data(G_OBJECT(ibus_), kPanelObjectKey)); |
827 if (!ibus_panel_service) { | 721 if (!ibus_panel_service) { |
828 DVLOG(1) << "IBusPanelService is NOT available."; | 722 DVLOG(1) << "IBusPanelService is NOT available."; |
829 return; | 723 return; |
830 } | 724 } |
831 // We don't _ref() or _weak_ref() the panel service object, since we're not | 725 // We don't _ref() or _weak_ref() the panel service object, since we're not |
832 // interested in the life time of the object. | 726 // interested in the life time of the object. |
833 g_signal_connect(ibus_panel_service, | 727 g_signal_connect(ibus_panel_service, |
834 "register-properties", | 728 "register-properties", |
835 G_CALLBACK(RegisterPropertiesThunk), | 729 G_CALLBACK(RegisterPropertiesThunk), |
836 this); | 730 this); |
837 g_signal_connect(ibus_panel_service, | 731 g_signal_connect(ibus_panel_service, |
838 "update-property", | 732 "update-property", |
839 G_CALLBACK(UpdatePropertyThunk), | 733 G_CALLBACK(UpdatePropertyThunk), |
840 this); | 734 this); |
841 } | 735 } |
842 | 736 |
843 void IBusControllerImpl::BusConnected(IBusBus* bus) { | 737 void IBusControllerImpl::BusConnected(IBusBus* bus) { |
844 DVLOG(1) << "IBus connection is established."; | 738 DVLOG(1) << "IBus connection is established."; |
845 MaybeRestoreConnections(); | 739 MaybeRestoreConnections(); |
846 } | 740 } |
847 | 741 |
848 void IBusControllerImpl::BusDisconnected(IBusBus* bus) { | |
849 DVLOG(1) << "IBus connection is terminated."; | |
850 // ibus-daemon might be terminated. Since |ibus_| object will automatically | |
851 // connect to the daemon if it restarts, we don't have to set NULL on ibus_. | |
852 // Call MaybeDestroyIBusConfig() to set |ibus_config_| to NULL temporarily. | |
853 MaybeDestroyIBusConfig(); | |
854 } | |
855 | |
856 void IBusControllerImpl::BusNameOwnerChanged(IBusBus* bus, | |
857 const gchar* name, | |
858 const gchar* old_name, | |
859 const gchar* new_name) { | |
860 DCHECK(name); | |
861 DCHECK(old_name); | |
862 DCHECK(new_name); | |
863 | |
864 if (name != std::string("org.freedesktop.IBus.Config")) { | |
865 // Not a signal for ibus-memconf. | |
866 return; | |
867 } | |
868 | |
869 const std::string empty_string; | |
870 if (old_name != empty_string || new_name == empty_string) { | |
871 // ibus-memconf died? | |
872 DVLOG(1) << "Unexpected name owner change: name=" << name | |
873 << ", old_name=" << old_name << ", new_name=" << new_name; | |
874 // TODO(yusukes): it might be nice to set |ibus_config_| to NULL and call | |
875 // a new callback function like OnDisconnect() here to allow Chrome to | |
876 // recover all input method configurations when ibus-memconf is | |
877 // automatically restarted by ibus-daemon. Though ibus-memconf is pretty | |
878 // stable and unlikely crashes. | |
879 return; | |
880 } | |
881 DVLOG(1) << "IBus config daemon is started. Recovering ibus_config_"; | |
882 | |
883 // Try to recover |ibus_config_|. If the |ibus_config_| object is | |
884 // successfully created, |OnConnectionChange| will be called to | |
885 // notify Chrome that IBus is ready. | |
886 MaybeRestoreConnections(); | |
887 } | |
888 | |
889 void IBusControllerImpl::RegisterProperties(IBusPanelService* panel, | 742 void IBusControllerImpl::RegisterProperties(IBusPanelService* panel, |
890 IBusPropList* ibus_prop_list) { | 743 IBusPropList* ibus_prop_list) { |
891 // Note: |panel| can be NULL. See ChangeInputMethod(). | 744 // Note: |panel| can be NULL. See ChangeInputMethod(). |
892 DVLOG(1) << "RegisterProperties" << (ibus_prop_list ? "" : " (clear)"); | 745 DVLOG(1) << "RegisterProperties" << (ibus_prop_list ? "" : " (clear)"); |
893 | 746 |
894 current_property_list_.clear(); | 747 current_property_list_.clear(); |
895 if (ibus_prop_list) { | 748 if (ibus_prop_list) { |
896 // You can call | 749 // You can call |
897 // DVLOG(1) << "\n" << PrintPropList(ibus_prop_list, 0); | 750 // DVLOG(1) << "\n" << PrintPropList(ibus_prop_list, 0); |
898 // here to dump |ibus_prop_list|. | 751 // here to dump |ibus_prop_list|. |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1002 static_cast<ui::InputMethodIBus*>( | 855 static_cast<ui::InputMethodIBus*>( |
1003 ash::Shell::GetPrimaryRootWindow()->GetProperty( | 856 ash::Shell::GetPrimaryRootWindow()->GetProperty( |
1004 aura::client::kRootWindowInputMethodKey)); | 857 aura::client::kRootWindowInputMethodKey)); |
1005 } | 858 } |
1006 | 859 |
1007 void IBusControllerImpl::set_input_method_for_testing( | 860 void IBusControllerImpl::set_input_method_for_testing( |
1008 ui::InputMethodIBus* input_method) { | 861 ui::InputMethodIBus* input_method) { |
1009 input_method_ = input_method; | 862 input_method_ = input_method; |
1010 } | 863 } |
1011 | 864 |
| 865 void IBusControllerImpl::OnIBusConfigClientInitialized() { |
| 866 InputMethodConfigRequests::const_iterator iter = |
| 867 current_config_values_.begin(); |
| 868 for (; iter != current_config_values_.end(); ++iter) { |
| 869 SetInputMethodConfigInternal(iter->first, iter->second); |
| 870 } |
| 871 } |
| 872 |
1012 // static | 873 // static |
1013 void IBusControllerImpl::IBusDaemonInitializationDone( | 874 void IBusControllerImpl::IBusDaemonInitializationDone( |
1014 IBusControllerImpl* controller, | 875 IBusControllerImpl* controller, |
1015 const std::string& ibus_address) { | 876 const std::string& ibus_address) { |
1016 if (controller->ibus_daemon_address_ != ibus_address) | 877 if (controller->ibus_daemon_address_ != ibus_address) |
1017 return; | 878 return; |
1018 | 879 |
1019 if (controller->ibus_daemon_status_ != IBUS_DAEMON_INITIALIZING) { | 880 if (controller->ibus_daemon_status_ != IBUS_DAEMON_INITIALIZING) { |
1020 // Stop() or OnIBusDaemonExit() has already been called. | 881 // Stop() or OnIBusDaemonExit() has already been called. |
1021 return; | 882 return; |
1022 } | 883 } |
1023 chromeos::DBusThreadManager::Get()->InitIBusBus(ibus_address); | 884 chromeos::DBusThreadManager::Get()->InitIBusBus(ibus_address); |
1024 controller->ibus_daemon_status_ = IBUS_DAEMON_RUNNING; | 885 controller->ibus_daemon_status_ = IBUS_DAEMON_RUNNING; |
1025 | 886 |
1026 ui::InputMethodIBus* input_method_ibus = controller->GetInputMethod(); | 887 ui::InputMethodIBus* input_method_ibus = controller->GetInputMethod(); |
1027 DCHECK(input_method_ibus); | 888 DCHECK(input_method_ibus); |
1028 input_method_ibus->OnConnected(); | 889 input_method_ibus->OnConnected(); |
1029 | 890 |
| 891 DBusThreadManager::Get()->GetIBusConfigClient()->InitializeAsync( |
| 892 base::Bind(&IBusControllerImpl::OnIBusConfigClientInitialized, |
| 893 controller->weak_ptr_factory_.GetWeakPtr())); |
| 894 |
1030 FOR_EACH_OBSERVER(Observer, controller->observers_, OnConnected()); | 895 FOR_EACH_OBSERVER(Observer, controller->observers_, OnConnected()); |
1031 | 896 |
1032 VLOG(1) << "The ibus-daemon initialization is done."; | 897 VLOG(1) << "The ibus-daemon initialization is done."; |
1033 } | 898 } |
1034 | 899 |
1035 // static | 900 // static |
1036 void IBusControllerImpl::SetInputMethodConfigCallback(GObject* source_object, | |
1037 GAsyncResult* res, | |
1038 gpointer user_data) { | |
1039 IBusConfig* config = IBUS_CONFIG(user_data); | |
1040 g_return_if_fail(config); | |
1041 | |
1042 GError* error = NULL; | |
1043 const gboolean result = | |
1044 ibus_config_set_value_async_finish(config, res, &error); | |
1045 | |
1046 if (!result) { | |
1047 std::string message = "(unknown error)"; | |
1048 if (error && error->message) { | |
1049 message = error->message; | |
1050 } | |
1051 DVLOG(1) << "ibus_config_set_value_async failed: " << message; | |
1052 } | |
1053 | |
1054 if (error) | |
1055 g_error_free(error); | |
1056 g_object_unref(config); | |
1057 } | |
1058 | |
1059 // static | |
1060 void IBusControllerImpl::OnIBusDaemonExit(GPid pid, | 901 void IBusControllerImpl::OnIBusDaemonExit(GPid pid, |
1061 gint status, | 902 gint status, |
1062 IBusControllerImpl* controller) { | 903 IBusControllerImpl* controller) { |
1063 if (controller->process_handle_ != base::kNullProcessHandle) { | 904 if (controller->process_handle_ != base::kNullProcessHandle) { |
1064 if (base::GetProcId(controller->process_handle_) == pid) { | 905 if (base::GetProcId(controller->process_handle_) == pid) { |
1065 // ibus-daemon crashed. | 906 // ibus-daemon crashed. |
1066 // TODO(nona): Shutdown ibus-bus connection. | 907 // TODO(nona): Shutdown ibus-bus connection. |
1067 controller->process_handle_ = base::kNullProcessHandle; | 908 controller->process_handle_ = base::kNullProcessHandle; |
1068 } else { | 909 } else { |
1069 // This condition is as follows. | 910 // This condition is as follows. |
(...skipping 26 matching lines...) Expand all Loading... |
1096 | 937 |
1097 // static | 938 // static |
1098 bool IBusControllerImpl::FindAndUpdatePropertyForTesting( | 939 bool IBusControllerImpl::FindAndUpdatePropertyForTesting( |
1099 const chromeos::input_method::InputMethodProperty& new_prop, | 940 const chromeos::input_method::InputMethodProperty& new_prop, |
1100 chromeos::input_method::InputMethodPropertyList* prop_list) { | 941 chromeos::input_method::InputMethodPropertyList* prop_list) { |
1101 return FindAndUpdateProperty(new_prop, prop_list); | 942 return FindAndUpdateProperty(new_prop, prop_list); |
1102 } | 943 } |
1103 | 944 |
1104 } // namespace input_method | 945 } // namespace input_method |
1105 } // namespace chromeos | 946 } // namespace chromeos |
OLD | NEW |