Load the system registry cache prior to the user one.
authorfujiwarat <takao.fujiwara1@gmail.com>
Wed, 10 Jul 2013 07:55:19 +0000 (16:55 +0900)
committerfujiwarat <takao.fujiwara1@gmail.com>
Wed, 10 Jul 2013 07:55:19 +0000 (16:55 +0900)
gnome-settings-daemon runs ibus-daemon after the user configures
any input method engines and causes a delay to show the engines
on UI because no cache exists for ibus-daemon.
The system cache can avoid the user timing.

Review URL: https://codereview.appspot.com/10364043

19 files changed:
bus/Makefile.am
bus/dbusimpl.c
bus/ibus-daemon.1.in
bus/ibusimpl.c
bus/ibusimpl.h
bus/main.c
bus/registry.c [deleted file]
bus/registry.h [deleted file]
bus/test-registry.c [deleted file]
docs/reference/ibus/ibus-docs.sgml.in
docs/reference/ibus/ibus.types
src/Makefile.am
src/ibus.h
src/ibusregistry.c [new file with mode: 0644]
src/ibusregistry.h [new file with mode: 0644]
src/tests/Makefile.am
src/tests/ibus-registry.c [new file with mode: 0644]
tools/ibus.1.in
tools/main.vala

index 826c673..2e06386 100644 (file)
@@ -70,8 +70,6 @@ commonsrc = \
        connection.h \
        matchrule.c \
        matchrule.h \
-       registry.c \
-       registry.h \
        marshalers.c \
        marshalers.h \
        types.h \
@@ -111,24 +109,12 @@ marshalers.c: marshalers.h marshalers.list
 if ENABLE_TESTS
 TESTS = \
        test-matchrule \
-       test-registry \
        test-stress     \
        $(NULL)
 endif
 
 noinst_PROGRAMS = $(TESTS)
 
-test_registry_SOURCES = \
-       $(commonsrc) \
-       test-registry.c \
-       $(NULL)
-test_registry_CFLAGS = \
-       $(AM_CFLAGS) \
-       $(NULL)
-test_registry_LDADD = \
-       $(AM_LDADD) \
-       $(NULL)
-
 test_matchrule_DEPENDENCIES = \
        $(libibus) \
        $(NULL)
index 4a4781a..ad69c8e 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -28,7 +28,6 @@
 #include "ibusimpl.h"
 #include "marshalers.h"
 #include "matchrule.h"
