Commit 5da21cee authored by Milan Crha's avatar Milan Crha
Browse files

Bug #655190 - Sluggish performance interacting with calendar/tasks

parent 444011c9
......@@ -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;
}
......@@ -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 */
......
......@@ -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);
}
}
......
......@@ -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,
......
......@@ -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);
......
......@@ -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,
......
......@@ -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,
......
......@@ -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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment