[evolution/webkit-composer: 120/147] ESpellDictionary: Keep a weak ref on the ESpellChecker.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/webkit-composer: 120/147] ESpellDictionary: Keep a weak ref on the ESpellChecker.
- Date: Mon, 21 Jan 2013 02:20:13 +0000 (UTC)
commit b96825baadd3e7461f36163eab27fc804deee435
Author: Matthew Barnes <mbarnes redhat com>
Date: Wed Jan 16 17:43:30 2013 -0500
ESpellDictionary: Keep a weak ref on the ESpellChecker.
Avoids a reference cycle, since ESpellChecker keeps a strong reference
on all ESpellDictionary instances.
This however changes ownership semantics on EnchantDict, since an
EnchantBroker is needed to free the EnchantDict (for some reason) and
ESpellChecker owns the EnchantBroker. It must therefore also own all
the EnchantDicts.
Add e_spell_checker_get_enchant_dict(), which returns an EnchantDict
for the given language code. ESpellDictionary will have to use this
to fetch an EnchantDict from the ESpellChecker as needed. This also
eliminates e_spell_checker_free_dict().
In addition, rename e_spell_dictionary_get_parent_checker() to
e_spell_dictionary_ref_spell_checker() and have it return a new
reference by way of g_weak_ref_get().
doc/reference/libeutil/libeutil-sections.txt | 4 +-
e-util/e-spell-checker.c | 89 +++++++++++++++---
e-util/e-spell-checker.h | 5 +-
e-util/e-spell-dictionary.c | 134 ++++++++++++++++++--------
e-util/e-spell-dictionary.h | 6 +-
5 files changed, 179 insertions(+), 59 deletions(-)
---
diff --git a/doc/reference/libeutil/libeutil-sections.txt b/doc/reference/libeutil/libeutil-sections.txt
index d7d4522..8571db9 100644
--- a/doc/reference/libeutil/libeutil-sections.txt
+++ b/doc/reference/libeutil/libeutil-sections.txt
@@ -3659,9 +3659,9 @@ ESpellChecker
e_spell_checker_instance
e_spell_checker_list_available_dicts
e_spell_checker_ref_dictionary
+e_spell_checker_get_enchant_dict
e_spell_checker_set_active_dictionaries
e_spell_checker_get_active_dictionaries
-e_spell_checker_free_dict
e_spell_checker_learn_word
e_spell_checker_ignore_word
<SUBSECTION Standard>
@@ -3687,12 +3687,12 @@ e_spell_dictionary_equal
e_spell_dictionary_compare
e_spell_dictionary_get_name
e_spell_dictionary_get_code
+e_spell_dictionary_ref_spell_checker
e_spell_dictionary_check
e_spell_dictionary_learn_word
e_spell_dictionary_ignore_word
e_spell_dictionary_get_suggestions
e_spell_dictionary_store_correction
-e_spell_dictionary_get_parent_checker
<SUBSECTION Standard>
E_SPELL_DICTIONARY
E_IS_SPELL_DICTIONARY
diff --git a/e-util/e-spell-checker.c b/e-util/e-spell-checker.c
index 306b0eb..7b66e4b 100644
--- a/e-util/e-spell-checker.c
+++ b/e-util/e-spell-checker.c
@@ -36,6 +36,11 @@ struct _ESpellCheckerPrivate {
EnchantBroker *broker;
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 {
@@ -66,6 +71,19 @@ G_DEFINE_TYPE_EXTENDED (
* so it can be set as a default spell-checker to WebKit editors
*/
+static gboolean
+spell_checker_enchant_dicts_foreach_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ EnchantDict *enchant_dict = value;
+ EnchantBroker *enchant_broker = user_data;
+
+ enchant_broker_free_dict (enchant_broker, enchant_dict);
+
+ return TRUE;
+}
+
static void
wksc_check_spelling (WebKitSpellChecker *webkit_checker,
const gchar *word,
@@ -310,14 +328,35 @@ spell_checker_dispose (GObject *object)
g_list_free_full (priv->active, g_object_unref);
priv->active = NULL;
- enchant_broker_free (priv->broker);
- priv->broker = NULL;
+ g_hash_table_remove_all (priv->dictionaries_cache);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_spell_checker_parent_class)->dispose (object);
}
static void
+spell_checker_finalize (GObject *object)
+{
+ ESpellCheckerPrivate *priv;
+
+ priv = E_SPELL_CHECKER_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->dictionaries_cache);
+
+ /* 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);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_spell_checker_parent_class)->finalize (object);
+}
+
+static void
e_spell_checker_class_init (ESpellCheckerClass *class)
{
GObjectClass *object_class;
@@ -328,6 +367,7 @@ e_spell_checker_class_init (ESpellCheckerClass *class)
object_class->set_property = spell_checker_set_property;
object_class->get_property = spell_checker_get_property;
object_class->dispose = spell_checker_dispose;
+ object_class->finalize = spell_checker_finalize;
g_object_class_install_property (
object_class,
@@ -355,6 +395,7 @@ static void
e_spell_checker_init (ESpellChecker *checker)
{
GHashTable *dictionaries_cache;
+ GHashTable *enchant_dicts;
dictionaries_cache = g_hash_table_new_full (
(GHashFunc) g_str_hash,
@@ -362,10 +403,17 @@ 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->dictionaries_cache = dictionaries_cache;
+ checker->priv->enchant_dicts = enchant_dicts;
}
ESpellChecker *
@@ -394,12 +442,19 @@ list_enchant_dicts (const gchar * const lang_tag,
ESpellDictionary *dictionary;
const gchar *code;
+ /* Note that we retain ownership of the EnchantDict.
+ * Since EnchantDict is not reference counted, we're
+ * merely loaning the pointer to ESpellDictionary. */
dictionary = e_spell_dictionary_new (checker, enchant_dict);
code = e_spell_dictionary_get_code (dictionary);
g_hash_table_insert (
checker->priv->dictionaries_cache,
(gpointer) code, dictionary);
+
+ g_hash_table_insert (
+ checker->priv->enchant_dicts,
+ g_strdup (code), enchant_dict);
}
}
@@ -474,6 +529,26 @@ e_spell_checker_ref_dictionary (ESpellChecker *checker,
}
/**
+ * e_spell_checker_get_enchant_dict:
+ * @checker: an #ESpellChecker
+ * @language_code: language code of a dictionary, or %NULL
+ *
+ * Returns the #EnchantDict for @language_code, or %NULL if there is none.
+ *
+ * Returns: the #EnchantDict for @language_code, or %NULL
+ **/
+EnchantDict *
+e_spell_checker_get_enchant_dict (ESpellChecker *checker,
+ const gchar *language_code)
+{
+ 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_get_active_dictionaries:
* @checker: an #ESpellChecker
*
@@ -509,16 +584,6 @@ e_spell_checker_set_active_dictionaries (ESpellChecker *checker,
g_list_foreach (checker->priv->active, (GFunc) g_object_ref, NULL);
}
-void
-e_spell_checker_free_dict (ESpellChecker *checker,
- EnchantDict *enchant_dict)
-{
- g_return_if_fail (E_IS_SPELL_CHECKER (checker));
- g_return_if_fail (enchant_dict != NULL);
-
- enchant_broker_free_dict (checker->priv->broker, enchant_dict);
-}
-
/**
* e_spell_checker_ignore_word:
* @checker: an #ESpellChecker
diff --git a/e-util/e-spell-checker.h b/e-util/e-spell-checker.h
index 66d1f1a..6b59452 100644
--- a/e-util/e-spell-checker.h
+++ b/e-util/e-spell-checker.h
@@ -67,13 +67,14 @@ GList * e_spell_checker_list_available_dicts
ESpellDictionary *
e_spell_checker_ref_dictionary (ESpellChecker *checker,
const gchar *language_code);
+EnchantDict * e_spell_checker_get_enchant_dict
+ (ESpellChecker *checker,
+ const gchar *language_code);
void e_spell_checker_set_active_dictionaries
(ESpellChecker *checker,
GList *active_dicts);
GList * e_spell_checker_get_active_dictionaries
(ESpellChecker *checker);
-void e_spell_checker_free_dict (ESpellChecker *checker,
- EnchantDict *enchant_dict);
void e_spell_checker_learn_word (ESpellChecker *checker,
const gchar *word);
void e_spell_checker_ignore_word (ESpellChecker *checker,
diff --git a/e-util/e-spell-dictionary.c b/e-util/e-spell-dictionary.c
index 5857250..a3f3be7 100644
--- a/e-util/e-spell-dictionary.c
+++ b/e-util/e-spell-dictionary.c
@@ -42,8 +42,7 @@ enum {
};
struct _ESpellDictionaryPrivate {
- ESpellChecker *spell_checker;
- EnchantDict *enchant_dict;
+ GWeakRef spell_checker;
gchar *name;
gchar *code;
@@ -321,7 +320,6 @@ spell_dictionary_set_enchant_dict (ESpellDictionary *dictionary,
enchant_dict_describe (enchant_dict, describe_dictionary, &data);
- dictionary->priv->enchant_dict = enchant_dict;
dictionary->priv->code = data.language_tag;
dictionary->priv->name = data.dict_name;
dictionary->priv->collate_key = g_utf8_collate_key (data.dict_name, -1);
@@ -332,9 +330,8 @@ spell_dictionary_set_spell_checker (ESpellDictionary *dictionary,
ESpellChecker *spell_checker)
{
g_return_if_fail (E_IS_SPELL_CHECKER (spell_checker));
- g_return_if_fail (dictionary->priv->spell_checker == NULL);
- dictionary->priv->spell_checker = g_object_ref (spell_checker);
+ g_weak_ref_set (&dictionary->priv->spell_checker, spell_checker);
}
static void
@@ -362,9 +359,9 @@ spell_dictionary_get_property (GObject *object,
{
switch (property_id) {
case PROP_SPELL_CHECKER:
- g_value_set_object (
+ g_value_take_object (
value,
- e_spell_dictionary_get_parent_checker (
+ e_spell_dictionary_ref_spell_checker (
E_SPELL_DICTIONARY (object)));
return;
}
@@ -379,7 +376,7 @@ spell_dictionary_dispose (GObject *object)
priv = E_SPELL_DICTIONARY_GET_PRIVATE (object);
- g_clear_object (&priv->spell_checker);
+ g_weak_ref_set (&priv->spell_checker, NULL);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_spell_dictionary_parent_class)->dispose (object);
@@ -392,8 +389,6 @@ spell_dictionary_finalize (GObject *object)
priv = E_SPELL_DICTIONARY_GET_PRIVATE (object);
- e_spell_checker_free_dict (priv->spell_checker, priv->enchant_dict);
-
g_free (priv->name);
g_free (priv->code);
g_free (priv->collate_key);
@@ -463,18 +458,20 @@ e_spell_dictionary_init (ESpellDictionary *dictionary)
}
ESpellDictionary *
-e_spell_dictionary_new (ESpellChecker *parent_checker,
+e_spell_dictionary_new (ESpellChecker *spell_checker,
EnchantDict *enchant_dict)
{
ESpellDictionary *dictionary;
- g_return_val_if_fail (E_IS_SPELL_CHECKER (parent_checker), NULL);
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (spell_checker), NULL);
g_return_val_if_fail (enchant_dict != NULL, NULL);
dictionary = g_object_new (
E_TYPE_SPELL_DICTIONARY,
- "spell-checker", parent_checker, NULL);
+ "spell-checker", spell_checker, NULL);
+ /* Since EnchantDict is not reference counted, ESpellChecker
+ * is loaning us the EnchantDict pointer. We do not own it. */
spell_dictionary_set_enchant_dict (dictionary, enchant_dict);
return dictionary;
@@ -590,6 +587,23 @@ e_spell_dictionary_get_code (ESpellDictionary *dictionary)
}
/**
+ * e_spell_dictionary_ref_spell_checker:
+ * @dictionary: an #ESpellDictionary
+ *
+ * Returns a new reference to the #ESpellChecker which owns the dictionary.
+ * Unreference the #ESpellChecker with g_object_unref() when finished with it.
+ *
+ * Returns: an #ESpellChecker
+ **/
+ESpellChecker *
+e_spell_dictionary_ref_spell_checker (ESpellDictionary *dictionary)
+{
+ g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
+
+ return g_weak_ref_get (&dictionary->priv->spell_checker);
+}
+
+/**
* e_spell_dictionary_check:
* @dictionary: an #ESpellDictionary
* @word: a word to spell-check
@@ -605,11 +619,25 @@ e_spell_dictionary_check (ESpellDictionary *dictionary,
const gchar *word,
gsize length)
{
+ ESpellChecker *spell_checker;
+ EnchantDict *enchant_dict;
+ gboolean correctly_spelled;
+
g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), TRUE);
g_return_val_if_fail (word != NULL && *word != '\0', TRUE);
- return enchant_dict_check (
- dictionary->priv->enchant_dict, word, length);
+ spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
+ g_return_val_if_fail (spell_checker != NULL, TRUE);
+
+ enchant_dict = e_spell_checker_get_enchant_dict (
+ spell_checker, e_spell_dictionary_get_code (dictionary));
+ g_return_val_if_fail (enchant_dict != NULL, TRUE);
+
+ correctly_spelled = enchant_dict_check (enchant_dict, word, length);
+
+ g_object_unref (spell_checker);
+
+ return correctly_spelled;
}
/**
@@ -626,11 +654,22 @@ e_spell_dictionary_learn_word (ESpellDictionary *dictionary,
const gchar *word,
gsize length)
{
+ ESpellChecker *spell_checker;
+ EnchantDict *enchant_dict;
+
g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
g_return_if_fail (word != NULL && *word != '\0');
- enchant_dict_add_to_personal (
- dictionary->priv->enchant_dict, word, length);
+ spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
+ g_return_if_fail (spell_checker != NULL);
+
+ enchant_dict = e_spell_checker_get_enchant_dict (
+ spell_checker, e_spell_dictionary_get_code (dictionary));
+ g_return_if_fail (enchant_dict != NULL);
+
+ enchant_dict_add_to_personal (enchant_dict, word, length);
+
+ g_object_unref (spell_checker);
}
/**
@@ -648,11 +687,22 @@ e_spell_dictionary_ignore_word (ESpellDictionary *dictionary,
const gchar *word,
gsize length)
{
+ ESpellChecker *spell_checker;
+ EnchantDict *enchant_dict;
+
g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
g_return_if_fail (word != NULL && *word != '\0');
- enchant_dict_add_to_session (
- dictionary->priv->enchant_dict, word, length);
+ spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
+ g_return_if_fail (spell_checker != NULL);
+
+ enchant_dict = e_spell_checker_get_enchant_dict (
+ spell_checker, e_spell_dictionary_get_code (dictionary));
+ g_return_if_fail (enchant_dict != NULL);
+
+ enchant_dict_add_to_session (enchant_dict, word, length);
+
+ g_object_unref (spell_checker);
}
/**
@@ -678,6 +728,8 @@ e_spell_dictionary_get_suggestions (ESpellDictionary *dictionary,
const gchar *word,
gsize length)
{
+ ESpellChecker *spell_checker;
+ EnchantDict *enchant_dict;
GList *list = NULL;
gchar **suggestions;
gsize ii, count;
@@ -685,12 +737,19 @@ e_spell_dictionary_get_suggestions (ESpellDictionary *dictionary,
g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
g_return_val_if_fail (word != NULL && *word != '\0', NULL);
- suggestions = enchant_dict_suggest (
- dictionary->priv->enchant_dict, word, length, &count);
+ spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
+ g_return_val_if_fail (spell_checker != NULL, NULL);
+
+ enchant_dict = e_spell_checker_get_enchant_dict (
+ spell_checker, e_spell_dictionary_get_code (dictionary));
+ g_return_val_if_fail (enchant_dict != NULL, NULL);
+
+ suggestions = enchant_dict_suggest (enchant_dict, word, length, &count);
for (ii = 0; ii < count; ii++)
list = g_list_prepend (list, g_strdup (suggestions[ii]));
- enchant_dict_free_suggestions (
- dictionary->priv->enchant_dict, suggestions);
+ enchant_dict_free_suggestions (enchant_dict, suggestions);
+
+ g_object_unref (spell_checker);
return g_list_reverse (list);
}
@@ -714,30 +773,25 @@ e_spell_dictionary_store_correction (ESpellDictionary *dictionary,
const gchar *correction,
gsize correction_length)
{
+ ESpellChecker *spell_checker;
+ EnchantDict *enchant_dict;
+
g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
g_return_if_fail (misspelled != NULL && *misspelled != '\0');
g_return_if_fail (correction != NULL && *correction != '\0');
+ spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
+ g_return_if_fail (spell_checker != NULL);
+
+ enchant_dict = e_spell_checker_get_enchant_dict (
+ spell_checker, e_spell_dictionary_get_code (dictionary));
+ g_return_if_fail (enchant_dict != NULL);
+
enchant_dict_store_replacement (
- dictionary->priv->enchant_dict,
+ enchant_dict,
misspelled, misspelled_length,
correction, correction_length);
-}
-
-/**
- * e_spell_dictionary_get_parent_checker:
- * @dictionary: an #ESpellDictionary
- *
- * Returns an #ESpellChecker which is parent (and the original owner) of
- * the @dictionary.
- *
- * Returns: an #ESpellChecker
- */
-ESpellChecker *
-e_spell_dictionary_get_parent_checker (ESpellDictionary *dictionary)
-{
- g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
- return dictionary->priv->spell_checker;
+ g_object_unref (spell_checker);
}
diff --git a/e-util/e-spell-dictionary.h b/e-util/e-spell-dictionary.h
index b25896c..77956fa 100644
--- a/e-util/e-spell-dictionary.h
+++ b/e-util/e-spell-dictionary.h
@@ -63,7 +63,7 @@ struct _ESpellDictionaryClass {
GType e_spell_dictionary_get_type (void) G_GNUC_CONST;
ESpellDictionary *
- e_spell_dictionary_new (ESpellChecker *parent_checker,
+ e_spell_dictionary_new (ESpellChecker *spell_checker,
EnchantDict *enchant_dict);
guint e_spell_dictionary_hash (ESpellDictionary *dictionary);
gboolean e_spell_dictionary_equal (ESpellDictionary *dictionary1,
@@ -72,6 +72,8 @@ gint e_spell_dictionary_compare (ESpellDictionary *dictionary1,
ESpellDictionary *dictionary2);
const gchar * e_spell_dictionary_get_name (ESpellDictionary *dictionary);
const gchar * e_spell_dictionary_get_code (ESpellDictionary *dictionary);
+ESpellChecker * e_spell_dictionary_ref_spell_checker
+ (ESpellDictionary *dictionary);
gboolean e_spell_dictionary_check (ESpellDictionary *dictionary,
const gchar *word,
gsize length);
@@ -91,8 +93,6 @@ void e_spell_dictionary_store_correction
gsize misspelled_length,
const gchar *correction,
gsize correction_length);
-ESpellChecker * e_spell_dictionary_get_parent_checker
- (ESpellDictionary *dictionary);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]