[evolution] Bug 697858 - Slow message composer open



commit e69e552c994c3a9058bdf7b253ae02d5ec0cbe95
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 21 14:55:48 2014 +0100

    Bug 697858 - Slow message composer open

 e-util/e-spell-checker.c |  118 +++++++++++++++++++++++++++++++---------------
 e-util/e-spell-checker.h |    2 +
 shell/main.c             |    3 +
 3 files changed, 85 insertions(+), 38 deletions(-)
---
diff --git a/e-util/e-spell-checker.c b/e-util/e-spell-checker.c
index c781672..f312cff 100644
--- a/e-util/e-spell-checker.c
+++ b/e-util/e-spell-checker.c
@@ -36,15 +36,8 @@
 #define MAX_SUGGESTIONS 10
 
 struct _ESpellCheckerPrivate {
-       EnchantBroker *broker;
        GHashTable *active_dictionaries;
        GHashTable *dictionaries_cache;
-       gboolean dictionaries_loaded;
-
-       /* We retain ownership of the EnchantDict's since they
-        * have to be freed through enchant_broker_free_dict()
-        * and we also own the EnchantBroker. */
-       GHashTable *enchant_dicts;
 };
 
 enum {
@@ -75,6 +68,14 @@ G_DEFINE_TYPE_EXTENDED (
  * so it can be set as a default spell-checker to WebKit editors
  */
 
+
+/* We retain ownership of the EnchantDict's since they
+ * have to be freed through enchant_broker_free_dict()
+ * and we also own the EnchantBroker. */
+static GHashTable *global_enchant_dicts;
+static EnchantBroker *global_broker;
+G_LOCK_DEFINE_STATIC (global_memory);
+
 static gboolean
 spell_checker_enchant_dicts_foreach_cb (gpointer key,
                                         gpointer value,
@@ -358,15 +359,6 @@ spell_checker_finalize (GObject *object)
 
        priv = E_SPELL_CHECKER_GET_PRIVATE (object);
 
-       /* Freeing EnchantDicts requires help from EnchantBroker. */
-       g_hash_table_foreach_remove (
-               priv->enchant_dicts,
-               spell_checker_enchant_dicts_foreach_cb,
-               priv->broker);
-       g_hash_table_destroy (priv->enchant_dicts);
-
-       enchant_broker_free (priv->broker);
-
        g_hash_table_destroy (priv->active_dictionaries);
        g_hash_table_destroy (priv->dictionaries_cache);
 
@@ -425,7 +417,6 @@ e_spell_checker_init (ESpellChecker *checker)
 {
        GHashTable *active_dictionaries;
        GHashTable *dictionaries_cache;
-       GHashTable *enchant_dicts;
 
        active_dictionaries = g_hash_table_new_full (
                (GHashFunc) e_spell_dictionary_hash,
@@ -439,18 +430,10 @@ e_spell_checker_init (ESpellChecker *checker)
                (GDestroyNotify) NULL,
                (GDestroyNotify) g_object_unref);
 
-       enchant_dicts = g_hash_table_new_full (
-               (GHashFunc) g_str_hash,
-               (GEqualFunc) g_str_equal,
-               (GDestroyNotify) g_free,
-               (GDestroyNotify) NULL);
-
        checker->priv = E_SPELL_CHECKER_GET_PRIVATE (checker);
 
-       checker->priv->broker = enchant_broker_init ();
        checker->priv->active_dictionaries = active_dictionaries;
        checker->priv->dictionaries_cache = dictionaries_cache;
-       checker->priv->enchant_dicts = enchant_dicts;
 }
 
 /**
@@ -473,12 +456,26 @@ list_enchant_dicts (const gchar * const lang_tag,
                     const gchar * const provider_file,
                     gpointer user_data)
 {
-       ESpellChecker *checker = user_data;
+       EnchantBroker *broker = user_data;
        EnchantDict *enchant_dict;
 
-       enchant_dict = enchant_broker_request_dict (
-               checker->priv->broker, lang_tag);
+       enchant_dict = enchant_broker_request_dict (broker, lang_tag);
        if (enchant_dict != NULL) {
+               g_hash_table_insert (
+                       global_enchant_dicts,
+                       g_strdup (lang_tag), enchant_dict);
+       }
+}
+
+static void
+copy_enchant_dicts (gpointer pcode,
+                   gpointer pdict,
+                   gpointer user_data)
+{
+       EnchantDict *enchant_dict = pdict;
+       ESpellChecker *checker = user_data;
+
+       if (enchant_dict) {
                ESpellDictionary *dictionary;
                const gchar *code;
 
@@ -491,11 +488,57 @@ list_enchant_dicts (const gchar * const lang_tag,
                g_hash_table_insert (
                        checker->priv->dictionaries_cache,
                        (gpointer) code, dictionary);
+       }
+}
 
-               g_hash_table_insert (
-                       checker->priv->enchant_dicts,
-                       g_strdup (code), enchant_dict);
+static void
+e_spell_checker_init_global_memory (void)
+{
+       G_LOCK (global_memory);
+
+       if (!global_broker) {
+               global_broker = enchant_broker_init ();
+               global_enchant_dicts = g_hash_table_new_full (
+                       (GHashFunc) g_str_hash,
+                       (GEqualFunc) g_str_equal,
+                       (GDestroyNotify) g_free,
+                       (GDestroyNotify) NULL);
+
+               enchant_broker_list_dicts (
+                       global_broker,
+                       list_enchant_dicts, global_broker);
        }
+
+       G_UNLOCK (global_memory);
+}
+
+/**
+ * e_spell_checker_free_global_memory:
+ *
+ * Frees global memory used by the ESpellChecker. This should be called at
+ * the end of main(), to avoid memory leaks.
+ *
+ * Since: 3.14
+ **/
+void
+e_spell_checker_free_global_memory (void)
+{
+       G_LOCK (global_memory);
+
+       if (global_enchant_dicts) {
+               /* Freeing EnchantDicts requires help from EnchantBroker. */
+               g_hash_table_foreach_remove (
+                       global_enchant_dicts,
+                       spell_checker_enchant_dicts_foreach_cb,
+                       global_broker);
+               g_hash_table_destroy (global_enchant_dicts);
+               global_enchant_dicts = NULL;
+
+               enchant_broker_free (global_broker);
+               global_broker = NULL;
+       }
+
+       G_UNLOCK (global_memory);
 }
 
 /**
@@ -516,11 +559,9 @@ e_spell_checker_list_available_dicts (ESpellChecker *checker)
 
        g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
 
-       if (!checker->priv->dictionaries_loaded) {
-               enchant_broker_list_dicts (
-                       checker->priv->broker,
-                       list_enchant_dicts, checker);
-               checker->priv->dictionaries_loaded = TRUE;
+       if (g_hash_table_size (checker->priv->dictionaries_cache) == 0) {
+               e_spell_checker_init_global_memory ();
+               g_hash_table_foreach (global_enchant_dicts, copy_enchant_dicts, checker);
        }
 
        list = g_hash_table_get_values (checker->priv->dictionaries_cache);
@@ -584,8 +625,9 @@ e_spell_checker_get_enchant_dict (ESpellChecker *checker,
        g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
        g_return_val_if_fail (language_code != NULL, NULL);
 
-       return g_hash_table_lookup (
-               checker->priv->enchant_dicts, language_code);
+       e_spell_checker_init_global_memory ();
+
+       return g_hash_table_lookup (global_enchant_dicts, language_code);
 }
 
 gboolean
diff --git a/e-util/e-spell-checker.h b/e-util/e-spell-checker.h
index 48303d6..d986e84 100644
--- a/e-util/e-spell-checker.h
+++ b/e-util/e-spell-checker.h
@@ -61,6 +61,8 @@ struct _ESpellCheckerClass {
 };
 
 GType          e_spell_checker_get_type        (void) G_GNUC_CONST;
+void           e_spell_checker_free_global_memory
+                                               (void);
 ESpellChecker *        e_spell_checker_new             (void);
 GList *                e_spell_checker_list_available_dicts
                                                (ESpellChecker *checker);
diff --git a/shell/main.c b/shell/main.c
index 972c0bd..fb066c2 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -72,6 +72,8 @@
 #include <libical/ical.h>
 #endif
 
+#include "e-util/e-util.h"
+
 #define APPLICATION_ID "org.gnome.Evolution"
 
 /* STABLE_VERSION is only defined for development versions. */
@@ -638,6 +640,7 @@ exit:
        gtk_accel_map_save (e_get_accels_filename ());
 
        e_util_cleanup_settings ();
+       e_spell_checker_free_global_memory ();
 
        return 0;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]