[evolution-data-server] Bug #540779 - Do not call e_book_new in the main thread



commit 11ca410a04a08a293b43d181e188834734310a76
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 17 09:48:03 2009 +0200

    Bug #540779 - Do not call e_book_new in the main thread

 libedataserverui/e-name-selector.c |  166 ++++++++++++++++++++++++------------
 1 files changed, 112 insertions(+), 54 deletions(-)
---
diff --git a/libedataserverui/e-name-selector.c b/libedataserverui/e-name-selector.c
index 2db4e36..223b910 100644
--- a/libedataserverui/e-name-selector.c
+++ b/libedataserverui/e-name-selector.c
@@ -35,8 +35,6 @@
 #include <libedataserverui/e-book-auth-util.h>
 #include "e-name-selector.h"
 
-#define PRIVATE_SOURCE_BOOKS_KEY "private-source-books"
-
 typedef struct {
 	gchar              *name;
 	ENameSelectorEntry *entry;
@@ -49,6 +47,16 @@ typedef struct {
 }
 SourceBook;
 
+typedef struct _ENameSelectorPrivate ENameSelectorPrivate;
+
+struct _ENameSelectorPrivate {
+	GThread *load_book_thread;
+	gboolean load_cancelled;
+	GArray *source_books;
+};
+
+#define E_NAME_SELECTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_NAME_SELECTOR, ENameSelectorPrivate))
+
 static void  e_name_selector_finalize   (GObject                 *object);
 
 /* ------------------ *
@@ -57,63 +65,35 @@ static void  e_name_selector_finalize   (GObject                 *object);
 
 G_DEFINE_TYPE (ENameSelector, e_name_selector, G_TYPE_OBJECT)
 
-static void
-source_books_destroy (GArray *source_books)
-{
-	gint i;
-
-	for (i = 0; i < source_books->len; i++) {
-		SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
-
-		g_object_unref (source_book->book);
-	}
-
-	g_array_free (source_books, TRUE);
-}
-
-static void
-e_name_selector_class_init (ENameSelectorClass *name_selector_class)
-{
-	GObjectClass *object_class;
-
-	object_class = G_OBJECT_CLASS (name_selector_class);
-
-	object_class->finalize = e_name_selector_finalize;
-}
-
-static void
-e_name_selector_init (ENameSelector *name_selector)
+static gpointer
+load_books_thread (gpointer user_data)
 {
+	ENameSelector *name_selector = user_data;
+	ENameSelectorPrivate *priv;
 	ESourceList *source_list;
-	GArray      *source_books;
 	GSList      *groups;
 	GSList      *l;
 
-	name_selector->sections = g_array_new (FALSE, FALSE, sizeof (Section));
-	name_selector->model = e_name_selector_model_new ();
-
-	/* Make a list of books */
+	/* XXX This thread is necessary because the e_book_new can block.
+	   See gnome's bug #540779 for more information. */
 
-	source_books = g_array_new (FALSE, FALSE, sizeof (SourceBook));
+	g_return_val_if_fail (name_selector != NULL, NULL);
 
-	/* This should be a private field, but we use g_object_set_data() to maintain
-	 * ABI compatibility in the GNOME 2.10 branch */
-	g_object_set_data_full (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY, source_books,
-				(GDestroyNotify) source_books_destroy);
+	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
 
 	if (!e_book_get_addressbooks (&source_list, NULL)) {
 		g_warning ("ENameSelector can't find any addressbooks!");
-		return;
+		return NULL;
 	}
 
 	groups = e_source_list_peek_groups (source_list);
 
-	for (l = groups; l; l = g_slist_next (l)) {
+	for (l = groups; l && !priv->load_cancelled; l = g_slist_next (l)) {
 		ESourceGroup *group   = l->data;
 		GSList       *sources = e_source_group_peek_sources (group);
 		GSList       *m;
 
-		for (m = sources; m; m = g_slist_next (m)) {
+		for (m = sources; m && !priv->load_cancelled; m = g_slist_next (m)) {
 			ESource      *source = m->data;
 			const gchar  *completion;
 			SourceBook    source_book;
@@ -130,16 +110,93 @@ e_name_selector_init (ENameSelector *name_selector)
 
 			source_book.is_completion_book = TRUE;
 
-			g_array_append_val (source_books, source_book);
+			g_array_append_val (priv->source_books, source_book);
+
+			if (!priv->load_cancelled) {
+				EContactStore *store;
+
+				if (name_selector->model) {
+					store = e_name_selector_model_peek_contact_store  (name_selector->model);
+					if (store)
+						e_contact_store_add_book (store, source_book.book);
+				}
+
+				if (name_selector->sections) {
+					gint j;
+
+					for (j = 0; j < name_selector->sections->len && !priv->load_cancelled; j++) {
+						Section *section = &g_array_index (name_selector->sections, Section, j);
+
+						if (section->entry) {
+							store = e_name_selector_entry_peek_contact_store (section->entry);
+							if (store)
+								e_contact_store_add_book (store, source_book.book);
+						}
+					}
+				}
+			}
 		}
 	}
 
 	g_object_unref (source_list);
+
+	return NULL;
+}
+
+static void
+e_name_selector_class_init (ENameSelectorClass *name_selector_class)
+{
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (name_selector_class);
+
+	object_class->finalize = e_name_selector_finalize;
+
+	g_type_class_add_private (name_selector_class, sizeof (ENameSelectorPrivate));
+}
+
+static void
+e_name_selector_init (ENameSelector *name_selector)
+{
+	ENameSelectorPrivate *priv;
+
+	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
+
+	name_selector->sections = g_array_new (FALSE, FALSE, sizeof (Section));
+	name_selector->model = e_name_selector_model_new ();
+
+	priv->source_books = g_array_new (FALSE, FALSE, sizeof (SourceBook));
+	priv->load_cancelled = FALSE;
+	priv->load_book_thread = g_thread_create (load_books_thread, name_selector, TRUE, NULL);
 }
 
 static void
 e_name_selector_finalize (GObject *object)
 {
+	ENameSelectorPrivate *priv;
+
+	priv = E_NAME_SELECTOR_GET_PRIVATE (object);
+
+	if (priv->load_book_thread) {
+		priv->load_cancelled = TRUE;
+		g_thread_join (priv->load_book_thread);
+		priv->load_book_thread = NULL;
+	}
+
+	if (priv->source_books) {
+		gint i;
+
+		for (i = 0; i < priv->source_books->len; i++) {
+			SourceBook *source_book = &g_array_index (priv->source_books, SourceBook, i);
+
+			if (source_book->book)
+				g_object_unref (source_book->book);
+		}
+
+		g_array_free (priv->source_books, TRUE);
+		priv->source_books = NULL;
+	}
+
 	if (G_OBJECT_CLASS (e_name_selector_parent_class)->finalize)
 		G_OBJECT_CLASS (e_name_selector_parent_class)->finalize (object);
 }
@@ -248,6 +305,7 @@ e_name_selector_peek_dialog (ENameSelector *name_selector)
 ENameSelectorEntry *
 e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *name)
 {
+	ENameSelectorPrivate *priv;
 	EDestinationStore *destination_store;
 	Section *section;
 	gint     n;
@@ -255,6 +313,8 @@ e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *n
 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
 	g_return_val_if_fail (name != NULL, NULL);
 
+	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
+
 	if (!e_name_selector_model_peek_section (name_selector->model, name,
 						 NULL, &destination_store))
 		return NULL;
@@ -266,7 +326,6 @@ e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *n
 	section = &g_array_index (name_selector->sections, Section, n);
 
 	if (!section->entry) {
-		GArray        *source_books;
 		EContactStore *contact_store;
 		gchar         *text;
 		gint           i;
@@ -282,12 +341,11 @@ e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *n
 		/* Create a contact store for the entry and assign our already-open books to it */
 
 		contact_store = e_contact_store_new ();
-		source_books = g_object_get_data (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY);
 
-		for (i = 0; i < source_books->len; i++) {
-			SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
+		for (i = 0; i < priv->source_books->len; i++) {
+			SourceBook *source_book = &g_array_index (priv->source_books, SourceBook, i);
 
-			if (source_book->is_completion_book)
+			if (source_book->is_completion_book && source_book->book)
 				e_contact_store_add_book (contact_store, source_book->book);
 		}
 
@@ -312,6 +370,7 @@ e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *n
 ENameSelectorList *
 e_name_selector_peek_section_list (ENameSelector *name_selector, const gchar *name)
 {
+	ENameSelectorPrivate *priv;
 	EDestinationStore *destination_store;
 	Section *section;
 	gint     n;
@@ -319,6 +378,8 @@ e_name_selector_peek_section_list (ENameSelector *name_selector, const gchar *na
 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
 	g_return_val_if_fail (name != NULL, NULL);
 
+	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
+
 	if (!e_name_selector_model_peek_section (name_selector->model, name,
 						 NULL, &destination_store))
 		return NULL;
@@ -330,7 +391,6 @@ e_name_selector_peek_section_list (ENameSelector *name_selector, const gchar *na
 	section = &g_array_index (name_selector->sections, Section, n);
 
 	if (!section->entry) {
-		GArray        *source_books;
 		EContactStore *contact_store;
 		gchar         *text;
 		gint           i;
@@ -340,18 +400,16 @@ e_name_selector_peek_section_list (ENameSelector *name_selector, const gchar *na
 					&text, NULL, NULL))  {
 			atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (section->entry)), text);
 			g_free (text);
-	}
+		}
 		e_name_selector_entry_set_destination_store (section->entry, destination_store);
 
 		/* Create a contact store for the entry and assign our already-open books to it */
 
 		contact_store = e_contact_store_new ();
-		source_books = g_object_get_data (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY);
-
-		for (i = 0; i < source_books->len; i++) {
-			SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
+		for (i = 0; i < priv->source_books->len; i++) {
+			SourceBook *source_book = &g_array_index (priv->source_books, SourceBook, i);
 
-			if (source_book->is_completion_book)
+			if (source_book->is_completion_book && source_book->book)
 				e_contact_store_add_book (contact_store, source_book->book);
 		}
 



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