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 "chromeos/dbus/ibus/ibus_client.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "chromeos/dbus/ibus/ibus_constants.h" 10 #include "chromeos/dbus/ibus/ibus_component.h" 11 #include "chromeos/dbus/ibus/ibus_engine_service.h" 12 #include "chromeos/ime/ibus_bridge.h" 13 #include "dbus/bus.h" 14 #include "dbus/message.h" 15 #include "dbus/object_path.h" 16 #include "dbus/object_proxy.h" 17 18 namespace chromeos { 19 20 namespace { 21 22 // The IBusClient implementation. 23 class IBusClientImpl : public IBusClient { 24 public: 25 explicit IBusClientImpl(dbus::Bus* bus) 26 : proxy_(bus->GetObjectProxy(ibus::kServiceName, 27 dbus::ObjectPath(ibus::bus::kServicePath))), 28 weak_ptr_factory_(this) { 29 } 30 31 virtual ~IBusClientImpl() {} 32 33 // IBusClient override. 34 virtual void CreateInputContext( 35 const std::string& client_name, 36 const CreateInputContextCallback& callback, 37 const ErrorCallback& error_callback) OVERRIDE { 38 DCHECK(!callback.is_null()); 39 DCHECK(!error_callback.is_null()); 40 dbus::MethodCall method_call(ibus::bus::kServiceInterface, 41 ibus::bus::kCreateInputContextMethod); 42 dbus::MessageWriter writer(&method_call); 43 writer.AppendString(client_name); 44 proxy_->CallMethodWithErrorCallback( 45 &method_call, 46 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 47 base::Bind(&IBusClientImpl::OnCreateInputContext, 48 weak_ptr_factory_.GetWeakPtr(), 49 callback, 50 error_callback), 51 base::Bind(&IBusClientImpl::OnDBusMethodCallFail, 52 weak_ptr_factory_.GetWeakPtr(), 53 error_callback)); 54 } 55 56 // IBusClient override. 57 virtual void RegisterComponent( 58 const IBusComponent& ibus_component, 59 const RegisterComponentCallback& callback, 60 const ErrorCallback& error_callback) OVERRIDE { 61 DCHECK(!callback.is_null()); 62 DCHECK(!error_callback.is_null()); 63 dbus::MethodCall method_call(ibus::bus::kServiceInterface, 64 ibus::bus::kRegisterComponentMethod); 65 dbus::MessageWriter writer(&method_call); 66 AppendIBusComponent(ibus_component, &writer); 67 proxy_->CallMethodWithErrorCallback( 68 &method_call, 69 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 70 base::Bind(&IBusClientImpl::OnRegisterComponent, 71 weak_ptr_factory_.GetWeakPtr(), 72 callback, 73 error_callback), 74 base::Bind(&IBusClientImpl::OnDBusMethodCallFail, 75 weak_ptr_factory_.GetWeakPtr(), 76 error_callback)); 77 } 78 79 // IBusClient override. 80 virtual void SetGlobalEngine(const std::string& engine_name, 81 const ErrorCallback& error_callback) OVERRIDE { 82 DCHECK(!error_callback.is_null()); 83 dbus::MethodCall method_call(ibus::bus::kServiceInterface, 84 ibus::bus::kSetGlobalEngineMethod); 85 dbus::MessageWriter writer(&method_call); 86 writer.AppendString(engine_name); 87 proxy_->CallMethodWithErrorCallback( 88 &method_call, 89 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 90 base::Bind(&IBusClientImpl::OnSetGlobalEngine, 91 weak_ptr_factory_.GetWeakPtr(), 92 error_callback), 93 base::Bind(&IBusClientImpl::OnDBusMethodCallFail, 94 weak_ptr_factory_.GetWeakPtr(), 95 error_callback)); 96 } 97 98 // IBusClient override. 99 virtual void Exit(ExitOption option, 100 const ErrorCallback& error_callback) OVERRIDE { 101 DCHECK(!error_callback.is_null()); 102 dbus::MethodCall method_call(ibus::bus::kServiceInterface, 103 ibus::bus::kExitMethod); 104 dbus::MessageWriter writer(&method_call); 105 writer.AppendBool(option == RESTART_IBUS_DAEMON); 106 proxy_->CallMethodWithErrorCallback( 107 &method_call, 108 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 109 base::Bind(&IBusClientImpl::OnExit, 110 weak_ptr_factory_.GetWeakPtr(), 111 error_callback), 112 base::Bind(&IBusClientImpl::OnDBusMethodCallFail, 113 weak_ptr_factory_.GetWeakPtr(), 114 error_callback)); 115 } 116 117 private: 118 // Handles responses of CreateInputContext method calls. 119 void OnCreateInputContext(const CreateInputContextCallback& callback, 120 const ErrorCallback& error_callback, 121 dbus::Response* response) { 122 if (!response) { 123 LOG(ERROR) << "Cannot get input context: response is NULL."; 124 error_callback.Run(); 125 return; 126 } 127 dbus::MessageReader reader(response); 128 dbus::ObjectPath object_path; 129 if (!reader.PopObjectPath(&object_path)) { 130 // The IBus message structure may be changed. 131 LOG(ERROR) << "Invalid response: " << response->ToString(); 132 error_callback.Run(); 133 return; 134 } 135 callback.Run(object_path); 136 } 137 138 // Handles responses of RegisterComponent method calls. 139 void OnRegisterComponent(const RegisterComponentCallback& callback, 140 const ErrorCallback& error_callback, 141 dbus::Response* response) { 142 if (!response) { 143 LOG(ERROR) << "Response is NULL."; 144 error_callback.Run(); 145 return; 146 } 147 callback.Run(); 148 } 149 150 // Handles responses of RegisterComponent method calls. 151 void OnSetGlobalEngine(const ErrorCallback& error_callback, 152 dbus::Response* response) { 153 if (!response) { 154 LOG(ERROR) << "Response is NULL."; 155 error_callback.Run(); 156 return; 157 } 158 } 159 160 // Handles responses of RegisterComponent method calls. 161 void OnExit(const ErrorCallback& error_callback, 162 dbus::Response* response) { 163 if (!response) { 164 LOG(ERROR) << "Response is NULL."; 165 error_callback.Run(); 166 return; 167 } 168 } 169 170 // Handles error response of RegisterComponent method call. 171 void OnDBusMethodCallFail(const ErrorCallback& error_callback, 172 dbus::ErrorResponse* response) { 173 error_callback.Run(); 174 } 175 176 dbus::ObjectProxy* proxy_; 177 base::WeakPtrFactory<IBusClientImpl> weak_ptr_factory_; 178 179 DISALLOW_COPY_AND_ASSIGN(IBusClientImpl); 180 }; 181 182 // An implementation of IBusClient without ibus-daemon interaction. 183 // Currently this class is used only on linux desktop. 184 // TODO(nona): Use this on ChromeOS device once crbug.com/171351 is fixed. 185 class IBusClientDaemonlessImpl : public IBusClient { 186 public: 187 IBusClientDaemonlessImpl() {} 188 virtual ~IBusClientDaemonlessImpl() {} 189 190 virtual void CreateInputContext( 191 const std::string& client_name, 192 const CreateInputContextCallback & callback, 193 const ErrorCallback& error_callback) OVERRIDE { 194 // TODO(nona): Remove this function once ibus-daemon is gone. 195 // We don't have to do anything for this function except for calling 196 // |callback| as the success of this function. The original spec of ibus 197 // supports multiple input contexts, but there is only one input context in 198 // Chrome OS. That is all IME events will be came from same input context 199 // and all engine action shuold be forwarded to same input context. 200 dbus::ObjectPath path("dummpy path"); 201 callback.Run(path); 202 } 203 204 virtual void RegisterComponent( 205 const IBusComponent& ibus_component, 206 const RegisterComponentCallback& callback, 207 const ErrorCallback& error_callback) OVERRIDE { 208 // TODO(nona): Remove this function once ibus-daemon is gone. 209 // The information about engine is stored in chromeos::InputMethodManager so 210 // IBusBridge doesn't do anything except for calling |callback| as success 211 // of this function. 212 callback.Run(); 213 } 214 215 virtual void SetGlobalEngine(const std::string& engine_name, 216 const ErrorCallback& error_callback) OVERRIDE { 217 IBusEngineHandlerInterface* previous_engine = 218 IBusBridge::Get()->GetEngineHandler(); 219 if (previous_engine) 220 previous_engine->Disable(); 221 IBusBridge::Get()->CreateEngine(engine_name); 222 IBusEngineHandlerInterface* next_engine = 223 IBusBridge::Get()->GetEngineHandler(); 224 if (next_engine) 225 next_engine->Enable(); 226 } 227 228 virtual void Exit(ExitOption option, 229 const ErrorCallback& error_callback) OVERRIDE { 230 // Exit is not supported on daemon-less implementation. 231 } 232 233 private: 234 DISALLOW_COPY_AND_ASSIGN(IBusClientDaemonlessImpl); 235 }; 236 237 } // namespace 238 239 /////////////////////////////////////////////////////////////////////////////// 240 // IBusClient 241 242 IBusClient::IBusClient() {} 243 244 IBusClient::~IBusClient() {} 245 246 // static 247 IBusClient* IBusClient::Create(DBusClientImplementationType type, 248 dbus::Bus* bus) { 249 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) { 250 return new IBusClientImpl(bus); 251 } 252 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 253 return new IBusClientDaemonlessImpl(); 254 } 255 256 } // namespace chromeos 257