1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4 * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5 * Copyright (C) 2008-2010 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include "engineproxy.h"
27 #include "marshalers.h"
30 struct _BusEngineProxy {
33 /* instance members */
34 /* TRUE if the engine has a focus (local copy of the engine's status.) */
36 /* TRUE if the engine is enabled (local copy of the engine's status.) */
38 /* A set of capabilities the current client supports (local copy of the engine's flag.) */
40 /* The current cursor location that are sent to the engine. */
46 /* an engine desc used to create the proxy. */
49 /* a key mapping for the engine that converts keycode into keysym. the mapping is used only when use_sys_layout is FALSE. */
53 /* cached surrounding text (see also IBusEnginePrivate and
54 IBusInputContextPrivate) */
55 IBusText *surrounding_text;
56 guint surrounding_cursor_pos;
57 guint selection_anchor_pos;
59 /* cached properties */
60 IBusPropList *prop_list;
63 struct _BusEngineProxyClass {
64 IBusProxyClass parent;
66 void (* register_properties) (BusEngineProxy *engine,
67 IBusPropList *prop_list);
68 void (* update_property) (BusEngineProxy *engine,
75 DELETE_SURROUNDING_TEXT,
76 REQUIRE_SURROUNDING_TEXT,
80 UPDATE_AUXILIARY_TEXT,
87 PAGE_DOWN_LOOKUP_TABLE,
88 CURSOR_UP_LOOKUP_TABLE,
89 CURSOR_DOWN_LOOKUP_TABLE,
100 static guint engine_signals[LAST_SIGNAL] = { 0 };
102 static IBusText *text_empty = NULL;
103 static IBusPropList *prop_list_empty = NULL;
105 /* functions prototype */
106 static void bus_engine_proxy_set_property (BusEngineProxy *engine,
110 static void bus_engine_proxy_get_property (BusEngineProxy *engine,
114 static void bus_engine_proxy_real_register_properties
115 (BusEngineProxy *engine,
116 IBusPropList *prop_list);
117 static void bus_engine_proxy_real_update_property
118 (BusEngineProxy *engine,
120 static void bus_engine_proxy_real_destroy (IBusProxy *proxy);
121 static void bus_engine_proxy_g_signal (GDBusProxy *proxy,
122 const gchar *sender_name,
123 const gchar *signal_name,
124 GVariant *parameters);
125 static void bus_engine_proxy_initable_iface_init
126 (GInitableIface *initable_iface);
128 G_DEFINE_TYPE_WITH_CODE (BusEngineProxy, bus_engine_proxy, IBUS_TYPE_PROXY,
129 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, bus_engine_proxy_initable_iface_init)
132 static GInitableIface *parent_initable_iface = NULL;
135 bus_engine_proxy_class_init (BusEngineProxyClass *class)
137 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
139 gobject_class->set_property = (GObjectSetPropertyFunc)bus_engine_proxy_set_property;
140 gobject_class->get_property = (GObjectGetPropertyFunc)bus_engine_proxy_get_property;
142 class->register_properties = bus_engine_proxy_real_register_properties;
143 class->update_property = bus_engine_proxy_real_update_property;
145 IBUS_PROXY_CLASS (class)->destroy = bus_engine_proxy_real_destroy;
146 G_DBUS_PROXY_CLASS (class)->g_signal = bus_engine_proxy_g_signal;
148 parent_initable_iface =
149 (GInitableIface *)g_type_interface_peek (bus_engine_proxy_parent_class, G_TYPE_INITABLE);
151 /* install properties */
152 g_object_class_install_property (gobject_class,
154 g_param_spec_object ("desc",
157 IBUS_TYPE_ENGINE_DESC,
159 G_PARAM_CONSTRUCT_ONLY |
160 G_PARAM_STATIC_NAME |
161 G_PARAM_STATIC_BLURB |
165 /* install glib signals that will be sent when corresponding D-Bus signals are sent from an engine process. */
166 engine_signals[COMMIT_TEXT] =
167 g_signal_new (I_("commit-text"),
168 G_TYPE_FROM_CLASS (class),
172 bus_marshal_VOID__OBJECT,
177 engine_signals[FORWARD_KEY_EVENT] =
178 g_signal_new (I_("forward-key-event"),
179 G_TYPE_FROM_CLASS (class),
183 bus_marshal_VOID__UINT_UINT_UINT,
190 engine_signals[DELETE_SURROUNDING_TEXT] =
191 g_signal_new (I_("delete-surrounding-text"),
192 G_TYPE_FROM_CLASS (class),
196 bus_marshal_VOID__INT_UINT,
202 engine_signals[REQUIRE_SURROUNDING_TEXT] =
203 g_signal_new (I_("require-surrounding-text"),
204 G_TYPE_FROM_CLASS (class),
208 bus_marshal_VOID__VOID,
212 engine_signals[UPDATE_PREEDIT_TEXT] =
213 g_signal_new (I_("update-preedit-text"),
214 G_TYPE_FROM_CLASS (class),
218 bus_marshal_VOID__OBJECT_UINT_BOOLEAN_UINT,
226 engine_signals[SHOW_PREEDIT_TEXT] =
227 g_signal_new (I_("show-preedit-text"),
228 G_TYPE_FROM_CLASS (class),
232 bus_marshal_VOID__VOID,
236 engine_signals[HIDE_PREEDIT_TEXT] =
237 g_signal_new (I_("hide-preedit-text"),
238 G_TYPE_FROM_CLASS (class),
242 bus_marshal_VOID__VOID,
246 engine_signals[UPDATE_AUXILIARY_TEXT] =
247 g_signal_new (I_("update-auxiliary-text"),
248 G_TYPE_FROM_CLASS (class),
252 bus_marshal_VOID__OBJECT_BOOLEAN,
258 engine_signals[SHOW_AUXILIARY_TEXT] =
259 g_signal_new (I_("show-auxiliary-text"),
260 G_TYPE_FROM_CLASS (class),
264 bus_marshal_VOID__VOID,
268 engine_signals[HIDE_AUXILIARY_TEXT] =
269 g_signal_new (I_("hide-auxiliary-text"),
270 G_TYPE_FROM_CLASS (class),
274 bus_marshal_VOID__VOID,
278 engine_signals[UPDATE_LOOKUP_TABLE] =
279 g_signal_new (I_("update-lookup-table"),
280 G_TYPE_FROM_CLASS (class),
284 bus_marshal_VOID__OBJECT_BOOLEAN,
287 IBUS_TYPE_LOOKUP_TABLE,
290 engine_signals[SHOW_LOOKUP_TABLE] =
291 g_signal_new (I_("show-lookup-table"),
292 G_TYPE_FROM_CLASS (class),
296 bus_marshal_VOID__VOID,
300 engine_signals[HIDE_LOOKUP_TABLE] =
301 g_signal_new (I_("hide-lookup-table"),
302 G_TYPE_FROM_CLASS (class),
306 bus_marshal_VOID__VOID,
310 engine_signals[PAGE_UP_LOOKUP_TABLE] =
311 g_signal_new (I_("page-up-lookup-table"),
312 G_TYPE_FROM_CLASS (class),
316 bus_marshal_VOID__VOID,
320 engine_signals[PAGE_DOWN_LOOKUP_TABLE] =
321 g_signal_new (I_("page-down-lookup-table"),
322 G_TYPE_FROM_CLASS (class),
326 bus_marshal_VOID__VOID,
330 engine_signals[CURSOR_UP_LOOKUP_TABLE] =
331 g_signal_new (I_("cursor-up-lookup-table"),
332 G_TYPE_FROM_CLASS (class),
336 bus_marshal_VOID__VOID,
340 engine_signals[CURSOR_DOWN_LOOKUP_TABLE] =
341 g_signal_new (I_("cursor-down-lookup-table"),
342 G_TYPE_FROM_CLASS (class),
346 bus_marshal_VOID__VOID,
350 engine_signals[REGISTER_PROPERTIES] =
351 g_signal_new (I_("register-properties"),
352 G_TYPE_FROM_CLASS (class),
354 G_STRUCT_OFFSET (BusEngineProxyClass, register_properties),
356 bus_marshal_VOID__OBJECT,
359 IBUS_TYPE_PROP_LIST);
361 engine_signals[UPDATE_PROPERTY] =
362 g_signal_new (I_("update-property"),
363 G_TYPE_FROM_CLASS (class),
365 G_STRUCT_OFFSET (BusEngineProxyClass, update_property),
367 bus_marshal_VOID__OBJECT,
372 text_empty = ibus_text_new_from_static_string ("");
373 g_object_ref_sink (text_empty);
375 prop_list_empty = ibus_prop_list_new ();
376 g_object_ref_sink (prop_list_empty);
380 bus_engine_proxy_init (BusEngineProxy *engine)
382 engine->surrounding_text = g_object_ref_sink (text_empty);
383 engine->prop_list = g_object_ref_sink (prop_list_empty);
387 bus_engine_proxy_set_property (BusEngineProxy *engine,
393 case PROP_ENGINE_DESC:
394 g_assert (engine->desc == NULL);
395 engine->desc = g_value_dup_object (value);
398 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
403 bus_engine_proxy_get_property (BusEngineProxy *engine,
409 case PROP_ENGINE_DESC:
410 g_value_set_object (value, bus_engine_proxy_get_desc (engine));
413 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
419 bus_engine_proxy_real_register_properties (BusEngineProxy *engine,
420 IBusPropList *prop_list)
422 g_assert (IBUS_IS_PROP_LIST (prop_list));
424 if (engine->prop_list != prop_list_empty)
425 g_object_unref (engine->prop_list);
426 engine->prop_list = (IBusPropList *) g_object_ref_sink (prop_list);
430 bus_engine_proxy_real_update_property (BusEngineProxy *engine,
433 g_return_if_fail (prop);
434 if (engine->prop_list)
435 ibus_prop_list_update_property (engine->prop_list, prop);
439 bus_engine_proxy_real_destroy (IBusProxy *proxy)
441 BusEngineProxy *engine = (BusEngineProxy *)proxy;
444 g_object_unref (engine->desc);
448 if (engine->keymap) {
449 g_object_unref (engine->keymap);
450 engine->keymap = NULL;
453 if (engine->surrounding_text) {
454 g_object_unref (engine->surrounding_text);
455 engine->surrounding_text = NULL;
458 if (engine->prop_list) {
459 g_object_unref (engine->prop_list);
460 engine->prop_list = NULL;
463 IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy ((IBusProxy *)engine);
467 _g_object_unref_if_floating (gpointer instance)
469 if (g_object_is_floating (instance))
470 g_object_unref (instance);
474 * bus_engine_proxy_g_signal:
476 * Handle all D-Bus signals from the engine process. This function emits corresponding glib signal for the D-Bus signal.
479 bus_engine_proxy_g_signal (GDBusProxy *proxy,
480 const gchar *sender_name,
481 const gchar *signal_name,
482 GVariant *parameters)
484 BusEngineProxy *engine = (BusEngineProxy *)proxy;
486 /* The list of nullary D-Bus signals. */
487 static const struct {
488 const gchar *signal_name;
489 const guint signal_id;
491 { "ShowPreeditText", SHOW_PREEDIT_TEXT },
492 { "HidePreeditText", HIDE_PREEDIT_TEXT },
493 { "ShowAuxiliaryText", SHOW_AUXILIARY_TEXT },
494 { "HideAuxiliaryText", HIDE_AUXILIARY_TEXT },
495 { "ShowLookupTable", SHOW_LOOKUP_TABLE },
496 { "HideLookupTable", HIDE_LOOKUP_TABLE },
497 { "PageUpLookupTable", PAGE_UP_LOOKUP_TABLE },
498 { "PageDownLookupTable", PAGE_DOWN_LOOKUP_TABLE },
499 { "CursorUpLookupTable", CURSOR_UP_LOOKUP_TABLE },
500 { "CursorDownLookupTable", CURSOR_DOWN_LOOKUP_TABLE },
501 { "RequireSurroundingText", REQUIRE_SURROUNDING_TEXT },
505 for (i = 0; i < G_N_ELEMENTS (signals); i++) {
506 if (g_strcmp0 (signal_name, signals[i].signal_name) == 0) {
507 g_signal_emit (engine, engine_signals[signals[i].signal_id], 0);
512 /* Handle D-Bus signals with parameters. Deserialize them and emit a glib signal. */
513 if (g_strcmp0 (signal_name, "CommitText") == 0) {
514 GVariant *arg0 = NULL;
515 g_variant_get (parameters, "(v)", &arg0);
516 g_return_if_fail (arg0 != NULL);
518 IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
519 g_variant_unref (arg0);
520 g_return_if_fail (text != NULL);
521 g_signal_emit (engine, engine_signals[COMMIT_TEXT], 0, text);
522 _g_object_unref_if_floating (text);
526 if (g_strcmp0 (signal_name, "ForwardKeyEvent") == 0) {
530 g_variant_get (parameters, "(uuu)", &keyval, &keycode, &states);
532 g_signal_emit (engine,
533 engine_signals[FORWARD_KEY_EVENT],
541 if (g_strcmp0 (signal_name, "DeleteSurroundingText") == 0) {
542 gint offset_from_cursor = 0;
544 g_variant_get (parameters, "(iu)", &offset_from_cursor, &nchars);
546 g_signal_emit (engine,
547 engine_signals[DELETE_SURROUNDING_TEXT],
548 0, offset_from_cursor, nchars);
552 if (g_strcmp0 (signal_name, "UpdatePreeditText") == 0) {
553 GVariant *arg0 = NULL;
554 guint cursor_pos = 0;
555 gboolean visible = FALSE;
558 g_variant_get (parameters, "(vubu)", &arg0, &cursor_pos, &visible, &mode);
559 g_return_if_fail (arg0 != NULL);
561 IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
562 g_variant_unref (arg0);
563 g_return_if_fail (text != NULL);
565 g_signal_emit (engine,
566 engine_signals[UPDATE_PREEDIT_TEXT],
567 0, text, cursor_pos, visible, mode);
569 _g_object_unref_if_floating (text);
573 if (g_strcmp0 (signal_name, "UpdateAuxiliaryText") == 0) {
574 GVariant *arg0 = NULL;
575 gboolean visible = FALSE;
577 g_variant_get (parameters, "(vb)", &arg0, &visible);
578 g_return_if_fail (arg0 != NULL);
580 IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
581 g_variant_unref (arg0);
582 g_return_if_fail (text != NULL);
584 g_signal_emit (engine, engine_signals[UPDATE_AUXILIARY_TEXT], 0, text, visible);
585 _g_object_unref_if_floating (text);
589 if (g_strcmp0 (signal_name, "UpdateLookupTable") == 0) {
590 GVariant *arg0 = NULL;
591 gboolean visible = FALSE;
593 g_variant_get (parameters, "(vb)", &arg0, &visible);
594 g_return_if_fail (arg0 != NULL);
596 IBusLookupTable *table = IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (arg0));
597 g_variant_unref (arg0);
598 g_return_if_fail (table != NULL);
600 g_signal_emit (engine, engine_signals[UPDATE_LOOKUP_TABLE], 0, table, visible);
601 _g_object_unref_if_floating (table);
605 if (g_strcmp0 (signal_name, "RegisterProperties") == 0) {
606 GVariant *arg0 = NULL;
607 g_variant_get (parameters, "(v)", &arg0);
608 g_return_if_fail (arg0 != NULL);
610 IBusPropList *prop_list = IBUS_PROP_LIST (ibus_serializable_deserialize (arg0));
611 g_variant_unref (arg0);
612 g_return_if_fail (prop_list != NULL);
614 g_signal_emit (engine, engine_signals[REGISTER_PROPERTIES], 0, prop_list);
615 _g_object_unref_if_floating (prop_list);
619 if (g_strcmp0 (signal_name, "UpdateProperty") == 0) {
620 GVariant *arg0 = NULL;
621 g_variant_get (parameters, "(v)", &arg0);
622 g_return_if_fail (arg0 != NULL);
624 IBusProperty *prop = IBUS_PROPERTY (ibus_serializable_deserialize (arg0));
625 g_variant_unref (arg0);
626 g_return_if_fail (prop != NULL);
628 g_signal_emit (engine, engine_signals[UPDATE_PROPERTY], 0, prop);
629 _g_object_unref_if_floating (prop);
633 g_return_if_reached ();
636 static BusEngineProxy *
637 bus_engine_proxy_new_internal (const gchar *path,
638 IBusEngineDesc *desc,
639 GDBusConnection *connection)
642 g_assert (IBUS_IS_ENGINE_DESC (desc));
643 g_assert (G_IS_DBUS_CONNECTION (connection));
645 GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
646 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
647 BusEngineProxy *engine =
648 (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY,
652 "g-connection", connection,
653 "g-interface-name", IBUS_INTERFACE_ENGINE,
654 "g-object-path", path,
655 "g-default-timeout", g_gdbus_timeout,
658 const gchar *layout = ibus_engine_desc_get_layout (desc);
659 if (layout != NULL && layout[0] != '\0') {
660 engine->keymap = ibus_keymap_get (layout);
666 GSimpleAsyncResult *simple;
667 IBusEngineDesc *desc;
668 BusComponent *component;
669 BusFactoryProxy *factory;
670 GCancellable *cancellable;
671 gulong cancelled_handler_id;
675 } EngineProxyNewData;
678 engine_proxy_new_data_free (EngineProxyNewData *data)
680 if (data->simple != NULL) {
681 g_object_unref (data->simple);
684 if (data->desc != NULL) {
685 g_object_unref (data->desc);
688 if (data->component != NULL) {
689 if (data->handler_id != 0) {
690 g_signal_handler_disconnect (data->component, data->handler_id);
692 g_object_unref (data->component);
695 if (data->factory != NULL) {
696 g_object_unref (data->factory);
699 if (data->timeout_id != 0) {
700 g_source_remove (data->timeout_id);
703 if (data->cancellable != NULL) {
704 if (data->cancelled_handler_id != 0) {
705 g_cancellable_disconnect (data->cancellable,
706 data->cancelled_handler_id);
708 g_object_unref (data->cancellable);
711 g_slice_free (EngineProxyNewData, data);
715 * create_engine_ready_cb:
717 * A callback function to be called when bus_factory_proxy_create_engine finishes.
718 * Create an BusEngineProxy object and call the GAsyncReadyCallback.
721 create_engine_ready_cb (BusFactoryProxy *factory,
723 EngineProxyNewData *data)
725 g_return_if_fail (data->simple != NULL);
727 GError *error = NULL;
728 gchar *path = bus_factory_proxy_create_engine_finish (factory,
732 g_simple_async_result_set_from_error (data->simple, error);
733 g_simple_async_result_complete_in_idle (data->simple);
734 engine_proxy_new_data_free (data);
738 BusEngineProxy *engine =
739 bus_engine_proxy_new_internal (path,
741 g_dbus_proxy_get_connection ((GDBusProxy *)data->factory));
744 /* FIXME: set destroy callback ? */
745 g_simple_async_result_set_op_res_gpointer (data->simple, engine, NULL);
746 g_simple_async_result_complete_in_idle (data->simple);
748 engine_proxy_new_data_free (data);
754 * A callback function to be called when bus_component_start() emits "notify::factory" signal within 5 seconds.
755 * Call bus_factory_proxy_create_engine to create the engine proxy asynchronously.
758 notify_factory_cb (BusComponent *component,
760 EngineProxyNewData *data)
762 data->factory = bus_component_get_factory (data->component);
764 if (data->factory != NULL) {
765 g_object_ref (data->factory);
766 /* Timeout should be removed */
767 if (data->timeout_id != 0) {
768 g_source_remove (data->timeout_id);
769 data->timeout_id = 0;
771 /* Handler of notify::factory should be removed. */
772 if (data->handler_id != 0) {
773 g_signal_handler_disconnect (data->component, data->handler_id);
774 data->handler_id = 0;
777 /* We *have to* disconnect the cancelled_cb here, since g_dbus_proxy_call
778 * calls create_engine_ready_cb even if the proxy call is cancelled, and
779 * in this case, create_engine_ready_cb itself will return error using
780 * g_simple_async_result_set_from_error and g_simple_async_result_complete.
781 * Otherwise, g_simple_async_result_complete might be called twice for a
782 * single data->simple twice (first in cancelled_cb and later in
783 * create_engine_ready_cb). */
784 if (data->cancellable && data->cancelled_handler_id != 0) {
785 g_cancellable_disconnect (data->cancellable, data->cancelled_handler_id);
786 data->cancelled_handler_id = 0;
789 /* Create engine from factory. */
790 bus_factory_proxy_create_engine (data->factory,
794 (GAsyncReadyCallback) create_engine_ready_cb,
797 /* If factory is NULL, we will continue wait for
798 * factory notify signal or timeout */
804 * A callback function to be called when bus_component_start() does not emit "notify::factory" signal within 5 seconds.
805 * Call the GAsyncReadyCallback and stop the 5 sec timer.
808 timeout_cb (EngineProxyNewData *data)
810 g_simple_async_result_set_error (data->simple,
813 "Timeout was reached");
814 g_simple_async_result_complete_in_idle (data->simple);
816 engine_proxy_new_data_free (data);
824 * A callback function to be called when someone calls g_cancellable_cancel()
825 * for the cancellable object for bus_engine_proxy_new.
826 * Call the GAsyncReadyCallback.
829 cancelled_idle_cb (EngineProxyNewData *data)
831 g_simple_async_result_set_error (data->simple,
834 "Operation was cancelled");
835 g_simple_async_result_complete_in_idle (data->simple);
837 engine_proxy_new_data_free (data);
843 cancelled_cb (GCancellable *cancellable,
844 EngineProxyNewData *data)
846 /* Cancel the bus_engine_proxy_new() in idle to avoid deadlock.
847 * And use HIGH priority to avoid timeout event happening before
849 g_idle_add_full (G_PRIORITY_HIGH,
850 (GSourceFunc) cancelled_idle_cb,
855 bus_engine_proxy_new (IBusEngineDesc *desc,
857 GCancellable *cancellable,
858 GAsyncReadyCallback callback,
861 g_assert (IBUS_IS_ENGINE_DESC (desc));
862 g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
865 GSimpleAsyncResult *simple =
866 g_simple_async_result_new (NULL,
869 bus_engine_proxy_new);
871 if (g_cancellable_is_cancelled (cancellable)) {
872 g_simple_async_result_set_error (simple,
875 "Operation was cancelled");
876 g_simple_async_result_complete_in_idle (simple);
877 g_object_unref (simple);
881 EngineProxyNewData *data = g_slice_new0 (EngineProxyNewData);
882 data->desc = g_object_ref (desc);
883 data->component = bus_component_from_engine_desc (desc);
884 g_object_ref (data->component);
885 data->simple = simple;
886 data->timeout = timeout;
888 data->factory = bus_component_get_factory (data->component);
890 if (data->factory == NULL) {
891 /* The factory is not ready yet. Create the factory first, and wait for
892 * the "notify::factory" signal. In the handler of "notify::factory",
893 * we'll create the engine proxy. */
894 data->handler_id = g_signal_connect (data->component,
896 G_CALLBACK (notify_factory_cb),
898 data->timeout_id = g_timeout_add (timeout,
899 (GSourceFunc) timeout_cb,
902 data->cancellable = (GCancellable *) g_object_ref (cancellable);
903 data->cancelled_handler_id = g_cancellable_connect (cancellable,
904 (GCallback) cancelled_cb,
908 bus_component_start (data->component, g_verbose);
911 /* The factory is ready. We'll create the engine proxy directly. */
912 g_object_ref (data->factory);
914 /* We don't have to connect to cancelled_cb here, since g_dbus_proxy_call
915 * calls create_engine_ready_cb even if the proxy call is cancelled, and
916 * in this case, create_engine_ready_cb itself can return error using
917 * g_simple_async_result_set_from_error and g_simple_async_result_complete. */
918 bus_factory_proxy_create_engine (data->factory,
922 (GAsyncReadyCallback) create_engine_ready_cb,
928 bus_engine_proxy_new_finish (GAsyncResult *res,
931 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
933 g_assert (error == NULL || *error == NULL);
934 g_assert (g_simple_async_result_get_source_tag (simple) == bus_engine_proxy_new);
936 if (g_simple_async_result_propagate_error (simple, error))
939 return (BusEngineProxy *) g_simple_async_result_get_op_res_gpointer(simple);
943 bus_engine_proxy_process_key_event (BusEngineProxy *engine,
947 GAsyncReadyCallback callback,
950 g_assert (BUS_IS_ENGINE_PROXY (engine));
952 if (keycode != 0 && bus_ibus_impl_is_use_sys_layout (BUS_DEFAULT_IBUS) == FALSE) {
953 /* Since use_sys_layout is false, we don't rely on XKB. Try to convert keyval from keycode by using our own mapping. */
954 IBusKeymap *keymap = engine->keymap;
956 keymap = BUS_DEFAULT_KEYMAP;
957 if (keymap != NULL) {
958 guint t = ibus_keymap_lookup_keysym (keymap, keycode, state);
959 if (t != IBUS_KEY_VoidSymbol) {
965 g_dbus_proxy_call ((GDBusProxy *)engine,
967 g_variant_new ("(uuu)", keyval, keycode, state),
968 G_DBUS_CALL_FLAGS_NONE,
976 bus_engine_proxy_set_cursor_location (BusEngineProxy *engine,
982 g_assert (BUS_IS_ENGINE_PROXY (engine));
984 if (engine->x != x || engine->y != y || engine->w != w || engine->h != h) {
989 g_dbus_proxy_call ((GDBusProxy *)engine,
991 g_variant_new ("(iiii)", x, y, w, h),
992 G_DBUS_CALL_FLAGS_NONE,
1001 bus_engine_proxy_process_hand_writing_event
1002 (BusEngineProxy *engine,
1003 GVariant *coordinates)
1005 g_assert (BUS_IS_ENGINE_PROXY (engine));
1007 g_dbus_proxy_call ((GDBusProxy *)engine,
1008 "ProcessHandWritingEvent",
1010 G_DBUS_CALL_FLAGS_NONE,
1018 bus_engine_proxy_cancel_hand_writing
1019 (BusEngineProxy *engine,
1022 g_assert (BUS_IS_ENGINE_PROXY (engine));
1024 g_dbus_proxy_call ((GDBusProxy *)engine,
1025 "CancelHandWriting",
1026 g_variant_new ("(u)", n_strokes),
1027 G_DBUS_CALL_FLAGS_NONE,
1035 bus_engine_proxy_set_capabilities (BusEngineProxy *engine,
1038 g_assert (BUS_IS_ENGINE_PROXY (engine));
1040 if (engine->capabilities != caps) {
1041 engine->capabilities = caps;
1042 g_dbus_proxy_call ((GDBusProxy *)engine,
1044 g_variant_new ("(u)", caps),
1045 G_DBUS_CALL_FLAGS_NONE,
1054 bus_engine_proxy_property_activate (BusEngineProxy *engine,
1055 const gchar *prop_name,
1058 g_assert (BUS_IS_ENGINE_PROXY (engine));
1059 g_assert (prop_name != NULL);
1061 g_dbus_proxy_call ((GDBusProxy *)engine,
1063 g_variant_new ("(su)", prop_name, prop_state),
1064 G_DBUS_CALL_FLAGS_NONE,
1072 bus_engine_proxy_property_show (BusEngineProxy *engine,
1073 const gchar *prop_name)
1075 g_assert (BUS_IS_ENGINE_PROXY (engine));
1076 g_assert (prop_name != NULL);
1078 g_dbus_proxy_call ((GDBusProxy *)engine,
1080 g_variant_new ("(s)", prop_name),
1081 G_DBUS_CALL_FLAGS_NONE,
1088 void bus_engine_proxy_property_hide (BusEngineProxy *engine,
1089 const gchar *prop_name)
1091 g_assert (BUS_IS_ENGINE_PROXY (engine));
1092 g_assert (prop_name != NULL);
1094 g_dbus_proxy_call ((GDBusProxy *)engine,
1096 g_variant_new ("(s)", prop_name),
1097 G_DBUS_CALL_FLAGS_NONE,
1104 void bus_engine_proxy_set_surrounding_text (BusEngineProxy *engine,
1109 g_assert (BUS_IS_ENGINE_PROXY (engine));
1110 g_assert (text != NULL);
1112 if (!engine->surrounding_text ||
1113 g_strcmp0 (text->text, engine->surrounding_text->text) != 0 ||
1114 cursor_pos != engine->surrounding_cursor_pos ||
1115 anchor_pos != engine->selection_anchor_pos) {
1116 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1117 if (engine->surrounding_text)
1118 g_object_unref (engine->surrounding_text);
1119 engine->surrounding_text = (IBusText *) g_object_ref_sink (text);
1120 engine->surrounding_cursor_pos = cursor_pos;
1121 engine->selection_anchor_pos = anchor_pos;
1123 g_dbus_proxy_call ((GDBusProxy *)engine,
1124 "SetSurroundingText",
1125 g_variant_new ("(vuu)",
1129 G_DBUS_CALL_FLAGS_NONE,
1137 /* a macro to generate a function to call a nullary D-Bus method. */
1138 #define DEFINE_FUNCTION(Name, name) \
1140 bus_engine_proxy_##name (BusEngineProxy *engine) \
1142 g_assert (BUS_IS_ENGINE_PROXY (engine)); \
1143 g_dbus_proxy_call ((GDBusProxy *)engine, \
1146 G_DBUS_CALL_FLAGS_NONE, \
1147 -1, NULL, NULL, NULL); \
1150 DEFINE_FUNCTION (Reset, reset)
1151 DEFINE_FUNCTION (PageUp, page_up)
1152 DEFINE_FUNCTION (PageDown, page_down)
1153 DEFINE_FUNCTION (CursorUp, cursor_up)
1154 DEFINE_FUNCTION (CursorDown, cursor_down)
1156 #undef DEFINE_FUNCTION
1159 bus_engine_proxy_focus_in (BusEngineProxy *engine)
1161 g_assert (BUS_IS_ENGINE_PROXY (engine));
1162 if (!engine->has_focus) {
1163 engine->has_focus = TRUE;
1164 g_dbus_proxy_call ((GDBusProxy *)engine,
1167 G_DBUS_CALL_FLAGS_NONE,
1176 bus_engine_proxy_focus_out (BusEngineProxy *engine)
1178 g_assert (BUS_IS_ENGINE_PROXY (engine));
1179 if (engine->has_focus) {
1180 engine->has_focus = FALSE;
1181 g_dbus_proxy_call ((GDBusProxy *)engine,
1184 G_DBUS_CALL_FLAGS_NONE,
1193 bus_engine_proxy_enable (BusEngineProxy *engine)
1195 g_assert (BUS_IS_ENGINE_PROXY (engine));
1196 if (!engine->enabled) {
1197 engine->enabled = TRUE;
1198 g_dbus_proxy_call ((GDBusProxy *)engine,
1201 G_DBUS_CALL_FLAGS_NONE,
1210 bus_engine_proxy_disable (BusEngineProxy *engine)
1212 g_assert (BUS_IS_ENGINE_PROXY (engine));
1213 if (engine->enabled) {
1214 engine->enabled = FALSE;
1215 g_dbus_proxy_call ((GDBusProxy *)engine,
1218 G_DBUS_CALL_FLAGS_NONE,
1227 bus_engine_proxy_candidate_clicked (BusEngineProxy *engine,
1232 g_assert (BUS_IS_ENGINE_PROXY (engine));
1234 g_dbus_proxy_call ((GDBusProxy *)engine,
1236 g_variant_new ("(uuu)", index, button, state),
1237 G_DBUS_CALL_FLAGS_NONE,
1245 bus_engine_proxy_get_desc (BusEngineProxy *engine)
1247 g_assert (BUS_IS_ENGINE_PROXY (engine));
1249 return engine->desc;
1253 bus_engine_proxy_get_properties (BusEngineProxy *engine)
1255 g_assert (BUS_IS_ENGINE_PROXY (engine));
1257 return engine->prop_list;
1261 bus_engine_proxy_is_enabled (BusEngineProxy *engine)
1263 g_assert (BUS_IS_ENGINE_PROXY (engine));
1265 return engine->enabled;
1269 initable_init (GInitable *initable,
1270 GCancellable *cancellable,
1273 BusEngineProxy *engine = BUS_ENGINE_PROXY (initable);
1274 if (engine->desc == NULL) {
1275 *error = g_error_new (G_DBUS_ERROR,
1276 G_DBUS_ERROR_FAILED,
1281 return parent_initable_iface->init (initable,
1287 bus_engine_proxy_initable_iface_init (GInitableIface *initable_iface)
1289 initable_iface->init = initable_init;