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