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_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