Fix make rpm errors due to ibus-dconf and pygobject override
[platform/upstream/ibus.git] / src / ibusengine.c
index e5bcb59..1c22d6a 100644 (file)
@@ -1,6 +1,8 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-
-#include <stdarg.h>
 #include "ibusengine.h"
+#include <stdarg.h>
+#include <string.h>
+#include "ibusmarshalers.h"
 #include "ibusinternal.h"
 #include "ibusshare.h"
 
@@ -42,152 +45,250 @@ enum {
     PROPERTY_ACTIVATE,
     PROPERTY_SHOW,
     PROPERTY_HIDE,
+    CANDIDATE_CLICKED,
+    SET_SURROUNDING_TEXT,
+    PROCESS_HAND_WRITING_EVENT,
+    CANCEL_HAND_WRITING,
     LAST_SIGNAL,
 };
 
 enum {
     PROP_0,
-    PROP_NAME,
-    PROP_CONNECTION,
+    PROP_ENGINE_NAME,
 };
 
 
 /* IBusEnginePriv */
 struct _IBusEnginePrivate {
-    gchar *name;
-    IBusConnection *connection;
+    gchar *engine_name;
+    GDBusConnection *connection;
+
+    /* cached surrounding text (see also IBusInputContextPrivate and
+       BusEngineProxy) */
+    IBusText *surrounding_text;
+    guint surrounding_cursor_pos;
+    guint selection_anchor_pos;
 };
-typedef struct _IBusEnginePrivate IBusEnginePrivate;
 
 static guint            engine_signals[LAST_SIGNAL] = { 0 };
 
+static IBusText *text_empty = NULL;
+
 /* functions prototype */
-static void     ibus_engine_class_init      (IBusEngineClass    *klass);
-static void     ibus_engine_init            (IBusEngine         *engine);
-static void     ibus_engine_destroy         (IBusEngine         *engine);
-static void     ibus_engine_set_property    (IBusEngine         *engine,
-                                             guint               prop_id,
-                                             const GValue       *value,
-                                             GParamSpec         *pspec);
-static void     ibus_engine_get_property    (IBusEngine         *engine,
-                                             guint               prop_id,
-                                             GValue             *value,
-                                             GParamSpec         *pspec);
-static gboolean ibus_engine_ibus_message    (IBusEngine         *engine,
-                                             IBusConnection     *connection,
-                                             IBusMessage        *message);
-static gboolean ibus_engine_process_key_event
-                                            (IBusEngine         *engine,
-                                             guint               keyval,
-                                             guint               state);
-static void     ibus_engine_focus_in        (IBusEngine         *engine);
-static void     ibus_engine_focus_out       (IBusEngine         *engine);
-static void     ibus_engine_reset           (IBusEngine         *engine);
-static void     ibus_engine_enable          (IBusEngine         *engine);
-static void     ibus_engine_disable         (IBusEngine         *engine);
-static void     ibus_engine_set_cursor_location
+static void      ibus_engine_destroy         (IBusEngine         *engine);
+static void      ibus_engine_set_property    (IBusEngine         *engine,
+                                              guint               prop_id,
+                                              const GValue       *value,
+                                              GParamSpec         *pspec);
+static void      ibus_engine_get_property    (IBusEngine         *engine,
+                                              guint               prop_id,
+                                              GValue             *value,
+                                              GParamSpec         *pspec);
+static void      ibus_engine_service_method_call
+                                              (IBusService        *service,
+                                               GDBusConnection    *connection,
+                                               const gchar        *sender,
+                                               const gchar        *object_path,
+                                               const gchar        *interface_name,
+                                               const gchar        *method_name,
+                                               GVariant           *parameters,
+                                               GDBusMethodInvocation
+                                                                  *invocation);
+static GVariant *ibus_engine_service_get_property
+                                             (IBusService        *service,
+                                              GDBusConnection    *connection,
+                                              const gchar        *sender,
+                                              const gchar        *object_path,
+                                              const gchar        *interface_name,
+                                              const gchar        *property_name,
+                                              GError            **error);
+static gboolean  ibus_engine_service_set_property
+                                             (IBusService        *service,
+                                              GDBusConnection    *connection,
+                                              const gchar        *sender,
+                                              const gchar        *object_path,
+                                              const gchar        *interface_name,
+                                              const gchar        *property_name,
+                                              GVariant           *value,
+                                              GError            **error);
+static gboolean  ibus_engine_process_key_event
+                                             (IBusEngine         *engine,
+                                              guint               keyval,
+                                              guint               keycode,
+                                              guint               state);
+static void      ibus_engine_focus_in        (IBusEngine         *engine);
+static void      ibus_engine_focus_out       (IBusEngine         *engine);
+static void      ibus_engine_reset           (IBusEngine         *engine);
+static void      ibus_engine_enable          (IBusEngine         *engine);
+static void      ibus_engine_disable         (IBusEngine         *engine);
+static void      ibus_engine_set_cursor_location
+                                             (IBusEngine         *engine,
+                                              gint                x,
+                                              gint                y,
+                                              gint                w,
+                                              gint                h);
+static void      ibus_engine_set_capabilities
+                                             (IBusEngine         *engine,
+                                              guint               caps);
+static void      ibus_engine_page_up         (IBusEngine         *engine);
+static void      ibus_engine_page_down       (IBusEngine         *engine);
+static void      ibus_engine_cursor_up       (IBusEngine         *engine);
+static void      ibus_engine_cursor_down     (IBusEngine         *engine);
+static void      ibus_engine_candidate_clicked
+                                             (IBusEngine         *engine,
+                                              guint               index,
+                                              guint               button,
+                                              guint               state);
+static void      ibus_engine_property_activate
+                                             (IBusEngine         *engine,
+                                              const gchar        *prop_name,
+                                              guint               prop_state);
+static void      ibus_engine_property_show   (IBusEngine         *engine,
+                                              const gchar        *prop_name);
+static void      ibus_engine_property_hide   (IBusEngine         *engine,
+                                              const gchar        *prop_name);
+static void      ibus_engine_set_surrounding_text
                                             (IBusEngine         *engine,
-                                             gint                x,
-                                             gint                y,
-                                             gint                w,
-                                             gint                h);
-static void     ibus_engine_set_capabilities
-                                            (IBusEngine         *engine,
-                                             guint               caps);
-static void     ibus_engine_page_up         (IBusEngine         *engine);
-static void     ibus_engine_page_down       (IBusEngine         *engine);
-static void     ibus_engine_cursor_up       (IBusEngine         *engine);
-static void     ibus_engine_cursor_down     (IBusEngine         *engine);
-static void     ibus_engine_property_activate
-                                            (IBusEngine         *engine,
-                                             const gchar        *prop_name,
-                                             guint               prop_state);
-static void     ibus_engine_property_show   (IBusEngine         *engine,
-                                             const gchar        *prop_name);
-static void     ibus_engine_property_hide   (IBusEngine         *engine,
-                                             const gchar        *prop_name);
-
-
-static IBusServiceClass  *parent_class = NULL;
-
-GType
-ibus_engine_get_type (void)
-{
-    static GType type = 0;
-
-    static const GTypeInfo type_info = {
-        sizeof (IBusEngineClass),
-        (GBaseInitFunc)     NULL,
-        (GBaseFinalizeFunc) NULL,
-        (GClassInitFunc)    ibus_engine_class_init,
-        NULL,               /* class finalize */
-        NULL,               /* class data */
-        sizeof (IBusEngine),
-        0,
-        (GInstanceInitFunc) ibus_engine_init,
-    };
-
-    if (type == 0) {
-        type = g_type_register_static (IBUS_TYPE_SERVICE,
-                    "IBusEngine",
-                    &type_info,
-                    (GTypeFlags) 0);
-    }
-    return type;
-}
-
-IBusEngine *
-ibus_engine_new (const gchar    *name,
-                 const gchar    *path,
-                 IBusConnection *connection)
-{
-    g_assert (path);
-    g_assert (IBUS_IS_CONNECTION (connection));
-
-    IBusEngine *engine;
-
-    engine = (IBusEngine *) g_object_new (IBUS_TYPE_ENGINE,
-                                          "name", name,
-                                          "path", path,
-                                          "connection", connection,
-                                          NULL);
-
-    return engine;
-}
+                                             IBusText           *text,
+                                             guint               cursor_pos,
+                                             guint               anchor_pos);
+static void      ibus_engine_process_hand_writing_event
+                                             (IBusEngine         *engine,
+                                              const gdouble      *coordinates,
+                                              guint               coordinates_len);
+static void      ibus_engine_cancel_hand_writing
+                                             (IBusEngine         *engine,
+                                              guint               n_strokes);
+static void      ibus_engine_emit_signal     (IBusEngine         *engine,
+                                              const gchar        *signal_name,
+                                              GVariant           *parameters);
+
+
+G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
+
+static const gchar introspection_xml[] =
+    "<node>"
+    "  <interface name='org.freedesktop.IBus.Engine'>"
+    /* FIXME methods */
+    "    <method name='ProcessKeyEvent'>"
+    "      <arg direction='in'  type='u' name='keyval' />"
+    "      <arg direction='in'  type='u' name='keycode' />"
+    "      <arg direction='in'  type='u' name='state' />"
+    "      <arg direction='out' type='b' />"
+    "    </method>"
+    "    <method name='SetCursorLocation'>"
+    "      <arg direction='in'  type='i' name='x' />"
+    "      <arg direction='in'  type='i' name='y' />"
+    "      <arg direction='in'  type='i' name='w' />"
+    "      <arg direction='in'  type='i' name='h' />"
+    "    </method>"
+    "    <method name='ProcessHandWritingEvent'>"
+    "      <arg direction='in'  type='ad' name='coordinates' />"
+    "    </method>"
+    "    <method name='CancelHandWriting'>"
+    "      <arg direction='in'  type='u' name='n_strokes' />"
+    "    </method>"
+    "    <method name='SetCapabilities'>"
+    "      <arg direction='in'  type='u' name='caps' />"
+    "    </method>"
+    "    <method name='PropertyActivate'>"
+    "      <arg direction='in'  type='s' name='name' />"
+    "      <arg direction='in'  type='u' name='state' />"
+    "    </method>"
+    "    <method name='PropertyShow'>"
+    "      <arg direction='in'  type='s' name='name' />"
+    "    </method>"
+    "    <method name='PropertyHide'>"
+    "      <arg direction='in'  type='s' name='name' />"
+    "    </method>"
+    "    <method name='CandidateClicked'>"
+    "      <arg direction='in'  type='u' name='index' />"
+    "      <arg direction='in'  type='u' name='button' />"
+    "      <arg direction='in'  type='u' name='state' />"
+    "    </method>"
+    "    <method name='FocusIn' />"
+    "    <method name='FocusOut' />"
+    "    <method name='Reset' />"
+    "    <method name='Enable' />"
+    "    <method name='Disable' />"
+    "    <method name='PageUp' />"
+    "    <method name='PageDown' />"
+    "    <method name='CursorUp' />"
+    "    <method name='CursorDown' />"
+    "    <method name='SetSurroundingText'>"
+    "      <arg direction='in'  type='v' name='text' />"
+    "      <arg direction='in'  type='u' name='cursor_pos' />"
+    "      <arg direction='in'  type='u' name='anchor_pos' />"
+    "    </method>"
+    /* FIXME signals */
+    "    <signal name='CommitText'>"
+    "      <arg type='v' name='text' />"
+    "    </signal>"
+    "    <signal name='UpdatePreeditText'>"
+    "      <arg type='v' name='text' />"
+    "      <arg type='u' name='cursor_pos' />"
+    "      <arg type='b' name='visible' />"
+    "      <arg type='u' name='mode' />"
+    "    </signal>"
+    "    <signal name='UpdateAuxiliaryText'>"
+    "      <arg type='v' name='text' />"
+    "      <arg type='b' name='visible' />"
+    "    </signal>"
+    "    <signal name='UpdateLookupTable'>"
+    "      <arg type='v' name='table' />"
+    "      <arg type='b' name='visible' />"
+    "    </signal>"
+    "    <signal name='RegisterProperties'>"
+    "      <arg type='v' name='props' />"
+    "    </signal>"
+    "    <signal name='UpdateProperty'>"
+    "      <arg type='v' name='prop' />"
+    "    </signal>"
+    "    <signal name='ForwardKeyEvent'>"
+    "      <arg type='u' name='keyval' />"
+    "      <arg type='u' name='keycode' />"
+    "      <arg type='u' name='state' />"
+    "    </signal>"
+    "  </interface>"
+    "</node>";
 
 static void
