c367f145f25d8e19738e04994a5481ad7addbeed
[platform/upstream/ibus.git] / src / ibusengine.c
1 /* vim:set et sts=4: */
2 /* ibus - The Input Bus
3  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
4  * Copyright (C) 2008-2010 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <stdarg.h>
23 #include "ibusengine.h"
24 #include "ibusinternal.h"
25 #include "ibusshare.h"
26
27 #define IBUS_ENGINE_GET_PRIVATE(o)  \
28    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE, IBusEnginePrivate))
29
30 enum {
31     PROCESS_KEY_EVENT,
32     FOCUS_IN,
33     FOCUS_OUT,
34     RESET,
35     ENABLE,
36     DISABLE,
37     SET_CURSOR_LOCATION,
38     SET_CAPABILITIES,
39     PAGE_UP,
40     PAGE_DOWN,
41     CURSOR_UP,
42     CURSOR_DOWN,
43     PROPERTY_ACTIVATE,
44     PROPERTY_SHOW,
45     PROPERTY_HIDE,
46     CANDIDATE_CLICKED,
47     LAST_SIGNAL,
48 };
49
50 enum {
51     PROP_0,
52     PROP_NAME,
53     PROP_CONNECTION,
54 };
55
56
57 /* IBusEnginePriv */
58 struct _IBusEnginePrivate {
59     gchar *name;
60     IBusConnection *connection;
61 };
62 typedef struct _IBusEnginePrivate IBusEnginePrivate;
63
64 static guint            engine_signals[LAST_SIGNAL] = { 0 };
65
66 /* functions prototype */
67 static void     ibus_engine_destroy         (IBusEngine         *engine);
68 static void     ibus_engine_set_property    (IBusEngine         *engine,
69                                              guint               prop_id,
70                                              const GValue       *value,
71                                              GParamSpec         *pspec);
72 static void     ibus_engine_get_property    (IBusEngine         *engine,
73                                              guint               prop_id,
74                                              GValue             *value,
75                                              GParamSpec         *pspec);
76 static gboolean ibus_engine_ibus_message    (IBusEngine         *engine,
77                                              IBusConnection     *connection,
78                                              IBusMessage        *message);
79 static gboolean ibus_engine_process_key_event
80                                             (IBusEngine         *engine,
81                                              guint               keyval,
82                                              guint               keycode,
83                                              guint               state);
84 static void     ibus_engine_focus_in        (IBusEngine         *engine);
85 static void     ibus_engine_focus_out       (IBusEngine         *engine);
86 static void     ibus_engine_reset           (IBusEngine         *engine);
87 static void     ibus_engine_enable          (IBusEngine         *engine);
88 static void     ibus_engine_disable         (IBusEngine         *engine);
89 static void     ibus_engine_set_cursor_location
90                                             (IBusEngine         *engine,
91                                              gint                x,
92                                              gint                y,
93                                              gint                w,
94                                              gint                h);
95 static void     ibus_engine_set_capabilities
96                                             (IBusEngine         *engine,
97                                              guint               caps);
98 static void     ibus_engine_page_up         (IBusEngine         *engine);
99 static void     ibus_engine_page_down       (IBusEngine         *engine);
100 static void     ibus_engine_cursor_up       (IBusEngine         *engine);
101 static void     ibus_engine_cursor_down     (IBusEngine         *engine);
102 static void     ibus_engine_candidate_clicked
103                                             (IBusEngine         *engine,
104                                              guint               index,
105                                              guint               button,
106                                              guint               state);
107 static void     ibus_engine_property_activate
108                                             (IBusEngine         *engine,
109                                              const gchar        *prop_name,
110                                              guint               prop_state);
111 static void     ibus_engine_property_show   (IBusEngine         *engine,
112                                              const gchar        *prop_name);
113 static void     ibus_engine_property_hide   (IBusEngine         *engine,
114                                              const gchar        *prop_name);
115
116
117 G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
118
119 IBusEngine *
120 ibus_engine_new (const gchar    *name,
121                  const gchar    *path,
122                  IBusConnection *connection)
123 {
124     g_assert (path);
125     g_assert (IBUS_IS_CONNECTION (connection));
126
127     IBusEngine *engine;
128
129     engine = (IBusEngine *) g_object_new (IBUS_TYPE_ENGINE,
130                                           "name", name,
131                                           "path", path,
132                                           "connection", connection,
133                                           NULL);
134
135     return engine;
136 }
137
138 static void
139 ibus_engine_class_init (IBusEngineClass *klass)
140 {
141     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142     IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
143
144     g_type_class_add_private (klass, sizeof (IBusEnginePrivate));
145
146     gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
147     gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
148
149     ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
150
151     IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) ibus_engine_ibus_message;
152
153     klass->process_key_event = ibus_engine_process_key_event;
154     klass->focus_in     = ibus_engine_focus_in;
155     klass->focus_out    = ibus_engine_focus_out;
156     klass->reset        = ibus_engine_reset;
157     klass->enable       = ibus_engine_enable;
158     klass->disable      = ibus_engine_disable;
159     klass->page_up      = ibus_engine_page_up;
160     klass->page_down    = ibus_engine_page_down;
161     klass->cursor_up    = ibus_engine_cursor_up;
162     klass->cursor_down  = ibus_engine_cursor_down;
163     klass->candidate_clicked    = ibus_engine_candidate_clicked;
164     klass->property_activate    = ibus_engine_property_activate;
165     klass->property_show        = ibus_engine_property_show;
166     klass->property_hide        = ibus_engine_property_hide;
167     klass->set_cursor_location  = ibus_engine_set_cursor_location;
168     klass->set_capabilities     = ibus_engine_set_capabilities;
169
170
171     /* install properties */
172     /**
173      * IBusEngine:name:
174      *
175      * Name of this IBusEngine.
176      */
177     g_object_class_install_property (gobject_class,
178                     PROP_NAME,
179                     g_param_spec_string ("name",
180                         "name",
181                         "engine name",
182                         "noname",
183                         G_PARAM_READWRITE |  G_PARAM_CONSTRUCT_ONLY));
184
185     /**
186      * IBusEngine:connection:
187      *
188      * Connection of this IBusEngine.
189      */
190     g_object_class_install_property (gobject_class,
191                     PROP_CONNECTION,
192                     g_param_spec_object ("connection",
193                         "connection",
194                         "The connection of engine object",
195                         IBUS_TYPE_CONNECTION,
196                         G_PARAM_READWRITE |  G_PARAM_CONSTRUCT_ONLY));
197
198     /* install signals */
199     /**
200      * IBusEngine::process-key-event:
201      * @engine: An IBusEngine.
202      * @keyval: Key symbol of the key press.
203      * @keycode: KeyCode of the key press.
204      * @state: Key modifier flags.
205      *
206      * Emitted when a key event is received.
207      * Implement the member function process_key_event() in extended class to receive this signal.
208      * Both the key symbol and keycode are passed to the member function.
209      * See ibus_input_context_process_key_event() for further explanation of
210      * key symbol, keycode and which to use.
211      *
212      * Returns: TRUE for successfully process the key; FALSE otherwise.
213      * See also:  ibus_input_context_process_key_event().
214      *
215      * <note><para>Argument @user_data is ignored in this function.</para></note>
216      */
217     engine_signals[PROCESS_KEY_EVENT] =
218         g_signal_new (I_("process-key-event"),
219             G_TYPE_FROM_CLASS (gobject_class),
220             G_SIGNAL_RUN_LAST,
221             G_STRUCT_OFFSET (IBusEngineClass, process_key_event),
222             NULL, NULL,
223             ibus_marshal_BOOL__UINT_UINT_UINT,
224             G_TYPE_BOOLEAN,
225             3,
226             G_TYPE_UINT,
227             G_TYPE_UINT,
228             G_TYPE_UINT);
229
230     /**
231      * IBusEngine::focus-in:
232      * @engine: An IBusEngine.
233      *
234      * Emitted when the client application get the focus.
235      * Implement the member function focus_in() in extended class to receive this signal.
236      *
237      * See also: ibus_input_context_focus_in()
238      * <note><para>Argument @user_data is ignored in this function.</para></note>
239      */
240     engine_signals[FOCUS_IN] =
241         g_signal_new (I_("focus-in"),
242             G_TYPE_FROM_CLASS (gobject_class),
243             G_SIGNAL_RUN_LAST,
244             G_STRUCT_OFFSET (IBusEngineClass, focus_in),
245             NULL, NULL,
246             ibus_marshal_VOID__VOID,
247             G_TYPE_NONE,
248             0);
249
250     /**
251      * IBusEngine::focus-out:
252      * @engine: An IBusEngine.
253      *
254      * Emitted when the client application  lost the focus.
255      * Implement the member function focus_out() in extended class to receive this signal.
256      *
257      * See also: ibus_input_context_focus_out()
258      * <note><para>Argument @user_data is ignored in this function.</para></note>
259      */
260     engine_signals[FOCUS_OUT] =
261         g_signal_new (I_("focus-out"),
262             G_TYPE_FROM_CLASS (gobject_class),
263             G_SIGNAL_RUN_LAST,
264             G_STRUCT_OFFSET (IBusEngineClass, focus_out),
265             NULL, NULL,
266             ibus_marshal_VOID__VOID,
267             G_TYPE_NONE,
268             0);
269
270     /**
271      * IBusEngine::reset:
272      * @engine: An IBusEngine.
273      *
274      * Emitted when the IME is reset.
275      * Implement the member function reset() in extended class to receive this signal.
276      *
277      * See also:  ibus_input_context_reset().
278      * <note><para>Argument @user_data is ignored in this function.</para></note>
279      */
280     engine_signals[RESET] =
281         g_signal_new (I_("reset"),
282             G_TYPE_FROM_CLASS (gobject_class),
283             G_SIGNAL_RUN_LAST,
284             G_STRUCT_OFFSET (IBusEngineClass, reset),
285             NULL, NULL,
286             ibus_marshal_VOID__VOID,
287             G_TYPE_NONE,
288             0);
289
290     /**
291      * IBusEngine::enable:
292      * @engine: An IBusEngine.
293      *
294      * Emitted when the IME is enabled.
295      * Implement the member function set_enable() in extended class to receive this signal.
296      *
297      * See also:  ibus_input_context_enable().
298      * <note><para>Argument @user_data is ignored in this function.</para></note>
299      */
300     engine_signals[ENABLE] =
301         g_signal_new (I_("enable"),
302             G_TYPE_FROM_CLASS (gobject_class),
303             G_SIGNAL_RUN_LAST,
304             G_STRUCT_OFFSET (IBusEngineClass, enable),
305             NULL, NULL,
306             ibus_marshal_VOID__VOID,
307             G_TYPE_NONE,
308             0);
309
310     /**
311      * IBusEngine::disable:
312      * @engine: An IBusEngine.
313      *
314      * Emitted when the IME is disabled.
315      * Implement the member function set_disable() in extended class to receive this signal.
316      *
317      * See also:  ibus_input_context_disable().
318      * <note><para>Argument @user_data is ignored in this function.</para></note>
319      */
320     engine_signals[DISABLE] =
321         g_signal_new (I_("disable"),
322             G_TYPE_FROM_CLASS (gobject_class),
323             G_SIGNAL_RUN_LAST,
324             G_STRUCT_OFFSET (IBusEngineClass, disable),
325             NULL, NULL,
326             ibus_marshal_VOID__VOID,
327             G_TYPE_NONE,
328             0);
329
330     /**
331      * IBusEngine::set-cursor-location:
332      * @engine: An IBusEngine.
333      * @x: X coordinate of the cursor.
334      * @y: Y coordinate of the cursor.
335      * @w: Width of the cursor.
336      * @h: Height of the cursor.
337      *
338      * Emitted when the location of IME is set.
339      * Implement the member function set_cursor_location() in extended class to receive this signal.
340      *
341      * See also:  ibus_input_context_set_cursor_location().
342      * <note><para>Argument @user_data is ignored in this function.</para></note>
343      */
344     engine_signals[SET_CURSOR_LOCATION] =
345         g_signal_new (I_("set-cursor-location"),
346             G_TYPE_FROM_CLASS (gobject_class),
347             G_SIGNAL_RUN_LAST,
348             G_STRUCT_OFFSET (IBusEngineClass, set_cursor_location),
349             NULL, NULL,
350             ibus_marshal_VOID__INT_INT_INT_INT,
351             G_TYPE_NONE,
352             4,
353             G_TYPE_INT,
354             G_TYPE_INT,
355             G_TYPE_INT,
356             G_TYPE_INT);
357
358     /**
359      * IBusEngine::set-capabilities:
360      * @engine: An IBusEngine.
361      * @caps: Capabilities flags of IBusEngine, see #IBusCapabilite
362      *
363      * Emitted when the client application capabilities is set.
364      * Implement the member function set_capabilities() in extended class to receive this signal.
365      *
366      * See also:  ibus_input_context_set_capabilities().
367      * <note><para>Argument @user_data is ignored in this function.</para></note>
368      */
369     engine_signals[SET_CAPABILITIES] =
370         g_signal_new (I_("set-capabilities"),
371             G_TYPE_FROM_CLASS (gobject_class),
372             G_SIGNAL_RUN_LAST,
373             G_STRUCT_OFFSET (IBusEngineClass, set_capabilities),
374             NULL, NULL,
375             ibus_marshal_VOID__UINT,
376             G_TYPE_NONE,
377             1,
378             G_TYPE_UINT);
379
380     /**
381      * IBusEngine::page-up:
382      * @engine: An IBusEngine.
383      *
384      * Emitted when the page-up button is pressed.
385      * Implement the member function page_up() in extended class to receive this signal.
386      *
387      * <note><para>Argument @user_data is ignored in this function.</para></note>
388      */
389     engine_signals[PAGE_UP] =
390         g_signal_new (I_("page-up"),
391             G_TYPE_FROM_CLASS (gobject_class),
392             G_SIGNAL_RUN_LAST,
393             G_STRUCT_OFFSET (IBusEngineClass, page_up),
394             NULL, NULL,
395             ibus_marshal_VOID__VOID,
396             G_TYPE_NONE,
397             0);
398
399     /**
400      * IBusEngine::page-down:
401      * @engine: An IBusEngine.
402      *
403      * Emitted when the page-down button is pressed.
404      * Implement the member function page_down() in extended class to receive this signal.
405      *
406      * <note><para>Argument @user_data is ignored in this function.</para></note>
407      */
408     engine_signals[PAGE_DOWN] =
409         g_signal_new (I_("page-down"),
410             G_TYPE_FROM_CLASS (gobject_class),
411             G_SIGNAL_RUN_LAST,
412             G_STRUCT_OFFSET (IBusEngineClass, page_down),
413             NULL, NULL,
414             ibus_marshal_VOID__VOID,
415             G_TYPE_NONE,
416             0);
417
418     /**
419      * IBusEngine::cursor-up:
420      * @engine: An IBusEngine.
421      *
422      * Emitted when the up cursor button is pressed.
423      * Implement the member function cursor_up() in extended class to receive this signal.
424      *
425      * <note><para>Argument @user_data is ignored in this function.</para></note>
426      */
427     engine_signals[CURSOR_UP] =
428         g_signal_new (I_("cursor-up"),
429             G_TYPE_FROM_CLASS (gobject_class),
430             G_SIGNAL_RUN_LAST,
431             G_STRUCT_OFFSET (IBusEngineClass, cursor_up),
432             NULL, NULL,
433             ibus_marshal_VOID__VOID,
434             G_TYPE_NONE,
435             0);
436
437     /**
438      * IBusEngine::cursor-down:
439      * @engine: An IBusEngine.
440      *
441      * Emitted when the down cursor button is pressed.
442      * Implement the member function cursor_down() in extended class to receive this signal.
443      *
444      * <note><para>Argument @user_data is ignored in this function.</para></note>
445      */
446     engine_signals[CURSOR_DOWN] =
447         g_signal_new (I_("cursor-down"),
448             G_TYPE_FROM_CLASS (gobject_class),
449             G_SIGNAL_RUN_LAST,
450             G_STRUCT_OFFSET (IBusEngineClass, cursor_down),
451             NULL, NULL,
452             ibus_marshal_VOID__VOID,
453             G_TYPE_NONE,
454             0);
455
456     /**
457      * IBusEngine::candidate-clicked:
458      * @engine: An IBusEngine.
459      *
460      * Emitted when candidate on lookup table is clicked.
461      * Implement the member function candidate_clicked() in extended class to receive this signal.
462      *
463      * <note><para>Argument @user_data is ignored in this function.</para></note>
464      */
465     engine_signals[CANDIDATE_CLICKED] =
466         g_signal_new (I_("candidate-clicked"),
467             G_TYPE_FROM_CLASS (gobject_class),
468             G_SIGNAL_RUN_LAST,
469             G_STRUCT_OFFSET (IBusEngineClass, candidate_clicked),
470             NULL, NULL,
471             ibus_marshal_VOID__UINT_UINT_UINT,
472             G_TYPE_NONE,
473             3,
474             G_TYPE_UINT,
475             G_TYPE_UINT,
476             G_TYPE_UINT);
477
478     /**
479      * IBusEngine::property-activate:
480      * @engine: An IBusEngine.
481      *
482      * Emitted when a property is activated or change changed.
483      * Implement the member function property_activate() in extended class to receive this signal.
484      *
485      * <note><para>Argument @user_data is ignored in this function.</para></note>
486      */
487     engine_signals[PROPERTY_ACTIVATE] =
488         g_signal_new (I_("property-activate"),
489             G_TYPE_FROM_CLASS (gobject_class),
490             G_SIGNAL_RUN_LAST,
491             G_STRUCT_OFFSET (IBusEngineClass, property_activate),
492             NULL, NULL,
493             ibus_marshal_VOID__STRING_UINT,
494             G_TYPE_NONE,
495             2,
496             G_TYPE_STRING,
497             G_TYPE_UINT);
498
499     /**
500      * IBusEngine::property-show:
501      * @engine: An IBusEngine.
502      *
503      * Emitted when a property is shown.
504      * Implement the member function property_side() in extended class to receive this signal.
505      *
506      * <note><para>Argument @user_data is ignored in this function.</para></note>
507      */
508     engine_signals[PROPERTY_SHOW] =
509         g_signal_new (I_("property-show"),
510             G_TYPE_FROM_CLASS (gobject_class),
511             G_SIGNAL_RUN_LAST,
512             G_STRUCT_OFFSET (IBusEngineClass, property_show),
513             NULL, NULL,
514             ibus_marshal_VOID__STRING,
515             G_TYPE_NONE,
516             1,
517             G_TYPE_STRING);
518
519     /**
520      * IBusEngine::property-hide:
521      * @engine: An IBusEngine.
522      *
523      * Emitted when a property is hidden.
524      * Implement the member function property_hide() in extended class to receive this signal.
525      *
526      * <note><para>Argument @user_data is ignored in this function.</para></note>
527      */
528     engine_signals[PROPERTY_HIDE] =
529         g_signal_new (I_("property-hide"),
530             G_TYPE_FROM_CLASS (gobject_class),
531             G_SIGNAL_RUN_LAST,
532             G_STRUCT_OFFSET (IBusEngineClass, property_hide),
533             NULL, NULL,
534             ibus_marshal_VOID__STRING,
535             G_TYPE_NONE,
536             1,
537             G_TYPE_STRING);
538
539 }
540
541 static void
542 ibus_engine_init (IBusEngine *engine)
543 {
544     IBusEnginePrivate *priv;
545     priv = IBUS_ENGINE_GET_PRIVATE (engine);
546
547     priv->name = NULL;
548     priv->connection = NULL;
549 }
550
551 static void
552 ibus_engine_destroy (IBusEngine *engine)
553 {
554     IBusEnginePrivate *priv;
555     priv = IBUS_ENGINE_GET_PRIVATE (engine);
556
557     g_free (priv->name);
558
559     if (priv->connection) {
560         g_object_unref (priv->connection);
561         priv->connection = NULL;
562     }
563
564     IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
565 }
566
567 static void
568 ibus_engine_set_property (IBusEngine   *engine,
569                           guint         prop_id,
570                           const GValue *value,
571                           GParamSpec   *pspec)
572 {
573     IBusEnginePrivate *priv;
574     priv = IBUS_ENGINE_GET_PRIVATE (engine);
575
576     switch (prop_id) {
577     case PROP_NAME:
578         priv->name = g_strdup (g_value_dup_string (value));
579         break;
580
581     case PROP_CONNECTION:
582         priv->connection = g_value_get_object (value);
583         g_object_ref_sink (priv->connection);
584         ibus_service_add_to_connection ((IBusService *) engine,
585                                         priv->connection);
586         break;
587
588     default:
589         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
590     }
591 }
592
593 static void
594 ibus_engine_get_property (IBusEngine *engine,
595     guint prop_id, GValue *value, GParamSpec *pspec)
596 {
597     IBusEnginePrivate *priv;
598     priv = IBUS_ENGINE_GET_PRIVATE (engine);
599
600     switch (prop_id) {
601     case PROP_NAME:
602         g_value_set_string (value, priv->name);
603         break;
604
605     case PROP_CONNECTION:
606         g_value_set_object (value, priv->connection);
607         break;
608
609     default:
610         G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
611     }
612 }
613
614 static gboolean
615 ibus_engine_ibus_message (IBusEngine     *engine,
616                           IBusConnection *connection,
617                           IBusMessage    *message)
618 {
619     g_assert (IBUS_IS_ENGINE (engine));
620     g_assert (IBUS_IS_CONNECTION (connection));
621     g_assert (message != NULL);
622     g_assert (ibus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL);
623
624     IBusEnginePrivate *priv;
625     priv = IBUS_ENGINE_GET_PRIVATE (engine);
626
627     g_assert (priv->connection == connection);
628
629     IBusMessage *reply = NULL;
630     IBusError *error = NULL;
631     gboolean retval;
632
633     gint i;
634     const gchar *interface;
635     const gchar *name;
636
637     static const struct {
638         gchar *member;
639         guint  signal_id;
640     } no_arg_methods[] = {
641         { "FocusIn",     FOCUS_IN },
642         { "FocusOut",    FOCUS_OUT },
643         { "Reset",       RESET },
644         { "Enable",      ENABLE },
645         { "Disable",     DISABLE },
646         { "PageUp",      PAGE_UP },
647         { "PageDown",    PAGE_DOWN },
648         { "CursorUp",    CURSOR_UP },
649         { "CursorDown",  CURSOR_DOWN },
650     };
651
652     interface = ibus_message_get_interface (message);
653     name = ibus_message_get_member (message);
654
655     if (interface != NULL && g_strcmp0 (interface, IBUS_INTERFACE_ENGINE) != 0)
656         return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->ibus_message (
657                         (IBusService *) engine, connection, message);
658
659     do {
660         if (g_strcmp0 (name, "ProcessKeyEvent") == 0) {
661             guint keyval, keycode, state;
662
663             retval = ibus_message_get_args (message,
664                                             &error,
665                                             G_TYPE_UINT, &keyval,
666                                             G_TYPE_UINT, &keycode,
667                                             G_TYPE_UINT, &state,
668                                             G_TYPE_INVALID);
669
670             if (!retval) {
671                 reply = ibus_message_new_error_printf (message,
672                                 DBUS_ERROR_INVALID_ARGS,
673                                 "%s.%s: Can not match signature (uuu) of method",
674                                 IBUS_INTERFACE_ENGINE, "ProcessKeyEvent");
675                 ibus_error_free (error);
676             }
677             else {
678                 retval = FALSE;
679                 g_signal_emit (engine,
680                                engine_signals[PROCESS_KEY_EVENT],
681                                0,
682                                keyval,
683                                keycode,
684                                state,
685                                &retval);
686
687                 reply = ibus_message_new_method_return (message);
688                 ibus_message_append_args (reply,
689                                           G_TYPE_BOOLEAN, &retval,
690                                           G_TYPE_INVALID);
691             }
692             break;
693         }
694
695         for (i = 0;
696              i < G_N_ELEMENTS (no_arg_methods) && g_strcmp0 (name, no_arg_methods[i].member) != 0;
697              i++);
698
699         if (i < G_N_ELEMENTS (no_arg_methods)) {
700             IBusMessageIter iter;
701             ibus_message_iter_init (message, &iter);
702             if (ibus_message_iter_has_next (&iter)) {
703                 reply = ibus_message_new_error_printf (message,
704                                     DBUS_ERROR_INVALID_ARGS,
705                                     "%s.%s: Method does not have arguments",
706                                     IBUS_INTERFACE_ENGINE, no_arg_methods[i].member);
707             }
708             else {
709                 g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
710                 reply = ibus_message_new_method_return (message);
711             }
712             break;
713         }
714
715         if (g_strcmp0 (name, "CandidateClicked") == 0) {
716             guint index, button, state;
717
718             retval = ibus_message_get_args (message,
719                                             &error,
720                                             G_TYPE_UINT, &index,
721                                             G_TYPE_UINT, &button,
722                                             G_TYPE_UINT, &state,
723                                             G_TYPE_INVALID);
724
725             if (!retval) {
726                 reply = ibus_message_new_error_printf (message,
727                                 DBUS_ERROR_INVALID_ARGS,
728                                 "%s.%s: Can not match signature (uuu) of method",
729                                 IBUS_INTERFACE_ENGINE, "CandidateClicked");
730                 ibus_error_free (error);
731             }
732             else {
733                 g_signal_emit (engine,
734                                engine_signals[CANDIDATE_CLICKED],
735                                0,
736                                index,
737                                button,
738                                state);
739                 reply = ibus_message_new_method_return (message);
740             }
741         }
742         else if (g_strcmp0 (name, "PropertyActivate") == 0) {
743             gchar *name;
744             guint state;
745
746             retval = ibus_message_get_args (message,
747                                             &error,
748                                             G_TYPE_STRING, &name,
749                                             G_TYPE_UINT, &state,
750                                             G_TYPE_INVALID);
751
752             if (!retval) {
753                 reply = ibus_message_new_error_printf (message,
754                                 DBUS_ERROR_INVALID_ARGS,
755                                 "%s.%s: Can not match signature (si) of method",
756                                 IBUS_INTERFACE_ENGINE,
757                                 "PropertyActivate");
758                 ibus_error_free (error);
759             }
760             else {
761                 g_signal_emit (engine,
762                                engine_signals[PROPERTY_ACTIVATE],
763                                0,
764                                name,
765                                state);
766
767                 reply = ibus_message_new_method_return (message);
768             }
769         }
770         else if (g_strcmp0 (name, "PropertyShow") == 0) {
771             gchar *name;
772
773             retval = ibus_message_get_args (message,
774                                             &error,
775                                             G_TYPE_STRING, &name,
776                                             G_TYPE_INVALID);
777
778             if (!retval) {
779                 reply = ibus_message_new_error_printf (message,
780                             DBUS_ERROR_INVALID_ARGS,
781                             "%s.%s: Can not match signature (s) of method",
782                             IBUS_INTERFACE_ENGINE,
783                             "PropertyShow");
784                 ibus_error_free (error);
785             }
786             else {
787                 g_signal_emit (engine,
788                                engine_signals[PROPERTY_SHOW],
789                                0,
790                                name);
791
792                 reply = ibus_message_new_method_return (message);
793             }
794         }
795         else if (g_strcmp0 (name, "PropertyHide") == 0) {
796             gchar *name;
797
798             retval = ibus_message_get_args (message,
799                                             &error,
800                                             G_TYPE_STRING, &name,
801                                             G_TYPE_INVALID);
802             if (!retval) {
803                 reply = ibus_message_new_error_printf (message,
804                             DBUS_ERROR_INVALID_ARGS,
805                             "%s.%s: Can not match signature (s) of method",
806                             IBUS_INTERFACE_ENGINE, "PropertyHide");
807                 ibus_error_free (error);
808             }
809             else {
810                 g_signal_emit (engine, engine_signals[PROPERTY_HIDE], 0, name);
811                 reply = ibus_message_new_method_return (message);
812             }
813         }
814         else if (g_strcmp0 (name, "SetCursorLocation") == 0) {
815             gint x, y, w, h;
816
817             retval = ibus_message_get_args (message,
818                                             &error,
819                                             G_TYPE_INT, &x,
820                                             G_TYPE_INT, &y,
821                                             G_TYPE_INT, &w,
822                                             G_TYPE_INT, &h,
823                                             G_TYPE_INVALID);
824             if (!retval) {
825                 reply = ibus_message_new_error_printf (message,
826                             DBUS_ERROR_INVALID_ARGS,
827                             "%s.%s: Can not match signature (iiii) of method",
828                             IBUS_INTERFACE_ENGINE,
829                             "SetCursorLocation");
830                 ibus_error_free (error);
831             }
832             else {
833                 engine->cursor_area.x = x;
834                 engine->cursor_area.y = y;
835                 engine->cursor_area.width = w;
836                 engine->cursor_area.height = h;
837
838                 g_signal_emit (engine,
839                                engine_signals[SET_CURSOR_LOCATION],
840                                0,
841                                x, y, w, h);
842
843                 reply = ibus_message_new_method_return (message);
844             }
845         }
846         else if (g_strcmp0 (name, "SetCapabilities") == 0) {
847             guint caps;
848
849             retval = ibus_message_get_args (message,
850                                             &error,
851                                             G_TYPE_UINT, &caps,
852                                             G_TYPE_INVALID);
853
854             if (!retval) {
855                 reply = ibus_message_new_error_printf (message,
856                             DBUS_ERROR_INVALID_ARGS,
857                             "%s.%s: Can not match signature (u) of method",
858                             IBUS_INTERFACE_ENGINE, "SetCapabilities");
859                 ibus_error_free (error);
860             }
861             else {
862                 engine->client_capabilities = caps;
863                 g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
864                 reply = ibus_message_new_method_return (message);
865             }
866         }
867         else if (g_strcmp0 (name, "Destroy") == 0) {
868             reply = ibus_message_new_method_return (message);
869             ibus_connection_send (connection, reply);
870             ibus_message_unref (reply);
871             ibus_object_destroy ((IBusObject *) engine);
872             return TRUE;
873         }
874         else {
875             reply = ibus_message_new_error_printf (message,
876                         DBUS_ERROR_UNKNOWN_METHOD,
877                         "%s.%s",
878                         IBUS_INTERFACE_ENGINE, name);
879             g_warn_if_reached ();
880         }
881     } while (0);
882
883     ibus_connection_send (connection, reply);
884     ibus_message_unref (reply);
885     return TRUE;
886 }
887
888 static gboolean
889 ibus_engine_process_key_event (IBusEngine *engine,
890                                guint       keyval,
891                                guint       keycode,
892                                guint       state)
893 {
894     return FALSE;
895 }
896
897 static void
898 ibus_engine_focus_in (IBusEngine *engine)
899 {
900     // g_debug ("focus-in");
901 }
902
903 static void
904 ibus_engine_focus_out (IBusEngine *engine)
905 {
906     // g_debug ("focus-out");
907 }
908
909 static void
910 ibus_engine_reset (IBusEngine *engine)
911 {
912     // g_debug ("reset");
913 }
914
915 static void
916 ibus_engine_enable (IBusEngine *engine)
917 {
918     // g_debug ("enable");
919 }
920
921 static void
922 ibus_engine_disable (IBusEngine *engine)
923 {
924     // g_debug ("disable");
925 }
926
927 static void
928 ibus_engine_set_cursor_location (IBusEngine *engine,
929                                  gint        x,
930                                  gint        y,
931                                  gint        w,
932                                  gint        h)
933 {
934     // g_debug ("set-cursor-location (%d, %d, %d, %d)", x, y, w, h);
935 }
936
937 static void
938 ibus_engine_set_capabilities (IBusEngine *engine,
939                               guint       caps)
940 {
941     // g_debug ("set-capabilities (0x%04x)", caps);
942 }
943
944 static void
945 ibus_engine_page_up (IBusEngine *engine)
946 {
947     // g_debug ("page-up");
948 }
949
950 static void
951 ibus_engine_page_down (IBusEngine *engine)
952 {
953     // g_debug ("page-down");
954 }
955
956 static void
957 ibus_engine_cursor_up (IBusEngine *engine)
958 {
959     // g_debug ("cursor-up");
960 }
961
962 static void
963 ibus_engine_cursor_down (IBusEngine *engine)
964 {
965     // g_debug ("cursor-down");
966 }
967
968 static void
969 ibus_engine_candidate_clicked (IBusEngine *engine,
970                                guint       index,
971                                guint       button,
972                                guint       state)
973 {
974     // g_debug ("candidate-clicked");
975 }
976
977 static void
978 ibus_engine_property_activate (IBusEngine  *engine,
979                                const gchar *prop_name,
980                                guint        prop_state)
981 {
982     // g_debug ("property-activate ('%s', %d)", prop_name, prop_state);
983 }
984
985 static void
986 ibus_engine_property_show (IBusEngine *engine, const gchar *prop_name)
987 {
988     // g_debug ("property-show ('%s')", prop_name);
989 }
990
991 static void
992 ibus_engine_property_hide (IBusEngine *engine, const gchar *prop_name)
993 {
994     // g_debug ("property-hide ('%s')", prop_name);
995 }
996
997 static void
998 _send_signal (IBusEngine  *engine,
999               const gchar *name,
1000               GType        first_arg_type,
1001               ...)
1002 {
1003     g_assert (IBUS_IS_ENGINE (engine));
1004     g_assert (name != NULL);
1005
1006     va_list args;
1007     const gchar *path;
1008     IBusEnginePrivate *priv;
1009
1010     priv = IBUS_ENGINE_GET_PRIVATE (engine);
1011
1012     path = ibus_service_get_path ((IBusService *)engine);
1013
1014     va_start (args, first_arg_type);
1015     ibus_connection_send_signal_valist (priv->connection,
1016                                         path,
1017                                         IBUS_INTERFACE_ENGINE,
1018                                         name,
1019                                         first_arg_type,
1020                                         args);
1021     va_end (args);
1022 }
1023
1024 void
1025 ibus_engine_commit_text (IBusEngine *engine,
1026                          IBusText   *text)
1027 {
1028     _send_signal (engine,
1029                   "CommitText",
1030                   IBUS_TYPE_TEXT, &text,
1031                   G_TYPE_INVALID);
1032
1033     if (g_object_is_floating (text)) {
1034         g_object_unref (text);
1035     }
1036 }
1037
1038 void
1039 ibus_engine_update_preedit_text (IBusEngine      *engine,
1040                                  IBusText        *text,
1041                                  guint            cursor_pos,
1042                                  gboolean         visible)
1043 {
1044     ibus_engine_update_preedit_text_with_mode (engine,
1045             text, cursor_pos, visible, IBUS_ENGINE_PREEDIT_CLEAR);
1046 }
1047
1048 void
1049 ibus_engine_update_preedit_text_with_mode (IBusEngine            *engine,
1050                                            IBusText              *text,
1051                                            guint                  cursor_pos,
1052                                            gboolean               visible,
1053                                            IBusPreeditFocusMode   mode)
1054 {
1055     _send_signal (engine,
1056                   "UpdatePreeditText",
1057                   IBUS_TYPE_TEXT, &text,
1058                   G_TYPE_UINT, &cursor_pos,
1059                   G_TYPE_BOOLEAN, &visible,
1060                   G_TYPE_UINT, &mode,
1061                   G_TYPE_INVALID);
1062
1063     if (g_object_is_floating (text)) {
1064         g_object_unref (text);
1065     }
1066 }
1067
1068 void
1069 ibus_engine_show_preedit_text (IBusEngine *engine)
1070 {
1071     _send_signal (engine,
1072                   "ShowPreeditText",
1073                   G_TYPE_INVALID);
1074 }
1075
1076 void ibus_engine_hide_preedit_text (IBusEngine *engine)
1077 {
1078     _send_signal (engine,
1079                   "HidePreeditText",
1080                   G_TYPE_INVALID);
1081 }
1082
1083 void ibus_engine_update_auxiliary_text (IBusEngine      *engine,
1084                                         IBusText        *text,
1085                                         gboolean         visible)
1086 {
1087     _send_signal (engine,
1088                   "UpdateAuxiliaryText",
1089                   IBUS_TYPE_TEXT, &text,
1090                   G_TYPE_BOOLEAN, &visible,
1091                   G_TYPE_INVALID);
1092
1093     if (g_object_is_floating (text)) {
1094         g_object_unref (text);
1095     }
1096 }
1097
1098 void
1099 ibus_engine_show_auxiliary_text (IBusEngine *engine)
1100 {
1101     _send_signal (engine,
1102                   "ShowAuxiliaryText",
1103                   G_TYPE_INVALID);
1104 }
1105
1106 void
1107 ibus_engine_hide_auxiliary_text (IBusEngine *engine)
1108 {
1109     _send_signal (engine,
1110                   "HideAuxiliaryText",
1111                   G_TYPE_INVALID);
1112 }
1113
1114 void
1115 ibus_engine_update_lookup_table (IBusEngine        *engine,
1116                                  IBusLookupTable   *table,
1117                                  gboolean           visible)
1118 {
1119     _send_signal (engine,
1120                   "UpdateLookupTable",
1121                   IBUS_TYPE_LOOKUP_TABLE, &table,
1122                   G_TYPE_BOOLEAN, &visible,
1123                   G_TYPE_INVALID);
1124
1125     if (g_object_is_floating (table)) {
1126         g_object_unref (table);
1127     }
1128 }
1129
1130 void
1131 ibus_engine_update_lookup_table_fast (IBusEngine        *engine,
1132                                       IBusLookupTable   *table,
1133                                       gboolean           visible)
1134 {
1135     IBusLookupTable *new_table;
1136     gint page_begin;
1137     gint i;
1138
1139     if (table->candidates->len < table->page_size << 2) {
1140         ibus_engine_update_lookup_table (engine, table, visible);
1141         return;
1142     }
1143
1144     page_begin = (table->cursor_pos / table->page_size) * table->page_size;
1145
1146     new_table = ibus_lookup_table_new (table->page_size, 0, table->cursor_visible, table->round);
1147
1148     for (i = page_begin; i < page_begin + table->page_size && i < table->candidates->len; i++) {
1149         ibus_lookup_table_append_candidate (new_table, ibus_lookup_table_get_candidate (table, i));
1150     }
1151
1152     ibus_lookup_table_set_cursor_pos (new_table, ibus_lookup_table_get_cursor_in_page (table));
1153     ibus_lookup_table_set_orientation (new_table, ibus_lookup_table_get_orientation (table));
1154
1155     ibus_engine_update_lookup_table (engine, new_table, visible);
1156
1157     if (g_object_is_floating (table)) {
1158         g_object_unref (table);
1159     }
1160 }
1161
1162 void ibus_engine_show_lookup_table (IBusEngine *engine)
1163 {
1164     _send_signal (engine,
1165                   "ShowLookupTable",
1166                   G_TYPE_INVALID);
1167 }
1168
1169 void ibus_engine_hide_lookup_table (IBusEngine *engine)
1170 {
1171     _send_signal (engine,
1172                   "HideLookupTable",
1173                   G_TYPE_INVALID);
1174 }
1175
1176 void ibus_engine_forward_key_event (IBusEngine      *engine,
1177                                     guint            keyval,
1178                                     guint            keycode,
1179                                     guint            state)
1180 {
1181     _send_signal (engine,
1182                   "ForwardKeyEvent",
1183                   G_TYPE_UINT, &keyval,
1184                   G_TYPE_UINT, &keycode,
1185                   G_TYPE_UINT, &state,
1186                   G_TYPE_INVALID);
1187 }
1188
1189 void ibus_engine_delete_surrounding_text (IBusEngine      *engine,
1190                                           gint             offset_from_cursor,
1191                                           guint            nchars)
1192 {
1193     _send_signal (engine,
1194                   "DeleteSurroundingText",
1195                   G_TYPE_INT,  &offset_from_cursor,
1196                   G_TYPE_UINT, &nchars,
1197                   G_TYPE_INVALID);
1198 }
1199
1200 void
1201 ibus_engine_register_properties (IBusEngine   *engine,
1202                                  IBusPropList *prop_list)
1203 {
1204     _send_signal (engine,
1205                   "RegisterProperties",
1206                   IBUS_TYPE_PROP_LIST, &prop_list,
1207                   G_TYPE_INVALID);
1208
1209     if (g_object_is_floating (prop_list)) {
1210         g_object_unref (prop_list);
1211     }
1212 }
1213
1214 void
1215 ibus_engine_update_property (IBusEngine   *engine,
1216                              IBusProperty *prop)
1217 {
1218     _send_signal (engine,
1219                   "UpdateProperty",
1220                   IBUS_TYPE_PROPERTY, &prop,
1221                   G_TYPE_INVALID);
1222
1223     if (g_object_is_floating (prop)) {
1224         g_object_unref (prop);
1225     }
1226 }
1227
1228 const gchar *
1229 ibus_engine_get_name (IBusEngine *engine)
1230 {
1231     g_assert (IBUS_IS_ENGINE (engine));
1232
1233     IBusEnginePrivate *priv;
1234     priv = IBUS_ENGINE_GET_PRIVATE (engine);
1235
1236     return priv->name;
1237 }
1238