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) 2008-2013 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.1 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 Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 #include "ibusengine.h"
25 #include "ibusmarshalers.h"
26 #include "ibusinternal.h"
27 #include "ibusshare.h"
29 #define IBUS_ENGINE_GET_PRIVATE(o) \
30 (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE, IBusEnginePrivate))
50 PROCESS_HAND_WRITING_EVENT,
63 struct _IBusEnginePrivate {
65 GDBusConnection *connection;
67 /* cached surrounding text (see also IBusInputContextPrivate and
69 IBusText *surrounding_text;
70 guint surrounding_cursor_pos;
71 guint selection_anchor_pos;
73 /* cached content-type */
74 guint content_purpose;
78 static guint engine_signals[LAST_SIGNAL] = { 0 };
80 static IBusText *text_empty = NULL;
82 /* functions prototype */
83 static void ibus_engine_destroy (IBusEngine *engine);
84 static void ibus_engine_set_property (IBusEngine *engine,
88 static void ibus_engine_get_property (IBusEngine *engine,
92 static void ibus_engine_service_method_call
93 (IBusService *service,
94 GDBusConnection *connection,
96 const gchar *object_path,
97 const gchar *interface_name,
98 const gchar *method_name,
100 GDBusMethodInvocation
102 static GVariant *ibus_engine_service_get_property
103 (IBusService *service,
104 GDBusConnection *connection,
106 const gchar *object_path,
107 const gchar *interface_name,
108 const gchar *property_name,
110 static gboolean ibus_engine_service_set_property
111 (IBusService *service,
112 GDBusConnection *connection,
114 const gchar *object_path,
115 const gchar *interface_name,
116 const gchar *property_name,
119 static gboolean ibus_engine_process_key_event
124 static void ibus_engine_focus_in (IBusEngine *engine);
125 static void ibus_engine_focus_out (IBusEngine *engine);
126 static void ibus_engine_reset (IBusEngine *engine);
127 static void ibus_engine_enable (IBusEngine *engine);
128 static void ibus_engine_disable (IBusEngine *engine);
129 static void ibus_engine_set_cursor_location
135 static void ibus_engine_set_capabilities
138 static void ibus_engine_page_up (IBusEngine *engine);
139 static void ibus_engine_page_down (IBusEngine *engine);
140 static void ibus_engine_cursor_up (IBusEngine *engine);
141 static void ibus_engine_cursor_down (IBusEngine *engine);
142 static void ibus_engine_candidate_clicked
147 static void ibus_engine_property_activate
149 const gchar *prop_name,
151 static void ibus_engine_property_show (IBusEngine *engine,
152 const gchar *prop_name);
153 static void ibus_engine_property_hide (IBusEngine *engine,
154 const gchar *prop_name);
155 static void ibus_engine_set_surrounding_text
160 static void ibus_engine_process_hand_writing_event
162 const gdouble *coordinates,
163 guint coordinates_len);
164 static void ibus_engine_cancel_hand_writing
167 static void ibus_engine_set_content_type
171 static void ibus_engine_emit_signal (IBusEngine *engine,
172 const gchar *signal_name,
173 GVariant *parameters);
174 static void ibus_engine_dbus_property_changed
176 const gchar *property_name,
180 G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
182 static const gchar introspection_xml[] =
184 " <interface name='org.freedesktop.IBus.Engine'>"
186 " <method name='ProcessKeyEvent'>"
187 " <arg direction='in' type='u' name='keyval' />"
188 " <arg direction='in' type='u' name='keycode' />"
189 " <arg direction='in' type='u' name='state' />"
190 " <arg direction='out' type='b' />"
192 " <method name='SetCursorLocation'>"
193 " <arg direction='in' type='i' name='x' />"
194 " <arg direction='in' type='i' name='y' />"
195 " <arg direction='in' type='i' name='w' />"
196 " <arg direction='in' type='i' name='h' />"
198 " <method name='ProcessHandWritingEvent'>"
199 " <arg direction='in' type='ad' name='coordinates' />"
201 " <method name='CancelHandWriting'>"
202 " <arg direction='in' type='u' name='n_strokes' />"
204 " <method name='SetCapabilities'>"
205 " <arg direction='in' type='u' name='caps' />"
207 " <method name='PropertyActivate'>"
208 " <arg direction='in' type='s' name='name' />"
209 " <arg direction='in' type='u' name='state' />"
211 " <method name='PropertyShow'>"
212 " <arg direction='in' type='s' name='name' />"
214 " <method name='PropertyHide'>"
215 " <arg direction='in' type='s' name='name' />"
217 " <method name='CandidateClicked'>"
218 " <arg direction='in' type='u' name='index' />"
219 " <arg direction='in' type='u' name='button' />"
220 " <arg direction='in' type='u' name='state' />"
222 " <method name='FocusIn' />"
223 " <method name='FocusOut' />"
224 " <method name='Reset' />"
225 " <method name='Enable' />"
226 " <method name='Disable' />"
227 " <method name='PageUp' />"
228 " <method name='PageDown' />"
229 " <method name='CursorUp' />"
230 " <method name='CursorDown' />"
231 " <method name='SetSurroundingText'>"
232 " <arg direction='in' type='v' name='text' />"
233 " <arg direction='in' type='u' name='cursor_pos' />"
234 " <arg direction='in' type='u' name='anchor_pos' />"
237 " <signal name='CommitText'>"
238 " <arg type='v' name='text' />"
240 " <signal name='UpdatePreeditText'>"
241 " <arg type='v' name='text' />"
242 " <arg type='u' name='cursor_pos' />"
243 " <arg type='b' name='visible' />"
244 " <arg type='u' name='mode' />"
246 " <signal name='UpdateAuxiliaryText'>"
247 " <arg type='v' name='text' />"
248 " <arg type='b' name='visible' />"
250 " <signal name='UpdateLookupTable'>"
251 " <arg type='v' name='table' />"
252 " <arg type='b' name='visible' />"
254 " <signal name='RegisterProperties'>"
255 " <arg type='v' name='props' />"
257 " <signal name='UpdateProperty'>"
258 " <arg type='v' name='prop' />"
260 " <signal name='ForwardKeyEvent'>"
261 " <arg type='u' name='keyval' />"
262 " <arg type='u' name='keycode' />"
263 " <arg type='u' name='state' />"
265 /* FIXME properties */
266 " <property name='ContentType' type='(uu)' access='write' />"
271 ibus_engine_class_init (IBusEngineClass *class)
273 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
274 IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
276 gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
277 gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
279 ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
281 IBUS_SERVICE_CLASS (class)->service_method_call = ibus_engine_service_method_call;
282 IBUS_SERVICE_CLASS (class)->service_get_property = ibus_engine_service_get_property;
283 IBUS_SERVICE_CLASS (class)->service_set_property = ibus_engine_service_set_property;
285 ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
287 class->process_key_event = ibus_engine_process_key_event;
288 class->focus_in = ibus_engine_focus_in;
289 class->focus_out = ibus_engine_focus_out;
290 class->reset = ibus_engine_reset;
291 class->enable = ibus_engine_enable;
292 class->disable = ibus_engine_disable;
293 class->page_up = ibus_engine_page_up;
294 class->page_down = ibus_engine_page_down;
295 class->cursor_up = ibus_engine_cursor_up;
296 class->cursor_down = ibus_engine_cursor_down;
297 class->candidate_clicked = ibus_engine_candidate_clicked;
298 class->property_activate = ibus_engine_property_activate;
299 class->property_show = ibus_engine_property_show;
300 class->property_hide = ibus_engine_property_hide;
301 class->set_cursor_location = ibus_engine_set_cursor_location;
302 class->set_capabilities = ibus_engine_set_capabilities;
303 class->set_surrounding_text = ibus_engine_set_surrounding_text;
304 class->process_hand_writing_event
305 = ibus_engine_process_hand_writing_event;
306 class->cancel_hand_writing = ibus_engine_cancel_hand_writing;
307 class->set_content_type = ibus_engine_set_content_type;
309 /* install properties */
313 * Name of this IBusEngine.
315 g_object_class_install_property (gobject_class,
317 g_param_spec_string ("engine-name",
322 G_PARAM_CONSTRUCT_ONLY |
323 G_PARAM_STATIC_STRINGS));
325 /* install signals */
327 * IBusEngine::process-key-event:
328 * @engine: An IBusEngine.
329 * @keyval: Key symbol of the key press.
330 * @keycode: KeyCode of the key press.
331 * @state: Key modifier flags.
333 * Emitted when a key event is received.
334 * Implement the member function process_key_event() in extended class to receive this signal.
335 * Both the key symbol and keycode are passed to the member function.
336 * See ibus_input_context_process_key_event() for further explanation of
337 * key symbol, keycode and which to use.
339 * Returns: TRUE for successfully process the key; FALSE otherwise.
340 * See also: ibus_input_context_process_key_event().
342 * <note><para>Argument @user_data is ignored in this function.</para></note>
344 engine_signals[PROCESS_KEY_EVENT] =
345 g_signal_new (I_("process-key-event"),
346 G_TYPE_FROM_CLASS (gobject_class),
348 G_STRUCT_OFFSET (IBusEngineClass, process_key_event),
349 g_signal_accumulator_true_handled, NULL,
350 _ibus_marshal_BOOL__UINT_UINT_UINT,
358 * IBusEngine::focus-in:
359 * @engine: An IBusEngine.
361 * Emitted when the client application get the focus.
362 * Implement the member function focus_in() in extended class to receive this signal.
364 * See also: ibus_input_context_focus_in()
365 * <note><para>Argument @user_data is ignored in this function.</para></note>
367 engine_signals[FOCUS_IN] =
368 g_signal_new (I_("focus-in"),
369 G_TYPE_FROM_CLASS (gobject_class),
371 G_STRUCT_OFFSET (IBusEngineClass, focus_in),
373 _ibus_marshal_VOID__VOID,
378 * IBusEngine::focus-out:
379 * @engine: An IBusEngine.
381 * Emitted when the client application lost the focus.
382 * Implement the member function focus_out() in extended class to receive this signal.
384 * See also: ibus_input_context_focus_out()
385 * <note><para>Argument @user_data is ignored in this function.</para></note>
387 engine_signals[FOCUS_OUT] =
388 g_signal_new (I_("focus-out"),
389 G_TYPE_FROM_CLASS (gobject_class),
391 G_STRUCT_OFFSET (IBusEngineClass, focus_out),
393 _ibus_marshal_VOID__VOID,
399 * @engine: An IBusEngine.
401 * Emitted when the IME is reset.
402 * Implement the member function reset() in extended class to receive this signal.
404 * See also: ibus_input_context_reset().
405 * <note><para>Argument @user_data is ignored in this function.</para></note>
407 engine_signals[RESET] =
408 g_signal_new (I_("reset"),
409 G_TYPE_FROM_CLASS (gobject_class),
411 G_STRUCT_OFFSET (IBusEngineClass, reset),
413 _ibus_marshal_VOID__VOID,
418 * IBusEngine::enable:
419 * @engine: An IBusEngine.
421 * Emitted when the IME is enabled.
422 * Implement the member function set_enable() in extended class to receive this signal.
424 * See also: ibus_input_context_enable().
425 * <note><para>Argument @user_data is ignored in this function.</para></note>
427 engine_signals[ENABLE] =
428 g_signal_new (I_("enable"),
429 G_TYPE_FROM_CLASS (gobject_class),
431 G_STRUCT_OFFSET (IBusEngineClass, enable),
433 _ibus_marshal_VOID__VOID,
438 * IBusEngine::disable:
439 * @engine: An IBusEngine.
441 * Emitted when the IME is disabled.
442 * Implement the member function set_disable() in extended class to receive this signal.
444 * See also: ibus_input_context_disable().
445 * <note><para>Argument @user_data is ignored in this function.</para></note>
447 engine_signals[DISABLE] =
448 g_signal_new (I_("disable"),
449 G_TYPE_FROM_CLASS (gobject_class),
451 G_STRUCT_OFFSET (IBusEngineClass, disable),
453 _ibus_marshal_VOID__VOID,
458 * IBusEngine::set-cursor-location:
459 * @engine: An IBusEngine.
460 * @x: X coordinate of the cursor.
461 * @y: Y coordinate of the cursor.
462 * @w: Width of the cursor.
463 * @h: Height of the cursor.
465 * Emitted when the location of IME is set.
466 * Implement the member function set_cursor_location() in extended class to receive this signal.
468 * See also: ibus_input_context_set_cursor_location().
469 * <note><para>Argument @user_data is ignored in this function.</para></note>
471 engine_signals[SET_CURSOR_LOCATION] =
472 g_signal_new (I_("set-cursor-location"),
473 G_TYPE_FROM_CLASS (gobject_class),
475 G_STRUCT_OFFSET (IBusEngineClass, set_cursor_location),
477 _ibus_marshal_VOID__INT_INT_INT_INT,
486 * IBusEngine::set-capabilities:
487 * @engine: An IBusEngine.
488 * @caps: Capabilities flags of IBusEngine, see #IBusCapabilite
490 * Emitted when the client application capabilities is set.
491 * Implement the member function set_capabilities() in extended class to receive this signal.
493 * See also: ibus_input_context_set_capabilities().
494 * <note><para>Argument @user_data is ignored in this function.</para></note>
496 engine_signals[SET_CAPABILITIES] =
497 g_signal_new (I_("set-capabilities"),
498 G_TYPE_FROM_CLASS (gobject_class),
500 G_STRUCT_OFFSET (IBusEngineClass, set_capabilities),
502 _ibus_marshal_VOID__UINT,
508 * IBusEngine::page-up:
509 * @engine: An IBusEngine.
511 * Emitted when the page-up button is pressed.
512 * Implement the member function page_up() in extended class to receive this signal.
514 * <note><para>Argument @user_data is ignored in this function.</para></note>
516 engine_signals[PAGE_UP] =
517 g_signal_new (I_("page-up"),
518 G_TYPE_FROM_CLASS (gobject_class),
520 G_STRUCT_OFFSET (IBusEngineClass, page_up),
522 _ibus_marshal_VOID__VOID,
527 * IBusEngine::page-down:
528 * @engine: An IBusEngine.
530 * Emitted when the page-down button is pressed.
531 * Implement the member function page_down() in extended class to receive this signal.
533 * <note><para>Argument @user_data is ignored in this function.</para></note>
535 engine_signals[PAGE_DOWN] =
536 g_signal_new (I_("page-down"),
537 G_TYPE_FROM_CLASS (gobject_class),
539 G_STRUCT_OFFSET (IBusEngineClass, page_down),
541 _ibus_marshal_VOID__VOID,
546 * IBusEngine::cursor-up:
547 * @engine: An IBusEngine.
549 * Emitted when the up cursor button is pressed.
550 * Implement the member function cursor_up() in extended class to receive this signal.
552 * <note><para>Argument @user_data is ignored in this function.</para></note>
554 engine_signals[CURSOR_UP] =
555 g_signal_new (I_("cursor-up"),
556 G_TYPE_FROM_CLASS (gobject_class),
558 G_STRUCT_OFFSET (IBusEngineClass, cursor_up),
560 _ibus_marshal_VOID__VOID,
565 * IBusEngine::cursor-down:
566 * @engine: An IBusEngine.
568 * Emitted when the down cursor button is pressed.
569 * Implement the member function cursor_down() in extended class to receive this signal.
571 * <note><para>Argument @user_data is ignored in this function.</para></note>
573 engine_signals[CURSOR_DOWN] =
574 g_signal_new (I_("cursor-down"),
575 G_TYPE_FROM_CLASS (gobject_class),
577 G_STRUCT_OFFSET (IBusEngineClass, cursor_down),
579 _ibus_marshal_VOID__VOID,
584 * IBusEngine::candidate-clicked:
585 * @engine: An IBusEngine.
586 * @index: Index of candidate be clicked.
587 * @button: Mouse button.
588 * @state: Keyboard state.
590 * Emitted when candidate on lookup table is clicked.
591 * Implement the member function candidate_clicked() in extended class to receive this signal.
593 * <note><para>Argument @user_data is ignored in this function.</para></note>
595 engine_signals[CANDIDATE_CLICKED] =
596 g_signal_new (I_("candidate-clicked"),
597 G_TYPE_FROM_CLASS (gobject_class),
599 G_STRUCT_OFFSET (IBusEngineClass, candidate_clicked),
601 _ibus_marshal_VOID__UINT_UINT_UINT,
609 * IBusEngine::property-activate:
610 * @engine: An IBusEngine.
611 * @name: Property name.
612 * @state: Property state.
614 * Emitted when a property is activated or change changed.
615 * Implement the member function property_activate() in extended class to receive this signal.
617 * <note><para>Argument @user_data is ignored in this function.</para></note>
619 engine_signals[PROPERTY_ACTIVATE] =
620 g_signal_new (I_("property-activate"),
621 G_TYPE_FROM_CLASS (gobject_class),
623 G_STRUCT_OFFSET (IBusEngineClass, property_activate),
625 _ibus_marshal_VOID__STRING_UINT,
632 * IBusEngine::property-show:
633 * @engine: An IBusEngine.
634 * @name: Property name.
636 * Emitted when a property is shown.
637 * Implement the member function property_side() in extended class to receive this signal.
639 * <note><para>Argument @user_data is ignored in this function.</para></note>
641 engine_signals[PROPERTY_SHOW] =
642 g_signal_new (I_("property-show"),
643 G_TYPE_FROM_CLASS (gobject_class),
645 G_STRUCT_OFFSET (IBusEngineClass, property_show),
647 _ibus_marshal_VOID__STRING,
653 * IBusEngine::property-hide:
654 * @engine: An IBusEngine.
655 * @name: Property name.
657 * Emitted when a property is hidden.
658 * Implement the member function property_hide() in extended class to receive this signal.
660 * <note><para>Argument @user_data is ignored in this function.</para></note>
662 engine_signals[PROPERTY_HIDE] =
663 g_signal_new (I_("property-hide"),
664 G_TYPE_FROM_CLASS (gobject_class),
666 G_STRUCT_OFFSET (IBusEngineClass, property_hide),
668 _ibus_marshal_VOID__STRING,
674 * IBusEngine::process-hand-writing-event:
675 * @engine: An IBusEngine.
676 * @coordinates: An array of double (0.0 to 1.0) which represents a stroke (i.e. [x1, y1, x2, y2, x3, y3, ...]).
677 * @coordinates_len: The number of elements in the array.
679 * Emitted when a hand writing operation is cancelled.
680 * Implement the member function cancel_hand_writing() in extended class to receive this signal.
682 * <note><para>Argument @user_data is ignored in this function.</para></note>
684 engine_signals[PROCESS_HAND_WRITING_EVENT] =
685 g_signal_new (I_("process-hand-writing-event"),
686 G_TYPE_FROM_CLASS (gobject_class),
688 G_STRUCT_OFFSET (IBusEngineClass, process_hand_writing_event),
690 _ibus_marshal_VOID__POINTER_UINT,
697 * IBusEngine::cancel-hand-writing:
698 * @engine: An IBusEngine.
699 * @n_strokes: The number of strokes to be removed. 0 means "remove all".
701 * Emitted when a hand writing operation is cancelled.
702 * Implement the member function cancel_hand_writing() in extended class to receive this signal.
704 * <note><para>Argument @user_data is ignored in this function.</para></note>
706 engine_signals[CANCEL_HAND_WRITING] =
707 g_signal_new (I_("cancel-hand-writing"),
708 G_TYPE_FROM_CLASS (gobject_class),
710 G_STRUCT_OFFSET (IBusEngineClass, cancel_hand_writing),
712 _ibus_marshal_VOID__UINT,
718 * IBusEngine::set-surrounding-text:
719 * @engine: An IBusEngine.
720 * @text: The surrounding text.
721 * @cursor_pos: The cursor position on surrounding text.
722 * @anchor_pos: The anchor position on selection area.
724 * Emitted when a surrounding text is set.
725 * Implement the member function set_surrounding_text() in extended class to receive this signal.
726 * If anchor_pos equals to cursor_pos, it means "there are no selection" or "does not support
727 * selection retrival".
729 * <note><para>Argument @user_data is ignored in this function.</para></note>
731 engine_signals[SET_SURROUNDING_TEXT] =
732 g_signal_new (I_("set-surrounding-text"),
733 G_TYPE_FROM_CLASS (gobject_class),
735 G_STRUCT_OFFSET (IBusEngineClass, set_surrounding_text),
737 _ibus_marshal_VOID__OBJECT_UINT_UINT,
745 * IBusEngine::set-content-type:
746 * @engine: An #IBusEngine.
747 * @purpose: Primary purpose of the input context, as an #IBusInputPurpose.
748 * @hints: Hints that augment @purpose, as an #IBusInputHints.
750 * Emitted when the client application content-type (primary
751 * purpose and hints) is set. The engine could change the
752 * behavior according to the content-type. Implement the member
753 * function set_content_type() in extended class to receive this
756 * For example, if the client application wants to restrict input
757 * to numbers, this signal will be emitted with @purpose set to
758 * #IBUS_INPUT_PURPOSE_NUMBER, so the engine can switch the input
761 * <note><para>Argument @user_data is ignored in this
762 * function.</para></note>
764 engine_signals[SET_CONTENT_TYPE] =
765 g_signal_new (I_("set-content-type"),
766 G_TYPE_FROM_CLASS (gobject_class),
768 G_STRUCT_OFFSET (IBusEngineClass, set_content_type),
770 _ibus_marshal_VOID__UINT_UINT,
776 g_type_class_add_private (class, sizeof (IBusEnginePrivate));
778 text_empty = ibus_text_new_from_static_string ("");
779 g_object_ref_sink (text_empty);
783 ibus_engine_init (IBusEngine *engine)
785 engine->priv = IBUS_ENGINE_GET_PRIVATE (engine);
787 engine->priv->surrounding_text = g_object_ref_sink (text_empty);
791 ibus_engine_destroy (IBusEngine *engine)
793 g_free (engine->priv->engine_name);
794 engine->priv->engine_name = NULL;
796 if (engine->priv->surrounding_text) {
797 g_object_unref (engine->priv->surrounding_text);
798 engine->priv->surrounding_text = NULL;
801 IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
805 ibus_engine_set_property (IBusEngine *engine,
811 case PROP_ENGINE_NAME:
812 engine->priv->engine_name = g_value_dup_string (value);
815 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
820 ibus_engine_get_property (IBusEngine *engine,
826 case PROP_ENGINE_NAME:
827 g_value_set_string (value, engine->priv->engine_name);
831 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
836 ibus_engine_service_method_call (IBusService *service,
837 GDBusConnection *connection,
839 const gchar *object_path,
840 const gchar *interface_name,
841 const gchar *method_name,
842 GVariant *parameters,
843 GDBusMethodInvocation *invocation)
845 IBusEngine *engine = IBUS_ENGINE (service);
847 if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
848 IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
849 service_method_call (service,
860 if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) {
861 guint keyval, keycode, state;
862 gboolean retval = FALSE;
863 g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state);
864 g_signal_emit (engine,
865 engine_signals[PROCESS_KEY_EVENT],
871 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval));
875 static const struct {
878 } no_arg_methods[] = {
879 { "FocusIn", FOCUS_IN },
880 { "FocusOut", FOCUS_OUT },
882 { "Enable", ENABLE },
883 { "Disable", DISABLE },
884 { "PageUp", PAGE_UP },
885 { "PageDown", PAGE_DOWN },
886 { "CursorUp", CURSOR_UP },
887 { "CursorDown", CURSOR_DOWN },
891 for (i = 0; i < G_N_ELEMENTS (no_arg_methods); i++) {
892 if (g_strcmp0 (method_name, no_arg_methods[i].member) == 0) {
893 g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
894 g_dbus_method_invocation_return_value (invocation, NULL);
899 if (g_strcmp0 (method_name, "CandidateClicked") == 0) {
900 guint index, button, state;
901 g_variant_get (parameters, "(uuu)", &index, &button, &state);
902 g_signal_emit (engine,
903 engine_signals[CANDIDATE_CLICKED],
908 g_dbus_method_invocation_return_value (invocation, NULL);
912 if (g_strcmp0 (method_name, "PropertyActivate") == 0) {
915 g_variant_get (parameters, "(&su)", &name, &state);
916 g_signal_emit (engine,
917 engine_signals[PROPERTY_ACTIVATE],
921 g_dbus_method_invocation_return_value (invocation, NULL);
925 if (g_strcmp0 (method_name, "PropertyShow") == 0) {
927 g_variant_get (parameters, "(&s)", &name);
928 g_signal_emit (engine,
929 engine_signals[PROPERTY_SHOW],
932 g_dbus_method_invocation_return_value (invocation, NULL);
936 if (g_strcmp0 (method_name, "PropertyHide") == 0) {
938 g_variant_get (parameters, "(&s)", &name);
939 g_signal_emit (engine,
940 engine_signals[PROPERTY_HIDE],
943 g_dbus_method_invocation_return_value (invocation, NULL);
947 if (g_strcmp0 (method_name, "SetCursorLocation") == 0) {
949 g_variant_get (parameters, "(iiii)", &x, &y, &w, &h);
950 engine->cursor_area.x = x;
951 engine->cursor_area.y = y;
952 engine->cursor_area.width = w;
953 engine->cursor_area.height = h;
955 g_signal_emit (engine,
956 engine_signals[SET_CURSOR_LOCATION],
959 g_dbus_method_invocation_return_value (invocation, NULL);
963 if (g_strcmp0 (method_name, "SetCapabilities") == 0) {
965 g_variant_get (parameters, "(u)", &caps);
966 engine->client_capabilities = caps;
967 g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
968 g_dbus_method_invocation_return_value (invocation, NULL);
972 if (g_strcmp0 (method_name, "SetSurroundingText") == 0) {
973 GVariant *variant = NULL;
978 g_variant_get (parameters,
983 text = IBUS_TEXT (ibus_serializable_deserialize (variant));
984 g_variant_unref (variant);
986 g_signal_emit (engine, engine_signals[SET_SURROUNDING_TEXT],
991 if (g_object_is_floating (text)) {
992 g_object_unref (text);
994 g_dbus_method_invocation_return_value (invocation, NULL);
998 if (g_strcmp0 (method_name, "ProcessHandWritingEvent") == 0) {
999 const gdouble *coordinates;
1000 gsize coordinates_len = 0;
1002 coordinates = g_variant_get_fixed_array (g_variant_get_child_value (parameters, 0), &coordinates_len, sizeof (gdouble));
1003 g_return_if_fail (coordinates != NULL);
1004 g_return_if_fail (coordinates_len >= 4); /* The array should contain at least one line. */
1005 g_return_if_fail (coordinates_len <= G_MAXUINT); /* to prevent overflow in the cast in g_signal_emit */
1006 g_return_if_fail ((coordinates_len & 1) == 0);
1008 g_signal_emit (engine, engine_signals[PROCESS_HAND_WRITING_EVENT], 0,
1009 coordinates, (guint) coordinates_len);
1010 g_dbus_method_invocation_return_value (invocation, NULL);
1014 if (g_strcmp0 (method_name, "CancelHandWriting") == 0) {
1015 guint n_strokes = 0;
1016 g_variant_get (parameters, "(u)", &n_strokes);
1017 g_signal_emit (engine, engine_signals[CANCEL_HAND_WRITING], 0, n_strokes);
1018 g_dbus_method_invocation_return_value (invocation, NULL);
1022 /* should not be reached */
1023 g_return_if_reached ();
1027 ibus_engine_service_get_property (IBusService *service,
1028 GDBusConnection *connection,
1029 const gchar *sender,
1030 const gchar *object_path,
1031 const gchar *interface_name,
1032 const gchar *property_name,
1035 return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
1036 service_get_property (service,
1046 ibus_engine_service_set_property (IBusService *service,
1047 GDBusConnection *connection,
1048 const gchar *sender,
1049 const gchar *object_path,
1050 const gchar *interface_name,
1051 const gchar *property_name,
1055 IBusEngine *engine = IBUS_ENGINE (service);
1057 if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
1058 return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
1059 service_set_property (service,
1069 if (g_strcmp0 (property_name, "ContentType") == 0) {
1073 g_variant_get (value, "(uu)", &purpose, &hints);
1074 if (purpose != engine->priv->content_purpose ||
1075 hints != engine->priv->content_hints) {
1076 engine->priv->content_purpose = purpose;
1077 engine->priv->content_hints = hints;
1079 g_signal_emit (engine,
1080 engine_signals[SET_CONTENT_TYPE],
1085 ibus_engine_dbus_property_changed (engine, "ContentType", value);
1091 g_return_val_if_reached (FALSE);
1095 ibus_engine_process_key_event (IBusEngine *engine,
1104 ibus_engine_focus_in (IBusEngine *engine)
1106 // g_debug ("focus-in");
1110 ibus_engine_focus_out (IBusEngine *engine)
1112 // g_debug ("focus-out");
1116 ibus_engine_reset (IBusEngine *engine)
1118 // g_debug ("reset");
1122 ibus_engine_enable (IBusEngine *engine)
1124 // g_debug ("enable");
1128 ibus_engine_disable (IBusEngine *engine)
1130 // g_debug ("disable");
1134 ibus_engine_set_cursor_location (IBusEngine *engine,
1140 // g_debug ("set-cursor-location (%d, %d, %d, %d)", x, y, w, h);
1144 ibus_engine_set_capabilities (IBusEngine *engine,
1147 // g_debug ("set-capabilities (0x%04x)", caps);
1151 ibus_engine_page_up (IBusEngine *engine)
1153 // g_debug ("page-up");
1157 ibus_engine_page_down (IBusEngine *engine)
1159 // g_debug ("page-down");
1163 ibus_engine_cursor_up (IBusEngine *engine)
1165 // g_debug ("cursor-up");
1169 ibus_engine_cursor_down (IBusEngine *engine)
1171 // g_debug ("cursor-down");
1175 ibus_engine_candidate_clicked (IBusEngine *engine,
1180 // g_debug ("candidate-clicked");
1184 ibus_engine_property_activate (IBusEngine *engine,
1185 const gchar *prop_name,
1188 // g_debug ("property-activate ('%s', %d)", prop_name, prop_state);
1192 ibus_engine_property_show (IBusEngine *engine, const gchar *prop_name)
1194 // g_debug ("property-show ('%s')", prop_name);
1198 ibus_engine_property_hide (IBusEngine *engine, const gchar *prop_name)
1200 // g_debug ("property-hide ('%s')", prop_name);
1204 ibus_engine_set_surrounding_text (IBusEngine *engine,
1209 g_assert (IBUS_IS_ENGINE (engine));
1211 if (engine->priv->surrounding_text) {
1212 g_object_unref (engine->priv->surrounding_text);
1215 engine->priv->surrounding_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
1216 engine->priv->surrounding_cursor_pos = cursor_pos;
1217 engine->priv->selection_anchor_pos = anchor_pos;
1218 // g_debug ("set-surrounding-text ('%s', %d, %d)", text->text, cursor_pos, anchor_pos);
1222 ibus_engine_process_hand_writing_event (IBusEngine *engine,
1223 const gdouble *coordinates,
1224 guint coordinates_len)
1227 // g_debug ("process-hand-writing-event (%u)", coordinates_len);
1228 // for (i = 0; i < coordinates_len; i++)
1229 // g_debug (" %lf", coordinates[i]);
1233 ibus_engine_cancel_hand_writing (IBusEngine *engine,
1236 // g_debug ("cancel-hand-writing (%u)", n_strokes);
1240 ibus_engine_set_content_type (IBusEngine *engine,
1244 // g_debug ("set-content-type (%u %u)", purpose, hints);
1248 ibus_engine_emit_signal (IBusEngine *engine,
1249 const gchar *signal_name,
1250 GVariant *parameters)
1252 ibus_service_emit_signal ((IBusService *)engine,
1254 IBUS_INTERFACE_ENGINE,
1261 ibus_engine_dbus_property_changed (IBusEngine *engine,
1262 const gchar *property_name,
1265 const gchar *object_path;
1266 GDBusConnection *connection;
1267 GDBusMessage *message;
1268 GVariantBuilder *builder;
1272 /* we cannot use ibus_service_emit_signal() here, since we need to
1273 set sender of the signal so that GDBusProxy can properly track
1274 the property change. */
1275 object_path = ibus_service_get_object_path ((IBusService *)engine);
1276 message = g_dbus_message_new_signal (object_path,
1277 "org.freedesktop.DBus.Properties",
1278 "PropertiesChanged");
1280 g_dbus_message_set_sender (message, "org.freedesktop.IBus");
1282 builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
1283 g_variant_builder_add (builder, "{sv}", property_name, value);
1284 g_dbus_message_set_body (message,
1285 g_variant_new ("(sa{sv}as)",
1286 IBUS_INTERFACE_ENGINE,
1291 connection = ibus_service_get_connection ((IBusService *)engine);
1292 retval = g_dbus_connection_send_message (connection,
1294 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1298 g_warning ("Failed to emit PropertiesChanged signal: %s",
1300 g_error_free (error);
1302 g_object_unref (message);
1306 ibus_engine_new (const gchar *engine_name,
1307 const gchar *object_path,
1308 GDBusConnection *connection)
1310 return ibus_engine_new_with_type (IBUS_TYPE_ENGINE,
1317 ibus_engine_new_with_type (GType engine_type,
1318 const gchar *engine_name,
1319 const gchar *object_path,
1320 GDBusConnection *connection)
1322 g_return_val_if_fail (g_type_is_a (engine_type, IBUS_TYPE_ENGINE), NULL);
1323 g_return_val_if_fail (engine_name != NULL, NULL);
1324 g_return_val_if_fail (object_path != NULL, NULL);
1325 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1327 GObject *object = g_object_new (engine_type,
1328 "engine-name", engine_name,
1329 "object-path", object_path,
1330 "connection", connection,
1332 return IBUS_ENGINE (object);
1337 ibus_engine_commit_text (IBusEngine *engine,
1340 g_return_if_fail (IBUS_IS_ENGINE (engine));
1341 g_return_if_fail (IBUS_IS_TEXT (text));
1343 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1344 ibus_engine_emit_signal (engine,
1346 g_variant_new ("(v)", variant));
1348 if (g_object_is_floating (text)) {
1349 g_object_unref (text);
1354 ibus_engine_update_preedit_text (IBusEngine *engine,
1359 ibus_engine_update_preedit_text_with_mode (engine,
1360 text, cursor_pos, visible, IBUS_ENGINE_PREEDIT_CLEAR);
1364 ibus_engine_update_preedit_text_with_mode (IBusEngine *engine,
1368 IBusPreeditFocusMode mode)
1370 g_return_if_fail (IBUS_IS_ENGINE (engine));
1371 g_return_if_fail (IBUS_IS_TEXT (text));
1373 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1374 ibus_engine_emit_signal (engine,
1375 "UpdatePreeditText",
1376 g_variant_new ("(vubu)", variant, cursor_pos, visible, mode));
1378 if (g_object_is_floating (text)) {
1379 g_object_unref (text);
1383 void ibus_engine_update_auxiliary_text (IBusEngine *engine,
1387 g_return_if_fail (IBUS_IS_ENGINE (engine));
1388 g_return_if_fail (IBUS_IS_TEXT (text));
1390 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1391 ibus_engine_emit_signal (engine,
1392 "UpdateAuxiliaryText",
1393 g_variant_new ("(vb)", variant, visible));
1395 if (g_object_is_floating (text)) {
1396 g_object_unref (text);
1402 ibus_engine_update_lookup_table (IBusEngine *engine,
1403 IBusLookupTable *table,
1406 g_return_if_fail (IBUS_IS_ENGINE (engine));
1407 g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
1409 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)table);
1410 ibus_engine_emit_signal (engine,
1411 "UpdateLookupTable",
1412 g_variant_new ("(vb)", variant, visible));
1414 if (g_object_is_floating (table)) {
1415 g_object_unref (table);
1420 ibus_engine_update_lookup_table_fast (IBusEngine *engine,
1421 IBusLookupTable *table,
1424 g_return_if_fail (IBUS_IS_ENGINE (engine));
1425 g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
1427 IBusLookupTable *new_table;
1432 if (table->candidates->len < table->page_size << 2) {
1433 ibus_engine_update_lookup_table (engine, table, visible);
1437 page_begin = (table->cursor_pos / table->page_size) * table->page_size;
1439 new_table = ibus_lookup_table_new (table->page_size, 0, table->cursor_visible, table->round);
1441 for (i = page_begin; i < page_begin + table->page_size && i < table->candidates->len; i++) {
1442 ibus_lookup_table_append_candidate (new_table, ibus_lookup_table_get_candidate (table, i));
1445 for (i = 0; (text = ibus_lookup_table_get_label (table, i)) != NULL; i++) {
1446 ibus_lookup_table_append_label (new_table, text);
1449 ibus_lookup_table_set_cursor_pos (new_table, ibus_lookup_table_get_cursor_in_page (table));
1450 ibus_lookup_table_set_orientation (new_table, ibus_lookup_table_get_orientation (table));
1452 ibus_engine_update_lookup_table (engine, new_table, visible);
1454 if (g_object_is_floating (table)) {
1455 g_object_unref (table);
1460 ibus_engine_forward_key_event (IBusEngine *engine,
1465 g_return_if_fail (IBUS_IS_ENGINE (engine));
1467 ibus_engine_emit_signal (engine,
1469 g_variant_new ("(uuu)", keyval, keycode, state));
1472 void ibus_engine_delete_surrounding_text (IBusEngine *engine,
1473 gint offset_from_cursor,
1476 IBusEnginePrivate *priv;
1478 g_return_if_fail (IBUS_IS_ENGINE (engine));
1480 priv = IBUS_ENGINE_GET_PRIVATE (engine);
1482 /* Update surrounding-text cache. This is necessary since some
1483 engines call ibus_engine_get_surrounding_text() immediately
1484 after ibus_engine_delete_surrounding_text(). */
1485 if (priv->surrounding_text) {
1487 glong cursor_pos, len;
1489 cursor_pos = priv->surrounding_cursor_pos + offset_from_cursor;
1490 len = ibus_text_get_length (priv->surrounding_text);
1491 if (cursor_pos >= 0 && len - cursor_pos >= nchars) {
1494 ucs = g_utf8_to_ucs4_fast (priv->surrounding_text->text,
1497 memmove (&ucs[cursor_pos],
1498 &ucs[cursor_pos + nchars],
1499 sizeof(gunichar) * (len - cursor_pos - nchars));
1500 ucs[len - nchars] = 0;
1501 text = ibus_text_new_from_ucs4 (ucs);
1503 priv->surrounding_cursor_pos = cursor_pos;
1506 priv->surrounding_cursor_pos = 0;
1509 g_object_unref (priv->surrounding_text);
1510 priv->surrounding_text = g_object_ref_sink (text);
1513 ibus_engine_emit_signal (engine,
1514 "DeleteSurroundingText",
1515 g_variant_new ("(iu)", offset_from_cursor, nchars));
1519 ibus_engine_get_surrounding_text (IBusEngine *engine,
1524 IBusEnginePrivate *priv;
1526 g_return_if_fail (IBUS_IS_ENGINE (engine));
1527 const gboolean signal_only = (text == NULL);
1529 g_return_if_fail (( signal_only && (cursor_pos == NULL)) ||
1530 (!signal_only && (cursor_pos != NULL)));
1532 g_return_if_fail (( signal_only && (anchor_pos == NULL)) ||
1533 (!signal_only && (anchor_pos != NULL)));
1535 priv = IBUS_ENGINE_GET_PRIVATE (engine);
1538 *text = g_object_ref (priv->surrounding_text);
1539 *cursor_pos = priv->surrounding_cursor_pos;
1540 *anchor_pos = priv->selection_anchor_pos;
1543 /* tell the client that this engine will utilize surrounding-text
1544 * feature, which causes periodical update. Note that the client
1545 * should request the initial surrounding-text when the engine is
1546 * enabled (see ibus_im_context_focus_in() and
1547 * _ibus_context_enabled_cb() in client/gtk2/ibusimcontext.c). */
1548 ibus_engine_emit_signal (engine,
1549 "RequireSurroundingText",
1552 // g_debug ("get-surrounding-text ('%s', %d, %d)", (*text)->text, *cursor_pos, *anchor_pos);
1556 ibus_engine_get_content_type (IBusEngine *engine,
1560 g_return_if_fail (IBUS_IS_ENGINE (engine));
1562 *purpose = engine->priv->content_purpose;
1563 *hints = engine->priv->content_hints;
1567 ibus_engine_register_properties (IBusEngine *engine,
1568 IBusPropList *prop_list)
1570 g_return_if_fail (IBUS_IS_ENGINE (engine));
1571 g_return_if_fail (IBUS_IS_PROP_LIST (prop_list));
1573 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop_list);
1574 ibus_engine_emit_signal (engine,
1575 "RegisterProperties",
1576 g_variant_new ("(v)", variant));
1578 if (g_object_is_floating (prop_list)) {
1579 g_object_unref (prop_list);
1584 ibus_engine_update_property (IBusEngine *engine,
1587 g_return_if_fail (IBUS_IS_ENGINE (engine));
1588 g_return_if_fail (IBUS_IS_PROPERTY (prop));
1590 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
1591 ibus_engine_emit_signal (engine,
1593 g_variant_new ("(v)", variant));
1595 if (g_object_is_floating (prop)) {
1596 g_object_unref (prop);
1600 #define DEFINE_FUNC(name, Name) \
1602 ibus_engine_##name (IBusEngine *engine) \
1604 g_return_if_fail (IBUS_IS_ENGINE (engine)); \
1605 ibus_engine_emit_signal (engine, \
1609 DEFINE_FUNC (show_preedit_text, ShowPreeditText)
1610 DEFINE_FUNC (hide_preedit_text, HidePreeditText)
1611 DEFINE_FUNC (show_auxiliary_text, ShowAuxiliaryText)
1612 DEFINE_FUNC (hide_auxiliary_text, HideAuxiliaryText)
1613 DEFINE_FUNC (show_lookup_table, ShowLookupTable)
1614 DEFINE_FUNC (hide_lookup_table, HideLookupTable)
1618 ibus_engine_get_name (IBusEngine *engine)
1620 g_return_val_if_fail (IBUS_IS_ENGINE (engine), NULL);
1621 return engine->priv->engine_name;