Add Ctrl+space customization.
[platform/upstream/ibus.git] / bus / panelproxy.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 "panelproxy.h"
23
24 #include "global.h"
25 #include "marshalers.h"
26 #include "types.h"
27
28 /* panelproxy.c is a very simple proxy class for the panel component that does only the following:
29  *
30  * 1. Handle D-Bus signals from the panel process. For the list of the D-Bus signals, you can check the bus_panel_proxy_g_signal function, or
31  *    introspection_xml in src/ibuspanelservice.c. The bus_panel_proxy_g_signal function simply emits a corresponding glib signal for each
32  *    D-Bus signal.
33  * 2. Handle glib signals for a BusPanelProxy object (which is usually emitted by bus_panel_proxy_g_signal.) The list of such glib signals is
34  *    in the bus_panel_proxy_class_init function. The signal handler function, e.g. bus_panel_proxy_candidate_clicked, simply calls the
35  *    corresponding function in inputcontext.c, e.g. bus_input_context_candidate_clicked, using the current focused context.
36  * 3. Provide a way to call D-Bus methods in the panel process. For the list of the D-Bus methods, you can check the header file (panelproxy.h)
37  *    or introspection_xml in src/ibuspanelservice.c. Functions that calls g_dbus_proxy_call, e.g. bus_panel_proxy_set_cursor_location, would
38  *    fall into this category.
39  * 4. Handle glib signals for a BusInputContext object. The list of such glib signals is in the input_context_signals[] array. The signal handler
40  *    function, e.g. _context_set_cursor_location_cb, simply invokes a D-Bus method by calling a function like bus_panel_proxy_set_cursor_location.
41  */
42
43 enum {
44     PAGE_UP,
45     PAGE_DOWN,
46     CURSOR_UP,
47     CURSOR_DOWN,
48     CANDIDATE_CLICKED,
49     PROPERTY_ACTIVATE,
50     PROPERTY_SHOW,
51     PROPERTY_HIDE,
52     LAST_SIGNAL,
53 };
54
55 struct _BusPanelProxy {
56     IBusProxy parent;
57
58     /* instance members */
59     BusInputContext *focused_context;
60 };
61
62 struct _BusPanelProxyClass {
63     IBusProxyClass parent;
64     /* class members */
65
66     void (* page_up)            (BusPanelProxy   *panel);
67     void (* page_down)          (BusPanelProxy   *panel);
68     void (* cursor_up)          (BusPanelProxy   *panel);
69     void (* cursor_down)        (BusPanelProxy   *panel);
70     void (* candidate_clicked)  (BusPanelProxy   *panel,
71                                  guint            index,
72                                  guint            button,
73                                  guint            state);
74
75     void (* property_activate)  (BusPanelProxy   *panel,
76                                  const gchar     *prop_name,
77                                  gint             prop_state);
78 };
79
80 static guint    panel_signals[LAST_SIGNAL] = { 0 };
81
82 /* functions prototype */
83 static void     bus_panel_proxy_init            (BusPanelProxy          *panel);
84 static void     bus_panel_proxy_real_destroy    (IBusProxy              *proxy);
85 static void     bus_panel_proxy_g_signal        (GDBusProxy             *proxy,
86                                                  const gchar            *sender_name,
87                                                  const gchar            *signal_name,
88                                                  GVariant               *parameters);
89 static void     bus_panel_proxy_page_up         (BusPanelProxy          *panel);
90 static void     bus_panel_proxy_page_down       (BusPanelProxy          *panel);
91 static void     bus_panel_proxy_cursor_up       (BusPanelProxy          *panel);
92 static void     bus_panel_proxy_cursor_down     (BusPanelProxy          *panel);
93 static void     bus_panel_proxy_candidate_clicked
94                                                 (BusPanelProxy          *panel,
95                                                  guint                   index,
96                                                  guint                   button,
97                                                  guint                   state);
98 static void     bus_panel_proxy_property_activate
99                                                 (BusPanelProxy          *panel,
100                                                  const gchar            *prop_name,
101                                                  gint                    prop_state);
102
103 G_DEFINE_TYPE(BusPanelProxy, bus_panel_proxy, IBUS_TYPE_PROXY)
104
105 BusPanelProxy *
106 bus_panel_proxy_new (BusConnection *connection)
107 {
108     g_assert (BUS_IS_CONNECTION (connection));
109
110     GObject *obj;
111     obj = g_initable_new (BUS_TYPE_PANEL_PROXY,
112                           NULL,
113                           NULL,
114                           "g-object-path",     IBUS_PATH_PANEL,
115                           "g-interface-name",  IBUS_INTERFACE_PANEL,
116                           "g-connection",      bus_connection_get_dbus_connection (connection),
117                           "g-default-timeout", g_gdbus_timeout,
118                           "g-flags",           G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
119                           NULL);
120
121     return BUS_PANEL_PROXY (obj);
122 }
123
124 static void
125 bus_panel_proxy_class_init (BusPanelProxyClass *class)
126 {
127     IBUS_PROXY_CLASS (class)->destroy = bus_panel_proxy_real_destroy;
128     G_DBUS_PROXY_CLASS (class)->g_signal = bus_panel_proxy_g_signal;
129
130     class->page_up     = bus_panel_proxy_page_up;
131     class->page_down   = bus_panel_proxy_page_down;
132     class->cursor_up   = bus_panel_proxy_cursor_up;
133     class->cursor_down = bus_panel_proxy_cursor_down;
134     class->candidate_clicked = bus_panel_proxy_candidate_clicked;
135     class->property_activate = bus_panel_proxy_property_activate;
136
137     /* install signals */
138     panel_signals[PAGE_UP] =
139         g_signal_new (I_("page-up"),
140             G_TYPE_FROM_CLASS (class),
141             G_SIGNAL_RUN_LAST,
142             G_STRUCT_OFFSET(BusPanelProxyClass, page_up),
143             NULL, NULL,
144             bus_marshal_VOID__VOID,
145             G_TYPE_NONE, 0);
146
147     panel_signals[PAGE_DOWN] =
148         g_signal_new (I_("page-down"),
149             G_TYPE_FROM_CLASS (class),
150             G_SIGNAL_RUN_LAST,
151             G_STRUCT_OFFSET(BusPanelProxyClass, page_down),
152             NULL, NULL,
153             bus_marshal_VOID__VOID,
154             G_TYPE_NONE, 0);
155
156     panel_signals[CURSOR_UP] =
157         g_signal_new (I_("cursor-up"),
158             G_TYPE_FROM_CLASS (class),
159             G_SIGNAL_RUN_LAST,
160             G_STRUCT_OFFSET(BusPanelProxyClass, cursor_up),
161             NULL, NULL,
162             bus_marshal_VOID__VOID,
163             G_TYPE_NONE, 0);
164
165     panel_signals[CURSOR_DOWN] =
166         g_signal_new (I_("cursor-down"),
167             G_TYPE_FROM_CLASS (class),
168             G_SIGNAL_RUN_LAST,
169             G_STRUCT_OFFSET(BusPanelProxyClass, cursor_down),
170             NULL, NULL,
171             bus_marshal_VOID__VOID,
172             G_TYPE_NONE, 0);
173
174     panel_signals[CANDIDATE_CLICKED] =
175         g_signal_new (I_("candidate-clicked"),
176             G_TYPE_FROM_CLASS (class),
177             G_SIGNAL_RUN_LAST,
178             G_STRUCT_OFFSET(BusPanelProxyClass, candidate_clicked),
179             NULL, NULL,
180             bus_marshal_VOID__UINT_UINT_UINT,
181             G_TYPE_NONE, 3,
182             G_TYPE_UINT,
183             G_TYPE_UINT,
184             G_TYPE_UINT);
185
186     panel_signals[PROPERTY_ACTIVATE] =
187         g_signal_new (I_("property-activate"),
188             G_TYPE_FROM_CLASS (class),
189             G_SIGNAL_RUN_LAST,
190             G_STRUCT_OFFSET(BusPanelProxyClass, property_activate),
191             NULL, NULL,
192             bus_marshal_VOID__STRING_INT,
193             G_TYPE_NONE, 2,
194             G_TYPE_STRING,
195             G_TYPE_INT);
196
197     panel_signals[PROPERTY_SHOW] =
198         g_signal_new (I_("property-show"),
199             G_TYPE_FROM_CLASS (class),
200             G_SIGNAL_RUN_LAST,
201             0,
202             NULL, NULL,
203             bus_marshal_VOID__STRING,
204             G_TYPE_NONE, 1,
205             G_TYPE_STRING);
206
207     panel_signals[PROPERTY_HIDE] =
208         g_signal_new (I_("property-hide"),
209             G_TYPE_FROM_CLASS (class),
210             G_SIGNAL_RUN_LAST,
211             0,
212             NULL, NULL,
213             bus_marshal_VOID__STRING,
214             G_TYPE_NONE, 1,
215             G_TYPE_STRING);
216
217 }
218
219 static void
220 bus_panel_proxy_init (BusPanelProxy *panel)
221 {
222     /* member variables will automatically be zero-cleared. */
223 }
224
225 static void
226 bus_panel_proxy_real_destroy (IBusProxy *proxy)
227 {
228     BusPanelProxy *panel = (BusPanelProxy *)proxy;
229
230     if (panel->focused_context) {
231         bus_panel_proxy_focus_out (panel, panel->focused_context);
232         panel->focused_context = NULL;
233     }
234
235     IBUS_PROXY_CLASS(bus_panel_proxy_parent_class)->destroy ((IBusProxy *)panel);
236 }
237
238 /**
239  * bus_panel_proxy_g_signal:
240  *
241  * Handle all D-Bus signals from the panel process. This function emits a corresponding glib signal for each D-Bus signal.
242  */
243 static void
244 bus_panel_proxy_g_signal (GDBusProxy  *proxy,
245                           const gchar *sender_name,
246                           const gchar *signal_name,
247                           GVariant    *parameters)
248 {
249     BusPanelProxy *panel = (BusPanelProxy *)proxy;
250
251     /* The list of nullary D-Bus signals. */
252     static const struct {
253         const gchar *signal_name;
254         const guint  signal_id;
255     } signals [] = {
256         { "PageUp",         PAGE_UP },
257         { "PageDown",       PAGE_DOWN },
258         { "CursorUp",       CURSOR_UP },
259         { "CursorDown",     CURSOR_DOWN },
260     };
261
262     gint i;
263     for (i = 0; i < G_N_ELEMENTS (signals); i++) {
264         if (g_strcmp0 (signal_name, signals[i].signal_name) == 0) {
265             g_signal_emit (panel, panel_signals[signals[i].signal_id], 0);
266             return;
267         }
268     }
269
270     /* Handle D-Bus signals with parameters. Deserialize them and emit a glib signal. */
271     if (g_strcmp0 ("CandidateClicked", signal_name) == 0) {
272         guint index = 0;
273         guint button = 0;
274         guint state = 0;
275         g_variant_get (parameters, "(uuu)", &index, &button, &state);
276         g_signal_emit (panel, panel_signals[CANDIDATE_CLICKED], 0, index, button, state);
277         return;
278     }
279
280     if (g_strcmp0 ("PropertyActivate", signal_name) == 0) {
281         gchar *prop_name = NULL;
282         gint prop_state = 0;
283         g_variant_get (parameters, "(&su)", &prop_name, &prop_state);
284         g_signal_emit (panel, panel_signals[PROPERTY_ACTIVATE], 0, prop_name, prop_state);
285         return;
286     }
287
288     if (g_strcmp0 ("PropertyShow", signal_name) == 0) {
289         gchar *prop_name = NULL;
290         g_variant_get (parameters, "(&s)", &prop_name);
291         g_signal_emit (panel, panel_signals[PROPERTY_SHOW], 0, prop_name);
292         return;
293     }
294
295     if (g_strcmp0 ("PropertyHide", signal_name) == 0) {
296         gchar *prop_name = NULL;
297         g_variant_get (parameters, "(&s)", &prop_name);
298         g_signal_emit (panel, panel_signals[PROPERTY_HIDE], 0, prop_name);
299         return;
300     }
301
302     /* shound not be reached */
303     g_return_if_reached ();
304 }
305
306
307 void
308 bus_panel_proxy_set_cursor_location (BusPanelProxy *panel,
309                                      gint           x,
310                                      gint           y,
311                                      gint           w,
312                                      gint           h)
313 {
314     g_assert (BUS_IS_PANEL_PROXY (panel));
315     g_dbus_proxy_call ((GDBusProxy *)panel,
316                        "SetCursorLocation",
317                        g_variant_new ("(iiii)", x, y, w, h),
318                        G_DBUS_CALL_FLAGS_NONE,
319                        -1, NULL, NULL, NULL);
320 }
321
322 void
323 bus_panel_proxy_update_preedit_text (BusPanelProxy  *panel,
324                                      IBusText       *text,
325                                      guint           cursor_pos,
326                                      gboolean        visible)
327 {
328     g_assert (BUS_IS_PANEL_PROXY (panel));
329     g_assert (IBUS_IS_TEXT (text));
330
331     GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )text);
332     g_dbus_proxy_call ((GDBusProxy *)panel,
333                        "UpdatePreeditText",
334                        g_variant_new ("(vub)", variant, cursor_pos, visible),
335                        G_DBUS_CALL_FLAGS_NONE,
336                        -1, NULL, NULL, NULL);
337 }
338
339 void
340 bus_panel_proxy_update_auxiliary_text (BusPanelProxy *panel,
341                                        IBusText      *text,
342                                        gboolean       visible)
343 {
344     g_assert (BUS_IS_PANEL_PROXY (panel));
345     g_assert (IBUS_IS_TEXT (text));
346
347     GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )text);
348     g_dbus_proxy_call ((GDBusProxy *)panel,
349                        "UpdateAuxiliaryText",
350                        g_variant_new ("(vb)", variant, visible),
351                        G_DBUS_CALL_FLAGS_NONE,
352                        -1, NULL, NULL, NULL);
353 }
354
355 void
356 bus_panel_proxy_update_lookup_table (BusPanelProxy   *panel,
357                                      IBusLookupTable *table,
358                                      gboolean         visible)
359 {
360     g_assert (BUS_IS_PANEL_PROXY (panel));
361     g_assert (IBUS_IS_LOOKUP_TABLE (table));
362
363     GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )table);
364     g_dbus_proxy_call ((GDBusProxy *)panel,
365                        "UpdateLookupTable",
366                        g_variant_new ("(vb)", variant, visible),
367                        G_DBUS_CALL_FLAGS_NONE,
368                        -1, NULL, NULL, NULL);
369 }
370
371 void
372 bus_panel_proxy_register_properties (BusPanelProxy  *panel,
373                                      IBusPropList   *prop_list)
374 {
375     g_assert (BUS_IS_PANEL_PROXY (panel));
376     g_assert (IBUS_IS_PROP_LIST (prop_list));
377
378     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop_list);
379     g_dbus_proxy_call ((GDBusProxy *)panel,
380                        "RegisterProperties",
381                        g_variant_new ("(v)", variant),
382                        G_DBUS_CALL_FLAGS_NONE,
383                        -1, NULL, NULL, NULL);
384 }
385
386 void
387 bus_panel_proxy_update_property (BusPanelProxy  *panel,
388                                  IBusProperty   *prop)
389 {
390     g_assert (BUS_IS_PANEL_PROXY (panel));
391     g_assert (IBUS_IS_PROPERTY (prop));
392
393     GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
394     g_dbus_proxy_call ((GDBusProxy *)panel,
395                        "UpdateProperty",
396                        g_variant_new ("(v)", variant),
397                        G_DBUS_CALL_FLAGS_NONE,
398                        -1, NULL, NULL, NULL);
399 }
400
401 #define DEFINE_FUNC(name)                                       \
402     static void                                                 \
403     bus_panel_proxy_##name (BusPanelProxy *panel)               \
404     {                                                           \
405         g_assert (BUS_IS_PANEL_PROXY (panel));                  \
406                                                                 \
407         if (panel->focused_context) {                           \
408             bus_input_context_##name (panel->focused_context);  \
409         }                                                       \
410     }
411
412 DEFINE_FUNC(page_up)
413 DEFINE_FUNC(page_down)
414 DEFINE_FUNC(cursor_up)
415 DEFINE_FUNC(cursor_down)
416 #undef DEFINE_FUNC
417
418 static void
419 bus_panel_proxy_candidate_clicked (BusPanelProxy *panel,
420                                    guint          index,
421                                    guint          button,
422                                    guint          state)
423 {
424     g_assert (BUS_IS_PANEL_PROXY (panel));
425
426     if (panel->focused_context) {
427         bus_input_context_candidate_clicked (panel->focused_context,
428                                              index,
429                                              button,
430                                              state);
431     }
432 }
433
434 static void
435 bus_panel_proxy_property_activate (BusPanelProxy *panel,
436                                    const gchar   *prop_name,
437                                    gint          prop_state)
438 {
439     g_assert (BUS_IS_PANEL_PROXY (panel));
440
441     if (panel->focused_context) {
442         bus_input_context_property_activate (panel->focused_context, prop_name, prop_state);
443     }
444 }
445
446 #define DEFINE_FUNCTION(Name, name)                     \
447     void bus_panel_proxy_##name (BusPanelProxy *panel)  \
448     {                                                   \
449         g_assert (BUS_IS_PANEL_PROXY (panel));          \
450         g_dbus_proxy_call ((GDBusProxy *) panel,        \
451                            #Name,                       \
452                            NULL,                        \
453                            G_DBUS_CALL_FLAGS_NONE,      \
454                            -1, NULL, NULL, NULL);       \
455     }
456
457 DEFINE_FUNCTION (ShowPreeditText, show_preedit_text)
458 DEFINE_FUNCTION (HidePreeditText, hide_preedit_text)
459 DEFINE_FUNCTION (ShowAuxiliaryText, show_auxiliary_text)
460 DEFINE_FUNCTION (HideAuxiliaryText, hide_auxiliary_text)
461 DEFINE_FUNCTION (ShowLookupTable, show_lookup_table)
462 DEFINE_FUNCTION (HideLookupTable, hide_lookup_table)
463 DEFINE_FUNCTION (PageUpLookupTable, page_up_lookup_table)
464 DEFINE_FUNCTION (PageDownLookupTable, page_down_lookup_table)
465 DEFINE_FUNCTION (CursorUpLookupTable, cursor_up_lookup_table)
466 DEFINE_FUNCTION (CursorDownLookupTable, cursor_down_lookup_table)
467 DEFINE_FUNCTION (StateChanged, state_changed)
468
469 #undef DEFINE_FUNCTION
470
471 static void
472 _context_set_cursor_location_cb (BusInputContext *context,
473                                  gint             x,
474                                  gint             y,
475                                  gint             w,
476                                  gint             h,
477                                  BusPanelProxy   *panel)
478 {
479     g_assert (BUS_IS_INPUT_CONTEXT (context));
480     g_assert (BUS_IS_PANEL_PROXY (panel));
481
482     g_return_if_fail (panel->focused_context == context);
483
484     bus_panel_proxy_set_cursor_location (panel, x, y, w, h);
485 }
486
487 static void
488 _context_update_preedit_text_cb (BusInputContext *context,
489                                  IBusText        *text,
490                                  guint            cursor_pos,
491                                  gboolean         visible,
492                                  BusPanelProxy   *panel)
493 {
494     g_assert (BUS_IS_INPUT_CONTEXT (context));
495     g_assert (text != NULL);
496     g_assert (BUS_IS_PANEL_PROXY (panel));
497
498     g_return_if_fail (panel->focused_context == context);
499
500     bus_panel_proxy_update_preedit_text (panel,
501                                          text,
502                                          cursor_pos,
503                                          visible);
504 }
505
506 static void
507 _context_update_auxiliary_text_cb (BusInputContext *context,
508                                    IBusText        *text,
509                                    gboolean         visible,
510                                    BusPanelProxy   *panel)
511 {
512     g_assert (BUS_IS_INPUT_CONTEXT (context));
513     g_assert (BUS_IS_PANEL_PROXY (panel));
514
515     g_return_if_fail (panel->focused_context == context);
516
517     bus_panel_proxy_update_auxiliary_text (panel,
518                                            text,
519                                            visible);
520 }
521
522 static void
523 _context_update_lookup_table_cb (BusInputContext *context,
524                                  IBusLookupTable *table,
525                                  gboolean         visible,
526                                  BusPanelProxy   *panel)
527 {
528     g_assert (BUS_IS_INPUT_CONTEXT (context));
529     g_assert (BUS_IS_PANEL_PROXY (panel));
530
531     g_return_if_fail (panel->focused_context == context);
532
533     bus_panel_proxy_update_lookup_table (panel,
534                                          table,
535                                          visible);
536 }
537
538 static void
539 _context_register_properties_cb (BusInputContext *context,
540                                  IBusPropList    *prop_list,
541                                  BusPanelProxy   *panel)
542 {
543     g_assert (BUS_IS_INPUT_CONTEXT (context));
544     g_assert (BUS_IS_PANEL_PROXY (panel));
545
546     g_return_if_fail (panel->focused_context == context);
547
548     bus_panel_proxy_register_properties (panel,
549                                          prop_list);
550 }
551
552 static void
553 _context_update_property_cb (BusInputContext *context,
554                              IBusProperty    *prop,
555                              BusPanelProxy   *panel)
556 {
557     g_assert (BUS_IS_INPUT_CONTEXT (context));
558     g_assert (BUS_IS_PANEL_PROXY (panel));
559
560     g_return_if_fail (panel->focused_context == context);
561
562     bus_panel_proxy_update_property (panel,
563                                      prop);
564 }
565
566 static void
567 _context_destroy_cb (BusInputContext *context,
568                      BusPanelProxy   *panel)
569 {
570     g_assert (BUS_IS_INPUT_CONTEXT (context));
571     g_assert (BUS_IS_PANEL_PROXY (panel));
572
573     g_assert (context == panel->focused_context);
574
575     bus_panel_proxy_focus_out (panel, context);
576 }
577
578 #define DEFINE_FUNCTION(name)                                   \
579     static void _context_##name##_cb (BusInputContext *context, \
580                                       BusPanelProxy   *panel)   \
581     {                                                           \
582         g_assert (BUS_IS_INPUT_CONTEXT (context));              \
583         g_assert (BUS_IS_PANEL_PROXY (panel));                  \
584                                                                 \
585         g_return_if_fail (panel->focused_context == context);   \
586                                                                 \
587         bus_panel_proxy_##name (panel);                         \
588     }
589
590 DEFINE_FUNCTION (show_preedit_text)
591 DEFINE_FUNCTION (hide_preedit_text)
592 DEFINE_FUNCTION (show_auxiliary_text)
593 DEFINE_FUNCTION (hide_auxiliary_text)
594 DEFINE_FUNCTION (show_lookup_table)
595 DEFINE_FUNCTION (hide_lookup_table)
596 DEFINE_FUNCTION (page_up_lookup_table)
597 DEFINE_FUNCTION (page_down_lookup_table)
598 DEFINE_FUNCTION (cursor_up_lookup_table)
599 DEFINE_FUNCTION (cursor_down_lookup_table)
600 DEFINE_FUNCTION (state_changed)
601
602 #undef DEFINE_FUNCTION
603
604 static const struct {
605     gchar *name;
606     GCallback callback;
607 } input_context_signals[] = {
608     { "set-cursor-location",        G_CALLBACK (_context_set_cursor_location_cb) },
609
610     { "update-preedit-text",        G_CALLBACK (_context_update_preedit_text_cb) },
611     { "show-preedit-text",          G_CALLBACK (_context_show_preedit_text_cb) },
612     { "hide-preedit-text",          G_CALLBACK (_context_hide_preedit_text_cb) },
613
614     { "update-auxiliary-text",      G_CALLBACK (_context_update_auxiliary_text_cb) },
615     { "show-auxiliary-text",        G_CALLBACK (_context_show_auxiliary_text_cb) },
616     { "hide-auxiliary-text",        G_CALLBACK (_context_hide_auxiliary_text_cb) },
617
618     { "update-lookup-table",        G_CALLBACK (_context_update_lookup_table_cb) },
619     { "show-lookup-table",          G_CALLBACK (_context_show_lookup_table_cb) },
620     { "hide-lookup-table",          G_CALLBACK (_context_hide_lookup_table_cb) },
621     { "page-up-lookup-table",       G_CALLBACK (_context_page_up_lookup_table_cb) },
622     { "page-down-lookup-table",     G_CALLBACK (_context_page_down_lookup_table_cb) },
623     { "cursor-up-lookup-table",     G_CALLBACK (_context_cursor_up_lookup_table_cb) },
624     { "cursor-down-lookup-table",   G_CALLBACK (_context_cursor_down_lookup_table_cb) },
625
626     { "register-properties",        G_CALLBACK (_context_register_properties_cb) },
627     { "update-property",            G_CALLBACK (_context_update_property_cb) },
628
629     { "engine-changed",             G_CALLBACK (_context_state_changed_cb) },
630
631     { "destroy",                    G_CALLBACK (_context_destroy_cb) },
632 };
633
634 void
635 bus_panel_proxy_focus_in (BusPanelProxy     *panel,
636                           BusInputContext   *context)
637 {
638     g_assert (BUS_IS_PANEL_PROXY (panel));
639     g_assert (BUS_IS_INPUT_CONTEXT (context));
640
641     if (panel->focused_context == context)
642         return;
643
644     if (panel->focused_context != NULL)
645         bus_panel_proxy_focus_out (panel, panel->focused_context);
646
647     g_object_ref_sink (context);
648     panel->focused_context = context;
649
650     const gchar *path = ibus_service_get_object_path ((IBusService *)context);
651
652     g_dbus_proxy_call ((GDBusProxy *)panel,
653                        "FocusIn",
654                        g_variant_new ("(o)", path),
655                        G_DBUS_CALL_FLAGS_NONE,
656                        -1, NULL, NULL, NULL);
657
658     /* install signal handlers */
659     gint i;
660     for (i = 0; i < G_N_ELEMENTS (input_context_signals); i++) {
661         g_signal_connect (context,
662                           input_context_signals[i].name,
663                           input_context_signals[i].callback,
664                           panel);
665     }
666 }
667
668 void
669 bus_panel_proxy_focus_out (BusPanelProxy    *panel,
670                            BusInputContext  *context)
671 {
672     g_assert (BUS_IS_PANEL_PROXY (panel));
673     g_assert (BUS_IS_INPUT_CONTEXT (context));
674
675     g_assert (panel->focused_context == context);
676
677     /* uninstall signal handlers */
678     gint i;
679     for (i = 0; i < G_N_ELEMENTS (input_context_signals); i++) {
680         g_signal_handlers_disconnect_by_func (context,
681                                               input_context_signals[i].callback,
682                                               panel);
683     }
684
685     const gchar *path = ibus_service_get_object_path ((IBusService *)context);
686
687     g_dbus_proxy_call ((GDBusProxy *)panel,
688                        "FocusOut",
689                        g_variant_new ("(o)", path),
690                        G_DBUS_CALL_FLAGS_NONE,
691                        -1, NULL, NULL, NULL);
692
693     g_object_unref (panel->focused_context);
694     panel->focused_context = NULL;
695 }
696