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_config_client.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "chromeos/dbus/ibus/ibus_constants.h" 12 #include "chromeos/dbus/ibus/ibus_component.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 // Called when the |signal| is connected. 23 void OnSignalConnected(const std::string& interface, 24 const std::string& signal, 25 bool succeeded) { 26 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " 27 << signal << " failed."; 28 } 29 30 // Called when the GetNameOwner method call is failed. 31 void OnGetNameOwnerFail(dbus::ErrorResponse* response) { 32 // Do nothing, because method call sometimes fails due to bootstrap timing of 33 // ibus-memconf. 34 } 35 36 // The IBusConfigClient implementation. 37 class IBusConfigClientImpl : public IBusConfigClient { 38 public: 39 explicit IBusConfigClientImpl(dbus::Bus* bus) 40 : proxy_(NULL), 41 bus_(bus), 42 weak_ptr_factory_(this) { 43 } 44 45 virtual ~IBusConfigClientImpl() {} 46 47 // IBusConfigClient override. 48 virtual void InitializeAsync(const OnIBusConfigReady& on_ready) OVERRIDE { 49 // We should check that the ibus-config daemon actually works first, so we 50 // can't initialize synchronously. 51 // NameOwnerChanged signal will be emitted by ibus-daemon, but from the 52 // service name kDBusServiceName instead of kServiceName. The signal will be 53 // used to detect start of ibus-daemon. 54 dbus::ObjectProxy* dbus_proxy = bus_->GetObjectProxy( 55 ibus::kDBusServiceName, 56 dbus::ObjectPath(ibus::kDBusObjectPath)); 57 58 // Watch NameOwnerChanged signal which is fired when the ibus-config daemon 59 // request its name ownership. 60 dbus_proxy->ConnectToSignal( 61 ibus::kDBusInterface, 62 ibus::kNameOwnerChangedSignal, 63 base::Bind(&IBusConfigClientImpl::OnNameOwnerChanged, 64 weak_ptr_factory_.GetWeakPtr(), 65 on_ready), 66 base::Bind(&OnSignalConnected)); 67 68 dbus::MethodCall method_call(ibus::kDBusInterface, 69 ibus::kGetNameOwnerMethod); 70 dbus::MessageWriter writer(&method_call); 71 writer.AppendString(ibus::config::kServiceName); 72 dbus_proxy->CallMethodWithErrorCallback( 73 &method_call, 74 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 75 base::Bind(&IBusConfigClientImpl::OnGetNameOwner, 76 weak_ptr_factory_.GetWeakPtr(), 77 on_ready), 78 base::Bind(&OnGetNameOwnerFail)); 79 } 80 81 // IBusConfigClient override. 82 virtual void SetStringValue(const std::string& section, 83 const std::string& key, 84 const std::string& value, 85 const ErrorCallback& error_callback) OVERRIDE { 86 if (!proxy_) 87 return; 88 DCHECK(!error_callback.is_null()); 89 dbus::MethodCall method_call(ibus::config::kServiceInterface, 90 ibus::config::kSetValueMethod); 91 dbus::MessageWriter writer(&method_call); 92 writer.AppendString(section); 93 writer.AppendString(key); 94 dbus::MessageWriter variant_writer(NULL); 95 writer.OpenVariant("s", &variant_writer); 96 variant_writer.AppendString(value); 97 writer.CloseContainer(&variant_writer); 98 CallWithDefaultCallback(&method_call, error_callback); 99 } 100 101 // IBusConfigClient override. 102 virtual void SetIntValue(const std::string& section, 103 const std::string& key, 104 int value, 105 const ErrorCallback& error_callback) OVERRIDE { 106 if (!proxy_) 107 return; 108 DCHECK(!error_callback.is_null()); 109 dbus::MethodCall method_call(ibus::config::kServiceInterface, 110 ibus::config::kSetValueMethod); 111 dbus::MessageWriter writer(&method_call); 112 writer.AppendString(section); 113 writer.AppendString(key); 114 dbus::MessageWriter variant_writer(NULL); 115 writer.OpenVariant("i", &variant_writer); 116 variant_writer.AppendInt32(value); 117 writer.CloseContainer(&variant_writer); 118 CallWithDefaultCallback(&method_call, error_callback); 119 } 120 121 // IBusConfigClient override. 122 virtual void SetBoolValue(const std::string& section, 123 const std::string& key, 124 bool value, 125 const ErrorCallback& error_callback) OVERRIDE { 126 if (!proxy_) 127 return; 128 DCHECK(!error_callback.is_null()); 129 dbus::MethodCall method_call(ibus::config::kServiceInterface, 130 ibus::config::kSetValueMethod); 131 dbus::MessageWriter writer(&method_call); 132 writer.AppendString(section); 133 writer.AppendString(key); 134 dbus::MessageWriter variant_writer(NULL); 135 writer.OpenVariant("b", &variant_writer); 136 variant_writer.AppendBool(value); 137 writer.CloseContainer(&variant_writer); 138 CallWithDefaultCallback(&method_call, error_callback); 139 } 140 141 // IBusConfigClient override. 142 virtual void SetStringListValue( 143 const std::string& section, 144 const std::string& key, 145 const std::vector<std::string>& value, 146 const ErrorCallback& error_callback) OVERRIDE { 147 if (!proxy_) 148 return; 149 DCHECK(!error_callback.is_null()); 150 dbus::MethodCall method_call(ibus::config::kServiceInterface, 151 ibus::config::kSetValueMethod); 152 dbus::MessageWriter writer(&method_call); 153 writer.AppendString(section); 154 writer.AppendString(key); 155 dbus::MessageWriter variant_writer(NULL); 156 dbus::MessageWriter array_writer(NULL); 157 158 writer.OpenVariant("as", &variant_writer); 159 variant_writer.OpenArray("s", &array_writer); 160 for (size_t i = 0; i < value.size(); ++i) { 161 array_writer.AppendString(value[i]); 162 } 163 variant_writer.CloseContainer(&array_writer); 164 writer.CloseContainer(&variant_writer); 165 CallWithDefaultCallback(&method_call, error_callback); 166 } 167 168 private: 169 void CallWithDefaultCallback(dbus::MethodCall* method_call, 170 const ErrorCallback& error_callback) { 171 if (!proxy_) 172 return; 173 proxy_->CallMethodWithErrorCallback( 174 method_call, 175 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 176 base::Bind(&IBusConfigClientImpl::OnSetValue, 177 weak_ptr_factory_.GetWeakPtr(), 178 error_callback), 179 base::Bind(&IBusConfigClientImpl::OnSetValueFail, 180 weak_ptr_factory_.GetWeakPtr(), 181 error_callback)); 182 } 183 184 void OnSetValue(const ErrorCallback& error_callback, 185 dbus::Response* response) { 186 if (!response) { 187 LOG(ERROR) << "Response is NULL."; 188 error_callback.Run(); 189 return; 190 } 191 } 192 193 void OnSetValueFail(const ErrorCallback& error_callback, 194 dbus::ErrorResponse* response) { 195 error_callback.Run(); 196 } 197 198 void OnNameOwnerChanged(const OnIBusConfigReady& on_ready, 199 dbus::Signal* signal) { 200 DCHECK(signal); 201 std::string name; 202 std::string old_owner; 203 std::string new_owner; 204 205 dbus::MessageReader reader(signal); 206 if (!reader.PopString(&name) || 207 !reader.PopString(&old_owner) || 208 !reader.PopString(&new_owner)) { 209 DLOG(ERROR) << "Invalid response of NameOwnerChanged." 210 << signal->ToString(); 211 return; 212 } 213 214 if (name != ibus::config::kServiceName) 215 return; // Not a signal for ibus-config. 216 217 if (!old_owner.empty() || new_owner.empty()) { 218 DVLOG(1) << "Unexpected name owner change: name=" << name 219 << ", old_owner=" << old_owner << ", new_owner=" << new_owner; 220 proxy_ = NULL; 221 return; 222 } 223 224 if (proxy_) 225 return; // Already initialized. 226 227 proxy_ = bus_->GetObjectProxy(ibus::config::kServiceName, 228 dbus::ObjectPath( 229 ibus::config::kServicePath)); 230 if (!on_ready.is_null()) 231 on_ready.Run(); 232 } 233 234 // Handles response of GetNameOwner. 235 void OnGetNameOwner(const OnIBusConfigReady& on_ready, 236 dbus::Response* response) { 237 if (!response) { 238 LOG(ERROR) << "Response is NULL."; 239 return; 240 } 241 std::string owner; 242 dbus::MessageReader reader(response); 243 244 if (!reader.PopString(&owner)) { 245 LOG(ERROR) << "Invalid response of GetNameOwner." 246 << response->ToString(); 247 return; 248 } 249 250 // If the owner is empty, ibus-config daemon is not ready. So will 251 // initialize object proxy on NameOwnerChanged signal. 252 if (owner.empty()) 253 return; 254 255 proxy_ = bus_->GetObjectProxy(ibus::config::kServiceName, 256 dbus::ObjectPath( 257 ibus::config::kServicePath)); 258 if (!on_ready.is_null()) 259 on_ready.Run(); 260 } 261 262 dbus::ObjectProxy* proxy_; 263 dbus::Bus* bus_; 264 base::WeakPtrFactory<IBusConfigClientImpl> weak_ptr_factory_; 265 266 DISALLOW_COPY_AND_ASSIGN(IBusConfigClientImpl); 267 }; 268 269 // A stub implementation of IBusConfigClient. 270 // A configuration framework based on ibus will not be used after Extension IME 271 // migration. 272 class IBusConfigClientStubImpl : public IBusConfigClient { 273 public: 274 IBusConfigClientStubImpl() {} 275 virtual ~IBusConfigClientStubImpl() {} 276 virtual void InitializeAsync(const OnIBusConfigReady& on_ready) OVERRIDE {} 277 virtual void SetStringValue(const std::string& section, 278 const std::string& key, 279 const std::string& value, 280 const ErrorCallback& error_callback) OVERRIDE {} 281 virtual void SetIntValue(const std::string& section, 282 const std::string& key, 283 int value, 284 const ErrorCallback& error_callback) OVERRIDE {} 285 virtual void SetBoolValue(const std::string& section, 286 const std::string& key, 287 bool value, 288 const ErrorCallback& error_callback) OVERRIDE {} 289 virtual void SetStringListValue( 290 const std::string& section, 291 const std::string& key, 292 const std::vector<std::string>& value, 293 const ErrorCallback& error_callback) OVERRIDE {} 294 295 private: 296 DISALLOW_COPY_AND_ASSIGN(IBusConfigClientStubImpl); 297 }; 298 299 } // namespace 300 301 /////////////////////////////////////////////////////////////////////////////// 302 // IBusConfigClient 303 304 IBusConfigClient::IBusConfigClient() {} 305 306 IBusConfigClient::~IBusConfigClient() {} 307 308 // static 309 IBusConfigClient* IBusConfigClient::Create(DBusClientImplementationType type, 310 dbus::Bus* bus) { 311 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) { 312 return new IBusConfigClientImpl(bus); 313 } 314 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 315 return new IBusConfigClientStubImpl(); 316 } 317 318 } // namespace chromeos 319