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