Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(491)

Side by Side Diff: chrome/browser/chromeos/input_method/ibus_controller_impl.cc

Issue 10159004: Extends DBusThreadManager to connect ibus-bus. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Avoid double initializing Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/bind.h"
16 #include "base/environment.h"
17 #include "base/files/file_path_watcher.h"
15 #include "base/memory/scoped_ptr.h" 18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop.h"
20 #include "base/rand_util.h"
16 #include "base/stringprintf.h" 21 #include "base/stringprintf.h"
17 #include "base/string_split.h" 22 #include "base/string_split.h"
18 #include "chrome/browser/chromeos/input_method/input_method_config.h" 23 #include "chrome/browser/chromeos/input_method/input_method_config.h"
19 #include "chrome/browser/chromeos/input_method/input_method_property.h" 24 #include "chrome/browser/chromeos/input_method/input_method_property.h"
20 #include "chrome/browser/chromeos/input_method/input_method_util.h" 25 #include "chrome/browser/chromeos/input_method/input_method_util.h"
26 #include "chromeos/dbus/dbus_thread_manager.h"
27 #include "content/public/browser/browser_thread.h"
21 28
22 // TODO(nona): Remove libibus dependency from this file. Then, write unit tests 29 // TODO(nona): Remove libibus dependency from this file. Then, write unit tests
23 // for all functions in this file. crbug.com/26334 30 // for all functions in this file. crbug.com/26334
24 #if defined(HAVE_IBUS) 31 #if defined(HAVE_IBUS)
25 #include <ibus.h> 32 #include <ibus.h>
26 #endif 33 #endif
27 34
28 namespace { 35 namespace {
29 36
30 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the 37 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 std::stringstream stream; 357 std::stringstream stream;
351 for (int i = 0;; ++i) { 358 for (int i = 0;; ++i) {
352 IBusProperty* prop = ibus_prop_list_get(prop_list, i); 359 IBusProperty* prop = ibus_prop_list_get(prop_list, i);
353 if (!prop) 360 if (!prop)
354 break; 361 break;
355 stream << PrintProp(prop, tree_level); 362 stream << PrintProp(prop, tree_level);
356 } 363 }
357 return stream.str(); 364 return stream.str();
358 } 365 }
359 366
367 // The implementation of FilePathWatcher::Delegate, used in
368 // StartAddressFileWatch function.
369 class IBusAddressFileWatcherDelegate
370 : public base::files::FilePathWatcher::Delegate {
371 public:
372 IBusAddressFileWatcherDelegate(const std::string& ibus_address,
373 base::files::FilePathWatcher* watcher,
374 IBusControllerImpl* controller)
375 : ibus_address_(ibus_address),
376 watcher_(watcher),
377 controller_(controller) {
378 }
379
380 virtual ~IBusAddressFileWatcherDelegate() {}
381
382 virtual void OnFilePathChanged(const FilePath& file_path) {
383 content::BrowserThread::PostTaskAndReply(
Yusuke Sato 2012/04/27 02:12:13 check return value?
Seigo Nonaka 2012/05/01 00:19:54 Done.
384 content::BrowserThread::UI,
385 FROM_HERE,
386 base::Bind(&chromeos::DBusThreadManager::MaybeResetIBusBus,
387 base::Unretained(chromeos::DBusThreadManager::Get()),
388 ibus_address_),
389 base::Bind(&IBusControllerImpl::IBusBusInitializationDone,
Yusuke Sato 2012/04/27 02:12:13 flipping the flag from FILE thread w/o locking loo
Seigo Nonaka 2012/05/01 00:19:54 Done.
390 controller_));
391 MessageLoop::current()->DeleteSoon(FROM_HERE, watcher_);
392 }
393
394 private:
395 // The ibus-daemon address.
396 const std::string ibus_address_;
397
Yusuke Sato 2012/04/27 02:12:13 nit: add a comment or remove this line.
Seigo Nonaka 2012/05/01 00:19:54 Done.
398 IBusControllerImpl* controller_;
399
Yusuke Sato 2012/04/27 02:12:13 nit: the same as above.
Seigo Nonaka 2012/05/01 00:19:54 Done.
400 base::files::FilePathWatcher* watcher_;
401
402 DISALLOW_COPY_AND_ASSIGN(IBusAddressFileWatcherDelegate);
403 };
404
405 void StartAddressFileWatch(const std::string& ibus_address,
406 IBusControllerImpl* controller) {
407 scoped_ptr<base::Environment> env(base::Environment::Create());
408 std::string address_file_path;
409 env->GetVar("IBUS_ADDRESS_FILE", &address_file_path);
Yusuke Sato 2012/04/27 02:12:13 DCHECK(!address_file_path.empty());
Seigo Nonaka 2012/05/01 00:19:54 Done.
410
411 // The |watcher| instance will be released by |delegate|.
412 base::files::FilePathWatcher* watcher = new base::files::FilePathWatcher;
413
414 // The |delegate| is owned by watcher.
415 IBusAddressFileWatcherDelegate* delegate = new IBusAddressFileWatcherDelegate(
416 ibus_address, watcher, controller);
417 bool result = watcher->Watch(FilePath(address_file_path), delegate);
418 DCHECK(result);
419 }
360 } // namespace 420 } // namespace
361 421
362 IBusControllerImpl::IBusControllerImpl() 422 IBusControllerImpl::IBusControllerImpl()
363 : ibus_(NULL), 423 : ibus_(NULL),
364 ibus_config_(NULL), 424 ibus_config_(NULL),
365 should_launch_daemon_(false), 425 should_launch_daemon_(false),
366 process_handle_(base::kNullProcessHandle) { 426 process_handle_(base::kNullProcessHandle),
427 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
428 is_initializing_ibus_daemon_(false) {
367 } 429 }
368 430
369 IBusControllerImpl::~IBusControllerImpl() { 431 IBusControllerImpl::~IBusControllerImpl() {
370 // Disconnect signals so the handler functions will not be called with 432 // Disconnect signals so the handler functions will not be called with
371 // |this| which is already freed. 433 // |this| which is already freed.
372 if (ibus_) { 434 if (ibus_) {
373 g_signal_handlers_disconnect_by_func( 435 g_signal_handlers_disconnect_by_func(
374 ibus_, 436 ibus_,
375 reinterpret_cast<gpointer>(G_CALLBACK(BusConnectedThunk)), 437 reinterpret_cast<gpointer>(G_CALLBACK(BusConnectedThunk)),
376 this); 438 this);
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 // Notify the change. 948 // Notify the change.
887 if (!prop_list.empty()) { 949 if (!prop_list.empty()) {
888 for (size_t i = 0; i < prop_list.size(); ++i) { 950 for (size_t i = 0; i < prop_list.size(); ++i) {
889 FindAndUpdateProperty(prop_list[i], &current_property_list_); 951 FindAndUpdateProperty(prop_list[i], &current_property_list_);
890 } 952 }
891 FOR_EACH_OBSERVER(Observer, observers_, PropertyChanged()); 953 FOR_EACH_OBSERVER(Observer, observers_, PropertyChanged());
892 } 954 }
893 } 955 }
894 956
895 bool IBusControllerImpl::MaybeLaunchIBusDaemon() { 957 bool IBusControllerImpl::MaybeLaunchIBusDaemon() {
896 static const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
897
898 if (process_handle_ != base::kNullProcessHandle) { 958 if (process_handle_ != base::kNullProcessHandle) {
899 DVLOG(1) << "MaybeLaunchIBusDaemon: ibus-daemon is already running."; 959 DVLOG(1) << "MaybeLaunchIBusDaemon: ibus-daemon is already running.";
900 return false; 960 return false;
901 } 961 }
902 if (!should_launch_daemon_) 962 if (!should_launch_daemon_)
903 return false; 963 return false;
904 964
965 if (is_initializing_ibus_daemon_)
966 return false;
967
968 is_initializing_ibus_daemon_ = true;
969 const std::string ibus_address = base::StringPrintf(
970 "unix:abstract=/tmp/ibus-%0lX", base::RandUint64());
971
972 // Set up ibus-daemon address file watcher before launching ibus-daemon,
973 // because if watcher start after ibus-daemon, we may miss the ibus connection
974 // initialization.
975 content::BrowserThread::PostTaskAndReply(
Yusuke Sato 2012/04/27 02:12:13 check return value?
Seigo Nonaka 2012/05/01 00:19:54 Done.
976 content::BrowserThread::FILE,
977 FROM_HERE,
978 base::Bind(&StartAddressFileWatch, ibus_address),
979 base::Bind(&IBusControllerImpl::LaunchIBusDaemon,
980 weak_ptr_factory_.GetWeakPtr(),
981 ibus_address));
982 return true;
983 }
984
985 void IBusControllerImpl::LaunchIBusDaemon(const std::string& ibus_address) {
986 static const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
905 // TODO(zork): Send output to /var/log/ibus.log 987 // TODO(zork): Send output to /var/log/ibus.log
906 const std::string ibus_daemon_command_line = 988 const std::string ibus_daemon_command_line =
907 base::StringPrintf("%s --panel=disable --cache=none --restart --replace", 989 base::StringPrintf("%s --panel=disable --cache=none --restart --replace"
908 kIBusDaemonPath); 990 " --address=%s",
991 kIBusDaemonPath,
992 ibus_address.c_str());
909 if (!LaunchProcess(ibus_daemon_command_line, 993 if (!LaunchProcess(ibus_daemon_command_line,
910 &process_handle_, 994 &process_handle_,
911 reinterpret_cast<GChildWatchFunc>(OnIBusDaemonExit))) { 995 reinterpret_cast<GChildWatchFunc>(OnIBusDaemonExit))) {
912 DVLOG(1) << "Failed to launch " << ibus_daemon_command_line; 996 DVLOG(1) << "Failed to launch " << ibus_daemon_command_line;
913 return false;
914 } 997 }
915 return true;
916 } 998 }
917 999
918 bool IBusControllerImpl::LaunchProcess(const std::string& command_line, 1000 bool IBusControllerImpl::LaunchProcess(const std::string& command_line,
919 base::ProcessHandle* process_handle, 1001 base::ProcessHandle* process_handle,
920 GChildWatchFunc watch_func) { 1002 GChildWatchFunc watch_func) {
921 std::vector<std::string> argv; 1003 std::vector<std::string> argv;
922 base::ProcessHandle handle = base::kNullProcessHandle; 1004 base::ProcessHandle handle = base::kNullProcessHandle;
923 1005
924 base::SplitString(command_line, ' ', &argv); 1006 base::SplitString(command_line, ' ', &argv);
925 1007
926 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) { 1008 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) {
927 DVLOG(1) << "Could not launch: " << command_line; 1009 DVLOG(1) << "Could not launch: " << command_line;
928 return false; 1010 return false;
929 } 1011 }
930 1012
931 // g_child_watch_add is necessary to prevent the process from becoming a 1013 // g_child_watch_add is necessary to prevent the process from becoming a
932 // zombie. 1014 // zombie.
933 // TODO(yusukes): port g_child_watch_add to base/process_utils_posix.cc. 1015 // TODO(yusukes): port g_child_watch_add to base/process_utils_posix.cc.
934 const base::ProcessId pid = base::GetProcId(handle); 1016 const base::ProcessId pid = base::GetProcId(handle);
935 g_child_watch_add(pid, watch_func, this); 1017 g_child_watch_add(pid, watch_func, this);
936 1018
937 *process_handle = handle; 1019 *process_handle = handle;
938 DVLOG(1) << command_line << "is started. PID=" << pid; 1020 DVLOG(1) << command_line << "is started. PID=" << pid;
939 return true; 1021 return true;
940 } 1022 }
941 1023
1024 void IBusControllerImpl::IBusDaemonInitializationDone() {
1025 is_initializing_ibus_daemon_ = false;
1026 }
1027
942 // static 1028 // static
943 void IBusControllerImpl::SetInputMethodConfigCallback(GObject* source_object, 1029 void IBusControllerImpl::SetInputMethodConfigCallback(GObject* source_object,
944 GAsyncResult* res, 1030 GAsyncResult* res,
945 gpointer user_data) { 1031 gpointer user_data) {
946 IBusConfig* config = IBUS_CONFIG(user_data); 1032 IBusConfig* config = IBUS_CONFIG(user_data);
947 g_return_if_fail(config); 1033 g_return_if_fail(config);
948 1034
949 GError* error = NULL; 1035 GError* error = NULL;
950 const gboolean result = 1036 const gboolean result =
951 ibus_config_set_value_async_finish(config, res, &error); 1037 ibus_config_set_value_async_finish(config, res, &error);
952 1038
953 if (!result) { 1039 if (!result) {
954 std::string message = "(unknown error)"; 1040 std::string message = "(unknown error)";
955 if (error && error->message) { 1041 if (error && error->message) {
956 message = error->message; 1042 message = error->message;
957 } 1043 }
958 DVLOG(1) << "ibus_config_set_value_async failed: " << message; 1044 DVLOG(1) << "ibus_config_set_value_async failed: " << message;
959 } 1045 }
960 1046
961 if (error) 1047 if (error)
962 g_error_free(error); 1048 g_error_free(error);
963 g_object_unref(config); 1049 g_object_unref(config);
964 } 1050 }
965 1051
966 // static 1052 // static
967 void IBusControllerImpl::OnIBusDaemonExit(GPid pid, 1053 void IBusControllerImpl::OnIBusDaemonExit(GPid pid,
Yusuke Sato 2012/04/27 02:12:13 please also make sure that your code works fine ev
Seigo Nonaka 2012/05/01 00:19:54 Done.
968 gint status, 1054 gint status,
969 IBusControllerImpl* controller) { 1055 IBusControllerImpl* controller) {
970 if (controller->process_handle_ != base::kNullProcessHandle && 1056 if (controller->process_handle_ != base::kNullProcessHandle &&
971 base::GetProcId(controller->process_handle_) == pid) { 1057 base::GetProcId(controller->process_handle_) == pid) {
972 controller->process_handle_ = base::kNullProcessHandle; 1058 controller->process_handle_ = base::kNullProcessHandle;
973 } 1059 }
974 // Restart the daemon if needed. 1060 // Restart the daemon if needed.
975 controller->MaybeLaunchIBusDaemon(); 1061 controller->MaybeLaunchIBusDaemon();
976 } 1062 }
977 #endif // defined(HAVE_IBUS) 1063 #endif // defined(HAVE_IBUS)
978 1064
979 // static 1065 // static
980 bool IBusControllerImpl::FindAndUpdatePropertyForTesting( 1066 bool IBusControllerImpl::FindAndUpdatePropertyForTesting(
981 const chromeos::input_method::InputMethodProperty& new_prop, 1067 const chromeos::input_method::InputMethodProperty& new_prop,
982 chromeos::input_method::InputMethodPropertyList* prop_list) { 1068 chromeos::input_method::InputMethodPropertyList* prop_list) {
983 return FindAndUpdateProperty(new_prop, prop_list); 1069 return FindAndUpdateProperty(new_prop, prop_list);
984 } 1070 }
985 1071
986 } // namespace input_method 1072 } // namespace input_method
987 } // namespace chromeos 1073 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698