[evolution/webkit: 41/102] Let the EMFormat object exist only for as long as it is displayed in a EMailDisplay.



commit ef7c80c5c8ccd1e13a0f20d0edf2820617b32e4e
Author: Dan VrÃtil <dvratil redhat com>
Date:   Thu Oct 13 21:04:49 2011 +0200

    Let the EMFormat object exist only for as long as it is displayed in a EMailDisplay.
    
    Every new EMailDisplay increases reference count of an EMFormat by one. When an
    EMFormat is not displayed in any EMailDisplay, the reference count drops to zero
    and it is destroyed and removed from the list of formatters.

 em-format/em-format.c |    5 +++--
 mail/e-mail-display.c |    4 +++-
 mail/e-mail-reader.c  |   47 +++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 51 insertions(+), 5 deletions(-)
---
diff --git a/em-format/em-format.c b/em-format/em-format.c
index f46bc9c..9159d6b 100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@ -1459,8 +1459,9 @@ em_format_init (EMFormat *emf)
 	emf->folder = NULL;
 	emf->mail_part_list = NULL;
 	emf->mail_part_table = g_hash_table_new_full (g_str_hash, g_str_equal,
-			(GDestroyNotify) g_free, (GDestroyNotify) em_format_puri_free);
-
+			NULL, (GDestroyNotify) em_format_puri_free);
+	/* No need to free the key, because it's owned and free'd by the PURI */
+	
 	shell = e_shell_get_default ();
 	shell_settings = e_shell_get_shell_settings (shell);
 
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 5a70cb9..060da9d 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -767,10 +767,12 @@ e_mail_display_set_formatter (EMailDisplay *display,
 	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 	g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
 
+	g_object_ref (formatter);
+	
 	if (display->priv->formatter != NULL)
 		g_object_unref (display->priv->formatter);
 
-	display->priv->formatter = g_object_ref (formatter);
+	display->priv->formatter = formatter;
 
 	mail_display_update_formatter_colors (display);
 
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 3e16eed..9bb3e2e 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2558,7 +2558,6 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
 	GtkWidget *message_list;
 	const gchar *message_uid;
 	GError *error = NULL;
-	GHashTable *formatters;
 
 	reader = closure->reader;
 	message_uid = closure->message_uid;
@@ -2844,6 +2843,27 @@ mail_reader_folder_loaded (EMailReader *reader)
 	e_mail_reader_update_actions (reader, state);
 }
 
+struct _formatter_weak_ref_closure {
+	GHashTable *formatters;
+	gchar *mail_uri;
+};
+
+static void
+formatter_weak_ref_cb (struct _formatter_weak_ref_closure *data,
+		       EMFormat *formatter)
+{
+	/* When this callback is called, the formatter is being finalized
+	 * so we only remove it from the formatters table. */
+	g_hash_table_remove (data->formatters,
+		data->mail_uri);
+
+	/* Destroying the formatter will prevent this callback
+	 * being called, so we can remove the closure data as well */
+	g_hash_table_unref (data->formatters);
+	g_free (data->mail_uri);
+	g_free (data);
+}
+
 static void
 mail_reader_message_loaded (EMailReader *reader,
                             const gchar *message_uid,
@@ -2899,21 +2919,44 @@ mail_reader_message_loaded (EMailReader *reader,
 	formatters = g_object_get_data (G_OBJECT (session), "formatters");
 	if (!formatters) {
 		formatters = g_hash_table_new_full (g_str_hash, g_str_equal,
-			(GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
+			(GDestroyNotify) g_free, NULL);
 		g_object_set_data (G_OBJECT (session), "formatters", formatters);
 	}
 
 
 	if ((formatter = g_hash_table_lookup (formatters, mail_uri)) == NULL) {
+		struct _formatter_weak_ref_closure *formatter_data =
+			g_new0 (struct _formatter_weak_ref_closure, 1);
+
+		formatter_data->formatters = g_hash_table_ref (formatters);
+		formatter_data->mail_uri = g_strdup (mail_uri);
+
 		formatter = em_format_html_display_new ();
+		/* When no EMailDisplay holds reference to the f ormatter, then
+		 * the formatter can be destroyed. */
+		 g_object_weak_ref (formatter, (GWeakNotify) formatter_weak_ref_cb,
+		 		    formatter_data);
+
 		EM_FORMAT (formatter)->message_uid = g_strdup (message_uid);
+
+		/* Parse the message.
+		 * FIXME WEBKIT: This should probably be asynchronous since it
+		 * can block for some time...*/
 		em_format_parse (EM_FORMAT (formatter), message, folder, NULL);
 		g_hash_table_insert (formatters, mail_uri, formatter);
+	} else {
+		/* Add reference that would be otherwise added when
+		 * the formatter is created. */
+		 g_object_ref (formatter);
 	}
 
 	e_mail_display_set_formatter (display, EM_FORMAT_HTML (formatter));
 	e_mail_display_load (display, mail_uri);
 
+	/* Remove the reference added when formatter was created,
+	 * so that only owners are EMailDisplays */
+	g_object_unref (formatter);
+
 	/* Reset the shell view icon. */
 	e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
 



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