diff options
Diffstat (limited to 'bus/registry.c')
-rw-r--r-- | bus/registry.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/bus/registry.c b/bus/registry.c new file mode 100644 index 0000000..cdc1aa7 --- /dev/null +++ b/bus/registry.c @@ -0,0 +1,447 @@ +/* vim:set et sts=4: */ +/* bus - The Input Bus + * Copyright (C) 2008-2009 Huang Peng <shawn.p.huang@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include <glib/gstdio.h> +#include <gio/gio.h> +#include <stdlib.h> +#include "registry.h" + +enum { + LAST_SIGNAL, +}; + +// static guint _signals[LAST_SIGNAL] = { 0 }; + +/* functions prototype */ +static void bus_registry_class_init (BusRegistryClass *klass); +static void bus_registry_init (BusRegistry *registry); +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); + +static IBusObjectClass *parent_class = NULL; + +GType +bus_registry_get_type (void) +{ + static GType type = 0; + + static const GTypeInfo type_info = { + sizeof (BusRegistryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) bus_registry_class_init, + NULL, /* class finalize */ + NULL, /* class data */ + sizeof (BusRegistry), + 0, + (GInstanceInitFunc) bus_registry_init, + }; + + if (type == 0) { + type = g_type_register_static (IBUS_TYPE_OBJECT, + "BusRegistry", + &type_info, + (GTypeFlags)0); + } + + return type; +} + + +static void +bus_registry_class_init (BusRegistryClass *klass) +{ + IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass); + + parent_class = (IBusObjectClass *) g_type_class_peek_parent (klass); + + 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); + + 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) { + IBusComponent *comp = (IBusComponent *)p->data; + GList *p1; + + for (p1 = comp->engines; p1 != NULL; p1 = p1->next) { + IBusEngineDesc *desc = (IBusEngineDesc *)p1->data; + g_hash_table_insert (registry->engine_table, desc->name, desc); + g_object_set_data ((GObject *)desc, "component", comp); + } + } +} + +static void +bus_registry_remove_all (BusRegistry *registry) +{ + g_list_foreach (registry->observed_paths, (GFunc) g_object_unref, NULL); + g_list_free (registry->observed_paths); + registry->observed_paths = NULL; + + g_list_foreach (registry->components, (GFunc) g_object_unref, NULL); + g_list_free (registry->components); + registry->components = NULL; + + g_hash_table_remove_all (registry->engine_table); +} + +static void +bus_registry_destroy (BusRegistry *registry) +{ + bus_registry_remove_all (registry); + + g_hash_table_destroy (registry->engine_table); + registry->engine_table = NULL; + + IBUS_OBJECT_CLASS (parent_class)->destroy (IBUS_OBJECT (registry)); +} + + +static void +bus_registry_load (BusRegistry *registry) +{ + g_assert (BUS_IS_REGISTRY (registry)); + + gchar *dirname; + gchar *homedir; + IBusObservedPath *path; + + dirname = g_build_filename (PKGDATADIR, "component", NULL); + + path = ibus_observed_path_new (dirname, TRUE); + registry->observed_paths = g_list_append (registry->observed_paths, path); + + bus_registry_load_in_dir (registry, dirname); + + g_free (dirname); + + homedir = (gchar *) g_getenv ("HOME"); + if (!homedir) + homedir = (gchar *) g_get_home_dir (); + dirname = g_build_filename (homedir, ".ibus", "component", NULL); + + path = ibus_observed_path_new (dirname, TRUE); + registry->observed_paths = g_list_append (registry->observed_paths, path); + + if (g_file_test(dirname, G_FILE_TEST_EXISTS)) { + bus_registry_load_in_dir (registry, dirname); + } + + g_free (dirname); +} + + +#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", "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) { + 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) { + registry->components = g_list_append (registry->components, component); + } + } + + 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 ((IBusComponent *)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; + + cachedir = g_build_filename (g_get_user_cache_dir (), "ibus", 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 ((IBusComponent *)p->data, + output, 2); + } + g_string_append_indent (output, 1); + g_string_append (output, "</components>\n"); + } + + g_string_append (output, "</ibus-registry>\n"); + fwrite (output->str, output->len, 1, pf); + g_string_free (output, TRUE); + fclose (pf); + return TRUE; +} + +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); + registry->components = g_list_append (registry->components, component); + + 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 +_component_is_name (IBusComponent *component, + const gchar *name) +{ + g_assert (IBUS_IS_COMPONENT (component)); + g_assert (name); + + return g_strcmp0 (component->name, name); +} + +IBusComponent * +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)_component_is_name); + if (p) { + return (IBusComponent *)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); +} + + +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); +} + + +BusFactoryProxy * +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); + + IBusComponent *component; + BusFactoryProxy *factory; + + component = bus_registry_lookup_component_by_name (registry, name); + + if (component == NULL) { + return NULL; + } + + if (g_strcmp0 (old_name, "") != 0) { + factory = bus_factory_proxy_get_from_component (component); + + if (factory != NULL) { + ibus_object_destroy ((IBusObject *)factory); + } + } + + if (g_strcmp0 (new_name, "") != 0) { + factory = bus_factory_proxy_new (component, NULL); + return factory; + } + + return NULL; +} |