[evolution] [EMailLabelListStore] Avoid circular dependency in a tag cache



commit b62174fab352fac622012ea3445dbe2fb34d31ef
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 13 17:11:25 2015 +0100

    [EMailLabelListStore] Avoid circular dependency in a tag cache
    
    The store has its own cache of tags for quicker lookup, but this
    cache used GtkTreeRowReference-s, which reference the model, thus
    it made circular dependency and the store was never freed. Using
    place GtkTreeIter pointer in the cache works too, one only needs
    to do more often manual updates of it.

 mail/e-mail-label-list-store.c |   83 ++++++++++++++++++----------------------
 1 files changed, 37 insertions(+), 46 deletions(-)
---
diff --git a/mail/e-mail-label-list-store.c b/mail/e-mail-label-list-store.c
index cb477b2..774495a 100644
--- a/mail/e-mail-label-list-store.c
+++ b/mail/e-mail-label-list-store.c
@@ -44,7 +44,7 @@ enum {
 static guint signals[LAST_SIGNAL];
 
 struct _EMailLabelListStorePrivate {
-       GHashTable *tag_index;
+       GHashTable *tag_index; /* gchar *tag_name ~> GtkTreeIter * */
        GSettings *mail_settings;
        guint idle_changed_id;
 };
@@ -110,6 +110,29 @@ mail_label_list_store_encode_label (const gchar *label_name,
 }
 
 static void
+mail_label_list_store_fill_tag_index (EMailLabelListStore *store)
+{
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+
+       g_hash_table_remove_all (store->priv->tag_index);
+
+       model = GTK_TREE_MODEL (store);
+       if (!gtk_tree_model_get_iter_first (model, &iter))
+               return;
+
+       do {
+               gchar *tag;
+
+               tag = e_mail_label_list_store_get_tag (store, &iter);
+               if (!tag)
+                       continue;
+
+               g_hash_table_insert (store->priv->tag_index, tag, gtk_tree_iter_copy (&iter));
+       } while (gtk_tree_model_iter_next (model, &iter));
+}
+
+static void
 mail_label_list_store_ensure_defaults (EMailLabelListStore *store)
 {
        gint ii;
@@ -266,6 +289,8 @@ labels_model_changed_idle_cb (gpointer user_data)
                store->priv->mail_settings,
                labels_settings_changed_cb, store);
 
+       mail_label_list_store_fill_tag_index (store);
+
        g_signal_emit (store, signals[CHANGED], 0);
 
        return FALSE;
@@ -276,6 +301,8 @@ labels_model_changed_cb (EMailLabelListStore *store)
 {
        g_return_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store));
 
+       mail_label_list_store_fill_tag_index (store);
+
        /* do the actual save and signal emission on idle,
         * to accumulate as many changes as possible */
        if (!store->priv->idle_changed_id)
@@ -327,6 +354,8 @@ labels_settings_changed_cb (GSettings *settings,
        if (g_hash_table_size (changed_labels) == 0) {
                g_hash_table_destroy (changed_labels);
                g_strfreev (strv);
+
+               mail_label_list_store_fill_tag_index (store);
                return;
        }
 
@@ -349,6 +378,8 @@ labels_settings_changed_cb (GSettings *settings,
 
        g_signal_handlers_unblock_by_func (
                store, labels_model_changed_cb, store);
+
+       mail_label_list_store_fill_tag_index (store);
 }
 
 static void
@@ -387,32 +418,6 @@ mail_label_list_store_constructed (GObject *object)
 }
 
 static void
-mail_label_list_store_row_inserted (GtkTreeModel *model,
-                                    GtkTreePath *path,
-                                    GtkTreeIter *iter)
-{
-       EMailLabelListStore *store;
-       GtkTreeRowReference *reference;
-       GHashTable *tag_index;
-       gchar *tag;
-
-       store = E_MAIL_LABEL_LIST_STORE (model);
-       tag = e_mail_label_list_store_get_tag (store, iter);
-       g_return_if_fail (tag != NULL);
-
-       /* Hash table takes ownership of both tag and reference. */
-       tag_index = store->priv->tag_index;
-       reference = gtk_tree_row_reference_new (model, path);
-       g_hash_table_insert (tag_index, tag, reference);
-
-       /* We don't need to do anything special for row deletion.
-        * The reference will automatically become invalid (that's
-        * why we're storing references and not iterators or paths),
-        * so garbage collection is not important.  We'll do it
-        * lazily. */
-}
-
-static void
 e_mail_label_list_store_class_init (EMailLabelListStoreClass *class)
 {
        GObjectClass *object_class;
@@ -439,7 +444,6 @@ e_mail_label_list_store_class_init (EMailLabelListStoreClass *class)
 static void
 e_mail_label_list_store_interface_init (GtkTreeModelIface *iface)
 {
-       iface->row_inserted = mail_label_list_store_row_inserted;
 }
 
 static void
@@ -451,7 +455,7 @@ e_mail_label_list_store_init (EMailLabelListStore *store)
        tag_index = g_hash_table_new_full (
                g_str_hash, g_str_equal,
                (GDestroyNotify) g_free,
-               (GDestroyNotify) gtk_tree_row_reference_free);
+               (GDestroyNotify) gtk_tree_iter_free);
 
        store->priv = E_MAIL_LABEL_LIST_STORE_GET_PRIVATE (store);
        store->priv->tag_index = tag_index;
@@ -658,31 +662,18 @@ e_mail_label_list_store_lookup (EMailLabelListStore *store,
                                 const gchar *tag,
                                 GtkTreeIter *iter)
 {
-       GtkTreeRowReference *reference;
-       GHashTable *tag_index;
-       GtkTreeModel *model;
-       GtkTreePath *path;
+       GtkTreeIter *stored_iter;
 
        g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), FALSE);
        g_return_val_if_fail (tag != NULL, FALSE);
        g_return_val_if_fail (iter != NULL, FALSE);
 
-       tag_index = store->priv->tag_index;
-       reference = g_hash_table_lookup (tag_index, tag);
+       stored_iter = g_hash_table_lookup (store->priv->tag_index, tag);
 
-       if (reference == NULL)
+       if (!stored_iter)
                return FALSE;
 
-       if (!gtk_tree_row_reference_valid (reference)) {
-               /* Garbage collect the dead reference. */
-               g_hash_table_remove (tag_index, tag);
-               return FALSE;
-       }
-
-       model = gtk_tree_row_reference_get_model (reference);
-       path = gtk_tree_row_reference_get_path (reference);
-       gtk_tree_model_get_iter (model, iter, path);
-       gtk_tree_path_free (path);
+       *iter = *stored_iter;
 
        return TRUE;
 }


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