aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2011-08-02 21:23:52 +0800
committerRodrigo Moya <rodrigo@gnome-db.org>2011-09-14 20:08:42 +0800
commitcbe678c4c58efdb0b0d7960a9c6d33c30a95ce8c (patch)
treef0c3d5d4443eceff47a6f43c0daafdaac840143f
parent86f37c46dd2f61e86a82938c956490c37ed6f2ce (diff)
downloadgsoc2013-evolution-cbe678c4c58efdb0b0d7960a9c6d33c30a95ce8c.tar.gz
gsoc2013-evolution-cbe678c4c58efdb0b0d7960a9c6d33c30a95ce8c.tar.zst
gsoc2013-evolution-cbe678c4c58efdb0b0d7960a9c6d33c30a95ce8c.zip
Bug #655190 - Sluggish performance interacting with calendar/tasks
-rw-r--r--calendar/gui/dialogs/goto-dialog.c6
-rw-r--r--calendar/gui/dialogs/recurrence-page.c12
-rw-r--r--calendar/gui/e-cal-model.c156
-rw-r--r--calendar/gui/e-cal-model.h3
-rw-r--r--calendar/gui/gnome-cal.c14
-rw-r--r--calendar/gui/print.c11
-rw-r--r--calendar/gui/tag-calendar.c31
-rw-r--r--calendar/gui/tag-calendar.h4
8 files changed, 176 insertions, 61 deletions
diff --git a/calendar/gui/dialogs/goto-dialog.c b/calendar/gui/dialogs/goto-dialog.c
index 3ef0db31bf..7b8fffa430 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 bf8f1c191c..8e52250dfa 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 2b4aac732d..457455b88d 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 766fd6286f..33ffcff52d 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 4bb430c018..03b5b6bfa6 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 702f281b5a..2c17b05c86 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 dff1285587..affe2a3633 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 2dc5bff176..c01e379b6e 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