-ibus_engine_class_init (IBusEngineClass *klass)
+ibus_engine_class_init (IBusEngineClass *class)
 {
-    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
-
-    parent_class = (IBusServiceClass *) g_type_class_peek_parent (klass);
-
-    g_type_class_add_private (klass, sizeof (IBusEnginePrivate));
+    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
 
     gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
     gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
 
     ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
 
-    IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) ibus_engine_ibus_message;
-
-    klass->process_key_event = ibus_engine_process_key_event;
-    klass->focus_in     = ibus_engine_focus_in;
-    klass->focus_out    = ibus_engine_focus_out;
-    klass->reset        = ibus_engine_reset;
-    klass->enable       = ibus_engine_enable;
-    klass->disable      = ibus_engine_disable;
-    klass->page_up      = ibus_engine_page_up;
-    klass->page_down    = ibus_engine_page_down;
-    klass->cursor_up    = ibus_engine_cursor_up;
-    klass->cursor_down  = ibus_engine_cursor_down;
-    klass->property_activate    = ibus_engine_property_activate;
-    klass->property_show        = ibus_engine_property_show;
-    klass->property_hide        = ibus_engine_property_hide;
-    klass->set_cursor_location  = ibus_engine_set_cursor_location;
-    klass->set_capabilities     = ibus_engine_set_capabilities;
-
+    IBUS_SERVICE_CLASS (class)->service_method_call  = ibus_engine_service_method_call;
+    IBUS_SERVICE_CLASS (class)->service_get_property = ibus_engine_service_get_property;
+    IBUS_SERVICE_CLASS (class)->service_set_property = ibus_engine_service_set_property;
+
+    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
+
+    class->process_key_event = ibus_engine_process_key_event;
+    class->focus_in     = ibus_engine_focus_in;
+    class->focus_out    = ibus_engine_focus_out;
+    class->reset        = ibus_engine_reset;
+    class->enable       = ibus_engine_enable;
+    class->disable      = ibus_engine_disable;
+    class->page_up      = ibus_engine_page_up;
+    class->page_down    = ibus_engine_page_down;
+    class->cursor_up    = ibus_engine_cursor_up;
+    class->cursor_down  = ibus_engine_cursor_down;
+    class->candidate_clicked    = ibus_engine_candidate_clicked;
+    class->property_activate    = ibus_engine_property_activate;
+    class->property_show        = ibus_engine_property_show;
+    class->property_hide        = ibus_engine_property_hide;
+    class->set_cursor_location  = ibus_engine_set_cursor_location;
+    class->set_capabilities     = ibus_engine_set_capabilities;
+    class->set_surrounding_text = ibus_engine_set_surrounding_text;
+    class->process_hand_writing_event
+                                = ibus_engine_process_hand_writing_event;
+    class->cancel_hand_writing  = ibus_engine_cancel_hand_writing;
 
     /* install properties */
     /**
@@ -196,47 +297,44 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * Name of this IBusEngine.
      */
     g_object_class_install_property (gobject_class,
-                    PROP_NAME,
-                    g_param_spec_string ("name",
-                        "name",
+                    PROP_ENGINE_NAME,
+                    g_param_spec_string ("engine-name",
+                        "engine name",
                         "engine name",
                         "noname",
-                        G_PARAM_READWRITE |  G_PARAM_CONSTRUCT_ONLY));
-
-    /**
-     * IBusEngine:connection:
-     *
-     * Connection of this IBusEngine.
-     */
-    g_object_class_install_property (gobject_class,
-                    PROP_CONNECTION,
-                    g_param_spec_object ("connection",
-                        "connection",
-                        "The connection of engine object",
-                        IBUS_TYPE_CONNECTION,
-                        G_PARAM_READWRITE |  G_PARAM_CONSTRUCT_ONLY));
+                        G_PARAM_READWRITE |
+                        G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_STATIC_STRINGS));
 
     /* install signals */
     /**
      * IBusEngine::process-key-event:
      * @engine: An IBusEngine.
-     * @keyval: KeySym of the key press.
-     * @state: Key modifier flags
+     * @keyval: Key symbol of the key press.
+     * @keycode: KeyCode of the key press.
+     * @state: Key modifier flags.
      *
      * Emitted when a key event is received.
      * Implement the member function process_key_event() in extended class to receive this signal.
+     * Both the key symbol and keycode are passed to the member function.
+     * See ibus_input_context_process_key_event() for further explanation of
+     * key symbol, keycode and which to use.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * Returns: TRUE for successfully process the key; FALSE otherwise.
+     * See also:  ibus_input_context_process_key_event().
+     *
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[PROCESS_KEY_EVENT] =
         g_signal_new (I_("process-key-event"),
             G_TYPE_FROM_CLASS (gobject_class),
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, process_key_event),
-            NULL, NULL,
-            ibus_marshal_BOOL__UINT_UINT,
+            g_signal_accumulator_true_handled, NULL,
+            _ibus_marshal_BOOL__UINT_UINT_UINT,
             G_TYPE_BOOLEAN,
-            2,
+            3,
+            G_TYPE_UINT,
             G_TYPE_UINT,
             G_TYPE_UINT);
 
@@ -244,10 +342,11 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * IBusEngine::focus-in:
      * @engine: An IBusEngine.
      *
-     * Emitted  when the client application get the focus.
+     * Emitted when the client application get the focus.
      * Implement the member function focus_in() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also: ibus_input_context_focus_in()
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[FOCUS_IN] =
         g_signal_new (I_("focus-in"),
@@ -255,7 +354,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, focus_in),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -266,7 +365,8 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * Emitted when the client application  lost the focus.
      * Implement the member function focus_out() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also: ibus_input_context_focus_out()
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[FOCUS_OUT] =
         g_signal_new (I_("focus-out"),
@@ -274,7 +374,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, focus_out),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -285,7 +385,8 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * Emitted when the IME is reset.
      * Implement the member function reset() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also:  ibus_input_context_reset().
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[RESET] =
         g_signal_new (I_("reset"),
@@ -293,7 +394,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, reset),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -304,7 +405,8 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * Emitted when the IME is enabled.
      * Implement the member function set_enable() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also:  ibus_input_context_enable().
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[ENABLE] =
         g_signal_new (I_("enable"),
@@ -312,7 +414,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, enable),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -323,7 +425,8 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * Emitted when the IME is disabled.
      * Implement the member function set_disable() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also:  ibus_input_context_disable().
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[DISABLE] =
         g_signal_new (I_("disable"),
@@ -331,18 +434,23 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, disable),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
     /**
      * IBusEngine::set-cursor-location:
      * @engine: An IBusEngine.
+     * @x: X coordinate of the cursor.
+     * @y: Y coordinate of the cursor.
+     * @w: Width of the cursor.
+     * @h: Height of the cursor.
      *
      * Emitted when the location of IME is set.
      * Implement the member function set_cursor_location() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also:  ibus_input_context_set_cursor_location().
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[SET_CURSOR_LOCATION] =
         g_signal_new (I_("set-cursor-location"),
@@ -350,7 +458,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, set_cursor_location),
             NULL, NULL,
-            ibus_marshal_VOID__INT_INT_INT_INT,
+            _ibus_marshal_VOID__INT_INT_INT_INT,
             G_TYPE_NONE,
             4,
             G_TYPE_INT,
@@ -366,7 +474,8 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * Emitted when the client application capabilities is set.
      * Implement the member function set_capabilities() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * See also:  ibus_input_context_set_capabilities().
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[SET_CAPABILITIES] =
         g_signal_new (I_("set-capabilities"),
@@ -374,7 +483,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, set_capabilities),
             NULL, NULL,
-            ibus_marshal_VOID__UINT,
+            _ibus_marshal_VOID__UINT,
             G_TYPE_NONE,
             1,
             G_TYPE_UINT);
@@ -383,10 +492,10 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * IBusEngine::page-up:
      * @engine: An IBusEngine.
      *
-     * Emitted when the page-up key is pressed.
+     * Emitted when the page-up button is pressed.
      * Implement the member function page_up() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[PAGE_UP] =
         g_signal_new (I_("page-up"),
@@ -394,7 +503,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, page_up),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -402,10 +511,10 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * IBusEngine::page-down:
      * @engine: An IBusEngine.
      *
-     * Emitted when the page-down key is pressed.
+     * Emitted when the page-down button is pressed.
      * Implement the member function page_down() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[PAGE_DOWN] =
         g_signal_new (I_("page-down"),
@@ -413,7 +522,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, page_down),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -421,10 +530,10 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * IBusEngine::cursor-up:
      * @engine: An IBusEngine.
      *
-     * Emitted when the up cursor key is pressed.
+     * Emitted when the up cursor button is pressed.
      * Implement the member function cursor_up() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[CURSOR_UP] =
         g_signal_new (I_("cursor-up"),
@@ -432,7 +541,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, cursor_up),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
@@ -440,10 +549,10 @@ ibus_engine_class_init (IBusEngineClass *klass)
      * IBusEngine::cursor-down:
      * @engine: An IBusEngine.
      *
-     * Emitted when the down cursor key is pressed.
+     * Emitted when the down cursor button is pressed.
      * Implement the member function cursor_down() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[CURSOR_DOWN] =
         g_signal_new (I_("cursor-down"),
@@ -451,18 +560,45 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, cursor_down),
             NULL, NULL,
-            ibus_marshal_VOID__VOID,
+            _ibus_marshal_VOID__VOID,
             G_TYPE_NONE,
             0);
 
     /**
+     * IBusEngine::candidate-clicked:
+     * @engine: An IBusEngine.
+     * @index:  Index of candidate be clicked.
+     * @button: Mouse button.
+     * @state:  Keyboard state.
+     *
+     * Emitted when candidate on lookup table is clicked.
+     * Implement the member function candidate_clicked() in extended class to receive this signal.
+     *
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     */
+    engine_signals[CANDIDATE_CLICKED] =
+        g_signal_new (I_("candidate-clicked"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusEngineClass, candidate_clicked),
+            NULL, NULL,
+            _ibus_marshal_VOID__UINT_UINT_UINT,
+            G_TYPE_NONE,
+            3,
+            G_TYPE_UINT,
+            G_TYPE_UINT,
+            G_TYPE_UINT);
+
+    /**
      * IBusEngine::property-activate:
      * @engine: An IBusEngine.
+     * @name:   Property name.
+     * @state:  Property state.
      *
      * Emitted when a property is activated or change changed.
      * Implement the member function property_activate() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[PROPERTY_ACTIVATE] =
         g_signal_new (I_("property-activate"),
@@ -470,7 +606,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, property_activate),
             NULL, NULL,
-            ibus_marshal_VOID__STRING_UINT,
+            _ibus_marshal_VOID__STRING_UINT,
             G_TYPE_NONE,
             2,
             G_TYPE_STRING,
@@ -479,11 +615,12 @@ ibus_engine_class_init (IBusEngineClass *klass)
     /**
      * IBusEngine::property-show:
      * @engine: An IBusEngine.
+     * @name:   Property name.
      *
      * Emitted when a property is shown.
      * Implement the member function property_side() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[PROPERTY_SHOW] =
         g_signal_new (I_("property-show"),
@@ -491,7 +628,7 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, property_show),
             NULL, NULL,
-            ibus_marshal_VOID__STRING,
+            _ibus_marshal_VOID__STRING,
             G_TYPE_NONE,
             1,
             G_TYPE_STRING);
@@ -499,11 +636,12 @@ ibus_engine_class_init (IBusEngineClass *klass)
     /**
      * IBusEngine::property-hide:
      * @engine: An IBusEngine.
+     * @name:   Property name.
      *
      * Emitted when a property is hidden.
      * Implement the member function property_hide() in extended class to receive this signal.
      *
-     * <note><para>@user_data is not actually a valid parameter. It is displayed because GtkDoc.</para></note>
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
      */
     engine_signals[PROPERTY_HIDE] =
         g_signal_new (I_("property-hide"),
@@ -511,37 +649,108 @@ ibus_engine_class_init (IBusEngineClass *klass)
             G_SIGNAL_RUN_LAST,
             G_STRUCT_OFFSET (IBusEngineClass, property_hide),
             NULL, NULL,
-            ibus_marshal_VOID__STRING,
+            _ibus_marshal_VOID__STRING,
             G_TYPE_NONE,
             1,
             G_TYPE_STRING);
 
