Add Ctrl+space customization.
[platform/upstream/ibus.git] / src / ibuscomponent.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* bus - The Input Bus
4  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2010 Red Hat, Inc.
6  *
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.
11  *
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.
16  *
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.
21  */
22 #include <glib/gstdio.h>
23 #include "ibuscomponent.h"
24
25 enum {
26     LAST_SIGNAL,
27 };
28
29 enum {
30     PROP_0 = 0,
31     PROP_NAME,
32     PROP_DESCRIPTION,
33     PROP_VERSION,
34     PROP_LICENSE,
35     PROP_AUTHOR,
36     PROP_HOMEPAGE,
37     PROP_COMMAND_LINE,
38     PROP_TEXTDOMAIN,
39 };
40
41 /* IBusComponentPriv */
42 struct _IBusComponentPrivate {
43     gchar *name;
44     gchar *description;
45     gchar *version;
46     gchar *license;
47     gchar *author;
48     gchar *homepage;
49     gchar *exec;
50     gchar *textdomain;
51
52     /* engines */
53     GList *engines;
54
55     /* observed paths */
56     GList *observed_paths;
57 };
58
59 #define IBUS_COMPONENT_GET_PRIVATE(o)  \
60    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_COMPONENT, IBusComponentPrivate))
61
62 // static guint            _signals[LAST_SIGNAL] = { 0 };
63
64 /* functions prototype */
65 static void         ibus_component_set_property (IBusComponent          *component,
66                                                  guint                   prop_id,
67                                                  const GValue           *value,
68                                                  GParamSpec             *pspec);
69 static void         ibus_component_get_property (IBusComponent          *component,
70                                                  guint                   prop_id,
71                                                  GValue                 *value,
72                                                  GParamSpec             *pspec);
73 static void         ibus_component_destroy      (IBusComponent          *component);
74 static gboolean     ibus_component_serialize    (IBusComponent          *component,
75                                                  GVariantBuilder        *builder);
76 static gint         ibus_component_deserialize  (IBusComponent          *component,
77                                                  GVariant               *variant);
78 static gboolean     ibus_component_copy         (IBusComponent          *dest,
79                                                  const IBusComponent    *src);
80 static gboolean     ibus_component_parse_xml_node
81                                                 (IBusComponent          *component,
82                                                  XMLNode                *node,
83                                                  gboolean                access_fs);
84
85 static void         ibus_component_parse_engines(IBusComponent          *component,
86                                                  XMLNode                *node);
87 static void         ibus_component_parse_observed_paths
88                                                 (IBusComponent          *component,
89                                                  XMLNode                *node,
90                                                  gboolean                access_fs);
91
92 G_DEFINE_TYPE (IBusComponent, ibus_component, IBUS_TYPE_SERIALIZABLE)
93
94 static void
95 ibus_component_class_init (IBusComponentClass *class)
96 {
97     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
98     IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
99     IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class);
100
101     g_type_class_add_private (class, sizeof (IBusComponentPrivate));
102
103     gobject_class->set_property = (GObjectSetPropertyFunc) ibus_component_set_property;
104     gobject_class->get_property = (GObjectGetPropertyFunc) ibus_component_get_property;
105     object_class->destroy = (IBusObjectDestroyFunc) ibus_component_destroy;
106
107     serializable_class->serialize   = (IBusSerializableSerializeFunc) ibus_component_serialize;
108     serializable_class->deserialize = (IBusSerializableDeserializeFunc) ibus_component_deserialize;
109     serializable_class->copy        = (IBusSerializableCopyFunc) ibus_component_copy;
110
111     /* install properties */
112     /**
113      * IBusComponent:name:
114      *
115      * The name of component
116      */
117     g_object_class_install_property (gobject_class,
118                     PROP_NAME,
119                     g_param_spec_string ("name",
120                         "component name",
121                         "The name of component",
122                         NULL,
123                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
124
125     /**
126      * IBusComponent:description:
127      *
128      * The description of component
129      */
130     g_object_class_install_property (gobject_class,
131                     PROP_DESCRIPTION,
132                     g_param_spec_string ("description",
133                         "component description",
134                         "The description of component",
135                         NULL,
136                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
137
138     /**
139      * IBusComponent:version:
140      *
141      * The version of component
142      */
143     g_object_class_install_property (gobject_class,
144                     PROP_VERSION,
145                     g_param_spec_string ("version",
146                         "component version",
147                         "The version of component",
148                         NULL,
149                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
150
151     /**
152      * IBusComponent:license:
153      *
154      * The license of component
155      */
156     g_object_class_install_property (gobject_class,
157                     PROP_LICENSE,
158                     g_param_spec_string ("license",
159                         "component license",
160                         "The license of component",
161                         NULL,
162                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
163
164     /**
165      * IBusComponent:author:
166      *
167      * The author of component
168      */
169     g_object_class_install_property (gobject_class,
170                     PROP_AUTHOR,
171                     g_param_spec_string ("author",
172                         "component author",
173                         "The author of component",
174                         NULL,
175                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
176
177     /**
178      * IBusComponent:homepage:
179      *
180      * The homepage of component
181      */
182     g_object_class_install_property (gobject_class,
183                     PROP_HOMEPAGE,
184                     g_param_spec_string ("homepage",
185                         "component homepage",
186                         "The homepage of component",
187                         NULL,
188                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
189
190     /**
191      * IBusComponent:command-line:
192      *
193      * The exec path of component
194      */
195     g_object_class_install_property (gobject_class,
196                     PROP_COMMAND_LINE,
197                     g_param_spec_string ("command-line",
198                         "component command-line",
199                         "The command line of component",
200                         NULL,
201                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
202
203     /**
204      * IBusComponent:textdomain:
205      *
206      * The textdomain of component
207      */
208     g_object_class_install_property (gobject_class,
209                     PROP_TEXTDOMAIN,
210                     g_param_spec_string ("textdomain",
211                         "component textdomain",
212                         "The textdomain path of component",
213                         NULL,
214                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
215 }
216
217
218 static void
219 ibus_component_init (IBusComponent *component)
220 {
221     component->priv = IBUS_COMPONENT_GET_PRIVATE (component);
222 }
223
224 static void
225 ibus_component_destroy (IBusComponent *component)
226 {
227     GList *p;
228
229     g_free (component->priv->name);
230     g_free (component->priv->description);
231     g_free (component->priv->version);
232     g_free (component->priv->license);
233     g_free (component->priv->author);
234     g_free (component->priv->homepage);
235     g_free (component->priv->exec);
236     g_free (component->priv->textdomain);
237
238     component->priv->name = NULL;
239     component->priv->description = NULL;
240     component->priv->version = NULL;
241     component->priv->license = NULL;
242     component->priv->author = NULL;
243     component->priv->homepage = NULL;
244     component->priv->exec = NULL;
245     component->priv->textdomain = NULL;
246
247     g_list_free_full (component->priv->observed_paths, g_object_unref);
248     component->priv->observed_paths = NULL;
249
250     for (p = component->priv->engines; p != NULL; p = p->next) {
251         g_object_steal_data ((GObject *)p->data, "component");
252         ibus_object_destroy ((IBusObject *)p->data);
253         g_object_unref (p->data);
254     }
255     g_list_free (component->priv->engines);
256     component->priv->engines = NULL;
257
258     IBUS_OBJECT_CLASS (ibus_component_parent_class)->destroy (IBUS_OBJECT (component));
259 }
260
261 static void
262 ibus_component_set_property (IBusComponent *component,
263                              guint          prop_id,
264                              const GValue  *value,
265                              GParamSpec    *pspec)
266 {
267     switch (prop_id) {
268     case PROP_NAME:
269         g_assert (component->priv->name == NULL);
270         component->priv->name = g_value_dup_string (value);
271         break;
272     case PROP_DESCRIPTION:
273         g_assert (component->priv->description == NULL);
274         component->priv->description = g_value_dup_string (value);
275         break;
276     case PROP_VERSION:
277         g_assert (component->priv->version == NULL);
278         component->priv->version = g_value_dup_string (value);
279         break;
280     case PROP_LICENSE:
281         g_assert (component->priv->license == NULL);
282         component->priv->license = g_value_dup_string (value);
283         break;
284     case PROP_AUTHOR:
285         g_assert (component->priv->author == NULL);
286         component->priv->author = g_value_dup_string (value);
287         break;
288     case PROP_HOMEPAGE:
289         g_assert (component->priv->homepage == NULL);
290         component->priv->homepage = g_value_dup_string (value);
291         break;
292     case PROP_COMMAND_LINE:
293         g_assert (component->priv->exec == NULL);
294         component->priv->exec = g_value_dup_string (value);
295         break;
296     case PROP_TEXTDOMAIN:
297         g_assert (component->priv->textdomain == NULL);
298         component->priv->textdomain = g_value_dup_string (value);
299         break;
300     default:
301         G_OBJECT_WARN_INVALID_PROPERTY_ID (component, prop_id, pspec);
302     }
303 }
304
305 static void
306 ibus_component_get_property (IBusComponent *component,
307                              guint          prop_id,
308                              GValue        *value,
309                              GParamSpec    *pspec)
310 {
311     switch (prop_id) {
312     case PROP_NAME:
313         g_value_set_string (value, ibus_component_get_name (component));
314         break;
315     case PROP_DESCRIPTION:
316         g_value_set_string (value, ibus_component_get_description (component));
317         break;
318     case PROP_VERSION:
319         g_value_set_string (value, ibus_component_get_version (component));
320         break;
321     case PROP_LICENSE:
322         g_value_set_string (value, ibus_component_get_license (component));
323         break;
324     case PROP_AUTHOR:
325         g_value_set_string (value, ibus_component_get_author (component));
326         break;
327     case PROP_HOMEPAGE:
328         g_value_set_string (value, ibus_component_get_homepage (component));
329         break;
330     case PROP_COMMAND_LINE:
331         g_value_set_string (value, ibus_component_get_exec (component));
332         break;
333     case PROP_TEXTDOMAIN:
334         g_value_set_string (value, ibus_component_get_textdomain (component));
335         break;
336     default:
337         G_OBJECT_WARN_INVALID_PROPERTY_ID (component, prop_id, pspec);
338     }
339 }
340
341 static gboolean
342 ibus_component_serialize (IBusComponent   *component,
343                           GVariantBuilder *builder)
344 {
345     gboolean retval;
346
347     retval = IBUS_SERIALIZABLE_CLASS (ibus_component_parent_class)->serialize ((IBusSerializable *)component, builder);
348     g_return_val_if_fail (retval, FALSE);
349
350     g_variant_builder_add (builder, "s", component->priv->name);
351     g_variant_builder_add (builder, "s", component->priv->description);
352     g_variant_builder_add (builder, "s", component->priv->version);
353     g_variant_builder_add (builder, "s", component->priv->license);
354     g_variant_builder_add (builder, "s", component->priv->author);
355     g_variant_builder_add (builder, "s", component->priv->homepage);
356     g_variant_builder_add (builder, "s", component->priv->exec);
357     g_variant_builder_add (builder, "s", component->priv->textdomain);
358
359     GList *p;
360     GVariantBuilder *array;
361     /* serialize observed paths */
362     array = g_variant_builder_new (G_VARIANT_TYPE ("av"));
363     for (p = component->priv->observed_paths; p != NULL; p = p->next) {
364         g_variant_builder_add (array, "v", ibus_serializable_serialize ((IBusSerializable *)p->data));
365     }
366     g_variant_builder_add (builder, "av", array);
367
368     /* serialize engine desc list */
369     array = g_variant_builder_new (G_VARIANT_TYPE ("av"));
370     for (p = component->priv->engines; p != NULL; p = p->next) {
371         g_variant_builder_add (array, "v", ibus_serializable_serialize ((IBusSerializable *)p->data));
372     }
373     g_variant_builder_add (builder, "av", array);
374
375     return TRUE;
376 }
377
378 static gint
379 ibus_component_deserialize (IBusComponent   *component,
380                             GVariant        *variant)
381 {
382     gboolean retval;
383
384     retval = IBUS_SERIALIZABLE_CLASS (ibus_component_parent_class)->deserialize ((IBusSerializable *)component, variant);
385     g_return_val_if_fail (retval, 0);
386
387     g_variant_get_child (variant, retval++, "s", &component->priv->name);
388     g_variant_get_child (variant, retval++, "s", &component->priv->description);
389     g_variant_get_child (variant, retval++, "s", &component->priv->version);
390     g_variant_get_child (variant, retval++, "s", &component->priv->license);
391     g_variant_get_child (variant, retval++, "s", &component->priv->author);
392     g_variant_get_child (variant, retval++, "s", &component->priv->homepage);
393     g_variant_get_child (variant, retval++, "s", &component->priv->exec);
394     g_variant_get_child (variant, retval++, "s", &component->priv->textdomain);
395
396     GVariant *var;
397     GVariantIter *iter = NULL;
398     g_variant_get_child (variant, retval++, "av", &iter);
399     while (g_variant_iter_loop (iter, "v", &var)) {
400         component->priv->observed_paths = g_list_append (component->priv->observed_paths,
401                         IBUS_OBSERVED_PATH (ibus_serializable_deserialize (var)));
402     }
403     g_variant_iter_free (iter);
404
405     g_variant_get_child (variant, retval++, "av", &iter);
406     while (g_variant_iter_loop (iter, "v", &var)) {
407         ibus_component_add_engine (component,
408                                    IBUS_ENGINE_DESC (ibus_serializable_deserialize (var)));
409     }
410     g_variant_iter_free (iter);
411
412     return retval;
413 }
414
415 static gboolean
416 ibus_component_copy (IBusComponent       *dest,
417                      const IBusComponent *src)
418 {
419     gboolean retval;
420
421     retval = IBUS_SERIALIZABLE_CLASS (ibus_component_parent_class)->copy ((IBusSerializable *)dest,
422                                  (IBusSerializable *)src);
423     g_return_val_if_fail (retval, FALSE);
424
425     dest->priv->name          = g_strdup (src->priv->name);
426     dest->priv->description   = g_strdup (src->priv->description);
427     dest->priv->version       = g_strdup (src->priv->version);
428     dest->priv->license       = g_strdup (src->priv->license);
429     dest->priv->author        = g_strdup (src->priv->author);
430     dest->priv->homepage      = g_strdup (src->priv->homepage);
431     dest->priv->exec          = g_strdup (src->priv->exec);
432     dest->priv->textdomain    = g_strdup (src->priv->textdomain);
433
434     dest->priv->observed_paths = g_list_copy (src->priv->observed_paths);
435     g_list_foreach (dest->priv->observed_paths, (GFunc) g_object_ref, NULL);
436
437     dest->priv->engines = g_list_copy (src->priv->engines);
438     g_list_foreach (dest->priv->engines, (GFunc) g_object_ref, NULL);
439
440     return TRUE;
441 }
442
443
444 #define g_string_append_indent(string, indent)  \
445     {                                           \
446         gint i;                                 \
447         for (i = 0; i < (indent); i++) {        \
448             g_string_append (string, "    ");   \
449         }                                       \
450     }
451
452 void
453 ibus_component_output (IBusComponent *component,
454                       GString      *output,
455                       gint          indent)
456 {
457     g_assert (IBUS_IS_COMPONENT (component));
458     GList *p;
459
460     g_string_append_indent (output, indent);
461     g_string_append (output, "<component>\n");
462
463 #define OUTPUT_ENTRY(field, element)                                        \
464     {                                                                       \
465         gchar *escape_text =                                                \
466             g_markup_escape_text (component->priv->field ?                  \
467                                   component->priv->field : "", -1);         \
468         g_string_append_indent (output, indent + 1);                        \
469         g_string_append_printf (output, "<"element">%s</"element">\n",      \
470                                 escape_text);                               \
471         g_free (escape_text);                                               \
472     }
473 #define OUTPUT_ENTRY_1(name) OUTPUT_ENTRY(name, #name)
474     OUTPUT_ENTRY_1 (name);
475     OUTPUT_ENTRY_1 (description);
476     OUTPUT_ENTRY_1 (version);
477     OUTPUT_ENTRY_1 (license);
478     OUTPUT_ENTRY_1 (author);
479     OUTPUT_ENTRY_1 (homepage);
480     OUTPUT_ENTRY_1 (exec);
481     OUTPUT_ENTRY_1 (textdomain);
482 #undef OUTPUT_ENTRY
483 #undef OUTPUT_ENTRY_1
484
485     if (component->priv->observed_paths) {
486         g_string_append_indent (output, indent + 1);
487         g_string_append (output, "<observed-paths>\n");
488
489         for (p = component->priv->observed_paths; p != NULL; p = p->next ) {
490             IBusObservedPath *path = (IBusObservedPath *) p->data;
491
492             g_string_append_indent (output, indent + 2);
493             g_string_append_printf (output, "<path mtime=\"%ld\" >%s</path>\n",
494                                     path->mtime,
495                                     path->path);
496         }
497
498         g_string_append_indent (output, indent + 1);
499         g_string_append (output, "</observed-paths>\n");
500     }
501
502     ibus_component_output_engines (component, output, indent + 1);
503
504     g_string_append_indent (output, indent);
505     g_string_append (output, "</component>\n");
506 }
507
508 void
509 ibus_component_output_engines (IBusComponent  *component,
510                                GString        *output,
511                                gint            indent)
512 {
513     g_assert (IBUS_IS_COMPONENT (component));
514     g_assert (output);
515
516     GList *p;
517
518     g_string_append_indent (output, indent);
519     g_string_append (output, "<engines>\n");
520
521     for (p = component->priv->engines; p != NULL; p = p->next) {
522         ibus_engine_desc_output ((IBusEngineDesc *)p->data, output, indent + 2);
523     }
524
525     g_string_append_indent (output, indent);
526     g_string_append (output, "</engines>\n");
527 }
528
529 static gboolean
530 ibus_component_parse_xml_node (IBusComponent   *component,
531                               XMLNode          *node,
532                               gboolean          access_fs)
533 {
534     g_assert (component);
535     g_assert (node);
536
537     if (G_UNLIKELY (g_strcmp0 (node->name, "component") != 0)) {
538         return FALSE;
539     }
540
541     GList *p;
542     for (p = node->sub_nodes; p != NULL; p = p->next) {
543         XMLNode *sub_node = (XMLNode *)p->data;
544
545 #define PARSE_ENTRY(field_name, element_name)                           \
546         if (g_strcmp0 (sub_node->name, element_name) == 0) {            \
547             if (component->priv->field_name != NULL) {                  \
548                 g_free (component->priv->field_name);                   \
549             }                                                           \
550             component->priv->field_name = g_strdup (sub_node->text);    \
551             continue;                                                   \
552         }
553 #define PARSE_ENTRY_1(name) PARSE_ENTRY (name, #name)
554         PARSE_ENTRY_1 (name);
555         PARSE_ENTRY_1 (description);
556         PARSE_ENTRY_1 (version);
557         PARSE_ENTRY_1 (license);
558         PARSE_ENTRY_1 (author);
559         PARSE_ENTRY_1 (homepage);
560         PARSE_ENTRY_1 (exec);
561         PARSE_ENTRY_1 (textdomain);
562 #undef PARSE_ENTRY
563 #undef PARSE_ENTRY_1
564
565         if (g_strcmp0 (sub_node->name, "engines") == 0) {
566             ibus_component_parse_engines (component, sub_node);
567             continue;
568         }
569
570         if (g_strcmp0 (sub_node->name, "observed-paths") == 0) {
571             ibus_component_parse_observed_paths (component, sub_node, access_fs);
572             continue;
573         }
574
575         g_warning ("<component> element contains invalidate element <%s>", sub_node->name);
576     }
577
578     return TRUE;
579 }
580
581
582 static void
583 ibus_component_parse_engines (IBusComponent *component,
584                               XMLNode       *node)
585 {
586     g_assert (IBUS_IS_COMPONENT (component));
587     g_assert (node);
588
589     gchar *exec = NULL;
590     gchar **p;
591     XMLNode *engines_node = NULL;
592
593     if (g_strcmp0 (node->name, "engines") != 0) {
594         return;
595     }
596
597     for (p = node->attributes; *p != NULL; p += 2) {
598         if (g_strcmp0 (*p, "exec") == 0) {
599             exec = *(p + 1);
600             break;
601         }
602     }
603
604     if (exec != NULL) {
605         gchar *output = NULL;
606         if (g_spawn_command_line_sync (exec, &output, NULL, NULL, NULL)) {
607             engines_node = ibus_xml_parse_buffer (output);
608             g_free (output);
609
610             if (engines_node) {
611                 if (g_strcmp0 (engines_node->name, "engines") == 0) {
612                     node = engines_node;
613                 }
614             }
615         }
616     }
617
618     GList *pl;
619     for (pl = node->sub_nodes; pl != NULL; pl = pl->next) {
620         IBusEngineDesc *engine;
621         engine = ibus_engine_desc_new_from_xml_node ((XMLNode *)pl->data);
622
623         if (G_UNLIKELY (engine == NULL))
624             continue;
625         ibus_component_add_engine (component, engine);
626     }
627
628     if (engines_node) {
629         ibus_xml_free (engines_node);
630     }
631 }
632
633 static void
634 ibus_component_parse_observed_paths (IBusComponent *component,
635                                      XMLNode       *node,
636                                      gboolean       access_fs)
637 {
638     g_assert (IBUS_IS_COMPONENT (component));
639     g_assert (node);
640
641     if (g_strcmp0 (node->name, "observed-paths") != 0) {
642         return;
643     }
644
645     GList *p;
646     for (p = node->sub_nodes; p != NULL; p = p->next) {
647         IBusObservedPath *path;
648
649         path = ibus_observed_path_new_from_xml_node ((XMLNode *)p->data, access_fs);
650         g_object_ref_sink (path);
651         component->priv->observed_paths = g_list_append (component->priv->observed_paths, path);
652
653         if (access_fs && path->is_dir && path->is_exist) {
654             component->priv->observed_paths =
655                     g_list_concat (component->priv->observed_paths,
656                                    ibus_observed_path_traverse (path, TRUE));
657         }
658     }
659 }
660
661 #define IBUS_COMPONENT_GET_PROPERTY(property, return_type)  \
662 return_type                                                 \
663 ibus_component_get_ ## property (IBusComponent *component)  \
664 {                                                           \
665     return component->priv->property;                       \
666 }
667
668 IBUS_COMPONENT_GET_PROPERTY (name, const gchar *)
669 IBUS_COMPONENT_GET_PROPERTY (description, const gchar *)
670 IBUS_COMPONENT_GET_PROPERTY (version, const gchar *)
671 IBUS_COMPONENT_GET_PROPERTY (license, const gchar *)
672 IBUS_COMPONENT_GET_PROPERTY (author, const gchar *)
673 IBUS_COMPONENT_GET_PROPERTY (homepage, const gchar *)
674 IBUS_COMPONENT_GET_PROPERTY (exec, const gchar *)
675 IBUS_COMPONENT_GET_PROPERTY (textdomain, const gchar *)
676 #undef IBUS_COMPONENT_GET_PROPERTY
677
678 IBusComponent *
679 ibus_component_new (const gchar *name,
680                     const gchar *description,
681                     const gchar *version,
682                     const gchar *license,
683                     const gchar *author,
684                     const gchar *homepage,
685                     const gchar *command_line,
686                     const gchar *textdomain)
687 {
688     return ibus_component_new_varargs ("name", name,
689                                        "description", description,
690                                        "version", version,
691                                        "license", license,
692                                        "author", author,
693                                        "homepage", homepage,
694                                        "command-line", command_line,
695                                        "textdomain", textdomain,
696                                        NULL);
697 }
698
699
700 IBusComponent *
701 ibus_component_new_varargs (const gchar *first_property_name, ...)
702 {
703     va_list var_args;
704     IBusComponent *component;
705     IBusComponentPrivate *priv;
706
707     g_assert (first_property_name);
708
709     va_start (var_args, first_property_name);
710     component = (IBusComponent *) g_object_new_valist (IBUS_TYPE_COMPONENT,
711                                                        first_property_name,
712                                                        var_args);
713     va_end (var_args);
714
715     priv = IBUS_COMPONENT_GET_PRIVATE (component);
716
717     /* name is required. Other properties are set in class_init by default. */
718     g_assert (priv->name);
719
720     return component;
721 }
722
723
724 IBusComponent *
725 ibus_component_new_from_xml_node (XMLNode  *node)
726 {
727     g_assert (node);
728
729     IBusComponent *component;
730
731     component = (IBusComponent *)g_object_new (IBUS_TYPE_COMPONENT, NULL);
732     if (!ibus_component_parse_xml_node (component, node, FALSE)) {
733         g_object_unref (component);
734         component = NULL;
735     }
736
737     return component;
738 }
739
740 IBusComponent *
741 ibus_component_new_from_file (const gchar *filename)
742 {
743     g_assert (filename);
744
745     XMLNode *node;
746     struct stat buf;
747     IBusComponent *component;
748     gboolean retval;
749
750     if (g_stat (filename, &buf) != 0) {
751         g_warning ("Can not get stat of file %s", filename);
752         return NULL;
753     }
754
755     node = ibus_xml_parse_file (filename);
756
757     if (!node) {
758         return NULL;
759     }
760
761     component = (IBusComponent *)g_object_new (IBUS_TYPE_COMPONENT, NULL);
762     retval = ibus_component_parse_xml_node (component, node, TRUE);
763     ibus_xml_free (node);
764
765     if (!retval) {
766         g_object_unref (component);
767         component = NULL;
768     }
769     else {
770         IBusObservedPath *path;
771         path = ibus_observed_path_new (filename, TRUE);
772         component->priv->observed_paths =
773                 g_list_prepend(component->priv->observed_paths, path);
774     }
775
776     return component;
777 }
778
779 void
780 ibus_component_add_observed_path (IBusComponent *component,
781                                   const gchar   *path,
782                                   gboolean       access_fs)
783 {
784     IBusObservedPath *p;
785
786     p = ibus_observed_path_new (path, access_fs);
787     g_object_ref_sink (p);
788     component->priv->observed_paths =
789             g_list_append (component->priv->observed_paths, p);
790
791     if (access_fs && p->is_dir && p->is_exist) {
792         component->priv->observed_paths =
793                 g_list_concat (component->priv->observed_paths,
794                                ibus_observed_path_traverse (p, TRUE));
795     }
796 }
797
798 void
799 ibus_component_add_engine (IBusComponent  *component,
800                            IBusEngineDesc *engine)
801 {
802     g_assert (IBUS_IS_COMPONENT (component));
803     g_assert (IBUS_IS_ENGINE_DESC (engine));
804
805     g_object_ref_sink (engine);
806     component->priv->engines =
807             g_list_append (component->priv->engines, engine);
808 }
809
810 GList *
811 ibus_component_get_engines (IBusComponent *component)
812 {
813     return g_list_copy (component->priv->engines);
814 }
815
816 gboolean
817 ibus_component_check_modification (IBusComponent *component)
818 {
819     g_assert (IBUS_IS_COMPONENT (component));
820
821     GList *p;
822
823     for (p = component->priv->observed_paths; p != NULL; p = p->next) {
824         if (ibus_observed_path_check_modification ((IBusObservedPath *)p->data))
825             return TRUE;
826     }
827     return FALSE;
828 }
829
830 GList *
831 ibus_component_get_observed_paths (IBusComponent *component)
832 {
833     g_assert (IBUS_IS_COMPONENT (component));
834     return g_list_copy (component->priv->observed_paths);
835 }