[evolution/wip/gsettings] Keep opening EClient-s till they report busy error



commit 8894b72f2045388990b5696f3e8db97b9544ccf4
Author: Milan Crha <mcrha redhat com>
Date:   Mon Jun 27 15:23:31 2011 +0200

    Keep opening EClient-s till they report busy error

 calendar/gui/e-cal-model.c              |   72 ++++++++++++++++++++++-
 calendar/gui/gnome-cal.c                |    6 --
 calendar/gui/gnome-cal.h                |    1 -
 modules/calendar/e-cal-shell-content.c  |    1 -
 modules/calendar/e-cal-shell-sidebar.c  |   96 +++++++++++++++++++++++++++----
 modules/calendar/e-memo-shell-sidebar.c |   95 ++++++++++++++++++++++++++----
 modules/calendar/e-task-shell-sidebar.c |   95 ++++++++++++++++++++++++++----
 7 files changed, 320 insertions(+), 46 deletions(-)
---
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index 9778d3e..2b4aac7 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -114,6 +114,8 @@ struct _ECalModelPrivate {
 	GSList *notify_removed;
 
 	GMutex *notify_lock;
+
+	GCancellable *loading_clients;
 };
 
 static gint ecm_column_count (ETableModel *etm);
@@ -377,6 +379,12 @@ cal_model_dispose (GObject *object)
 
 	priv = E_CAL_MODEL (object)->priv;
 
+	if (priv->loading_clients) {
+		g_cancellable_cancel (priv->loading_clients);
+		g_object_unref (priv->loading_clients);
+		priv->loading_clients = NULL;
+	}
+
 	if (priv->clients) {
 		while (priv->clients != NULL) {
 			ECalModelClient *client_data = (ECalModelClient *) priv->clients->data;
@@ -701,6 +709,8 @@ e_cal_model_init (ECalModel *model)
 	model->priv->notify_modified = NULL;
 	model->priv->notify_removed = NULL;
 	model->priv->notify_lock = g_mutex_new ();
+
+	model->priv->loading_clients = g_cancellable_new ();
 }
 
 /* ETableModel methods */
@@ -2582,6 +2592,28 @@ cal_model_retrieve_capabilies_cb (GObject *source_object, GAsyncResult *result,
 	update_e_cal_view_for_client (model, client_data);
 }
 
+struct RetryOpenData
+{
+	EClient *client;
+	ECalModel *model;
+	GCancellable *cancellable;
+};
+
+static void
+free_retry_open_data (gpointer data)
+{
+	struct RetryOpenData *rod = data;
+
+	if (!rod)
+		return;
+
+	g_object_unref (rod->client);
+	g_object_unref (rod->cancellable);
+	g_free (rod);
+}
+
+static gboolean cal_model_retry_open_timeout_cb (gpointer user_data);
+
 static void
 client_opened_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -2591,6 +2623,28 @@ client_opened_cb (GObject *source_object, GAsyncResult *result, gpointer user_da
 
 	e_client_open_finish (E_CLIENT (client), result, &error);
 
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
+	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_error_free (error);
+		return;
+	}
+
+	if (error && g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
+		struct RetryOpenData *rod;
+
+		rod = g_new0 (struct RetryOpenData, 1);
+		rod->client = g_object_ref (client);
+		rod->model = model;
+		rod->cancellable = g_object_ref (model->priv->loading_clients);
+
+		/* postpone for 1/2 of a second, backend is busy now */
+		g_timeout_add_full (G_PRIORITY_DEFAULT, 500, cal_model_retry_open_timeout_cb, rod, free_retry_open_data);
+
+		g_error_free (error);
+
+		return;
+	}
+
 	if (error) {
 		e_cal_model_remove_client (model, client);
 		g_debug ("%s: Failed to open '%s': %s", G_STRFUNC, e_client_get_uri (E_CLIENT (client)), error->message);
@@ -2600,7 +2654,21 @@ client_opened_cb (GObject *source_object, GAsyncResult *result, gpointer user_da
 	}
 
 	/* to have them ready for later use */
-	e_client_retrieve_capabilities (E_CLIENT (client), NULL, cal_model_retrieve_capabilies_cb, model);
+	e_client_retrieve_capabilities (E_CLIENT (client), model->priv->loading_clients, cal_model_retrieve_capabilies_cb, model);
+}
+
+static gboolean
+cal_model_retry_open_timeout_cb (gpointer user_data)
+{
+	struct RetryOpenData *rod = user_data;
+
+	g_return_val_if_fail (rod != NULL, FALSE);
+	g_return_val_if_fail (rod->client != NULL, FALSE);
+	g_return_val_if_fail (rod->model != NULL, FALSE);
+
+	e_client_open (rod->client, TRUE, rod->cancellable, client_opened_cb, rod->model);
+
+	return FALSE;
 }
 
 static ECalModelClient *
@@ -2649,7 +2717,7 @@ add_new_client (ECalModel *model, ECalClient *client, gboolean do_query)
 
 		e_cal_client_set_default_timezone (client, e_cal_model_get_timezone (model));
 
-		e_client_open (E_CLIENT (client), TRUE, NULL, client_opened_cb, model);
+		e_client_open (E_CLIENT (client), TRUE, model->priv->loading_clients, client_opened_cb, model);
 	}
 
 	return client_data;
diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c
index 78721bf..4bb430c 100644
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@ -1510,12 +1510,6 @@ gnome_calendar_finalize (GObject *object)
 	G_OBJECT_CLASS (gnome_calendar_parent_class)->finalize (object);
 }
 
-void
-gnome_calendar_dispose (GnomeCalendar *gcal)
-{
-	g_object_run_dispose (G_OBJECT (gcal));
-}
-
 static void
 notify_selected_time_changed (GnomeCalendar *gcal)
 {
diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h
index 6657b8e..5813039 100644
--- a/calendar/gui/gnome-cal.h
+++ b/calendar/gui/gnome-cal.h
@@ -113,7 +113,6 @@ struct _GnomeCalendarClass {
 
 GType		gnome_calendar_get_type		(void);
 GtkWidget *	gnome_calendar_new		(void);
-void		gnome_calendar_dispose          (GnomeCalendar *gcal);
 ECalendar *	gnome_calendar_get_date_navigator
 						(GnomeCalendar *gcal);
 void		gnome_calendar_set_date_navigator
diff --git a/modules/calendar/e-cal-shell-content.c b/modules/calendar/e-cal-shell-content.c
index e85f920..b4297b9 100644
--- a/modules/calendar/e-cal-shell-content.c
+++ b/modules/calendar/e-cal-shell-content.c
@@ -279,7 +279,6 @@ cal_shell_content_dispose (GObject *object)
 	}
 
 	if (priv->calendar != NULL) {
-		gnome_calendar_dispose (GNOME_CALENDAR (priv->calendar));
 		g_object_unref (priv->calendar);
 		priv->calendar = NULL;
 	}
diff --git a/modules/calendar/e-cal-shell-sidebar.c b/modules/calendar/e-cal-shell-sidebar.c
index e33a7dc..efa233e 100644
--- a/modules/calendar/e-cal-shell-sidebar.c
+++ b/modules/calendar/e-cal-shell-sidebar.c
@@ -59,6 +59,7 @@ struct _ECalShellSidebarPrivate {
 	ECalClient *default_client;
 
 	GCancellable *loading_default_client;
+	GCancellable *loading_clients;
 };
 
 enum {
@@ -181,6 +182,28 @@ cal_shell_sidebar_retrieve_capabilies_cb (GObject *source_object, GAsyncResult *
 	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
 }
 
+static gboolean cal_shell_sidebar_retry_open_timeout_cb (gpointer user_data);
+
+struct RetryOpenData
+{
+	EClient *client;
+	ECalShellSidebar *cal_shell_sidebar;
+	GCancellable *cancellable;
+};
+
+static void
+free_retry_open_data (gpointer data)
+{
+	struct RetryOpenData *rod = data;
+
+	if (!rod)
+		return;
+
+	g_object_unref (rod->client);
+	g_object_unref (rod->cancellable);
+	g_free (rod);
+}
+
 static void
 cal_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -191,22 +214,44 @@ cal_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *result
 	EShellSidebar *shell_sidebar;
 	GError *error = NULL;
 
-	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-
 	e_client_open_finish (E_CLIENT (client), result, &error);
 
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
+	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_clear_error (&error);
+		return;
+	}
+
 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED) ||
 	    g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED))
 		e_client_utils_forget_password (E_CLIENT (client));
 
 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
