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