+    /**
+     * IBusEngine::process-hand-writing-event:
+     * @engine: An IBusEngine.
+     * @coordinates: An array of double (0.0 to 1.0) which represents a stroke (i.e. [x1, y1, x2, y2, x3, y3, ...]).
+     * @coordinates_len: The number of elements in the array.
+     *
+     * Emitted when a hand writing operation is cancelled.
+     * Implement the member function cancel_hand_writing() in extended class to receive this signal.
+     *
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     */
+    engine_signals[PROCESS_HAND_WRITING_EVENT] =
+        g_signal_new (I_("process-hand-writing-event"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusEngineClass, process_hand_writing_event),
+            NULL, NULL,
+            _ibus_marshal_VOID__POINTER_UINT,
+            G_TYPE_NONE,
+            2,
+            G_TYPE_POINTER,
+            G_TYPE_UINT);
+
+    /**
+     * IBusEngine::cancel-hand-writing:
+     * @engine: An IBusEngine.
+     * @n_strokes: The number of strokes to be removed. 0 means "remove all".
+     *
+     * Emitted when a hand writing operation is cancelled.
+     * Implement the member function cancel_hand_writing() in extended class to receive this signal.
+     *
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     */
+    engine_signals[CANCEL_HAND_WRITING] =
+        g_signal_new (I_("cancel-hand-writing"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusEngineClass, cancel_hand_writing),
+            NULL, NULL,
+            _ibus_marshal_VOID__UINT,
+            G_TYPE_NONE,
+            1,
+            G_TYPE_UINT);
+
+    g_type_class_add_private (class, sizeof (IBusEnginePrivate));
+
+    /**
+     * IBusEngine::set-surrounding-text:
+     * @engine: An IBusEngine.
+     * @text: The surrounding text.
+     * @cursor_pos: The cursor position on surrounding text.
+     * @anchor_pos: The anchor position on selection area.
+     *
+     * Emitted when a surrounding text is set.
+     * Implement the member function set_surrounding_text() in extended class to receive this signal.
+     * If anchor_pos equals to cursor_pos, it means "there are no selection" or "does not support
+     * selection retrival".
+     *
+     * <note><para>Argument @user_data is ignored in this function.</para></note>
+     */
+    engine_signals[SET_SURROUNDING_TEXT] =
+        g_signal_new (I_("set-surrounding-text"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusEngineClass, set_surrounding_text),
+            NULL, NULL,
+            _ibus_marshal_VOID__OBJECT_UINT_UINT,
+            G_TYPE_NONE,
+            3,
+            G_TYPE_OBJECT,
+            G_TYPE_UINT,
+            G_TYPE_UINT);
+
+    text_empty = ibus_text_new_from_static_string ("");
+    g_object_ref_sink (text_empty);
 }
 
 static void
 ibus_engine_init (IBusEngine *engine)
 {
-    IBusEnginePrivate *priv;
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
+    engine->priv = IBUS_ENGINE_GET_PRIVATE (engine);
 
-    priv->name = NULL;
-    priv->connection = NULL;
+    engine->priv->surrounding_text = g_object_ref_sink (text_empty);
 }
 
 static void
 ibus_engine_destroy (IBusEngine *engine)
 {
-    IBusEnginePrivate *priv;
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
+    g_free (engine->priv->engine_name);
+    engine->priv->engine_name = NULL;
 
-    g_free (priv->name);
-
-    if (priv->connection) {
-        g_object_unref (priv->connection);
-        priv->connection = NULL;
+    if (engine->priv->surrounding_text) {
+        g_object_unref (engine->priv->surrounding_text);
+        engine->priv->surrounding_text = NULL;
     }
 
-    IBUS_OBJECT_CLASS(parent_class)->destroy (IBUS_OBJECT (engine));
+    IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
 }
 
 static void
@@ -550,21 +759,10 @@ ibus_engine_set_property (IBusEngine   *engine,
                           const GValue *value,
                           GParamSpec   *pspec)
 {
-    IBusEnginePrivate *priv;
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
-
     switch (prop_id) {
-    case PROP_NAME:
-        priv->name = g_strdup (g_value_dup_string (value));
+    case PROP_ENGINE_NAME:
+        engine->priv->engine_name = g_value_dup_string (value);
         break;
-
-    case PROP_CONNECTION:
-        priv->connection = g_value_get_object (value);
-        g_object_ref (priv->connection);
-        ibus_service_add_to_connection ((IBusService *) engine,
-                                        priv->connection);
-        break;
-
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
     }
@@ -572,18 +770,13 @@ ibus_engine_set_property (IBusEngine   *engine,
 
 static void
 ibus_engine_get_property (IBusEngine *engine,
-    guint prop_id, GValue *value, GParamSpec *pspec)
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
 {
-    IBusEnginePrivate *priv;
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
-
     switch (prop_id) {
-    case PROP_NAME:
-        g_value_set_string (value, priv->name);
-        break;
-
-    case PROP_CONNECTION:
-        g_value_set_object (value, priv->connection);
+    case PROP_ENGINE_NAME:
+        g_value_set_string (value, engine->priv->engine_name);
         break;
 
     default:
@@ -591,216 +784,121 @@ ibus_engine_get_property (IBusEngine *engine,
     }
 }
 
-static gboolean
-ibus_engine_ibus_message (IBusEngine     *engine,
-                          IBusConnection *connection,
-                          IBusMessage    *message)
+static void
+ibus_engine_service_method_call (IBusService           *service,
+                                 GDBusConnection       *connection,
+                                 const gchar           *sender,
+                                 const gchar           *object_path,
+                                 const gchar           *interface_name,
+                                 const gchar           *method_name,
+                                 GVariant              *parameters,
+                                 GDBusMethodInvocation *invocation)
 {
-    g_assert (IBUS_IS_ENGINE (engine));
-    g_assert (IBUS_IS_CONNECTION (connection));
-    g_assert (message != NULL);
-
-    IBusEnginePrivate *priv;
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
-
-    g_assert (priv->connection == connection);
+    IBusEngine *engine = IBUS_ENGINE (service);
+
+    if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
+        IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
+                service_method_call (service,
+                                     connection,
+                                     sender,
+                                     object_path,
+                                     interface_name,
+                                     method_name,
+                                     parameters,
+                                     invocation);
+        return;
+    }
 
-    IBusMessage *return_message = NULL;
-    IBusMessage *error_message = NULL;
+    if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) {
+        guint keyval, keycode, state;
+        gboolean retval = FALSE;
+        g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state);
+        g_signal_emit (engine,
+                       engine_signals[PROCESS_KEY_EVENT],
+                       0,
+                       keyval,
+                       keycode,
+                       state,
+                       &retval);
+        g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval));
+        return;
+    }
 
     static const struct {
         gchar *member;
         guint  signal_id;
     } no_arg_methods[] = {
-        {"FocusIn",     FOCUS_IN},
-        {"FocusOut",    FOCUS_OUT},
-        {"Reset",       RESET},
-        {"Enable",      ENABLE},
-        {"Disable",     DISABLE},
-        {"PageUp",      PAGE_UP},
-        {"PageDown",    PAGE_DOWN},
-        {"CursorUp",    CURSOR_UP},
-        {"CursorDown",  CURSOR_DOWN},
-        {NULL, 0},
+        { "FocusIn",     FOCUS_IN },
+        { "FocusOut",    FOCUS_OUT },
+        { "Reset",       RESET },
+        { "Enable",      ENABLE },
+        { "Disable",     DISABLE },
+        { "PageUp",      PAGE_UP },
+        { "PageDown",    PAGE_DOWN },
+        { "CursorUp",    CURSOR_UP },
+        { "CursorDown",  CURSOR_DOWN },
     };