-		e_client_open (E_CLIENT (client), FALSE, NULL, cal_shell_sidebar_client_opened_cb, user_data);
+		e_client_open (E_CLIENT (client), FALSE, cal_shell_sidebar->priv->loading_clients, cal_shell_sidebar_client_opened_cb, user_data);
+
 		g_clear_error (&error);
 		return;
 	}
 
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
+		struct RetryOpenData *rod;
+
+		rod = g_new0 (struct RetryOpenData, 1);
+		rod->client = g_object_ref (client);
+		rod->cal_shell_sidebar = cal_shell_sidebar;
+		rod->cancellable = g_object_ref (cal_shell_sidebar->priv->loading_clients);
+
+		/* postpone for 1/2 of a second, backend is busy now */
+		g_timeout_add_full (G_PRIORITY_DEFAULT, 500, cal_shell_sidebar_retry_open_timeout_cb, rod, free_retry_open_data);
+
+		g_clear_error (&error);
+		return;
+	}
+
+	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+
 	/* Handle errors. */
 	switch ((error && error->domain == E_CLIENT_ERROR) ? error->code : -1) {
 		case -1:
@@ -245,6 +290,24 @@ cal_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *result
 	e_client_retrieve_capabilities (E_CLIENT (client), NULL, cal_shell_sidebar_retrieve_capabilies_cb, cal_shell_sidebar);
 }
 
+static gboolean
+cal_shell_sidebar_retry_open_timeout_cb (gpointer user_data)
+{
+	struct RetryOpenData *rod = user_data;
+
+	g_return_val_if_fail (rod != NULL, FALSE);
+	g_return_val_if_fail (rod->client != NULL, FALSE);
+	g_return_val_if_fail (rod->cal_shell_sidebar != NULL, FALSE);
+	g_return_val_if_fail (rod->cancellable != NULL, FALSE);
+
+	if (g_cancellable_is_cancelled (rod->cancellable))
+		return FALSE;
+
+	e_client_open (rod->client, FALSE, rod->cal_shell_sidebar->priv->loading_clients, cal_shell_sidebar_client_opened_cb, rod->cal_shell_sidebar);
+
+	return FALSE;
+}
+
 static void
 cal_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -259,11 +322,6 @@ cal_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *resul
 
 	priv = E_CAL_SHELL_SIDEBAR (shell_sidebar)->priv;
 
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-	cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
-	model = e_cal_shell_content_get_model (cal_shell_content);
-
 	if (!e_client_utils_open_new_finish (E_SOURCE (source_object), result, &client, &error))
 		client = NULL;
 
@@ -271,7 +329,14 @@ cal_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *resul
 	    g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED)) {
 		g_error_free (error);
 		goto exit;
-	} else if (error != NULL) {
+	}
+
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+	cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
+	model = e_cal_shell_content_get_model (cal_shell_content);
+
+	if (error != NULL) {
 		e_alert_submit (
 			E_ALERT_SINK (shell_content),
 			"calendar:failed-open-calendar",
@@ -560,6 +625,12 @@ cal_shell_sidebar_dispose (GObject *object)
 		priv->loading_default_client = NULL;
 	}
 
+	if (priv->loading_clients != NULL) {
+		g_cancellable_cancel (priv->loading_clients);
+		g_object_unref (priv->loading_clients);
+		priv->loading_clients = NULL;
+	}
+
 	g_hash_table_remove_all (priv->client_table);
 
 	/* Chain up to parent's dispose() method. */
@@ -864,6 +935,7 @@ cal_shell_sidebar_init (ECalShellSidebar *cal_shell_sidebar)
 		ECalShellSidebarPrivate);
 
 	cal_shell_sidebar->priv->client_table = client_table;
+	cal_shell_sidebar->priv->loading_clients = g_cancellable_new ();
 
 	/* Postpone widget construction until we have a shell view. */
 }
@@ -1027,7 +1099,7 @@ e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
 	timezone = e_cal_model_get_timezone (model);
 
 	e_cal_client_set_default_timezone (client, timezone);