-#include "registry.h"
 #include "types.h"
 
 enum {
@@ -1189,9 +1188,8 @@ bus_dbus_impl_start_service_by_name (BusDBusImpl           *dbus,
         return;
     }
 
-    BusRegistry *registry = BUS_DEFAULT_REGISTRY;
-    BusComponent *component = bus_registry_lookup_component_by_name (registry,
-                                                                     name);
+    BusComponent *component = bus_ibus_impl_lookup_component_by_name (
+            BUS_DEFAULT_IBUS, name);
 
     if (component == NULL || !bus_component_start (component, g_verbose)) {
         g_dbus_method_invocation_return_error (invocation,
index 74e7431..fe06e2b 100644 (file)
@@ -55,8 +55,9 @@ specify the address of ibus daemon.
 \fB\-r\fR, \fB\-\-replace\fR
 if there is an old ibus\-daemon is running, it will be replaced.
 .TP
-\fB\-t\fR, \fB\-\-re\-scan\fR
+\fB\-t\fR, \fB\-\-cache\fR=\fImode\fR [default is auto]
 force to re\-scan components, and re\-create registry cache.
+auto, refresh, none is available.
 .TP
 \fB\-o\fR, \fB\-\-timeout\fR=\fItimeout\fR [default is 2000]
 dbus reply timeout in milliseconds.
index 3fca02a..2cd293d 100644 (file)
@@ -35,7 +35,6 @@
 #include "global.h"
 #include "inputcontext.h"
 #include "panelproxy.h"
-#include "registry.h"
 #include "server.h"
 #include "types.h"
 
@@ -62,7 +61,15 @@ struct _BusIBusImpl {
 
     gboolean embed_preedit_text;
 
-    BusRegistry     *registry;
+    IBusRegistry    *registry;
+
+    /* a list of BusComponent objects that are created from component XML
+     * files (or from the cache of them). */
+    GList *components;
+
+    /* a mapping from an engine name (e.g. 'pinyin') to the corresponding
+     * IBusEngineDesc object. */
+    GHashTable *engine_table;
 
     BusInputContext *focused_context;
     BusPanelProxy   *panel;
@@ -95,8 +102,8 @@ static guint            _signals[LAST_SIGNAL] = { 0 };
 */
 
 /* functions prototype */
-static void      bus_ibus_impl_destroy  (BusIBusImpl        *ibus);
-static void      bus_ibus_impl_service_method_call
+static void     bus_ibus_impl_destroy   (BusIBusImpl        *ibus);
+static void     bus_ibus_impl_service_method_call
                                         (IBusService        *service,
                                          GDBusConnection    *connection,
                                          const gchar        *sender,
@@ -125,8 +132,17 @@ static gboolean
                                          const gchar        *property_name,
                                          GVariant           *value,
                                          GError            **error);
+static void     bus_ibus_impl_registry_init
+                                        (BusIBusImpl        *ibus);
 static void     bus_ibus_impl_registry_changed
                                         (BusIBusImpl        *ibus);
+static void     bus_ibus_impl_registry_destroy
+                                        (BusIBusImpl        *ibus);
+static void     bus_ibus_impl_component_name_owner_changed
+                                        (BusIBusImpl        *ibus,
+                                         const gchar        *name,
+                                         const gchar        *old_name,
+                                         const gchar        *new_name);
 static void     bus_ibus_impl_global_engine_changed
                                         (BusIBusImpl        *ibus);
 static void     bus_ibus_impl_set_context_engine_from_desc
@@ -277,8 +293,8 @@ _panel_destroy_cb (BusPanelProxy *panel,
 }
 
 static void
-_registry_changed_cb (BusRegistry *registry,
-                      BusIBusImpl *ibus)
+_registry_changed_cb (IBusRegistry *registry,
+                      BusIBusImpl  *ibus)
 {
     bus_ibus_impl_registry_changed (ibus);
 }
@@ -348,7 +364,7 @@ _dbus_name_owner_changed_cb (BusDBusImpl   *dbus,
         }
     }
 
-    bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name);
+    bus_ibus_impl_component_name_owner_changed (ibus, name, old_name, new_name);
 }
 
 /**
@@ -383,13 +399,6 @@ bus_ibus_impl_init (BusIBusImpl *ibus)
     ibus->contexts = NULL;
     ibus->focused_context = NULL;
     ibus->panel = NULL;
-    ibus->registry = bus_registry_new ();
-
-    g_signal_connect (ibus->registry,
-                      "changed",
-                      G_CALLBACK (_registry_changed_cb),
-                      ibus);
-    bus_registry_start_monitor_changes (ibus->registry);
 
     ibus->keymap = ibus_keymap_get ("us");
 
@@ -407,6 +416,8 @@ bus_ibus_impl_init (BusIBusImpl *ibus)
                       "name-owner-changed",
                       G_CALLBACK (_dbus_name_owner_changed_cb),
                       ibus);
+
+    bus_ibus_impl_registry_init (ibus);
 }
 
 /**
@@ -422,7 +433,7 @@ bus_ibus_impl_destroy (BusIBusImpl *ibus)
     gint status;
     gboolean flag;
 
-    bus_registry_stop_all_components (ibus->registry);
+    g_list_foreach (ibus->components, (GFunc) bus_component_stop, NULL);
 
     pid = 0;
     timeout = 0;
@@ -477,6 +488,8 @@ bus_ibus_impl_destroy (BusIBusImpl *ibus)
         ibus->fake_context = NULL;
     }
 
+    bus_ibus_impl_registry_destroy (ibus);
+
     IBUS_OBJECT_CLASS (bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus));
 }
 
@@ -565,7 +578,8 @@ bus_ibus_impl_get_engine_desc (BusIBusImpl *ibus,
 
     IBusEngineDesc *desc = _find_engine_desc_by_name (ibus, engine_name);
     if (desc == NULL) {
-        desc = bus_registry_find_engine_by_name (ibus->registry, engine_name);
+        desc = (IBusEngineDesc *) g_hash_table_lookup (ibus->engine_table,
+                                                       engine_name);
     }
     return desc;
 }
@@ -1062,7 +1076,7 @@ _ibus_get_engines (BusIBusImpl     *ibus,
 
     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
 
-    engines = bus_registry_get_engines (ibus->registry);
+    engines = g_hash_table_get_values (ibus->engine_table);
 
     for (p = engines; p != NULL; p = p->next) {
         g_variant_builder_add (
@@ -1112,8 +1126,8 @@ _ibus_get_engines_by_names (BusIBusImpl           *ibus,
     GVariantBuilder builder;
     g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
     while (names[i] != NULL) {
-        IBusEngineDesc *desc = bus_registry_find_engine_by_name (
-                ibus->registry, names[i++]);
+        IBusEngineDesc *desc = (IBusEngineDesc *) g_hash_table_lookup (
+                ibus->engine_table, names[i++]);
         if (desc == NULL)
             continue;
         g_variant_builder_add (
@@ -1859,13 +1873,177 @@ bus_ibus_impl_get_keymap (BusIBusImpl *ibus)
     return ibus->keymap;
 }
 
-BusRegistry *
-bus_ibus_impl_get_registry (BusIBusImpl *ibus)
+/**
+ * bus_ibus_impl_registry_init:
+ *
+ * Initialize IBusRegistry.
+ */
+static void
+bus_ibus_impl_registry_init (BusIBusImpl *ibus)
+{
+    GList *p;
+    GList *components;
+    IBusRegistry *registry = ibus_registry_new ();
+
+    ibus->registry = NULL;
+    ibus->components = NULL;
+    ibus->engine_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+    if (g_strcmp0 (g_cache, "none") == 0) {
+        /* Only load registry, but not read and write cache. */
+        ibus_registry_load (registry);
+    }
+    else if (g_strcmp0 (g_cache, "refresh") == 0) {
+        /* Load registry and overwrite the cache. */
+        ibus_registry_load (registry);
+        ibus_registry_save_cache (registry, TRUE);
+    }
+    else if (g_strcmp0 (g_cache, "auto") == 0) {
+        /* Load registry from cache. If the cache does not exist or
+         * it is outdated, then generate it.
+         */
+        if (ibus_registry_load_cache (registry, FALSE) == FALSE ||
+            ibus_registry_check_modification (registry)) {
+
+            ibus_object_destroy (IBUS_OBJECT (registry));
+            registry = ibus_registry_new ();
+
+            if (ibus_registry_load_cache (registry, TRUE) == FALSE ||
+                ibus_registry_check_modification (registry)) {
+
+                ibus_object_destroy (IBUS_OBJECT (registry));
+                registry = ibus_registry_new ();
+                ibus_registry_load (registry);
+                ibus_registry_save_cache (registry, TRUE);
+            }
+        }
+    }
+
+    ibus->registry = registry;
+    components = ibus_registry_get_components (registry);
+
+    for (p = components; p != NULL; p = p->next) {
+        IBusComponent *component = (IBusComponent *) p->data;
+        BusComponent *buscomp = bus_component_new (component,
+                                                   NULL /* factory */);
+        GList *engines = NULL;
+        GList *p1;
+
+        g_object_ref_sink (buscomp);
+        ibus->components = g_list_append (ibus->components, buscomp);
+
+        engines = bus_component_get_engines (buscomp);
+        for (p1 = engines; p1 != NULL; p1 = p1->next) {
+            IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
+            const gchar *name = ibus_engine_desc_get_name (desc);
+            if (g_hash_table_lookup (ibus->engine_table, name) == NULL) {
+                g_hash_table_insert (ibus->engine_table,
+                                     (gpointer) name,
+                                     desc);
+            } else {
+                g_message ("Engine %s is already registered by other component",
+                           name);
+            }
+        }
+        g_list_free (engines);
+    }
+
+    g_list_free (components);
+
+    g_signal_connect (ibus->registry,
+                      "changed",
+                      G_CALLBACK (_registry_changed_cb),
+                      ibus);
+    ibus_registry_start_monitor_changes (ibus->registry);
+}
+
+static void
+bus_ibus_impl_registry_destroy (BusIBusImpl *ibus)
 {
+    g_list_free_full (ibus->components, g_object_unref);
+    ibus->components = NULL;
+
+    g_hash_table_destroy (ibus->engine_table);
+    ibus->engine_table = NULL;
+
+    ibus_object_destroy (IBUS_OBJECT (ibus->registry));
+    ibus->registry = NULL;
+}
+
+static gint
+_component_is_name_cb (BusComponent *component,
+                       const gchar  *name)
+{
+    g_assert (BUS_IS_COMPONENT (component));
+    g_assert (name);
+
+    return g_strcmp0 (bus_component_get_name (component), name);
+}
+
+static void
+bus_ibus_impl_component_name_owner_changed (BusIBusImpl *ibus,
+                                            const gchar *name,
+                                            const gchar *old_name,
+                                            const gchar *new_name)
+{
+    BusComponent *component;
+    BusFactoryProxy *factory;
 
     g_assert (BUS_IS_IBUS_IMPL (ibus));
+    g_assert (name);
+    g_assert (old_name);
+    g_assert (new_name);
+
+    component = bus_ibus_impl_lookup_component_by_name (ibus, name);
 
-    return ibus->registry;
+    if (component == NULL) {
+        /* name is a unique name, or a well-known name we don't know. */
+        return;
+    }
+
+    if (g_strcmp0 (old_name, "") != 0) {
+        /* the component is stopped. */
+        factory = bus_component_get_factory (component);
+
+        if (factory != NULL) {
+            ibus_proxy_destroy ((IBusProxy *) factory);
+        }
+    }
+
+    if (g_strcmp0 (new_name, "") != 0) {
+        /* the component is started. */
+        BusConnection *connection =
+                bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS,
+                                                      new_name);
+        if (connection == NULL)
+            return;
+
+        factory = bus_factory_proxy_new (connection);
+        if (factory == NULL)
+            return;
+        bus_component_set_factory (component, factory);
+        g_object_unref (factory);
+    }
+}
+
+BusComponent *
+bus_ibus_impl_lookup_component_by_name (BusIBusImpl *ibus,
+                                        const gchar *name)
+{
+    GList *p;
+
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
+    g_assert (name);
+
+    p = g_list_find_custom (ibus->components,
+                            name,
+                            (GCompareFunc) _component_is_name_cb);
+    if (p) {
+        return (BusComponent *) p->data;
+    }
+    else {
+        return NULL;
+    }
 }
 
 /**
index ade022b..4263778 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* bus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,8 +24,8 @@
 
 #include <ibus.h>
 #include "connection.h"
+#include "component.h"
 #include "inputcontext.h"
-#include "registry.h"
 #include "factoryproxy.h"
 #include "panelproxy.h"
 #include "engineproxy.h"
@@ -52,8 +52,6 @@
     (bus_ibus_impl_get_default ())
 #define BUS_DEFAULT_KEYMAP \
     (bus_ibus_impl_get_keymap (BUS_DEFAULT_IBUS))
-#define BUS_DEFAULT_REGISTRY \
-    (bus_ibus_impl_get_registry (BUS_DEFAULT_IBUS))
 
 G_BEGIN_DECLS
 
@@ -75,7 +73,9 @@ BusIBusImpl     *bus_ibus_impl_get_default          (void);
 BusFactoryProxy *bus_ibus_impl_lookup_factory       (BusIBusImpl        *ibus,
                                                      const gchar        *path);
 IBusKeymap      *bus_ibus_impl_get_keymap           (BusIBusImpl        *ibus);
-BusRegistry     *bus_ibus_impl_get_registry         (BusIBusImpl        *ibus);
+BusComponent    *bus_ibus_impl_lookup_component_by_name
+                                                    (BusIBusImpl        *ibus,
+                                                     const gchar        *name);
 gboolean         bus_ibus_impl_is_use_sys_layout    (BusIBusImpl        *ibus);
 gboolean         bus_ibus_impl_is_embed_preedit_text
                                                     (BusIBusImpl        *ibus);
index 676988f..34ae0c6 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -238,7 +238,8 @@ main (gint argc, gchar **argv)
         /* execute config component */
         if (g_strcmp0 (config, "default") == 0) {
             BusComponent *component;
-            component = bus_registry_lookup_component_by_name (BUS_DEFAULT_REGISTRY, IBUS_SERVICE_CONFIG);
+            component = bus_ibus_impl_lookup_component_by_name (
+                    BUS_DEFAULT_IBUS, IBUS_SERVICE_CONFIG);
             if (component) {
                 bus_component_set_restart (component, restart);
             }
@@ -254,7 +255,8 @@ main (gint argc, gchar **argv)
         /* execute panel component */
         if (g_strcmp0 (panel, "default") == 0) {
             BusComponent *component;
-            component = bus_registry_lookup_component_by_name (BUS_DEFAULT_REGISTRY, IBUS_SERVICE_PANEL);
+            component = bus_ibus_impl_lookup_component_by_name (
+                    BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL);
             if (component) {
                 bus_component_set_restart (component, restart);
             }
diff --git a/bus/registry.c b/bus/registry.c
deleted file mode 100644 (file)
index 9f917e7..0000000
+++ /dev/null
@@ -1,673 +0,0 @@
-/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-/* vim:set et sts=4: */
-/* bus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
- *
- * 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 "registry.h"
-
-#include <gio/gio.h>
-#include <glib/gstdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dbusimpl.h"
-#include "global.h"
-#include "marshalers.h"
-#include "types.h"
-
-enum {
-    CHANGED,
-    LAST_SIGNAL,
-};
-
-static guint             _signals[LAST_SIGNAL] = { 0 };
-
-struct _BusRegistry {
-    IBusObject parent;
-
-    /* instance members */
-
-    /* a list of IBusObservedPath objects. */
-    GList *observed_paths;
-    /* a list of BusComponent objects that are created from component XML files (or from the cache of them). */
-    GList *components;
-    /* a mapping from an engine name (e.g. 'pinyin') to the corresponding IBusEngineDesc object. */
-    GHashTable *engine_table;
-    gboolean changed;
-    /* a mapping from GFile to GFileMonitor. */
-    GHashTable *monitor_table;
-    guint monitor_timeout_id;
-};
-
-struct _BusRegistryClass {
-    IBusObjectClass parent;
-
-    /* class members */
-};
-
-/* functions prototype */
-static void              bus_registry_destroy           (BusRegistry        *registry);
-static void              bus_registry_load              (BusRegistry        *registry);
-static void              bus_registry_load_in_dir       (BusRegistry        *registry,
-                                                         const gchar        *dirname);
-static gboolean          bus_registry_save_cache        (BusRegistry        *registry);
-static gboolean          bus_registry_load_cache        (BusRegistry        *registry);
-static gboolean          bus_registry_check_modification(BusRegistry        *registry);
-static void              bus_registry_remove_all        (BusRegistry        *registry);
-
-G_DEFINE_TYPE (BusRegistry, bus_registry, IBUS_TYPE_OBJECT)
-
-static void
-bus_registry_class_init (BusRegistryClass *class)
-{
-    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
-
-    _signals[CHANGED] =
-        g_signal_new (I_("changed"),
-            G_TYPE_FROM_CLASS (gobject_class),
-            G_SIGNAL_RUN_LAST,
-            0, /* does not associate a method in this class. the "changed" signal would be handled in other classes. */
-            NULL, NULL,
-            bus_marshal_VOID__VOID,
-            G_TYPE_NONE,
-            0);
-
-    ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_registry_destroy;
-}
-
-static void
-bus_registry_init (BusRegistry *registry)
-{
-    GList *p;
-    registry->observed_paths = NULL;
-    registry->components = NULL;
-    registry->engine_table = g_hash_table_new (g_str_hash, g_str_equal);
-    registry->changed = FALSE;
-    registry->monitor_table =
-        g_hash_table_new_full (g_file_hash,
-                               (GEqualFunc) g_file_equal,
-                               (GDestroyNotify) g_object_unref,
-                               (GDestroyNotify) g_object_unref);
-
-    if (g_strcmp0 (g_cache, "none") == 0) {
-        /* Only load registry, but not read and write cache. */
-        bus_registry_load (registry);
-    }
-    else if (g_strcmp0 (g_cache, "refresh") == 0) {
-        /* Load registry and overwrite the cache. */
-        bus_registry_load (registry);
-        bus_registry_save_cache (registry);
-    }
-    else {
-        /* Load registry from cache. If the cache does not exist or
-         * it is outdated, then generate it.
-         */
-        if (bus_registry_load_cache (registry) == FALSE ||
-            bus_registry_check_modification (registry)) {
-            bus_registry_remove_all (registry);
-            bus_registry_load (registry);
-            bus_registry_save_cache (registry);
-        }
-    }
-
-    for (p = registry->components; p != NULL; p = p->next) {
-        BusComponent *comp = (BusComponent *) p->data;
-        GList *engines = bus_component_get_engines (comp);
-        GList *p1;
-        for (p1 = engines; p1 != NULL; p1 = p1->next) {
-            IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
-            const gchar *name = ibus_engine_desc_get_name (desc);
-            if (g_hash_table_lookup (registry->engine_table, name) == NULL) {
-                g_hash_table_insert (registry->engine_table,
-                                     (gpointer) name,
-                                     desc);
-            } else {
-                g_message ("Engine %s is already registered by other component",
-                           name);
-            }
-        }
-        g_list_free (engines);
-    }
-}
-
-static void
-bus_registry_remove_all (BusRegistry *registry)
-{
-    g_list_free_full (registry->observed_paths, g_object_unref);
-    registry->observed_paths = NULL;
-
-    g_list_free_full (registry->components, g_object_unref);
-    registry->components = NULL;
-
-    g_hash_table_remove_all (registry->engine_table);
-    g_hash_table_remove_all (registry->monitor_table);
-}
-
-static void
-bus_registry_destroy (BusRegistry *registry)
-{
-    bus_registry_remove_all (registry);
-
-    g_hash_table_destroy (registry->engine_table);
-    registry->engine_table = NULL;
-
-    g_hash_table_destroy (registry->monitor_table);
-    registry->monitor_table = NULL;
-
-    if (registry->monitor_timeout_id > 0) {
-        g_source_remove (registry->monitor_timeout_id);
-        registry->monitor_timeout_id = 0;
-    }
-
-    IBUS_OBJECT_CLASS (bus_registry_parent_class)->destroy (IBUS_OBJECT (registry));
-}
-
-/**
- * bus_registry_load:
- *
- * Read all XML files in the PKGDATADIR (typically /usr/share/ibus/components/ *.xml) and update the registry object.
- */
-static void
-bus_registry_load (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    const gchar *envstr;
-    GPtrArray *path;
-    gchar **d, **search_path;
-
-    path = g_ptr_array_new();
-
-    envstr = g_getenv ("IBUS_COMPONENT_PATH");
-    if (envstr) {
-        gchar **dirs = g_strsplit (envstr, G_SEARCHPATH_SEPARATOR_S, 0);
-        for (d = dirs; *d != NULL; d++)
-            g_ptr_array_add (path, *d);
-        g_free (dirs);
-    } else {
-        gchar *dirname;
-
-        dirname = g_build_filename (PKGDATADIR, "component", NULL);
-        g_ptr_array_add (path, dirname);
-
-#if 0
-        /* FIXME Should we support install some IME in user dir? */
-        dirname = g_build_filename (g_get_user_data_dir (),
-                                    "ibus", "component",
-                                    NULL);
-        g_ptr_array_add (path, dirname);
-#endif
-    }
-
-    g_ptr_array_add (path, NULL);
-    search_path = (gchar **) g_ptr_array_free (path, FALSE);
-    for (d = search_path; *d != NULL; d++) {
-        IBusObservedPath *observed_path = ibus_observed_path_new (*d, TRUE);
-
-        registry->observed_paths = g_list_append (registry->observed_paths,
-                                                  observed_path);
-
-        bus_registry_load_in_dir (registry, *d);
-    }
-    g_strfreev (search_path);
-}
-
-#define g_string_append_indent(string, indent)  \
-    {                                           \
-        gint i;                                 \
-        for (i = 0; i < (indent); i++) {        \
-            g_string_append (string, "    ");   \
-        }                                       \
-    }
-
-static gboolean
-bus_registry_load_cache (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    gchar *filename;
-    XMLNode *node;
-    GList *p;
-
-    filename = g_build_filename (g_get_user_cache_dir (), "ibus", "bus", "registry.xml", NULL);
-    node = ibus_xml_parse_file (filename);
-    g_free (filename);
-
-    if (node == NULL) {
-        return FALSE;
-    }
-
-    if (g_strcmp0 (node->name, "ibus-registry") != 0) {
-        ibus_xml_free (node);
-        return FALSE;
-    }
-
-    for (p = node->sub_nodes; p != NULL; p = p->next) {
-        XMLNode *sub_node = (XMLNode *) p->data;
-
-        if (g_strcmp0 (sub_node->name, "observed-paths") == 0) {
-            GList *pp;
-            for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) {
-                IBusObservedPath *path;
-                path = ibus_observed_path_new_from_xml_node (pp->data, FALSE);
-                if (path) {
-                    g_object_ref_sink (path);
-                    registry->observed_paths = g_list_append (registry->observed_paths, path);
-                }
-            }
-            continue;
-        }
-        if (g_strcmp0 (sub_node->name, "components") == 0) {
-            GList *pp;
-            for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) {
-                IBusComponent *component;
-                component = ibus_component_new_from_xml_node (pp->data);
-                if (component) {
-                    BusComponent *buscomp = bus_component_new (component,
-                                                               NULL /* factory */);
-                    g_object_ref_sink (buscomp);
-                    registry->components =
-                        g_list_append (registry->components, buscomp);
-                }
-            }
-
-            continue;
-        }
-        g_warning ("Unknown element <%s>", sub_node->name);
-    }
-
-    ibus_xml_free (node);
-    return TRUE;
-}
-
-static gboolean
-bus_registry_check_modification (BusRegistry *registry)
-{
-    GList *p;
-
-    for (p = registry->observed_paths; p != NULL; p = p->next) {
-        if (ibus_observed_path_check_modification ((IBusObservedPath *) p->data))
-            return TRUE;
-    }
-
-    for (p = registry->components; p != NULL; p = p->next) {
-        if (ibus_component_check_modification (bus_component_get_component ((BusComponent *) p->data)))
-            return TRUE;
-    }
-
-    return FALSE;
-}
-
-static gboolean
-bus_registry_save_cache (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    gchar *cachedir;
-    gchar *filename;
-    GString *output;
-    GList *p;
-    FILE *pf;
-    size_t items = 0;
-
-    cachedir = g_build_filename (g_get_user_cache_dir (), "ibus", "bus", NULL);
-    filename = g_build_filename (cachedir, "registry.xml", NULL);
-    g_mkdir_with_parents (cachedir, 0775);
-    pf = g_fopen (filename, "w");
-    g_free (filename);
-    g_free (cachedir);
-
-    if (pf == NULL) {
-        g_warning ("create registry.xml failed");
-        return FALSE;
-    }
-
-    output = g_string_new ("");
-    g_string_append (output, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
-    g_string_append (output, "<!-- \n"
-                             "    This file was generated by ibus-daemon. Please don't modify it.\n"
-                             "    -->\n");
-    g_string_append (output, "<ibus-registry>\n");
-
-    if (registry->observed_paths) {
-        g_string_append_indent (output, 1);
-        g_string_append (output, "<observed-paths>\n");
-        for (p = registry->observed_paths; p != NULL; p = p->next) {
-            ibus_observed_path_output ((IBusObservedPath *) p->data,
-                                      output, 2);
-        }
-        g_string_append_indent (output, 1);
-        g_string_append (output, "</observed-paths>\n");
-    }
-
-    if (registry->components) {
-        g_string_append_indent (output, 1);
-        g_string_append (output, "<components>\n");
-        for (p = registry->components; p != NULL; p = p->next) {
-            ibus_component_output (bus_component_get_component ((BusComponent *) p->data),
-                                   output, 2);
-        }
-        g_string_append_indent (output, 1);
-        g_string_append (output, "</components>\n");
-    }
-
-    g_string_append (output, "</ibus-registry>\n");
-    items = fwrite (output->str, output->len, 1, pf);
-    g_string_free (output, TRUE);
-    fclose (pf);
-    return (items == 1 ? TRUE : FALSE);
-}
-
-/**
- * bus_registry_load_in_dir:
- *
- * Read all XML files in dirname, create a BusComponent object for each file, and add the component objects to the registry.
- */
-static void
-bus_registry_load_in_dir (BusRegistry *registry,
-                          const gchar *dirname)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-    g_assert (dirname);
-
-    GError *error = NULL;
-    GDir *dir;
-    const gchar *filename;
-
-    dir = g_dir_open (dirname, 0, &error);
-
-    if (dir == NULL) {
-        g_warning ("Unable open directory %s : %s", dirname, error->message);
-        g_error_free (error);
-        return;
-    }
-
-    while ((filename = g_dir_read_name (dir)) != NULL) {
-        glong size;
-        gchar *path;
-        IBusComponent *component;
-
-        size = g_utf8_strlen (filename, -1);
-        if (g_strcmp0 (MAX (filename, filename + size - 4), ".xml") != 0)
-            continue;
-
-        path = g_build_filename (dirname, filename, NULL);
-        component = ibus_component_new_from_file (path);
-        if (component != NULL) {
-            BusComponent *buscomp = bus_component_new (component,
-                                                       NULL /* factory */);
-            g_object_ref_sink (buscomp);
-            registry->components =
-                g_list_append (registry->components, buscomp);
-        }
-
-        g_free (path);
-    }
-
-    g_dir_close (dir);
-}
-
-
-BusRegistry *
-bus_registry_new (void)
-{
-    BusRegistry *registry;
-    registry = (BusRegistry *) g_object_new (BUS_TYPE_REGISTRY, NULL);
-    return registry;
-}
-
-static gint
-bus_register_component_is_name_cb (BusComponent *component,
-                                   const gchar  *name)
-{
-    g_assert (BUS_IS_COMPONENT (component));
-    g_assert (name);
-
-    return g_strcmp0 (bus_component_get_name (component), name);
-}
-
-BusComponent *
-bus_registry_lookup_component_by_name (BusRegistry *registry,
-                                       const gchar *name)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-    g_assert (name);
-
-    GList *p;
-    p = g_list_find_custom (registry->components,
-                            name,
-                            (GCompareFunc) bus_register_component_is_name_cb);
-    if (p) {
-        return (BusComponent *) p->data;
-    }
-    else {
-        return NULL;
-    }
-}
-
-GList *
-bus_registry_get_components (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    return g_list_copy (registry->components);
-}
-
-GList *
-bus_registry_get_engines (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    return g_hash_table_get_values (registry->engine_table);
-}
-
-GList *
-bus_registry_get_engines_by_language (BusRegistry *registry,
-                                      const gchar *language)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-    g_assert (language);
-
-    gint n;
-    GList *p1, *p2, *engines;
-
-    n = strlen (language);
-
-    p1 = bus_registry_get_engines (registry);
-
-    engines = NULL;
-
-    for (p2 = p1; p2 != NULL; p2 = p2->next) {
-        IBusEngineDesc *desc = (IBusEngineDesc *) p2->data;
-        if (strncmp (ibus_engine_desc_get_language (desc), language, n) == 0) {
-            engines = g_list_append (engines, desc);
-        }
-    }
-
-    g_list_free (p1);
-    return engines;
-}
-
-IBusEngineDesc *
-bus_registry_find_engine_by_name (BusRegistry *registry,
-                                  const gchar *name)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-    g_assert (name);
-
-    return (IBusEngineDesc *) g_hash_table_lookup (registry->engine_table, name);
-}
-
-void
-bus_registry_stop_all_components (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    g_list_foreach (registry->components, (GFunc) bus_component_stop, NULL);
-
-}
-
-static gboolean
-_monitor_timeout_cb (BusRegistry *registry)
-{
-    g_hash_table_remove_all (registry->monitor_table);
-    registry->changed = TRUE;
-    g_signal_emit (registry, _signals[CHANGED], 0);
-    registry->monitor_timeout_id = 0;
-    return FALSE;
-}
-
-static void
-_monitor_changed_cb (GFileMonitor     *monitor,
-                     GFile            *file,
-                     GFile            *other_file,
-                     GFileMonitorEvent event_type,
-                     BusRegistry      *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
-        event_type != G_FILE_MONITOR_EVENT_DELETED &&
-        event_type != G_FILE_MONITOR_EVENT_CREATED &&
-        event_type != G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED)
-        return;
-
-    /* Merge successive file changes into one, with a low priority
-       timeout handler. */
-    if (registry->monitor_timeout_id > 0)
-        return;
-
-    registry->monitor_timeout_id =
-        g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
-                            5000,
-                            (GSourceFunc) _monitor_timeout_cb,
-                            g_object_ref (registry),
-                            (GDestroyNotify) g_object_unref);
-}
-
-/**
- * bus_registry_start_monitor_changes:
- *
- * Start the monitor thread.
- */
-void
-bus_registry_start_monitor_changes (BusRegistry *registry)
-{
-    GList *observed_paths, *p;
-
-    g_assert (BUS_IS_REGISTRY (registry));
-
-    g_hash_table_remove_all (registry->monitor_table);
-
-    observed_paths = g_list_copy (registry->observed_paths);
-    for (p = registry->components; p != NULL; p = p->next) {
-        BusComponent *buscomp = (BusComponent *) p->data;
-        IBusComponent *component = bus_component_get_component (buscomp);
-        GList *component_observed_paths =
-            ibus_component_get_observed_paths (component);
-        observed_paths = g_list_concat (observed_paths,
-                                        component_observed_paths);
-    }
-
-    for (p = observed_paths; p != NULL; p = p->next) {
-        IBusObservedPath *path = (IBusObservedPath *) p->data;
-        GFile *file = g_file_new_for_path (path->path);
-        if (g_hash_table_lookup (registry->monitor_table,file) == NULL) {
-            GFileMonitor *monitor;
-            GError *error;
-
-            error = NULL;
-            monitor = g_file_monitor (file,
-                                      G_FILE_MONITOR_NONE,
-                                      NULL,
-                                      &error);
-
-            if (monitor != NULL) {
-                g_signal_connect (monitor, "changed",
-                                  G_CALLBACK (_monitor_changed_cb),
-                                  registry);
-
-                g_hash_table_replace (registry->monitor_table,
-                                      g_object_ref (file),
-                                      monitor);
-            } else {
-                g_warning ("Can't monitor directory %s: %s",
-                           path->path,
-                           error->message);
-                g_error_free (error);
-            }
-        }
-        g_object_unref (file);
-    }
-    g_list_free (observed_paths);
-}
-
-gboolean
-bus_registry_is_changed (BusRegistry *registry)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-    return (registry->changed != 0);
-}
-
-void
-bus_registry_name_owner_changed (BusRegistry *registry,
-                                 const gchar *name,
-                                 const gchar *old_name,
-                                 const gchar *new_name)
-{
-    g_assert (BUS_IS_REGISTRY (registry));
-    g_assert (name);
-    g_assert (old_name);
-    g_assert (new_name);
-
-    BusComponent *component;
-    BusFactoryProxy *factory;
-
-    component = bus_registry_lookup_component_by_name (registry, name);
-
-    if (component == NULL) {
-        /* name is a unique name, or a well-known name we don't know. */
-        return;
-    }
-
-    if (g_strcmp0 (old_name, "") != 0) {
-        /* the component is stopped. */
-        factory = bus_component_get_factory (component);
-
-        if (factory != NULL) {
-            ibus_proxy_destroy ((IBusProxy *) factory);
-        }
-    }
-
-    if (g_strcmp0 (new_name, "") != 0) {
-        /* the component is started. */
-        BusConnection *connection =
-                bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS,
-                                                      new_name);
-        if (connection == NULL)
-            return;
-
-        factory = bus_factory_proxy_new (connection);
-        if (factory == NULL)
-            return;
-        bus_component_set_factory (component, factory);
-        g_object_unref (factory);
-    }
-}
diff --git a/bus/registry.h b/bus/registry.h
deleted file mode 100644 (file)
index 2864ed9..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-/* vim:set et sts=4: */
-/* bus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
- *
- * 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.
- */
-#ifndef __BUS_REGISTRY_H_
-#define __BUS_REGISTRY_H_
-
-#include <ibus.h>
-#include "component.h"
-
-/*
- * Type macros.
- */
-
-/* define GOBJECT macros */
-#define BUS_TYPE_REGISTRY             \
-    (bus_registry_get_type ())
-#define BUS_REGISTRY(obj)             \
-    (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUS_TYPE_REGISTRY, BusRegistry))
-#define BUS_REGISTRY_CLASS(klass)     \
-    (G_TYPE_CHECK_CLASS_CAST ((klass), BUS_TYPE_REGISTRY, BusRegistryClass))
-#define BUS_IS_REGISTRY(obj)          \
-    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUS_TYPE_REGISTRY))
-#define BUS_IS_REGISTRY_CLASS(klass)  \
-    (G_TYPE_CHECK_CLASS_TYPE ((klass), BUS_TYPE_REGISTRY))
-#define BUS_REGISTRY_GET_CLASS(obj)   \
-    (G_TYPE_INSTANCE_GET_CLASS ((obj), BUS_TYPE_REGISTRY, BusRegistryClass))
-
-G_BEGIN_DECLS
-
-typedef struct _BusRegistry BusRegistry;
-typedef struct _BusRegistryClass BusRegistryClass;
-
-GType            bus_registry_get_type          (void);
-BusRegistry     *bus_registry_new               (void);
-
-/**
- * bus_registry_get_components:
- * @returns: a list of BusComponent objects. The caller has to call g_list_free for the returned list.
- */
-GList           *bus_registry_get_components    (BusRegistry    *registry);
-
-/**
- * bus_registry_get_engines:
- * @returns: a list of all IBusEngineDesc objects available. The caller has to call g_list_free for the returned list.
- */
-GList           *bus_registry_get_engines       (BusRegistry    *registry);
-
-/**
- * bus_registry_get_engines_by_language:
- * @language: a language name like 'ja'
- * @returns: a list of IBusEngineDesc objects for the language. The caller has to call g_list_free for the returned list.
- */
-GList           *bus_registry_get_engines_by_language
-                                                (BusRegistry    *registry,
-                                                 const gchar    *language);
-
-/**
- * bus_registry_stop_all_components:
- *
- * Terminate all component processes.
- */
-void             bus_registry_stop_all_components
-                                                (BusRegistry    *registry);
-
-/**
- * bus_registry_lookup_component_by_name:
- * @name: a component name such as 'org.freedesktop.IBus.Panel' and 'com.google.IBus.Mozc'
- * @returns: a BusComponent object, or NULL if such component is not found.
- */
-BusComponent    *bus_registry_lookup_component_by_name
-                                                (BusRegistry    *registry,
-                                                 const gchar    *name);
-
-/**
- * bus_registry_find_engine_by_name:
- * @name: an engine name like 'pinyin'
- * @returns: an IBusEngineDesc object, or NULL if not found.
- */
-IBusEngineDesc  *bus_registry_find_engine_by_name
-                                                (BusRegistry    *registry,
-                                                 const gchar    *name);
-
-/**
- * bus_registry_name_owner_changed:
- * @name: a unique or well-known name like ":1.1", "org.freedesktop.IBus.Config", "com.google.IBus.Mozc".
- * @old_name: a unique name like ":1.1", or empty string "" when the client is started.
- * @new_name: a unique name like ":1.1", or empty string "" when the client is stopped.
- *
- * Handle the "name-owner-changed" glib signal from dbusimpl. If a component is stopped, remove a BusFactoryProxy object from the
- * bus for the component. If a component is started, create a new BusFactoryProxy object for the bus.
- */
-void             bus_registry_name_owner_changed
-                                                (BusRegistry    *registry,
-                                                 const gchar    *name,
-                                                 const gchar    *old_name,
-                                                 const gchar    *new_name);
-
-void             bus_registry_start_monitor_changes
-                                                (BusRegistry    *registry);
-gboolean         bus_registry_is_changed        (BusRegistry    *registry);
-
-G_END_DECLS
-#endif
-
diff --git a/bus/test-registry.c b/bus/test-registry.c
deleted file mode 100644 (file)
index 2257220..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-#include "registry.h"
-
-int main()
-{
-#if !GLIB_CHECK_VERSION(2,35,0)
-       g_type_init ();
-#endif
-       BusRegistry *registry = bus_registry_new ();
-       g_object_unref (registry);
-       return 0;
-}
index febfe8c..ca158c2 100644 (file)
@@ -89,6 +89,7 @@
       <xi:include href="xml/ibusconfig.xml"/>
       <xi:include href="xml/ibusconfigservice.xml"/>
       <xi:include href="xml/ibusobservedpath.xml"/>
