Add Ctrl+space customization.
[platform/upstream/ibus.git] / bus / engineproxy.c
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.
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include "engineproxy.h"
24
25 #include "global.h"
26 #include "ibusimpl.h"
27 #include "marshalers.h"
28 #include "types.h"
29
30 struct _BusEngineProxy {
31     IBusProxy parent;
32
33     /* instance members */
34     /* TRUE if the engine has a focus (local copy of the engine's status.) */
35     gboolean has_focus;
36     /* TRUE if the engine is enabled (local copy of the engine's status.) */
37     gboolean enabled;
38     /* A set of capabilities the current client supports (local copy of the engine's flag.) */
39     guint capabilities;
40     /* The current cursor location that are sent to the engine. */
41     gint x;
42     gint y;
43     gint w;
44     gint h;
45
46     /* an engine desc used to create the proxy. */
47     IBusEngineDesc *desc;
48
49     /* a key mapping for the engine that converts keycode into keysym. the mapping is used only when use_sys_layout is FALSE. */
50     IBusKeymap     *keymap;
51     /* private member */
52
53     /* cached surrounding text (see also IBusEnginePrivate and
54        IBusInputContextPrivate) */
55     IBusText *surrounding_text;
56     guint     surrounding_cursor_pos;
57     guint     selection_anchor_pos;
58
59     /* cached properties */
60     IBusPropList *prop_list;
61 };
62
63 struct _BusEngineProxyClass {
64     IBusProxyClass parent;
65     /* class members */
66     void (* register_properties) (BusEngineProxy   *engine,
67                                   IBusPropList     *prop_list);
68     void (* update_property) (BusEngineProxy       *engine,
69                               IBusProperty         *prop);
70 };
71
72 enum {
73     COMMIT_TEXT,
74     FORWARD_KEY_EVENT,
75     DELETE_SURROUNDING_TEXT,
76     REQUIRE_SURROUNDING_TEXT,
77     UPDATE_PREEDIT_TEXT,
78     SHOW_PREEDIT_TEXT,
79     HIDE_PREEDIT_TEXT,
80     UPDATE_AUXILIARY_TEXT,
81     SHOW_AUXILIARY_TEXT,
82     HIDE_AUXILIARY_TEXT,
83     UPDATE_LOOKUP_TABLE,
84     SHOW_LOOKUP_TABLE,
85     HIDE_LOOKUP_TABLE,
86     PAGE_UP_LOOKUP_TABLE,
87     PAGE_DOWN_LOOKUP_TABLE,
88     CURSOR_UP_LOOKUP_TABLE,
89     CURSOR_DOWN_LOOKUP_TABLE,
90     REGISTER_PROPERTIES,
91     UPDATE_PROPERTY,
92     LAST_SIGNAL,
93 };
94
95 enum {
96     PROP_0 = 0,
97     PROP_ENGINE_DESC,
98 };
99
100 static guint    engine_signals[LAST_SIGNAL] = { 0 };
101
102 static IBusText *text_empty = NULL;
103 static IBusPropList *prop_list_empty = NULL;
104
105 /* functions prototype */
106 static void     bus_engine_proxy_set_property   (BusEngineProxy      *engine,
107                                                  guint                prop_id,
108                                                  const GValue        *value,
109                                                  GParamSpec          *pspec);
110 static void     bus_engine_proxy_get_property   (BusEngineProxy      *engine,
111                                                  guint                prop_id,
112                                                  GValue              *value,
113                                                  GParamSpec          *pspec);
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,
119                                                  IBusProperty        *prop);
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);
127
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)
130                         );
131
132 static GInitableIface *parent_initable_iface = NULL;
133
134 static void
135 bus_engine_proxy_class_init (BusEngineProxyClass *class)
136 {
137     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
138
139     gobject_class->set_property = (GObjectSetPropertyFunc)bus_engine_proxy_set_property;
140     gobject_class->get_property = (GObjectGetPropertyFunc)bus_engine_proxy_get_property;
141
142     class->register_properties = bus_engine_proxy_real_register_properties;
143     class->update_property = bus_engine_proxy_real_update_property;
144
145     IBUS_PROXY_CLASS (class)->destroy = bus_engine_proxy_real_destroy;
146     G_DBUS_PROXY_CLASS (class)->g_signal = bus_engine_proxy_g_signal;
147
148     parent_initable_iface =
149             (GInitableIface *)g_type_interface_peek (bus_engine_proxy_parent_class, G_TYPE_INITABLE);
150
151     /* install properties */
152     g_object_class_install_property (gobject_class,
153                     PROP_ENGINE_DESC,
154                     g_param_spec_object ("desc",
155                         "desc",
156                         "desc",
157                         IBUS_TYPE_ENGINE_DESC,
158                         G_PARAM_READWRITE |
159                         G_PARAM_CONSTRUCT_ONLY |
160                         G_PARAM_STATIC_NAME |
161                         G_PARAM_STATIC_BLURB |
162                         G_PARAM_STATIC_NICK
163                         ));
164
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),
169             G_SIGNAL_RUN_LAST,
170             0,
171             NULL, NULL,
172             bus_marshal_VOID__OBJECT,
173             G_TYPE_NONE,
174             1,
175             IBUS_TYPE_TEXT);
176
177     engine_signals[FORWARD_KEY_EVENT] =
178         g_signal_new (I_("forward-key-event"),
179             G_TYPE_FROM_CLASS (class),
180             G_SIGNAL_RUN_LAST,
181             0,
182             NULL, NULL,
183             bus_marshal_VOID__UINT_UINT_UINT,
184             G_TYPE_NONE,
185             3,
186             G_TYPE_UINT,
187             G_TYPE_UINT,
188             G_TYPE_UINT);
189
190     engine_signals[DELETE_SURROUNDING_TEXT] =
191         g_signal_new (I_("delete-surrounding-text"),
192             G_TYPE_FROM_CLASS (class),
193             G_SIGNAL_RUN_LAST,
194             0,
195             NULL, NULL,
196             bus_marshal_VOID__INT_UINT,
197             G_TYPE_NONE,
198             2,
199             G_TYPE_INT,
200             G_TYPE_UINT);
201
202     engine_signals[REQUIRE_SURROUNDING_TEXT] =
203         g_signal_new (I_("require-surrounding-text"),
204             G_TYPE_FROM_CLASS (class),
205             G_SIGNAL_RUN_LAST,
206             0,
207             NULL, NULL,
208             bus_marshal_VOID__VOID,
209             G_TYPE_NONE,
210             0);
211
212     engine_signals[UPDATE_PREEDIT_TEXT] =
213         g_signal_new (I_("update-preedit-text"),
214             G_TYPE_FROM_CLASS (class),
215             G_SIGNAL_RUN_LAST,
216             0,
217             NULL, NULL,
218             bus_marshal_VOID__OBJECT_UINT_BOOLEAN_UINT,
219             G_TYPE_NONE,
220             4,
221             IBUS_TYPE_TEXT,
222             G_TYPE_UINT,
223             G_TYPE_BOOLEAN,
224             G_TYPE_UINT);
225
226     engine_signals[SHOW_PREEDIT_TEXT] =
227         g_signal_new (I_("show-preedit-text"),
228             G_TYPE_FROM_CLASS (class),
229             G_SIGNAL_RUN_LAST,
230             0,
231             NULL, NULL,
232             bus_marshal_VOID__VOID,
233             G_TYPE_NONE,
234             0);
235
236     engine_signals[HIDE_PREEDIT_TEXT] =
237         g_signal_new (I_("hide-preedit-text"),
238             G_TYPE_FROM_CLASS (class),
239             G_SIGNAL_RUN_LAST,
240             0,
241             NULL, NULL,
242             bus_marshal_VOID__VOID,
243             G_TYPE_NONE,
244             0);
245
246     engine_signals[UPDATE_AUXILIARY_TEXT] =
247         g_signal_new (I_("update-auxiliary-text"),
248             G_TYPE_FROM_CLASS (class),
249             G_SIGNAL_RUN_LAST,
250             0,
251             NULL, NULL,
252             bus_marshal_VOID__OBJECT_BOOLEAN,
253             G_TYPE_NONE,
254             2,
255             IBUS_TYPE_TEXT,
256             G_TYPE_BOOLEAN);
257
258     engine_signals[SHOW_AUXILIARY_TEXT] =
259         g_signal_new (I_("show-auxiliary-text"),
260             G_TYPE_FROM_CLASS (class),
261             G_SIGNAL_RUN_LAST,
262             0,
263             NULL, NULL,
264             bus_marshal_VOID__VOID,
265             G_TYPE_NONE,
266             0);
267
268     engine_signals[HIDE_AUXILIARY_TEXT] =
269         g_signal_new (I_("hide-auxiliary-text"),
270             G_TYPE_FROM_CLASS (class),
271             G_SIGNAL_RUN_LAST,
272             0,
273             NULL, NULL,
274             bus_marshal_VOID__VOID,
275             G_TYPE_NONE,
276             0);
277
278     engine_signals[UPDATE_LOOKUP_TABLE] =
279         g_signal_new (I_("update-lookup-table"),
280             G_TYPE_FROM_CLASS (class),
281             G_SIGNAL_RUN_LAST,
282             0,
283             NULL, NULL,
284             bus_marshal_VOID__OBJECT_BOOLEAN,
285             G_TYPE_NONE,
286             2,
287             IBUS_TYPE_LOOKUP_TABLE,
288             G_TYPE_BOOLEAN);
289
290     engine_signals[SHOW_LOOKUP_TABLE] =
291         g_signal_new (I_("show-lookup-table"),
292             G_TYPE_FROM_CLASS (class),
293             G_SIGNAL_RUN_LAST,
294             0,
295             NULL, NULL,
296             bus_marshal_VOID__VOID,
297             G_TYPE_NONE,
298             0);
299
300     engine_signals[HIDE_LOOKUP_TABLE] =
301         g_signal_new (I_("hide-lookup-table"),
302             G_TYPE_FROM_CLASS (class),
303             G_SIGNAL_RUN_LAST,
304             0,
305             NULL, NULL,
306             bus_marshal_VOID__VOID,
307             G_TYPE_NONE,
308             0);
309
310     engine_signals[PAGE_UP_LOOKUP_TABLE] =
311         g_signal_new (I_("page-up-lookup-table"),
312             G_TYPE_FROM_CLASS (class),
313             G_SIGNAL_RUN_LAST,
314             0,
315             NULL, NULL,
316             bus_marshal_VOID__VOID,
317             G_TYPE_NONE,
318             0);
319
320     engine_signals[PAGE_DOWN_LOOKUP_TABLE] =
321         g_signal_new (I_("page-down-lookup-table"),
322             G_TYPE_FROM_CLASS (class),
323             G_SIGNAL_RUN_LAST,
324             0,
325             NULL, NULL,
326             bus_marshal_VOID__VOID,
327             G_TYPE_NONE,
328             0);
329
330     engine_signals[CURSOR_UP_LOOKUP_TABLE] =
331         g_signal_new (I_("cursor-up-lookup-table"),
332             G_TYPE_FROM_CLASS (class),
333             G_SIGNAL_RUN_LAST,
334             0,
335             NULL, NULL,
336             bus_marshal_VOID__VOID,
337             G_TYPE_NONE,
338             0);
339
340     engine_signals[CURSOR_DOWN_LOOKUP_TABLE] =
341         g_signal_new (I_("cursor-down-lookup-table"),
342             G_TYPE_FROM_CLASS (class),
343             G_SIGNAL_RUN_LAST,
344             0,
345             NULL, NULL,
346             bus_marshal_VOID__VOID,
347             G_TYPE_NONE,
348             0);
349
350     engine_signals[REGISTER_PROPERTIES] =
351         g_signal_new (I_("register-properties"),
352             G_TYPE_FROM_CLASS (class),
353             G_SIGNAL_RUN_LAST,
354             G_STRUCT_OFFSET (BusEngineProxyClass, register_properties),
355             NULL, NULL,
356             bus_marshal_VOID__OBJECT,
357             G_TYPE_NONE,
358             1,
359             IBUS_TYPE_PROP_LIST);
360
361     engine_signals[UPDATE_PROPERTY] =
362         g_signal_new (I_("update-property"),
363             G_TYPE_FROM_CLASS (class),
364             G_SIGNAL_RUN_LAST,
365             G_STRUCT_OFFSET (BusEngineProxyClass, update_property),
366             NULL, NULL,
367             bus_marshal_VOID__OBJECT,
368             G_TYPE_NONE,
369             1,
370             IBUS_TYPE_PROPERTY);
371
372     text_empty = ibus_text_new_from_static_string ("");
373     g_object_ref_sink (text_empty);
374
375     prop_list_empty = ibus_prop_list_new ();
376     g_object_ref_sink (prop_list_empty);
377 }
378
379 static void
380 bus_engine_proxy_init (BusEngineProxy *engine)
381 {
382     engine->surrounding_text = g_object_ref_sink (text_empty);
383     engine->prop_list = g_object_ref_sink (prop_list_empty);
384 }
385
386 static void
387 bus_engine_proxy_set_property (BusEngineProxy *engine,
388                                guint           prop_id,
389                                const GValue   *value,
390                                GParamSpec     *pspec)
391 {
392     switch (prop_id) {
393     case PROP_ENGINE_DESC:
394         g_assert (engine->desc == NULL);
395         engine->desc = g_value_dup_object (value);
396         break;
397     default:
398         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
399     }
400 }
401
402 static void
403 bus_engine_proxy_get_property (BusEngineProxy *engine,
404                                guint           prop_id,
405                                GValue         *value,
406                                GParamSpec     *pspec)
407 {
408     switch (prop_id) {
409     case PROP_ENGINE_DESC:
410         g_value_set_object (value, bus_engine_proxy_get_desc (engine));
411         break;
412     default:
413         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
414     }
415
416 }
417
418 static void
419 bus_engine_proxy_real_register_properties (BusEngineProxy *engine,
420                                            IBusPropList   *prop_list)
421 {
422     g_assert (IBUS_IS_PROP_LIST (prop_list));
423
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);
427 }
428
429 static void
430 bus_engine_proxy_real_update_property (BusEngineProxy *engine,
431                                        IBusProperty   *prop)
432 {
433     g_return_if_fail (prop);
434     if (engine->prop_list)
435         ibus_prop_list_update_property (engine->prop_list, prop);
436 }
437
438 static void
439 bus_engine_proxy_real_destroy (IBusProxy *proxy)
440 {
441     BusEngineProxy *engine = (BusEngineProxy *)proxy;
442
443     if (engine->desc) {
444         g_object_unref (engine->desc);
445         engine->desc = NULL;
446     }
447
448     if (engine->keymap) {
449         g_object_unref (engine->keymap);
450         engine->keymap = NULL;
451     }
452
453     if (engine->surrounding_text) {
454         g_object_unref (engine->surrounding_text);
455         engine->surrounding_text = NULL;
456     }
457
458     if (engine->prop_list) {
459         g_object_unref (engine->prop_list);
460         engine->prop_list = NULL;
461     }
462
463     IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy ((IBusProxy *)engine);
464 }
465
466 static void
467 _g_object_unref_if_floating (gpointer instance)
468 {
469     if (g_object_is_floating (instance))
470         g_object_unref (instance);
471 }
472
473 /**
474  * bus_engine_proxy_g_signal:
475  *
476  * Handle all D-Bus signals from the engine process. This function emits corresponding glib signal for the D-Bus signal.
477  */
478 static void
479 bus_engine_proxy_g_signal (GDBusProxy  *proxy,
480                            const gchar *sender_name,
481                            const gchar *signal_name,
482                            GVariant    *parameters)
483 {
484     BusEngineProxy *engine = (BusEngineProxy *)proxy;
485
486     /* The list of nullary D-Bus signals. */
487     static const struct {
488         const gchar *signal_name;
489         const guint  signal_id;
490     } signals [] = {
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 },
502     };
503
504     gint i;
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);
508             return;
509         }
510     }
511
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);
517
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);
523         return;
524     }
525
526     if (g_strcmp0 (signal_name, "ForwardKeyEvent") == 0) {
527         guint32 keyval = 0;
528         guint32 keycode = 0;
529         guint32 states = 0;
530         g_variant_get (parameters, "(uuu)", &keyval, &keycode, &states);
531
532         g_signal_emit (engine,
533                        engine_signals[FORWARD_KEY_EVENT],
534                        0,
535                        keyval,
536                        keycode,
537                        states);
538         return;
539     }
540
541     if (g_strcmp0 (signal_name, "DeleteSurroundingText") == 0) {
542         gint  offset_from_cursor = 0;
543         guint nchars = 0;
544         g_variant_get (parameters, "(iu)", &offset_from_cursor, &nchars);
545
546         g_signal_emit (engine,
547                        engine_signals[DELETE_SURROUNDING_TEXT],
548                        0, offset_from_cursor, nchars);
549         return;
550     }
551
552     if (g_strcmp0 (signal_name, "UpdatePreeditText") == 0) {
553         GVariant *arg0 = NULL;
554         guint cursor_pos = 0;
555         gboolean visible = FALSE;
556         guint mode = 0;
557
558         g_variant_get (parameters, "(vubu)", &arg0, &cursor_pos, &visible, &mode);
559         g_return_if_fail (arg0 != NULL);
560
561         IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
562         g_variant_unref (arg0);
563         g_return_if_fail (text != NULL);
564
565         g_signal_emit (engine,
566                        engine_signals[UPDATE_PREEDIT_TEXT],
567                        0, text, cursor_pos, visible, mode);
568
569         _g_object_unref_if_floating (text);
570         return;
571     }
572
573     if (g_strcmp0 (signal_name, "UpdateAuxiliaryText") == 0) {
574         GVariant *arg0 = NULL;
575         gboolean visible = FALSE;
576
577         g_variant_get (parameters, "(vb)", &arg0, &visible);
578         g_return_if_fail (arg0 != NULL);
579
580         IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
581         g_variant_unref (arg0);
582         g_return_if_fail (text != NULL);
583
584         g_signal_emit (engine, engine_signals[UPDATE_AUXILIARY_TEXT], 0, text, visible);
585         _g_object_unref_if_floating (text);
586         return;
587     }
588
589     if (g_strcmp0 (signal_name, "UpdateLookupTable") == 0) {
590         GVariant *arg0 = NULL;
591         gboolean visible = FALSE;
592
593         g_variant_get (parameters, "(vb)", &arg0, &visible);
594         g_return_if_fail (arg0 != NULL);
595
596         IBusLookupTable *table = IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (arg0));
597         g_variant_unref (arg0);
598         g_return_if_fail (table != NULL);
599
600         g_signal_emit (engine, engine_signals[UPDATE_LOOKUP_TABLE], 0, table, visible);
601         _g_object_unref_if_floating (table);
602         return;
603     }
604
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);
609
610         IBusPropList *prop_list = IBUS_PROP_LIST (ibus_serializable_deserialize (arg0));
611         g_variant_unref (arg0);
612         g_return_if_fail (prop_list != NULL);
613
614         g_signal_emit (engine, engine_signals[REGISTER_PROPERTIES], 0, prop_list);
615         _g_object_unref_if_floating (prop_list);
616         return;
617     }
618
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);
623
624         IBusProperty *prop = IBUS_PROPERTY (ibus_serializable_deserialize (arg0));
625         g_variant_unref (arg0);
626         g_return_if_fail (prop != NULL);
627
628         g_signal_emit (engine, engine_signals[UPDATE_PROPERTY], 0, prop);
629         _g_object_unref_if_floating (prop);
630         return;
631     }
632
633     g_return_if_reached ();
634 }
635
636 static BusEngineProxy *
637 bus_engine_proxy_new_internal (const gchar     *path,
638                                IBusEngineDesc  *desc,
639                                GDBusConnection *connection)
640 {
641     g_assert (path);
642     g_assert (IBUS_IS_ENGINE_DESC (desc));
643     g_assert (G_IS_DBUS_CONNECTION (connection));
644
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,
649                                            NULL,
650                                            NULL,
651                                            "desc",              desc,
652                                            "g-connection",      connection,
653                                            "g-interface-name",  IBUS_INTERFACE_ENGINE,
654                                            "g-object-path",     path,
655                                            "g-default-timeout", g_gdbus_timeout,
656                                            "g-flags",           flags,
657                                            NULL);
658     const gchar *layout = ibus_engine_desc_get_layout (desc);
659     if (layout != NULL && layout[0] != '\0') {
660         engine->keymap = ibus_keymap_get (layout);
661     }
662     return engine;
663 }
664
665 typedef struct {
666     GSimpleAsyncResult *simple;
667     IBusEngineDesc  *desc;
668     BusComponent    *component;
669     BusFactoryProxy *factory;
670     GCancellable *cancellable;
671     gulong cancelled_handler_id;
672     guint handler_id;
673     guint timeout_id;
674     gint timeout;
675 } EngineProxyNewData;
676
677 static void
678 engine_proxy_new_data_free (EngineProxyNewData *data)
679 {
680     if (data->simple != NULL) {
681         g_object_unref (data->simple);
682     }
683
684     if (data->desc != NULL) {
685         g_object_unref (data->desc);
686     }
687
688     if (data->component != NULL) {
689         if (data->handler_id != 0) {
690             g_signal_handler_disconnect (data->component, data->handler_id);
691         }
692         g_object_unref (data->component);
693     }
694
695     if (data->factory != NULL) {
696         g_object_unref (data->factory);
697     }
698
699     if (data->timeout_id != 0) {
700         g_source_remove (data->timeout_id);
701     }
702
703     if (data->cancellable != NULL) {
704         if (data->cancelled_handler_id != 0) {
705             g_cancellable_disconnect (data->cancellable,
706                                       data->cancelled_handler_id);
707         }
708         g_object_unref (data->cancellable);
709     }
710
711     g_slice_free (EngineProxyNewData, data);
712 }
713
714 /**
715  * create_engine_ready_cb:
716  *
717  * A callback function to be called when bus_factory_proxy_create_engine finishes.
718  * Create an BusEngineProxy object and call the GAsyncReadyCallback.
719  */
720 static void
721 create_engine_ready_cb (BusFactoryProxy    *factory,
722                         GAsyncResult       *res,
723                         EngineProxyNewData *data)
724 {
725     g_return_if_fail (data->simple != NULL);
726
727     GError *error = NULL;
728     gchar *path = bus_factory_proxy_create_engine_finish (factory,
729                                                           res,
730                                                           &error);
731     if (path == NULL) {
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);
735         return;
736     }
737
738     BusEngineProxy *engine =
739             bus_engine_proxy_new_internal (path,
740                                            data->desc,
741                                            g_dbus_proxy_get_connection ((GDBusProxy *)data->factory));
742     g_free (path);
743
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);
747
748     engine_proxy_new_data_free (data);
749 }
750
751 /**
752  * notify_factory_cb:
753  *
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.
756  */
757 static void
758 notify_factory_cb (BusComponent       *component,
759                    GParamSpec         *spec,
760                    EngineProxyNewData *data)
761 {
762     data->factory = bus_component_get_factory (data->component);
763
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;
770         }
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;
775         }
776
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;
787         }
788
789         /* Create engine from factory. */
790         bus_factory_proxy_create_engine (data->factory,
791                                          data->desc,
792                                          data->timeout,
793                                          data->cancellable,
794                                          (GAsyncReadyCallback) create_engine_ready_cb,
795                                          data);
796     }
797     /* If factory is NULL, we will continue wait for
798      * factory notify signal or timeout */
799 }
800
801 /**
802  * timeout_cb:
803  *
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.
806  */
807 static gboolean
808 timeout_cb (EngineProxyNewData *data)
809 {
810     g_simple_async_result_set_error (data->simple,
811                                      G_DBUS_ERROR,
812                                      G_DBUS_ERROR_FAILED,
813                                      "Timeout was reached");
814     g_simple_async_result_complete_in_idle (data->simple);
815
816     engine_proxy_new_data_free (data);
817
818     return FALSE;
819 }
820
821 /**
822  * cancelled_cb:
823  *
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.
827  */
828 static gboolean
829 cancelled_idle_cb (EngineProxyNewData *data)
830 {
831     g_simple_async_result_set_error (data->simple,
832                                      G_DBUS_ERROR,
833                                      G_DBUS_ERROR_FAILED,
834                                      "Operation was cancelled");
835     g_simple_async_result_complete_in_idle (data->simple);
836
837     engine_proxy_new_data_free (data);
838
839     return FALSE;
840 }
841
842 static void
843 cancelled_cb (GCancellable       *cancellable,
844               EngineProxyNewData *data)
845 {
846     /* Cancel the bus_engine_proxy_new() in idle to avoid deadlock.
847      * And use HIGH priority to avoid timeout event happening before
848      * idle callback. */
849     g_idle_add_full (G_PRIORITY_HIGH,
850                     (GSourceFunc) cancelled_idle_cb,
851                     data, NULL);
852 }
853
854 void
855 bus_engine_proxy_new (IBusEngineDesc      *desc,
856                       gint                 timeout,
857                       GCancellable        *cancellable,
858                       GAsyncReadyCallback  callback,
859                       gpointer             user_data)
860 {
861     g_assert (IBUS_IS_ENGINE_DESC (desc));
862     g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
863     g_assert (callback);
864
865     GSimpleAsyncResult *simple =
866         g_simple_async_result_new (NULL,
867                                    callback,
868                                    user_data,
869                                    bus_engine_proxy_new);
870
871     if (g_cancellable_is_cancelled (cancellable)) {
872         g_simple_async_result_set_error (simple,
873                                          G_DBUS_ERROR,
874                                          G_DBUS_ERROR_FAILED,
875                                          "Operation was cancelled");
876         g_simple_async_result_complete_in_idle (simple);
877         g_object_unref (simple);
878         return;
879     }
880
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;
887
888     data->factory = bus_component_get_factory (data->component);
889
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,
895                                              "notify::factory",
896                                              G_CALLBACK (notify_factory_cb),
897                                              data);
898         data->timeout_id = g_timeout_add (timeout,
899                                           (GSourceFunc) timeout_cb,
900                                           data);
901         if (cancellable) {
902             data->cancellable = (GCancellable *) g_object_ref (cancellable);
903             data->cancelled_handler_id = g_cancellable_connect (cancellable,
904                                                                 (GCallback) cancelled_cb,
905                                                                 data,
906                                                                 NULL);
907         }
908         bus_component_start (data->component, g_verbose);
909     }
910     else {
911         /* The factory is ready. We'll create the engine proxy directly. */
912         g_object_ref (data->factory);
913
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,
919                                          data->desc,
920                                          timeout,
921                                          cancellable,
922                                          (GAsyncReadyCallback) create_engine_ready_cb,
923                                          data);
924     }
925 }
926
927 BusEngineProxy *
928 bus_engine_proxy_new_finish (GAsyncResult   *res,
929                              GError       **error)
930 {
931     GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
932
933     g_assert (error == NULL || *error == NULL);
934     g_assert (g_simple_async_result_get_source_tag (simple) == bus_engine_proxy_new);
935
936     if (g_simple_async_result_propagate_error (simple, error))
937         return NULL;
938
939     return (BusEngineProxy *) g_simple_async_result_get_op_res_gpointer(simple);
940 }
941
942 void
943 bus_engine_proxy_process_key_event (BusEngineProxy      *engine,
944                                     guint                keyval,
945                                     guint                keycode,
946                                     guint                state,
947                                     GAsyncReadyCallback  callback,
948                                     gpointer             user_data)
949 {
950     g_assert (BUS_IS_ENGINE_PROXY (engine));
951
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;
955         if (keymap == NULL)
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) {
960                 keyval = t;
961             }
962         }
963     }
964
965     g_dbus_proxy_call ((GDBusProxy *)engine,
966                        "ProcessKeyEvent",
967                        g_variant_new ("(uuu)", keyval, keycode, state),
968                        G_DBUS_CALL_FLAGS_NONE,
969                        -1,
970                        NULL,
971                        callback,
972                        user_data);
973 }
974
975 void
976 bus_engine_proxy_set_cursor_location (BusEngineProxy *engine,
977                                       gint            x,
978                                       gint            y,
979                                       gint            w,
980                                       gint            h)
981 {
982     g_assert (BUS_IS_ENGINE_PROXY (engine));
983
984     if (engine->x != x || engine->y != y || engine->w != w || engine->h != h) {
985         engine->x = x;
986         engine->y = y;
987         engine->w = w;
988         engine->h = h;
989         g_dbus_proxy_call ((GDBusProxy *)engine,
990                            "SetCursorLocation",
991                            g_variant_new ("(iiii)", x, y, w, h),
992                            G_DBUS_CALL_FLAGS_NONE,
993                            -1,
994                            NULL,
995                            NULL,
996                            NULL);
997     }
998 }
999
1000 void
1001 bus_engine_proxy_process_hand_writing_event
1002                                   (BusEngineProxy        *engine,
1003                                    GVariant              *coordinates)
1004 {
1005     g_assert (BUS_IS_ENGINE_PROXY (engine));
1006
1007     g_dbus_proxy_call ((GDBusProxy *)engine,
1008                        "ProcessHandWritingEvent",
1009                        coordinates,
1010                        G_DBUS_CALL_FLAGS_NONE,
1011                        -1,
1012                        NULL,
1013                        NULL,
1014                        NULL);
1015 }
1016
1017 void
1018 bus_engine_proxy_cancel_hand_writing
1019                                   (BusEngineProxy        *engine,
1020                                    guint                  n_strokes)
1021 {
1022     g_assert (BUS_IS_ENGINE_PROXY (engine));
1023
1024     g_dbus_proxy_call ((GDBusProxy *)engine,
1025                        "CancelHandWriting",
1026                        g_variant_new ("(u)", n_strokes),
1027                        G_DBUS_CALL_FLAGS_NONE,
1028                        -1,
1029                        NULL,
1030                        NULL,
1031                        NULL);
1032 }
1033
1034 void
1035 bus_engine_proxy_set_capabilities (BusEngineProxy *engine,
1036                                    guint           caps)
1037 {
1038     g_assert (BUS_IS_ENGINE_PROXY (engine));
1039
1040     if (engine->capabilities != caps) {
1041         engine->capabilities = caps;
1042         g_dbus_proxy_call ((GDBusProxy *)engine,
1043                            "SetCapabilities",
1044                            g_variant_new ("(u)", caps),
1045                            G_DBUS_CALL_FLAGS_NONE,
1046                            -1,
1047                            NULL,
1048                            NULL,
1049                            NULL);
1050     }
1051 }
1052
1053 void
1054 bus_engine_proxy_property_activate (BusEngineProxy *engine,
1055                                     const gchar    *prop_name,
1056                                     guint           prop_state)
1057 {
1058     g_assert (BUS_IS_ENGINE_PROXY (engine));
1059     g_assert (prop_name != NULL);
1060
1061     g_dbus_proxy_call ((GDBusProxy *)engine,
1062                        "PropertyActivate",
1063                        g_variant_new ("(su)", prop_name, prop_state),
1064                        G_DBUS_CALL_FLAGS_NONE,
1065                        -1,
1066                        NULL,
1067                        NULL,
1068                        NULL);
1069 }
1070
1071 void
1072 bus_engine_proxy_property_show (BusEngineProxy *engine,
1073                                 const gchar    *prop_name)
1074 {
1075     g_assert (BUS_IS_ENGINE_PROXY (engine));
1076     g_assert (prop_name != NULL);
1077
1078     g_dbus_proxy_call ((GDBusProxy *)engine,
1079                        "PropertyShow",
1080                        g_variant_new ("(s)", prop_name),
1081                        G_DBUS_CALL_FLAGS_NONE,
1082                        -1,
1083                        NULL,
1084                        NULL,
1085                        NULL);
1086 }
1087
1088 void bus_engine_proxy_property_hide (BusEngineProxy *engine,
1089                                      const gchar    *prop_name)
1090 {
1091     g_assert (BUS_IS_ENGINE_PROXY (engine));
1092     g_assert (prop_name != NULL);
1093
1094     g_dbus_proxy_call ((GDBusProxy *)engine,
1095                        "PropertyHide",
1096                        g_variant_new ("(s)", prop_name),
1097                        G_DBUS_CALL_FLAGS_NONE,
1098                        -1,
1099                        NULL,
1100                        NULL,
1101                        NULL);
1102 }
1103
1104 void bus_engine_proxy_set_surrounding_text (BusEngineProxy *engine,
1105                                             IBusText       *text,
1106                                             guint           cursor_pos,
1107                                             guint           anchor_pos)
1108 {
1109     g_assert (BUS_IS_ENGINE_PROXY (engine));
1110     g_assert (text != NULL);
1111
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;
1122
1123         g_dbus_proxy_call ((GDBusProxy *)engine,
1124                            "SetSurroundingText",
1125                            g_variant_new ("(vuu)",
1126                                           variant,
1127                                           cursor_pos,
1128                                           anchor_pos),
1129                            G_DBUS_CALL_FLAGS_NONE,
1130                            -1,
1131                            NULL,
1132                            NULL,
1133                            NULL);
1134     }
1135 }
1136
1137 /* a macro to generate a function to call a nullary D-Bus method. */
1138 #define DEFINE_FUNCTION(Name, name)                         \
1139     void                                                    \
1140     bus_engine_proxy_##name (BusEngineProxy *engine)        \
1141     {                                                       \
1142         g_assert (BUS_IS_ENGINE_PROXY (engine));            \
1143         g_dbus_proxy_call ((GDBusProxy *)engine,            \
1144                            #Name,                           \
1145                            NULL,                            \
1146                            G_DBUS_CALL_FLAGS_NONE,          \
1147                            -1, NULL, NULL, NULL);           \
1148     }
1149
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)
1155
1156 #undef DEFINE_FUNCTION
1157
1158 void
1159 bus_engine_proxy_focus_in (BusEngineProxy *engine)
1160 {
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,
1165                            "FocusIn",
1166                            NULL,
1167                            G_DBUS_CALL_FLAGS_NONE,
1168                            -1,
1169                            NULL,
1170                            NULL,
1171                            NULL);
1172     }
1173 }
1174
1175 void
1176 bus_engine_proxy_focus_out (BusEngineProxy *engine)
1177 {
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,
1182                            "FocusOut",
1183                            NULL,
1184                            G_DBUS_CALL_FLAGS_NONE,
1185                            -1,
1186                            NULL,
1187                            NULL,
1188                            NULL);
1189     }
1190 }
1191
1192 void
1193 bus_engine_proxy_enable (BusEngineProxy *engine)
1194 {
1195     g_assert (BUS_IS_ENGINE_PROXY (engine));
1196     if (!engine->enabled) {
1197         engine->enabled = TRUE;
1198         g_dbus_proxy_call ((GDBusProxy *)engine,
1199                            "Enable",
1200                            NULL,
1201                            G_DBUS_CALL_FLAGS_NONE,
1202                            -1,
1203                            NULL,
1204                            NULL,
1205                            NULL);
1206     }
1207 }
1208
1209 void
1210 bus_engine_proxy_disable (BusEngineProxy *engine)
1211 {
1212     g_assert (BUS_IS_ENGINE_PROXY (engine));
1213     if (engine->enabled) {
1214         engine->enabled = FALSE;
1215         g_dbus_proxy_call ((GDBusProxy *)engine,
1216                            "Disable",
1217                            NULL,
1218                            G_DBUS_CALL_FLAGS_NONE,
1219                            -1,
1220                            NULL,
1221                            NULL,
1222                            NULL);
1223     }
1224 }
1225
1226 void
1227 bus_engine_proxy_candidate_clicked (BusEngineProxy *engine,
1228                                     guint           index,
1229                                     guint           button,
1230                                     guint           state)
1231 {
1232     g_assert (BUS_IS_ENGINE_PROXY (engine));
1233
1234     g_dbus_proxy_call ((GDBusProxy *)engine,
1235                        "CandidateClicked",
1236                        g_variant_new ("(uuu)", index, button, state),
1237                        G_DBUS_CALL_FLAGS_NONE,
1238                        -1,
1239                        NULL,
1240                        NULL,
1241                        NULL);
1242 }
1243
1244 IBusEngineDesc *
1245 bus_engine_proxy_get_desc (BusEngineProxy *engine)
1246 {
1247     g_assert (BUS_IS_ENGINE_PROXY (engine));
1248
1249     return engine->desc;
1250 }
1251
1252 IBusPropList *
1253 bus_engine_proxy_get_properties (BusEngineProxy *engine)
1254 {
1255     g_assert (BUS_IS_ENGINE_PROXY (engine));
1256
1257     return engine->prop_list;
1258 }
1259
1260 gboolean
1261 bus_engine_proxy_is_enabled (BusEngineProxy *engine)
1262 {
1263     g_assert (BUS_IS_ENGINE_PROXY (engine));
1264
1265     return engine->enabled;
1266 }
1267
1268 static gboolean
1269 initable_init (GInitable     *initable,
1270                GCancellable  *cancellable,
1271                GError       **error)
1272 {
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,
1277                               "Desc is NULL");
1278         return FALSE;
1279     }
1280
1281     return parent_initable_iface->init (initable,
1282                                         cancellable,
1283                                         error);
1284 }
1285
1286 static void
1287 bus_engine_proxy_initable_iface_init (GInitableIface *initable_iface)
1288 {
1289     initable_iface->init = initable_init;
1290 }