-	e_client_open (E_CLIENT (client), FALSE, NULL, cal_shell_sidebar_client_opened_cb, cal_shell_sidebar);
+	e_client_open (E_CLIENT (client), FALSE, cal_shell_sidebar->priv->loading_clients, cal_shell_sidebar_client_opened_cb, cal_shell_sidebar);
 }
 
 void
diff --git a/modules/calendar/e-memo-shell-sidebar.c b/modules/calendar/e-memo-shell-sidebar.c
index 213179c..0180619 100644
--- a/modules/calendar/e-memo-shell-sidebar.c
+++ b/modules/calendar/e-memo-shell-sidebar.c
@@ -55,6 +55,7 @@ struct _EMemoShellSidebarPrivate {
 	ECalClient *default_client;
 
 	GCancellable *loading_default_client;
+	GCancellable *loading_clients;
 };
 
 enum {
@@ -176,6 +177,28 @@ memo_shell_sidebar_retrieve_capabilies_cb (GObject *source_object, GAsyncResult
 	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
 }
 
+static gboolean memo_shell_sidebar_retry_open_timeout_cb (gpointer user_data);
+
+struct RetryOpenData
+{
+	EClient *client;
+	EMemoShellSidebar *memo_shell_sidebar;
+	GCancellable *cancellable;
+};
+
+static void
+free_retry_open_data (gpointer data)
+{
+	struct RetryOpenData *rod = data;
+
+	if (!rod)
+		return;
+
+	g_object_unref (rod->client);
+	g_object_unref (rod->cancellable);
+	g_free (rod);
+}
+
 static void
 memo_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -186,22 +209,43 @@ memo_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *resul
 	EShellSidebar *shell_sidebar;
 	GError *error = NULL;
 
-	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-
 	e_client_open_finish (E_CLIENT (client), result, &error);
 
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
+	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_clear_error (&error);
+		return;
+	}
+
 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED) ||
 	    g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED))
 		e_client_utils_forget_password (E_CLIENT (client));
 
 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
-		e_client_open (E_CLIENT (client), FALSE, NULL, memo_shell_sidebar_client_opened_cb, user_data);
+		e_client_open (E_CLIENT (client), FALSE, memo_shell_sidebar->priv->loading_clients, memo_shell_sidebar_client_opened_cb, user_data);
+		g_clear_error (&error);
+		return;
+	}
+
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
+		struct RetryOpenData *rod;
+
+		rod = g_new0 (struct RetryOpenData, 1);
+		rod->client = g_object_ref (client);
+		rod->memo_shell_sidebar = memo_shell_sidebar;
+		rod->cancellable = g_object_ref (memo_shell_sidebar->priv->loading_clients);
+
+		/* postpone for 1/2 of a second, backend is busy now */
+		g_timeout_add_full (G_PRIORITY_DEFAULT, 500, memo_shell_sidebar_retry_open_timeout_cb, rod, free_retry_open_data);
+
 		g_clear_error (&error);
 		return;
 	}
 
+	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+
 	/* Handle errors. */
 	switch ((error && error->domain == E_CLIENT_ERROR) ? error->code : -1) {
 		case -1:
@@ -240,6 +284,24 @@ memo_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *resul
 	e_client_retrieve_capabilities (E_CLIENT (client), NULL, memo_shell_sidebar_retrieve_capabilies_cb, memo_shell_sidebar);
 }
 
+static gboolean
+memo_shell_sidebar_retry_open_timeout_cb (gpointer user_data)
+{
+	struct RetryOpenData *rod = user_data;
+
+	g_return_val_if_fail (rod != NULL, FALSE);
+	g_return_val_if_fail (rod->client != NULL, FALSE);
+	g_return_val_if_fail (rod->memo_shell_sidebar != NULL, FALSE);
+	g_return_val_if_fail (rod->cancellable != NULL, FALSE);
+
+	if (g_cancellable_is_cancelled (rod->cancellable))
+		return FALSE;
+
+	e_client_open (rod->client, FALSE, rod->memo_shell_sidebar->priv->loading_clients, memo_shell_sidebar_client_opened_cb, rod->memo_shell_sidebar);
+
+	return FALSE;
+}
+
 static void
 memo_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -254,11 +316,6 @@ memo_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *resu
 
 	priv = E_MEMO_SHELL_SIDEBAR (shell_sidebar)->priv;
 
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-	memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
-	model = e_memo_shell_content_get_memo_model (memo_shell_content);
-
 	if (!e_client_utils_open_new_finish (E_SOURCE (source_object), result, &client, &error))
 		client = NULL;
 
