diff --git a/src/core/gcal-timeline.c b/src/core/gcal-timeline.c index 2369651e..bacc2fa6 100644 --- a/src/core/gcal-timeline.c +++ b/src/core/gcal-timeline.c @@ -77,6 +77,7 @@ struct _GcalTimeline GCancellable *cancellable; + GHashTable *queued_adds; GQueue *event_queue; GSource *timeline_source; @@ -101,6 +102,13 @@ static GParamSpec *properties [N_PROPS] = { NULL, }; * Auxiliary methods */ +static gchar* +format_subscriber_event_id (GcalTimelineSubscriber *subscriber, + GcalEvent *event) +{ + return g_strdup_printf ("%s:%s", G_OBJECT_TYPE_NAME (subscriber), gcal_event_get_uid (event)); +} + static void queue_data_free (QueueData *queue_data) { @@ -118,6 +126,7 @@ queue_event_data (GcalTimeline *self, GcalEvent *old_event, gboolean update_range_tree) { + g_autofree gchar *subscriber_event_id = NULL; QueueData *queue_data; queue_data = g_new0 (QueueData, 1); @@ -128,7 +137,49 @@ queue_event_data (GcalTimeline *self, queue_data->old_event = old_event ? g_object_ref (old_event) : NULL; queue_data->update_range_tree = update_range_tree; + subscriber_event_id = format_subscriber_event_id (subscriber, event); + + switch (queue_event) + { + case ADD_EVENT: + case UPDATE_EVENT: + break; + case REMOVE_EVENT: + { + GList *queued_add_link; + + queued_add_link = g_hash_table_lookup (self->queued_adds, subscriber_event_id); + if (queued_add_link) + { + QueueData *queued_add = queued_add_link->data; + + GCAL_TRACE_MSG ("Removing ADD_EVENT for event '%s' (%s) from event queue", + gcal_event_get_summary (event), + subscriber_event_id); + + g_hash_table_remove (self->queued_adds, subscriber_event_id); + g_queue_delete_link (self->event_queue, queued_add_link); + queue_data_free (queued_add); + return; + } + } + break; + } + g_queue_push_tail (self->event_queue, queue_data); + + switch (queue_event) + { + case ADD_EVENT: + g_hash_table_insert (self->queued_adds, + g_steal_pointer (&subscriber_event_id), + g_queue_peek_tail_link (self->event_queue)); + break; + + case UPDATE_EVENT: + case REMOVE_EVENT: + break; + } } static inline gboolean @@ -608,6 +659,7 @@ timeline_source_dispatch (GSource *source, while (processed_events < BATCH_SIZE && !g_queue_is_empty (self->event_queue)) { GcalTimelineSubscriber *subscriber; + g_autofree gchar *subscriber_event_id = NULL; GcalRange *event_range; QueueData *queue_data; GcalEvent *event; @@ -617,10 +669,12 @@ timeline_source_dispatch (GSource *source, event = queue_data->event; subscriber = queue_data->subscriber; event_range = gcal_event_get_range (event); + subscriber_event_id = format_subscriber_event_id (subscriber, event); /* The subscriber may have been removed already */ if (!g_hash_table_contains (self->subscribers, subscriber)) { + g_hash_table_remove (self->queued_adds, subscriber_event_id); queue_data_free (queue_data); continue; } @@ -628,10 +682,12 @@ timeline_source_dispatch (GSource *source, switch (queue_data->queue_event) { case ADD_EVENT: - GCAL_TRACE_MSG ("Processing ADD_EVENT for event '%s' (%s)", + GCAL_TRACE_MSG ("Processing ADD_EVENT for event '%s' (%s) (in queued_adds: %d)", gcal_event_get_summary (event), - gcal_event_get_uid (event)); + gcal_event_get_uid (event), + g_hash_table_contains (self->queued_adds, subscriber_event_id)); + g_hash_table_remove (self->queued_adds, subscriber_event_id); if (queue_data->update_range_tree) gcal_range_tree_add_range (self->events, event_range, g_object_ref (event)); @@ -708,6 +764,7 @@ gcal_timeline_finalize (GObject *object) g_clear_pointer (&self->events, gcal_range_tree_unref); g_clear_pointer (&self->calendars, g_hash_table_destroy); g_clear_pointer (&self->subscribers, g_hash_table_destroy); + g_clear_pointer (&self->queued_adds, g_hash_table_destroy); g_clear_pointer (&self->subscriber_ranges, gcal_range_tree_unref); g_source_destroy (self->timeline_source); @@ -829,6 +886,7 @@ gcal_timeline_init (GcalTimeline *self) self->subscribers = g_hash_table_new_full (NULL, NULL, g_object_unref, (GDestroyNotify) gcal_range_unref); self->subscriber_ranges = gcal_range_tree_new (); self->event_queue = g_queue_new (); + self->queued_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* Timeline source */ timeline_source = (TimelineSource*) g_source_new (&timeline_source_funcs, sizeof (TimelineSource));