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.
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.
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.
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.
22 #include "panelproxy.h"
25 #include "marshalers.h"
28 /* panelproxy.c is a very simple proxy class for the panel component that does only the following:
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
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.
55 struct _BusPanelProxy {
58 /* instance members */
59 BusInputContext *focused_context;
62 struct _BusPanelProxyClass {
63 IBusProxyClass parent;
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,
75 void (* property_activate) (BusPanelProxy *panel,
76 const gchar *prop_name,
80 static guint panel_signals[LAST_SIGNAL] = { 0 };
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,
98 static void bus_panel_proxy_property_activate
99 (BusPanelProxy *panel,
100 const gchar *prop_name,
103 G_DEFINE_TYPE(BusPanelProxy, bus_panel_proxy, IBUS_TYPE_PROXY)
106 bus_panel_proxy_new (BusConnection *connection)
108 g_assert (BUS_IS_CONNECTION (connection));
111 obj = g_initable_new (BUS_TYPE_PANEL_PROXY,
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,
121 return BUS_PANEL_PROXY (obj);
125 bus_panel_proxy_class_init (BusPanelProxyClass *class)
127 IBUS_PROXY_CLASS (class)->destroy = bus_panel_proxy_real_destroy;
128 G_DBUS_PROXY_CLASS (class)->g_signal = bus_panel_proxy_g_signal;
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;
137 /* install signals */
138 panel_signals[PAGE_UP] =
139 g_signal_new (I_("page-up"),
140 G_TYPE_FROM_CLASS (class),
142 G_STRUCT_OFFSET(BusPanelProxyClass, page_up),
144 bus_marshal_VOID__VOID,
147 panel_signals[PAGE_DOWN] =
148 g_signal_new (I_("page-down"),
149 G_TYPE_FROM_CLASS (class),
151 G_STRUCT_OFFSET(BusPanelProxyClass, page_down),
153 bus_marshal_VOID__VOID,
156 panel_signals[CURSOR_UP] =
157 g_signal_new (I_("cursor-up"),
158 G_TYPE_FROM_CLASS (class),
160 G_STRUCT_OFFSET(BusPanelProxyClass, cursor_up),
162 bus_marshal_VOID__VOID,
165 panel_signals[CURSOR_DOWN] =
166 g_signal_new (I_("cursor-down"),
167 G_TYPE_FROM_CLASS (class),
169 G_STRUCT_OFFSET(BusPanelProxyClass, cursor_down),
171 bus_marshal_VOID__VOID,
174 panel_signals[CANDIDATE_CLICKED] =
175 g_signal_new (I_("candidate-clicked"),
176 G_TYPE_FROM_CLASS (class),
178 G_STRUCT_OFFSET(BusPanelProxyClass, candidate_clicked),
180 bus_marshal_VOID__UINT_UINT_UINT,
186 panel_signals[PROPERTY_ACTIVATE] =
187 g_signal_new (I_("property-activate"),
188 G_TYPE_FROM_CLASS (class),
190 G_STRUCT_OFFSET(BusPanelProxyClass, property_activate),
192 bus_marshal_VOID__STRING_INT,
197 panel_signals[PROPERTY_SHOW] =
198 g_signal_new (I_("property-show"),
199 G_TYPE_FROM_CLASS (class),
203 bus_marshal_VOID__STRING,
207 panel_signals[PROPERTY_HIDE] =
208 g_signal_new (I_("property-hide"),
209 G_TYPE_FROM_CLASS (class),
213 bus_marshal_VOID__STRING,
220 bus_panel_proxy_init (BusPanelProxy *panel)
222 /* member variables will automatically be zero-cleared. */
226 bus_panel_proxy_real_destroy (IBusProxy *proxy)
228 BusPanelProxy *panel = (BusPanelProxy *)proxy;
230 if (panel->focused_context) {
231 bus_panel_proxy_focus_out (panel, panel->focused_context);
232 panel->focused_context = NULL;
235 IBUS_PROXY_CLASS(bus_panel_proxy_parent_class)->destroy ((IBusProxy *)panel);
239 * bus_panel_proxy_g_signal:
241 * Handle all D-Bus signals from the panel process. This function emits a corresponding glib signal for each D-Bus signal.
244 bus_panel_proxy_g_signal (GDBusProxy *proxy,
245 const gchar *sender_name,
246 const gchar *signal_name,
247 GVariant *parameters)
249 BusPanelProxy *panel = (BusPanelProxy *)proxy;
251 /* The list of nullary D-Bus signals. */
252 static const struct {
253 const gchar *signal_name;
254 const guint signal_id;
256 { "PageUp", PAGE_UP },
257 { "PageDown", PAGE_DOWN },
258 { "CursorUp", CURSOR_UP },
259 { "CursorDown", CURSOR_DOWN },
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);
270 /* Handle D-Bus signals with parameters. Deserialize them and emit a glib signal. */
271 if (g_strcmp0 ("CandidateClicked", signal_name) == 0) {
275 g_variant_get (parameters, "(uuu)", &index, &button, &state);
276 g_signal_emit (panel, panel_signals[CANDIDATE_CLICKED], 0, index, button, state);
280 if (g_strcmp0 ("PropertyActivate", signal_name) == 0) {
281 gchar *prop_name = NULL;
283 g_variant_get (parameters, "(&su)", &prop_name, &prop_state);
284 g_signal_emit (panel, panel_signals[PROPERTY_ACTIVATE], 0, prop_name, prop_state);
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);
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);
302 /* shound not be reached */
303 g_return_if_reached ();
308 bus_panel_proxy_set_cursor_location (BusPanelProxy *panel,
314 g_assert (BUS_IS_PANEL_PROXY (panel));
315 g_dbus_proxy_call ((GDBusProxy *)panel,
317 g_variant_new ("(iiii)", x, y, w, h),
318 G_DBUS_CALL_FLAGS_NONE,
319 -1, NULL, NULL, NULL);
323 bus_panel_proxy_update_preedit_text (BusPanelProxy *panel,
328 g_assert (BUS_IS_PANEL_PROXY (panel));
329 g_assert (IBUS_IS_TEXT (text));
331 GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )text);
332 g_dbus_proxy_call ((GDBusProxy *)panel,
334 g_variant_new ("(vub)", variant, cursor_pos, visible),
335 G_DBUS_CALL_FLAGS_NONE,
336 -1, NULL, NULL, NULL);
340 bus_panel_proxy_update_auxiliary_text (BusPanelProxy *panel,
344 g_assert (BUS_IS_PANEL_PROXY (panel));
345 g_assert (IBUS_IS_TEXT (text));
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);
356 bus_panel_proxy_update_lookup_table (BusPanelProxy *panel,
357 IBusLookupTable *table,
360 g_assert (BUS_IS_PANEL_PROXY (panel));
361 g_assert (IBUS_IS_LOOKUP_TABLE (table));
363 GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )table);
364 g_dbus_proxy_call ((GDBusProxy *)panel,
366 g_variant_new ("(vb)", variant, visible),
367 G_DBUS_CALL_FLAGS_NONE,
368 -1, NULL, NULL, NULL);
372 bus_panel_proxy_register_properties (BusPanelProxy *panel,
373 IBusPropList *prop_list)
375 g_assert (BUS_IS_PANEL_PROXY (panel));
376 g_assert (IBUS_IS_PROP_LIST (prop_list));
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);
387 bus_panel_proxy_update_property (BusPanelProxy *panel,
390 g_assert (BUS_IS_PANEL_PROXY (panel));
391 g_assert (IBUS_IS_PROPERTY (prop));
393 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
394 g_dbus_proxy_call ((GDBusProxy *)panel,
396 g_variant_new ("(v)", variant),
397 G_DBUS_CALL_FLAGS_NONE,
398 -1, NULL, NULL, NULL);
401 #define DEFINE_FUNC(name) \
403 bus_panel_proxy_##name (BusPanelProxy *panel) \
405 g_assert (BUS_IS_PANEL_PROXY (panel)); \
407 if (panel->focused_context) { \
408 bus_input_context_##name (panel->focused_context); \
413 DEFINE_FUNC(page_down)
414 DEFINE_FUNC(cursor_up)
415 DEFINE_FUNC(cursor_down)
419 bus_panel_proxy_candidate_clicked (BusPanelProxy *panel,
424 g_assert (BUS_IS_PANEL_PROXY (panel));
426 if (panel->focused_context) {
427 bus_input_context_candidate_clicked (panel->focused_context,
435 bus_panel_proxy_property_activate (BusPanelProxy *panel,
436 const gchar *prop_name,
439 g_assert (BUS_IS_PANEL_PROXY (panel));
441 if (panel->focused_context) {
442 bus_input_context_property_activate (panel->focused_context, prop_name, prop_state);
446 #define DEFINE_FUNCTION(Name, name) \
447 void bus_panel_proxy_##name (BusPanelProxy *panel) \
449 g_assert (BUS_IS_PANEL_PROXY (panel)); \
450 g_dbus_proxy_call ((GDBusProxy *) panel, \
453 G_DBUS_CALL_FLAGS_NONE, \
454 -1, NULL, NULL, NULL); \
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)
469 #undef DEFINE_FUNCTION
472 _context_set_cursor_location_cb (BusInputContext *context,
477 BusPanelProxy *panel)
479 g_assert (BUS_IS_INPUT_CONTEXT (context));
480 g_assert (BUS_IS_PANEL_PROXY (panel));
482 g_return_if_fail (panel->focused_context == context);
484 bus_panel_proxy_set_cursor_location (panel, x, y, w, h);
488 _context_update_preedit_text_cb (BusInputContext *context,
492 BusPanelProxy *panel)
494 g_assert (BUS_IS_INPUT_CONTEXT (context));
495 g_assert (text != NULL);
496 g_assert (BUS_IS_PANEL_PROXY (panel));
498 g_return_if_fail (panel->focused_context == context);
500 bus_panel_proxy_update_preedit_text (panel,
507 _context_update_auxiliary_text_cb (BusInputContext *context,
510 BusPanelProxy *panel)
512 g_assert (BUS_IS_INPUT_CONTEXT (context));
513 g_assert (BUS_IS_PANEL_PROXY (panel));
515 g_return_if_fail (panel->focused_context == context);
517 bus_panel_proxy_update_auxiliary_text (panel,
523 _context_update_lookup_table_cb (BusInputContext *context,
524 IBusLookupTable *table,
526 BusPanelProxy *panel)
528 g_assert (BUS_IS_INPUT_CONTEXT (context));
529 g_assert (BUS_IS_PANEL_PROXY (panel));
531 g_return_if_fail (panel->focused_context == context);
533 bus_panel_proxy_update_lookup_table (panel,
539 _context_register_properties_cb (BusInputContext *context,
540 IBusPropList *prop_list,
541 BusPanelProxy *panel)
543 g_assert (BUS_IS_INPUT_CONTEXT (context));
544 g_assert (BUS_IS_PANEL_PROXY (panel));
546 g_return_if_fail (panel->focused_context == context);
548 bus_panel_proxy_register_properties (panel,
553 _context_update_property_cb (BusInputContext *context,
555 BusPanelProxy *panel)
557 g_assert (BUS_IS_INPUT_CONTEXT (context));
558 g_assert (BUS_IS_PANEL_PROXY (panel));
560 g_return_if_fail (panel->focused_context == context);
562 bus_panel_proxy_update_property (panel,
567 _context_destroy_cb (BusInputContext *context,
568 BusPanelProxy *panel)
570 g_assert (BUS_IS_INPUT_CONTEXT (context));
571 g_assert (BUS_IS_PANEL_PROXY (panel));
573 g_assert (context == panel->focused_context);
575 bus_panel_proxy_focus_out (panel, context);
578 #define DEFINE_FUNCTION(name) \
579 static void _context_##name##_cb (BusInputContext *context, \
580 BusPanelProxy *panel) \
582 g_assert (BUS_IS_INPUT_CONTEXT (context)); \
583 g_assert (BUS_IS_PANEL_PROXY (panel)); \
585 g_return_if_fail (panel->focused_context == context); \
587 bus_panel_proxy_##name (panel); \
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)
602 #undef DEFINE_FUNCTION
604 static const struct {
607 } input_context_signals[] = {
608 { "set-cursor-location", G_CALLBACK (_context_set_cursor_location_cb) },
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) },
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) },
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) },
626 { "register-properties", G_CALLBACK (_context_register_properties_cb) },
627 { "update-property", G_CALLBACK (_context_update_property_cb) },
629 { "engine-changed", G_CALLBACK (_context_state_changed_cb) },
631 { "destroy", G_CALLBACK (_context_destroy_cb) },
635 bus_panel_proxy_focus_in (BusPanelProxy *panel,
636 BusInputContext *context)
638 g_assert (BUS_IS_PANEL_PROXY (panel));
639 g_assert (BUS_IS_INPUT_CONTEXT (context));
641 if (panel->focused_context == context)
644 if (panel->focused_context != NULL)
645 bus_panel_proxy_focus_out (panel, panel->focused_context);
647 g_object_ref_sink (context);
648 panel->focused_context = context;
650 const gchar *path = ibus_service_get_object_path ((IBusService *)context);
652 g_dbus_proxy_call ((GDBusProxy *)panel,
654 g_variant_new ("(o)", path),
655 G_DBUS_CALL_FLAGS_NONE,
656 -1, NULL, NULL, NULL);
658 /* install signal handlers */
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,
669 bus_panel_proxy_focus_out (BusPanelProxy *panel,
670 BusInputContext *context)
672 g_assert (BUS_IS_PANEL_PROXY (panel));
673 g_assert (BUS_IS_INPUT_CONTEXT (context));
675 g_assert (panel->focused_context == context);
677 /* uninstall signal handlers */
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,
685 const gchar *path = ibus_service_get_object_path ((IBusService *)context);
687 g_dbus_proxy_call ((GDBusProxy *)panel,
689 g_variant_new ("(o)", path),
690 G_DBUS_CALL_FLAGS_NONE,
691 -1, NULL, NULL, NULL);
693 g_object_unref (panel->focused_context);
694 panel->focused_context = NULL;