aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2011-11-24 23:35:59 +0800
committerMilan Crha <mcrha@redhat.com>2011-11-24 23:36:42 +0800
commit4169ce41cc34d992ebd63b1bcc8f604e69aea89a (patch)
tree1aba982292305af36dc6873f487d67443c34f277
parent2eb60688a1955a95c3a040bd98f76bb67e3ff3ed (diff)
downloadgsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.tar
gsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.tar.gz
gsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.tar.bz2
gsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.tar.lz
gsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.tar.xz
gsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.tar.zst
gsoc2013-evolution-4169ce41cc34d992ebd63b1bcc8f604e69aea89a.zip
Bug #664634 - Deadlock when processing completed tasks filter
-rw-r--r--calendar/gui/e-cal-model.c2
-rw-r--r--calendar/gui/e-task-table.c244
-rw-r--r--modules/calendar/e-task-shell-view-private.c30
-rw-r--r--modules/calendar/e-task-shell-view-private.h1
4 files changed, 165 insertions, 112 deletions
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index 4428d31cbd..fb9898775b 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -3752,7 +3752,9 @@ e_cal_model_generate_instances_sync (ECalModel *model,
GPtrArray *
e_cal_model_get_object_array (ECalModel *model)
{
+ g_return_val_if_fail (model != NULL, NULL);
g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
+ g_return_val_if_fail (model->priv != NULL, NULL);
return model->priv->objects;
}
diff --git a/calendar/gui/e-task-table.c b/calendar/gui/e-task-table.c
index 0a38889e2d..e052e82357 100644
--- a/calendar/gui/e-task-table.c
+++ b/calendar/gui/e-task-table.c
@@ -66,6 +66,7 @@
struct _ETaskTablePrivate {
gpointer shell_view; /* weak pointer */
ECalModel *model;
+ GCancellable *completed_cancellable; /* when processing completed tasks */
GtkTargetList *copy_target_list;
GtkTargetList *paste_target_list;
@@ -383,6 +384,12 @@ task_table_dispose (GObject *object)
priv = E_TASK_TABLE (object)->priv;
+ if (priv->completed_cancellable) {
+ g_cancellable_cancel (priv->completed_cancellable);
+ g_object_unref (priv->completed_cancellable);
+ priv->completed_cancellable = NULL;
+ }
+
if (priv->shell_view != NULL) {
g_object_remove_weak_pointer (
G_OBJECT (priv->shell_view), &priv->shell_view);
@@ -1474,6 +1481,8 @@ task_table_init (ETaskTable *task_table)
task_table->priv = G_TYPE_INSTANCE_GET_PRIVATE (
task_table, E_TYPE_TASK_TABLE, ETaskTablePrivate);
+ task_table->priv->completed_cancellable = NULL;
+
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_calendar_targets (target_list, 0);
task_table->priv->copy_target_list = target_list;
@@ -1634,62 +1643,79 @@ e_task_table_get_paste_target_list (ETaskTable *task_table)
}
static void
-hide_completed_rows (ECalModel *model,
- GList *clients_list,
- gchar *hide_sexp,
- GPtrArray *comp_objects)
+task_table_get_object_list_async (GList *clients_list,
+ const gchar *sexp,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
{
GList *l;
- GSList *m, *objects;
- ECalClient *client;
- gint pos;
- gboolean changed = FALSE;
for (l = clients_list; l != NULL; l = l->next) {
- GError *error = NULL;
+ ECalClient *client = l->data;
- client = l->data;
+ e_cal_client_get_object_list (
+ client, sexp, cancellable,
+ callback, callback_data);
+ }
+}
- e_cal_client_get_object_list_sync (
- client, hide_sexp, &objects, NULL, &error);
+static void
+hide_completed_rows_ready (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ECalModel *model = user_data;
+ GSList *m, *objects;
+ gboolean changed = FALSE;
+ gint pos;
+ GPtrArray *comp_objects;
+ GError *error = NULL;
- if (error != NULL) {
- g_warning (
- "%s: Could not get the objects: %s",
- G_STRFUNC, error->message);
- g_error_free (error);
- continue;
- }
+ if (!e_cal_client_get_object_list_finish (E_CAL_CLIENT (source_object), result, &objects, &error)) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ !g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED)) {
+ ESource *source = e_client_get_source (E_CLIENT (source_object));
- for (m = objects; m; m = m->next) {
- ECalModelComponent *comp_data;
- ECalComponentId *id;
- ECalComponent *comp = e_cal_component_new ();
-
- e_cal_component_set_icalcomponent (
- comp, icalcomponent_new_clone (m->data));
- id = e_cal_component_get_id (comp);
-
- comp_data = e_cal_model_get_component_for_uid (model, id);
- if (comp_data != NULL) {
- e_table_model_pre_change (E_TABLE_MODEL (model));
- pos = get_position_in_array (
- comp_objects, comp_data);
- e_table_model_row_deleted (
- E_TABLE_MODEL (model), pos);
- changed = TRUE;
-
- if (g_ptr_array_remove (comp_objects, comp_data))
- g_object_unref (comp_data);
- }
- e_cal_component_free_id (id);
- g_object_unref (comp);
+ g_debug ("%s: Could not get the objects from '%s': %s",
+ G_STRFUNC,
+ source ? e_source_peek_name (source) : "???",
+ error ? error->message : "Uknown error");
}
+ g_clear_error (&error);
+ return;
+ }
- g_slist_foreach (objects, (GFunc) icalcomponent_free, NULL);
- g_slist_free (objects);
+ comp_objects = e_cal_model_get_object_array (model);
+ g_return_if_fail (comp_objects != NULL);
+
+ for (m = objects; m; m = m->next) {
+ ECalModelComponent *comp_data;
+ ECalComponentId *id;
+ ECalComponent *comp = e_cal_component_new ();
+
+ e_cal_component_set_icalcomponent (
+ comp, icalcomponent_new_clone (m->data));
+ id = e_cal_component_get_id (comp);
+
+ comp_data = e_cal_model_get_component_for_uid (model, id);
+ if (comp_data != NULL) {
+ e_table_model_pre_change (E_TABLE_MODEL (model));
+ pos = get_position_in_array (
+ comp_objects, comp_data);
+ e_table_model_row_deleted (
+ E_TABLE_MODEL (model), pos);
+ changed = TRUE;
+
+ if (g_ptr_array_remove (comp_objects, comp_data))
+ g_object_unref (comp_data);
+ }
+ e_cal_component_free_id (id);
+ g_object_unref (comp);
}
+ e_cal_client_free_icalcomp_slist (objects);
+
if (changed) {
/* To notify about changes, because in call of
* row_deleted there are still all events. */
@@ -1698,68 +1724,71 @@ hide_completed_rows (ECalModel *model,
}
static void
-show_completed_rows (ECalModel *model,
- GList *clients_list,
- gchar *show_sexp,
- GPtrArray *comp_objects)
+show_completed_rows_ready (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GList *l;
- GSList *m, *objects;
ECalClient *client;
+ ECalModel *model = user_data;
+ GSList *m, *objects;
+ GPtrArray *comp_objects;
+ GError *error = NULL;
- for (l = clients_list; l != NULL; l = l->next) {
- GError *error = NULL;
+ if (!e_cal_client_get_object_list_finish (E_CAL_CLIENT (source_object), result, &objects, &error)) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ !g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED)) {
+ ESource *source = e_client_get_source (E_CLIENT (source_object));
- client = l->data;
+ g_debug ("%s: Could not get the objects from '%s': %s",
+ G_STRFUNC,
+ source ? e_source_peek_name (source) : "???",
+ error ? error->message : "Uknown error");
+ }
+ g_clear_error (&error);
+ return;
+ }
- e_cal_client_get_object_list_sync (
- client, show_sexp, &objects, NULL, &error);
+ client = E_CAL_CLIENT (source_object);
+ g_return_if_fail (client != NULL);
- if (error != NULL) {
- g_warning (
- "%s: Could not get the objects: %s",
- G_STRFUNC, error->message);
- g_error_free (error);
- continue;
- }
+ comp_objects = e_cal_model_get_object_array (model);
+ g_return_if_fail (comp_objects != NULL);
- for (m = objects; m; m = m->next) {
- ECalModelComponent *comp_data;
- ECalComponentId *id;
- ECalComponent *comp = e_cal_component_new ();
-
- e_cal_component_set_icalcomponent (
- comp, icalcomponent_new_clone (m->data));
- id = e_cal_component_get_id (comp);
-
- if (!(e_cal_model_get_component_for_uid (model, id))) {
- e_table_model_pre_change (E_TABLE_MODEL (model));
- comp_data = g_object_new (
- E_TYPE_CAL_MODEL_COMPONENT, NULL);
- comp_data->client = g_object_ref (client);
- comp_data->icalcomp =
- icalcomponent_new_clone (m->data);
- e_cal_model_set_instance_times (
- comp_data,
- e_cal_model_get_timezone (model));
- comp_data->dtstart = NULL;
- comp_data->dtend = NULL;
- comp_data->due = NULL;
- comp_data->completed = NULL;
- comp_data->color = NULL;
-
- g_ptr_array_add (comp_objects, comp_data);
- e_table_model_row_inserted (
- E_TABLE_MODEL (model),
- comp_objects->len - 1);
- }
- e_cal_component_free_id (id);
- g_object_unref (comp);
- }
+ for (m = objects; m; m = m->next) {
+ ECalModelComponent *comp_data;
+ ECalComponentId *id;
+ ECalComponent *comp = e_cal_component_new ();
- g_slist_foreach (objects, (GFunc) icalcomponent_free, NULL);
- g_slist_free (objects);
+ e_cal_component_set_icalcomponent (
+ comp, icalcomponent_new_clone (m->data));
+ id = e_cal_component_get_id (comp);
+
+ if (!(e_cal_model_get_component_for_uid (model, id))) {
+ e_table_model_pre_change (E_TABLE_MODEL (model));
+ comp_data = g_object_new (
+ E_TYPE_CAL_MODEL_COMPONENT, NULL);
+ comp_data->client = g_object_ref (client);
+ comp_data->icalcomp =
+ icalcomponent_new_clone (m->data);
+ e_cal_model_set_instance_times (
+ comp_data,
+ e_cal_model_get_timezone (model));
+ comp_data->dtstart = NULL;
+ comp_data->dtend = NULL;
+ comp_data->due = NULL;
+ comp_data->completed = NULL;
+ comp_data->color = NULL;
+
+ g_ptr_array_add (comp_objects, comp_data);
+ e_table_model_row_inserted (
+ E_TABLE_MODEL (model),
+ comp_objects->len - 1);
+ }
+ e_cal_component_free_id (id);
+ g_object_unref (comp);
}
+
+ e_cal_client_free_icalcomp_slist (objects);
}
/* Returns the current time, for the ECellDateEdit items.
@@ -1806,18 +1835,18 @@ e_task_table_process_completed_tasks (ETaskTable *task_table,
gboolean config_changed)
{
ECalModel *model;
- static GMutex *mutex = NULL;
+ GCancellable *cancellable;
gchar *hide_sexp, *show_sexp;
- GPtrArray *comp_objects = NULL;
- if (!mutex)
- mutex = g_mutex_new ();
+ if (task_table->priv->completed_cancellable) {
+ g_cancellable_cancel (task_table->priv->completed_cancellable);
+ g_object_unref (task_table->priv->completed_cancellable);
+ }
- g_mutex_lock (mutex);
+ task_table->priv->completed_cancellable = g_cancellable_new ();
+ cancellable = task_table->priv->completed_cancellable;
model = e_task_table_get_model (task_table);
- comp_objects = e_cal_model_get_object_array (model);
-
hide_sexp = calendar_config_get_hide_completed_tasks_sexp (TRUE);
show_sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
@@ -1827,15 +1856,16 @@ e_task_table_process_completed_tasks (ETaskTable *task_table,
/* Delete rows from model*/
if (hide_sexp) {
- hide_completed_rows (model, clients_list, hide_sexp, comp_objects);
+ task_table_get_object_list_async (clients_list, hide_sexp, cancellable,
+ hide_completed_rows_ready, model);
}
/* Insert rows into model */
if (config_changed) {
- show_completed_rows (model, clients_list, show_sexp, comp_objects);
+ task_table_get_object_list_async (clients_list, show_sexp, cancellable,
+ show_completed_rows_ready, model);
}
g_free (hide_sexp);
g_free (show_sexp);
- g_mutex_unlock (mutex);
}
diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c
index 3467c12190..916494757d 100644
--- a/modules/calendar/e-task-shell-view-private.c
+++ b/modules/calendar/e-task-shell-view-private.c
@@ -46,14 +46,17 @@ task_shell_view_model_row_appended_cb (ETaskShellView *task_shell_view,
e_task_shell_sidebar_add_source (task_shell_sidebar, source);
}
-static void
-task_shell_view_process_completed_tasks (ETaskShellView *task_shell_view)
+static gboolean
+task_shell_view_process_completed_tasks (gpointer user_data)
{
+ ETaskShellView *task_shell_view = user_data;
ETaskShellContent *task_shell_content;
ETaskShellSidebar *task_shell_sidebar;
ETaskTable *task_table;
GList *clients;
+ task_shell_view->priv->update_completed_timeout = 0;
+
task_shell_content = task_shell_view->priv->task_shell_content;
task_table = e_task_shell_content_get_task_table (task_shell_content);
@@ -67,6 +70,18 @@ task_shell_view_process_completed_tasks (ETaskShellView *task_shell_view)
e_shell_view_execute_search (E_SHELL_VIEW (task_shell_view));
g_list_free (clients);
+
+ return FALSE;
+}
+
+static void
+task_shell_view_schedule_process_completed_tasks (ETaskShellView *task_shell_view)
+{
+ if (task_shell_view->priv->update_completed_timeout)
+ g_source_remove (task_shell_view->priv->update_completed_timeout);
+
+ task_shell_view->priv->update_completed_timeout =
+ g_timeout_add_seconds (1, task_shell_view_process_completed_tasks, task_shell_view);
}
static void
@@ -345,15 +360,15 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
/* Hide Completed Tasks (enable/units/value) */
g_signal_connect_object (
shell_settings, "notify::cal-hide-completed-tasks",
- G_CALLBACK (task_shell_view_process_completed_tasks),
+ G_CALLBACK (task_shell_view_schedule_process_completed_tasks),
task_shell_view, G_CONNECT_SWAPPED);
g_signal_connect_object (
shell_settings, "notify::cal-hide-completed-tasks-units",
- G_CALLBACK (task_shell_view_process_completed_tasks),
+ G_CALLBACK (task_shell_view_schedule_process_completed_tasks),
task_shell_view, G_CONNECT_SWAPPED);
g_signal_connect_object (
shell_settings, "notify::cal-hide-completed-tasks-value",
- G_CALLBACK (task_shell_view_process_completed_tasks),
+ G_CALLBACK (task_shell_view_schedule_process_completed_tasks),
task_shell_view, G_CONNECT_SWAPPED);
e_task_shell_view_actions_init (task_shell_view);
@@ -392,6 +407,11 @@ e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
g_source_remove (priv->update_timeout);
priv->update_timeout = 0;
}
+
+ if (priv->update_completed_timeout > 0) {
+ g_source_remove (priv->update_completed_timeout);
+ priv->update_completed_timeout = 0;
+ }
}
void
diff --git a/modules/calendar/e-task-shell-view-private.h b/modules/calendar/e-task-shell-view-private.h
index ec2173f201..66e664645e 100644
--- a/modules/calendar/e-task-shell-view-private.h
+++ b/modules/calendar/e-task-shell-view-private.h
@@ -100,6 +100,7 @@ struct _ETaskShellViewPrivate {
EActivity *activity;
guint update_timeout;
+ guint update_completed_timeout;
guint confirm_purge : 1;
};