-    gint i;
 
-    for (i = 0; no_arg_methods[i].member != NULL; i++) {
-        if (!ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, no_arg_methods[i].member))
-            continue;
-
-        IBusMessageIter iter;
-        ibus_message_iter_init (message, &iter);
-        if (ibus_message_iter_has_next (&iter)) {
-            error_message = ibus_message_new_error_printf (message,
-                                DBUS_ERROR_INVALID_ARGS,
-                                "%s.%s: Method does not have arguments",
-                                IBUS_INTERFACE_ENGINE, no_arg_methods[i].member);
-            ibus_connection_send (connection, error_message);
-            ibus_message_unref (error_message);
-            return TRUE;
+    gint i;
+    for (i = 0; i < G_N_ELEMENTS (no_arg_methods); i++) {
+        if (g_strcmp0 (method_name, no_arg_methods[i].member) == 0) {
+            g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
+            g_dbus_method_invocation_return_value (invocation, NULL);
+            return;
         }
-
-        g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
-        return_message = ibus_message_new_method_return (message);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
     }
 
-
-    if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "ProcessKeyEvent")) {
-        guint keyval, state;
-        gboolean retval;
-        IBusError *error = NULL;
-
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_UINT, &keyval,
-                                        G_TYPE_UINT, &state,
-                                        G_TYPE_INVALID);
-
-        if (!retval)
-            goto _keypress_fail;
-
-        retval = FALSE;
+    if (g_strcmp0 (method_name, "CandidateClicked") == 0) {
+        guint index, button, state;
+        g_variant_get (parameters, "(uuu)", &index, &button, &state);
         g_signal_emit (engine,
-                       engine_signals[PROCESS_KEY_EVENT],
+                       engine_signals[CANDIDATE_CLICKED],
                        0,
-                       keyval,
-                       state,
-                       &retval);
-
-        return_message = ibus_message_new_method_return (message);
-        ibus_message_append_args (return_message,
-                                  G_TYPE_BOOLEAN, &retval,
-                                  G_TYPE_INVALID);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
-
-    _keypress_fail:
-        error_message = ibus_message_new_error_printf (message,
-                        DBUS_ERROR_INVALID_ARGS,
-                        "%s.%s: Can not match signature (ubu) of method",
-                        IBUS_INTERFACE_ENGINE, "ProcessKeyEvent");
-        ibus_connection_send (connection, error_message);
-        ibus_message_unref (error_message);
-        return TRUE;
+                       index,
+                       button,
+                       state);
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
     }