+      <xi:include href="xml/ibusregistry.xml"/>
       <xi:include href="xml/ibusversion.xml"/>
       <xi:include href="xml/ibusxml.xml"/>
   </chapter>
index 016e9ce..8055cae 100644 (file)
@@ -27,3 +27,4 @@ ibus_property_get_type
 ibus_prop_list_get_type
 ibus_input_context_get_type
 ibus_observed_path_get_type
+ibus_registry_get_type
index b2793c8..74b6838 100644 (file)
@@ -2,8 +2,8 @@
 #
 # ibus - The Input Bus
 #
-# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
-# Copyright (c) 2007-2010 Red Hat, Inc.
+# Copyright (c) 2007-2013 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2013 Red Hat, Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -42,15 +42,16 @@ INTROSPECTION_GIRS =
 CLEANFILES =
 
 # C preprocessor flags
-AM_CPPFLAGS =                                   \
-    -DG_LOG_DOMAIN=\"IBUS\"                     \
-    @GLIB2_CFLAGS@                              \
-    @GOBJECT2_CFLAGS@                           \
-    @GIO2_CFLAGS@                               \
-    -DIBUS_DATA_DIR=\"$(pkgdatadir)\"           \
-    -DIBUS_DISABLE_DEPRECATION_WARNINGS         \
-    -DIBUS_COMPILATION                          \
-    -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\"    \
+AM_CPPFLAGS =                                           \
+    -DG_LOG_DOMAIN=\"IBUS\"                             \
+    @GLIB2_CFLAGS@                                      \
+    @GOBJECT2_CFLAGS@                                   \
+    @GIO2_CFLAGS@                                       \
+    -DIBUS_CACHE_DIR=\""$(localstatedir)/cache/ibus"\"  \
+    -DIBUS_DATA_DIR=\"$(pkgdatadir)\"                   \
+    -DIBUS_DISABLE_DEPRECATION_WARNINGS                 \
+    -DIBUS_COMPILATION                                  \
+    -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\"            \
     $(NULL)
 
 # ibus library
