[evolution] Bug #655190 - Sluggish performance interacting with calendar/tasks



commit 5da21ceee424eb238278bdec258b0c6d8725ae21
Author: Milan Crha <mcrha redhat com>
Date:   Tue Aug 2 15:23:52 2011 +0200

    Bug #655190 - Sluggish performance interacting with calendar/tasks

 calendar/gui/dialogs/goto-dialog.c     |    6 +-
 calendar/gui/dialogs/recurrence-page.c |   12 +++-
 calendar/gui/e-cal-model.c             |  156 ++++++++++++++++++++++++--------
 calendar/gui/e-cal-model.h             |    3 +-
 calendar/gui/gnome-cal.c               |   14 +++-
 calendar/gui/print.c                   |   11 +--
 calendar/gui/tag-calendar.c            |   31 +++++--
 calendar/gui/tag-calendar.h            |    4 +-
 8 files changed, 176 insertions(+), 61 deletions(-)
---
diff --git a/calendar/gui/dialogs/goto-dialog.c b/calendar/gui/dialogs/goto-dialog.c
index 3ef0db3..7b8fffa 100644
--- a/calendar/gui/dialogs/goto-dialog.c
+++ b/calendar/gui/dialogs/goto-dialog.c
@@ -52,6 +52,7 @@ typedef struct
 	gint month_val;
 	gint day_val;
 
+	GCancellable *cancellable;
 } GoToDialog;
 
 static GoToDialog *dlg = NULL;
@@ -94,7 +95,7 @@ ecal_date_range_changed (ECalendarItem *calitem, gpointer user_data)
 	model = gnome_calendar_get_model (dlg->gcal);
 	client = e_cal_model_get_default_client (model);
 	if (client)
-		tag_calendar_by_client (dlg->ecal, client);
+		tag_calendar_by_client (dlg->ecal, client, dlg->cancellable);
 }
 
 /* Event handler for day groups in the month item.  A button press makes
@@ -248,6 +249,7 @@ goto_dialog (GtkWindow *parent, GnomeCalendar *gcal)
 		return;
 	}
 	dlg->gcal = gcal;
+	dlg->cancellable = g_cancellable_new ();
 
 	model = gnome_calendar_get_model (gcal);
 	timezone = e_cal_model_get_timezone (model);
@@ -287,6 +289,8 @@ goto_dialog (GtkWindow *parent, GnomeCalendar *gcal)
 		goto_today (dlg);
 
 	g_object_unref (dlg->builder);
+	g_cancellable_cancel (dlg->cancellable);
+	g_object_unref (dlg->cancellable);
 	g_free (dlg);
 	dlg = NULL;
 }
diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c
index bf8f1c1..8e52250 100644
--- a/calendar/gui/dialogs/recurrence-page.c
+++ b/calendar/gui/dialogs/recurrence-page.c
@@ -185,6 +185,8 @@ struct _RecurrencePagePrivate {
 
 	/* This just holds some settings we need */
 	EMeetingStore *meeting_store;
+
+	GCancellable *cancellable;
 };
 
 
@@ -266,7 +268,7 @@ preview_recur (RecurrencePage *rpage)
 	fill_component (rpage, comp);
 
 	tag_calendar_by_comp (E_CALENDAR (priv->preview_calendar), comp,
-			      client, zone, TRUE, FALSE, FALSE);
+			      client, zone, TRUE, FALSE, FALSE, priv->cancellable);
 	g_object_unref (comp);
 }
 
@@ -324,6 +326,12 @@ recurrence_page_dispose (GObject *object)
 		priv->meeting_store = NULL;
 	}
 
+	if (priv->cancellable) {
+		g_cancellable_cancel (priv->cancellable);
+		g_object_unref (priv->cancellable);
+		priv->cancellable = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (recurrence_page_parent_class)->dispose (object);
 }