@@ -266,7 +323,14 @@ memo_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *resu
 	    g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED)) {
 		g_error_free (error);
 		goto exit;
-	} else if (error != NULL) {
+	}
+
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+	memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+	model = e_memo_shell_content_get_memo_model (memo_shell_content);
+
+	if (error != NULL) {
 		e_alert_submit (
 			E_ALERT_SINK (shell_content),
 			"calendar:failed-open-memos",
@@ -527,6 +591,12 @@ memo_shell_sidebar_dispose (GObject *object)
 		priv->loading_default_client = NULL;
 	}
 
+	if (priv->loading_clients != NULL) {
+		g_cancellable_cancel (priv->loading_clients);
+		g_object_unref (priv->loading_clients);
+		priv->loading_clients = NULL;
+	}
+
 	g_hash_table_remove_all (priv->client_table);
 
 	/* Chain up to parent's dispose() method. */
@@ -760,6 +830,7 @@ memo_shell_sidebar_init (EMemoShellSidebar *memo_shell_sidebar)
 		EMemoShellSidebarPrivate);
 
 	memo_shell_sidebar->priv->client_table = client_table;
+	memo_shell_sidebar->priv->loading_clients = g_cancellable_new ();
 
 	/* Postpone widget construction until we have a shell view. */
 }
@@ -914,7 +985,7 @@ e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
 	timezone = e_cal_model_get_timezone (model);
 
 	e_cal_client_set_default_timezone (client, timezone);
-	e_client_open (E_CLIENT (client), FALSE, NULL, memo_shell_sidebar_client_opened_cb, memo_shell_sidebar);
+	e_client_open (E_CLIENT (client), FALSE, memo_shell_sidebar->priv->loading_clients, memo_shell_sidebar_client_opened_cb, memo_shell_sidebar);
 }
 
 void
diff --git a/modules/calendar/e-task-shell-sidebar.c b/modules/calendar/e-task-shell-sidebar.c
index 04d2c25..dbb1ba9 100644
--- a/modules/calendar/e-task-shell-sidebar.c
+++ b/modules/calendar/e-task-shell-sidebar.c
@@ -55,6 +55,7 @@ struct _ETaskShellSidebarPrivate {
 	ECalClient *default_client;
 
 	GCancellable *loading_default_client;
+	GCancellable *loading_clients;
 };
 
 enum {
@@ -176,6 +177,28 @@ task_shell_sidebar_retrieve_capabilies_cb (GObject *source_object, GAsyncResult
 	task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
 }
 
+static gboolean task_shell_sidebar_retry_open_timeout_cb (gpointer user_data);
+
+struct RetryOpenData
+{
+	EClient *client;
+	ETaskShellSidebar *task_shell_sidebar;
+	GCancellable *cancellable;
+};
+
+static void
+free_retry_open_data (gpointer data)
+{
+	struct RetryOpenData *rod = data;
+
+	if (!rod)
+		return;
+
+	g_object_unref (rod->client);
+	g_object_unref (rod->cancellable);
+	g_free (rod);
+}
+
 static void
 task_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -186,22 +209,43 @@ task_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *resul
 	EShellSidebar *shell_sidebar;
 	GError *error = NULL;
 
-	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-
 	e_client_open_finish (E_CLIENT (client), result, &error);
 
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
+	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_clear_error (&error);
+		return;
+	}
+
 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED) ||
 	    g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED))
 		e_client_utils_forget_password (E_CLIENT (client));
 
 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
