timeline: Implement processing changes in idle

This commit is contained in:
Georges Basile Stavracas Neto
2020-04-01 21:06:51 -03:00
parent f052cb6589
commit cfa4b56a05
+215 -42
View File
@@ -32,6 +32,31 @@
#include <libedataserver/libedataserver.h>
typedef enum
{
ADD_EVENT,
UPDATE_EVENT,
REMOVE_EVENT,
} QueueEvent;
typedef struct
{
GcalTimeline *timeline;
QueueEvent queue_event;
GPtrArray *subscribers;
GcalEvent *event;
GcalEvent *old_event;
gboolean update_range_tree;
} QueueData;
typedef struct
{
GSource parent;
GcalTimeline *timeline;
} TimelineSource;
typedef struct
{
GDateTime *range_start;
@@ -57,6 +82,9 @@ struct _GcalTimeline
GCancellable *cancellable;
GQueue *event_queue;
GSource *timeline_source;
GcalContext *context;
};
@@ -78,6 +106,36 @@ static GParamSpec *properties [N_PROPS] = { NULL, };
* Auxiliary methods
*/
static void
queue_data_free (QueueData *queue_data)
{
g_clear_pointer (&queue_data->subscribers, g_ptr_array_unref);
g_clear_object (&queue_data->old_event);
g_clear_object (&queue_data->event);
g_free (queue_data);
}
static void
queue_event_data (GcalTimeline *self,
QueueEvent queue_event,
GPtrArray *subscribers,
GcalEvent *event,
GcalEvent *old_event,
gboolean update_range_tree)
{
QueueData *queue_data;
queue_data = g_new0 (QueueData, 1);
queue_data->timeline = self;
queue_data->queue_event = queue_event;
queue_data->subscribers = subscribers ? g_ptr_array_ref (subscribers) : NULL;
queue_data->event = event ? g_object_ref (event) : NULL;
queue_data->old_event = old_event ? g_object_ref (old_event) : NULL;
queue_data->update_range_tree = update_range_tree;
g_queue_push_tail (self->event_queue, queue_data);
}
static inline gboolean
is_timeline_complete (GcalTimeline *self)
{
@@ -255,6 +313,7 @@ calculate_changed_events (GcalTimeline *self,
GDateTime *new_range_start,
GDateTime *new_range_end)
{
g_autoptr (GPtrArray) subscriber_array = NULL;
g_autoptr (GPtrArray) events_to_remove = NULL;
g_autoptr (GPtrArray) events_to_add = NULL;
gint range_diff;
@@ -305,6 +364,9 @@ calculate_changed_events (GcalTimeline *self,
}
}
subscriber_array = g_ptr_array_new ();
g_ptr_array_add (subscriber_array, subscriber);
for (i = 0; i < events_to_remove->len; i++)
{
GcalEvent *event = g_ptr_array_index (events_to_remove, i);
@@ -312,6 +374,12 @@ calculate_changed_events (GcalTimeline *self,
if (!gcal_event_is_within_range (event, old_range_start, old_range_end))
continue;
GCAL_TRACE_MSG ("Removing event from subscriber %s due to time range change (event: '%s' (%s))",
G_OBJECT_TYPE_NAME (subscriber),
gcal_event_get_summary (event),
gcal_event_get_uid (event));
/* XXX: remove immediately, but add in idle */
remove_event_from_subscriber (subscriber, event);
}
@@ -322,7 +390,12 @@ calculate_changed_events (GcalTimeline *self,
if (!gcal_event_is_within_range (event, new_range_start, new_range_end))
continue;
add_event_to_subscriber (subscriber, event);
GCAL_TRACE_MSG ("Queueing event addition for subscriber %s (event: '%s' (%s))",
G_OBJECT_TYPE_NAME (subscriber),
gcal_event_get_summary (event),
gcal_event_get_uid (event));
queue_event_data (self, ADD_EVENT, subscriber_array, event, NULL, FALSE);
}
}
@@ -390,26 +463,17 @@ on_calendar_monitor_event_added_cb (GcalCalendarMonitor *monitor,
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GDateTime *event_start;
GDateTime *event_end;
gint i;
GCAL_ENTRY;
event_start = gcal_event_get_date_start (event);
event_end = gcal_event_get_date_end (event);
gcal_range_tree_add_range (self->events, event_start, event_end, g_object_ref (event));
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_start, event_end);
for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i);
if (!subscriber_contains_event (subscriber, event))
continue;
add_event_to_subscriber (subscriber, event);
}
if (subscribers_at_range)
queue_event_data (self, ADD_EVENT, subscribers_at_range, event, NULL, TRUE);
GCAL_EXIT;
}
@@ -421,37 +485,20 @@ on_calendar_monitor_event_updated_cb (GcalCalendarMonitor *monitor,
GcalTimeline *self)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GDateTime *old_event_start;
GDateTime *old_event_end;
GDateTime *event_start;
GDateTime *event_end;
gint i;
GCAL_ENTRY;
/* Remove the old event */
old_event_start = gcal_event_get_date_start (old_event);
old_event_end = gcal_event_get_date_end (old_event);
gcal_range_tree_remove_range (self->events, old_event_start, old_event_end, old_event);
/* Add the updated event to the (potentially new) range */
event_start = gcal_event_get_date_start (event);
event_end = gcal_event_get_date_end (event);
gcal_range_tree_add_range (self->events, event_start, event_end, g_object_ref (event));
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_start, event_end);
for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i);
if (!subscriber_contains_event (subscriber, event))
continue;
update_subscriber_event (subscriber, event);
}
if (subscribers_at_range)
queue_event_data (self, UPDATE_EVENT, subscribers_at_range, event, old_event, TRUE);
GCAL_EXIT;
}
@@ -464,7 +511,6 @@ on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor,
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GDateTime *event_start;
GDateTime *event_end;
gint i;
GCAL_ENTRY;
@@ -473,17 +519,9 @@ on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor,
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_start, event_end);
for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i);
if (!subscriber_contains_event (subscriber, event))
continue;
remove_event_from_subscriber (subscriber, event);
}
gcal_range_tree_remove_range (self->events, event_start, event_end, event);
if (subscribers_at_range)
queue_event_data (self, REMOVE_EVENT, subscribers_at_range, event, NULL, TRUE);
GCAL_EXIT;
}
@@ -527,6 +565,122 @@ on_subscriber_range_changed_cb (GcalTimelineSubscriber *subscriber,
self->update_range_idle_id = g_idle_add (update_timeline_range_in_idle_cb, self);
}
static gboolean
timeline_source_prepare (GSource *source,
gint *timeout)
{
TimelineSource *timeline_source;
GcalTimeline *self;
timeline_source = (TimelineSource*) source;
self = timeline_source->timeline;
return self->event_queue->length > 0;
}
static gboolean
timeline_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
TimelineSource *timeline_source;
GcalTimeline *self;
GDateTime *event_start;
GDateTime *event_end;
QueueData *queue_data;
GcalEvent *event;
gint i;
GCAL_ENTRY;
timeline_source = (TimelineSource*) source;
self = timeline_source->timeline;
queue_data = g_queue_pop_head (self->event_queue);
event = queue_data->event;
event_start = gcal_event_get_date_start (event);
event_end = gcal_event_get_date_end (event);
switch (queue_data->queue_event)
{
case ADD_EVENT:
GCAL_TRACE_MSG ("Processing ADD_EVENT for event '%s' (%s)",
gcal_event_get_summary (event),
gcal_event_get_uid (event));
if (queue_data->update_range_tree)
gcal_range_tree_add_range (self->events, event_start, event_end, g_object_ref (event));
for (i = 0; queue_data->subscribers && i < queue_data->subscribers->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (queue_data->subscribers, i);
if (!subscriber_contains_event (subscriber, event))
continue;
add_event_to_subscriber (subscriber, event);
}
break;
case UPDATE_EVENT:
{
GCAL_TRACE_MSG ("Processing UPDATE_EVENT for event '%s' (%s)",
gcal_event_get_summary (event),
gcal_event_get_uid (event));
if (queue_data->update_range_tree)
{
GDateTime *old_event_start;
GDateTime *old_event_end;
/* Remove the old event */
old_event_start = gcal_event_get_date_start (queue_data->old_event);
old_event_end = gcal_event_get_date_end (queue_data->old_event);
gcal_range_tree_remove_range (self->events, old_event_start, old_event_end, queue_data->old_event);
gcal_range_tree_add_range (self->events, event_start, event_end, g_object_ref (event));
}
for (i = 0; queue_data->subscribers && i < queue_data->subscribers->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (queue_data->subscribers, i);
if (!subscriber_contains_event (subscriber, event))
continue;
update_subscriber_event (subscriber, event);
}
}
break;
case REMOVE_EVENT:
GCAL_TRACE_MSG ("Processing REMOVE_EVENT for event '%s' (%s)",
gcal_event_get_summary (event),
gcal_event_get_uid (event));
for (i = 0; queue_data->subscribers && i < queue_data->subscribers->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (queue_data->subscribers, i);
remove_event_from_subscriber (subscriber, event);
}
if (queue_data->update_range_tree)
gcal_range_tree_remove_range (self->events, event_start, event_end, event);
break;
}
queue_data_free (queue_data);
GCAL_RETURN (G_SOURCE_CONTINUE);
}
static GSourceFuncs timeline_source_funcs =
{
timeline_source_prepare,
NULL,
timeline_source_dispatch,
NULL,
};
/*
* GObject overrides
@@ -550,6 +704,13 @@ gcal_timeline_finalize (GObject *object)
g_clear_pointer (&self->calendars, g_hash_table_destroy);
g_clear_pointer (&self->subscribers, g_hash_table_destroy);
g_clear_pointer (&self->subscriber_ranges, gcal_range_tree_unref);
g_clear_pointer (&self->timeline_source, g_source_destroy);
if (self->event_queue)
{
g_queue_free_full (self->event_queue, (GDestroyNotify) queue_data_free);
self->event_queue = NULL;
}
G_OBJECT_CLASS (gcal_timeline_parent_class)->finalize (object);
}
@@ -653,11 +814,23 @@ gcal_timeline_class_init (GcalTimelineClass *klass)
static void
gcal_timeline_init (GcalTimeline *self)
{
TimelineSource *timeline_source;
self->cancellable = g_cancellable_new ();
self->events = gcal_range_tree_new_with_free_func (g_object_unref);
self->calendars = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
self->subscribers = g_hash_table_new_full (NULL, NULL, g_object_unref, (GDestroyNotify) subscriber_data_free);
self->subscriber_ranges = gcal_range_tree_new ();
self->event_queue = g_queue_new ();
/* Timeline source */
timeline_source = (TimelineSource*) g_source_new (&timeline_source_funcs, sizeof (TimelineSource));
timeline_source->timeline = self;
self->timeline_source = (GSource*) timeline_source;
g_source_set_name (self->timeline_source, "Timeline Source");
g_source_set_priority (self->timeline_source, G_PRIORITY_DEFAULT_IDLE);
g_source_attach (self->timeline_source, g_main_context_default ());
}
/**