summaryrefslogtreecommitdiffstats
path: root/src/ibuscomponent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ibuscomponent.c')
-rw-r--r--src/ibuscomponent.c743
1 files changed, 743 insertions, 0 deletions
diff --git a/src/ibuscomponent.c b/src/ibuscomponent.c
new file mode 100644
index 0000000..9ca487d
--- /dev/null
+++ b/src/ibuscomponent.c
@@ -0,0 +1,743 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gstdio.h>
+#include "ibuscomponent.h"
+
+enum {
+ LAST_SIGNAL,
+};
+
+
+/* IBusComponentPriv */
+struct _IBusComponentPrivate {
+ gpointer pad;
+};
+typedef struct _IBusComponentPrivate IBusComponentPrivate;
+
+#define IBUS_COMPONENT_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), BUS_TYPE_COMPONENT, IBusComponentPrivate))
+
+// static guint _signals[LAST_SIGNAL] = { 0 };
+
+/* functions prototype */
+static void ibus_component_class_init (IBusComponentClass *klass);
+static void ibus_component_init (IBusComponent *component);
+static void ibus_component_destroy (IBusComponent *component);
+static gboolean ibus_component_serialize (IBusComponent *component,
+ IBusMessageIter *iter);
+static gboolean ibus_component_deserialize (IBusComponent *component,
+ IBusMessageIter *iter);
+static gboolean ibus_component_copy (IBusComponent *dest,
+ const IBusComponent *src);
+static gboolean ibus_component_parse_xml_node
+ (IBusComponent *component,
+ XMLNode *node,
+ gboolean access_fs);
+
+static void ibus_component_parse_engines(IBusComponent *component,
+ XMLNode *node);
+static void ibus_component_parse_observed_paths
+ (IBusComponent *component,
+ XMLNode *node,
+ gboolean access_fs);
+
+static IBusSerializableClass *parent_class = NULL;
+
+GType
+ibus_component_get_type (void)
+{
+ static GType type = 0;
+
+ static const GTypeInfo type_info = {
+ sizeof (IBusComponentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ibus_component_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (IBusComponent),
+ 0,
+ (GInstanceInitFunc) ibus_component_init,
+ };
+
+ if (type == 0) {
+ type = g_type_register_static (IBUS_TYPE_SERIALIZABLE,
+ "IBusComponent",
+ &type_info,
+ (GTypeFlags)0);
+ }
+
+ return type;
+}
+
+
+static void
+ibus_component_class_init (IBusComponentClass *klass)
+{
+ IBusObjectClass *object_class = IBUS_OBJECT_CLASS (klass);
+ IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (klass);
+
+ parent_class = (IBusSerializableClass *) g_type_class_peek_parent (klass);
+
+ object_class->destroy = (IBusObjectDestroyFunc) ibus_component_destroy;
+
+ serializable_class->serialize = (IBusSerializableSerializeFunc) ibus_component_serialize;
+ serializable_class->deserialize = (IBusSerializableDeserializeFunc) ibus_component_deserialize;
+ serializable_class->copy = (IBusSerializableCopyFunc) ibus_component_copy;
+
+ g_string_append (serializable_class->signature, "ssssssssavav");
+}
+
+
+
+static void
+ibus_component_init (IBusComponent *component)
+{
+ component->name = NULL;
+ component->description = NULL;
+ component->version = NULL;
+ component->license = NULL;
+ component->author = NULL;
+ component->homepage = NULL;
+ component->exec = NULL;
+ component->textdomain = NULL;
+ component->engines = NULL;
+ component->observed_paths = NULL;
+}
+
+static void
+ibus_component_destroy (IBusComponent *component)
+{
+ GList *p;
+
+ g_free (component->name);
+ g_free (component->description);
+ g_free (component->version);
+ g_free (component->license);
+ g_free (component->author);
+ g_free (component->homepage);
+ g_free (component->exec);
+ g_free (component->textdomain);
+
+ component->name = NULL;
+ component->description = NULL;
+ component->version = NULL;
+ component->license = NULL;
+ component->author = NULL;
+ component->homepage = NULL;
+ component->exec = NULL;
+ component->textdomain = NULL;
+
+ g_list_foreach (component->observed_paths, (GFunc)g_object_unref, NULL);
+ g_list_free (component->observed_paths);
+ component->observed_paths = NULL;
+
+ for (p = component->engines; p != NULL; p = p->next) {
+ g_object_steal_data ((GObject *)p->data, "component");
+ ibus_object_destroy ((IBusObject *)p->data);
+ g_object_unref (p->data);
+ }
+ g_list_free (component->engines);
+ component->engines = NULL;
+
+ IBUS_OBJECT_CLASS (parent_class)->destroy (IBUS_OBJECT (component));
+}
+
+static gboolean
+ibus_component_serialize (IBusComponent *component,
+ IBusMessageIter *iter)
+{
+ gboolean retval;
+ IBusMessageIter array_iter;
+ GList *p;
+
+ retval = parent_class->serialize ((IBusSerializable *)component, iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->name);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->description);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->version);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->license);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->author);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->homepage);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->exec);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_append (iter, G_TYPE_STRING, &component->textdomain);
+ g_return_val_if_fail (retval, FALSE);
+
+ /* serialize observed paths */
+ retval = ibus_message_iter_open_container (iter, IBUS_TYPE_ARRAY, "v", &array_iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ for (p = component->observed_paths; p != NULL; p = p->next) {
+ retval = ibus_message_iter_append (&array_iter, IBUS_TYPE_OBSERVED_PATH, &(p->data));
+ g_return_val_if_fail (retval, FALSE);
+ }
+ retval = ibus_message_iter_close_container (iter, &array_iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ /* serialize engine desc */
+ retval = ibus_message_iter_open_container (iter, IBUS_TYPE_ARRAY, "v", &array_iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ for (p = component->engines; p != NULL; p = p->next) {
+ retval = ibus_message_iter_append (&array_iter, IBUS_TYPE_ENGINE_DESC, &(p->data));
+ g_return_val_if_fail (retval, FALSE);
+ }
+ retval = ibus_message_iter_close_container (iter, &array_iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ return TRUE;
+}
+
+static gboolean
+ibus_component_deserialize (IBusComponent *component,
+ IBusMessageIter *iter)
+{
+ gboolean retval;
+ gchar *str;
+ IBusMessageIter array_iter;
+
+ retval = parent_class->deserialize ((IBusSerializable *)component, iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->name = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->description = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->version = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->license = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->author = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->homepage = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->exec = g_strdup (str);
+
+ retval = ibus_message_iter_get (iter, G_TYPE_STRING, &str);
+ g_return_val_if_fail (retval, FALSE);
+ component->textdomain = g_strdup (str);
+
+ retval = ibus_message_iter_recurse (iter, IBUS_TYPE_ARRAY, &array_iter);
+ g_return_val_if_fail (retval, FALSE);
+ while (ibus_message_iter_get_arg_type (&array_iter) != G_TYPE_INVALID) {
+ IBusObservedPath *path;
+ retval = ibus_message_iter_get (&array_iter, IBUS_TYPE_OBSERVED_PATH, &path);
+ component->observed_paths = g_list_append (component->observed_paths, path);
+ }
+ ibus_message_iter_next (iter);
+
+ retval = ibus_message_iter_recurse (iter, IBUS_TYPE_ARRAY, &array_iter);
+ g_return_val_if_fail (retval, FALSE);
+
+ while (ibus_message_iter_get_arg_type (&array_iter) != G_TYPE_INVALID) {
+ IBusEngineDesc *engine;
+ retval = ibus_message_iter_get (&array_iter, IBUS_TYPE_ENGINE_DESC, &engine);
+ ibus_component_add_engine (component, engine);
+ }
+ ibus_message_iter_next (iter);
+
+ return TRUE;
+}
+
+static gboolean
+ibus_component_copy (IBusComponent *dest,
+ const IBusComponent *src)
+{
+ gboolean retval;
+
+ retval = parent_class->copy ((IBusSerializable *)dest,
+ (IBusSerializable *)src);
+ g_return_val_if_fail (retval, FALSE);
+
+
+ dest->name = g_strdup (src->name);
+ dest->description = g_strdup (src->description);
+ dest->version = g_strdup (src->version);
+ dest->license = g_strdup (src->license);
+ dest->author = g_strdup (src->author);
+ dest->homepage = g_strdup (src->homepage);
+ dest->exec = g_strdup (src->exec);
+ dest->textdomain = g_strdup (src->textdomain);
+
+ dest->observed_paths = g_list_copy (src->observed_paths);
+ g_list_foreach (dest->observed_paths, (GFunc) g_object_ref, NULL);
+
+ dest->engines = g_list_copy (src->engines);
+ g_list_foreach (dest->engines, (GFunc) g_object_ref, NULL);
+
+ return TRUE;
+}
+
+
+#define g_string_append_indent(string, indent) \
+ { \
+ gint i; \
+ for (i = 0; i < (indent); i++) { \
+ g_string_append (string, " "); \
+ } \
+ }
+
+void
+ibus_component_output (IBusComponent *component,
+ GString *output,
+ gint indent)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+ GList *p;
+
+ g_string_append_indent (output, indent);
+ g_string_append (output, "<component>\n");
+
+#define OUTPUT_ENTRY(field, element) \
+ { \
+ gchar *escape_text = g_markup_escape_text (component->field, -1); \
+ g_string_append_indent (output, indent + 1); \
+ g_string_append_printf (output, "<"element">%s</"element">\n", \
+ escape_text); \
+ g_free (escape_text); \
+ }
+#define OUTPUT_ENTRY_1(name) OUTPUT_ENTRY(name, #name)
+ OUTPUT_ENTRY_1 (name);
+ OUTPUT_ENTRY_1 (description);
+ OUTPUT_ENTRY_1 (version);
+ OUTPUT_ENTRY_1 (license);
+ OUTPUT_ENTRY_1 (author);
+ OUTPUT_ENTRY_1 (homepage);
+ OUTPUT_ENTRY_1 (exec);
+ OUTPUT_ENTRY_1 (textdomain);
+#undef OUTPUT_ENTRY
+#undef OUTPUT_ENTRY_1
+
+ if (component->observed_paths) {
+ g_string_append_indent (output, indent + 1);
+ g_string_append (output, "<observed-paths>\n");
+
+ for (p = component->observed_paths; p != NULL; p = p->next ) {
+ IBusObservedPath *path = (IBusObservedPath *) p->data;
+
+ g_string_append_indent (output, indent + 2);
+ g_string_append_printf (output, "<path mtime=\"%ld\" >%s</path>\n",
+ path->mtime,
+ path->path);
+ }
+
+ g_string_append_indent (output, indent + 1);
+ g_string_append (output, "</observed-paths>\n");
+ }
+
+ ibus_component_output_engines (component, output, indent + 1);
+
+ g_string_append_indent (output, indent);
+ g_string_append (output, "</component>\n");
+}
+
+void
+ibus_component_output_engines (IBusComponent *component,
+ GString *output,
+ gint indent)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+ g_assert (output);
+
+ GList *p;
+
+ g_string_append_indent (output, indent);
+ g_string_append (output, "<engines>\n");
+
+ for (p = component->engines; p != NULL; p = p->next) {
+ ibus_engine_desc_output ((IBusEngineDesc *)p->data, output, indent + 2);
+ }
+
+ g_string_append_indent (output, indent);
+ g_string_append (output, "</engines>\n");
+}
+
+static gboolean
+ibus_component_parse_xml_node (IBusComponent *component,
+ XMLNode *node,
+ gboolean access_fs)
+{
+ g_assert (component);
+ g_assert (node);
+
+ if (G_UNLIKELY (g_strcmp0 (node->name, "component") != 0)) {
+ return FALSE;
+ }
+
+ GList *p;
+ for (p = node->sub_nodes; p != NULL; p = p->next) {
+ XMLNode *sub_node = (XMLNode *)p->data;
+
+#define PARSE_ENTRY(field_name, element_name) \
+ if (g_strcmp0 (sub_node->name, element_name) == 0) { \
+ if (component->field_name != NULL) { \
+ g_free (component->field_name); \
+ } \
+ component->field_name = g_strdup (sub_node->text); \
+ continue; \
+ }
+#define PARSE_ENTRY_1(name) PARSE_ENTRY (name, #name)
+ PARSE_ENTRY_1 (name);
+ PARSE_ENTRY_1 (description);
+ PARSE_ENTRY_1 (version);
+ PARSE_ENTRY_1 (license);
+ PARSE_ENTRY_1 (author);
+ PARSE_ENTRY_1 (homepage);
+ PARSE_ENTRY_1 (exec);
+ PARSE_ENTRY_1 (textdomain);
+#undef PARSE_ENTRY
+#undef PARSE_ENTRY_1
+
+ if (g_strcmp0 (sub_node->name, "engines") == 0) {
+ ibus_component_parse_engines (component, sub_node);
+ continue;
+ }
+
+ if (g_strcmp0 (sub_node->name, "observed-paths") == 0) {
+ ibus_component_parse_observed_paths (component, sub_node, access_fs);
+ continue;
+ }
+
+ g_warning ("<component> element contains invalidate element <%s>", sub_node->name);
+ }
+
+ return TRUE;
+}
+
+
+static void
+ibus_component_parse_engines (IBusComponent *component,
+ XMLNode *node)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+ g_assert (node);
+
+ gchar *exec = NULL;
+ gchar **p;
+ XMLNode *engines_node = NULL;
+
+ if (g_strcmp0 (node->name, "engines") != 0) {
+ return;
+ }
+
+ for (p = node->attributes; *p != NULL; p += 2) {
+ if (g_strcmp0 (*p, "exec") == 0) {
+ exec = *(p + 1);
+ break;
+ }
+ }
+
+ if (exec != NULL) {
+ gchar *output = NULL;
+ if (g_spawn_command_line_sync (exec, &output, NULL, NULL, NULL)) {
+ engines_node = ibus_xml_parse_buffer (output);
+ g_free (output);
+
+ if (engines_node) {
+ if (g_strcmp0 (engines_node->name, "engines") != 0) {
+ ibus_xml_free (engines_node);
+ engines_node = NULL;
+ }
+ }
+ node = engines_node;
+ }
+ }
+
+ GList *pl;
+ for (pl = node->sub_nodes; pl != NULL; pl = pl->next) {
+ IBusEngineDesc *engine;
+ engine = ibus_engine_desc_new_from_xml_node ((XMLNode *)pl->data);
+
+ if (G_UNLIKELY (engine == NULL))
+ continue;
+ ibus_component_add_engine (component, engine);
+ }
+
+ if (engines_node) {
+ ibus_xml_free (engines_node);
+ }
+}
+
+static void
+ibus_component_parse_observed_paths (IBusComponent *component,
+ XMLNode *node,
+ gboolean access_fs)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+ g_assert (node);
+
+ if (g_strcmp0 (node->name, "observed-paths") != 0) {
+ return;
+ }
+
+ GList *p;
+ for (p = node->sub_nodes; p != NULL; p = p->next) {
+ IBusObservedPath *path;
+
+ path = ibus_observed_path_new_from_xml_node ((XMLNode *)p->data, access_fs);
+ component->observed_paths = g_list_append (component->observed_paths, path);
+
+ if (access_fs && path->is_dir && path->is_exist) {
+ component->observed_paths = g_list_concat (component->observed_paths,
+ ibus_observed_path_traverse (path));
+ }
+ }
+}
+
+IBusComponent *
+ibus_component_new (const gchar *name,
+ const gchar *descritpion,
+ const gchar *version,
+ const gchar *license,
+ const gchar *author,
+ const gchar *homepage,
+ const gchar *exec,
+ const gchar *textdomain)
+{
+
+ IBusComponent *component;
+ component = (IBusComponent *)g_object_new (IBUS_TYPE_COMPONENT, NULL);
+
+ component->name = g_strdup (name);
+ component->description = g_strdup (descritpion);
+ component->version = g_strdup (version);
+ component->license = g_strdup (license);
+ component->author = g_strdup (author);
+ component->homepage = g_strdup (homepage);
+ component->exec = g_strdup (exec);
+ component->textdomain = g_strdup (textdomain);
+
+ return component;
+}
+
+
+IBusComponent *
+ibus_component_new_from_xml_node (XMLNode *node)
+{
+ g_assert (node);
+
+ IBusComponent *component;
+
+ component = (IBusComponent *)g_object_new (IBUS_TYPE_COMPONENT, NULL);
+ if (!ibus_component_parse_xml_node (component, node, FALSE)) {
+ g_object_unref (component);
+ component = NULL;
+ }
+
+ return component;
+}
+
+IBusComponent *
+ibus_component_new_from_file (const gchar *filename)
+{
+ g_assert (filename);
+
+ XMLNode *node;
+ struct stat buf;
+ IBusComponent *component;
+ gboolean retval;
+
+ if (g_stat (filename, &buf) != 0) {
+ g_warning ("Can not get stat of file %s", filename);
+ return NULL;
+ }
+
+ node = ibus_xml_parse_file (filename);
+
+ if (!node) {
+ return NULL;
+ }
+
+ component = (IBusComponent *)g_object_new (IBUS_TYPE_COMPONENT, NULL);
+ retval = ibus_component_parse_xml_node (component, node, TRUE);
+ ibus_xml_free (node);
+
+ if (!retval) {
+ g_object_unref (component);
+ component = NULL;
+ }
+ else {
+ IBusObservedPath *path;
+ path = ibus_observed_path_new (filename, TRUE);
+ component->observed_paths = g_list_prepend (component->observed_paths, path);
+ }
+
+ return component;
+}
+
+void
+ibus_component_add_observed_path (IBusComponent *component,
+ const gchar *path,
+ gboolean access_fs)
+{
+ IBusObservedPath *p;
+
+ p = ibus_observed_path_new (path, access_fs);
+ component->observed_paths = g_list_append (component->observed_paths, p);
+
+ if (access_fs && p->is_dir && p->is_exist) {
+ component->observed_paths = g_list_concat (component->observed_paths,
+ ibus_observed_path_traverse (p));
+ }
+}
+
+void
+ibus_component_add_engine (IBusComponent *component,
+ IBusEngineDesc *engine)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+ g_assert (IBUS_IS_ENGINE_DESC (engine));
+
+ component->engines = g_list_append (component->engines, engine);
+ g_object_set_data ((GObject *)engine, "component", component);
+}
+
+GList *
+ibus_component_get_engines (IBusComponent *component)
+{
+ return g_list_copy (component->engines);
+}
+
+static void
+ibus_component_child_cb (GPid pid,
+ gint status,
+ IBusComponent *component)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+ g_assert (component->pid == pid);
+
+ g_spawn_close_pid (pid);
+ component->pid = 0;
+}
+
+gboolean
+ibus_component_start (IBusComponent *component)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+
+ if (component->pid != 0)
+ return TRUE;
+
+ gint argc;
+ gchar **argv;
+ gboolean retval;
+ GError *error;
+
+ error = NULL;
+ if (!g_shell_parse_argv (component->exec, &argc, &argv, &error)) {
+ g_warning ("Can not parse component %s exec: %s", component->name, error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ error = NULL;
+ retval = g_spawn_async (NULL, argv, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL, NULL,
+ &(component->pid), &error);
+ g_strfreev (argv)
+ ;
+ if (!retval) {
+ g_warning ("Can not execute component %s: %s", component->name, error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ g_child_watch_add (component->pid, (GChildWatchFunc) ibus_component_child_cb, component);
+
+ return TRUE;
+}
+
+gboolean
+ibus_component_stop (IBusComponent *component)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+
+ if (component->pid == 0)
+ return TRUE;
+
+ kill (component->pid, SIGTERM);
+ return TRUE;
+}
+
+gboolean
+ibus_component_is_running (IBusComponent *component)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+
+ return (component->pid != 0);
+}
+
+
+gboolean
+ibus_component_check_modification (IBusComponent *component)
+{
+ g_assert (IBUS_IS_COMPONENT (component));
+
+ GList *p;
+
+ for (p = component->observed_paths; p != NULL; p = p->next) {
+ if (ibus_observed_path_check_modification ((IBusObservedPath *)p->data))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+IBusComponent *
+ibus_component_get_from_engine (IBusEngineDesc *engine)
+{
+ g_assert (IBUS_IS_ENGINE_DESC (engine));
+
+ IBusComponent *component;
+
+ component = (IBusComponent *)g_object_get_data ((GObject *)engine, "component");
+ return component;
+}