@@ -379,6 +387,8 @@ recurrence_page_init (RecurrencePage *rpage)
 {
 	rpage->priv = G_TYPE_INSTANCE_GET_PRIVATE (
 		rpage, TYPE_RECURRENCE_PAGE, RecurrencePagePrivate);
+
+	rpage->priv->cancellable = g_cancellable_new ();
 }
 
 /* get_widget handler for the recurrence page */
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index 2b4aac7..457455b 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -46,6 +46,7 @@ typedef struct {
 	ECalClientView *view;
 
 	gboolean do_query;
+	GCancellable *cancellable;
 } ECalModelClient;
 
 struct _ECalModelPrivate {
@@ -398,6 +399,10 @@ cal_model_dispose (GObject *object)
 			priv->clients = g_list_remove (priv->clients, client_data);
 
 			g_object_unref (client_data->client);
+			if (client_data->cancellable) {
+				g_cancellable_cancel (client_data->cancellable);
+				g_object_unref (client_data->cancellable);
+			}
 			if (client_data->view)
 				g_object_unref (client_data->view);
 			g_free (client_data);
@@ -2226,14 +2231,18 @@ process_added (ECalClientView *view, const GSList *objects, ECalModel *model)
 		ensure_dates_are_in_default_zone (model, l->data);
 
 		if (e_cal_util_component_has_recurrences (l->data) && (priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES)) {
-			RecurrenceExpansionData rdata;
-
-			rdata.client = client;
-			rdata.view = view;
-			rdata.model = model;
-			rdata.icalcomp = l->data;
-			e_cal_client_generate_instances_for_object (rdata.client, l->data, priv->start, priv->end,
-								    (ECalRecurInstanceFn) add_instance_cb, &rdata);
+			ECalModelClient *client_data = find_client_data (model, client);
+
+			if (client_data) {
+				RecurrenceExpansionData *rdata = g_new0 (RecurrenceExpansionData, 1);
+				rdata->client = client;
+				rdata->view = view;
+				rdata->model = model;
+				rdata->icalcomp = l->data;
+
+				e_cal_client_generate_instances_for_object (rdata->client, l->data, priv->start, priv->end, client_data->cancellable,
+									    (ECalRecurInstanceFn) add_instance_cb, rdata, g_free);
+			}
 		} else {
 			e_table_model_pre_change (E_TABLE_MODEL (model));
 
@@ -2494,12 +2503,97 @@ client_view_complete_cb (ECalClientView *view, const GError *error, gpointer use
 			e_cal_client_get_source_type (client));
 }
 
+struct get_view_data
+{
+	ECalModel *model; /* do not touch this, if cancelled */
+	ECalModelClient *client_data; /* do not touch this, if cancelled */
+	GCancellable *cancellable;
+	guint tries;
+};
+
+static void
+free_get_view_data (struct get_view_data *gvd)
+{
+	if (!gvd)
+		return;
+
+	g_object_unref (gvd->cancellable);
+	g_free (gvd);
+}
+
+static gboolean retry_get_view_timeout_cb (gpointer user_data);
+
+static void
+get_view_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	struct get_view_data *gvd = user_data;
+	GError *error = NULL;
+	ECalClientView *view = NULL;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (result != NULL);
+	g_return_if_fail (gvd != NULL);
+	g_return_if_fail (gvd->model != NULL);
+	g_return_if_fail (gvd->client_data != NULL);
+
+	if (!e_cal_client_get_view_finish (E_CAL_CLIENT (source_object), result, &view, &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);
+
+			free_get_view_data (gvd);
+			return;
+		}
+
+		if (gvd->tries < 10) {
+			gvd->tries++;
+			g_timeout_add (500, retry_get_view_timeout_cb, gvd);
+			return;
+		}
+
+		g_debug ("%s: Failed to get view: %s", G_STRFUNC, error ? error->message : "Unknown error");
+
+		g_clear_error (&error);
+	} else {
+		gvd->client_data->view = view;
+
+		g_signal_connect (gvd->client_data->view, "objects-added", G_CALLBACK (client_view_objects_added_cb), gvd->model);
+		g_signal_connect (gvd->client_data->view, "objects-modified", G_CALLBACK (client_view_objects_modified_cb), gvd->model);
+		g_signal_connect (gvd->client_data->view, "objects-removed", G_CALLBACK (client_view_objects_removed_cb), gvd->model);
+		g_signal_connect (gvd->client_data->view, "progress", G_CALLBACK (client_view_progress_cb), gvd->model);
+		g_signal_connect (gvd->client_data->view, "complete", G_CALLBACK (client_view_complete_cb), gvd->model);
+
+		e_cal_client_view_start (gvd->client_data->view, &error);
+	
+		if (error) {
+			g_debug ("%s: Failed to start view: %s", G_STRFUNC, error->message);
+			g_error_free (error);
+		}
+	}
+
+	free_get_view_data (gvd);
+}
+
+static gboolean
+retry_get_view_timeout_cb (gpointer user_data)
+{
+	struct get_view_data *gvd = user_data;
+
+	if (g_cancellable_is_cancelled (gvd->cancellable)) {
+		free_get_view_data (gvd);
+		return FALSE;
+	}
+
+	e_cal_client_get_view (gvd->client_data->client, gvd->model->priv->full_sexp, gvd->cancellable, get_view_cb, gvd);
+
+	return FALSE;
+}
+
 static void
 update_e_cal_view_for_client (ECalModel *model, ECalModelClient *client_data)
 {
 	ECalModelPrivate *priv;
-	GError *error = NULL;
-	gint tries = 0;
+	struct get_view_data *gvd;
 
 	priv = model->priv;
 
@@ -2522,34 +2616,20 @@ update_e_cal_view_for_client (ECalModel *model, ECalModelClient *client_data)
 	if (!client_data->do_query)
 		return;
 
- try_again:
-	if (!e_cal_client_get_view_sync (client_data->client, priv->full_sexp, &client_data->view, NULL, &error)) {
-		if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && tries != 10) {
-			tries++;
-			/*TODO chose an optimal value */
-			g_usleep (500);
-			g_clear_error (&error);
-			goto try_again;
-		}
-
-		g_warning (G_STRLOC ": Unable to get query, %s", error ? error->message : "Unknown error");
-		if (error)
-			g_error_free (error);
-
-		return;
+	if (client_data->cancellable) {
+		g_cancellable_cancel (client_data->cancellable);
+		g_object_unref (client_data->cancellable);
 	}
 
-	g_signal_connect (client_data->view, "objects-added", G_CALLBACK (client_view_objects_added_cb), model);
-	g_signal_connect (client_data->view, "objects-modified", G_CALLBACK (client_view_objects_modified_cb), model);
-	g_signal_connect (client_data->view, "objects-removed", G_CALLBACK (client_view_objects_removed_cb), model);
-	g_signal_connect (client_data->view, "progress", G_CALLBACK (client_view_progress_cb), model);
-	g_signal_connect (client_data->view, "complete", G_CALLBACK (client_view_complete_cb), model);
+	client_data->cancellable = g_cancellable_new ();
 
-	e_cal_client_view_start (client_data->view, &error);
-	if (error) {
-		g_debug ("%s: Failed to start view: %s", G_STRFUNC, error->message);
-		g_error_free (error);
-	}
+	gvd = g_new0 (struct get_view_data, 1);
+	gvd->client_data = client_data;
+	gvd->model = model;
+	gvd->tries = 0;
+	gvd->cancellable = g_object_ref (client_data->cancellable);
+
+	e_cal_client_get_view (client_data->client, priv->full_sexp, gvd->cancellable, get_view_cb, gvd);
 }
 
 void
