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