1 /* vim:set et sts=4: */
2 /* ibus - The Input Bus
3 * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "ibusengine.h"
23 #include "ibusinternal.h"
24 #include "ibusshare.h"
26 #define IBUS_ENGINE_GET_PRIVATE(o) \
27 (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE, IBusEnginePrivate))
56 struct _IBusEnginePrivate {
58 IBusConnection *connection;
60 typedef struct _IBusEnginePrivate IBusEnginePrivate;
62 static guint engine_signals[LAST_SIGNAL] = { 0 };
64 /* functions prototype */
65 static void ibus_engine_class_init (IBusEngineClass *klass);
66 static void ibus_engine_init (IBusEngine *engine);
67 static void ibus_engine_destroy (IBusEngine *engine);
68 static void ibus_engine_set_property (IBusEngine *engine,
72 static void ibus_engine_get_property (IBusEngine *engine,
76 static gboolean ibus_engine_ibus_message (IBusEngine *engine,
77 IBusConnection *connection,
78 IBusMessage *message);
79 static gboolean ibus_engine_process_key_event
83 static void ibus_engine_focus_in (IBusEngine *engine);
84 static void ibus_engine_focus_out (IBusEngine *engine);
85 static void ibus_engine_reset (IBusEngine *engine);
86 static void ibus_engine_enable (IBusEngine *engine);
87 static void ibus_engine_disable (IBusEngine *engine);
88 static void ibus_engine_set_cursor_location
94 static void ibus_engine_set_capabilities
97 static void ibus_engine_page_up (IBusEngine *engine);
98 static void ibus_engine_page_down (IBusEngine *engine);
99 static void ibus_engine_cursor_up (IBusEngine *engine);
100 static void ibus_engine_cursor_down (IBusEngine *engine);
101 static void ibus_engine_property_activate
103 const gchar *prop_name,
105 static void ibus_engine_property_show (IBusEngine *engine,
106 const gchar *prop_name);
107 static void ibus_engine_property_hide (IBusEngine *engine,
108 const gchar *prop_name);
111 static IBusServiceClass *parent_class = NULL;
114 ibus_engine_get_type (void)
116 static GType type = 0;
118 static const GTypeInfo type_info = {
119 sizeof (IBusEngineClass),
120 (GBaseInitFunc) NULL,
121 (GBaseFinalizeFunc) NULL,
122 (GClassInitFunc) ibus_engine_class_init,
123 NULL, /* class finalize */
124 NULL, /* class data */
127 (GInstanceInitFunc) ibus_engine_init,
131 type = g_type_register_static (IBUS_TYPE_SERVICE,
140 ibus_engine_new (const gchar *name,
142 IBusConnection *connection)
145 g_assert (IBUS_IS_CONNECTION (connection));
149 engine = (IBusEngine *) g_object_new (IBUS_TYPE_ENGINE,
152 "connection", connection,
159 ibus_engine_class_init (IBusEngineClass *klass)
161 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
162 IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
164 parent_class = (IBusServiceClass *) g_type_class_peek_parent (klass);
166 g_type_class_add_private (klass, sizeof (IBusEnginePrivate));
168 gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
169 gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
171 ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
173 IBUS_SERVICE_CLASS (klass)->ibus_message = (ServiceIBusMessageFunc) ibus_engine_ibus_message;
175 klass->process_key_event = ibus_engine_process_key_event;
176 klass->focus_in = ibus_engine_focus_in;
177 klass->focus_out = ibus_engine_focus_out;
178 klass->reset = ibus_engine_reset;
179 klass->enable = ibus_engine_enable;
180 klass->disable = ibus_engine_disable;
181 klass->page_up = ibus_engine_page_up;
182 klass->page_down = ibus_engine_page_down;
183 klass->cursor_up = ibus_engine_cursor_up;
184 klass->cursor_down = ibus_engine_cursor_down;
185 klass->property_activate = ibus_engine_property_activate;
186 klass->property_show = ibus_engine_property_show;
187 klass->property_hide = ibus_engine_property_hide;
188 klass->set_cursor_location = ibus_engine_set_cursor_location;
189 klass->set_capabilities = ibus_engine_set_capabilities;
192 /* install properties */
193 g_object_class_install_property (gobject_class,
195 g_param_spec_string ("name",
199 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
202 g_object_class_install_property (gobject_class,
204 g_param_spec_object ("connection",
206 "The connection of engine object",
207 IBUS_TYPE_CONNECTION,
208 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
210 /* install signals */
211 engine_signals[PROCESS_KEY_EVENT] =
212 g_signal_new (I_("process-key-event"),
213 G_TYPE_FROM_CLASS (gobject_class),
215 G_STRUCT_OFFSET (IBusEngineClass, process_key_event),
217 ibus_marshal_BOOL__UINT_UINT,
223 engine_signals[FOCUS_IN] =
224 g_signal_new (I_("focus-in"),
225 G_TYPE_FROM_CLASS (gobject_class),
227 G_STRUCT_OFFSET (IBusEngineClass, focus_in),
229 ibus_marshal_VOID__VOID,
233 engine_signals[FOCUS_OUT] =
234 g_signal_new (I_("focus-out"),
235 G_TYPE_FROM_CLASS (gobject_class),
237 G_STRUCT_OFFSET (IBusEngineClass, focus_out),
239 ibus_marshal_VOID__VOID,
243 engine_signals[RESET] =
244 g_signal_new (I_("reset"),
245 G_TYPE_FROM_CLASS (gobject_class),
247 G_STRUCT_OFFSET (IBusEngineClass, reset),
249 ibus_marshal_VOID__VOID,
253 engine_signals[ENABLE] =
254 g_signal_new (I_("enable"),
255 G_TYPE_FROM_CLASS (gobject_class),
257 G_STRUCT_OFFSET (IBusEngineClass, enable),
259 ibus_marshal_VOID__VOID,
263 engine_signals[DISABLE] =
264 g_signal_new (I_("disable"),
265 G_TYPE_FROM_CLASS (gobject_class),
267 G_STRUCT_OFFSET (IBusEngineClass, disable),
269 ibus_marshal_VOID__VOID,
273 engine_signals[SET_CURSOR_LOCATION] =
274 g_signal_new (I_("set-cursor-location"),
275 G_TYPE_FROM_CLASS (gobject_class),
277 G_STRUCT_OFFSET (IBusEngineClass, set_cursor_location),
279 ibus_marshal_VOID__INT_INT_INT_INT,
287 engine_signals[SET_CAPABILITIES] =
288 g_signal_new (I_("set-capabilities"),
289 G_TYPE_FROM_CLASS (gobject_class),
291 G_STRUCT_OFFSET (IBusEngineClass, set_capabilities),
293 ibus_marshal_VOID__UINT,
298 engine_signals[PAGE_UP] =
299 g_signal_new (I_("page-up"),
300 G_TYPE_FROM_CLASS (gobject_class),
302 G_STRUCT_OFFSET (IBusEngineClass, page_up),
304 ibus_marshal_VOID__VOID,
308 engine_signals[PAGE_DOWN] =
309 g_signal_new (I_("page-down"),
310 G_TYPE_FROM_CLASS (gobject_class),
312 G_STRUCT_OFFSET (IBusEngineClass, page_down),
314 ibus_marshal_VOID__VOID,
318 engine_signals[CURSOR_UP] =
319 g_signal_new (I_("cursor-up"),
320 G_TYPE_FROM_CLASS (gobject_class),
322 G_STRUCT_OFFSET (IBusEngineClass, cursor_up),
324 ibus_marshal_VOID__VOID,
328 engine_signals[CURSOR_DOWN] =
329 g_signal_new (I_("cursor-down"),
330 G_TYPE_FROM_CLASS (gobject_class),
332 G_STRUCT_OFFSET (IBusEngineClass, cursor_down),
334 ibus_marshal_VOID__VOID,
338 engine_signals[PROPERTY_ACTIVATE] =
339 g_signal_new (I_("property-activate"),
340 G_TYPE_FROM_CLASS (gobject_class),
342 G_STRUCT_OFFSET (IBusEngineClass, property_activate),
344 ibus_marshal_VOID__STRING_INT,
350 engine_signals[PROPERTY_SHOW] =
351 g_signal_new (I_("property-show"),
352 G_TYPE_FROM_CLASS (gobject_class),
354 G_STRUCT_OFFSET (IBusEngineClass, property_show),
356 ibus_marshal_VOID__STRING,
361 engine_signals[PROPERTY_HIDE] =
362 g_signal_new (I_("property-hide"),
363 G_TYPE_FROM_CLASS (gobject_class),
365 G_STRUCT_OFFSET (IBusEngineClass, property_hide),
367 ibus_marshal_VOID__STRING,
375 ibus_engine_init (IBusEngine *engine)
377 IBusEnginePrivate *priv;
378 priv = IBUS_ENGINE_GET_PRIVATE (engine);
381 priv->connection = NULL;
385 ibus_engine_destroy (IBusEngine *engine)
387 IBusEnginePrivate *priv;
388 priv = IBUS_ENGINE_GET_PRIVATE (engine);
392 if (priv->connection) {
393 g_object_unref (priv->connection);
394 priv->connection = NULL;
397 IBUS_OBJECT_CLASS(parent_class)->destroy (IBUS_OBJECT (engine));
401 ibus_engine_set_property (IBusEngine *engine,
406 IBusEnginePrivate *priv;
407 priv = IBUS_ENGINE_GET_PRIVATE (engine);
411 priv->name = g_strdup (g_value_dup_string (value));
414 case PROP_CONNECTION:
415 priv->connection = g_value_get_object (value);
416 g_object_ref (priv->connection);
417 ibus_service_add_to_connection ((IBusService *) engine,
422 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
427 ibus_engine_get_property (IBusEngine *engine,
428 guint prop_id, GValue *value, GParamSpec *pspec)
430 IBusEnginePrivate *priv;
431 priv = IBUS_ENGINE_GET_PRIVATE (engine);
435 g_value_set_string (value, priv->name);
438 case PROP_CONNECTION:
439 g_value_set_object (value, priv->connection);
443 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
448 ibus_engine_ibus_message (IBusEngine *engine,
449 IBusConnection *connection,
450 IBusMessage *message)
452 g_assert (IBUS_IS_ENGINE (engine));
453 g_assert (IBUS_IS_CONNECTION (connection));
454 g_assert (message != NULL);
456 IBusEnginePrivate *priv;
457 priv = IBUS_ENGINE_GET_PRIVATE (engine);
459 g_assert (priv->connection == connection);
461 IBusMessage *return_message = NULL;
462 IBusMessage *error_message = NULL;
464 static const struct {
467 } no_arg_methods[] = {
468 {"FocusIn", FOCUS_IN},
469 {"FocusOut", FOCUS_OUT},
472 {"Disable", DISABLE},
474 {"PageDown", PAGE_DOWN},
475 {"CursorUp", CURSOR_UP},
476 {"CursorDown", CURSOR_DOWN},
481 for (i = 0; no_arg_methods[i].member != NULL; i++) {
482 if (!ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, no_arg_methods[i].member))
485 IBusMessageIter iter;
486 ibus_message_iter_init (message, &iter);
487 if (ibus_message_iter_has_next (&iter)) {
488 error_message = ibus_message_new_error_printf (message,
489 "%s.%s: Method does not have arguments",
490 IBUS_INTERFACE_ENGINE, no_arg_methods[i].member);
491 ibus_connection_send (connection, error_message);
492 ibus_message_unref (error_message);
496 g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
497 return_message = ibus_message_new_method_return (message);
498 ibus_connection_send (connection, return_message);
499 ibus_message_unref (return_message);
504 if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "ProcessKeyEvent")) {
507 IBusError *error = NULL;
509 retval = ibus_message_get_args (message,
511 G_TYPE_UINT, &keyval,
519 g_signal_emit (engine,
520 engine_signals[PROCESS_KEY_EVENT],
526 return_message = ibus_message_new_method_return (message);
527 ibus_message_append_args (return_message,
528 G_TYPE_BOOLEAN, &retval,
530 ibus_connection_send (connection, return_message);
531 ibus_message_unref (return_message);
535 error_message = ibus_message_new_error_printf (message,
536 "%s.%s: Can not match signature (ubu) of method",
537 IBUS_INTERFACE_ENGINE, "ProcessKeyEvent");
538 ibus_connection_send (connection, error_message);
539 ibus_message_unref (error_message);
542 else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "PropertyActivate")) {
546 IBusError *error = NULL;
548 retval = ibus_message_get_args (message,
550 G_TYPE_STRING, &name,
555 goto _property_activate_fail;
557 g_signal_emit (engine,
558 engine_signals[PROPERTY_ACTIVATE],
563 return_message = ibus_message_new_method_return (message);
564 ibus_connection_send (connection, return_message);
565 ibus_message_unref (return_message);
568 _property_activate_fail:
569 error_message = ibus_message_new_error_printf (message,
570 "%s.%s: Can not match signature (si) of method",
571 IBUS_INTERFACE_ENGINE,
573 ibus_connection_send (connection, error_message);
574 ibus_message_unref (error_message);
578 else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "PropertyShow")) {
583 retval = ibus_message_get_args (message,
585 G_TYPE_STRING, &name,
589 goto _property_show_fail;
591 g_signal_emit (engine,
592 engine_signals[PROPERTY_SHOW],
596 return_message = ibus_message_new_method_return (message);
597 ibus_connection_send (connection, return_message);
598 ibus_message_unref (return_message);
602 error_message = ibus_message_new_error_printf (message,
603 "%s.%s: Can not match signature (s) of method",
604 IBUS_INTERFACE_ENGINE,
606 ibus_connection_send (connection, error_message);
607 ibus_message_unref (error_message);
610 else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "PropertyHide")) {
613 IBusError *error = NULL;
615 retval = ibus_message_get_args (message,
617 G_TYPE_STRING, &name,
620 goto _property_hide_fail;
622 g_signal_emit (engine, engine_signals[PROPERTY_HIDE], 0, name);
624 return_message = ibus_message_new_method_return (message);
625 ibus_connection_send (connection, return_message);
626 ibus_message_unref (return_message);
630 error_message = ibus_message_new_error_printf (message,
631 "%s.%s: Can not match signature (s) of method",
632 IBUS_INTERFACE_ENGINE, "PropertyHide");
633 ibus_connection_send (connection, error_message);
634 ibus_message_unref (error_message);
637 else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "SetCursorLocation")) {
640 IBusError *error = NULL;
642 retval = ibus_message_get_args (message,
650 goto _set_cursor_location_fail;
652 engine->cursor_area.x = x;
653 engine->cursor_area.y = y;
654 engine->cursor_area.width = w;
655 engine->cursor_area.height = h;
657 g_signal_emit (engine,
658 engine_signals[SET_CURSOR_LOCATION],
662 return_message = ibus_message_new_method_return (message);
663 ibus_connection_send (connection, return_message);
664 ibus_message_unref (return_message);
667 _set_cursor_location_fail:
668 error_message = ibus_message_new_error_printf (message,
669 "%s.%s: Can not match signature (iiii) of method",
670 IBUS_INTERFACE_ENGINE,
671 "SetCursorLocation");
672 ibus_connection_send (connection, error_message);
673 ibus_message_unref (error_message);
676 else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "SetCapabilities")) {
679 IBusError *error = NULL;
681 retval = ibus_message_get_args (message,
687 goto _set_capabilities_fail;
689 engine->client_capabilities = caps;
691 g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
693 return_message = ibus_message_new_method_return (message);
694 ibus_connection_send (connection, return_message);
695 ibus_message_unref (return_message);
698 _set_capabilities_fail:
699 error_message = ibus_message_new_error_printf (message,
700 "%s.%s: Can not match signature (u) of method",
701 IBUS_INTERFACE_ENGINE, "SetCapabilities");
702 ibus_connection_send (connection, error_message);
703 ibus_message_unref (error_message);
706 else if (ibus_message_is_method_call (message, IBUS_INTERFACE_ENGINE, "Destroy")) {
707 return_message = ibus_message_new_method_return (message);
709 ibus_connection_send (connection, return_message);
710 ibus_message_unref (return_message);
712 ibus_object_destroy ((IBusObject *) engine);
715 return parent_class->ibus_message ((IBusService *) engine, connection, message);
719 ibus_engine_process_key_event (IBusEngine *engine,
723 // g_debug ("process-key-event (%d, %d)", keyval, state);
728 ibus_engine_focus_in (IBusEngine *engine)
730 // g_debug ("focus-in");
734 ibus_engine_focus_out (IBusEngine *engine)
736 // g_debug ("focus-out");
740 ibus_engine_reset (IBusEngine *engine)
742 // g_debug ("reset");
746 ibus_engine_enable (IBusEngine *engine)
748 // g_debug ("enable");
752 ibus_engine_disable (IBusEngine *engine)
754 // g_debug ("disable");
758 ibus_engine_set_cursor_location (IBusEngine *engine,
764 // g_debug ("set-cursor-location (%d, %d, %d, %d)", x, y, w, h);
768 ibus_engine_set_capabilities (IBusEngine *engine,
771 // g_debug ("set-capabilities (0x%04x)", caps);
775 ibus_engine_page_up (IBusEngine *engine)
777 // g_debug ("page-up");
781 ibus_engine_page_down (IBusEngine *engine)
783 // g_debug ("page-down");
787 ibus_engine_cursor_up (IBusEngine *engine)
789 // g_debug ("cursor-up");
793 ibus_engine_cursor_down (IBusEngine *engine)
795 // g_debug ("cursor-down");
799 ibus_engine_property_activate (IBusEngine *engine,
800 const gchar *prop_name, gint prop_state)
802 // g_debug ("property-activate ('%s', %d)", prop_name, prop_state);
806 ibus_engine_property_show (IBusEngine *engine, const gchar *prop_name)
808 // g_debug ("property-show ('%s')", prop_name);
812 ibus_engine_property_hide (IBusEngine *engine, const gchar *prop_name)
814 // g_debug ("property-hide ('%s')", prop_name);
818 _send_signal (IBusEngine *engine,
820 GType first_arg_type,
823 g_assert (IBUS_IS_ENGINE (engine));
824 g_assert (name != NULL);
828 IBusEnginePrivate *priv;
830 priv = IBUS_ENGINE_GET_PRIVATE (engine);
832 path = ibus_service_get_path ((IBusService *)engine);
834 va_start (args, first_arg_type);
835 ibus_connection_send_signal_valist (priv->connection,
837 IBUS_INTERFACE_ENGINE,
845 ibus_engine_commit_text (IBusEngine *engine,
848 _send_signal (engine,
850 IBUS_TYPE_TEXT, &text,
855 ibus_engine_update_preedit_text (IBusEngine *engine,
860 _send_signal (engine,
862 IBUS_TYPE_TEXT, &text,
863 G_TYPE_UINT, &cursor_pos,
864 G_TYPE_BOOLEAN, &visible,
869 ibus_engine_show_preedit_text (IBusEngine *engine)
871 _send_signal (engine,
876 void ibus_engine_hide_preedit_text (IBusEngine *engine)
878 _send_signal (engine,
883 void ibus_engine_update_auxiliary_text (IBusEngine *engine,
887 _send_signal (engine,
888 "UpdateAuxiliaryText",
889 IBUS_TYPE_TEXT, &text,
890 G_TYPE_BOOLEAN, &visible,
895 ibus_engine_show_auxiliary_text (IBusEngine *engine)
897 _send_signal (engine,
903 ibus_engine_hide_auxiliary_text (IBusEngine *engine)
905 _send_signal (engine,
910 void ibus_engine_update_lookup_table (IBusEngine *engine,
911 IBusLookupTable *table,
914 _send_signal (engine,
916 IBUS_TYPE_LOOKUP_TABLE, &table,
917 G_TYPE_BOOLEAN, &visible,
921 void ibus_engine_show_lookup_table (IBusEngine *engine)
923 _send_signal (engine,
928 void ibus_engine_hide_lookup_table (IBusEngine *engine)
930 _send_signal (engine,
935 void ibus_engine_forward_key_event (IBusEngine *engine,
940 _send_signal (engine,
942 G_TYPE_UINT, &keyval,
943 G_TYPE_BOOLEAN, &is_press,
949 ibus_engine_register_properties (IBusEngine *engine,
950 IBusPropList *prop_list)
952 _send_signal (engine,
953 "RegisterProperties",
954 IBUS_TYPE_PROP_LIST, &prop_list,
959 ibus_engine_update_property (IBusEngine *engine,
962 _send_signal (engine,
964 IBUS_TYPE_PROPERTY, &prop,
969 ibus_engine_get_name (IBusEngine *engine)
971 g_assert (IBUS_IS_ENGINE (engine));
973 IBusEnginePrivate *priv;
974 priv = IBUS_ENGINE_GET_PRIVATE (engine);