@@ -3353,12 +3433,12 @@ e_cal_model_component_get_type (void)
 }
 
 /**
- * e_cal_model_generate_instances
+ * e_cal_model_generate_instances_sync
  *
  * cb function is not called with cb_data, but with ECalModelGenerateInstancesData which contains cb_data
  */
 void
-e_cal_model_generate_instances (ECalModel *model, time_t start, time_t end,
+e_cal_model_generate_instances_sync (ECalModel *model, time_t start, time_t end,
 				ECalRecurInstanceFn cb, gpointer cb_data)
 {
 	ECalModelGenerateInstancesData mdata;
@@ -3372,7 +3452,7 @@ e_cal_model_generate_instances (ECalModel *model, time_t start, time_t end,
 		mdata.cb_data = cb_data;
 
 		if (comp_data->instance_start < end && comp_data->instance_end > start)
-			e_cal_client_generate_instances_for_object (comp_data->client, comp_data->icalcomp, start, end, cb, &mdata);
+			e_cal_client_generate_instances_for_object_sync (comp_data->client, comp_data->icalcomp, start, end, cb, &mdata);
 	}
 }
 
diff --git a/calendar/gui/e-cal-model.h b/calendar/gui/e-cal-model.h
index 766fd62..33ffcff 100644
--- a/calendar/gui/e-cal-model.h
+++ b/calendar/gui/e-cal-model.h
@@ -281,7 +281,8 @@ ECalModelComponent *
 						 const ECalComponentId *id);
 gchar *		e_cal_model_date_value_to_string (ECalModel *model,
 						 gconstpointer value);