-		e_client_open (E_CLIENT (client), FALSE, NULL, task_shell_sidebar_client_opened_cb, user_data);
+		e_client_open (E_CLIENT (client), FALSE, task_shell_sidebar->priv->loading_clients, task_shell_sidebar_client_opened_cb, user_data);
+		g_clear_error (&error);
+		return;
+	}
+
+	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
+		struct RetryOpenData *rod;
+
+		rod = g_new0 (struct RetryOpenData, 1);
+		rod->client = g_object_ref (client);
+		rod->task_shell_sidebar = task_shell_sidebar;
+		rod->cancellable = g_object_ref (task_shell_sidebar->priv->loading_clients);
+
+		/* postpone for 1/2 of a second, backend is busy now */
+		g_timeout_add_full (G_PRIORITY_DEFAULT, 500, task_shell_sidebar_retry_open_timeout_cb, rod, free_retry_open_data);
+
 		g_clear_error (&error);
 		return;
 	}
 
+	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+
 	/* Handle errors. */
 	switch ((error && error->domain == E_CLIENT_ERROR) ? error->code : -1) {
 		case -1:
@@ -240,6 +284,24 @@ task_shell_sidebar_client_opened_cb (GObject *source_object, GAsyncResult *resul
 	e_client_retrieve_capabilities (E_CLIENT (client), NULL, task_shell_sidebar_retrieve_capabilies_cb, task_shell_sidebar);
 }
 
+static gboolean
+task_shell_sidebar_retry_open_timeout_cb (gpointer user_data)
+{
+	struct RetryOpenData *rod = user_data;
+
+	g_return_val_if_fail (rod != NULL, FALSE);
+	g_return_val_if_fail (rod->client != NULL, FALSE);
+	g_return_val_if_fail (rod->task_shell_sidebar != NULL, FALSE);
+	g_return_val_if_fail (rod->cancellable != NULL, FALSE);
+
+	if (g_cancellable_is_cancelled (rod->cancellable))
+		return FALSE;
+
+	e_client_open (rod->client, FALSE, rod->task_shell_sidebar->priv->loading_clients, task_shell_sidebar_client_opened_cb, rod->task_shell_sidebar);
+
+	return FALSE;
+}
+
 static void
 task_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
 {
@@ -254,11 +316,6 @@ task_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *resu
 
 	priv = E_TASK_SHELL_SIDEBAR (shell_sidebar)->priv;
 
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-	task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
-	model = e_task_shell_content_get_task_model (task_shell_content);
-
 	if (!e_client_utils_open_new_finish (E_SOURCE (source_object), result, &client, &error))
 		client = NULL;
 
@@ -266,7 +323,14 @@ task_shell_sidebar_default_loaded_cb (GObject *source_object, GAsyncResult *resu
 	    g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED)) {
 		g_error_free (error);
 		goto exit;
-	} else if (error != NULL) {
+	}
+
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+	task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+	model = e_task_shell_content_get_task_model (task_shell_content);
+
+	if (error != NULL) {
 		e_alert_submit (
 			E_ALERT_SINK (shell_content),
 			"calendar:failed-open-tasks",
@@ -527,6 +591,12 @@ task_shell_sidebar_dispose (GObject *object)
 		priv->loading_default_client = NULL;
 	}
 
+	if (priv->loading_clients != NULL) {
+		g_cancellable_cancel (priv->loading_clients);
+		g_object_unref (priv->loading_clients);
+		priv->loading_clients = NULL;
+	}
+
 	g_hash_table_remove_all (priv->client_table);
 
 	/* Chain up to parent's dispose() method. */
@@ -760,6 +830,7 @@ task_shell_sidebar_init (ETaskShellSidebar *task_shell_sidebar)
 		ETaskShellSidebarPrivate);
 
 	task_shell_sidebar->priv->client_table = client_table;
+	task_shell_sidebar->priv->loading_clients = g_cancellable_new ();
 
 	/* Postpone widget construction until we have a shell view. */
 }
@@ -914,7 +985,7 @@ e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
 	timezone = e_cal_model_get_timezone (model);
 
 	e_cal_client_set_default_timezone (client, timezone);
-	e_client_open (E_CLIENT (client), FALSE, NULL, task_shell_sidebar_client_opened_cb, task_shell_sidebar);
+	e_client_open (E_CLIENT (client), FALSE, task_shell_sidebar->priv->loading_clients, task_shell_sidebar_client_opened_cb, task_shell_sidebar);
 }
 
 void



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