-    else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "PropertyActivate")) {
+
+    if (g_strcmp0 (method_name, "PropertyActivate") == 0) {
         gchar *name;
         guint state;
-        gboolean retval;
-        IBusError *error = NULL;
-
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_STRING, &name,
-                                        G_TYPE_UINT, &state,
-                                        G_TYPE_INVALID);
-
-        if (!retval)
-            goto _property_activate_fail;
-
+        g_variant_get (parameters, "(&su)", &name, &state);
         g_signal_emit (engine,
                        engine_signals[PROPERTY_ACTIVATE],
                        0,
                        name,
                        state);
-
-        return_message = ibus_message_new_method_return (message);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
-
-    _property_activate_fail:
-        error_message = ibus_message_new_error_printf (message,
-                        DBUS_ERROR_INVALID_ARGS,
-                        "%s.%s: Can not match signature (si) of method",
-                        IBUS_INTERFACE_ENGINE,
-                        "PropertyActivate");
-        ibus_connection_send (connection, error_message);
-        ibus_message_unref (error_message);
-        return TRUE;
-
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
     }
-    else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "PropertyShow")) {
-        gchar *name;
-        gboolean retval;
-        IBusError *error;
-
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_STRING, &name,
-                                        G_TYPE_INVALID);
-
-        if (!retval)
-            goto _property_show_fail;
 
+    if (g_strcmp0 (method_name, "PropertyShow") == 0) {
+        gchar *name;
+        g_variant_get (parameters, "(&s)", &name);
         g_signal_emit (engine,
                        engine_signals[PROPERTY_SHOW],
                        0,
                        name);
-
-        return_message = ibus_message_new_method_return (message);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
-
-    _property_show_fail:
-        error_message = ibus_message_new_error_printf (message,
-                        DBUS_ERROR_INVALID_ARGS,
-                        "%s.%s: Can not match signature (s) of method",
-                        IBUS_INTERFACE_ENGINE,
-                        "PropertyShow");
-        ibus_connection_send (connection, error_message);
-        ibus_message_unref (error_message);
-        return TRUE;
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
     }