@@ -97,6 +98,7 @@ ibus_sources =              \
     ibuscomponent.c         \
     ibusutil.c              \
     ibusenginesimple.c      \
+    ibusregistry.c          \
     $(NULL)
 libibus_1_0_la_SOURCES =    \
     ibusmarshalers.c        \
@@ -145,6 +147,7 @@ ibus_headers =              \
     ibuscomponent.h         \
     ibusutil.h              \
     ibusenginesimple.h      \
+    ibusregistry.h          \
     $(NULL)
 ibusincludedir = $(includedir)/ibus-@IBUS_API_VERSION@
 ibus_public_headers =       \
index ef811a4..e27f845 100644 (file)
@@ -1,8 +1,8 @@
 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
 /* vim:set et sts=4: */
 /* ibus - The Input Bus
- * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2013 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -55,6 +55,7 @@
 #include <ibusconfigservice.h>
 #include <ibuspanelservice.h>
 #include <ibusutil.h>
+#include <ibusregistry.h>
 
 #ifndef IBUS_DISABLE_DEPRECATED
 #include <ibuskeysyms-compat.h>
diff --git a/src/ibusregistry.c b/src/ibusregistry.c
new file mode 100644 (file)
index 0000000..d239955
--- /dev/null
@@ -0,0 +1,557 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * 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 <gio/gio.h>
+#include <glib/gstdio.h>
+#include <string.h>
+
+#include "ibusinternal.h"
+#include "ibusmarshalers.h"
+#include "ibusregistry.h"
+
+enum {
+    CHANGED,
+    LAST_SIGNAL,
+};
+
+static guint             _signals[LAST_SIGNAL] = { 0 };
+
+struct _IBusRegistryPrivate {
+    /* a list of IBusObservedPath objects. */
+    GList *observed_paths;
+
+    /* a list of IBusComponent objects that are created from component XML
+     * files (or from the cache of them). */
+    GList *components;
+
+    gboolean changed;
+
+    /* a mapping from GFile to GFileMonitor. */
+    GHashTable *monitor_table;
+
+    guint monitor_timeout_id;
+};
+
+#define IBUS_REGISTRY_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_REGISTRY, IBusRegistryPrivate))
+
+/* functions prototype */
+static void     ibus_registry_destroy        (IBusRegistry           *registry);
+static void     ibus_registry_remove_all     (IBusRegistry           *registry);
+
+G_DEFINE_TYPE (IBusRegistry, ibus_registry, IBUS_TYPE_OBJECT)
+
+static void
+ibus_registry_class_init (IBusRegistryClass *class)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
+
+    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_registry_destroy;
+
+    g_type_class_add_private (class, sizeof (IBusRegistryPrivate));
+
+    /* install signals */
+    /**
+     * IBusRegistry::changed:
+     * @registry: An #IBusRegistry.
+     *
+     * Emitted when any observed paths are changed.
+     * A method is not associated in this class. the "changed"
+     * signal would be handled in other classes.
+     *
+     * See also: ibus_registry_start_monitor_changes().
+     */
+    _signals[CHANGED] =
+        g_signal_new (I_("changed"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            0,
+            NULL, NULL,
+            _ibus_marshal_VOID__VOID,
+            G_TYPE_NONE,
+            0);
+}
+
+static void
+ibus_registry_init (IBusRegistry *registry)
+{
+    registry->priv = IBUS_REGISTRY_GET_PRIVATE (registry);
+
+    registry->priv->observed_paths = NULL;
+    registry->priv->components = NULL;
+    registry->priv->changed = FALSE;
+    registry->priv->monitor_table =
+        g_hash_table_new_full (g_file_hash,
+                               (GEqualFunc) g_file_equal,
+                               (GDestroyNotify) g_object_unref,
+                               (GDestroyNotify) g_object_unref);
+}
+
+static void
+ibus_registry_destroy (IBusRegistry *registry)
+{
+    ibus_registry_remove_all (registry);
+
+    g_hash_table_destroy (registry->priv->monitor_table);
+    registry->priv->monitor_table = NULL;
+
+    if (registry->priv->monitor_timeout_id > 0) {
+        g_source_remove (registry->priv->monitor_timeout_id);
+        registry->priv->monitor_timeout_id = 0;
+    }
+
+    IBUS_OBJECT_CLASS (ibus_registry_parent_class)->
+            destroy (IBUS_OBJECT (registry));
+}
+
+/**
+ * ibus_registry_remove_all:
+ *
+ * Remove the loaded registry.
+ */
+static void
+ibus_registry_remove_all (IBusRegistry *registry)
+{
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    g_list_free_full (registry->priv->observed_paths, g_object_unref);
+    registry->priv->observed_paths = NULL;
+
+    g_list_free_full (registry->priv->components, g_object_unref);
+    registry->priv->components = NULL;
+}
+
+void
+ibus_registry_load (IBusRegistry *registry)
+{
+    const gchar *envstr;
+    GPtrArray *path;
+    gchar **d, **search_path;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    path = g_ptr_array_new();
+
+    envstr = g_getenv ("IBUS_COMPONENT_PATH");
+    if (envstr) {
+        gchar **dirs = g_strsplit (envstr, G_SEARCHPATH_SEPARATOR_S, 0);
+        for (d = dirs; *d != NULL; d++)
+            g_ptr_array_add (path, *d);
+        g_free (dirs);
+    } else {
+        gchar *dirname;
+
+        dirname = g_build_filename (IBUS_DATA_DIR, "component", NULL);
+        g_ptr_array_add (path, dirname);
+
+#if 0
+        /* FIXME Should we support install some IME in user dir? */
+        dirname = g_build_filename (g_get_user_data_dir (),
+                                    "ibus", "component",
+                                    NULL);
+        g_ptr_array_add (path, dirname);
+#endif
+    }
+
+    g_ptr_array_add (path, NULL);
+    search_path = (gchar **) g_ptr_array_free (path, FALSE);
+    for (d = search_path; *d != NULL; d++) {
+        ibus_registry_load_in_dir (registry, *d);
+    }
+    g_strfreev (search_path);
+}
+
+gboolean
+ibus_registry_load_cache (IBusRegistry *registry, gboolean is_user)
+{
+    gchar *filename;
+    gboolean retval;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    if (is_user) {
+        filename = g_build_filename (g_get_user_cache_dir (),
+                                     "ibus", "bus", "registry.xml", NULL);
+    } else {
+        filename = g_build_filename (IBUS_CACHE_DIR,
+                                     "bus", "registry.xml", NULL);
+    }
+
+    retval = ibus_registry_load_cache_file (registry, filename);
+    g_free (filename);
+
+    return retval;
+}
+
+gboolean
+ibus_registry_load_cache_file (IBusRegistry *registry, const gchar *filename)
+{
+    XMLNode *node;
+    GList *p;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+    g_assert (filename != NULL);
+
+    node = ibus_xml_parse_file (filename);
+
+    if (node == NULL) {
+        return FALSE;
+    }
+
+    if (g_strcmp0 (node->name, "ibus-registry") != 0) {
+        ibus_xml_free (node);
+        return FALSE;
+    }
+
+    for (p = node->sub_nodes; p != NULL; p = p->next) {
+        XMLNode *sub_node = (XMLNode *) p->data;
+
+        if (g_strcmp0 (sub_node->name, "observed-paths") == 0) {
+            GList *pp;
+            for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) {
+                IBusObservedPath *path;
+                path = ibus_observed_path_new_from_xml_node (pp->data, FALSE);
+                if (path) {
+                    g_object_ref_sink (path);
+                    registry->priv->observed_paths =
+                            g_list_append (registry->priv->observed_paths,
+                                           path);
+                }
+            }
+            continue;
+        }
+        if (g_strcmp0 (sub_node->name, "components") == 0) {
+            GList *pp;
+            for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) {
+                IBusComponent *component;
+                component = ibus_component_new_from_xml_node (pp->data);
+                if (component) {
+                    g_object_ref_sink (component);
+                    registry->priv->components =
+                        g_list_append (registry->priv->components, component);
+                }
+            }
+
+            continue;
+        }
+        g_warning ("Unknown element <%s>", sub_node->name);
+    }
+
+    ibus_xml_free (node);
+    return TRUE;
+}
+
+gboolean
+ibus_registry_check_modification (IBusRegistry *registry)
+{
+    GList *p;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    for (p = registry->priv->observed_paths; p != NULL; p = p->next) {
+        if (ibus_observed_path_check_modification (
+                    (IBusObservedPath *) p->data))
+            return TRUE;
+    }
+
+    for (p = registry->priv->components; p != NULL; p = p->next) {
+        if (ibus_component_check_modification ((IBusComponent *) p->data))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+gboolean
+ibus_registry_save_cache (IBusRegistry *registry, gboolean is_user)
+{
+    gchar *filename;
+    gboolean retval;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    if (is_user) {
+        filename = g_build_filename (g_get_user_cache_dir (),
+                                     "ibus", "bus", "registry.xml", NULL);
+    } else {
+        filename = g_build_filename (IBUS_CACHE_DIR,
+                                     "bus", "registry.xml", NULL);
+    }
+
+    retval = ibus_registry_save_cache_file (registry, filename);
+    g_free (filename);
+
+    return retval;
+}
+
+gboolean
+ibus_registry_save_cache_file (IBusRegistry *registry, const gchar *filename)
+{
+    gchar *cachedir;
+    const gchar *user_cachedir;
+    gboolean is_user = TRUE;
+    GString *output;
+    FILE *pf;
+    size_t items = 0;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+    g_assert (filename != NULL);
+
+    cachedir = g_path_get_dirname (filename);
+    g_mkdir_with_parents (cachedir, 0775);
+    g_free (cachedir);
+    pf = g_fopen (filename, "w");
+
+    if (pf == NULL) {
+        g_warning ("create %s failed", filename);
+        return FALSE;
+    }
+
+    output = g_string_new ("");
+
+    ibus_registry_output (registry, output, 1);
+
+    items = fwrite (output->str, output->len, 1, pf);
+    g_string_free (output, TRUE);
+    fclose (pf);
+
+    user_cachedir = g_get_user_cache_dir ();
+    is_user = (strncmp (user_cachedir, filename, strlen (user_cachedir)) == 0);
+
+    if (!is_user) {
+        g_chmod (filename, 0644);
+    }
+
+    return (items == 1 ? TRUE : FALSE);
+}
+
+#define g_string_append_indent(string, indent)  \
+    {                                           \
+        gint i;                                 \
+        for (i = 0; i < (indent); i++) {        \
+            g_string_append (string, "    ");   \
+        }                                       \
+    }
+
+void
+ibus_registry_output (IBusRegistry *registry, GString *output, int indent)
+{
+    GList *p;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+    g_return_if_fail (output != NULL);
+
+    g_string_append (output, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+    g_string_append (output, "<!-- \n"
+                             "    This file was generated by ibus-daemon. "
+                             "Please don't modify it.\n"
+                             "    -->\n");
+    g_string_append (output, "<ibus-registry>\n");
+
+    if (registry->priv->observed_paths) {
+        g_string_append_indent (output, indent);
+        g_string_append (output, "<observed-paths>\n");
+        for (p = registry->priv->observed_paths; p != NULL; p = p->next) {
+            ibus_observed_path_output ((IBusObservedPath *) p->data,
+                                      output, indent * 2);
+        }
+        g_string_append_indent (output, indent);
+        g_string_append (output, "</observed-paths>\n");
+    }
+
+    if (registry->priv->components) {
+        g_string_append_indent (output, indent);
+        g_string_append (output, "<components>\n");
+        for (p = registry->priv->components; p != NULL; p = p->next) {
+            ibus_component_output ((IBusComponent *) p->data,
+                                   output, indent * 2);
+        }
+        g_string_append_indent (output, indent);
+        g_string_append (output, "</components>\n");
+    }
+
+    g_string_append (output, "</ibus-registry>\n");
+}
+
+void
+ibus_registry_load_in_dir (IBusRegistry *registry,
+                           const gchar  *dirname)
+{
+    GError *error = NULL;
+    GDir *dir;
+    IBusObservedPath *observed_path = NULL;
+    const gchar *filename;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+    g_assert (dirname);
+
+    dir = g_dir_open (dirname, 0, &error);
+
+    if (dir == NULL) {
+        g_warning ("Unable open directory %s : %s", dirname, error->message);
+        g_error_free (error);
+        return;
+    }
+
+    observed_path = ibus_observed_path_new (dirname, TRUE);
+
+    registry->priv->observed_paths =
+            g_list_append (registry->priv->observed_paths,
+                           observed_path);
+
+    while ((filename = g_dir_read_name (dir)) != NULL) {
+        glong size;
+        gchar *path;
+        IBusComponent *component;
+
+        size = g_utf8_strlen (filename, -1);
+        if (g_strcmp0 (MAX (filename, filename + size - 4), ".xml") != 0)
+            continue;
+
+        path = g_build_filename (dirname, filename, NULL);
+        component = ibus_component_new_from_file (path);
+        if (component != NULL) {
+            g_object_ref_sink (component);
+            registry->priv->components =
+                g_list_append (registry->priv->components, component);
+        }
+
+        g_free (path);
+    }
+
+    g_dir_close (dir);
+}
+
+
+IBusRegistry *
+ibus_registry_new (void)
+{
+    IBusRegistry *registry;
+    registry = (IBusRegistry *) g_object_new (IBUS_TYPE_REGISTRY, NULL);
+    return registry;
+}
+
+GList *
+ibus_registry_get_components (IBusRegistry *registry)
+{
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    return g_list_copy (registry->priv->components);
+}
+
+GList *
+ibus_registry_get_observed_paths (IBusRegistry *registry)
+{
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    return g_list_copy (registry->priv->observed_paths);
+}
+
+static gboolean
+_monitor_timeout_cb (IBusRegistry *registry)
+{
+    g_hash_table_remove_all (registry->priv->monitor_table);
+    registry->priv->changed = TRUE;
+    g_signal_emit (registry, _signals[CHANGED], 0);
+    registry->priv->monitor_timeout_id = 0;
+    return FALSE;
+}
+
+static void
+_monitor_changed_cb (GFileMonitor     *monitor,
+                     GFile            *file,
+                     GFile            *other_file,
+                     GFileMonitorEvent event_type,
+                     IBusRegistry     *registry)
+{
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
+        event_type != G_FILE_MONITOR_EVENT_DELETED &&
+        event_type != G_FILE_MONITOR_EVENT_CREATED &&
+        event_type != G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED)
+        return;
+
+    /* Merge successive file changes into one, with a low priority
+       timeout handler. */
+    if (registry->priv->monitor_timeout_id > 0)
+        return;
+
+    registry->priv->monitor_timeout_id =
+        g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
+                            5000,
+                            (GSourceFunc) _monitor_timeout_cb,
+                            g_object_ref (registry),
+                            (GDestroyNotify) g_object_unref);
+}
+
+void
+ibus_registry_start_monitor_changes (IBusRegistry *registry)
+{
+    GList *observed_paths, *p;
+
+    g_assert (IBUS_IS_REGISTRY (registry));
+
+    g_hash_table_remove_all (registry->priv->monitor_table);
+
+    observed_paths = g_list_copy (registry->priv->observed_paths);
+    for (p = registry->priv->components; p != NULL; p = p->next) {
+        IBusComponent *component = (IBusComponent *) p->data;
+        GList *component_observed_paths =
+            ibus_component_get_observed_paths (component);
+        observed_paths = g_list_concat (observed_paths,
+                                        component_observed_paths);
+    }
+
+    for (p = observed_paths; p != NULL; p = p->next) {
+        IBusObservedPath *path = (IBusObservedPath *) p->data;
+        GFile *file = g_file_new_for_path (path->path);
+        if (g_hash_table_lookup (registry->priv->monitor_table, file) == NULL) {
+            GFileMonitor *monitor;
+            GError *error;
+
+            error = NULL;
+            monitor = g_file_monitor (file,
+                                      G_FILE_MONITOR_NONE,
+                                      NULL,
+                                      &error);
+
+            if (monitor != NULL) {
+                g_signal_connect (monitor, "changed",
+                                  G_CALLBACK (_monitor_changed_cb),
+                                  registry);
+
+                g_hash_table_replace (registry->priv->monitor_table,
+                                      g_object_ref (file),
+                                      monitor);
+            } else {
+                g_warning ("Can't monitor directory %s: %s",
+                           path->path,
+                           error->message);
+                g_error_free (error);
+            }
+        }
+        g_object_unref (file);
+    }
+    g_list_free (observed_paths);
+}
diff --git a/src/ibusregistry.h b/src/ibusregistry.h
new file mode 100644 (file)
index 0000000..288dc07
--- /dev/null
@@ -0,0 +1,223 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2013 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION)
+#error "Only <ibus.h> can be included directly"
+#endif
+
+#ifndef __IBUS_REGISTRY_H_
+#define __IBUS_REGISTRY_H_
+
+/**
+ * SECTION: ibusregistry
+ * @short_description: Registry cache handling.
+ * @title: IBusRegistry
+ * @stability: Stable
+ *
+ * An #IBusRegistry loads IBus component files and generates the cache files.
+ *
+ * see_also: #IBusComponent
+ */
+
+#include "ibuscomponent.h"
+
+/*
+ * Type macros.
+ */
+
+/* define GOBJECT macros */
+#define IBUS_TYPE_REGISTRY            \
+    (ibus_registry_get_type ())
+#define IBUS_REGISTRY(obj)            \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_REGISTRY, IBusRegistry))
+#define IBUS_REGISTRY_CLASS(klass)    \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_REGISTRY, IBusRegistryClass))
+#define IBUS_IS_REGISTRY(obj)         \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_REGISTRY))
+#define IBUS_IS_REGISTRY_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_REGISTRY))
+#define IBUS_REGISTRY_GET_CLASS(obj)  \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_REGISTRY, IBusRegistryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _IBusRegistry IBusRegistry;
+typedef struct _IBusRegistryPrivate IBusRegistryPrivate;
+typedef struct _IBusRegistryClass IBusRegistryClass;
+
+/**
+ * IBusRegistry:
+ *
+ * Registry cache handling.
+ * You can load the registry from compose files or a cache file.
+ */
+struct _IBusRegistry {
+    /* instance members */
+    /*< private >*/
+    IBusObject parent;
+    IBusRegistryPrivate *priv;
+};
+
+struct _IBusRegistryClass {
+    /* class members */
+    /*< private >*/
+    IBusObjectClass parent;
+};
+
+GType            ibus_registry_get_type         (void);
+
+/**
+ * ibus_registry_new:
+ * @returns: A newly allocated #IBusRegistry.
+ *
+ * New a #IBusRegistry
+ */
+IBusRegistry    *ibus_registry_new              (void);
+
+/**
+ * ibus_registry_load:
+ * @registry: An #IBusRegistry.
+ *
+ * Read all XML files in a IBus component directory (typically
+ * /usr/share/ibus/component/ *.xml) and update the registry object.
+ * IBUS_COMPONENT_PATH environment valuable is also available for
+ * the custom component directories, whose delimiter is ':'.
+ */
+void             ibus_registry_load             (IBusRegistry   *registry);
+
+/**
+ * ibus_registry_load_in_dir:
+ * @registry: An #IBusRegistry.
+ * @dirname: IBus component directory which includes XML files.
+ *
+ * Read all XML files in @dirname, create a #IBusComponent object for each file,
+ * and add the component objects to the registry.
+ * If @dirname is "/usr/share/ibus/component", this API and
+ * ibus_registry_load() are same.
+ */
+void             ibus_registry_load_in_dir      (IBusRegistry   *registry,
+                                                 const gchar    *dirname);
+
+/**
+ * ibus_registry_load_cache:
+ * @registry: An #IBusRegistry.
+ * @is_user: %TRUE if the registry cache is loaded in the user directory.
+ * @returns: %TRUE if the cache exists and is loaded successfully,
+ *           %FALSE otherwise.
+ *
+ * Load the user or system registry cache.
+ */
+gboolean         ibus_registry_load_cache       (IBusRegistry   *registry,
+                                                 gboolean        is_user);
+
+/**
+ * ibus_registry_load_cache_file:
+ * @registry: An #IBusRegistry.
+ * @filename: The file path of the registry cache
+ * @returns: %TRUE if the cache exists and is loaded successfully,
+ *           %FALSE otherwise.
+ *
+ * Load the registry cache @filename.
+ */
+gboolean         ibus_registry_load_cache_file  (IBusRegistry   *registry,
+                                                 const gchar    *filename);
+
+/**
+ * ibus_registry_save_cache:
+ * @registry: An #IBusRegistry.
+ * @is_user: %TRUE if the registry cache is saved in the user directory.
+ * @returns: %TRUE if the cache is saved successfully, %FALSE otherwise.
+ *
+ * Save the registry in a user directory or system directory.
+ */
+gboolean         ibus_registry_save_cache       (IBusRegistry   *registry,
+                                                 gboolean        is_user);
+
+/**
+ * ibus_registry_save_cache_file:
+ * @registry: An #IBusRegistry.
+ * @filename: The file path of the registry cache
+ * @returns: %TRUE if the cache is saved successfully, %FALSE otherwise.
+ *
+ * Save the registry cache @filename.
+ */
+gboolean         ibus_registry_save_cache_file  (IBusRegistry   *registry,
+                                                 const gchar    *filename);
+
+/**
+ * ibus_registry_output:
+ * @registry: An #IBusRegistry.
+ * @output: GString that holds the result.
+ * @indent: level of indent.
+ *
+ * Output #IBusRegistry as an XML-formatted string.
+ * The output string can be then shown on the screen or written to file.
+ */
+void             ibus_registry_output           (IBusRegistry   *registry,
+                                                 GString        *output,
+                                                 int             indent);
+
+/**
+ * ibus_registry_check_modification:
+ * @registry: An #IBusRegistry.
+ * @returns: %TRUE if mtime is changed; %FALSE otherwise.
+ *
+ * Check if the registry is updated.
+ */
+gboolean         ibus_registry_check_modification
+                                                (IBusRegistry   *registry);
+
+/**
+ * ibus_registry_get_components:
+ * @registry: An #IBusRegistry.
+ * @returns: (transfer container) (element-type IBusComponent):
+ * a list of #IBusComponent objects.
+ * The caller has to call g_list_free() for the returned list.
+ *
+ * List components.
+ */
+GList           *ibus_registry_get_components   (IBusRegistry   *registry);
+
+/**
+ * ibus_registry_get_observed_paths:
+ * @registry: An #IBusRegistry.
+ * @returns: (transfer container) (element-type IBusObservedPath):
+ * a list of #IBusObservedPath objects.
+ * The caller has to call g_list_free() for the returned list.
+ *
+ * List observed paths.
+ */
+GList           *ibus_registry_get_observed_paths
+                                                (IBusRegistry   *registry);
+
+/**
+ * ibus_registry_start_monitor_changes:
+ * @registry: An #IBusRegistry.
+ *
+ * Start to monitor observed paths.
+ */
+void             ibus_registry_start_monitor_changes
+                                                (IBusRegistry   *registry);
+
+G_END_DECLS
+#endif
index ad8bb8e..b5b2da3 100644 (file)
@@ -2,8 +2,8 @@
 #
 # ibus - The Input Bus
 #
-# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
-# Copyright (c) 2007-2010 Red Hat, Inc.
+# Copyright (c) 2007-2013 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2013 Red Hat, Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -40,17 +40,18 @@ prog_ldadd =                        \
        $(NULL)
 
 noinst_PROGRAMS = $(TESTS)
-TESTS =               \
-       ibus-bus          \
-       ibus-config       \
-       ibus-configservice\
-       ibus-factory      \
-       ibus-inputcontext \
-       ibus-inputcontext-create \
-       ibus-keynames     \
-       ibus-serializable \
-       ibus-share        \
-       ibus-util         \
+TESTS = \
+       ibus-bus                        \
+       ibus-config                     \
+       ibus-configservice              \
+       ibus-factory                    \
+       ibus-inputcontext               \
+       ibus-inputcontext-create        \
+       ibus-keynames                   \
+       ibus-registry                   \
+       ibus-serializable               \
+       ibus-share                      \
+       ibus-util                       \
        $(NULL)
 
 if ENABLE_ENGINE
@@ -91,6 +92,9 @@ ibus_inputcontext_create_LDADD = $(prog_ldadd)
 ibus_keynames_SOURCES = ibus-keynames.c
 ibus_keynames_LDADD = $(prog_ldadd)
 
+ibus_registry_SOURCES = ibus-registry.c
+ibus_registry_LDADD = $(prog_ldadd)
+
 ibus_serializable_SOURCES = ibus-serializable.c
 ibus_serializable_LDADD = $(prog_ldadd)
 
