Avoid compiler error in ibus_engine_dbus_property_changed
[platform/upstream/ibus.git] / src / ibusengine.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-2013 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2013 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.1 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 Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
20  * USA
21  */
22 #include "ibusengine.h"
23 #include <stdarg.h>
24 #include <string.h>
25 #include "ibusmarshalers.h"
26 #include "ibusinternal.h"
27 #include "ibusshare.h"
28
29 #define IBUS_ENGINE_GET_PRIVATE(o)  \
30    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE, IBusEnginePrivate))
31
32 enum {
33     PROCESS_KEY_EVENT,
34     FOCUS_IN,
35     FOCUS_OUT,
36     RESET,
37     ENABLE,
38     DISABLE,
39     SET_CURSOR_LOCATION,
40     SET_CAPABILITIES,
41     PAGE_UP,
42     PAGE_DOWN,
43     CURSOR_UP,
44     CURSOR_DOWN,
45     PROPERTY_ACTIVATE,
46     PROPERTY_SHOW,
47     PROPERTY_HIDE,
48     CANDIDATE_CLICKED,
49     SET_SURROUNDING_TEXT,
50     PROCESS_HAND_WRITING_EVENT,
51     CANCEL_HAND_WRITING,
52     SET_CONTENT_TYPE,
53     LAST_SIGNAL,
54 };
55
56 enum {
57     PROP_0,
58     PROP_ENGINE_NAME,
59 };
60
61
62 /* IBusEnginePriv */
63 struct _IBusEnginePrivate {
64     gchar *engine_name;
65     GDBusConnection *connection;
66
67     /* cached surrounding text (see also IBusInputContextPrivate and
68        BusEngineProxy) */
69     IBusText *surrounding_text;
70     guint surrounding_cursor_pos;
71     guint selection_anchor_pos;
72
73     /* cached content-type */
74     guint content_purpose;
75     guint content_hints;
76 };
77
78 static guint            engine_signals[LAST_SIGNAL] = { 0 };
79
80 static IBusText *text_empty = NULL;
81
82 /* functions prototype */
83 static void      ibus_engine_destroy         (IBusEngine         *engine);
84 static void      ibus_engine_set_property    (IBusEngine         *engine,
85                                               guint               prop_id,
86                                               const GValue       *value,
87                                               GParamSpec         *pspec);
88 static void      ibus_engine_get_property    (IBusEngine         *engine,
89                                               guint               prop_id,
90                                               GValue             *value,
91                                               GParamSpec         *pspec);
92 static void      ibus_engine_service_method_call
93                                               (IBusService        *service,
94                                                GDBusConnection    *connection,
95                                                const gchar        *sender,
96                                                const gchar        *object_path,
97                                                const gchar        *interface_name,
98                                                const gchar        *method_name,
99                                                GVariant           *parameters,
100                                                GDBusMethodInvocation
101                                                                   *invocation);
102 static GVariant *ibus_engine_service_get_property
103                                              (IBusService        *service,
104                                               GDBusConnection    *connection,
105                                               const gchar        *sender,
106                                               const gchar        *object_path,
107                                               const gchar        *interface_name,
108                                               const gchar        *property_name,
109                                               GError            **error);
110 static gboolean  ibus_engine_service_set_property
111                                              (IBusService        *service,
112                                               GDBusConnection    *connection,
113                                               const gchar        *sender,
114                                               const gchar        *object_path,
115                                               const gchar        *interface_name,
116                                               const gchar        *property_name,
117                                               GVariant           *value,
118                                               GError            **error);
119 static gboolean  ibus_engine_process_key_event
120                                              (IBusEngine         *engine,
121                                               guint               keyval,
122                                               guint               keycode,
123                                               guint               state);
124 static void      ibus_engine_focus_in        (IBusEngine         *engine);
125 static void      ibus_engine_focus_out       (IBusEngine         *engine);
126 static void      ibus_engine_reset           (IBusEngine         *engine);
127 static void      ibus_engine_enable          (IBusEngine         *engine);
128 static void      ibus_engine_disable         (IBusEngine         *engine);
129 static void      ibus_engine_set_cursor_location
130                                              (IBusEngine         *engine,
131                                               gint                x,
132                                               gint                y,
133                                               gint                w,
134                                               gint                h);
135 static void      ibus_engine_set_capabilities
136                                              (IBusEngine         *engine,
137                                               guint               caps);
138 static void      ibus_engine_page_up         (IBusEngine         *engine);
139 static void      ibus_engine_page_down       (IBusEngine         *engine);
140 static void      ibus_engine_cursor_up       (IBusEngine         *engine);
141 static void      ibus_engine_cursor_down     (IBusEngine         *engine);
142 static void      ibus_engine_candidate_clicked
143                                              (IBusEngine         *engine,
144                                               guint               index,
145                                               guint               button,
146                                               guint               state);
147 static void      ibus_engine_property_activate
148                                              (IBusEngine         *engine,
149                                               const gchar        *prop_name,
150                                               guint               prop_state);
151 static void      ibus_engine_property_show   (IBusEngine         *engine,
152                                               const gchar        *prop_name);
153 static void      ibus_engine_property_hide   (IBusEngine         *engine,
154                                               const gchar        *prop_name);
155 static void      ibus_engine_set_surrounding_text
156                                             (IBusEngine         *engine,
157                                              IBusText           *text,
158                                              guint               cursor_pos,
159                                              guint               anchor_pos);
160 static void      ibus_engine_process_hand_writing_event
161                                              (IBusEngine         *engine,
162                                               const gdouble      *coordinates,
163                                               guint               coordinates_len);
164 static void      ibus_engine_cancel_hand_writing
165                                              (IBusEngine         *engine,
166                                               guint               n_strokes);
167 static void      ibus_engine_set_content_type
168                                              (IBusEngine         *engine,
169                                               guint               purpose,
170                                               guint               hints);
171 static void      ibus_engine_emit_signal     (IBusEngine         *engine,
172                                               const gchar        *signal_name,
173                                               GVariant           *parameters);
174 static void      ibus_engine_dbus_property_changed
175                                              (IBusEngine         *engine,
176                                               const gchar        *property_name,
177                                               GVariant           *value);
178
179
180 G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
181
182 static const gchar introspection_xml[] =
183     "<node>"
184     "  <interface name='org.freedesktop.IBus.Engine'>"
185     /* FIXME methods */
186     "    <method name='ProcessKeyEvent'>"
187     "      <arg direction='in'  type='u' name='keyval' />"
188     "      <arg direction='in'  type='u' name='keycode' />"
189     "      <arg direction='in'  type='u' name='state' />"
190     "      <arg direction='out' type='b' />"
191     "    </method>"
192     "    <method name='SetCursorLocation'>"
193     "      <arg direction='in'  type='i' name='x' />"
194     "      <arg direction='in'  type='i' name='y' />"
195     "      <arg direction='in'  type='i' name='w' />"
196     "      <arg direction='in'  type='i' name='h' />"
197     "    </method>"
198     "    <method name='ProcessHandWritingEvent'>"
199     "      <arg direction='in'  type='ad' name='coordinates' />"
200     "    </method>"
201     "    <method name='CancelHandWriting'>"
202     "      <arg direction='in'  type='u' name='n_strokes' />"
203     "    </method>"
204     "    <method name='SetCapabilities'>"
205     "      <arg direction='in'  type='u' name='caps' />"
206     "    </method>"
207     "    <method name='PropertyActivate'>"
208     "      <arg direction='in'  type='s' name='name' />"
209     "      <arg direction='in'  type='u' name='state' />"
210     "    </method>"
211     "    <method name='PropertyShow'>"
212     "      <arg direction='in'  type='s' name='name' />"
213     "    </method>"
214     "    <method name='PropertyHide'>"
215     "      <arg direction='in'  type='s' name='name' />"
216     "    </method>"
217     "    <method name='CandidateClicked'>"
218     "      <arg direction='in'  type='u' name='index' />"
219     "      <arg direction='in'  type='u' name='button' />"
220     "      <arg direction='in'  type='u' name='state' />"
221     "    </method>"
222     "    <method name='FocusIn' />"
223     "    <method name='FocusOut' />"
224     "    <method name='Reset' />"
225     "    <method name='Enable' />"
226     "    <method name='Disable' />"
227     "    <method name='PageUp' />"
228     "    <method name='PageDown' />"
229     "    <method name='CursorUp' />"
230     "    <method name='CursorDown' />"
231     "    <method name='SetSurroundingText'>"
232     "      <arg direction='in'  type='v' name='text' />"
233     "      <arg direction='in'  type='u' name='cursor_pos' />"
234     "      <arg direction='in'  type='u' name='anchor_pos' />"
235     "    </method>"
236     /* FIXME signals */
237     "    <signal name='CommitText'>"
238     "      <arg type='v' name='text' />"
239     "    </signal>"
240     "    <signal name='UpdatePreeditText'>"
241     "      <arg type='v' name='text' />"
242     "      <arg type='u' name='cursor_pos' />"
243     "      <arg type='b' name='visible' />"
244     "      <arg type='u' name='mode' />"
245     "    </signal>"
246     "    <signal name='UpdateAuxiliaryText'>"
247     "      <arg type='v' name='text' />"
248     "      <arg type='b' name='visible' />"
249     "    </signal>"
250     "    <signal name='UpdateLookupTable'>"
251     "      <arg type='v' name='table' />"
252     "      <arg type='b' name='visible' />"
253     "    </signal>"
254     "    <signal name='RegisterProperties'>"
255     "      <arg type='v' name='props' />"
256     "    </signal>"
257     "    <signal name='UpdateProperty'>"
258     "      <arg type='v' name='prop' />"
259     "    </signal>"
260     "    <signal name='ForwardKeyEvent'>"
261     "      <arg type='u' name='keyval' />"
262     "      <arg type='u' name='keycode' />"
263     "      <arg type='u' name='state' />"
264     "    </signal>"
265     /* FIXME properties */
266     "    <property name='ContentType' type='(uu)' access='write' />"
267     "  </interface>"
268     "</node>";
269
270 static void
271 ibus_engine_class_init (IBusEngineClass *class)
272 {
273     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
274     IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
275
276     gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
277     gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
278
279     ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
280
281     IBUS_SERVICE_CLASS (class)->service_method_call  = ibus_engine_service_method_call;
282     IBUS_SERVICE_CLASS (class)->service_get_property = ibus_engine_service_get_property;
283     IBUS_SERVICE_CLASS (class)->service_set_property = ibus_engine_service_set_property;
284
285     ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
286
287     class->process_key_event = ibus_engine_process_key_event;
288     class->focus_in     = ibus_engine_focus_in;
289     class->focus_out    = ibus_engine_focus_out;
290     class->reset        = ibus_engine_reset;
291     class->enable       = ibus_engine_enable;
292     class->disable      = ibus_engine_disable;
293     class->page_up      = ibus_engine_page_up;
294     class->page_down    = ibus_engine_page_down;
295     class->cursor_up    = ibus_engine_cursor_up;
296     class->cursor_down  = ibus_engine_cursor_down;
297     class->candidate_clicked    = ibus_engine_candidate_clicked;
298     class->property_activate    = ibus_engine_property_activate;
299     class->property_show        = ibus_engine_property_show;
300     class->property_hide        = ibus_engine_property_hide;
301     class->set_cursor_location  = ibus_engine_set_cursor_location;
302     class->set_capabilities     = ibus_engine_set_capabilities;
303     class->set_surrounding_text = ibus_engine_set_surrounding_text;
304     class->process_hand_writing_event
305                                 = ibus_engine_process_hand_writing_event;
306     class->cancel_hand_writing  = ibus_engine_cancel_hand_writing;
307     class->set_content_type     = ibus_engine_set_content_type;
308
309     /* install properties */
310     /**
311      * IBusEngine:name:
312      *
313      * Name of this IBusEngine.
314      */
315     g_object_class_install_property (gobject_class,
316                     PROP_ENGINE_NAME,
317                     g_param_spec_string ("engine-name",
318                         "engine name",
319                         "engine name",
320                         "noname",
321                         G_PARAM_READWRITE |
322                         G_PARAM_CONSTRUCT_ONLY |
323                         G_PARAM_STATIC_STRINGS));
324
325     /* install signals */
326     /**
327      * IBusEngine::process-key-event:
328      * @engine: An IBusEngine.
329      * @keyval: Key symbol of the key press.
330      * @keycode: KeyCode of the key press.
331      * @state: Key modifier flags.
332      *
333      * Emitted when a key event is received.
334      * Implement the member function process_key_event() in extended class to receive this signal.
335      * Both the key symbol and keycode are passed to the member function.
336      * See ibus_input_context_process_key_event() for further explanation of
337      * key symbol, keycode and which to use.
338      *
339      * Returns: TRUE for successfully process the key; FALSE otherwise.
340      * See also:  ibus_input_context_process_key_event().
341      *
342      * <note><para>Argument @user_data is ignored in this function.</para></note>
343      */
344     engine_signals[PROCESS_KEY_EVENT] =
345         g_signal_new (I_("process-key-event"),
346             G_TYPE_FROM_CLASS (gobject_class),
347             G_SIGNAL_RUN_LAST,
348             G_STRUCT_OFFSET (IBusEngineClass, process_key_event),
349             g_signal_accumulator_true_handled, NULL,
350             _ibus_marshal_BOOL__UINT_UINT_UINT,
351             G_TYPE_BOOLEAN,
352             3,
353             G_TYPE_UINT,
354             G_TYPE_UINT,
355             G_TYPE_UINT);
356
357     /**
358      * IBusEngine::focus-in:
359      * @engine: An IBusEngine.
360      *
361      * Emitted when the client application get the focus.
362      * Implement the member function focus_in() in extended class to receive this signal.
363      *
364      * See also: ibus_input_context_focus_in()
365      * <note><para>Argument @user_data is ignored in this function.</para></note>
366      */
367     engine_signals[FOCUS_IN] =
368         g_signal_new (I_("focus-in"),
369             G_TYPE_FROM_CLASS (gobject_class),
370             G_SIGNAL_RUN_LAST,
371             G_STRUCT_OFFSET (IBusEngineClass, focus_in),
372             NULL, NULL,
373             _ibus_marshal_VOID__VOID,
374             G_TYPE_NONE,
375             0);
376
377     /**
378      * IBusEngine::focus-out:
379      * @engine: An IBusEngine.
380      *
381      * Emitted when the client application  lost the focus.
382      * Implement the member function focus_out() in extended class to receive this signal.
383      *
384      * See also: ibus_input_context_focus_out()
385      * <note><para>Argument @user_data is ignored in this function.</para></note>
386      */
387     engine_signals[FOCUS_OUT] =
388         g_signal_new (I_("focus-out"),
389             G_TYPE_FROM_CLASS (gobject_class),
390             G_SIGNAL_RUN_LAST,
391             G_STRUCT_OFFSET (IBusEngineClass, focus_out),
392             NULL, NULL,
393             _ibus_marshal_VOID__VOID,
394             G_TYPE_NONE,
395             0);
396
397     /**
398      * IBusEngine::reset:
399      * @engine: An IBusEngine.
400      *
401      * Emitted when the IME is reset.
402      * Implement the member function reset() in extended class to receive this signal.
403      *
404      * See also:  ibus_input_context_reset().
405      * <note><para>Argument @user_data is ignored in this function.</para></note>
406      */
407     engine_signals[RESET] =
408         g_signal_new (I_("reset"),
409             G_TYPE_FROM_CLASS (gobject_class),
410             G_SIGNAL_RUN_LAST,
411             G_STRUCT_OFFSET (IBusEngineClass, reset),
412             NULL, NULL,
413             _ibus_marshal_VOID__VOID,
414             G_TYPE_NONE,
415             0);
416
417     /**
418      * IBusEngine::enable:
419      * @engine: An IBusEngine.
420      *
421      * Emitted when the IME is enabled.
422      * Implement the member function set_enable() in extended class to receive this signal.
423      *
424      * See also:  ibus_input_context_enable().
425      * <note><para>Argument @user_data is ignored in this function.</para></note>
426      */
427     engine_signals[ENABLE] =
428         g_signal_new (I_("enable"),
429             G_TYPE_FROM_CLASS (gobject_class),
430             G_SIGNAL_RUN_LAST,
431             G_STRUCT_OFFSET (IBusEngineClass, enable),
432             NULL, NULL,
433             _ibus_marshal_VOID__VOID,
434             G_TYPE_NONE,
435             0);
436
437     /**
438      * IBusEngine::disable:
439      * @engine: An IBusEngine.
440      *
441      * Emitted when the IME is disabled.
442      * Implement the member function set_disable() in extended class to receive this signal.
443      *
444      * See also:  ibus_input_context_disable().
445      * <note><para>Argument @user_data is ignored in this function.</para></note>
446      */
447     engine_signals[DISABLE] =
448         g_signal_new (I_("disable"),
449             G_TYPE_FROM_CLASS (gobject_class),
450             G_SIGNAL_RUN_LAST,
451             G_STRUCT_OFFSET (IBusEngineClass, disable),
452             NULL, NULL,
453             _ibus_marshal_VOID__VOID,
454             G_TYPE_NONE,
455             0);
456
457     /**
458      * IBusEngine::set-cursor-location:
459      * @engine: An IBusEngine.
460      * @x: X coordinate of the cursor.
461      * @y: Y coordinate of the cursor.
462      * @w: Width of the cursor.
463      * @h: Height of the cursor.
464      *
465      * Emitted when the location of IME is set.
466      * Implement the member function set_cursor_location() in extended class to receive this signal.
467      *
468      * See also:  ibus_input_context_set_cursor_location().
469      * <note><para>Argument @user_data is ignored in this function.</para></note>
470      */
471     engine_signals[SET_CURSOR_LOCATION] =
472         g_signal_new (I_("set-cursor-location"),
473             G_TYPE_FROM_CLASS (gobject_class),
474             G_SIGNAL_RUN_LAST,
475             G_STRUCT_OFFSET (IBusEngineClass, set_cursor_location),
476             NULL, NULL,
477             _ibus_marshal_VOID__INT_INT_INT_INT,
478             G_TYPE_NONE,
479             4,
480             G_TYPE_INT,
481             G_TYPE_INT,
482             G_TYPE_INT,
483             G_TYPE_INT);
484
485     /**
486      * IBusEngine::set-capabilities:
487      * @engine: An IBusEngine.
488      * @caps: Capabilities flags of IBusEngine, see #IBusCapabilite
489      *
490      * Emitted when the client application capabilities is set.
491      * Implement the member function set_capabilities() in extended class to receive this signal.
492      *
493      * See also:  ibus_input_context_set_capabilities().
494      * <note><para>Argument @user_data is ignored in this function.</para></note>
495      */
496     engine_signals[SET_CAPABILITIES] =
497         g_signal_new (I_("set-capabilities"),
498             G_TYPE_FROM_CLASS (gobject_class),
499             G_SIGNAL_RUN_LAST,
500             G_STRUCT_OFFSET (IBusEngineClass, set_capabilities),
501             NULL, NULL,
502             _ibus_marshal_VOID__UINT,
503             G_TYPE_NONE,
504             1,
505             G_TYPE_UINT);
506
507     /**
508      * IBusEngine::page-up:
509      * @engine: An IBusEngine.
510      *
511      * Emitted when the page-up button is pressed.
512      * Implement the member function page_up() in extended class to receive this signal.
513      *
514      * <note><para>Argument @user_data is ignored in this function.</para></note>
515      */
516     engine_signals[PAGE_UP] =
517         g_signal_new (I_("page-up"),
518             G_TYPE_FROM_CLASS (gobject_class),
519             G_SIGNAL_RUN_LAST,
520             G_STRUCT_OFFSET (IBusEngineClass, page_up),
521             NULL, NULL,
522             _ibus_marshal_VOID__VOID,
523             G_TYPE_NONE,
524             0);
525
526     /**
527      * IBusEngine::page-down:
528      * @engine: An IBusEngine.
529      *
530      * Emitted when the page-down button is pressed.
531      * Implement the member function page_down() in extended class to receive this signal.
532      *
533      * <note><para>Argument @user_data is ignored in this function.</para></note>
534      */
535     engine_signals[PAGE_DOWN] =
536         g_signal_new (I_("page-down"),
537             G_TYPE_FROM_CLASS (gobject_class),
538             G_SIGNAL_RUN_LAST,
539             G_STRUCT_OFFSET (IBusEngineClass, page_down),
540             NULL, NULL,
541             _ibus_marshal_VOID__VOID,
542             G_TYPE_NONE,
543             0);
544
545     /**
546      * IBusEngine::cursor-up:
547      * @engine: An IBusEngine.
548      *
549      * Emitted when the up cursor button is pressed.
550      * Implement the member function cursor_up() in extended class to receive this signal.
551      *
552      * <note><para>Argument @user_data is ignored in this function.</para></note>
553      */
554     engine_signals[CURSOR_UP] =
555         g_signal_new (I_("cursor-up"),
556             G_TYPE_FROM_CLASS (gobject_class),
557             G_SIGNAL_RUN_LAST,
558             G_STRUCT_OFFSET (IBusEngineClass, cursor_up),
559             NULL, NULL,
560             _ibus_marshal_VOID__VOID,
561             G_TYPE_NONE,
562             0);
563
564     /**
565      * IBusEngine::cursor-down:
566      * @engine: An IBusEngine.
567      *
568      * Emitted when the down cursor button is pressed.
569      * Implement the member function cursor_down() in extended class to receive this signal.
570      *
571      * <note><para>Argument @user_data is ignored in this function.</para></note>
572      */
573     engine_signals[CURSOR_DOWN] =
574         g_signal_new (I_("cursor-down"),
575             G_TYPE_FROM_CLASS (gobject_class),
576             G_SIGNAL_RUN_LAST,
577             G_STRUCT_OFFSET (IBusEngineClass, cursor_down),
578             NULL, NULL,
579             _ibus_marshal_VOID__VOID,
580             G_TYPE_NONE,
581             0);
582
583     /**
584      * IBusEngine::candidate-clicked:
585      * @engine: An IBusEngine.
586      * @index:  Index of candidate be clicked.
587      * @button: Mouse button.
588      * @state:  Keyboard state.
589      *
590      * Emitted when candidate on lookup table is clicked.
591      * Implement the member function candidate_clicked() in extended class to receive this signal.
592      *
593      * <note><para>Argument @user_data is ignored in this function.</para></note>
594      */
595     engine_signals[CANDIDATE_CLICKED] =
596         g_signal_new (I_("candidate-clicked"),
597             G_TYPE_FROM_CLASS (gobject_class),
598             G_SIGNAL_RUN_LAST,
599             G_STRUCT_OFFSET (IBusEngineClass, candidate_clicked),
600             NULL, NULL,
601             _ibus_marshal_VOID__UINT_UINT_UINT,
602             G_TYPE_NONE,
603             3,
604             G_TYPE_UINT,
605             G_TYPE_UINT,
606             G_TYPE_UINT);
607
608     /**
609      * IBusEngine::property-activate:
610      * @engine: An IBusEngine.
611      * @name:   Property name.
612      * @state:  Property state.
613      *
614      * Emitted when a property is activated or change changed.
615      * Implement the member function property_activate() in extended class to receive this signal.
616      *
617      * <note><para>Argument @user_data is ignored in this function.</para></note>
618      */
619     engine_signals[PROPERTY_ACTIVATE] =
620         g_signal_new (I_("property-activate"),
621             G_TYPE_FROM_CLASS (gobject_class),
622             G_SIGNAL_RUN_LAST,
623             G_STRUCT_OFFSET (IBusEngineClass, property_activate),
624             NULL, NULL,
625             _ibus_marshal_VOID__STRING_UINT,
626             G_TYPE_NONE,
627             2,
628             G_TYPE_STRING,
629             G_TYPE_UINT);
630
631     /**
632      * IBusEngine::property-show:
633      * @engine: An IBusEngine.
634      * @name:   Property name.
635      *
636      * Emitted when a property is shown.
637      * Implement the member function property_side() in extended class to receive this signal.
638      *
639      * <note><para>Argument @user_data is ignored in this function.</para></note>
640      */
641     engine_signals[PROPERTY_SHOW] =
642         g_signal_new (I_("property-show"),
643             G_TYPE_FROM_CLASS (gobject_class),
644             G_SIGNAL_RUN_LAST,
645             G_STRUCT_OFFSET (IBusEngineClass, property_show),
646             NULL, NULL,
647             _ibus_marshal_VOID__STRING,
648             G_TYPE_NONE,
649             1,
650             G_TYPE_STRING);
651
652     /**
653      * IBusEngine::property-hide:
654      * @engine: An IBusEngine.
655      * @name:   Property name.
656      *
657      * Emitted when a property is hidden.
658      * Implement the member function property_hide() in extended class to receive this signal.
659      *
660      * <note><para>Argument @user_data is ignored in this function.</para></note>
661      */
662     engine_signals[PROPERTY_HIDE] =
663         g_signal_new (I_("property-hide"),
664             G_TYPE_FROM_CLASS (gobject_class),
665             G_SIGNAL_RUN_LAST,
666             G_STRUCT_OFFSET (IBusEngineClass, property_hide),
667             NULL, NULL,
668             _ibus_marshal_VOID__STRING,
669             G_TYPE_NONE,
670             1,
671             G_TYPE_STRING);
672
673     /**
674      * IBusEngine::process-hand-writing-event:
675      * @engine: An IBusEngine.
676      * @coordinates: An array of double (0.0 to 1.0) which represents a stroke (i.e. [x1, y1, x2, y2, x3, y3, ...]).
677      * @coordinates_len: The number of elements in the array.
678      *
679      * Emitted when a hand writing operation is cancelled.
680      * Implement the member function cancel_hand_writing() in extended class to receive this signal.
681      *
682      * <note><para>Argument @user_data is ignored in this function.</para></note>
683      */
684     engine_signals[PROCESS_HAND_WRITING_EVENT] =
685         g_signal_new (I_("process-hand-writing-event"),
686             G_TYPE_FROM_CLASS (gobject_class),
687             G_SIGNAL_RUN_LAST,
688             G_STRUCT_OFFSET (IBusEngineClass, process_hand_writing_event),
689             NULL, NULL,
690             _ibus_marshal_VOID__POINTER_UINT,
691             G_TYPE_NONE,
692             2,
693             G_TYPE_POINTER,
694             G_TYPE_UINT);
695
696     /**
697      * IBusEngine::cancel-hand-writing:
698      * @engine: An IBusEngine.
699      * @n_strokes: The number of strokes to be removed. 0 means "remove all".
700      *
701      * Emitted when a hand writing operation is cancelled.
702      * Implement the member function cancel_hand_writing() in extended class to receive this signal.
703      *
704      * <note><para>Argument @user_data is ignored in this function.</para></note>
705      */
706     engine_signals[CANCEL_HAND_WRITING] =
707         g_signal_new (I_("cancel-hand-writing"),
708             G_TYPE_FROM_CLASS (gobject_class),
709             G_SIGNAL_RUN_LAST,
710             G_STRUCT_OFFSET (IBusEngineClass, cancel_hand_writing),
711             NULL, NULL,
712             _ibus_marshal_VOID__UINT,
713             G_TYPE_NONE,
714             1,
715             G_TYPE_UINT);
716
717     /**
718      * IBusEngine::set-surrounding-text:
719      * @engine: An IBusEngine.
720      * @text: The surrounding text.
721      * @cursor_pos: The cursor position on surrounding text.
722      * @anchor_pos: The anchor position on selection area.
723      *
724      * Emitted when a surrounding text is set.
725      * Implement the member function set_surrounding_text() in extended class to receive this signal.
726      * If anchor_pos equals to cursor_pos, it means "there are no selection" or "does not support
727      * selection retrival".
728      *
729      * <note><para>Argument @user_data is ignored in this function.</para></note>
730      */
731     engine_signals[SET_SURROUNDING_TEXT] =
732         g_signal_new (I_("set-surrounding-text"),
733             G_TYPE_FROM_CLASS (gobject_class),
734             G_SIGNAL_RUN_LAST,
735             G_STRUCT_OFFSET (IBusEngineClass, set_surrounding_text),
736             NULL, NULL,
737             _ibus_marshal_VOID__OBJECT_UINT_UINT,
738             G_TYPE_NONE,
739             3,
740             G_TYPE_OBJECT,
741             G_TYPE_UINT,
742             G_TYPE_UINT);
743
744     /**
745      * IBusEngine::set-content-type:
746      * @engine: An #IBusEngine.
747      * @purpose: Primary purpose of the input context, as an #IBusInputPurpose.
748      * @hints: Hints that augment @purpose, as an #IBusInputHints.
749      *
750      * Emitted when the client application content-type (primary
751      * purpose and hints) is set.  The engine could change the
752      * behavior according to the content-type.  Implement the member
753      * function set_content_type() in extended class to receive this
754      * signal.
755      *
756      * For example, if the client application wants to restrict input
757      * to numbers, this signal will be emitted with @purpose set to
758      * #IBUS_INPUT_PURPOSE_NUMBER, so the engine can switch the input
759      * mode to latin.
760      *
761      * <note><para>Argument @user_data is ignored in this
762      * function.</para></note>
763      */
764     engine_signals[SET_CONTENT_TYPE] =
765         g_signal_new (I_("set-content-type"),
766             G_TYPE_FROM_CLASS (gobject_class),
767             G_SIGNAL_RUN_LAST,
768             G_STRUCT_OFFSET (IBusEngineClass, set_content_type),
769             NULL, NULL,
770             _ibus_marshal_VOID__UINT_UINT,
771             G_TYPE_NONE,
772             2,
773             G_TYPE_UINT,
774             G_TYPE_UINT);
775
776     g_type_class_add_private (class, sizeof (IBusEnginePrivate));
777
778     text_empty = ibus_text_new_from_static_string ("");
779     g_object_ref_sink (text_empty);
780 }
781
782 static void
783 ibus_engine_init (IBusEngine *engine)
784 {
785     engine->priv = IBUS_ENGINE_GET_PRIVATE (engine);
786
787     engine->priv->surrounding_text = g_object_ref_sink (text_empty);
788 }
789
790 static void
791 ibus_engine_destroy (IBusEngine *engine)
792 {
793     g_free (engine->priv->engine_name);
794     engine->priv->engine_name = NULL;
795
796     if (engine->priv->surrounding_text) {
797         g_object_unref (engine->priv->surrounding_text);
798         engine->priv->surrounding_text = NULL;
799     }
800
801     IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
802 }
803
804 static void
805 ibus_engine_set_property (IBusEngine   *engine,
806                           guint         prop_id,
807                           const GValue *value,
808                           GParamSpec   *pspec)
809 {
810     switch (prop_id) {
811     case PROP_ENGINE_NAME:
812         engine->priv->engine_name = g_value_dup_string (value);
813         break;
814     default:
815         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
816     }
817 }
818
819 static void
820 ibus_engine_get_property (IBusEngine *engine,
821                           guint       prop_id,
822                           GValue     *value,
823                           GParamSpec *pspec)
824 {
825     switch (prop_id) {
826     case PROP_ENGINE_NAME:
827         g_value_set_string (value, engine->priv->engine_name);
828         break;
829
830     default:
831         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
832     }
833 }
834
835 static void
836 ibus_engine_service_method_call (IBusService           *service,
837                                  GDBusConnection       *connection,
838                                  const gchar           *sender,
839                                  const gchar           *object_path,
840                                  const gchar           *interface_name,
841                                  const gchar           *method_name,
842                                  GVariant              *parameters,
843                                  GDBusMethodInvocation *invocation)
844 {
845     IBusEngine *engine = IBUS_ENGINE (service);
846
847     if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
848         IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
849                 service_method_call (service,
850                                      connection,
851                                      sender,
852                                      object_path,
853                                      interface_name,
854                                      method_name,
855                                      parameters,
856                                      invocation);
857         return;
858     }
859
860     if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) {
861         guint keyval, keycode, state;
862         gboolean retval = FALSE;
863         g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state);
864         g_signal_emit (engine,
865                        engine_signals[PROCESS_KEY_EVENT],
866                        0,
867                        keyval,
868                        keycode,
869                        state,
870                        &retval);
871         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval));
872         return;
873     }
874
875     static const struct {
876         gchar *member;
877         guint  signal_id;
878     } no_arg_methods[] = {
879         { "FocusIn",     FOCUS_IN },
880         { "FocusOut",    FOCUS_OUT },
881         { "Reset",       RESET },
882         { "Enable",      ENABLE },
883         { "Disable",     DISABLE },
884         { "PageUp",      PAGE_UP },
885         { "PageDown",    PAGE_DOWN },
886         { "CursorUp",    CURSOR_UP },
887         { "CursorDown",  CURSOR_DOWN },
888     };
889
890     gint i;
891     for (i = 0; i < G_N_ELEMENTS (no_arg_methods); i++) {
892         if (g_strcmp0 (method_name, no_arg_methods[i].member) == 0) {
893             g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
894             g_dbus_method_invocation_return_value (invocation, NULL);
895             return;
896         }
897     }
898
899     if (g_strcmp0 (method_name, "CandidateClicked") == 0) {
900         guint index, button, state;
901         g_variant_get (parameters, "(uuu)", &index, &button, &state);
902         g_signal_emit (engine,
903                        engine_signals[CANDIDATE_CLICKED],
904                        0,
905                        index,
906                        button,
907                        state);
908         g_dbus_method_invocation_return_value (invocation, NULL);
909         return;
910     }
911
912     if (g_strcmp0 (method_name, "PropertyActivate") == 0) {
913         gchar *name;
914         guint state;
915         g_variant_get (parameters, "(&su)", &name, &state);
916         g_signal_emit (engine,
917                        engine_signals[PROPERTY_ACTIVATE],
918                        0,
919                        name,
920                        state);
921         g_dbus_method_invocation_return_value (invocation, NULL);
922         return;
923     }
924
925     if (g_strcmp0 (method_name, "PropertyShow") == 0) {
926         gchar *name;
927         g_variant_get (parameters, "(&s)", &name);
928         g_signal_emit (engine,
929                        engine_signals[PROPERTY_SHOW],
930                        0,
931                        name);
932         g_dbus_method_invocation_return_value (invocation, NULL);
933         return;
934     }
935
936     if (g_strcmp0 (method_name, "PropertyHide") == 0) {
937         gchar *name;
938         g_variant_get (parameters, "(&s)", &name);
939         g_signal_emit (engine,
940                        engine_signals[PROPERTY_HIDE],
941                        0,
942                        name);
943         g_dbus_method_invocation_return_value (invocation, NULL);
944         return;
945     }
946
947     if (g_strcmp0 (method_name, "SetCursorLocation") == 0) {
948         gint x, y, w, h;
949         g_variant_get (parameters, "(iiii)", &x, &y, &w, &h);
950         engine->cursor_area.x = x;
951         engine->cursor_area.y = y;
952         engine->cursor_area.width = w;
953         engine->cursor_area.height = h;
954
955         g_signal_emit (engine,
956                        engine_signals[SET_CURSOR_LOCATION],
957                        0,
958                        x, y, w, h);
959         g_dbus_method_invocation_return_value (invocation, NULL);
960         return;
961     }
962
963     if (g_strcmp0 (method_name, "SetCapabilities") == 0) {
964         guint caps;
965         g_variant_get (parameters, "(u)", &caps);
966         engine->client_capabilities = caps;
967         g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
968         g_dbus_method_invocation_return_value (invocation, NULL);
969         return;
970     }
971
972     if (g_strcmp0 (method_name, "SetSurroundingText") == 0) {
973         GVariant *variant = NULL;
974         IBusText *text;
975         guint cursor_pos;
976         guint anchor_pos;
977
978         g_variant_get (parameters,
979                        "(vuu)",
980                        &variant,
981                        &cursor_pos,
982                        &anchor_pos);
983         text = IBUS_TEXT (ibus_serializable_deserialize (variant));
984         g_variant_unref (variant);
985
986         g_signal_emit (engine, engine_signals[SET_SURROUNDING_TEXT],
987                        0,
988                        text,
989                        cursor_pos,
990                        anchor_pos);
991         if (g_object_is_floating (text)) {
992             g_object_unref (text);
993         }
994         g_dbus_method_invocation_return_value (invocation, NULL);
995         return;
996     }
997
998     if (g_strcmp0 (method_name, "ProcessHandWritingEvent") == 0) {
999         const gdouble *coordinates;
1000         gsize coordinates_len = 0;
1001
1002         coordinates = g_variant_get_fixed_array (g_variant_get_child_value (parameters, 0), &coordinates_len, sizeof (gdouble));
1003         g_return_if_fail (coordinates != NULL);
1004         g_return_if_fail (coordinates_len >= 4); /* The array should contain at least one line. */
1005         g_return_if_fail (coordinates_len <= G_MAXUINT); /* to prevent overflow in the cast in g_signal_emit */
1006         g_return_if_fail ((coordinates_len & 1) == 0);
1007
1008         g_signal_emit (engine, engine_signals[PROCESS_HAND_WRITING_EVENT], 0,
1009                        coordinates, (guint) coordinates_len);
1010         g_dbus_method_invocation_return_value (invocation, NULL);
1011         return;
1012     }
1013
1014     if (g_strcmp0 (method_name, "CancelHandWriting") == 0) {
1015         guint n_strokes = 0;
1016         g_variant_get (parameters, "(u)", &n_strokes);
1017         g_signal_emit (engine, engine_signals[CANCEL_HAND_WRITING], 0, n_strokes);
1018         g_dbus_method_invocation_return_value (invocation, NULL);
1019         return;
1020     }
1021
1022     /* should not be reached */
1023     g_return_if_reached ();
1024 }
1025
1026 static GVariant *
1027 ibus_engine_service_get_property (IBusService        *service,
1028                                   GDBusConnection    *connection,
1029                                   const gchar        *sender,
1030                                   const gchar        *object_path,
1031                                   const gchar        *interface_name,
1032                                   const gchar        *property_name,
1033                                   GError            **error)
1034 {
1035     return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
1036                 service_get_property (service,
1037                                       connection,
1038                                       sender,
1039                                       object_path,
1040                                       interface_name,
1041                                       property_name,
1042                                       error);
1043 }
1044
1045 static gboolean
1046 ibus_engine_service_set_property (IBusService        *service,
1047                                   GDBusConnection    *connection,
1048                                   const gchar        *sender,
1049                                   const gchar        *object_path,
1050                                   const gchar        *interface_name,
1051                                   const gchar        *property_name,
1052                                   GVariant           *value,
1053                                   GError            **error)
1054 {
1055     IBusEngine *engine = IBUS_ENGINE (service);
1056
1057     if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
1058         return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
1059             service_set_property (service,
1060                                   connection,
1061                                   sender,
1062                                   object_path,
1063                                   interface_name,
1064                                   property_name,
1065                                   value,
1066                                   error);
1067     }
1068
1069     if (g_strcmp0 (property_name, "ContentType") == 0) {
1070         guint purpose = 0;
1071         guint hints = 0;
1072
1073         g_variant_get (value, "(uu)", &purpose, &hints);
1074         if (purpose != engine->priv->content_purpose ||
1075             hints != engine->priv->content_hints) {
1076             engine->priv->content_purpose = purpose;
1077             engine->priv->content_hints = hints;
1078
1079             g_signal_emit (engine,
1080                            engine_signals[SET_CONTENT_TYPE],
1081                            0,
1082                            purpose,
1083                            hints);
1084
1085             ibus_engine_dbus_property_changed (engine, "ContentType", value);
1086         }
1087
1088         return TRUE;
1089     }
1090
1091     g_return_val_if_reached (FALSE);
1092 }
1093
1094 static gboolean
1095 ibus_engine_process_key_event (IBusEngine *engine,
1096                                guint       keyval,
1097                                guint       keycode,
1098                                guint       state)
1099 {
1100     return FALSE;
1101 }
1102
1103 static void
1104 ibus_engine_focus_in (IBusEngine *engine)
1105 {
1106     // g_debug ("focus-in");
1107 }
1108
1109 static void
1110 ibus_engine_focus_out (IBusEngine *engine)
1111 {
1112     // g_debug ("focus-out");
1113 }
1114
1115 static void
1116 ibus_engine_reset (IBusEngine *engine)
1117 {
1118     // g_debug ("reset");
1119 }
1120
1121 static void
1122 ibus_engine_enable (IBusEngine *engine)
1123 {
1124     // g_debug ("enable");
1125 }
1126
1127 static void
1128 ibus_engine_disable (IBusEngine *engine)
1129 {
1130     // g_debug ("disable");
1131 }
1132
1133 static void
1134 ibus_engine_set_cursor_location (IBusEngine *engine,
1135                                  gint        x,
1136                                  gint        y,
1137                                  gint        w,
1138                                  gint        h)
1139 {
1140     // g_debug ("set-cursor-location (%d, %d, %d, %d)", x, y, w, h);
1141 }
1142
1143 static void
1144 ibus_engine_set_capabilities (IBusEngine *engine,
1145                               guint       caps)
1146 {
1147     // g_debug ("set-capabilities (0x%04x)", caps);
1148 }
1149
1150 static void
1151 ibus_engine_page_up (IBusEngine *engine)
1152 {
1153     // g_debug ("page-up");
1154 }
1155
1156 static void
1157 ibus_engine_page_down (IBusEngine *engine)
1158 {
1159     // g_debug ("page-down");
1160 }
1161
1162 static void
1163 ibus_engine_cursor_up (IBusEngine *engine)
1164 {
1165     // g_debug ("cursor-up");
1166 }
1167
1168 static void
1169 ibus_engine_cursor_down (IBusEngine *engine)
1170 {
1171     // g_debug ("cursor-down");
1172 }
1173
1174 static void
1175 ibus_engine_candidate_clicked (IBusEngine *engine,
1176                                guint       index,
1177                                guint       button,
1178                                guint       state)
1179 {
1180     // g_debug ("candidate-clicked");
1181 }
1182
1183 static void
1184 ibus_engine_property_activate (IBusEngine  *engine,
1185                                const gchar *prop_name,
1186                                guint        prop_state)
1187 {
1188     // g_debug ("property-activate ('%s', %d)", prop_name, prop_state);
1189 }
1190
1191 static void
1192 ibus_engine_property_show (IBusEngine *engine, const gchar *prop_name)
1193 {
1194     // g_debug ("property-show ('%s')", prop_name);
1195 }
1196
1197 static void
1198 ibus_engine_property_hide (IBusEngine *engine, const gchar *prop_name)
1199 {
1200     // g_debug ("property-hide ('%s')", prop_name);
1201 }
1202
1203 static void
1204 ibus_engine_set_surrounding_text (IBusEngine *engine,
1205                                   IBusText   *text,
1206                                   guint       cursor_pos,
1207                                   guint       anchor_pos)
1208 {
1209     g_assert (IBUS_IS_ENGINE (engine));
1210
1211     if (engine->priv->surrounding_text) {
1212         g_object_unref (engine->priv->surrounding_text);
1213     }
1214
1215     engine->priv->surrounding_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
1216     engine->priv->surrounding_cursor_pos = cursor_pos;
1217     engine->priv->selection_anchor_pos = anchor_pos;
1218     // g_debug ("set-surrounding-text ('%s', %d, %d)", text->text, cursor_pos, anchor_pos);
1219 }
1220
1221 static void
1222 ibus_engine_process_hand_writing_event (IBusEngine         *engine,
1223                                         const gdouble      *coordinates,
1224                                         guint               coordinates_len)
1225 {
1226     // guint i;
1227     // g_debug ("process-hand-writing-event (%u)", coordinates_len);
1228     // for (i = 0; i < coordinates_len; i++)
1229     //     g_debug (" %lf", coordinates[i]);
1230 }
1231
1232 static void
1233 ibus_engine_cancel_hand_writing (IBusEngine         *engine,
1234                                  guint               n_strokes)
1235 {
1236     // g_debug ("cancel-hand-writing (%u)", n_strokes);
1237 }
1238
1239 static void
1240 ibus_engine_set_content_type (IBusEngine *engine,
1241                               guint       purpose,
1242                               guint       hints)
1243 {
1244     // g_debug ("set-content-type (%u %u)", purpose, hints);
1245 }
1246
1247 static void
1248 ibus_engine_emit_signal (IBusEngine  *engine,
1249                          const gchar *signal_name,
1250                          GVariant    *parameters)
1251 {
1252     ibus_service_emit_signal ((IBusService *)engine,
1253                               NULL,
1254                               IBUS_INTERFACE_ENGINE,
1255                               signal_name,
1256                               parameters,
1257                               NULL);
1258 }
1259
1260 static void
1261 ibus_engine_dbus_property_changed (IBusEngine  *engine,
1262                                    const gchar *property_name,
1263                                    GVariant    *value)
1264 {
1265     const gchar *object_path;
1266     GDBusConnection *connection;
1267     GDBusMessage *message;
1268     GVariantBuilder *builder;
1269     gboolean retval;
1270     GError *error;
1271
1272     /* we cannot use ibus_service_emit_signal() here, since we need to
1273        set sender of the signal so that GDBusProxy can properly track
1274        the property change. */
1275     object_path = ibus_service_get_object_path ((IBusService *)engine);
1276     message = g_dbus_message_new_signal (object_path,
1277                                          "org.freedesktop.DBus.Properties",
1278                                          "PropertiesChanged");
1279
1280     g_dbus_message_set_sender (message, "org.freedesktop.IBus");
1281
1282     builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
1283     g_variant_builder_add (builder, "{sv}", property_name, value);
1284     g_dbus_message_set_body (message,
1285                              g_variant_new ("(sa{sv}as)",
1286                                             IBUS_INTERFACE_ENGINE,
1287                                             builder,
1288                                             NULL));
1289
1290     error = NULL;
1291     connection = ibus_service_get_connection ((IBusService *)engine);
1292     retval = g_dbus_connection_send_message (connection,
1293                                              message,
1294                                              G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1295                                              NULL,
1296                                              &error);
1297     if (!retval) {
1298         g_warning ("Failed to emit PropertiesChanged signal: %s",
1299                    error->message);
1300         g_error_free (error);
1301     }
1302     g_object_unref (message);
1303 }
1304
1305 IBusEngine *
1306 ibus_engine_new (const gchar     *engine_name,
1307                  const gchar     *object_path,
1308                  GDBusConnection *connection)
1309 {
1310     return ibus_engine_new_with_type (IBUS_TYPE_ENGINE,
1311                                       engine_name,
1312                                       object_path,
1313                                       connection);
1314 }
1315
1316 IBusEngine  *
1317 ibus_engine_new_with_type (GType            engine_type,
1318                            const gchar     *engine_name,
1319                            const gchar     *object_path,
1320                            GDBusConnection *connection)
1321 {
1322     g_return_val_if_fail (g_type_is_a (engine_type, IBUS_TYPE_ENGINE), NULL);
1323     g_return_val_if_fail (engine_name != NULL, NULL);
1324     g_return_val_if_fail (object_path != NULL, NULL);
1325     g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1326
1327     GObject *object = g_object_new (engine_type,
1328                                     "engine-name", engine_name,
1329                                     "object-path", object_path,
1330                                     "connection", connection,
1331                                     NULL);
1332     return IBUS_ENGINE (object);
1333 }
1334
1335
1336 void
1337 ibus_engine_commit_text (IBusEngine *engine,
1338                          IBusText   *text)
1339 {
1340     g_return_if_fail (IBUS_IS_ENGINE (engine));
1341     g_return_if_fail (IBUS_IS_TEXT (text));
1342
1343     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1344     ibus_engine_emit_signal (engine,
1345                              "CommitText",
1346                              g_variant_new ("(v)", variant));
1347
1348     if (g_object_is_floating (text)) {
1349         g_object_unref (text);
1350     }
1351 }
1352
1353 void
1354 ibus_engine_update_preedit_text (IBusEngine      *engine,
1355                                  IBusText        *text,
1356                                  guint            cursor_pos,
1357                                  gboolean         visible)
1358 {
1359     ibus_engine_update_preedit_text_with_mode (engine,
1360             text, cursor_pos, visible, IBUS_ENGINE_PREEDIT_CLEAR);
1361 }
1362
1363 void
1364 ibus_engine_update_preedit_text_with_mode (IBusEngine            *engine,
1365                                            IBusText              *text,
1366                                            guint                  cursor_pos,
1367                                            gboolean               visible,
1368                                            IBusPreeditFocusMode   mode)
1369 {
1370     g_return_if_fail (IBUS_IS_ENGINE (engine));
1371     g_return_if_fail (IBUS_IS_TEXT (text));
1372
1373     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1374     ibus_engine_emit_signal (engine,
1375                              "UpdatePreeditText",
1376                              g_variant_new ("(vubu)", variant, cursor_pos, visible, mode));
1377
1378     if (g_object_is_floating (text)) {
1379         g_object_unref (text);
1380     }
1381 }
1382
1383 void ibus_engine_update_auxiliary_text (IBusEngine      *engine,
1384                                         IBusText        *text,
1385                                         gboolean         visible)
1386 {
1387     g_return_if_fail (IBUS_IS_ENGINE (engine));
1388     g_return_if_fail (IBUS_IS_TEXT (text));
1389
1390     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1391     ibus_engine_emit_signal (engine,
1392                              "UpdateAuxiliaryText",
1393                              g_variant_new ("(vb)", variant, visible));
1394
1395     if (g_object_is_floating (text)) {
1396         g_object_unref (text);
1397     }
1398 }
1399
1400
1401 void
1402 ibus_engine_update_lookup_table (IBusEngine        *engine,
1403                                  IBusLookupTable   *table,
1404                                  gboolean           visible)
1405 {
1406     g_return_if_fail (IBUS_IS_ENGINE (engine));
1407     g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
1408
1409     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)table);
1410     ibus_engine_emit_signal (engine,
1411                              "UpdateLookupTable",
1412                              g_variant_new ("(vb)", variant, visible));
1413
1414     if (g_object_is_floating (table)) {
1415         g_object_unref (table);
1416     }
1417 }
1418
1419 void
1420 ibus_engine_update_lookup_table_fast (IBusEngine        *engine,
1421                                       IBusLookupTable   *table,
1422                                       gboolean           visible)
1423 {
1424     g_return_if_fail (IBUS_IS_ENGINE (engine));
1425     g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
1426
1427     IBusLookupTable *new_table;
1428     IBusText *text;
1429     gint page_begin;
1430     gint i;
1431
1432     if (table->candidates->len < table->page_size << 2) {
1433         ibus_engine_update_lookup_table (engine, table, visible);
1434         return;
1435     }
1436
1437     page_begin = (table->cursor_pos / table->page_size) * table->page_size;
1438
1439     new_table = ibus_lookup_table_new (table->page_size, 0, table->cursor_visible, table->round);
1440
1441     for (i = page_begin; i < page_begin + table->page_size && i < table->candidates->len; i++) {
1442         ibus_lookup_table_append_candidate (new_table, ibus_lookup_table_get_candidate (table, i));
1443     }
1444
1445     for (i = 0; (text = ibus_lookup_table_get_label (table, i)) != NULL; i++) {
1446         ibus_lookup_table_append_label (new_table, text);
1447     }
1448
1449     ibus_lookup_table_set_cursor_pos (new_table, ibus_lookup_table_get_cursor_in_page (table));
1450     ibus_lookup_table_set_orientation (new_table, ibus_lookup_table_get_orientation (table));
1451
1452     ibus_engine_update_lookup_table (engine, new_table, visible);
1453
1454     if (g_object_is_floating (table)) {
1455         g_object_unref (table);
1456     }
1457 }
1458
1459 void
1460 ibus_engine_forward_key_event (IBusEngine      *engine,
1461                                guint            keyval,
1462                                guint            keycode,
1463                                guint            state)
1464 {
1465     g_return_if_fail (IBUS_IS_ENGINE (engine));
1466
1467     ibus_engine_emit_signal (engine,
1468                              "ForwardKeyEvent",
1469                              g_variant_new ("(uuu)", keyval, keycode, state));
1470 }
1471
1472 void ibus_engine_delete_surrounding_text (IBusEngine      *engine,
1473                                           gint             offset_from_cursor,
1474                                           guint            nchars)
1475 {
1476     IBusEnginePrivate *priv;
1477
1478     g_return_if_fail (IBUS_IS_ENGINE (engine));
1479
1480     priv = IBUS_ENGINE_GET_PRIVATE (engine);
1481
1482     /* Update surrounding-text cache.  This is necessary since some
1483        engines call ibus_engine_get_surrounding_text() immediately
1484        after ibus_engine_delete_surrounding_text(). */
1485     if (priv->surrounding_text) {
1486         IBusText *text;
1487         glong cursor_pos, len;
1488
1489         cursor_pos = priv->surrounding_cursor_pos + offset_from_cursor;
1490         len = ibus_text_get_length (priv->surrounding_text);
1491         if (cursor_pos >= 0 && len - cursor_pos >= nchars) {
1492             gunichar *ucs;
1493
1494             ucs = g_utf8_to_ucs4_fast (priv->surrounding_text->text,
1495                                        -1,
1496                                        NULL);
1497             memmove (&ucs[cursor_pos],
1498                      &ucs[cursor_pos + nchars],
1499                      sizeof(gunichar) * (len - cursor_pos - nchars));
1500             ucs[len - nchars] = 0;
1501             text = ibus_text_new_from_ucs4 (ucs);
1502             g_free (ucs);
1503             priv->surrounding_cursor_pos = cursor_pos;
1504         } else {
1505             text = text_empty;
1506             priv->surrounding_cursor_pos = 0;
1507         }
1508
1509         g_object_unref (priv->surrounding_text);
1510         priv->surrounding_text = g_object_ref_sink (text);
1511     }
1512
1513     ibus_engine_emit_signal (engine,
1514                              "DeleteSurroundingText",
1515                              g_variant_new ("(iu)", offset_from_cursor, nchars));
1516 }
1517
1518 void
1519 ibus_engine_get_surrounding_text (IBusEngine   *engine,
1520                                   IBusText    **text,
1521                                   guint        *cursor_pos,
1522                                   guint        *anchor_pos)
1523 {
1524     IBusEnginePrivate *priv;
1525
1526     g_return_if_fail (IBUS_IS_ENGINE (engine));
1527     const gboolean signal_only = (text == NULL);
1528
1529     g_return_if_fail (( signal_only && (cursor_pos == NULL)) ||
1530                       (!signal_only && (cursor_pos != NULL)));
1531
1532     g_return_if_fail (( signal_only && (anchor_pos == NULL)) ||
1533                       (!signal_only && (anchor_pos != NULL)));
1534
1535     priv = IBUS_ENGINE_GET_PRIVATE (engine);
1536
1537     if (!signal_only) {
1538         *text = g_object_ref (priv->surrounding_text);
1539         *cursor_pos = priv->surrounding_cursor_pos;
1540         *anchor_pos = priv->selection_anchor_pos;
1541     }
1542
1543     /* tell the client that this engine will utilize surrounding-text
1544      * feature, which causes periodical update.  Note that the client
1545      * should request the initial surrounding-text when the engine is
1546      * enabled (see ibus_im_context_focus_in() and
1547      * _ibus_context_enabled_cb() in client/gtk2/ibusimcontext.c). */
1548     ibus_engine_emit_signal (engine,
1549                              "RequireSurroundingText",
1550                              NULL);
1551
1552     // g_debug ("get-surrounding-text ('%s', %d, %d)", (*text)->text, *cursor_pos, *anchor_pos);
1553 }
1554
1555 void
1556 ibus_engine_get_content_type (IBusEngine *engine,
1557                               guint      *purpose,
1558                               guint      *hints)
1559 {
1560     g_return_if_fail (IBUS_IS_ENGINE (engine));
1561
1562     *purpose = engine->priv->content_purpose;
1563     *hints = engine->priv->content_hints;
1564 }
1565
1566 void
1567 ibus_engine_register_properties (IBusEngine   *engine,
1568                                  IBusPropList *prop_list)
1569 {
1570     g_return_if_fail (IBUS_IS_ENGINE (engine));
1571     g_return_if_fail (IBUS_IS_PROP_LIST (prop_list));
1572
1573     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop_list);
1574     ibus_engine_emit_signal (engine,
1575                              "RegisterProperties",
1576                              g_variant_new ("(v)", variant));
1577
1578     if (g_object_is_floating (prop_list)) {
1579         g_object_unref (prop_list);
1580     }
1581 }
1582
1583 void
1584 ibus_engine_update_property (IBusEngine   *engine,
1585                              IBusProperty *prop)
1586 {
1587     g_return_if_fail (IBUS_IS_ENGINE (engine));
1588     g_return_if_fail (IBUS_IS_PROPERTY (prop));
1589
1590     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
1591     ibus_engine_emit_signal (engine,
1592                              "UpdateProperty",
1593                              g_variant_new ("(v)", variant));
1594
1595     if (g_object_is_floating (prop)) {
1596         g_object_unref (prop);
1597     }
1598 }
1599
1600 #define DEFINE_FUNC(name, Name)                             \
1601     void                                                    \
1602     ibus_engine_##name (IBusEngine *engine)                 \
1603     {                                                       \
1604         g_return_if_fail (IBUS_IS_ENGINE (engine));         \
1605         ibus_engine_emit_signal (engine,                    \
1606                               #Name,                        \
1607                               NULL);                        \
1608     }
1609 DEFINE_FUNC (show_preedit_text, ShowPreeditText)
1610 DEFINE_FUNC (hide_preedit_text, HidePreeditText)
1611 DEFINE_FUNC (show_auxiliary_text, ShowAuxiliaryText)
1612 DEFINE_FUNC (hide_auxiliary_text, HideAuxiliaryText)
1613 DEFINE_FUNC (show_lookup_table, ShowLookupTable)
1614 DEFINE_FUNC (hide_lookup_table, HideLookupTable)
1615 #undef DEFINE_FUNC
1616
1617 const gchar *
1618 ibus_engine_get_name (IBusEngine *engine)
1619 {
1620     g_return_val_if_fail (IBUS_IS_ENGINE (engine), NULL);
1621     return engine->priv->engine_name;
1622 }