diff options
author | fujiwarat <takao.fujiwara1@gmail.com> | 2016-02-10 11:41:34 +0900 |
---|---|---|
committer | fujiwarat <takao.fujiwara1@gmail.com> | 2016-02-10 11:41:34 +0900 |
commit | 97e28cc04b4601295b22a0aa8e9e21ed4e0758a1 (patch) | |
tree | 8b20c239b3ffcc131aa63ea8b94376d68ef8d5f3 | |
parent | 706ba01504a0c48391360a236d7c7aa8e0057753 (diff) | |
download | ibus-97e28cc04b4601295b22a0aa8e9e21ed4e0758a1.tar.gz |
src: Use cache file for compose table for launching time
Save the cache files of compose files under $HOME/.cache/ibus/compose
for the performance.
Load a compose file with the following order:
1. $HOME/.config/ibus/Compose
2. $HOME/.config/gtk-3.0/Compose
3. $HOME/.XCompose
4. /usr/share/X11/locale/$locale/Compose
Check the system compose files of "el_GR", "fi_FI", "pt_BR" only for the
performance because other compose files just load "en_US" compose file.
BUG=https://bugzilla.gnome.org/show_bug.cgi?id=721120
R=Shawn.P.Huang@gmail.com
Review URL: https://codereview.appspot.com/286040043
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/ibuscomposetable.c | 361 | ||||
-rw-r--r-- | src/ibuscomposetable.h | 20 | ||||
-rw-r--r-- | src/ibusenginesimple.c | 133 |
5 files changed, 463 insertions, 62 deletions
diff --git a/configure.ac b/configure.ac index 59ca9347..57cf16ec 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ # ibus - The Input Bus # # Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com> +# Copyright (c) 2015-2016 Takao Fujiwara <takao.fujiwara1@gmail.com> # Copyright (c) 2007-2016 Red Hat, Inc. # # This library is free software; you can redistribute it and/or @@ -257,6 +258,15 @@ else enable_xim="no (disabled, use --enable-xim to enable)" fi +if $PKG_CONFIG --exists x11; then + X11_PREFIX="`$PKG_CONFIG --variable=prefix x11`" +elif test x"$prefix" != xNONE; then + X11_PREFIX="$prefix" +else + X11_PREFIX="$ac_default_prefix" +fi +AC_SUBST(X11_PREFIX) + if test x"$enable_wayland" = x"yes"; then # Check for wayland PKG_CHECK_MODULES(WAYLAND, [ diff --git a/src/Makefile.am b/src/Makefile.am index 1c161a84..adaebe98 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,6 +53,7 @@ AM_CPPFLAGS = \ -DIBUS_DISABLE_DEPRECATION_WARNINGS \ -DIBUS_COMPILATION \ -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\" \ + -DX11_DATA_PREFIX=\"$(X11_PREFIX)\" \ $(NULL) # ibus library diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c index 17da93b8..86c9314c 100644 --- a/src/ibuscomposetable.c +++ b/src/ibuscomposetable.c @@ -19,12 +19,6 @@ * USA */ -/* If you copy libX11/nls/??/Compose.pre in xorg git HEAD to - * /usr/share/X11/locale/??/Compose , need to convert: - * # sed -e 's/^XCOMM/#/' -e 's|X11_LOCALEDATADIR|/usr/share/X11/locale|' - * Compose.pre > /usr/share/X11/locale/foo/Compose - */ - #include <glib.h> #include <glib/gstdio.h> #include <locale.h> @@ -40,6 +34,9 @@ #include "ibusenginesimpleprivate.h" +#define IBUS_COMPOSE_TABLE_MAGIC "IBusComposeTable" +#define IBUS_COMPOSE_TABLE_VERSION (2) + typedef struct { gunichar *sequence; gunichar value[2]; @@ -469,10 +466,282 @@ ibus_compose_list_print (GList *compose_list, total_size, max_compose_len, n_index_stride); } +/* Implemented from g_str_hash() */ +static guint32 +ibus_compose_table_data_hash (gconstpointer v, + int length) +{ + const guint16 *p, *head; + unsigned char c; + guint32 h = 5381; + + for (p = v, head = v; (p - head) < length; p++) { + c = 0x00ff & (*p >> 8); + h = (h << 5) + h + c; + c = 0x00ff & *p; + h = (h << 5) + h + c; + } + + return h; +} + +static gchar * +ibus_compose_hash_get_cache_path (guint32 hash) +{ + gchar *basename = NULL; + gchar *dir = NULL; + gchar *path = NULL; + + basename = g_strdup_printf ("%08x.cache", hash); + + dir = g_build_filename (g_get_user_cache_dir (), + "ibus", "compose", NULL); + path = g_build_filename (dir, basename, NULL); + if (g_mkdir_with_parents (dir, 0755) != 0) { + g_warning ("Failed to mkdir %s", dir); + g_free (path); + path = NULL; + } + + g_free (dir); + g_free (basename); + + return path; +} + +static GVariant * +ibus_compose_table_serialize (IBusComposeTable *compose_table) +{ + const gchar *header = IBUS_COMPOSE_TABLE_MAGIC; + const guint16 version = IBUS_COMPOSE_TABLE_VERSION; + guint16 max_seq_len; + guint16 index_stride; + guint16 n_seqs; + GVariant *variant_data; + GVariant *variant_table; + + g_return_val_if_fail (compose_table != NULL, NULL); + g_return_val_if_fail (compose_table->data != NULL, NULL); + + max_seq_len = compose_table->max_seq_len; + index_stride = max_seq_len + 2; + n_seqs = compose_table->n_seqs; + + g_return_val_if_fail (max_seq_len > 0, NULL); + g_return_val_if_fail (n_seqs > 0, NULL); + + variant_data = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT16, + compose_table->data, + index_stride * n_seqs, + sizeof (guint16)); + if (variant_data == NULL) { + g_warning ("Could not change compose data to GVariant."); + return NULL; + } + variant_table = g_variant_new ("(sqqqv)", + header, + version, + max_seq_len, + n_seqs, + variant_data); + return g_variant_ref_sink (variant_table); +} + +static gint +ibus_compose_table_find (gconstpointer data1, + gconstpointer data2) +{ + const IBusComposeTable *compose_table = (const IBusComposeTable *) data1; + guint32 hash = (guint32) GPOINTER_TO_INT (data2); + return compose_table->id != hash; +} + +static IBusComposeTable * +ibus_compose_table_deserialize (const gchar *contents, + gsize length) +{ + IBusComposeTable *retval = NULL; + GVariantType *type; + GVariant *variant_data = NULL; + GVariant *variant_table = NULL; + const gchar *header = NULL; + guint16 version = 0; + guint16 max_seq_len = 0; + guint16 n_seqs = 0; + guint16 index_stride; + gconstpointer data = NULL; + gsize data_length = 0; + + g_return_val_if_fail (contents != NULL, NULL); + g_return_val_if_fail (length > 0, NULL); + + /* Check the cache version at first before load whole the file content. */ + type = g_variant_type_new ("(sq)"); + variant_table = g_variant_new_from_data (type, + contents, + length, + FALSE, + NULL, + NULL); + g_variant_type_free (type); + + if (variant_table == NULL) { + g_warning ("cache is broken."); + goto out_load_cache; + } + + g_variant_ref_sink (variant_table); + g_variant_get (variant_table, "(&sq)", &header, &version); + + if (g_strcmp0 (header, IBUS_COMPOSE_TABLE_MAGIC) != 0) { + g_warning ("cache is not IBusComposeTable."); + goto out_load_cache; + } + + if (version != IBUS_COMPOSE_TABLE_VERSION) { + g_warning ("cache version is different: %u != %u", + version, IBUS_COMPOSE_TABLE_VERSION); + goto out_load_cache; + } + + version = 0; + header = NULL; + g_variant_unref (variant_table); + variant_table = NULL; + + type = g_variant_type_new ("(sqqqv)"); + variant_table = g_variant_new_from_data (type, + contents, + length, + FALSE, + NULL, + NULL); + g_variant_type_free (type); + + if (variant_table == NULL) { + g_warning ("cache is broken."); + goto out_load_cache; + } + + g_variant_ref_sink (variant_table); + g_variant_get (variant_table, "(&sqqqv)", + NULL, + NULL, + &max_seq_len, + &n_seqs, + &variant_data); + + if (max_seq_len == 0 || n_seqs == 0) { + g_warning ("cache size is not correct %d %d", max_seq_len, n_seqs); + goto out_load_cache; + } + + data = g_variant_get_fixed_array (variant_data, + &data_length, + sizeof (guint16)); + index_stride = max_seq_len + 2; + + if (data == NULL) { + g_warning ("cache data is null."); + goto out_load_cache; + } + if (data_length != (gsize) index_stride * n_seqs) { + g_warning ("cache size is not correct %d %d %lu", + max_seq_len, n_seqs, data_length); + goto out_load_cache; + } + + retval = g_new0 (IBusComposeTable, 1); + retval->data = g_new (guint16, data_length); + memcpy (retval->data, data, data_length * sizeof (guint16)); + retval->max_seq_len = max_seq_len; + retval->n_seqs = n_seqs; + + +out_load_cache: + if (variant_data) + g_variant_unref (variant_data); + if (variant_table) + g_variant_unref (variant_table); + return retval; +} + +static IBusComposeTable * +ibus_compose_table_load_cache (const gchar *compose_file) +{ + IBusComposeTable *retval = NULL; + guint32 hash; + gchar *path = NULL; + gchar *contents = NULL; + GStatBuf original_buf; + GStatBuf cache_buf; + gsize length = 0; + GError *error = NULL; + + hash = g_str_hash (compose_file); + if ((path = ibus_compose_hash_get_cache_path (hash)) == NULL) + return NULL; + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + goto out_load_cache; + + g_stat (compose_file, &original_buf); + g_stat (path, &cache_buf); + if (original_buf.st_mtime > cache_buf.st_mtime) + goto out_load_cache; + if (!g_file_get_contents (path, &contents, &length, &error)) { + g_warning ("Failed to get cache content %s: %s", path, error->message); + g_error_free (error); + goto out_load_cache; + } + + retval = ibus_compose_table_deserialize (contents, length); + if (retval == NULL) + g_warning ("Failed to load the cache file: %s", path); + else + retval->id = hash; + + +out_load_cache: + g_free (contents); + g_free (path); + return retval; +} + +static void +ibus_compose_table_save_cache (IBusComposeTable *compose_table) +{ + gchar *path = NULL; + GVariant *variant_table = NULL; + const gchar *contents = NULL; + GError *error = NULL; + gsize length = 0; + + if ((path = ibus_compose_hash_get_cache_path (compose_table->id)) == NULL) + return; + + variant_table = ibus_compose_table_serialize (compose_table); + if (variant_table == NULL) { + g_warning ("Failed to serialize compose table %s", path); + goto out_save_cache; + } + contents = g_variant_get_data (variant_table); + length = g_variant_get_size (variant_table); + if (!g_file_set_contents (path, contents, length, &error)) { + g_warning ("Failed to save compose table %s: %s", path, error->message); + g_error_free (error); + goto out_save_cache; + } + +out_save_cache: + g_variant_unref (variant_table); + g_free (path); +} + static IBusComposeTable * ibus_compose_table_new_with_list (GList *compose_list, int max_compose_len, - int n_index_stride) + int n_index_stride, + guint32 hash) { guint length; guint n = 0; @@ -506,6 +775,7 @@ ibus_compose_table_new_with_list (GList *compose_list, retval->data = ibus_compose_seqs; retval->max_seq_len = max_compose_len; retval->n_seqs = length; + retval->id = hash; return retval; } @@ -546,10 +816,85 @@ ibus_compose_table_new_with_file (const gchar *compose_file) compose_table = ibus_compose_table_new_with_list ( compose_list, max_compose_len, - n_index_stride); + n_index_stride, + g_str_hash (compose_file)); g_list_free_full (compose_list, (GDestroyNotify) ibus_compose_list_element_free); return compose_table; } + +/* if ibus_compose_seqs[N - 1] is an outputed compose character, + * ibus_compose_seqs[N * 2 - 1] is also an outputed compose character. + * and ibus_compose_seqs[0] to ibus_compose_seqs[0 + N - 3] are the + * sequences and call ibus_engine_simple_add_table: + * ibus_engine_simple_add_table(engine, ibus_compose_seqs, + * N - 2, G_N_ELEMENTS(ibus_compose_seqs) / N) + * The compose sequences are allowed within G_MAXUINT16 + */ +GSList * +ibus_compose_table_list_add_array (GSList *compose_tables, + const guint16 *data, + gint max_seq_len, + gint n_seqs) +{ + guint32 hash; + IBusComposeTable *compose_table; + int n_index_stride = max_seq_len + 2; + int length = n_index_stride * n_seqs; + int i; + guint16 *ibus_compose_seqs = NULL; + + g_return_val_if_fail (data != NULL, compose_tables); + g_return_val_if_fail (max_seq_len <= IBUS_MAX_COMPOSE_LEN, compose_tables); + + hash = ibus_compose_table_data_hash (data, length); + + if (g_slist_find_custom (compose_tables, + GINT_TO_POINTER (hash), + ibus_compose_table_find) != NULL) { + return compose_tables; + } + + ibus_compose_seqs = g_new0 (guint16, length); + for (i = 0; i < length; i++) + ibus_compose_seqs[i] = data[i]; + + compose_table = g_new (IBusComposeTable, 1); + compose_table->data = ibus_compose_seqs; + compose_table->max_seq_len = max_seq_len; + compose_table->n_seqs = n_seqs; + compose_table->id = hash; + + return g_slist_prepend (compose_tables, compose_table); +} + +GSList * +ibus_compose_table_list_add_file (GSList *compose_tables, + const gchar *compose_file) +{ + guint32 hash; + IBusComposeTable *compose_table; + + g_return_val_if_fail (compose_file != NULL, compose_tables); + + hash = g_str_hash (compose_file); + if (g_slist_find_custom (compose_tables, + GINT_TO_POINTER (hash), + ibus_compose_table_find) != NULL) { + return compose_tables; + } + + compose_table = ibus_compose_table_load_cache (compose_file); + if (compose_table != NULL) + return g_slist_prepend (compose_tables, compose_table); + + if ((compose_table = ibus_compose_table_new_with_file (compose_file)) + == NULL) { + return compose_tables; + } + + ibus_compose_table_save_cache (compose_table); + return g_slist_prepend (compose_tables, compose_table); +} diff --git a/src/ibuscomposetable.h b/src/ibuscomposetable.h index 3172d74f..8346df6d 100644 --- a/src/ibuscomposetable.h +++ b/src/ibuscomposetable.h @@ -25,13 +25,6 @@ #include <glib.h> -/* if ibus_compose_seqs[N - 1] is an outputed compose character, - * ibus_compose_seqs[N * 2 - 1] is also an outputed compose character. - * and ibus_compose_seqs[0] to ibus_compose_seqs[0 + N - 3] are the - * sequences and call ibus_engine_simple_add_table: - * ibus_engine_simple_add_table(engine, ibus_compose_seqs, - * N - 2, G_N_ELEMENTS(ibus_compose_seqs) / N) - * The compose sequences are allowed within G_MAXUINT16 */ G_BEGIN_DECLS @@ -40,9 +33,10 @@ typedef struct _IBusComposeTableCompact IBusComposeTableCompact; struct _IBusComposeTable { - const guint16 *data; + guint16 *data; gint max_seq_len; gint n_seqs; + guint32 id; }; struct _IBusComposeTableCompact @@ -54,6 +48,16 @@ struct _IBusComposeTableCompact }; IBusComposeTable *ibus_compose_table_new_with_file (const gchar *compose_file); +GSList *ibus_compose_table_list_add_array + (GSList + *compose_tables, + const guint16 + *data, + gint max_seq_len, + gint n_seqs); +GSList *ibus_compose_table_list_add_file (GSList + *compose_tables, + const gchar *compose_file); G_BEGIN_DECLS #endif diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c index b8190c64..1b688b09 100644 --- a/src/ibusenginesimple.c +++ b/src/ibusenginesimple.c @@ -41,12 +41,11 @@ #include <memory.h> #include <stdlib.h> -#define X11_DATADIR "/usr/share/X11/locale" +#define X11_DATADIR X11_DATA_PREFIX "/share/X11/locale" #define IBUS_ENGINE_SIMPLE_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE_SIMPLE, IBusEngineSimplePrivate)) struct _IBusEngineSimplePrivate { - GSList *tables; guint16 compose_buffer[IBUS_MAX_COMPOSE_LEN + 1]; gunichar tentative_match; gint tentative_match_len; @@ -67,6 +66,8 @@ const IBusComposeTableCompact ibus_compose_table_compact = { 6 }; +static GSList *global_tables; + static const guint16 ibus_compose_ignore[] = { IBUS_KEY_Shift_L, IBUS_KEY_Shift_R, @@ -127,11 +128,6 @@ ibus_engine_simple_init (IBusEngineSimple *simple) static void ibus_engine_simple_destroy (IBusEngineSimple *simple) { - IBusEngineSimplePrivate *priv = simple->priv; - - g_slist_free_full (priv->tables, g_free); - priv->tables = NULL; - IBUS_OBJECT_CLASS(ibus_engine_simple_parent_class)->destroy ( IBUS_OBJECT (simple)); } @@ -315,9 +311,9 @@ compare_seq (const void *key, const void *value) static gboolean -check_table (IBusEngineSimple *simple, - IBusComposeTable *table, - gint n_compose) +check_table (IBusEngineSimple *simple, + const IBusComposeTable *table, + gint n_compose) { // g_debug("check_table"); IBusEngineSimplePrivate *priv = simple->priv; @@ -904,7 +900,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, } } else { - GSList *list = priv->tables; + GSList *list = global_tables; while (list) { if (check_table (simple, (IBusComposeTable *)list->data, @@ -950,51 +946,102 @@ ibus_engine_simple_add_table (IBusEngineSimple *simple, gint max_seq_len, gint n_seqs) { - IBusEngineSimplePrivate *priv = simple->priv; - g_return_if_fail (IBUS_IS_ENGINE_SIMPLE (simple)); - g_return_if_fail (data != NULL); - g_return_if_fail (max_seq_len <= IBUS_MAX_COMPOSE_LEN); - - IBusComposeTable *table = g_new (IBusComposeTable, 1); - table->data = data; - table->max_seq_len = max_seq_len; - table->n_seqs = n_seqs; - priv->tables = g_slist_prepend (priv->tables, table); + global_tables = ibus_compose_table_list_add_array (global_tables, + data, + max_seq_len, + n_seqs); } gboolean ibus_engine_simple_add_table_by_locale (IBusEngineSimple *simple, const gchar *locale) { - const gchar *_locale = locale; - gchar **langs = NULL; - gchar **l = NULL; + /* Now ibus_engine_simple_add_compose_file() always returns TRUE. */ + gboolean retval = TRUE; gchar *path = NULL; + const gchar *home; + const gchar *_locale; + gchar **langs = NULL; + gchar **lang = NULL; + gchar * const sys_langs[] = { "el_gr", "fi_fi", "pt_br", NULL }; + gchar * const *sys_lang = NULL; + + if (locale == NULL) { + path = g_build_filename (g_get_user_config_dir (), + "ibus", "Compose", NULL); + if (g_file_test (path, G_FILE_TEST_EXISTS)) { + ibus_engine_simple_add_compose_file (simple, path); + g_free (path); + return retval; + } + g_free (path); + path = NULL; + + path = g_build_filename (g_get_user_config_dir (), + "gtk-3.0", "Compose", NULL); + if (g_file_test (path, G_FILE_TEST_EXISTS)) { + ibus_engine_simple_add_compose_file (simple, path); + g_free (path); + return retval; + } + g_free (path); + path = NULL; + + home = g_get_home_dir (); + if (home == NULL) + return retval; + + path = g_build_filename (home, ".XCompose", NULL); + if (g_file_test (path, G_FILE_TEST_EXISTS)) { + ibus_engine_simple_add_compose_file (simple, path); + g_free (path); + return retval; + } + g_free (path); + path = NULL; - if (_locale == NULL) { _locale = g_getenv ("LC_CTYPE"); - if (_locale == NULL) { + if (_locale == NULL) _locale = g_getenv ("LANG"); - } - if (_locale == NULL) { + if (_locale == NULL) _locale = "C"; - } + /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=751826 */ langs = g_get_locale_variants (_locale); - for (l = langs; *l; l++) { - if (g_str_has_prefix (*l, "en_US")) + + for (lang = langs; *lang; lang++) { + if (g_str_has_prefix (*lang, "en_US")) break; - if (g_strcmp0 (*l, "C") == 0) + if (**lang == 'C') break; - path = g_build_filename (X11_DATADIR, *l, "Compose", NULL); + + /* Other languages just include en_us compose table. */ + for (sys_lang = sys_langs; *sys_lang; sys_lang++) { + if (g_ascii_strncasecmp (*lang, *sys_lang, + strlen (*sys_lang)) == 0) { + path = g_build_filename (X11_DATADIR, + *lang, "Compose", NULL); + break; + } + } + + if (path == NULL) + continue; + if (g_file_test (path, G_FILE_TEST_EXISTS)) break; g_free (path); path = NULL; } + g_strfreev (langs); + + if (path != NULL) + ibus_engine_simple_add_compose_file (simple, path); + g_free (path); + path = NULL; } else { path = g_build_filename (X11_DATADIR, locale, "Compose", NULL); do { @@ -1003,27 +1050,21 @@ ibus_engine_simple_add_table_by_locale (IBusEngineSimple *simple, g_free (path); path = NULL; } while (0); + if (path == NULL) + return retval; + ibus_engine_simple_add_compose_file (simple, path); } - if (path == NULL) - return FALSE; - - return ibus_engine_simple_add_compose_file (simple, path); + return retval; } gboolean ibus_engine_simple_add_compose_file (IBusEngineSimple *simple, const gchar *compose_file) { - IBusEngineSimplePrivate *priv = simple->priv; - IBusComposeTable *table; - - g_assert (compose_file != NULL); - - table = ibus_compose_table_new_with_file (compose_file); - if (table == NULL) - return FALSE; + g_return_val_if_fail (IBUS_IS_ENGINE_SIMPLE (simple), TRUE); - priv->tables = g_slist_prepend (priv->tables, table); + global_tables = ibus_compose_table_list_add_file (global_tables, + compose_file); return TRUE; } |