-void		e_cal_model_generate_instances	(ECalModel *model,
+void		e_cal_model_generate_instances_sync
+						(ECalModel *model,
 						 time_t start,
 						 time_t end,
 						 ECalRecurInstanceFn cb,
diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c
index 4bb430c..03b5b6b 100644
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@ -131,6 +131,8 @@ struct _GnomeCalendarPrivate {
 	/* Used in update_todo_view, to prevent interleaving when
 	 * called in separate thread. */
 	GMutex *todo_update_lock;
+
+	GCancellable *cancellable;
 };
 
 enum {
@@ -775,7 +777,7 @@ dn_client_view_objects_added_cb (ECalClientView *view, const GSList *objects, gp
 		tag_calendar_by_comp (
 			priv->date_navigator, comp,
 			e_cal_client_view_get_client (view),
-			NULL, FALSE, TRUE, TRUE);
+			NULL, FALSE, TRUE, TRUE, priv->cancellable);
 		g_object_unref (comp);
 	}
 }
@@ -1438,6 +1440,8 @@ gnome_calendar_init (GnomeCalendar *gcal)
 	priv->visible_start = -1;
 	priv->visible_end = -1;
 	priv->updating = FALSE;
+
+	priv->cancellable = g_cancellable_new ();
 }
 
 static void
@@ -1492,6 +1496,12 @@ gnome_calendar_do_dispose (GObject *object)
 		priv->update_marcus_bains_line_timeout = 0;
 	}
 
+	if (priv->cancellable) {
+		g_cancellable_cancel (priv->cancellable);
+		g_object_unref (priv->cancellable);
+		priv->cancellable = NULL;
+	}
+
 	G_OBJECT_CLASS (gnome_calendar_parent_class)->dispose (object);
 }
 
@@ -2238,7 +2248,7 @@ gnome_calendar_purge (GnomeCalendar *gcal, time_t older_than)
 				pd.remove = TRUE;
 				pd.older_than = older_than;
 