diff --git a/src/tests/ibus-registry.c b/src/tests/ibus-registry.c
new file mode 100644 (file)
index 0000000..c1cfd8a
--- /dev/null
@@ -0,0 +1,11 @@
+#include <ibus.h>
+
+int main()
+{
+#if !GLIB_CHECK_VERSION(2,35,0)
+    g_type_init ();
+#endif
+    IBusRegistry *registry = ibus_registry_new ();
+    g_object_unref (registry);
+    return 0;
+}
index 05bf63d..80fcf41 100644 (file)
@@ -51,8 +51,37 @@ Restart ibus-daemon.
 \fBversion\fR
 Show the ibus version.
 .TP
+\fBread\-cache\fR [\fB\-\-system|\-\-file=FILE\fR]
+Show the content of the user registry cache if
+.B \-\-system
+is not given.
+Show the content of the system registry cache if
+.B \-\-system
+is given.
+Show the content of the custom registry cache 
+.B FILE
+if
+.B \-\-file=FILE
+is given.
+.TP
+\fBwrite\-cache\fR [\fB\-\-system|\-\-file=FILE\fR]
+Save the user registry cache if
+.B \-\-system
+is not given.
+Save the system registry cache if
+.B \-\-system
+is given.
+Save the custom registry cache
+.B FILE
+if
+.B \-\-file=FILE
+is given.
+IBUS_COMPONENT_PATH environment valuable is also available for
+the custom component directories, whose delimiter is ':'.
+.TP
 \fBwatch\fR
 Under construction.
