Home | History | Annotate | Download | only in ibus
      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