-    else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "PropertyHide")) {
+
+    if (g_strcmp0 (method_name, "PropertyHide") == 0) {
         gchar *name;
-        gboolean retval;
-        IBusError *error = NULL;
-
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_STRING, &name,
-                                        G_TYPE_INVALID);
-        if (!retval)
-            goto _property_hide_fail;
-
-        g_signal_emit (engine, engine_signals[PROPERTY_HIDE], 0, name);
-
-        return_message = ibus_message_new_method_return (message);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
-
-    _property_hide_fail:
-        error_message = ibus_message_new_error_printf (message,
-                        DBUS_ERROR_INVALID_ARGS,
-                        "%s.%s: Can not match signature (s) of method",
-                        IBUS_INTERFACE_ENGINE, "PropertyHide");
-        ibus_connection_send (connection, error_message);
-        ibus_message_unref (error_message);
-        return TRUE;
+        g_variant_get (parameters, "(&s)", &name);
+        g_signal_emit (engine,
+                       engine_signals[PROPERTY_HIDE],
+                       0,
+                       name);
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
     }
-    else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "SetCursorLocation")) {
-        gint x, y, w, h;
-        gboolean retval;
-        IBusError *error = NULL;
-
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_INT, &x,
-                                        G_TYPE_INT, &y,
-                                        G_TYPE_INT, &w,
-                                        G_TYPE_INT, &h,
-                                        G_TYPE_INVALID);
-        if (!retval)
-            goto _set_cursor_location_fail;
 
+    if (g_strcmp0 (method_name, "SetCursorLocation") == 0) {
+        gint x, y, w, h;
+        g_variant_get (parameters, "(iiii)", &x, &y, &w, &h);
         engine->cursor_area.x = x;
         engine->cursor_area.y = y;
         engine->cursor_area.width = w;
@@ -810,71 +908,119 @@ ibus_engine_ibus_message (IBusEngine     *engine,
                        engine_signals[SET_CURSOR_LOCATION],
                        0,
                        x, y, w, h);
-
-        return_message = ibus_message_new_method_return (message);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
-
-    _set_cursor_location_fail:
-        error_message = ibus_message_new_error_printf (message,
-                        DBUS_ERROR_INVALID_ARGS,
-                        "%s.%s: Can not match signature (iiii) of method",
-                        IBUS_INTERFACE_ENGINE,
-                        "SetCursorLocation");
-        ibus_connection_send (connection, error_message);
-        ibus_message_unref (error_message);
-        return TRUE;
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
     }
-    else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "SetCapabilities")) {
+
+    if (g_strcmp0 (method_name, "SetCapabilities") == 0) {
         guint caps;
-        gboolean retval;
-        IBusError *error = NULL;
+        g_variant_get (parameters, "(u)", &caps);
+        engine->client_capabilities = caps;
+        g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
+    }
 
-        retval = ibus_message_get_args (message,
-                                        &error,
-                                        G_TYPE_UINT, &caps,
-                                        G_TYPE_INVALID);
+    if (g_strcmp0 (method_name, "SetSurroundingText") == 0) {
+        GVariant *variant = NULL;
+        IBusText *text;
+        guint cursor_pos;
+        guint anchor_pos;
+
+        g_variant_get (parameters,
+                       "(vuu)",
+                       &variant,
+                       &cursor_pos,
+                       &anchor_pos);
+        text = IBUS_TEXT (ibus_serializable_deserialize (variant));
+        g_variant_unref (variant);
+
+        g_signal_emit (engine, engine_signals[SET_SURROUNDING_TEXT],
+                       0,
+                       text,
+                       cursor_pos,
+                       anchor_pos);
+        if (g_object_is_floating (text)) {
+            g_object_unref (text);
+        }
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
+    }
 
-        if (!retval)
-            goto _set_capabilities_fail;
+    if (g_strcmp0 (method_name, "ProcessHandWritingEvent") == 0) {
+        const gdouble *coordinates;
+        gsize coordinates_len = 0;
 
-        engine->client_capabilities = caps;
+        coordinates = g_variant_get_fixed_array (g_variant_get_child_value (parameters, 0), &coordinates_len, sizeof (gdouble));
+        g_return_if_fail (coordinates != NULL);
+        g_return_if_fail (coordinates_len >= 4); /* The array should contain at least one line. */
+        g_return_if_fail (coordinates_len <= G_MAXUINT); /* to prevent overflow in the cast in g_signal_emit */
+        g_return_if_fail ((coordinates_len & 1) == 0);
 
-        g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
+        g_signal_emit (engine, engine_signals[PROCESS_HAND_WRITING_EVENT], 0,
+                       coordinates, (guint) coordinates_len);
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
+    }
 
-        return_message = ibus_message_new_method_return (message);
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
-        return TRUE;
-
-    _set_capabilities_fail:
-        error_message = ibus_message_new_error_printf (message,
-                        DBUS_ERROR_INVALID_ARGS,
-                        "%s.%s: Can not match signature (u) of method",
-                        IBUS_INTERFACE_ENGINE, "SetCapabilities");
-        ibus_connection_send (connection, error_message);
-        ibus_message_unref (error_message);
-        return TRUE;
+    if (g_strcmp0 (method_name, "CancelHandWriting") == 0) {
+        guint n_strokes = 0;
+        g_variant_get (parameters, "(u)", &n_strokes);
+        g_signal_emit (engine, engine_signals[CANCEL_HAND_WRITING], 0, n_strokes);
+        g_dbus_method_invocation_return_value (invocation, NULL);
+        return;
     }
-    else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "Destroy")) {
-        return_message = ibus_message_new_method_return (message);
 
-        ibus_connection_send (connection, return_message);
-        ibus_message_unref (return_message);
+    /* should not be reached */
+    g_return_if_reached ();
+}
 
-        ibus_object_destroy ((IBusObject *) engine);
-    }
+static GVariant *
+ibus_engine_service_get_property (IBusService        *service,
+                                  GDBusConnection    *connection,
+                                  const gchar        *sender,
+                                  const gchar        *object_path,
+                                  const gchar        *interface_name,
+                                  const gchar        *property_name,
+                                  GError            **error)
+{
+    return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
+                service_get_property (service,
+                                      connection,
+                                      sender,
+                                      object_path,
+                                      interface_name,
+                                      property_name,
+                                      error);
+}
 
-    return parent_class->ibus_message ((IBusService *) engine, connection, message);
+static gboolean
+ibus_engine_service_set_property (IBusService        *service,
+                                  GDBusConnection    *connection,
+                                  const gchar        *sender,
+                                  const gchar        *object_path,
+                                  const gchar        *interface_name,
+                                  const gchar        *property_name,
+                                  GVariant           *value,
+                                  GError            **error)
+{
+    return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
+                service_set_property (service,
+                                      connection,
+                                      sender,
+                                      object_path,
+                                      interface_name,
+                                      property_name,
+                                      value,
+                                      error);
 }
 
 static gboolean
 ibus_engine_process_key_event (IBusEngine *engine,
                                guint       keyval,
+                               guint       keycode,
                                guint       state)
 {
-    // g_debug ("process-key-event (%d, %d)", keyval, state);
     return FALSE;
 }
 
@@ -950,6 +1096,15 @@ ibus_engine_cursor_down (IBusEngine *engine)
 }
 
 static void
+ibus_engine_candidate_clicked (IBusEngine *engine,
+                               guint       index,
+                               guint       button,
+                               guint       state)
+{
+    // g_debug ("candidate-clicked");
+}
+
+static void
 ibus_engine_property_activate (IBusEngine  *engine,
                                const gchar *prop_name,
                                guint        prop_state)
