Index: calendar/gui/e-cal-model.c
===================================================================
--- calendar/gui/e-cal-model.c	(revision 37479)
+++ calendar/gui/e-cal-model.c	(working copy)
@@ -81,6 +81,16 @@ struct _ECalModelPrivate {
 	/* callback, to retrieve start time for newly added rows by click-to-add */
 	ECalModelDefaultTimeFunc get_default_time;
 	gpointer get_default_time_user_data;
+
+	gboolean in_added;
+	gboolean in_modified;
+	gboolean in_removed;
+
+	GList *notify_added;
+	GList *notify_modified;
+	GList *notify_removed;
+
+	GMutex *notify_lock;
 };
 
 #define E_CAL_MODEL_COMPONENT_GET_PRIVATE(obj) \
@@ -214,6 +224,14 @@ e_cal_model_init (ECalModel *model)
 	priv->accounts = itip_addresses_get ();
 
 	priv->use_24_hour_format = TRUE;
+
+	priv->in_added = FALSE;
+	priv->in_modified = FALSE;
+	priv->in_removed = FALSE;
+	priv->notify_added = NULL;
+	priv->notify_modified = NULL;
+	priv->notify_removed = NULL;
+	priv->notify_lock = g_mutex_new ();
 }
 
 static void
@@ -289,6 +307,7 @@ e_cal_model_finalize (GObject *object)
 
 	clear_objects_array (priv);
 	g_ptr_array_free (priv->objects, FALSE);
+	g_mutex_free (priv->notify_lock);
 
 	g_free (priv);
 
@@ -1437,10 +1456,11 @@ ensure_dates_are_in_default_zone (icalco
 	}
 }
 
+static void e_cal_view_objects_added_cb (ECalView *query, GList *objects, ECalModel *model);
+
 static void
-e_cal_view_objects_added_cb (ECalView *query, GList *objects, gpointer user_data)
+process_added (ECalView *query, GList *objects, ECalModel *model)
 {
-	ECalModel *model = (ECalModel *) user_data;
 	ECalModelPrivate *priv;
 	GList *l;
 
@@ -1511,9 +1531,8 @@ e_cal_view_objects_added_cb (ECalView *q
 }
 
 static void
-e_cal_view_objects_modified_cb (ECalView *query, GList *objects, gpointer user_data)
+process_modified (ECalView *query, GList *objects, ECalModel *model)
 {
-	ECalModel *model = (ECalModel *) user_data;
 	ECalModelPrivate *priv;
 	GList *l, *list = NULL;
 
@@ -1586,10 +1605,9 @@ e_cal_view_objects_modified_cb (ECalView
 }
 
 static void
-e_cal_view_objects_removed_cb (ECalView *query, GList *ids, gpointer user_data)
+process_removed (ECalView *query, GList *ids, ECalModel *model)
 {
 	ECalModelPrivate *priv;
-	ECalModel *model = (ECalModel *) user_data;
 	GList *l;
 
 	priv = model->priv;
@@ -1623,6 +1641,106 @@ e_cal_view_objects_removed_cb (ECalView 
 	e_table_model_changed (E_TABLE_MODEL (model));
 }
 
+static gpointer
+copy_comp_id (gpointer id)
+{
+	ECalComponentId *comp_id = (ECalComponentId *) id, *copy;
+
+	g_return_val_if_fail (comp_id != NULL, NULL);
+
+	copy = g_new0 (ECalComponentId, 1);
+	copy->uid = g_strdup (comp_id->uid);
+	copy->rid = g_strdup (comp_id->rid);
+
+	return copy;
+}
+
+static void
+free_comp_id (gpointer id)
+{
+	ECalComponentId *comp_id = (ECalComponentId *) id;
+
+	g_return_if_fail (comp_id != NULL);
+
+	g_free (comp_id->uid);
+	g_free (comp_id->rid);
+	g_free (comp_id);
+}
+
+static void
+process_event (ECalView *query, GList *objects, ECalModel *model,
+	void (*process_fn) (ECalView *query, GList *objects, ECalModel *model), 
+	gboolean *in, GList **save_list, gpointer (*copy_fn) (gpointer data), void (*free_fn)(gpointer data))
+{
+	gboolean skip = FALSE;
+	GList *l;
+
+	g_mutex_lock (model->priv->notify_lock);
+	if (*in) {
+		skip = TRUE;
+		for (l = objects; l; l = l->next) {
+			if (l->data)
+				*save_list = g_list_append (*save_list, copy_fn (l->data));
+		}
+	} else {
+		*in = TRUE;
+	}
+
+	g_mutex_unlock (model->priv->notify_lock);
+
+	if (skip)
+		return;
+
+	/* do it */
+	process_fn (query, objects, model);
+
+	g_mutex_lock (model->priv->notify_lock);
+	while (*save_list) {
+		GList *copy = *save_list;
+		*save_list = NULL;
+		g_mutex_unlock (model->priv->notify_lock);
+
+		/* do it */
+		process_fn (query, copy, model);
+
+		for (l = copy; l; l = l->next) {
+			if (l->data) {
+				free_fn (l->data);
+			}
+		}
+		g_list_free (copy);
+
+		g_mutex_lock (model->priv->notify_lock);
+	}
+
+	*in = FALSE;
+	g_mutex_unlock (model->priv->notify_lock);
+}
+
+static void
+e_cal_view_objects_added_cb (ECalView *query, GList *objects, ECalModel *model)
+{
+	process_event (query, objects, model,
+		process_added, &model->priv->in_added, &model->priv->notify_added,
+		(gpointer (*)(gpointer)) icalcomponent_new_clone, (void (*)(gpointer)) icalcomponent_free);
+}
+
+static void
+e_cal_view_objects_modified_cb (ECalView *query, GList *objects, ECalModel *model)
+{
+	process_event (query, objects, model,
+		process_modified, &model->priv->in_modified, &model->priv->notify_modified,
+		(gpointer (*)(gpointer)) icalcomponent_new_clone, (void (*)(gpointer)) icalcomponent_free);
+}
+
+static void
+e_cal_view_objects_removed_cb (ECalView *query, GList *ids, ECalModel *model)
+{
+	process_event (query, ids, model,
+		process_removed, &model->priv->in_removed, &model->priv->notify_removed,
+		copy_comp_id, free_comp_id);
+}
+
 static void
 e_cal_view_progress_cb (ECalView *query, const char *message, int percent, gpointer user_data)
 {
Index: calendar/ChangeLog
===================================================================
--- calendar/ChangeLog	(revision 37479)
+++ calendar/ChangeLog	(working copy)
@@ -1,3 +1,14 @@
+2009-03-27  Milan Crha  <mcrha@redhat.com>
+
+	** Fix for bug #539334
+
+	* gui/e-cal-model.c: (struct _ECalModelPrivate), (e_cal_model_init),
+	(e_cal_model_finalize), (process_added), (process_modified),
+	(process_removed), (copy_comp_id), (free_comp_id), (process_event),
+	(e_cal_view_objects_added_cb), (e_cal_view_objects_modified_cb),
+	(e_cal_view_objects_removed_cb):
+	Postpone processing event when called recursively.
+
 2009-03-06  Milan Crha  <mcrha@redhat.com>
 
 	** Fix for bug #401346
