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 "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,
62 struct _IBusEnginePrivate {
64 GDBusConnection *connection;
66 /* cached surrounding text (see also IBusInputContextPrivate and
68 IBusText *surrounding_text;
69 guint surrounding_cursor_pos;
70 guint selection_anchor_pos;
73 static guint engine_signals[LAST_SIGNAL] = { 0 };
75 static IBusText *text_empty = NULL;
77 /* functions prototype */
78 static void ibus_engine_destroy (IBusEngine *engine);
79 static void ibus_engine_set_property (IBusEngine *engine,
83 static void ibus_engine_get_property (IBusEngine *engine,
87 static void ibus_engine_service_method_call
88 (IBusService *service,
89 GDBusConnection *connection,
91 const gchar *object_path,
92 const gchar *interface_name,
93 const gchar *method_name,
97 static GVariant *ibus_engine_service_get_property
98 (IBusService *service,
99 GDBusConnection *connection,
101 const gchar *object_path,
102 const gchar *interface_name,
103 const gchar *property_name,
105 static gboolean ibus_engine_service_set_property
106 (IBusService *service,
107 GDBusConnection *connection,
109 const gchar *object_path,
110 const gchar *interface_name,
111 const gchar *property_name,
114 static gboolean ibus_engine_process_key_event
119 static void ibus_engine_focus_in (IBusEngine *engine);
120 static void ibus_engine_focus_out (IBusEngine *engine);
121 static void ibus_engine_reset (IBusEngine *engine);
122 static void ibus_engine_enable (IBusEngine *engine);
123 static void ibus_engine_disable (IBusEngine *engine);
124 static void ibus_engine_set_cursor_location
130 static void ibus_engine_set_capabilities
133 static void ibus_engine_page_up (IBusEngine *engine);
134 static void ibus_engine_page_down (IBusEngine *engine);
135 static void ibus_engine_cursor_up (IBusEngine *engine);
136 static void ibus_engine_cursor_down (IBusEngine *engine);
137 static void ibus_engine_candidate_clicked
142 static void ibus_engine_property_activate
144 const gchar *prop_name,
146 static void ibus_engine_property_show (IBusEngine *engine,
147 const gchar *prop_name);
148 static void ibus_engine_property_hide (IBusEngine *engine,
149 const gchar *prop_name);
150 static void ibus_engine_set_surrounding_text
155 static void ibus_engine_process_hand_writing_event
157 const gdouble *coordinates,
158 guint coordinates_len);
159 static void ibus_engine_cancel_hand_writing
162 static void ibus_engine_emit_signal (IBusEngine *engine,
163 const gchar *signal_name,
164 GVariant *parameters);
167 G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE)
169 static const gchar introspection_xml[] =
171 " <interface name='org.freedesktop.IBus.Engine'>"
173 " <method name='ProcessKeyEvent'>"
174 " <arg direction='in' type='u' name='keyval' />"
175 " <arg direction='in' type='u' name='keycode' />"
176 " <arg direction='in' type='u' name='state' />"
177 " <arg direction='out' type='b' />"
179 " <method name='SetCursorLocation'>"
180 " <arg direction='in' type='i' name='x' />"
181 " <arg direction='in' type='i' name='y' />"
182 " <arg direction='in' type='i' name='w' />"
183 " <arg direction='in' type='i' name='h' />"
185 " <method name='ProcessHandWritingEvent'>"
186 " <arg direction='in' type='ad' name='coordinates' />"
188 " <method name='CancelHandWriting'>"
189 " <arg direction='in' type='u' name='n_strokes' />"
191 " <method name='SetCapabilities'>"
192 " <arg direction='in' type='u' name='caps' />"
194 " <method name='PropertyActivate'>"
195 " <arg direction='in' type='s' name='name' />"
196 " <arg direction='in' type='u' name='state' />"
198 " <method name='PropertyShow'>"
199 " <arg direction='in' type='s' name='name' />"
201 " <method name='PropertyHide'>"
202 " <arg direction='in' type='s' name='name' />"
204 " <method name='CandidateClicked'>"
205 " <arg direction='in' type='u' name='index' />"
206 " <arg direction='in' type='u' name='button' />"
207 " <arg direction='in' type='u' name='state' />"
209 " <method name='FocusIn' />"
210 " <method name='FocusOut' />"
211 " <method name='Reset' />"
212 " <method name='Enable' />"
213 " <method name='Disable' />"
214 " <method name='PageUp' />"
215 " <method name='PageDown' />"
216 " <method name='CursorUp' />"
217 " <method name='CursorDown' />"
218 " <method name='SetSurroundingText'>"
219 " <arg direction='in' type='v' name='text' />"
220 " <arg direction='in' type='u' name='cursor_pos' />"
221 " <arg direction='in' type='u' name='anchor_pos' />"
224 " <signal name='CommitText'>"
225 " <arg type='v' name='text' />"
227 " <signal name='UpdatePreeditText'>"
228 " <arg type='v' name='text' />"
229 " <arg type='u' name='cursor_pos' />"
230 " <arg type='b' name='visible' />"
231 " <arg type='u' name='mode' />"
233 " <signal name='UpdateAuxiliaryText'>"
234 " <arg type='v' name='text' />"
235 " <arg type='b' name='visible' />"
237 " <signal name='UpdateLookupTable'>"
238 " <arg type='v' name='table' />"
239 " <arg type='b' name='visible' />"
241 " <signal name='RegisterProperties'>"
242 " <arg type='v' name='props' />"
244 " <signal name='UpdateProperty'>"
245 " <arg type='v' name='prop' />"
247 " <signal name='ForwardKeyEvent'>"
248 " <arg type='u' name='keyval' />"
249 " <arg type='u' name='keycode' />"
250 " <arg type='u' name='state' />"
256 ibus_engine_class_init (IBusEngineClass *class)
258 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
259 IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
261 gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
262 gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
264 ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
266 IBUS_SERVICE_CLASS (class)->service_method_call = ibus_engine_service_method_call;
267 IBUS_SERVICE_CLASS (class)->service_get_property = ibus_engine_service_get_property;
268 IBUS_SERVICE_CLASS (class)->service_set_property = ibus_engine_service_set_property;
270 ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
272 class->process_key_event = ibus_engine_process_key_event;
273 class->focus_in = ibus_engine_focus_in;
274 class->focus_out = ibus_engine_focus_out;
275 class->reset = ibus_engine_reset;
276 class->enable = ibus_engine_enable;
277 class->disable = ibus_engine_disable;
278 class->page_up = ibus_engine_page_up;
279 class->page_down = ibus_engine_page_down;
280 class->cursor_up = ibus_engine_cursor_up;
281 class->cursor_down = ibus_engine_cursor_down;
282 class->candidate_clicked = ibus_engine_candidate_clicked;
283 class->property_activate = ibus_engine_property_activate;
284 class->property_show = ibus_engine_property_show;
285 class->property_hide = ibus_engine_property_hide;
286 class->set_cursor_location = ibus_engine_set_cursor_location;
287 class->set_capabilities = ibus_engine_set_capabilities;
288 class->set_surrounding_text = ibus_engine_set_surrounding_text;
289 class->process_hand_writing_event
290 = ibus_engine_process_hand_writing_event;
291 class->cancel_hand_writing = ibus_engine_cancel_hand_writing;
293 /* install properties */
297 * Name of this IBusEngine.
299 g_object_class_install_property (gobject_class,
301 g_param_spec_string ("engine-name",
306 G_PARAM_CONSTRUCT_ONLY |
307 G_PARAM_STATIC_STRINGS));
309 /* install signals */
311 * IBusEngine::process-key-event:
312 * @engine: An IBusEngine.
313 * @keyval: Key symbol of the key press.
314 * @keycode: KeyCode of the key press.
315 * @state: Key modifier flags.
317 * Emitted when a key event is received.
318 * Implement the member function process_key_event() in extended class to receive this signal.
319 * Both the key symbol and keycode are passed to the member function.
320 * See ibus_input_context_process_key_event() for further explanation of
321 * key symbol, keycode and which to use.
323 * Returns: TRUE for successfully process the key; FALSE otherwise.
324 * See also: ibus_input_context_process_key_event().
326 * <note><para>Argument @user_data is ignored in this function.</para></note>
328 engine_signals[PROCESS_KEY_EVENT] =
329 g_signal_new (I_("process-key-event"),
330 G_TYPE_FROM_CLASS (gobject_class),
332 G_STRUCT_OFFSET (IBusEngineClass, process_key_event),
333 g_signal_accumulator_true_handled, NULL,
334 _ibus_marshal_BOOL__UINT_UINT_UINT,
342 * IBusEngine::focus-in:
343 * @engine: An IBusEngine.
345 * Emitted when the client application get the focus.
346 * Implement the member function focus_in() in extended class to receive this signal.
348 * See also: ibus_input_context_focus_in()
349 * <note><para>Argument @user_data is ignored in this function.</para></note>
351 engine_signals[FOCUS_IN] =
352 g_signal_new (I_("focus-in"),
353 G_TYPE_FROM_CLASS (gobject_class),
355 G_STRUCT_OFFSET (IBusEngineClass, focus_in),
357 _ibus_marshal_VOID__VOID,
362 * IBusEngine::focus-out:
363 * @engine: An IBusEngine.
365 * Emitted when the client application lost the focus.
366 * Implement the member function focus_out() in extended class to receive this signal.
368 * See also: ibus_input_context_focus_out()
369 * <note><para>Argument @user_data is ignored in this function.</para></note>
371 engine_signals[FOCUS_OUT] =
372 g_signal_new (I_("focus-out"),
373 G_TYPE_FROM_CLASS (gobject_class),
375 G_STRUCT_OFFSET (IBusEngineClass, focus_out),
377 _ibus_marshal_VOID__VOID,
383 * @engine: An IBusEngine.
385 * Emitted when the IME is reset.
386 * Implement the member function reset() in extended class to receive this signal.
388 * See also: ibus_input_context_reset().
389 * <note><para>Argument @user_data is ignored in this function.</para></note>
391 engine_signals[RESET] =
392 g_signal_new (I_("reset"),
393 G_TYPE_FROM_CLASS (gobject_class),
395 G_STRUCT_OFFSET (IBusEngineClass, reset),
397 _ibus_marshal_VOID__VOID,
402 * IBusEngine::enable:
403 * @engine: An IBusEngine.
405 * Emitted when the IME is enabled.
406 * Implement the member function set_enable() in extended class to receive this signal.
408 * See also: ibus_input_context_enable().
409 * <note><para>Argument @user_data is ignored in this function.</para></note>
411 engine_signals[ENABLE] =
412 g_signal_new (I_("enable"),
413 G_TYPE_FROM_CLASS (gobject_class),
415 G_STRUCT_OFFSET (IBusEngineClass, enable),
417 _ibus_marshal_VOID__VOID,
422 * IBusEngine::disable:
423 * @engine: An IBusEngine.
425 * Emitted when the IME is disabled.
426 * Implement the member function set_disable() in extended class to receive this signal.
428 * See also: ibus_input_context_disable().
429 * <note><para>Argument @user_data is ignored in this function.</para></note>
431 engine_signals[DISABLE] =
432 g_signal_new (I_("disable"),
433 G_TYPE_FROM_CLASS (gobject_class),
435 G_STRUCT_OFFSET (IBusEngineClass, disable),
437 _ibus_marshal_VOID__VOID,
442 * IBusEngine::set-cursor-location:
443 * @engine: An IBusEngine.
444 * @x: X coordinate of the cursor.
445 * @y: Y coordinate of the cursor.
446 * @w: Width of the cursor.
447 * @h: Height of the cursor.
449 * Emitted when the location of IME is set.
450 * Implement the member function set_cursor_location() in extended class to receive this signal.
452 * See also: ibus_input_context_set_cursor_location().
453 * <note><para>Argument @user_data is ignored in this function.</para></note>
455 engine_signals[SET_CURSOR_LOCATION] =
456 g_signal_new (I_("set-cursor-location"),
457 G_TYPE_FROM_CLASS (gobject_class),
459 G_STRUCT_OFFSET (IBusEngineClass, set_cursor_location),
461 _ibus_marshal_VOID__INT_INT_INT_INT,
470 * IBusEngine::set-capabilities:
471 * @engine: An IBusEngine.
472 * @caps: Capabilities flags of IBusEngine, see #IBusCapabilite
474 * Emitted when the client application capabilities is set.
475 * Implement the member function set_capabilities() in extended class to receive this signal.
477 * See also: ibus_input_context_set_capabilities().
478 * <note><para>Argument @user_data is ignored in this function.</para></note>
480 engine_signals[SET_CAPABILITIES] =
481 g_signal_new (I_("set-capabilities"),
482 G_TYPE_FROM_CLASS (gobject_class),
484 G_STRUCT_OFFSET (IBusEngineClass, set_capabilities),
486 _ibus_marshal_VOID__UINT,
492 * IBusEngine::page-up:
493 * @engine: An IBusEngine.
495 * Emitted when the page-up button is pressed.
496 * Implement the member function page_up() in extended class to receive this signal.
498 * <note><para>Argument @user_data is ignored in this function.</para></note>
500 engine_signals[PAGE_UP] =
501 g_signal_new (I_("page-up"),
502 G_TYPE_FROM_CLASS (gobject_class),
504 G_STRUCT_OFFSET (IBusEngineClass, page_up),
506 _ibus_marshal_VOID__VOID,
511 * IBusEngine::page-down:
512 * @engine: An IBusEngine.
514 * Emitted when the page-down button is pressed.
515 * Implement the member function page_down() in extended class to receive this signal.
517 * <note><para>Argument @user_data is ignored in this function.</para></note>
519 engine_signals[PAGE_DOWN] =
520 g_signal_new (I_("page-down"),
521 G_TYPE_FROM_CLASS (gobject_class),
523 G_STRUCT_OFFSET (IBusEngineClass, page_down),
525 _ibus_marshal_VOID__VOID,
530 * IBusEngine::cursor-up:
531 * @engine: An IBusEngine.
533 * Emitted when the up cursor button is pressed.
534 * Implement the member function cursor_up() in extended class to receive this signal.
536 * <note><para>Argument @user_data is ignored in this function.</para></note>
538 engine_signals[CURSOR_UP] =
539 g_signal_new (I_("cursor-up"),
540 G_TYPE_FROM_CLASS (gobject_class),
542 G_STRUCT_OFFSET (IBusEngineClass, cursor_up),
544 _ibus_marshal_VOID__VOID,
549 * IBusEngine::cursor-down:
550 * @engine: An IBusEngine.
552 * Emitted when the down cursor button is pressed.
553 * Implement the member function cursor_down() in extended class to receive this signal.
555 * <note><para>Argument @user_data is ignored in this function.</para></note>
557 engine_signals[CURSOR_DOWN] =
558 g_signal_new (I_("cursor-down"),
559 G_TYPE_FROM_CLASS (gobject_class),
561 G_STRUCT_OFFSET (IBusEngineClass, cursor_down),
563 _ibus_marshal_VOID__VOID,
568 * IBusEngine::candidate-clicked:
569 * @engine: An IBusEngine.
570 * @index: Index of candidate be clicked.
571 * @button: Mouse button.
572 * @state: Keyboard state.
574 * Emitted when candidate on lookup table is clicked.
575 * Implement the member function candidate_clicked() in extended class to receive this signal.
577 * <note><para>Argument @user_data is ignored in this function.</para></note>
579 engine_signals[CANDIDATE_CLICKED] =
580 g_signal_new (I_("candidate-clicked"),
581 G_TYPE_FROM_CLASS (gobject_class),
583 G_STRUCT_OFFSET (IBusEngineClass, candidate_clicked),
585 _ibus_marshal_VOID__UINT_UINT_UINT,
593 * IBusEngine::property-activate:
594 * @engine: An IBusEngine.
595 * @name: Property name.
596 * @state: Property state.
598 * Emitted when a property is activated or change changed.
599 * Implement the member function property_activate() in extended class to receive this signal.
601 * <note><para>Argument @user_data is ignored in this function.</para></note>
603 engine_signals[PROPERTY_ACTIVATE] =
604 g_signal_new (I_("property-activate"),
605 G_TYPE_FROM_CLASS (gobject_class),
607 G_STRUCT_OFFSET (IBusEngineClass, property_activate),
609 _ibus_marshal_VOID__STRING_UINT,
616 * IBusEngine::property-show:
617 * @engine: An IBusEngine.
618 * @name: Property name.
620 * Emitted when a property is shown.
621 * Implement the member function property_side() in extended class to receive this signal.
623 * <note><para>Argument @user_data is ignored in this function.</para></note>
625 engine_signals[PROPERTY_SHOW] =
626 g_signal_new (I_("property-show"),
627 G_TYPE_FROM_CLASS (gobject_class),
629 G_STRUCT_OFFSET (IBusEngineClass, property_show),
631 _ibus_marshal_VOID__STRING,
637 * IBusEngine::property-hide:
638 * @engine: An IBusEngine.
639 * @name: Property name.
641 * Emitted when a property is hidden.
642 * Implement the member function property_hide() in extended class to receive this signal.
644 * <note><para>Argument @user_data is ignored in this function.</para></note>
646 engine_signals[PROPERTY_HIDE] =
647 g_signal_new (I_("property-hide"),
648 G_TYPE_FROM_CLASS (gobject_class),
650 G_STRUCT_OFFSET (IBusEngineClass, property_hide),
652 _ibus_marshal_VOID__STRING,
658 * IBusEngine::process-hand-writing-event:
659 * @engine: An IBusEngine.
660 * @coordinates: An array of double (0.0 to 1.0) which represents a stroke (i.e. [x1, y1, x2, y2, x3, y3, ...]).
661 * @coordinates_len: The number of elements in the array.
663 * Emitted when a hand writing operation is cancelled.
664 * Implement the member function cancel_hand_writing() in extended class to receive this signal.
666 * <note><para>Argument @user_data is ignored in this function.</para></note>
668 engine_signals[PROCESS_HAND_WRITING_EVENT] =
669 g_signal_new (I_("process-hand-writing-event"),
670 G_TYPE_FROM_CLASS (gobject_class),
672 G_STRUCT_OFFSET (IBusEngineClass, process_hand_writing_event),
674 _ibus_marshal_VOID__POINTER_UINT,
681 * IBusEngine::cancel-hand-writing:
682 * @engine: An IBusEngine.
683 * @n_strokes: The number of strokes to be removed. 0 means "remove all".
685 * Emitted when a hand writing operation is cancelled.
686 * Implement the member function cancel_hand_writing() in extended class to receive this signal.
688 * <note><para>Argument @user_data is ignored in this function.</para></note>
690 engine_signals[CANCEL_HAND_WRITING] =
691 g_signal_new (I_("cancel-hand-writing"),
692 G_TYPE_FROM_CLASS (gobject_class),
694 G_STRUCT_OFFSET (IBusEngineClass, cancel_hand_writing),
696 _ibus_marshal_VOID__UINT,
701 g_type_class_add_private (class, sizeof (IBusEnginePrivate));
704 * IBusEngine::set-surrounding-text:
705 * @engine: An IBusEngine.
706 * @text: The surrounding text.
707 * @cursor_pos: The cursor position on surrounding text.
708 * @anchor_pos: The anchor position on selection area.
710 * Emitted when a surrounding text is set.
711 * Implement the member function set_surrounding_text() in extended class to receive this signal.
712 * If anchor_pos equals to cursor_pos, it means "there are no selection" or "does not support
713 * selection retrival".
715 * <note><para>Argument @user_data is ignored in this function.</para></note>
717 engine_signals[SET_SURROUNDING_TEXT] =
718 g_signal_new (I_("set-surrounding-text"),
719 G_TYPE_FROM_CLASS (gobject_class),
721 G_STRUCT_OFFSET (IBusEngineClass, set_surrounding_text),
723 _ibus_marshal_VOID__OBJECT_UINT_UINT,
730 text_empty = ibus_text_new_from_static_string ("");
731 g_object_ref_sink (text_empty);
735 ibus_engine_init (IBusEngine *engine)
737 engine->priv = IBUS_ENGINE_GET_PRIVATE (engine);
739 engine->priv->surrounding_text = g_object_ref_sink (text_empty);
743 ibus_engine_destroy (IBusEngine *engine)
745 g_free (engine->priv->engine_name);
746 engine->priv->engine_name = NULL;
748 if (engine->priv->surrounding_text) {
749 g_object_unref (engine->priv->surrounding_text);
750 engine->priv->surrounding_text = NULL;
753 IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
757 ibus_engine_set_property (IBusEngine *engine,
763 case PROP_ENGINE_NAME:
764 engine->priv->engine_name = g_value_dup_string (value);
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
772 ibus_engine_get_property (IBusEngine *engine,
778 case PROP_ENGINE_NAME:
779 g_value_set_string (value, engine->priv->engine_name);
783 G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
788 ibus_engine_service_method_call (IBusService *service,
789 GDBusConnection *connection,
791 const gchar *object_path,
792 const gchar *interface_name,
793 const gchar *method_name,
794 GVariant *parameters,
795 GDBusMethodInvocation *invocation)
797 IBusEngine *engine = IBUS_ENGINE (service);
799 if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
800 IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
801 service_method_call (service,
812 if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) {
813 guint keyval, keycode, state;
814 gboolean retval = FALSE;
815 g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state);
816 g_signal_emit (engine,
817 engine_signals[PROCESS_KEY_EVENT],
823 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval));
827 static const struct {
830 } no_arg_methods[] = {
831 { "FocusIn", FOCUS_IN },
832 { "FocusOut", FOCUS_OUT },
834 { "Enable", ENABLE },
835 { "Disable", DISABLE },
836 { "PageUp", PAGE_UP },
837 { "PageDown", PAGE_DOWN },
838 { "CursorUp", CURSOR_UP },
839 { "CursorDown", CURSOR_DOWN },
843 for (i = 0; i < G_N_ELEMENTS (no_arg_methods); i++) {
844 if (g_strcmp0 (method_name, no_arg_methods[i].member) == 0) {
845 g_signal_emit (engine, engine_signals[no_arg_methods[i].signal_id], 0);
846 g_dbus_method_invocation_return_value (invocation, NULL);
851 if (g_strcmp0 (method_name, "CandidateClicked") == 0) {
852 guint index, button, state;
853 g_variant_get (parameters, "(uuu)", &index, &button, &state);
854 g_signal_emit (engine,
855 engine_signals[CANDIDATE_CLICKED],
860 g_dbus_method_invocation_return_value (invocation, NULL);
864 if (g_strcmp0 (method_name, "PropertyActivate") == 0) {
867 g_variant_get (parameters, "(&su)", &name, &state);
868 g_signal_emit (engine,
869 engine_signals[PROPERTY_ACTIVATE],
873 g_dbus_method_invocation_return_value (invocation, NULL);
877 if (g_strcmp0 (method_name, "PropertyShow") == 0) {
879 g_variant_get (parameters, "(&s)", &name);
880 g_signal_emit (engine,
881 engine_signals[PROPERTY_SHOW],
884 g_dbus_method_invocation_return_value (invocation, NULL);
888 if (g_strcmp0 (method_name, "PropertyHide") == 0) {
890 g_variant_get (parameters, "(&s)", &name);
891 g_signal_emit (engine,
892 engine_signals[PROPERTY_HIDE],
895 g_dbus_method_invocation_return_value (invocation, NULL);
899 if (g_strcmp0 (method_name, "SetCursorLocation") == 0) {
901 g_variant_get (parameters, "(iiii)", &x, &y, &w, &h);
902 engine->cursor_area.x = x;
903 engine->cursor_area.y = y;
904 engine->cursor_area.width = w;
905 engine->cursor_area.height = h;
907 g_signal_emit (engine,
908 engine_signals[SET_CURSOR_LOCATION],
911 g_dbus_method_invocation_return_value (invocation, NULL);
915 if (g_strcmp0 (method_name, "SetCapabilities") == 0) {
917 g_variant_get (parameters, "(u)", &caps);
918 engine->client_capabilities = caps;
919 g_signal_emit (engine, engine_signals[SET_CAPABILITIES], 0, caps);
920 g_dbus_method_invocation_return_value (invocation, NULL);
924 if (g_strcmp0 (method_name, "SetSurroundingText") == 0) {
925 GVariant *variant = NULL;
930 g_variant_get (parameters,
935 text = IBUS_TEXT (ibus_serializable_deserialize (variant));
936 g_variant_unref (variant);
938 g_signal_emit (engine, engine_signals[SET_SURROUNDING_TEXT],
943 if (g_object_is_floating (text)) {
944 g_object_unref (text);
946 g_dbus_method_invocation_return_value (invocation, NULL);
950 if (g_strcmp0 (method_name, "ProcessHandWritingEvent") == 0) {
951 const gdouble *coordinates;
952 gsize coordinates_len = 0;
954 coordinates = g_variant_get_fixed_array (g_variant_get_child_value (parameters, 0), &coordinates_len, sizeof (gdouble));
955 g_return_if_fail (coordinates != NULL);
956 g_return_if_fail (coordinates_len >= 4); /* The array should contain at least one line. */
957 g_return_if_fail (coordinates_len <= G_MAXUINT); /* to prevent overflow in the cast in g_signal_emit */
958 g_return_if_fail ((coordinates_len & 1) == 0);
960 g_signal_emit (engine, engine_signals[PROCESS_HAND_WRITING_EVENT], 0,
961 coordinates, (guint) coordinates_len);
962 g_dbus_method_invocation_return_value (invocation, NULL);
966 if (g_strcmp0 (method_name, "CancelHandWriting") == 0) {
968 g_variant_get (parameters, "(u)", &n_strokes);
969 g_signal_emit (engine, engine_signals[CANCEL_HAND_WRITING], 0, n_strokes);
970 g_dbus_method_invocation_return_value (invocation, NULL);
974 /* should not be reached */
975 g_return_if_reached ();
979 ibus_engine_service_get_property (IBusService *service,
980 GDBusConnection *connection,
982 const gchar *object_path,
983 const gchar *interface_name,
984 const gchar *property_name,
987 return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
988 service_get_property (service,
998 ibus_engine_service_set_property (IBusService *service,
999 GDBusConnection *connection,
1000 const gchar *sender,
1001 const gchar *object_path,
1002 const gchar *interface_name,
1003 const gchar *property_name,
1007 return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
1008 service_set_property (service,
1019 ibus_engine_process_key_event (IBusEngine *engine,
1028 ibus_engine_focus_in (IBusEngine *engine)
1030 // g_debug ("focus-in");
1034 ibus_engine_focus_out (IBusEngine *engine)
1036 // g_debug ("focus-out");
1040 ibus_engine_reset (IBusEngine *engine)
1042 // g_debug ("reset");
1046 ibus_engine_enable (IBusEngine *engine)
1048 // g_debug ("enable");
1052 ibus_engine_disable (IBusEngine *engine)
1054 // g_debug ("disable");
1058 ibus_engine_set_cursor_location (IBusEngine *engine,
1064 // g_debug ("set-cursor-location (%d, %d, %d, %d)", x, y, w, h);
1068 ibus_engine_set_capabilities (IBusEngine *engine,
1071 // g_debug ("set-capabilities (0x%04x)", caps);
1075 ibus_engine_page_up (IBusEngine *engine)
1077 // g_debug ("page-up");
1081 ibus_engine_page_down (IBusEngine *engine)
1083 // g_debug ("page-down");
1087 ibus_engine_cursor_up (IBusEngine *engine)
1089 // g_debug ("cursor-up");
1093 ibus_engine_cursor_down (IBusEngine *engine)
1095 // g_debug ("cursor-down");
1099 ibus_engine_candidate_clicked (IBusEngine *engine,
1104 // g_debug ("candidate-clicked");
1108 ibus_engine_property_activate (IBusEngine *engine,
1109 const gchar *prop_name,
1112 // g_debug ("property-activate ('%s', %d)", prop_name, prop_state);
1116 ibus_engine_property_show (IBusEngine *engine, const gchar *prop_name)
1118 // g_debug ("property-show ('%s')", prop_name);
1122 ibus_engine_property_hide (IBusEngine *engine, const gchar *prop_name)
1124 // g_debug ("property-hide ('%s')", prop_name);
1128 ibus_engine_set_surrounding_text (IBusEngine *engine,
1133 g_assert (IBUS_IS_ENGINE (engine));
1135 if (engine->priv->surrounding_text) {
1136 g_object_unref (engine->priv->surrounding_text);
1139 engine->priv->surrounding_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
1140 engine->priv->surrounding_cursor_pos = cursor_pos;
1141 engine->priv->selection_anchor_pos = anchor_pos;
1142 // g_debug ("set-surrounding-text ('%s', %d, %d)", text->text, cursor_pos, anchor_pos);
1146 ibus_engine_process_hand_writing_event (IBusEngine *engine,
1147 const gdouble *coordinates,
1148 guint coordinates_len)
1151 // g_debug ("process-hand-writing-event (%u)", coordinates_len);
1152 // for (i = 0; i < coordinates_len; i++)
1153 // g_debug (" %lf", coordinates[i]);
1157 ibus_engine_cancel_hand_writing (IBusEngine *engine,
1160 // g_debug ("cancel-hand-writing (%u)", n_strokes);
1164 ibus_engine_emit_signal (IBusEngine *engine,
1165 const gchar *signal_name,
1166 GVariant *parameters)
1168 ibus_service_emit_signal ((IBusService *)engine,
1170 IBUS_INTERFACE_ENGINE,
1177 ibus_engine_new (const gchar *engine_name,
1178 const gchar *object_path,
1179 GDBusConnection *connection)
1181 return ibus_engine_new_with_type (IBUS_TYPE_ENGINE,
1188 ibus_engine_new_with_type (GType engine_type,
1189 const gchar *engine_name,
1190 const gchar *object_path,
1191 GDBusConnection *connection)
1193 g_return_val_if_fail (g_type_is_a (engine_type, IBUS_TYPE_ENGINE), NULL);
1194 g_return_val_if_fail (engine_name != NULL, NULL);
1195 g_return_val_if_fail (object_path != NULL, NULL);
1196 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1198 GObject *object = g_object_new (engine_type,
1199 "engine-name", engine_name,
1200 "object-path", object_path,
1201 "connection", connection,
1203 return IBUS_ENGINE (object);
1208 ibus_engine_commit_text (IBusEngine *engine,
1211 g_return_if_fail (IBUS_IS_ENGINE (engine));
1212 g_return_if_fail (IBUS_IS_TEXT (text));
1214 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1215 ibus_engine_emit_signal (engine,
1217 g_variant_new ("(v)", variant));
1219 if (g_object_is_floating (text)) {
1220 g_object_unref (text);
1225 ibus_engine_update_preedit_text (IBusEngine *engine,
1230 ibus_engine_update_preedit_text_with_mode (engine,
1231 text, cursor_pos, visible, IBUS_ENGINE_PREEDIT_CLEAR);
1235 ibus_engine_update_preedit_text_with_mode (IBusEngine *engine,
1239 IBusPreeditFocusMode mode)
1241 g_return_if_fail (IBUS_IS_ENGINE (engine));
1242 g_return_if_fail (IBUS_IS_TEXT (text));
1244 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1245 ibus_engine_emit_signal (engine,
1246 "UpdatePreeditText",
1247 g_variant_new ("(vubu)", variant, cursor_pos, visible, mode));
1249 if (g_object_is_floating (text)) {
1250 g_object_unref (text);
1254 void ibus_engine_update_auxiliary_text (IBusEngine *engine,
1258 g_return_if_fail (IBUS_IS_ENGINE (engine));
1259 g_return_if_fail (IBUS_IS_TEXT (text));
1261 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
1262 ibus_engine_emit_signal (engine,
1263 "UpdateAuxiliaryText",
1264 g_variant_new ("(vb)", variant, visible));
1266 if (g_object_is_floating (text)) {
1267 g_object_unref (text);
1273 ibus_engine_update_lookup_table (IBusEngine *engine,
1274 IBusLookupTable *table,
1277 g_return_if_fail (IBUS_IS_ENGINE (engine));
1278 g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
1280 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)table);
1281 ibus_engine_emit_signal (engine,
1282 "UpdateLookupTable",
1283 g_variant_new ("(vb)", variant, visible));
1285 if (g_object_is_floating (table)) {
1286 g_object_unref (table);
1291 ibus_engine_update_lookup_table_fast (IBusEngine *engine,
1292 IBusLookupTable *table,
1295 g_return_if_fail (IBUS_IS_ENGINE (engine));
1296 g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
1298 IBusLookupTable *new_table;
1303 if (table->candidates->len < table->page_size << 2) {
1304 ibus_engine_update_lookup_table (engine, table, visible);
1308 page_begin = (table->cursor_pos / table->page_size) * table->page_size;
1310 new_table = ibus_lookup_table_new (table->page_size, 0, table->cursor_visible, table->round);
1312 for (i = page_begin; i < page_begin + table->page_size && i < table->candidates->len; i++) {
1313 ibus_lookup_table_append_candidate (new_table, ibus_lookup_table_get_candidate (table, i));
1316 for (i = 0; (text = ibus_lookup_table_get_label (table, i)) != NULL; i++) {
1317 ibus_lookup_table_append_label (new_table, text);
1320 ibus_lookup_table_set_cursor_pos (new_table, ibus_lookup_table_get_cursor_in_page (table));
1321 ibus_lookup_table_set_orientation (new_table, ibus_lookup_table_get_orientation (table));
1323 ibus_engine_update_lookup_table (engine, new_table, visible);
1325 if (g_object_is_floating (table)) {
1326 g_object_unref (table);
1331 ibus_engine_forward_key_event (IBusEngine *engine,
1336 g_return_if_fail (IBUS_IS_ENGINE (engine));
1338 ibus_engine_emit_signal (engine,
1340 g_variant_new ("(uuu)", keyval, keycode, state));
1343 void ibus_engine_delete_surrounding_text (IBusEngine *engine,
1344 gint offset_from_cursor,
1347 IBusEnginePrivate *priv;
1349 g_return_if_fail (IBUS_IS_ENGINE (engine));
1351 priv = IBUS_ENGINE_GET_PRIVATE (engine);
1353 /* Update surrounding-text cache. This is necessary since some
1354 engines call ibus_engine_get_surrounding_text() immediately
1355 after ibus_engine_delete_surrounding_text(). */
1356 if (priv->surrounding_text) {
1358 glong cursor_pos, len;
1360 cursor_pos = priv->surrounding_cursor_pos + offset_from_cursor;
1361 len = ibus_text_get_length (priv->surrounding_text);
1362 if (cursor_pos >= 0 && len - cursor_pos >= nchars) {
1365 ucs = g_utf8_to_ucs4_fast (priv->surrounding_text->text,
1368 memmove (&ucs[cursor_pos],
1369 &ucs[cursor_pos + nchars],
1370 sizeof(gunichar) * (len - cursor_pos - nchars));
1371 ucs[len - nchars] = 0;
1372 text = ibus_text_new_from_ucs4 (ucs);
1374 priv->surrounding_cursor_pos = cursor_pos;
1377 priv->surrounding_cursor_pos = 0;
1380 g_object_unref (priv->surrounding_text);
1381 priv->surrounding_text = g_object_ref_sink (text);
1384 ibus_engine_emit_signal (engine,
1385 "DeleteSurroundingText",
1386 g_variant_new ("(iu)", offset_from_cursor, nchars));
1390 ibus_engine_get_surrounding_text (IBusEngine *engine,
1395 IBusEnginePrivate *priv;
1397 g_return_if_fail (IBUS_IS_ENGINE (engine));
1398 const gboolean signal_only = (text == NULL);
1400 g_return_if_fail (( signal_only && (cursor_pos == NULL)) ||
1401 (!signal_only && (cursor_pos != NULL)));
1403 g_return_if_fail (( signal_only && (anchor_pos == NULL)) ||
1404 (!signal_only && (anchor_pos != NULL)));
1406 priv = IBUS_ENGINE_GET_PRIVATE (engine);
1409 *text = g_object_ref (priv->surrounding_text);
1410 *cursor_pos = priv->surrounding_cursor_pos;
1411 *anchor_pos = priv->selection_anchor_pos;
1414 /* tell the client that this engine will utilize surrounding-text
1415 * feature, which causes periodical update. Note that the client
1416 * should request the initial surrounding-text when the engine is
1417 * enabled (see ibus_im_context_focus_in() and
1418 * _ibus_context_enabled_cb() in client/gtk2/ibusimcontext.c). */
1419 ibus_engine_emit_signal (engine,
1420 "RequireSurroundingText",
1423 // g_debug ("get-surrounding-text ('%s', %d, %d)", (*text)->text, *cursor_pos, *anchor_pos);
1427 ibus_engine_register_properties (IBusEngine *engine,
1428 IBusPropList *prop_list)
1430 g_return_if_fail (IBUS_IS_ENGINE (engine));
1431 g_return_if_fail (IBUS_IS_PROP_LIST (prop_list));
1433 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop_list);
1434 ibus_engine_emit_signal (engine,
1435 "RegisterProperties",
1436 g_variant_new ("(v)", variant));
1438 if (g_object_is_floating (prop_list)) {
1439 g_object_unref (prop_list);
1444 ibus_engine_update_property (IBusEngine *engine,
1447 g_return_if_fail (IBUS_IS_ENGINE (engine));
1448 g_return_if_fail (IBUS_IS_PROPERTY (prop));
1450 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
1451 ibus_engine_emit_signal (engine,
1453 g_variant_new ("(v)", variant));
1455 if (g_object_is_floating (prop)) {
1456 g_object_unref (prop);
1460 #define DEFINE_FUNC(name, Name) \
1462 ibus_engine_##name (IBusEngine *engine) \
1464 g_return_if_fail (IBUS_IS_ENGINE (engine)); \
1465 ibus_engine_emit_signal (engine, \
1469 DEFINE_FUNC (show_preedit_text, ShowPreeditText)
1470 DEFINE_FUNC (hide_preedit_text, HidePreeditText)
1471 DEFINE_FUNC (show_auxiliary_text, ShowAuxiliaryText)
1472 DEFINE_FUNC (hide_auxiliary_text, HideAuxiliaryText)
1473 DEFINE_FUNC (show_lookup_table, ShowLookupTable)
1474 DEFINE_FUNC (hide_lookup_table, HideLookupTable)
1478 ibus_engine_get_name (IBusEngine *engine)
1480 g_return_val_if_fail (IBUS_IS_ENGINE (engine), NULL);
1481 return engine->priv->engine_name;