@@ -970,40 +1125,100 @@ ibus_engine_property_hide (IBusEngine *engine, const gchar *prop_name)
 }
 
 static void
-_send_signal (IBusEngine  *engine,
-              const gchar *name,
-              GType        first_arg_type,
-              ...)
+ibus_engine_set_surrounding_text (IBusEngine *engine,
+                                  IBusText   *text,
+                                  guint       cursor_pos,
+                                  guint       anchor_pos)
 {
     g_assert (IBUS_IS_ENGINE (engine));
-    g_assert (name != NULL);
 
-    va_list args;
-    const gchar *path;
-    IBusEnginePrivate *priv;
+    if (engine->priv->surrounding_text) {
+        g_object_unref (engine->priv->surrounding_text);
+    }
 
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
+    engine->priv->surrounding_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
+    engine->priv->surrounding_cursor_pos = cursor_pos;
+    engine->priv->selection_anchor_pos = anchor_pos;
+    // g_debug ("set-surrounding-text ('%s', %d, %d)", text->text, cursor_pos, anchor_pos);
+}
+
+static void
+ibus_engine_process_hand_writing_event (IBusEngine         *engine,
+                                        const gdouble      *coordinates,
+                                        guint               coordinates_len)
+{
+    // guint i;
+    // g_debug ("process-hand-writing-event (%u)", coordinates_len);
+    // for (i = 0; i < coordinates_len; i++)
+    //     g_debug (" %lf", coordinates[i]);
+}
 
-    path = ibus_service_get_path ((IBusService *)engine);
+static void
+ibus_engine_cancel_hand_writing (IBusEngine         *engine,
+                                 guint               n_strokes)
+{
+    // g_debug ("cancel-hand-writing (%u)", n_strokes);
+}
 
-    va_start (args, first_arg_type);
-    ibus_connection_send_signal_valist (priv->connection,
-                                        path,
-                                        IBUS_INTERFACE_ENGINE,
-                                        name,
-                                        first_arg_type,
-                                        args);
-    va_end (args);
+static void
+ibus_engine_emit_signal (IBusEngine  *engine,
+                         const gchar *signal_name,
+                         GVariant    *parameters)
+{
+    ibus_service_emit_signal ((IBusService *)engine,
+                              NULL,
+                              IBUS_INTERFACE_ENGINE,
+                              signal_name,
+                              parameters,
+                              NULL);
 }
 
+IBusEngine *
+ibus_engine_new (const gchar     *engine_name,
+                 const gchar     *object_path,
+                 GDBusConnection *connection)
+{
+    return ibus_engine_new_with_type (IBUS_TYPE_ENGINE,
+                                      engine_name,
+                                      object_path,
+                                      connection);
+}
+
+IBusEngine  *
+ibus_engine_new_with_type (GType            engine_type,
+                           const gchar     *engine_name,
+                           const gchar     *object_path,
+                           GDBusConnection *connection)
+{
+    g_return_val_if_fail (g_type_is_a (engine_type, IBUS_TYPE_ENGINE), NULL);
+    g_return_val_if_fail (engine_name != NULL, NULL);
+    g_return_val_if_fail (object_path != NULL, NULL);
+    g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+
+    GObject *object = g_object_new (engine_type,
+                                    "engine-name", engine_name,
+                                    "object-path", object_path,
+                                    "connection", connection,
+                                    NULL);
+    return IBUS_ENGINE (object);
+}
+
+
 void
 ibus_engine_commit_text (IBusEngine *engine,
                          IBusText   *text)
 {
-    _send_signal (engine,
-                  "CommitText",
-                  IBUS_TYPE_TEXT, &text,
-                  G_TYPE_INVALID);
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_TEXT (text));
+
+    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
+    ibus_engine_emit_signal (engine,
+                             "CommitText",
+                             g_variant_new ("(v)", variant));
+
+    if (g_object_is_floating (text)) {
+        g_object_unref (text);
+    }
 }
 
 void
@@ -1012,66 +1227,64 @@ ibus_engine_update_preedit_text (IBusEngine      *engine,
                                  guint            cursor_pos,
                                  gboolean         visible)
 {
-    _send_signal (engine,
-                  "UpdatePreeditText",
-                  IBUS_TYPE_TEXT, &text,
-                  G_TYPE_UINT, &cursor_pos,
-                  G_TYPE_BOOLEAN, &visible,
-                  G_TYPE_INVALID);
+    ibus_engine_update_preedit_text_with_mode (engine,
+            text, cursor_pos, visible, IBUS_ENGINE_PREEDIT_CLEAR);
 }
 
 void
-ibus_engine_show_preedit_text (IBusEngine *engine)
+ibus_engine_update_preedit_text_with_mode (IBusEngine            *engine,
+                                           IBusText              *text,
+                                           guint                  cursor_pos,
+                                           gboolean               visible,
+                                           IBusPreeditFocusMode   mode)
 {
-    _send_signal (engine,
-                  "ShowPreeditText",
-                  G_TYPE_INVALID);
-}
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_TEXT (text));
 
-void ibus_engine_hide_preedit_text (IBusEngine *engine)
-{
-    _send_signal (engine,
-                  "HidePreeditText",
-                  G_TYPE_INVALID);
+    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
+    ibus_engine_emit_signal (engine,
+                             "UpdatePreeditText",
+                             g_variant_new ("(vubu)", variant, cursor_pos, visible, mode));
+
+    if (g_object_is_floating (text)) {
+        g_object_unref (text);
+    }
 }
 
 void ibus_engine_update_auxiliary_text (IBusEngine      *engine,
                                         IBusText        *text,
                                         gboolean         visible)
 {
-    _send_signal (engine,
-                  "UpdateAuxiliaryText",
-                  IBUS_TYPE_TEXT, &text,
-                  G_TYPE_BOOLEAN, &visible,
-                  G_TYPE_INVALID);
-}
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_TEXT (text));
 
-void
-ibus_engine_show_auxiliary_text (IBusEngine *engine)
-{
-    _send_signal (engine,
-                  "ShowAuxiliaryText",
-                  G_TYPE_INVALID);
-}
+    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
+    ibus_engine_emit_signal (engine,
+                             "UpdateAuxiliaryText",
+                             g_variant_new ("(vb)", variant, visible));
 
-void
-ibus_engine_hide_auxiliary_text (IBusEngine *engine)
-{
-    _send_signal (engine,
-                  "HideAuxiliaryText",
-                  G_TYPE_INVALID);
+    if (g_object_is_floating (text)) {
+        g_object_unref (text);
+    }
 }
 
+
 void
 ibus_engine_update_lookup_table (IBusEngine        *engine,
                                  IBusLookupTable   *table,
                                  gboolean           visible)
 {
-    _send_signal (engine,
-                  "UpdateLookupTable",
-                  IBUS_TYPE_LOOKUP_TABLE, &table,
-                  G_TYPE_BOOLEAN, &visible,
-                  G_TYPE_INVALID);
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
+
+    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)table);
+    ibus_engine_emit_signal (engine,
+                             "UpdateLookupTable",
+                             g_variant_new ("(vb)", variant, visible));
+
+    if (g_object_is_floating (table)) {
+        g_object_unref (table);
+    }
 }
 
 void