-				e_cal_client_generate_instances_for_object (client, m->data,
+				e_cal_client_generate_instances_for_object_sync (client, m->data,
 							     older_than, G_MAXINT32,
 							     check_instance_cb,
 							     &pd);
diff --git a/calendar/gui/print.c b/calendar/gui/print.c
index 702f281..2c17b05 100644
--- a/calendar/gui/print.c
+++ b/calendar/gui/print.c
@@ -786,7 +786,7 @@ print_month_small (GtkPrintContext *context, GnomeCalendar *gcal, time_t month,
 				sprintf (buf, "%d", day);
 
 				/* this is a slow messy way to do this ... but easy ... */
-				e_cal_model_generate_instances (gnome_calendar_get_model (gcal), now,
+				e_cal_model_generate_instances_sync (gnome_calendar_get_model (gcal), now,
 								time_day_end_with_zone (now, zone),
 								instance_cb, &found);
 
@@ -1412,7 +1412,7 @@ print_day_details (GtkPrintContext *context, GnomeCalendar *gcal, time_t whence,
 	pdi.zone = e_cal_model_get_timezone (model);
 
 	/* Get the events from the server. */
-	e_cal_model_generate_instances (model, start, end, print_day_details_cb, &pdi);
+	e_cal_model_generate_instances_sync (model, start, end, print_day_details_cb, &pdi);
 	qsort (pdi.long_events->data, pdi.long_events->len,
 	       sizeof (EDayViewEvent), e_day_view_event_sort_func);
 	qsort (pdi.events[0]->data, pdi.events[0]->len,
@@ -1976,7 +1976,7 @@ print_week_summary (GtkPrintContext *context, GnomeCalendar *gcal,
 	}
 
 	/* Get the events from the server. */
-	e_cal_model_generate_instances (model,
+	e_cal_model_generate_instances_sync (model,
 					psi.day_starts[0], psi.day_starts[psi.days_shown],
 					print_week_summary_cb, &psi);
 	qsort (psi.events->data, psi.events->len,
@@ -2496,7 +2496,7 @@ print_work_week_day_details (GtkPrintContext *context, GnomeCalendar *gcal,
 	pdi.zone = e_cal_model_get_timezone (model);
 
 	/* Get the events from the server. */
-	e_cal_model_generate_instances (model, start, end, print_day_details_cb, &pdi);
+	e_cal_model_generate_instances_sync (model, start, end, print_day_details_cb, &pdi);
 	qsort (pdi.long_events->data, pdi.long_events->len,
 	       sizeof (EDayViewEvent), e_day_view_event_sort_func);
 	qsort (pdi.events[0]->data, pdi.events[0]->len,
@@ -2689,8 +2689,7 @@ print_work_week_view (GtkPrintContext *context, GnomeCalendar *gcal, time_t date
 	pdi.end_hour = e_cal_model_get_work_day_end_hour (model);
 	pdi.zone = zone;
 
-	e_cal_model_generate_instances (model, start, end,
-					print_work_week_view_cb, &pdi);
+	e_cal_model_generate_instances_sync (model, start, end, print_work_week_view_cb, &pdi);
 
 	print_work_week_background (context, gcal, date, &pdi, 0.0, width,
 				    HEADER_HEIGHT + DAY_VIEW_ROW_HEIGHT + LONG_EVENT_OFFSET,
diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c
index dff1285..affe2a3 100644
--- a/calendar/gui/tag-calendar.c
+++ b/calendar/gui/tag-calendar.c
@@ -145,15 +145,17 @@ get_recur_events_italic (void)
  * tag_calendar_by_client:
  * @ecal: Calendar widget to tag.
  * @client: A calendar client object.
+ * @cancellable: A #GCancellable; can be %NULL
  *
  * Tags an #ECalendar widget with the events that occur in its current time
  * range.  The occurrences are extracted from the specified calendar @client.
  **/
 void
 tag_calendar_by_client (ECalendar *ecal,
-                        ECalClient *client)
+                        ECalClient *client,
+			GCancellable *cancellable)
 {
-	struct calendar_tag_closure c;
+	struct calendar_tag_closure *c;
 
 	g_return_if_fail (E_IS_CALENDAR (ecal));
 	g_return_if_fail (E_IS_CAL_CLIENT (client));
@@ -165,14 +167,18 @@ tag_calendar_by_client (ECalendar *ecal,
 	if (!e_client_is_opened (E_CLIENT (client)))
 		return;
 
-	if (!prepare_tag (ecal, &c, NULL, TRUE))
+	c = g_new0 (struct calendar_tag_closure, 1);
+
+	if (!prepare_tag (ecal, c, NULL, TRUE)) {
+		g_free (c);
 		return;
+	}
 
-	c.skip_transparent_events = TRUE;
-	c.recur_events_italic = get_recur_events_italic ();
+	c->skip_transparent_events = TRUE;
+	c->recur_events_italic = get_recur_events_italic ();
 
 	e_cal_client_generate_instances (
-		client, c.start_time, c.end_time, tag_calendar_cb, &c);
+		client, c->start_time, c->end_time, cancellable, tag_calendar_cb, c, g_free);
 }
 
 /* Resolves TZIDs for the recurrence generator, for when the comp is not on
@@ -227,7 +233,8 @@ tag_calendar_by_comp (ECalendar *ecal,
                       icaltimezone *display_zone,
                       gboolean clear_first,
                       gboolean comp_is_on_server,
-		      gboolean can_recur_events_italic)
+		      gboolean can_recur_events_italic,
+		      GCancellable *cancellable)
 {
 	struct calendar_tag_closure c;
 
@@ -244,11 +251,15 @@ tag_calendar_by_comp (ECalendar *ecal,
 	c.skip_transparent_events = FALSE;
 	c.recur_events_italic = can_recur_events_italic && get_recur_events_italic ();
 
-	if (comp_is_on_server)
+	if (comp_is_on_server) {
+		struct calendar_tag_closure *closure = g_new0 (struct calendar_tag_closure, 1);
+
+		*closure = c;
+
 		e_cal_client_generate_instances_for_object (
 			client, e_cal_component_get_icalcomponent (comp),
-			c.start_time, c.end_time, tag_calendar_cb, &c);
-	else
+			c.start_time, c.end_time, cancellable, tag_calendar_cb, closure, g_free);
+	} else
 		e_cal_recur_generate_instances (
 			comp, c.start_time, c.end_time,
 			tag_calendar_cb, &c, resolve_tzid_cb,
diff --git a/calendar/gui/tag-calendar.h b/calendar/gui/tag-calendar.h
index 2dc5bff..c01e379 100644
--- a/calendar/gui/tag-calendar.h
+++ b/calendar/gui/tag-calendar.h
@@ -30,10 +30,10 @@
 #include <misc/e-calendar.h>
 #include <libecal/e-cal-client.h>
 
-void tag_calendar_by_client (ECalendar *ecal, ECalClient *client);
+void tag_calendar_by_client (ECalendar *ecal, ECalClient *client, GCancellable *cancellable);
 void tag_calendar_by_comp (ECalendar *ecal, ECalComponent *comp,
 			   ECalClient *client, icaltimezone *display_zone,
 			   gboolean clear_first, gboolean comp_is_on_server,
-			   gboolean can_recur_events_italic);
+			   gboolean can_recur_events_italic, GCancellable *cancellable);
 
 #endif



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