OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium OS 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_input_method_ui.h" | |
6 | |
7 #include <base/logging.h> | |
8 #include <base/string_util.h> | |
9 #include <base/utf_string_conversions.h> | |
10 #include <ibus.h> | |
11 | |
12 namespace chromeos { | |
13 | |
14 namespace { | |
15 | |
16 // Checks the attribute if this indicates annotation. | |
17 gboolean IsAnnotation(IBusAttribute *attr) { | |
18 g_return_val_if_fail(attr, FALSE); | |
19 | |
20 // Define annotation text color. | |
21 static const guint kAnnotationColor = 0x888888; | |
22 | |
23 // Currently, we can discriminate annotation by specific value |attr->value| | |
24 // TODO(nhiroki): We should change the way when iBus supports annotations. | |
25 if (attr->type == IBUS_ATTR_TYPE_FOREGROUND && | |
26 attr->value == kAnnotationColor) { | |
27 return TRUE; | |
28 } | |
29 return FALSE; | |
30 } | |
31 | |
32 // Returns an string representation of |table| for debugging. | |
33 std::string IBusLookupTableToString(IBusLookupTable* table) { | |
34 std::stringstream stream; | |
35 stream << "page_size: " << table->page_size << "\n"; | |
36 stream << "cursor_pos: " << table->cursor_pos << "\n"; | |
37 stream << "cursor_visible: " << table->cursor_visible << "\n"; | |
38 stream << "round: " << table->round << "\n"; | |
39 stream << "orientation: " << table->orientation << "\n"; | |
40 stream << "candidates:"; | |
41 for (int i = 0; ; i++) { | |
42 IBusText *text = ibus_lookup_table_get_candidate(table, i); | |
43 if (!text) { | |
44 break; | |
45 } | |
46 stream << " " << text->text; | |
47 } | |
48 return stream.str(); | |
49 } | |
50 | |
51 } // namespace | |
52 | |
53 // A thin wrapper for IBusPanelService. | |
54 class InputMethodUiStatusConnection { | |
55 public: | |
56 InputMethodUiStatusConnection( | |
57 const InputMethodUiStatusMonitorFunctions& monitor_functions, | |
58 void* input_method_library) | |
59 : monitor_functions_(monitor_functions), | |
60 connection_change_handler_(NULL), | |
61 input_method_library_(input_method_library), | |
62 ibus_(NULL), | |
63 ibus_panel_service_(NULL) { | |
64 } | |
65 | |
66 ~InputMethodUiStatusConnection() { | |
67 // ibus_panel_service_ depends on ibus_, thus unref it first. | |
68 if (ibus_panel_service_) { | |
69 DisconnectPanelServiceSignals(); | |
70 g_object_unref(ibus_panel_service_); | |
71 } | |
72 if (ibus_) { | |
73 DisconnectIBusSignals(); | |
74 g_object_unref(ibus_); | |
75 } | |
76 } | |
77 | |
78 // Creates IBusBus object if it's not created yet, and tries to connect to | |
79 // ibus-daemon. Returns true if IBusBus is successfully connected to the | |
80 // daemon. | |
81 bool ConnectToIBus() { | |
82 if (ibus_) { | |
83 return true; | |
84 } | |
85 ibus_init(); | |
86 ibus_ = ibus_bus_new(); | |
87 CHECK(ibus_) << "ibus_bus_new() failed. Out of memory?"; | |
88 | |
89 bool result = false; | |
90 // Check the IBus connection status. | |
91 if (ibus_bus_is_connected(ibus_)) { | |
92 LOG(INFO) << "ibus_bus_is_connected(). IBus connection is ready."; | |
93 if (connection_change_handler_) { | |
94 connection_change_handler_(input_method_library_, true); | |
95 } | |
96 result = true; | |
97 } | |
98 | |
99 // Start listening the gobject signals regardless of the bus connection | |
100 // status. | |
101 ConnectIBusSignals(); | |
102 return result; | |
103 } | |
104 | |
105 // Creates IBusPanelService object if |ibus_| is already connected. | |
106 bool MaybeRestorePanelService() { | |
107 if (!ibus_ || !ibus_bus_is_connected(ibus_)) { | |
108 return false; | |
109 } | |
110 | |
111 if (ibus_panel_service_) { | |
112 LOG(ERROR) << "IBusPanelService is already available. Remove it first."; | |
113 g_object_set_data(G_OBJECT(ibus_), kPanelObjectKey, NULL); | |
114 g_object_unref(ibus_panel_service_); | |
115 ibus_panel_service_ = NULL; | |
116 } | |
117 | |
118 // Create an IBusPanelService object. | |
119 GDBusConnection* ibus_connection = ibus_bus_get_connection(ibus_); | |
120 if (!ibus_connection) { | |
121 LOG(ERROR) << "ibus_bus_get_connection() failed"; | |
122 return false; | |
123 } | |
124 ibus_panel_service_ = ibus_panel_service_new(ibus_connection); | |
125 if (!ibus_panel_service_) { | |
126 LOG(ERROR) << "ibus_chromeos_panel_service_new() failed"; | |
127 return false; | |
128 } | |
129 ConnectPanelServiceSignals(); | |
130 g_object_set_data(G_OBJECT(ibus_), kPanelObjectKey, ibus_panel_service_); | |
131 LOG(INFO) << "IBusPanelService object is successfully (re-)created."; | |
132 | |
133 // Request the well-known name *asynchronously*. | |
134 ibus_bus_request_name_async(ibus_, | |
135 IBUS_SERVICE_PANEL, | |
136 0 /* flags */, | |
137 -1 /* timeout */, | |
138 NULL /* cancellable */, | |
139 RequestNameCallback, | |
140 g_object_ref(ibus_)); | |
141 return true; | |
142 } | |
143 | |
144 // A function called when a user clicks the candidate_window. | |
145 bool NotifyCandidateClicked(int index, int button, int flags) { | |
146 if (!ibus_ || !ibus_bus_is_connected(ibus_)) { | |
147 LOG(ERROR) << "NotifyCandidateClicked: bus is not connected."; | |
148 return false; | |
149 } | |
150 if (!ibus_panel_service_) { | |
151 LOG(ERROR) << "NotifyCandidateClicked: panel service is not available."; | |
152 return false; | |
153 } | |
154 | |
155 /* Send a D-Bus signal to ibus-daemon *asynchronously*. */ | |
156 ibus_panel_service_candidate_clicked(ibus_panel_service_, | |
157 index, | |
158 button, | |
159 flags); | |
160 return true; | |
161 } | |
162 | |
163 // A function called when a user clicks the cursor up button. | |
164 bool NotifyCursorUp() { | |
165 if (!ibus_ || !ibus_bus_is_connected(ibus_)) { | |
166 LOG(ERROR) << "NotifyCursorUp: bus is not connected."; | |
167 return false; | |
168 } | |
169 if (!ibus_panel_service_) { | |
170 LOG(ERROR) << "NotifyCursorUp: panel service is not available."; | |
171 return false; | |
172 } | |
173 | |
174 /* Send a D-Bus signal to ibus-daemon *asynchronously*. */ | |
175 ibus_panel_service_cursor_up(ibus_panel_service_); | |
176 return true; | |
177 } | |
178 | |
179 // A function called when a user clicks the cursor down button. | |
180 bool NotifyCursorDown() { | |
181 if (!ibus_ || !ibus_bus_is_connected(ibus_)) { | |
182 LOG(ERROR) << "NotifyCursorDown: bus is not connected."; | |
183 return false; | |
184 } | |
185 if (!ibus_panel_service_) { | |
186 LOG(ERROR) << "NotifyCursorDown: panel service is not available."; | |
187 return false; | |
188 } | |
189 /* Send a D-Bus signal to ibus-daemon *asynchronously*. */ | |
190 ibus_panel_service_cursor_down(ibus_panel_service_); | |
191 return true; | |
192 } | |
193 | |
194 // A function called when a user clicks the page up button. | |
195 bool NotifyPageUp() { | |
196 if (!ibus_ || !ibus_bus_is_connected(ibus_)) { | |
197 LOG(ERROR) << "NotifyPageUp: bus is not connected."; | |
198 return false; | |
199 } | |
200 if (!ibus_panel_service_) { | |
201 LOG(ERROR) << "NotifyPageUp: panel service is not available."; | |
202 return false; | |
203 } | |
204 | |
205 /* Send a D-Bus signal to ibus-daemon *asynchronously*. */ | |
206 ibus_panel_service_page_up(ibus_panel_service_); | |
207 return true; | |
208 } | |
209 | |
210 // A function called when a user clicks the page down button. | |
211 bool NotifyPageDown() { | |
212 if (!ibus_ || !ibus_bus_is_connected(ibus_)) { | |
213 LOG(ERROR) << "NotifyPageDown: bus is not connected."; | |
214 return false; | |
215 } | |
216 if (!ibus_panel_service_) { | |
217 LOG(ERROR) << "NotifyPageDown: panel service is not available."; | |
218 return false; | |
219 } | |
220 | |
221 /* Send a D-Bus signal to ibus-daemon *asynchronously*. */ | |
222 ibus_panel_service_page_down(ibus_panel_service_); | |
223 return true; | |
224 } | |
225 | |
226 | |
227 // Registers a callback function which is called when IBusBus connection | |
228 // status is changed. | |
229 void MonitorInputMethodConnection( | |
230 InputMethodConnectionChangeMonitorFunction connection_change_handler) { | |
231 connection_change_handler_ = connection_change_handler; | |
232 } | |
233 | |
234 private: | |
235 // Installs gobject signal handlers to |ibus_|. | |
236 void ConnectIBusSignals() { | |
237 if (!ibus_) { | |
238 return; | |
239 } | |
240 g_signal_connect(ibus_, | |
241 "connected", | |
242 G_CALLBACK(IBusBusConnectedCallback), | |
243 this); | |
244 g_signal_connect(ibus_, | |
245 "disconnected", | |
246 G_CALLBACK(IBusBusDisconnectedCallback), | |
247 this); | |
248 } | |
249 | |
250 // Removes gobject signal handlers from |ibus_|. | |
251 void DisconnectIBusSignals() { | |
252 if (!ibus_) { | |
253 return; | |
254 } | |
255 g_signal_handlers_disconnect_by_func( | |
256 ibus_, | |
257 reinterpret_cast<gpointer>(G_CALLBACK(IBusBusConnectedCallback)), | |
258 this); | |
259 g_signal_handlers_disconnect_by_func( | |
260 ibus_, | |
261 reinterpret_cast<gpointer>(G_CALLBACK(IBusBusDisconnectedCallback)), | |
262 this); | |
263 } | |
264 | |
265 // Installs gobject signal handlers to |ibus_panel_service_|. | |
266 void ConnectPanelServiceSignals() { | |
267 if (!ibus_panel_service_) { | |
268 return; | |
269 } | |
270 g_signal_connect(ibus_panel_service_, | |
271 "hide-auxiliary-text", | |
272 G_CALLBACK(HideAuxiliaryTextCallback), | |
273 this); | |
274 g_signal_connect(ibus_panel_service_, | |
275 "hide-lookup-table", | |
276 G_CALLBACK(HideLookupTableCallback), | |
277 this); | |
278 g_signal_connect(ibus_panel_service_, | |
279 "update-auxiliary-text", | |
280 G_CALLBACK(UpdateAuxiliaryTextCallback), | |
281 this); | |
282 g_signal_connect(ibus_panel_service_, | |
283 "set-cursor-location", | |
284 G_CALLBACK(SetCursorLocationCallback), | |
285 this); | |
286 g_signal_connect(ibus_panel_service_, | |
287 "update-lookup-table", | |
288 G_CALLBACK(UpdateLookupTableCallback), | |
289 this); | |
290 } | |
291 | |
292 // Removes gobject signal handlers from |ibus_panel_service_|. | |
293 void DisconnectPanelServiceSignals() { | |
294 if (!ibus_panel_service_) { | |
295 return; | |
296 } | |
297 g_signal_handlers_disconnect_by_func( | |
298 ibus_panel_service_, | |
299 reinterpret_cast<gpointer>(HideAuxiliaryTextCallback), | |
300 this); | |
301 g_signal_handlers_disconnect_by_func( | |
302 ibus_panel_service_, | |
303 reinterpret_cast<gpointer>(HideLookupTableCallback), | |
304 this); | |
305 g_signal_handlers_disconnect_by_func( | |
306 ibus_panel_service_, | |
307 reinterpret_cast<gpointer>(UpdateAuxiliaryTextCallback), | |
308 this); | |
309 g_signal_handlers_disconnect_by_func( | |
310 ibus_panel_service_, | |
311 reinterpret_cast<gpointer>(SetCursorLocationCallback), | |
312 this); | |
313 g_signal_handlers_disconnect_by_func( | |
314 ibus_panel_service_, | |
315 reinterpret_cast<gpointer>(UpdateLookupTableCallback), | |
316 this); | |
317 } | |
318 | |
319 // Handles "connected" signal from ibus-daemon. | |
320 static void IBusBusConnectedCallback(IBusBus* bus, gpointer user_data) { | |
321 LOG(WARNING) << "IBus connection is recovered."; | |
322 g_return_if_fail(user_data); | |
323 InputMethodUiStatusConnection* self | |
324 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
325 if (!self->MaybeRestorePanelService()) { | |
326 LOG(ERROR) << "MaybeRestorePanelService() failed"; | |
327 return; | |
328 } | |
329 if (self->connection_change_handler_) { | |
330 self->connection_change_handler_(self->input_method_library_, true); | |
331 } | |
332 } | |
333 | |
334 // Handles "disconnected" signal from ibus-daemon. Releases the | |
335 // |ibus_panel_service_| object since the connection the service has will be | |
336 // destroyed soon. | |
337 static void IBusBusDisconnectedCallback(IBusBus* bus, gpointer user_data) { | |
338 LOG(WARNING) << "IBus connection is terminated."; | |
339 g_return_if_fail(user_data); | |
340 InputMethodUiStatusConnection* self | |
341 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
342 if (self->ibus_panel_service_) { | |
343 self->DisconnectPanelServiceSignals(); | |
344 // Since the connection being disconnected is currently mutex-locked, | |
345 // we can't unref the panel service object directly here. Because when the | |
346 // service object is deleted, the connection, which the service also has, | |
347 // will be locked again. To avoid deadlock, we use g_idle_add instead. | |
348 g_object_set_data(G_OBJECT(self->ibus_), kPanelObjectKey, NULL); | |
349 g_idle_add(ReleasePanelService, self->ibus_panel_service_); | |
350 self->ibus_panel_service_ = NULL; | |
351 } | |
352 | |
353 if (self->connection_change_handler_) { | |
354 self->connection_change_handler_(self->input_method_library_, false); | |
355 } | |
356 } | |
357 | |
358 // Releases |ibus_panel_service_|. See the comment above. | |
359 static gboolean ReleasePanelService(gpointer user_data) { | |
360 g_return_val_if_fail(IBUS_IS_PANEL_SERVICE(user_data), FALSE); | |
361 g_object_unref(user_data); | |
362 return FALSE; // stop the idle timer. | |
363 } | |
364 | |
365 // Handles IBusPanelService's |HideAuxiliaryText| method call. | |
366 // Calls |hide_auxiliary_text| in |monitor_functions|. | |
367 static void HideAuxiliaryTextCallback(IBusPanelService *panel, | |
368 gpointer user_data) { | |
369 g_return_if_fail(user_data); | |
370 InputMethodUiStatusConnection* self | |
371 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
372 g_return_if_fail(self->monitor_functions_.hide_auxiliary_text); | |
373 self->monitor_functions_.hide_auxiliary_text(self->input_method_library_); | |
374 } | |
375 | |
376 // Handles IBusPanelService's |HideLookupTable| method call. | |
377 // Calls |hide_lookup_table| in |monitor_functions|. | |
378 static void HideLookupTableCallback(IBusPanelService *panel, | |
379 gpointer user_data) { | |
380 g_return_if_fail(user_data); | |
381 InputMethodUiStatusConnection* self | |
382 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
383 g_return_if_fail(self->monitor_functions_.hide_lookup_table); | |
384 self->monitor_functions_.hide_lookup_table(self->input_method_library_); | |
385 } | |
386 | |
387 // Handles IBusPanelService's |UpdateAuxiliaryText| method call. | |
388 // Converts IBusText to a std::string, and calls |update_auxiliary_text| in | |
389 // |monitor_functions| | |
390 static void UpdateAuxiliaryTextCallback(IBusPanelService *panel, | |
391 IBusText *text, | |
392 gboolean visible, | |
393 gpointer user_data) { | |
394 g_return_if_fail(text); | |
395 g_return_if_fail(text->text); | |
396 g_return_if_fail(user_data); | |
397 InputMethodUiStatusConnection* self | |
398 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
399 g_return_if_fail(self->monitor_functions_.update_auxiliary_text); | |
400 // Convert IBusText to a std::string. IBusText is an attributed text, | |
401 const std::string simple_text = text->text; | |
402 self->monitor_functions_.update_auxiliary_text( | |
403 self->input_method_library_, simple_text, visible == TRUE); | |
404 } | |
405 | |
406 // Handles IBusPanelService's |SetCursorLocation| method call. | |
407 // Calls |set_cursor_location| in |monitor_functions|. | |
408 static void SetCursorLocationCallback(IBusPanelService *panel, | |
409 gint x, | |
410 gint y, | |
411 gint width, | |
412 gint height, | |
413 gpointer user_data) { | |
414 g_return_if_fail(user_data); | |
415 InputMethodUiStatusConnection* self | |
416 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
417 g_return_if_fail(self->monitor_functions_.set_cursor_location); | |
418 self->monitor_functions_.set_cursor_location( | |
419 self->input_method_library_, x, y, width, height); | |
420 } | |
421 | |
422 // Handles IBusPanelService's |UpdateLookupTable| method call. | |
423 // Creates an InputMethodLookupTable object and calls |update_lookup_table| in | |
424 // |monitor_functions| | |
425 static void UpdateLookupTableCallback(IBusPanelService *panel, | |
426 IBusLookupTable *table, | |
427 gboolean visible, | |
428 gpointer user_data) { | |
429 g_return_if_fail(table); | |
430 g_return_if_fail(user_data); | |
431 InputMethodUiStatusConnection* self | |
432 = static_cast<InputMethodUiStatusConnection*>(user_data); | |
433 g_return_if_fail(self->monitor_functions_.update_lookup_table); | |
434 | |
435 InputMethodLookupTable lookup_table; | |
436 lookup_table.visible = (visible == TRUE); | |
437 | |
438 // Copy the orientation information. | |
439 const gint orientation = ibus_lookup_table_get_orientation(table); | |
440 if (orientation == IBUS_ORIENTATION_VERTICAL) { | |
441 lookup_table.orientation = InputMethodLookupTable::kVertical; | |
442 } else if (orientation == IBUS_ORIENTATION_HORIZONTAL) { | |
443 lookup_table.orientation = InputMethodLookupTable::kHorizontal; | |
444 } | |
445 | |
446 // Copy candidates and annotations to |lookup_table|. | |
447 for (int i = 0; ; i++) { | |
448 IBusText *text = ibus_lookup_table_get_candidate(table, i); | |
449 if (!text) { | |
450 break; | |
451 } | |
452 | |
453 if (!text->attrs || !text->attrs->attributes) { | |
454 lookup_table.candidates.push_back(text->text); | |
455 lookup_table.annotations.push_back(""); | |
456 continue; | |
457 } | |
458 | |
459 // Divide candidate and annotation by specific attribute. | |
460 const guint length = text->attrs->attributes->len; | |
461 for (int j = 0; ; j++) { | |
462 IBusAttribute *attr = ibus_attr_list_get(text->attrs, j); | |
463 | |
464 // The candidate does not have annotation. | |
465 if (!attr) { | |
466 lookup_table.candidates.push_back(text->text); | |
467 lookup_table.annotations.push_back(""); | |
468 break; | |
469 } | |
470 | |
471 // Check that the attribute indicates annotation. | |
472 if (IsAnnotation(attr) && j + 1 == static_cast<int>(length)) { | |
473 const std::wstring candidate_word = | |
474 UTF8ToWide(text->text).substr(0, attr->start_index); | |
475 lookup_table.candidates.push_back(WideToUTF8(candidate_word)); | |
476 | |
477 const std::wstring annotation_word = | |
478 UTF8ToWide(text->text).substr(attr->start_index, attr->end_index); | |
479 lookup_table.annotations.push_back(WideToUTF8(annotation_word)); | |
480 | |
481 break; | |
482 } | |
483 } | |
484 } | |
485 DCHECK_EQ(lookup_table.candidates.size(), | |
486 lookup_table.annotations.size()); | |
487 | |
488 // Copy labels to |lookup_table|. | |
489 for (int i = 0; ; i++) { | |
490 IBusText *text = ibus_lookup_table_get_label(table, i); | |
491 if (!text) { | |
492 break; | |
493 } | |
494 lookup_table.labels.push_back(text->text); | |
495 } | |
496 | |
497 lookup_table.cursor_absolute_index = | |
498 ibus_lookup_table_get_cursor_pos(table); | |
499 lookup_table.page_size = ibus_lookup_table_get_page_size(table); | |
500 // Ensure that the page_size is non-zero to avoid div-by-zero error. | |
501 if (lookup_table.page_size <= 0) { | |
502 LOG(DFATAL) << "Invalid page size: " << lookup_table.page_size; | |
503 lookup_table.page_size = 1; | |
504 } | |
505 | |
506 self->monitor_functions_.update_lookup_table( | |
507 self->input_method_library_, lookup_table); | |
508 } | |
509 | |
510 // A callback function that will be called when ibus_bus_request_name_async() | |
511 // request is finished. | |
512 static void RequestNameCallback(GObject* source_object, | |
513 GAsyncResult* res, | |
514 gpointer user_data) { | |
515 IBusBus* bus = IBUS_BUS(user_data); | |
516 g_return_if_fail(bus); | |
517 | |
518 GError* error = NULL; | |
519 const guint service_id = | |
520 ibus_bus_request_name_async_finish(bus, res, &error); | |
521 | |
522 if (!service_id) { | |
523 std::string message = "(unknown error)"; | |
524 if (error && error->message) { | |
525 message = error->message; | |
526 } | |
527 LOG(ERROR) << "Failed to register the panel service: " << message; | |
528 } else { | |
529 LOG(INFO) << "The panel service is registered: ID=" << service_id; | |
530 } | |
531 | |
532 if (error) { | |
533 g_error_free(error); | |
534 } | |
535 g_object_unref(bus); | |
536 } | |
537 | |
538 InputMethodUiStatusMonitorFunctions monitor_functions_; | |
539 InputMethodConnectionChangeMonitorFunction connection_change_handler_; | |
540 void* input_method_library_; | |
541 IBusBus* ibus_; | |
542 IBusPanelService* ibus_panel_service_; | |
543 }; | |
544 | |
545 // | |
546 // cros APIs | |
547 // | |
548 | |
549 // The function will be bound to chromeos::MonitorInputMethodUiStatus with | |
550 // dlsym() in load.cc so it needs to be in the C linkage, so the symbol | |
551 // name does not get mangled. | |
552 extern "C" | |
553 InputMethodUiStatusConnection* ChromeOSMonitorInputMethodUiStatus( | |
554 const InputMethodUiStatusMonitorFunctions& monitor_functions, | |
555 void* input_method_library) { | |
556 DLOG(INFO) << "MonitorInputMethodUiStatus"; | |
557 | |
558 InputMethodUiStatusConnection* connection = | |
559 new InputMethodUiStatusConnection(monitor_functions, | |
560 input_method_library); | |
561 | |
562 // It's totally fine if ConnectToIBus() fails here, as we'll get "connected" | |
563 // gobject signal once the connection becomes ready. | |
564 if (connection->ConnectToIBus()) { | |
565 connection->MaybeRestorePanelService(); | |
566 } | |
567 return connection; | |
568 } | |
569 | |
570 extern "C" | |
571 void ChromeOSDisconnectInputMethodUiStatus( | |
572 InputMethodUiStatusConnection* connection) { | |
573 DLOG(INFO) << "DisconnectInputMethodUiStatus"; | |
574 delete connection; | |
575 } | |
576 | |
577 extern "C" | |
578 void ChromeOSNotifyCandidateClicked(InputMethodUiStatusConnection* connection, | |
579 int index, int button, int flags) { | |
580 DLOG(INFO) << "NotifyCandidateClicked"; | |
581 DCHECK(connection); | |
582 if (connection) { | |
583 connection->NotifyCandidateClicked(index, button, flags); | |
584 } | |
585 } | |
586 | |
587 extern "C" | |
588 void ChromeOSNotifyCursorUp(InputMethodUiStatusConnection* connection) { | |
589 DLOG(INFO) << "NotifyCursorUp"; | |
590 DCHECK(connection); | |
591 if (connection) { | |
592 connection->NotifyCursorUp(); | |
593 } | |
594 } | |
595 | |
596 extern "C" | |
597 void ChromeOSNotifyCursorDown(InputMethodUiStatusConnection* connection) { | |
598 DLOG(INFO) << "NotifyCursorDown"; | |
599 DCHECK(connection); | |
600 if (connection) { | |
601 connection->NotifyCursorDown(); | |
602 } | |
603 } | |
604 | |
605 extern "C" | |
606 void ChromeOSNotifyPageUp(InputMethodUiStatusConnection* connection) { | |
607 DLOG(INFO) << "NotifyPageUp"; | |
608 DCHECK(connection); | |
609 if (connection) { | |
610 connection->NotifyPageUp(); | |
611 } | |
612 } | |
613 | |
614 extern "C" | |
615 void ChromeOSNotifyPageDown(InputMethodUiStatusConnection* connection) { | |
616 DLOG(INFO) << "NotifyPageDown"; | |
617 DCHECK(connection); | |
618 if (connection) { | |
619 connection->NotifyPageDown(); | |
620 } | |
621 } | |
622 | |
623 extern "C" | |
624 void ChromeOSMonitorInputMethodConnection( | |
625 InputMethodUiStatusConnection* connection, | |
626 InputMethodConnectionChangeMonitorFunction connection_change_handler) { | |
627 DLOG(INFO) << "MonitorInputMethodConnection"; | |
628 DCHECK(connection); | |
629 if (connection) { | |
630 connection->MonitorInputMethodConnection(connection_change_handler); | |
631 } | |
632 } | |
633 | |
634 } // namespace chromeos | |
OLD | NEW |