+.TP
 
 .SH BUGS
 If you find a bug, please report it at http://code.google.com/p/ibus/issues/list.
index 28bd336..b358974 100644 (file)
@@ -2,7 +2,7 @@
  *
  * ibus - The Input Bus
  *
- * Copyright(c) 2011 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright(c) 2013 Peng Huang <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
@@ -21,6 +21,9 @@
  */
 
 bool name_only = false;
+/* system() exists as a public API. */
+bool is_system = false;
+string cache_file = null;
 
 class EngineList {
     public IBus.EngineDesc[] data = {};
@@ -41,8 +44,8 @@ int list_engine(string[] argv) {
         { null }
     };
 
-    var option = new OptionContext(_("command [OPTIONS]"));
-    option.add_main_entries(options, "ibus");
+    var option = new OptionContext();
+    option.add_main_entries(options, Config.GETTEXT_PACKAGE);
 
     try {
         option.parse(ref argv);
@@ -196,6 +199,78 @@ int print_version(string[] argv) {
     return Posix.EXIT_SUCCESS;
 }
 
+int read_cache (string[] argv) {
+    const OptionEntry[] options = {
+        { "system", 0, 0, OptionArg.NONE, out is_system,
+          N_("Read the system registry cache."), null },
+        { "file", 0, 0, OptionArg.STRING, out cache_file,
+          N_("Read the registry cache FILE."), "FILE" },
+        { null }
+    };
+
+    var option = new OptionContext();
+    option.add_main_entries(options, Config.GETTEXT_PACKAGE);
+
+    try {
+        option.parse(ref argv);
+    } catch (OptionError e) {
+        stderr.printf("%s\n", e.message);
+        return Posix.EXIT_FAILURE;
+    }
+
+    var registry = new IBus.Registry();
+
+    if (cache_file != null) {
+        if (!registry.load_cache_file(cache_file)) {
+            stderr.printf(_("The registry cache is invalid.\n"));
+            return Posix.EXIT_FAILURE;
+        }
+    } else {
+        if (!registry.load_cache(!is_system)) {
+            stderr.printf(_("The registry cache is invalid.\n"));
+            return Posix.EXIT_FAILURE;
+        }
+    }
+
+    var output = new GLib.StringBuilder();
+    registry.output(output, 1);
+
+    print ("%s\n", output.str);
+    return Posix.EXIT_SUCCESS;
+}
+
+int write_cache (string[] argv) {
+    const OptionEntry[] options = {
+        { "system", 0, 0, OptionArg.NONE, out is_system,
+          N_("Write the system registry cache."), null },
+        { "file", 0, 0, OptionArg.STRING, out cache_file,
+          N_("Write the registry cache FILE."),
+          "FILE" },
+        { null }
+    };
+
+    var option = new OptionContext();
+    option.add_main_entries(options, Config.GETTEXT_PACKAGE);
+
+    try {
+        option.parse(ref argv);
+    } catch (OptionError e) {
+        stderr.printf("%s\n", e.message);
+        return Posix.EXIT_FAILURE;
+    }
+
+    var registry = new IBus.Registry();
+    registry.load();
+
+    if (cache_file != null) {
+        return registry.save_cache_file(cache_file) ?
+                Posix.EXIT_SUCCESS : Posix.EXIT_FAILURE;
+    }
+
+    return registry.save_cache(!is_system) ?
+            Posix.EXIT_SUCCESS : Posix.EXIT_FAILURE;
+}
+
 int print_help(string[] argv) {
     print_usage(stdout);
     return Posix.EXIT_SUCCESS;
@@ -215,6 +290,8 @@ static const CommandEntry commands[]  = {
     { "watch", message_watch },
     { "restart", restart_daemon },
     { "version", print_version },
+    { "read-cache", read_cache },
+    { "write-cache", write_cache },
     { "help", print_help }
 };
 
@@ -229,6 +306,7 @@ void print_usage(FileStream stream) {
 }
 
 public int main(string[] argv) {
+    GLib.Intl.setlocale(GLib.LocaleCategory.ALL, "");
     GLib.Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GLIB_LOCALE_DIR);
     GLib.Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
 
@@ -239,6 +317,7 @@ public int main(string[] argv) {
     }
 
     string[] new_argv = argv[1:argv.length];
+    new_argv[0] = "%s %s".printf(program_name, new_argv[0]);
     for (int i = 0; i < commands.length; i++) {
         if (commands[i].name == argv[1])
             return commands[i].entry(new_argv);