Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / chromeos / dbus / ibus / ibus_input_context_client.cc
blob72b202f24d52e7cd14eed38254d19a0153a4ccff
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.
5 #include "chromeos/dbus/ibus/ibus_input_context_client.h"
7 #include <string>
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "chromeos/dbus/ibus/ibus_constants.h"
11 #include "chromeos/dbus/ibus/ibus_engine_service.h"
12 #include "chromeos/dbus/ibus/ibus_panel_service.h"
13 #include "chromeos/dbus/ibus/ibus_text.h"
14 #include "chromeos/ime/ibus_bridge.h"
15 #include "dbus/bus.h"
16 #include "dbus/message.h"
17 #include "dbus/object_path.h"
18 #include "dbus/object_proxy.h"
20 namespace chromeos {
22 using chromeos::IBusText;
24 namespace {
26 // The IBusInputContextClient implementation.
27 class IBusInputContextClientImpl : public IBusInputContextClient {
28 public:
29 IBusInputContextClientImpl()
30 : proxy_(NULL),
31 is_xkb_layout_(true),
32 weak_ptr_factory_(this) {
35 virtual ~IBusInputContextClientImpl() {}
37 public:
38 // IBusInputContextClient override.
39 virtual void Initialize(dbus::Bus* bus,
40 const dbus::ObjectPath& object_path) OVERRIDE {
41 if (proxy_ != NULL) {
42 LOG(ERROR) << "IBusInputContextClient is already initialized.";
43 return;
45 proxy_ = bus->GetObjectProxy(ibus::kServiceName, object_path);
47 ConnectSignals();
50 // IBusInputContextClient override.
51 virtual void SetInputContextHandler(
52 IBusInputContextHandlerInterface* handler) OVERRIDE {
53 handler_ = handler;
56 // IBusInputContextClient override.
57 virtual void SetSetCursorLocationHandler(
58 const SetCursorLocationHandler& set_cursor_location_handler) OVERRIDE {
59 DCHECK(!set_cursor_location_handler.is_null());
60 set_cursor_location_handler_ = set_cursor_location_handler;
63 // IBusInputContextClient override.
64 virtual void UnsetSetCursorLocationHandler() OVERRIDE {
65 set_cursor_location_handler_.Reset();
68 // IBusInputContextClient override.
69 virtual void ResetObjectProxy() OVERRIDE {
70 // Do not delete proxy here, proxy object is managed by dbus::Bus object.
71 proxy_ = NULL;
74 // IBusInputContextClient override.
75 virtual bool IsObjectProxyReady() const OVERRIDE {
76 return proxy_ != NULL;
79 // IBusInputContextClient override.
80 virtual void SetCapabilities(uint32 capabilities) OVERRIDE {
81 dbus::MethodCall method_call(ibus::input_context::kServiceInterface,
82 ibus::input_context::kSetCapabilitiesMethod);
83 dbus::MessageWriter writer(&method_call);
84 writer.AppendUint32(capabilities);
85 CallNoResponseMethod(&method_call,
86 ibus::input_context::kSetCapabilitiesMethod);
89 // IBusInputContextClient override.
90 virtual void FocusIn() OVERRIDE {
91 dbus::MethodCall method_call(ibus::input_context::kServiceInterface,
92 ibus::input_context::kFocusInMethod);
93 CallNoResponseMethod(&method_call, ibus::input_context::kFocusInMethod);
96 // IBusInputContextClient override.
97 virtual void FocusOut() OVERRIDE {
98 dbus::MethodCall method_call(ibus::input_context::kServiceInterface,
99 ibus::input_context::kFocusOutMethod);
100 CallNoResponseMethod(&method_call, ibus::input_context::kFocusOutMethod);
103 // IBusInputContextClient override.
104 virtual void Reset() OVERRIDE {
105 dbus::MethodCall method_call(ibus::input_context::kServiceInterface,
106 ibus::input_context::kResetMethod);
107 CallNoResponseMethod(&method_call, ibus::input_context::kResetMethod);
110 // IBusInputContextClient override.
111 virtual void SetCursorLocation(const ibus::Rect& cursor_location,
112 const ibus::Rect& composition_head) OVERRIDE {
113 if (!set_cursor_location_handler_.is_null())
114 set_cursor_location_handler_.Run(cursor_location, composition_head);
117 // IBusInputContextClient override.
118 virtual void ProcessKeyEvent(
119 uint32 keyval,
120 uint32 keycode,
121 uint32 state,
122 const ProcessKeyEventCallback& callback,
123 const ErrorCallback& error_callback) OVERRIDE {
124 dbus::MethodCall method_call(ibus::input_context::kServiceInterface,
125 ibus::input_context::kProcessKeyEventMethod);
126 dbus::MessageWriter writer(&method_call);
127 writer.AppendUint32(keyval);
128 writer.AppendUint32(keycode);
129 writer.AppendUint32(state);
130 proxy_->CallMethodWithErrorCallback(
131 &method_call,
132 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
133 base::Bind(&IBusInputContextClientImpl::OnProcessKeyEvent,
134 callback,
135 error_callback),
136 base::Bind(&IBusInputContextClientImpl::OnProecessKeyEventFail,
137 error_callback));
140 // IBusInputContextClient override.
141 virtual void SetSurroundingText(const std::string& text,
142 uint32 start_index,
143 uint32 end_index) OVERRIDE {
144 dbus::MethodCall method_call(
145 ibus::input_context::kServiceInterface,
146 ibus::input_context::kSetSurroundingTextMethod);
147 dbus::MessageWriter writer(&method_call);
148 AppendStringAsIBusText(text, &writer);
149 writer.AppendUint32(start_index);
150 writer.AppendUint32(end_index);
151 CallNoResponseMethod(&method_call,
152 ibus::input_context::kSetSurroundingTextMethod);
155 // IBusInputContextClient override.
156 virtual void PropertyActivate(const std::string& key,
157 ibus::IBusPropertyState state) OVERRIDE {
158 dbus::MethodCall method_call(ibus::input_context::kServiceInterface,
159 ibus::input_context::kPropertyActivateMethod);
160 dbus::MessageWriter writer(&method_call);
161 writer.AppendString(key);
162 if (state == ibus::IBUS_PROPERTY_STATE_CHECKED) {
163 writer.AppendUint32(ibus::IBUS_PROPERTY_STATE_CHECKED);
164 } else {
165 writer.AppendUint32(ibus::IBUS_PROPERTY_STATE_UNCHECKED);
167 CallNoResponseMethod(&method_call,
168 ibus::input_context::kPropertyActivateMethod);
171 // IBusInputContextClient override.
172 virtual bool IsXKBLayout() OVERRIDE {
173 return is_xkb_layout_;
176 // IBusInputContextClient override.
177 virtual void SetIsXKBLayout(bool is_xkb_layout) OVERRIDE {
178 is_xkb_layout_ = is_xkb_layout;
181 private:
182 void CallNoResponseMethod(dbus::MethodCall* method_call,
183 const std::string& method_name) {
184 proxy_->CallMethodWithErrorCallback(
185 method_call,
186 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
187 base::Bind(&IBusInputContextClientImpl::DefaultCallback,
188 method_name),
189 base::Bind(&IBusInputContextClientImpl::DefaultErrorCallback,
190 method_name));
193 // Handles no response method call reply.
194 static void DefaultCallback(const std::string& method_name,
195 dbus::Response* response) {
196 if (!response) {
197 LOG(ERROR) << "Failed to call method: " << method_name;
198 return;
202 // Handles error response of default method call.
203 static void DefaultErrorCallback(const std::string& method_name,
204 dbus::ErrorResponse* response) {
205 LOG(ERROR) << "Failed to call method: " << method_name;
208 // Handles ProcessKeyEvent method call reply.
209 static void OnProcessKeyEvent(const ProcessKeyEventCallback& callback,
210 const ErrorCallback& error_callback,
211 dbus::Response* response) {
212 if (!response) {
213 LOG(ERROR) << "Cannot get input context: " << response->ToString();
214 error_callback.Run();
215 return;
217 dbus::MessageReader reader(response);
218 bool is_keyevent_used;
219 if (!reader.PopBool(&is_keyevent_used)) {
220 // The IBus message structure may be changed.
221 LOG(ERROR) << "Invalid response: " << response->ToString();
222 error_callback.Run();
223 return;
225 DCHECK(!callback.is_null());
226 callback.Run(is_keyevent_used);
229 // Handles error response of ProcessKeyEvent method call.
230 static void OnProecessKeyEventFail(const ErrorCallback& error_callback,
231 dbus::ErrorResponse* response) {
232 error_callback.Run();
235 // Handles CommitText signal.
236 void OnCommitText(dbus::Signal* signal) {
237 if (!handler_)
238 return;
239 dbus::MessageReader reader(signal);
240 IBusText ibus_text;
241 if (!PopIBusText(&reader, &ibus_text)) {
242 // The IBus message structure may be changed.
243 LOG(ERROR) << "Invalid signal: " << signal->ToString();
244 return;
246 handler_->CommitText(ibus_text);
249 // Handles ForwardKeyEvetn signal.
250 void OnForwardKeyEvent(dbus::Signal* signal) {
251 if (!handler_)
252 return;
253 dbus::MessageReader reader(signal);
254 uint32 keyval = 0;
255 uint32 keycode = 0;
256 uint32 state = 0;
257 if (!reader.PopUint32(&keyval) ||
258 !reader.PopUint32(&keycode) ||
259 !reader.PopUint32(&state)) {
260 // The IBus message structure may be changed.
261 LOG(ERROR) << "Invalid signal: " << signal->ToString();
262 return;
264 handler_->ForwardKeyEvent(keyval, keycode, state);
267 // Handles UpdatePreeditText signal.
268 void OnUpdatePreeditText(dbus::Signal* signal) {
269 if (!handler_)
270 return;
271 dbus::MessageReader reader(signal);
272 IBusText ibus_text;
273 uint32 cursor_pos = 0;
274 bool visible = true;
275 if (!PopIBusText(&reader, &ibus_text) ||
276 !reader.PopUint32(&cursor_pos) ||
277 !reader.PopBool(&visible)) {
278 // The IBus message structure may be changed.
279 LOG(ERROR) << "Invalid signal: " << signal->ToString();
280 return;
282 handler_->UpdatePreeditText(ibus_text, cursor_pos, visible);
285 // Handles ShowPreeditText signal.
286 void OnShowPreeditText(dbus::Signal* signal) {
287 if (handler_)
288 handler_->ShowPreeditText();
291 // Handles HidePreeditText signal.
292 void OnHidePreeditText(dbus::Signal* signal) {
293 if (handler_)
294 handler_->HidePreeditText();
297 // Connects signals to signal handlers.
298 void ConnectSignals() {
299 proxy_->ConnectToSignal(
300 ibus::input_context::kServiceInterface,
301 ibus::input_context::kCommitTextSignal,
302 base::Bind(&IBusInputContextClientImpl::OnCommitText,
303 weak_ptr_factory_.GetWeakPtr()),
304 base::Bind(&IBusInputContextClientImpl::OnSignalConnected,
305 weak_ptr_factory_.GetWeakPtr()));
307 proxy_->ConnectToSignal(
308 ibus::input_context::kServiceInterface,
309 ibus::input_context::kForwardKeyEventSignal,
310 base::Bind(&IBusInputContextClientImpl::OnForwardKeyEvent,
311 weak_ptr_factory_.GetWeakPtr()),
312 base::Bind(&IBusInputContextClientImpl::OnSignalConnected,
313 weak_ptr_factory_.GetWeakPtr()));
315 proxy_->ConnectToSignal(
316 ibus::input_context::kServiceInterface,
317 ibus::input_context::kUpdatePreeditTextSignal,
318 base::Bind(&IBusInputContextClientImpl::OnUpdatePreeditText,
319 weak_ptr_factory_.GetWeakPtr()),
320 base::Bind(&IBusInputContextClientImpl::OnSignalConnected,
321 weak_ptr_factory_.GetWeakPtr()));
323 proxy_->ConnectToSignal(
324 ibus::input_context::kServiceInterface,
325 ibus::input_context::kShowPreeditTextSignal,
326 base::Bind(&IBusInputContextClientImpl::OnShowPreeditText,
327 weak_ptr_factory_.GetWeakPtr()),
328 base::Bind(&IBusInputContextClientImpl::OnSignalConnected,
329 weak_ptr_factory_.GetWeakPtr()));
331 proxy_->ConnectToSignal(
332 ibus::input_context::kServiceInterface,
333 ibus::input_context::kHidePreeditTextSignal,
334 base::Bind(&IBusInputContextClientImpl::OnHidePreeditText,
335 weak_ptr_factory_.GetWeakPtr()),
336 base::Bind(&IBusInputContextClientImpl::OnSignalConnected,
337 weak_ptr_factory_.GetWeakPtr()));
340 // Handles the result of signal connection setup.
341 void OnSignalConnected(const std::string& interface,
342 const std::string& signal,
343 bool succeeded) {
344 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
345 << signal << " failed.";
348 dbus::ObjectProxy* proxy_;
350 // The pointer for input context handler. This can be NULL.
351 IBusInputContextHandlerInterface* handler_;
353 SetCursorLocationHandler set_cursor_location_handler_;
355 // True if the current input method is xkb layout.
356 bool is_xkb_layout_;
358 base::WeakPtrFactory<IBusInputContextClientImpl> weak_ptr_factory_;
360 DISALLOW_COPY_AND_ASSIGN(IBusInputContextClientImpl);
363 // An implementation of IBusInputContextClient without ibus-daemon interaction.
364 // Currently this class is used only on linux desktop.
365 // TODO(nona): Use this on ChromeOS device once crbug.com/171351 is fixed.
366 class IBusInputContextClientDaemonlessImpl : public IBusInputContextClient {
367 public:
368 IBusInputContextClientDaemonlessImpl()
369 : is_xkb_layout_(true),
370 initialized_(false)
372 virtual ~IBusInputContextClientDaemonlessImpl() {}
374 // IBusInputContextClient override.
375 virtual void Initialize(dbus::Bus* bus,
376 const dbus::ObjectPath& object_path) OVERRIDE {
377 initialized_ = true;
380 virtual void SetInputContextHandler(
381 IBusInputContextHandlerInterface* handler) OVERRIDE {
382 IBusBridge::Get()->SetInputContextHandler(handler);
385 virtual void SetSetCursorLocationHandler(
386 const SetCursorLocationHandler& set_cursor_location_handler) OVERRIDE {
389 virtual void UnsetSetCursorLocationHandler() OVERRIDE {
392 virtual void ResetObjectProxy() OVERRIDE {
393 initialized_ = false;
396 virtual bool IsObjectProxyReady() const OVERRIDE {
397 return initialized_;
400 virtual void SetCapabilities(uint32 capability) OVERRIDE {
401 IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
402 if (engine)
403 engine->SetCapability(
404 static_cast<IBusEngineHandlerInterface::IBusCapability>(capability));
407 virtual void FocusIn() OVERRIDE {
408 IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
409 if (engine)
410 engine->FocusIn();
413 virtual void FocusOut() OVERRIDE {
414 IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
415 if (engine)
416 engine->FocusOut();
419 virtual void Reset() OVERRIDE {
420 IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
421 if (engine)
422 engine->Reset();
425 virtual void SetCursorLocation(const ibus::Rect& cursor_location,
426 const ibus::Rect& composition_head) OVERRIDE {
427 IBusPanelCandidateWindowHandlerInterface* candidate_window =
428 IBusBridge::Get()->GetCandidateWindowHandler();
430 if (candidate_window)
431 candidate_window->SetCursorLocation(cursor_location, composition_head);
434 virtual void ProcessKeyEvent(
435 uint32 keyval,
436 uint32 keycode,
437 uint32 state,
438 const ProcessKeyEventCallback& callback,
439 const ErrorCallback& error_callback) OVERRIDE {
440 IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
441 if (engine)
442 engine->ProcessKeyEvent(keyval, keycode, state, callback);
445 virtual void SetSurroundingText(const std::string& text,
446 uint32 start_index,
447 uint32 end_index) OVERRIDE {
448 // TODO(nona): Implement this.
451 virtual void PropertyActivate(const std::string& key,
452 ibus::IBusPropertyState state) OVERRIDE {
453 IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
454 if (engine)
455 engine->PropertyActivate(key,
456 static_cast<ibus::IBusPropertyState>(state));
459 virtual bool IsXKBLayout() OVERRIDE {
460 return is_xkb_layout_;
463 virtual void SetIsXKBLayout(bool is_xkb_layout) OVERRIDE {
464 is_xkb_layout_ = is_xkb_layout;
467 private:
468 // True if the current input method is xkb layout.
469 bool is_xkb_layout_;
470 bool initialized_;
472 DISALLOW_COPY_AND_ASSIGN(IBusInputContextClientDaemonlessImpl);
475 } // namespace
477 ///////////////////////////////////////////////////////////////////////////////
478 // IBusInputContextClient
480 IBusInputContextClient::IBusInputContextClient() {}
482 IBusInputContextClient::~IBusInputContextClient() {}
484 // static
485 IBusInputContextClient* IBusInputContextClient::Create(
486 DBusClientImplementationType type) {
487 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) {
488 return new IBusInputContextClientImpl();
490 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
491 return new IBusInputContextClientDaemonlessImpl();
493 } // namespace chromeos