Add Ctrl+space customization.
[platform/upstream/ibus.git] / src / ibusinputcontext.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2010 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #include "ibusinputcontext.h"
23 #include <gio/gio.h>
24 #include "ibusshare.h"
25 #include "ibusinternal.h"
26 #include "ibusmarshalers.h"
27 #include "ibusattribute.h"
28 #include "ibuslookuptable.h"
29 #include "ibusproplist.h"
30 #include "ibuserror.h"
31
32 #define IBUS_INPUT_CONTEXT_GET_PRIVATE(o)  \
33    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_INPUT_CONTEXT, IBusInputContextPrivate))
34
35 enum {
36     ENABLED,
37     DISABLED,
38     COMMIT_TEXT,
39     FORWARD_KEY_EVENT,
40     DELETE_SURROUNDING_TEXT,
41     UPDATE_PREEDIT_TEXT,
42     SHOW_PREEDIT_TEXT,
43     HIDE_PREEDIT_TEXT,
44     UPDATE_AUXILIARY_TEXT,
45     SHOW_AUXILIARY_TEXT,
46     HIDE_AUXILIARY_TEXT,
47     UPDATE_LOOKUP_TABLE,
48     SHOW_LOOKUP_TABLE,
49     HIDE_LOOKUP_TABLE,
50     PAGE_UP_LOOKUP_TABLE,
51     PAGE_DOWN_LOOKUP_TABLE,
52     CURSOR_UP_LOOKUP_TABLE,
53     CURSOR_DOWN_LOOKUP_TABLE,
54     REGISTER_PROPERTIES,
55     UPDATE_PROPERTY,
56     LAST_SIGNAL,
57 };
58
59 /* IBusInputContextPrivate */
60 struct _IBusInputContextPrivate {
61     /* TRUE if the current engine needs surrounding text; FALSE otherwise */
62     gboolean  needs_surrounding_text;
63
64     /* cached surrounding text (see also IBusEnginePrivate and
65        BusEngineProxy) */
66     IBusText *surrounding_text;
67     guint     surrounding_cursor_pos;
68     guint     selection_anchor_pos;
69 };
70
71 typedef struct _IBusInputContextPrivate IBusInputContextPrivate;
72
73 static guint            context_signals[LAST_SIGNAL] = { 0 };
74
75 static IBusText *text_empty = NULL;
76
77 /* functions prototype */
78 static void     ibus_input_context_real_destroy (IBusProxy              *context);
79 static void     ibus_input_context_g_signal     (GDBusProxy             *proxy,
80                                                  const gchar            *sender_name,
81                                                  const gchar            *signal_name,
82                                                  GVariant               *parameters);
83
84 G_DEFINE_TYPE (IBusInputContext, ibus_input_context, IBUS_TYPE_PROXY)
85
86 static void
87 ibus_input_context_class_init (IBusInputContextClass *class)
88 {
89     IBusProxyClass *ibus_proxy_class = IBUS_PROXY_CLASS (class);
90     GDBusProxyClass *g_dbus_proxy_class = G_DBUS_PROXY_CLASS (class);
91
92     g_type_class_add_private (class, sizeof (IBusInputContextPrivate));
93
94     ibus_proxy_class->destroy = ibus_input_context_real_destroy;
95
96     g_dbus_proxy_class->g_signal = ibus_input_context_g_signal;
97
98     /* install signals */
99     /**
100      * IBusInputContext::enabled:
101      * @context: An IBusInputContext.
102      *
103      * Emitted when an IME is enabled.
104      */
105     context_signals[ENABLED] =
106         g_signal_new (I_("enabled"),
107             G_TYPE_FROM_CLASS (class),
108             G_SIGNAL_RUN_LAST,
109             0,
110             NULL, NULL,
111             _ibus_marshal_VOID__VOID,
112             G_TYPE_NONE, 0);
113
114     /**
115      * IBusInputContext::disabled:
116      * @context: An IBusInputContext.
117      *
118      * Emitted when an IME is disabled.
119      */
120     context_signals[DISABLED] =
121         g_signal_new (I_("disabled"),
122             G_TYPE_FROM_CLASS (class),
123             G_SIGNAL_RUN_LAST,
124             0,
125             NULL, NULL,
126             _ibus_marshal_VOID__VOID,
127             G_TYPE_NONE, 0);
128
129     /**
130      * IBusInputContext::commit-text:
131      * @context: An IBusInputContext.
132      * @text: Text to be committed.
133      *
134      * Emitted when the text is going to be committed.
135      *
136      * (Note: The text object is floating, and it will be released after the signal.
137      *  If singal handler want to keep the object, the handler should use g_object_ref_sink()
138      *  to get the ownership of the object.)
139      */
140     context_signals[COMMIT_TEXT] =
141         g_signal_new (I_("commit-text"),
142             G_TYPE_FROM_CLASS (class),
143             G_SIGNAL_RUN_LAST,
144             0,
145             NULL, NULL,
146             _ibus_marshal_VOID__OBJECT,
147             G_TYPE_NONE,
148             1,
149             IBUS_TYPE_TEXT);
150
151     /**
152      * IBusInputContext::forward-key-event:
153      * @context: An IBusInputContext.
154      * @keyval: Key symbol of the keyboard event.
155      * @keycode: Key symbol of the keyboard event.
156      * @modifiers: Key modifier flags.
157      *
158      * Emitted to forward key event from IME to client of IME.
159      */
160     context_signals[FORWARD_KEY_EVENT] =
161         g_signal_new (I_("forward-key-event"),
162             G_TYPE_FROM_CLASS (class),
163             G_SIGNAL_RUN_LAST,
164             0,
165             NULL, NULL,
166             _ibus_marshal_VOID__UINT_UINT_UINT,
167             G_TYPE_NONE,
168             3,
169             G_TYPE_UINT,
170             G_TYPE_UINT,
171             G_TYPE_UINT);
172
173     /**
174      * IBusInputContext::delete-surrounding-text:
175      * @context: An IBusInputContext.
176      * @offset: the character offset from the cursor position of the text to be deleted.
177      *   A negative value indicates a position before the cursor.
178      * @n_chars: the number of characters to be deleted.
179      *
180      * Emitted to delete surrounding text event from IME to client of IME.
181      */
182     context_signals[DELETE_SURROUNDING_TEXT] =
183         g_signal_new (I_("delete-surrounding-text"),
184             G_TYPE_FROM_CLASS (class),
185             G_SIGNAL_RUN_LAST,
186             0,
187             NULL, NULL,
188             _ibus_marshal_VOID__INT_UINT,
189             G_TYPE_NONE,
190             2,
191             G_TYPE_INT,
192             G_TYPE_UINT);
193
194     /**
195      * IBusInputContext::update-preedit-text:
196      * @context: An IBusInputContext.
197      * @text: Text to be updated.
198      * @cursor_pos: Cursor position.
199      * @visible: Whether the update is visible.
200      *
201      * Emitted to update preedit text.
202      *
203      * (Note: The text object is floating, and it will be released after the signal.
204      *  If singal handler want to keep the object, the handler should use g_object_ref_sink()
205      *  to get the ownership of the object.)
206      */
207     context_signals[UPDATE_PREEDIT_TEXT] =
208         g_signal_new (I_("update-preedit-text"),
209             G_TYPE_FROM_CLASS (class),
210             G_SIGNAL_RUN_LAST,
211             0,
212             NULL, NULL,
213             _ibus_marshal_VOID__OBJECT_UINT_BOOLEAN,
214             G_TYPE_NONE,
215             3,
216             IBUS_TYPE_TEXT,
217             G_TYPE_UINT,
218             G_TYPE_BOOLEAN);
219
220     /**
221      * IBusInputContext::show-preedit-text:
222      * @context: An IBusInputContext.
223      *
224      * Emitted to show preedit text.
225      */
226     context_signals[SHOW_PREEDIT_TEXT] =
227         g_signal_new (I_("show-preedit-text"),
228             G_TYPE_FROM_CLASS (class),
229             G_SIGNAL_RUN_LAST,
230             0,
231             NULL, NULL,
232             _ibus_marshal_VOID__VOID,
233             G_TYPE_NONE, 0);
234
235     /**
236      * IBusInputContext::hide-preedit-text:
237      * @context: An IBusInputContext.
238      *
239      * Emitted to hide preedit text.
240      */
241     context_signals[HIDE_PREEDIT_TEXT] =
242         g_signal_new (I_("hide-preedit-text"),
243             G_TYPE_FROM_CLASS (class),
244             G_SIGNAL_RUN_LAST,
245             0,
246             NULL, NULL,
247             _ibus_marshal_VOID__VOID,
248             G_TYPE_NONE, 0);
249
250     /**
251      * IBusInputContext::update-auxiliary-text:
252      * @context: An IBusInputContext.
253      *
254      * Emitted to hide auxilary text.
255      *
256      * (Note: The text object is floating, and it will be released after the signal.
257      *  If singal handler want to keep the object, the handler should use g_object_ref_sink()
258      *  to get the ownership of the object.)
259      */
260     context_signals[UPDATE_AUXILIARY_TEXT] =
261         g_signal_new (I_("update-auxiliary-text"),
262             G_TYPE_FROM_CLASS (class),
263             G_SIGNAL_RUN_LAST,
264             0,
265             NULL, NULL,
266             _ibus_marshal_VOID__OBJECT_BOOLEAN,
267             G_TYPE_NONE, 2,
268             IBUS_TYPE_TEXT,
269             G_TYPE_BOOLEAN);
270
271     /**
272      * IBusInputContext::show-auxiliary-text:
273      * @context: An IBusInputContext.
274      *
275      * Emitted to show auxiliary text.
276      */
277     context_signals[SHOW_AUXILIARY_TEXT] =
278         g_signal_new (I_("show-auxiliary-text"),
279             G_TYPE_FROM_CLASS (class),
280             G_SIGNAL_RUN_LAST,
281             0,
282             NULL, NULL,
283             _ibus_marshal_VOID__VOID,
284             G_TYPE_NONE, 0);
285
286     /**
287      * IBusInputContext::hide-auxiliary-text:
288      * @context: An IBusInputContext.
289      *
290      * Emitted to hide auxiliary text.
291      */
292     context_signals[HIDE_AUXILIARY_TEXT] =
293         g_signal_new (I_("hide-auxiliary-text"),
294             G_TYPE_FROM_CLASS (class),
295             G_SIGNAL_RUN_LAST,
296             0,
297             NULL, NULL,
298             _ibus_marshal_VOID__VOID,
299             G_TYPE_NONE, 0);
300
301     /**
302      * IBusInputContext::update-lookup-table:
303      * @context: An IBusInputContext.
304      * @table: An IBusLookupTable to be updated.
305      * @visible: Whether the table should be visible.
306      *
307      * Emitted to update lookup table.
308      *
309      * (Note: The table object is floating, and it will be released after the signal.
310      *  If singal handler want to keep the object, the handler should use g_object_ref_sink()
311      *  to get the ownership of the object.)
312      */
313     context_signals[UPDATE_LOOKUP_TABLE] =
314         g_signal_new (I_("update-lookup-table"),
315             G_TYPE_FROM_CLASS (class),
316             G_SIGNAL_RUN_LAST,
317             0,
318             NULL, NULL,
319             _ibus_marshal_VOID__OBJECT_BOOLEAN,
320             G_TYPE_NONE, 2,
321             IBUS_TYPE_LOOKUP_TABLE,
322             G_TYPE_BOOLEAN);
323
324     /**
325      * IBusInputContext::show-lookup-table:
326      * @context: An IBusInputContext.
327      *
328      * Emitted to show lookup table.
329      */
330     context_signals[SHOW_LOOKUP_TABLE] =
331         g_signal_new (I_("show-lookup-table"),
332             G_TYPE_FROM_CLASS (class),
333             G_SIGNAL_RUN_LAST,
334             0,
335             NULL, NULL,
336             _ibus_marshal_VOID__VOID,
337             G_TYPE_NONE, 0);
338
339     /**
340      * IBusInputContext::hide-lookup-table:
341      * @context: An IBusInputContext.
342      *
343      * Emitted to hide lookup table.
344      */
345     context_signals[HIDE_LOOKUP_TABLE] =
346         g_signal_new (I_("hide-lookup-table"),
347             G_TYPE_FROM_CLASS (class),
348             G_SIGNAL_RUN_LAST,
349             0,
350             NULL, NULL,
351             _ibus_marshal_VOID__VOID,
352             G_TYPE_NONE, 0);
353
354     /**
355      * IBusInputContext::page-up-lookup-table:
356      * @context: An IBusInputContext.
357      *
358      * Emitted to view the previous page of lookup table.
359      */
360     context_signals[PAGE_UP_LOOKUP_TABLE] =
361         g_signal_new (I_("page-up-lookup-table"),
362             G_TYPE_FROM_CLASS (class),
363             G_SIGNAL_RUN_LAST,
364             0,
365             NULL, NULL,
366             _ibus_marshal_VOID__VOID,
367             G_TYPE_NONE, 0);
368
369     /**
370      * IBusInputContext::page-down-lookup-table:
371      * @context: An IBusInputContext.
372      *
373      * Emitted to view the next page of lookup table.
374      */
375     context_signals[PAGE_DOWN_LOOKUP_TABLE] =
376         g_signal_new (I_("page-down-lookup-table"),
377             G_TYPE_FROM_CLASS (class),
378             G_SIGNAL_RUN_LAST,
379             0,
380             NULL, NULL,
381             _ibus_marshal_VOID__VOID,
382             G_TYPE_NONE, 0);
383
384     /**
385      * IBusInputContext::cursor-up-lookup-table:
386      * @context: An IBusInputContext.
387      *
388      * Emitted to select previous candidate of lookup table.
389      */
390     context_signals[CURSOR_UP_LOOKUP_TABLE] =
391         g_signal_new (I_("cursor-up-lookup-table"),
392             G_TYPE_FROM_CLASS (class),
393             G_SIGNAL_RUN_LAST,
394             0,
395             NULL, NULL,
396             _ibus_marshal_VOID__VOID,
397             G_TYPE_NONE, 0);
398
399     /**
400      * IBusInputContext::cursor-down-lookup-table:
401      * @context: An IBusInputContext.
402      *
403      * Emitted to select next candidate of lookup table.
404      */
405     context_signals[CURSOR_DOWN_LOOKUP_TABLE] =
406         g_signal_new (I_("cursor-down-lookup-table"),
407             G_TYPE_FROM_CLASS (class),
408             G_SIGNAL_RUN_LAST,
409             0,
410             NULL, NULL,
411             _ibus_marshal_VOID__VOID,
412             G_TYPE_NONE,
413             0);
414
415     /**
416      * IBusInputContext::register-properties:
417      * @context: An IBusInputContext.
418      * @props: An IBusPropList that contains properties.
419      *
420      * Emitted to register the properties in @props.
421      *
422      * (Note: The props object is floating, and it will be released after the signal.
423      *  If singal handler want to keep the object, the handler should use g_object_ref_sink()
424      *  to get the ownership of the object.)
425      */
426     context_signals[REGISTER_PROPERTIES] =
427         g_signal_new (I_("register-properties"),
428             G_TYPE_FROM_CLASS (class),
429             G_SIGNAL_RUN_LAST,
430             0,
431             NULL, NULL,
432             _ibus_marshal_VOID__OBJECT,
433             G_TYPE_NONE,
434             1,
435             IBUS_TYPE_PROP_LIST);
436
437     /**
438      * IBusInputContext::update-property:
439      * @context: An IBusInputContext.
440      * @prop: The IBusProperty to be updated.
441      *
442      * Emitted to update the property @prop.
443      *
444      * (Note: The prop object is floating, and it will be released after the signal.
445      *  If singal handler want to keep the object, the handler should use g_object_ref_sink()
446      *  to get the ownership of the object.)
447      */
448     context_signals[UPDATE_PROPERTY] =
449         g_signal_new (I_("update-property"),
450             G_TYPE_FROM_CLASS (class),
451             G_SIGNAL_RUN_LAST,
452             0,
453             NULL, NULL,
454             _ibus_marshal_VOID__OBJECT,
455             G_TYPE_NONE,
456             1,
457             IBUS_TYPE_PROPERTY);
458
459     text_empty = ibus_text_new_from_static_string ("");
460     g_object_ref_sink (text_empty);
461 }
462
463 static void
464 ibus_input_context_init (IBusInputContext *context)
465 {
466     IBusInputContextPrivate *priv;
467
468     priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (context);
469     priv->surrounding_text = g_object_ref_sink (text_empty);
470 }
471
472 static void
473 ibus_input_context_real_destroy (IBusProxy *context)
474 {
475     IBusInputContextPrivate *priv;
476     priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
477
478     if (priv->surrounding_text) {
479         g_object_unref (priv->surrounding_text);
480         priv->surrounding_text = NULL;
481     }
482
483     IBUS_PROXY_CLASS(ibus_input_context_parent_class)->destroy (context);
484 }
485
486 static void
487 ibus_input_context_g_signal (GDBusProxy  *proxy,
488                              const gchar *sender_name,
489                              const gchar *signal_name,
490                              GVariant    *parameters)
491 {
492     g_assert (IBUS_IS_INPUT_CONTEXT (proxy));
493
494     IBusInputContext *context;
495     context = IBUS_INPUT_CONTEXT (proxy);
496
497     static const struct {
498         const gchar *signal_name;
499         guint signal_id;
500     } signals [] = {
501         { "ShowPreeditText",        SHOW_PREEDIT_TEXT        },
502         { "HidePreeditText",        HIDE_PREEDIT_TEXT        },
503         { "ShowAuxiliaryText",      SHOW_AUXILIARY_TEXT      },
504         { "HideAuxiliaryText",      HIDE_AUXILIARY_TEXT      },
505         { "ShowLookupTable",        SHOW_LOOKUP_TABLE        },
506         { "HideLookupTable",        HIDE_LOOKUP_TABLE        },
507         { "PageUpLookupTable",      PAGE_UP_LOOKUP_TABLE     },
508         { "PageDownLookupTable",    PAGE_DOWN_LOOKUP_TABLE   },
509         { "CursorUpLookupTable",    CURSOR_UP_LOOKUP_TABLE   },
510         { "CursorDownLookupTable",  CURSOR_DOWN_LOOKUP_TABLE },
511     };
512
513     if (g_strcmp0 (signal_name, "CommitText") == 0) {
514         GVariant *variant = NULL;
515         g_variant_get (parameters, "(v)", &variant);
516         IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (variant));
517         g_variant_unref (variant);
518         g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text);
519
520         if (g_object_is_floating (text))
521             g_object_unref (text);
522         return;
523     }
524     if (g_strcmp0 (signal_name, "UpdatePreeditText") == 0) {
525         GVariant *variant = NULL;
526         gint32 cursor_pos;
527         gboolean visible;
528         g_variant_get (parameters, "(vub)", &variant, &cursor_pos, &visible);
529         IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (variant));
530         g_variant_unref (variant);
531
532         g_signal_emit (context,
533                        context_signals[UPDATE_PREEDIT_TEXT],
534                        0,
535                        text,
536                        cursor_pos,
537                        visible);
538
539         if (g_object_is_floating (text))
540             g_object_unref (text);
541         return;
542     }
543
544     /* lookup signal in table */
545     gint i;
546     for (i = 0;
547          i < G_N_ELEMENTS (signals) && g_strcmp0 (signal_name, signals[i].signal_name) != 0;
548          i++);
549
550     if (i < G_N_ELEMENTS (signals)) {
551         g_signal_emit (context, context_signals[signals[i].signal_id], 0);
552         return;
553     }
554
555     if (g_strcmp0 (signal_name, "UpdateAuxiliaryText") == 0) {
556         GVariant *variant = NULL;
557         gboolean visible;
558         g_variant_get (parameters, "(vb)", &variant, &visible);
559         IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (variant));
560         g_variant_unref (variant);
561
562         g_signal_emit (context,
563                        context_signals[UPDATE_AUXILIARY_TEXT],
564                        0,
565                        text,
566                        visible);
567         if (g_object_is_floating (text))
568             g_object_unref (text);
569         return;
570     }
571
572     if (g_strcmp0 (signal_name, "UpdateLookupTable") == 0) {
573         GVariant *variant = NULL;
574         gboolean visible;
575         g_variant_get (parameters, "(vb)", &variant, &visible);
576
577         IBusLookupTable *table = IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (variant));
578         g_variant_unref (variant);
579
580         g_signal_emit (context,
581                        context_signals[UPDATE_LOOKUP_TABLE],
582                        0,
583                        table,
584                        visible);
585         if (g_object_is_floating (table))
586             g_object_unref (table);
587         return;
588
589     }
590
591     if (g_strcmp0 (signal_name, "RegisterProperties") == 0) {
592         GVariant *variant = NULL;
593         g_variant_get (parameters, "(v)", &variant);
594
595         IBusPropList *prop_list = IBUS_PROP_LIST (ibus_serializable_deserialize (variant));
596         g_variant_unref (variant);
597
598         g_signal_emit (context,
599                        context_signals[REGISTER_PROPERTIES],
600                        0,
601                        prop_list);
602
603         if (g_object_is_floating (prop_list))
604             g_object_unref (prop_list);
605         return;
606     }
607
608     if (g_strcmp0 (signal_name, "UpdateProperty") == 0) {
609         GVariant *variant = NULL;
610         g_variant_get (parameters, "(v)", &variant);
611         IBusProperty *prop = IBUS_PROPERTY (ibus_serializable_deserialize (variant));
612         g_variant_unref (variant);
613
614         g_signal_emit (context, context_signals[UPDATE_PROPERTY], 0, prop);
615
616         if (g_object_is_floating (prop))
617             g_object_unref (prop);
618         return;
619     }
620
621     if (g_strcmp0 (signal_name, "ForwardKeyEvent") == 0) {
622         guint32 keyval;
623         guint32 keycode;
624         guint32 state;
625
626         g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state);
627
628         /* Forward key event back with IBUS_FORWARD_MASK. And process_key_event will
629          * not process key event with IBUS_FORWARD_MASK again. */
630         g_signal_emit (context,
631                        context_signals[FORWARD_KEY_EVENT],
632                        0,
633                        keyval,
634                        keycode,
635                        state | IBUS_FORWARD_MASK);
636         return;
637     }
638
639     if (g_strcmp0 (signal_name, "DeleteSurroundingText") == 0) {
640         gint offset_from_cursor;
641         guint nchars;
642
643         g_variant_get (parameters, "(iu)", &offset_from_cursor, &nchars);
644
645         g_signal_emit (context,
646                        context_signals[DELETE_SURROUNDING_TEXT],
647                        0,
648                        offset_from_cursor,
649                        nchars);
650         return;
651     }
652
653     IBusInputContextPrivate *priv;
654     priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
655
656     if (g_strcmp0 (signal_name, "Enabled") == 0) {
657         priv->needs_surrounding_text = FALSE;
658         g_signal_emit (context, context_signals[ENABLED], 0);
659         return;
660     }
661
662     if (g_strcmp0 (signal_name, "Disabled") == 0) {
663         priv->needs_surrounding_text = FALSE;
664         g_signal_emit (context, context_signals[DISABLED], 0);
665         return;
666     }
667
668     if (g_strcmp0 (signal_name, "RequireSurroundingText") == 0) {
669         priv->needs_surrounding_text = TRUE;
670         return;
671     }
672
673     G_DBUS_PROXY_CLASS (ibus_input_context_parent_class)->g_signal (
674                                 proxy, sender_name, signal_name, parameters);
675 }
676
677 IBusInputContext *
678 ibus_input_context_new (const gchar     *path,
679                         GDBusConnection *connection,
680                         GCancellable    *cancellable,
681                         GError         **error)
682 {
683     g_assert (path != NULL);
684     g_assert (G_IS_DBUS_CONNECTION (connection));
685
686     GInitable *initable;
687
688     GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
689                             G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
690
691     initable = g_initable_new (IBUS_TYPE_INPUT_CONTEXT,
692                                cancellable,
693                                error,
694                                "g-connection",      connection,
695                                "g-name",            IBUS_SERVICE_IBUS,
696                                "g-flags",           flags,
697                                "g-interface-name",  IBUS_INTERFACE_INPUT_CONTEXT,
698                                "g-object-path",     path,
699                                "g-default-timeout", ibus_get_timeout (),
700                                NULL);
701     if (initable != NULL)
702         return IBUS_INPUT_CONTEXT (initable);
703     return NULL;
704 }
705
706 void
707 ibus_input_context_new_async (const gchar         *path,
708                               GDBusConnection     *connection,
709                               GCancellable        *cancellable,
710                               GAsyncReadyCallback  callback,
711                               gpointer             user_data)
712 {
713     g_assert (path != NULL);
714     g_assert (G_IS_DBUS_CONNECTION (connection));
715     g_assert (callback != NULL);
716
717     GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
718                             G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
719
720     g_async_initable_new_async (IBUS_TYPE_INPUT_CONTEXT,
721                                 G_PRIORITY_DEFAULT,
722                                 cancellable,
723                                 callback,
724                                 user_data,
725                                 "g-connection",      connection,
726                                 "g-name",            IBUS_SERVICE_IBUS,
727                                 "g-flags",           flags,
728                                 "g-interface-name",  IBUS_INTERFACE_INPUT_CONTEXT,
729                                 "g-object-path",     path,
730                                 "g-default-timeout", ibus_get_timeout (),
731                                 NULL);
732 }
733
734 IBusInputContext *
735 ibus_input_context_new_async_finish (GAsyncResult  *res,
736                                      GError       **error)
737 {
738     GObject *object = NULL;
739     GObject *source_object = NULL;
740
741     source_object = g_async_result_get_source_object (res);
742     g_assert (source_object != NULL);
743
744     object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
745                                           res,
746                                           error);
747     g_object_unref (source_object);
748
749     if (object != NULL) {
750         return IBUS_INPUT_CONTEXT (object);
751     }
752     else {
753         return NULL;
754     }
755 }
756
757 IBusInputContext *
758 ibus_input_context_get_input_context (const gchar     *path,
759                                       GDBusConnection *connection)
760 {
761     IBusInputContext *context = NULL;
762     GError *error = NULL;
763
764     context = ibus_input_context_new (path, connection, NULL, &error);
765     if (context == NULL) {
766         g_warning ("ibus_input_context_get_input_context: %s", error->message);
767         g_error_free (error);
768         return NULL;
769     }
770
771     /* Do not call "org.freedesktop.IBus.Service.Destroy" when the input
772      * context object is disposed. */
773     IBUS_PROXY (context)->own = FALSE;
774     return context;
775 }
776
777 void
778 ibus_input_context_get_input_context_async (const gchar         *path,
779                                             GDBusConnection     *connection,
780                                             GCancellable        *cancellable,
781                                             GAsyncReadyCallback  callback,
782                                             gpointer             user_data)
783 {
784     ibus_input_context_new_async (path,
785                                   connection,
786                                   cancellable,
787                                   callback,
788                                   user_data);
789 }
790
791 IBusInputContext *
792 ibus_input_context_get_input_context_async_finish (GAsyncResult  *res,
793                                                    GError       **error)
794 {
795     IBusInputContext *context = NULL;
796
797     context = ibus_input_context_new_async_finish (res, error);
798     if (context == NULL) {
799         return NULL;
800     }
801
802     /* Do not call "org.freedesktop.IBus.Service.Destroy" when the input
803      * context object is disposed. */
804     IBUS_PROXY (context)->own = FALSE;
805     return context;
806 }
807
808 void
809 ibus_input_context_process_hand_writing_event (IBusInputContext   *context,
810                                                const gdouble      *coordinates,
811                                                guint               coordinates_len)
812 {
813     g_assert (IBUS_IS_INPUT_CONTEXT (context));
814     g_return_if_fail (coordinates != NULL);
815     g_return_if_fail (coordinates_len >= 4); /* The array should contain at least one line. */
816     g_return_if_fail ((coordinates_len & 1) == 0);
817
818     guint i;
819     GVariantBuilder builder;
820     g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
821     for (i = 0; i < coordinates_len; i++) {
822         g_variant_builder_add (&builder, "d", coordinates[i]);
823     }
824
825     g_dbus_proxy_call ((GDBusProxy *) context,
826                        "ProcessHandWritingEvent",           /* method_name */
827                        g_variant_new ("(ad)", &builder),    /* parameters */
828                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
829                        -1,                                  /* timeout */
830                        NULL,                                /* cancellable */
831                        NULL,                                /* callback */
832                        NULL                                 /* user_data */
833                        );
834 }
835
836 void
837 ibus_input_context_cancel_hand_writing (IBusInputContext   *context,
838                                         guint               n_strokes)
839 {
840     g_assert (IBUS_IS_INPUT_CONTEXT (context));
841
842     g_dbus_proxy_call ((GDBusProxy *) context,
843                        "CancelHandWriting",                 /* method_name */
844                        g_variant_new ("(u)", n_strokes),    /* parameters */
845                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
846                        -1,                                  /* timeout */
847                        NULL,                                /* cancellable */
848                        NULL,                                /* callback */
849                        NULL                                 /* user_data */
850                        );
851 }
852
853 void
854 ibus_input_context_process_key_event_async (IBusInputContext   *context,
855                                             guint32             keyval,
856                                             guint32             keycode,
857                                             guint32             state,
858                                             gint                timeout_msec,
859                                             GCancellable       *cancellable,
860                                             GAsyncReadyCallback callback,
861                                             gpointer            user_data)
862 {
863     g_assert (IBUS_IS_INPUT_CONTEXT (context));
864
865     g_dbus_proxy_call ((GDBusProxy *) context,
866                        "ProcessKeyEvent",                   /* method_name */
867                        g_variant_new ("(uuu)",
868                             keyval, keycode, state),        /* parameters */
869                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
870                        timeout_msec,                        /* timeout */
871                        cancellable,                         /* cancellable */
872                        callback,                            /* callback */
873                        user_data                            /* user_data */
874                        );
875 }
876
877 gboolean
878 ibus_input_context_process_key_event_async_finish (IBusInputContext  *context,
879                                                    GAsyncResult      *res,
880                                                    GError           **error)
881 {
882     g_assert (IBUS_IS_INPUT_CONTEXT (context));
883     g_assert (G_IS_ASYNC_RESULT (res));
884     g_assert (error == NULL || *error == NULL);
885
886     gboolean processed = FALSE;
887
888     GVariant *variant = g_dbus_proxy_call_finish ((GDBusProxy *) context,
889                                                    res, error);
890     if (variant != NULL) {
891         g_variant_get (variant, "(b)", &processed);
892         g_variant_unref (variant);
893     }
894
895     return processed;
896 }
897
898 gboolean
899 ibus_input_context_process_key_event (IBusInputContext *context,
900                                       guint32           keyval,
901                                       guint32           keycode,
902                                       guint32           state)
903 {
904     g_assert (IBUS_IS_INPUT_CONTEXT (context));
905
906     GVariant *result = g_dbus_proxy_call_sync ((GDBusProxy *) context,
907                             "ProcessKeyEvent",              /* method_name */
908                             g_variant_new ("(uuu)",
909                                  keyval, keycode, state),   /* parameters */
910                             G_DBUS_CALL_FLAGS_NONE,         /* flags */
911                             -1,                             /* timeout */
912                             NULL,                           /* cancellable */
913                             NULL);
914
915     if (result != NULL) {
916         gboolean processed = FALSE;
917
918         g_variant_get (result, "(b)", &processed);
919         g_variant_unref (result);
920         return processed;
921     }
922
923     return FALSE;
924 }
925
926 void
927 ibus_input_context_set_cursor_location (IBusInputContext *context,
928                                         gint32            x,
929                                         gint32            y,
930                                         gint32            w,
931                                         gint32            h)
932 {
933     g_assert (IBUS_IS_INPUT_CONTEXT (context));
934
935     g_dbus_proxy_call ((GDBusProxy *) context,
936                        "SetCursorLocation",                 /* method_name */
937                        g_variant_new ("(iiii)", x, y, w, h),/* parameters */
938                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
939                        -1,                                  /* timeout */
940                        NULL,                                /* cancellable */
941                        NULL,                                /* callback */
942                        NULL                                 /* user_data */
943                        );
944 }
945
946 void
947 ibus_input_context_set_capabilities (IBusInputContext   *context,
948                                      guint32             capabilites)
949 {
950     g_assert (IBUS_IS_INPUT_CONTEXT (context));
951     g_dbus_proxy_call ((GDBusProxy *) context,
952                        "SetCapabilities",                   /* method_name */
953                        g_variant_new ("(u)", capabilites),  /* parameters */
954                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
955                        -1,                                  /* timeout */
956                        NULL,                                /* cancellable */
957                        NULL,                                /* callback */
958                        NULL                                 /* user_data */
959                        );
960 }
961
962 void
963 ibus_input_context_property_activate (IBusInputContext *context,
964                                       const gchar      *prop_name,
965                                       guint32           state)
966 {
967     g_assert (IBUS_IS_INPUT_CONTEXT (context));
968     g_dbus_proxy_call ((GDBusProxy *) context,
969                        "PropertyActivate",                  /* method_name */
970                        g_variant_new ("(su)",
971                                 prop_name, state),          /* parameters */
972                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
973                        -1,                                  /* timeout */
974                        NULL,                                /* cancellable */
975                        NULL,                                /* callback */
976                        NULL                                 /* user_data */
977                        );
978 }
979
980 void
981 ibus_input_context_property_show (IBusInputContext *context,
982                                   const gchar     *prop_name)
983 {
984     g_assert (IBUS_IS_INPUT_CONTEXT (context));
985     g_dbus_proxy_call ((GDBusProxy *) context,
986                        "PropertyShow",                      /* method_name */
987                        g_variant_new ("(s)", prop_name),    /* parameters */
988                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
989                        -1,                                  /* timeout */
990                        NULL,                                /* cancellable */
991                        NULL,                                /* callback */
992                        NULL                                 /* user_data */
993                        );
994 }
995
996 void
997 ibus_input_context_property_hide (IBusInputContext *context,
998                                        const gchar      *prop_name)
999 {
1000     g_assert (IBUS_IS_INPUT_CONTEXT (context));
1001     g_dbus_proxy_call ((GDBusProxy *) context,
1002                        "PropertyHide",                      /* method_name */
1003                        g_variant_new ("(s)", prop_name),    /* parameters */
1004                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
1005                        -1,                                  /* timeout */
1006                        NULL,                                /* cancellable */
1007                        NULL,                                /* callback */
1008                        NULL                                 /* user_data */
1009                        );
1010 }
1011
1012 void
1013 ibus_input_context_set_surrounding_text (IBusInputContext   *context,
1014                                          IBusText           *text,
1015                                          guint32             cursor_pos,
1016                                          guint32             anchor_pos)
1017 {
1018     g_assert (IBUS_IS_INPUT_CONTEXT (context));
1019     g_assert (IBUS_IS_TEXT (text));
1020
1021     IBusInputContextPrivate *priv;
1022     priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (context);
1023
1024     if (cursor_pos != priv->surrounding_cursor_pos ||
1025         anchor_pos != priv->selection_anchor_pos ||
1026         priv->surrounding_text == NULL ||
1027         g_strcmp0 (text->text, priv->surrounding_text->text) != 0) {
1028         if (priv->surrounding_text)
1029             g_object_unref (priv->surrounding_text);
1030         priv->surrounding_text = (IBusText *) g_object_ref_sink (text);
1031         priv->surrounding_cursor_pos = cursor_pos;
1032         priv->selection_anchor_pos = anchor_pos;
1033
1034         if (priv->needs_surrounding_text) {
1035             GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1036             g_dbus_proxy_call ((GDBusProxy *) context,
1037                                "SetSurroundingText",        /* method_name */
1038                                g_variant_new ("(vuu)",
1039                                               variant,
1040                                               cursor_pos,
1041                                               anchor_pos),  /* parameters */
1042                                 G_DBUS_CALL_FLAGS_NONE,     /* flags */
1043                                 -1,                         /* timeout */
1044                                 NULL,                       /* cancellable */
1045                                 NULL,                       /* callback */
1046                                 NULL                        /* user_data */
1047                                 );
1048         }
1049     }
1050 }
1051
1052 gboolean
1053 ibus_input_context_needs_surrounding_text (IBusInputContext *context)
1054 {
1055     IBusInputContextPrivate *priv;
1056     priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
1057     return priv->needs_surrounding_text;
1058 }
1059
1060 void
1061 ibus_input_context_get_engine_async (IBusInputContext   *context,
1062                                      gint                timeout_msec,
1063                                      GCancellable       *cancellable,
1064                                      GAsyncReadyCallback callback,
1065                                      gpointer            user_data)
1066 {
1067     g_assert (IBUS_IS_INPUT_CONTEXT (context));
1068     g_dbus_proxy_call ((GDBusProxy *) context,
1069                        "GetEngine",               /* method_name */
1070                        NULL,                      /* parameters */
1071                        G_DBUS_CALL_FLAGS_NONE,    /* flags */
1072                        timeout_msec,
1073                        cancellable,
1074                        callback,
1075                        user_data);
1076 }
1077
1078 IBusEngineDesc *
1079 ibus_input_context_get_engine_async_finish (IBusInputContext   *context,
1080                                             GAsyncResult       *res,
1081                                             GError            **error)
1082 {
1083     g_assert (IBUS_IS_INPUT_CONTEXT (context));
1084     g_assert (G_IS_ASYNC_RESULT (res));
1085     g_assert (error == NULL || *error == NULL);
1086
1087     GVariant *variant = g_dbus_proxy_call_finish ((GDBusProxy *) context,
1088                                                    res, error);
1089     if (variant == NULL) {
1090         return NULL;
1091     }
1092
1093     GVariant *engine_desc_variant = g_variant_get_child_value (variant, 0);
1094     IBusEngineDesc *desc = IBUS_ENGINE_DESC (ibus_serializable_deserialize (engine_desc_variant));
1095     g_variant_unref (engine_desc_variant);
1096     g_variant_unref (variant);
1097
1098     return desc;
1099 }
1100
1101 IBusEngineDesc *
1102 ibus_input_context_get_engine (IBusInputContext *context)
1103 {
1104     g_assert (IBUS_IS_INPUT_CONTEXT (context));
1105     GVariant *result = NULL;
1106     GError *error = NULL;
1107     result = g_dbus_proxy_call_sync ((GDBusProxy *) context,
1108                                      "GetEngine",               /* method_name */
1109                                      NULL,                      /* parameters */
1110                                      G_DBUS_CALL_FLAGS_NONE,    /* flags */
1111                                      -1,                        /* timeout */
1112                                      NULL,                      /* cancellable */
1113                                      &error                     /* error */
1114                                      );
1115     if (result == NULL) {
1116         if (g_error_matches (error, IBUS_ERROR, IBUS_ERROR_NO_ENGINE)) {
1117             g_debug ("%s.GetEngine: %s",
1118                      IBUS_INTERFACE_INPUT_CONTEXT,
1119                      error->message);
1120         }
1121         else {
1122             g_warning ("%s.GetEngine: %s",
1123                        IBUS_INTERFACE_INPUT_CONTEXT,
1124                        error->message);
1125         }
1126         g_error_free (error);
1127         return NULL;
1128     }
1129
1130     GVariant *engine_desc_variant = g_variant_get_child_value (result, 0);
1131     IBusEngineDesc *desc = IBUS_ENGINE_DESC (ibus_serializable_deserialize (engine_desc_variant));
1132     g_variant_unref (engine_desc_variant);
1133     g_variant_unref (result);
1134
1135     return desc;
1136 }
1137
1138 void
1139 ibus_input_context_set_engine (IBusInputContext *context,
1140                                const gchar *name)
1141 {
1142     g_assert (IBUS_IS_INPUT_CONTEXT (context));
1143     g_assert (name);
1144     g_dbus_proxy_call ((GDBusProxy *) context,
1145                        "SetEngine",                         /* method_name */
1146                        g_variant_new ("(s)", name),         /* parameters */
1147                        G_DBUS_CALL_FLAGS_NONE,              /* flags */
1148                        -1,                                  /* timeout */
1149                        NULL,                                /* cancellable */
1150                        NULL,                                /* callback */
1151                        NULL                                 /* user_data */
1152                        );
1153 }
1154
1155 #define DEFINE_FUNC(name, Name)                                         \
1156     void                                                                \
1157     ibus_input_context_##name (IBusInputContext *context)               \
1158     {                                                                   \
1159         g_assert (IBUS_IS_INPUT_CONTEXT (context));                     \
1160         g_dbus_proxy_call ((GDBusProxy *) context,                      \
1161                            #Name,                   /* method_name */   \
1162                            NULL,                    /* parameters */    \
1163                            G_DBUS_CALL_FLAGS_NONE,  /* flags */         \
1164                            -1,                      /* timeout */       \
1165                            NULL,                    /* cancellable */   \
1166                            NULL,                    /* callback */      \
1167                            NULL                     /* user_data */     \
1168                            );                                           \
1169     }
1170
1171 DEFINE_FUNC(focus_in, FocusIn);
1172 DEFINE_FUNC(focus_out, FocusOut);
1173 DEFINE_FUNC(reset, Reset);
1174 DEFINE_FUNC(page_up, PageUp);
1175 DEFINE_FUNC(page_down, PageDown);
1176 DEFINE_FUNC(cursor_up, CursorUp);
1177 DEFINE_FUNC(cursor_down, CursorDown);
1178 #undef DEFINE_FUNC