@@ -1079,7 +1292,11 @@ ibus_engine_update_lookup_table_fast (IBusEngine        *engine,
                                       IBusLookupTable   *table,
                                       gboolean           visible)
 {
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
+
     IBusLookupTable *new_table;
+    IBusText *text;
     gint page_begin;
     gint i;
 
@@ -1096,66 +1313,170 @@ ibus_engine_update_lookup_table_fast (IBusEngine        *engine,
         ibus_lookup_table_append_candidate (new_table, ibus_lookup_table_get_candidate (table, i));
     }
 
+    for (i = 0; (text = ibus_lookup_table_get_label (table, i)) != NULL; i++) {
+        ibus_lookup_table_append_label (new_table, text);
+    }
+
     ibus_lookup_table_set_cursor_pos (new_table, ibus_lookup_table_get_cursor_in_page (table));
+    ibus_lookup_table_set_orientation (new_table, ibus_lookup_table_get_orientation (table));
 
     ibus_engine_update_lookup_table (engine, new_table, visible);
 
-    g_object_unref (new_table);
+    if (g_object_is_floating (table)) {
+        g_object_unref (table);
+    }
 }
 
-void ibus_engine_show_lookup_table (IBusEngine *engine)
+void
+ibus_engine_forward_key_event (IBusEngine      *engine,
+                               guint            keyval,
+                               guint            keycode,
+                               guint            state)
 {
-    _send_signal (engine,
-                  "ShowLookupTable",
-                  G_TYPE_INVALID);
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+
+    ibus_engine_emit_signal (engine,
+                             "ForwardKeyEvent",
+                             g_variant_new ("(uuu)", keyval, keycode, state));
 }
 
-void ibus_engine_hide_lookup_table (IBusEngine *engine)
+void ibus_engine_delete_surrounding_text (IBusEngine      *engine,
+                                          gint             offset_from_cursor,
+                                          guint            nchars)
 {
-    _send_signal (engine,
-                  "HideLookupTable",
-                  G_TYPE_INVALID);
+    IBusEnginePrivate *priv;
+
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+
+    priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+    /* Update surrounding-text cache.  This is necessary since some
+       engines call ibus_engine_get_surrounding_text() immediately
+       after ibus_engine_delete_surrounding_text(). */
+    if (priv->surrounding_text) {
+        IBusText *text;
+        glong cursor_pos, len;
+
+        cursor_pos = priv->surrounding_cursor_pos + offset_from_cursor;
+        len = ibus_text_get_length (priv->surrounding_text);
+        if (cursor_pos >= 0 && len - cursor_pos >= nchars) {
+            gunichar *ucs;
+
+            ucs = g_utf8_to_ucs4_fast (priv->surrounding_text->text,
+                                       -1,
+                                       NULL);
+            memmove (&ucs[cursor_pos],
+                     &ucs[cursor_pos + nchars],
+                     sizeof(gunichar) * (len - cursor_pos - nchars));
+            ucs[len - nchars] = 0;
+            text = ibus_text_new_from_ucs4 (ucs);
+            g_free (ucs);
+            priv->surrounding_cursor_pos = cursor_pos;
+        } else {
+            text = text_empty;
+            priv->surrounding_cursor_pos = 0;
+        }
+
+        g_object_unref (priv->surrounding_text);
+        priv->surrounding_text = g_object_ref_sink (text);
+    }
+
+    ibus_engine_emit_signal (engine,
+                             "DeleteSurroundingText",
+                             g_variant_new ("(iu)", offset_from_cursor, nchars));
 }
 
-void ibus_engine_forward_key_event (IBusEngine      *engine,
-                                    guint            keyval,
-                                    guint            state)
+void
+ibus_engine_get_surrounding_text (IBusEngine   *engine,
+                                  IBusText    **text,
+                                  guint        *cursor_pos,
+                                  guint        *anchor_pos)
 {
-    _send_signal (engine,
-                  "ForwardKeyEvent",
-                  G_TYPE_UINT, &keyval,
-                  G_TYPE_UINT, &state,
-                  G_TYPE_INVALID);
+    IBusEnginePrivate *priv;
+
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    const gboolean signal_only = (text == NULL);
+
+    g_return_if_fail (( signal_only && (cursor_pos == NULL)) ||
+                      (!signal_only && (cursor_pos != NULL)));
+
+    g_return_if_fail (( signal_only && (anchor_pos == NULL)) ||
+                      (!signal_only && (anchor_pos != NULL)));
+
+    priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+    if (!signal_only) {
+        *text = g_object_ref (priv->surrounding_text);
+        *cursor_pos = priv->surrounding_cursor_pos;
+        *anchor_pos = priv->selection_anchor_pos;
+    }
+
+    /* tell the client that this engine will utilize surrounding-text
+     * feature, which causes periodical update.  Note that the client
+     * should request the initial surrounding-text when the engine is
+     * enabled (see ibus_im_context_focus_in() and
+     * _ibus_context_enabled_cb() in client/gtk2/ibusimcontext.c). */
+    ibus_engine_emit_signal (engine,
+                             "RequireSurroundingText",
+                             NULL);
+
+    // g_debug ("get-surrounding-text ('%s', %d, %d)", (*text)->text, *cursor_pos, *anchor_pos);
 }
 
 void
 ibus_engine_register_properties (IBusEngine   *engine,
                                  IBusPropList *prop_list)
 {
-    _send_signal (engine,
-                  "RegisterProperties",
-                  IBUS_TYPE_PROP_LIST, &prop_list,
-                  G_TYPE_INVALID);
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_PROP_LIST (prop_list));
+
+    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop_list);
+    ibus_engine_emit_signal (engine,
+                             "RegisterProperties",
+                             g_variant_new ("(v)", variant));
+
+    if (g_object_is_floating (prop_list)) {
+        g_object_unref (prop_list);
+    }
 }
 
 void
 ibus_engine_update_property (IBusEngine   *engine,
                              IBusProperty *prop)
 {
-    _send_signal (engine,
-                  "UpdateProperty",
-                  IBUS_TYPE_PROPERTY, &prop,
-                  G_TYPE_INVALID);
+    g_return_if_fail (IBUS_IS_ENGINE (engine));
+    g_return_if_fail (IBUS_IS_PROPERTY (prop));
+
+    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
+    ibus_engine_emit_signal (engine,
+                             "UpdateProperty",
+                             g_variant_new ("(v)", variant));
+
+    if (g_object_is_floating (prop)) {
+        g_object_unref (prop);
+    }
 }
 
+#define DEFINE_FUNC(name, Name)                             \
+    void                                                    \
+    ibus_engine_##name (IBusEngine *engine)                 \
+    {                                                       \
+        g_return_if_fail (IBUS_IS_ENGINE (engine));         \
+        ibus_engine_emit_signal (engine,                    \
+                              #Name,                        \
+                              NULL);                        \
+    }
+DEFINE_FUNC (show_preedit_text, ShowPreeditText)
+DEFINE_FUNC (hide_preedit_text, HidePreeditText)
+DEFINE_FUNC (show_auxiliary_text, ShowAuxiliaryText)
+DEFINE_FUNC (hide_auxiliary_text, HideAuxiliaryText)
+DEFINE_FUNC (show_lookup_table, ShowLookupTable)
+DEFINE_FUNC (hide_lookup_table, HideLookupTable)
+#undef DEFINE_FUNC
+
 const gchar *
 ibus_engine_get_name (IBusEngine *engine)
 {
-    g_assert (IBUS_IS_ENGINE (engine));
-
-    IBusEnginePrivate *priv;
-    priv = IBUS_ENGINE_GET_PRIVATE (engine);
-
-    return priv->name;
+    g_return_val_if_fail (IBUS_IS_ENGINE (engine), NULL);
+    return engine->priv->engine_name;
 }
-