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