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