timeline: Implement processing changes in idle
This commit is contained in:
+215
-42
@@ -32,6 +32,31 @@
|
|||||||
|
|
||||||
#include <libedataserver/libedataserver.h>
|
#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
|
typedef struct
|
||||||
{
|
{
|
||||||
GDateTime *range_start;
|
GDateTime *range_start;
|
||||||
@@ -57,6 +82,9 @@ struct _GcalTimeline
|
|||||||
|
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
GQueue *event_queue;
|
||||||
|
GSource *timeline_source;
|
||||||
|
|
||||||
GcalContext *context;
|
GcalContext *context;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,6 +106,36 @@ static GParamSpec *properties [N_PROPS] = { NULL, };
|
|||||||
* Auxiliary methods
|
* 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
|
static inline gboolean
|
||||||
is_timeline_complete (GcalTimeline *self)
|
is_timeline_complete (GcalTimeline *self)
|
||||||
{
|
{
|
||||||
@@ -255,6 +313,7 @@ calculate_changed_events (GcalTimeline *self,
|
|||||||
GDateTime *new_range_start,
|
GDateTime *new_range_start,
|
||||||
GDateTime *new_range_end)
|
GDateTime *new_range_end)
|
||||||
{
|
{
|
||||||
|
g_autoptr (GPtrArray) subscriber_array = NULL;
|
||||||
g_autoptr (GPtrArray) events_to_remove = NULL;
|
g_autoptr (GPtrArray) events_to_remove = NULL;
|
||||||
g_autoptr (GPtrArray) events_to_add = NULL;
|
g_autoptr (GPtrArray) events_to_add = NULL;
|
||||||
gint range_diff;
|
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++)
|
for (i = 0; i < events_to_remove->len; i++)
|
||||||
{
|
{
|
||||||
GcalEvent *event = g_ptr_array_index (events_to_remove, 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))
|
if (!gcal_event_is_within_range (event, old_range_start, old_range_end))
|
||||||
continue;
|
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);
|
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))
|
if (!gcal_event_is_within_range (event, new_range_start, new_range_end))
|
||||||
continue;
|
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;
|
g_autoptr (GPtrArray) subscribers_at_range = NULL;
|
||||||
GDateTime *event_start;
|
GDateTime *event_start;
|
||||||
GDateTime *event_end;
|
GDateTime *event_end;
|
||||||
gint i;
|
|
||||||
|
|
||||||
GCAL_ENTRY;
|
GCAL_ENTRY;
|
||||||
|
|
||||||
event_start = gcal_event_get_date_start (event);
|
event_start = gcal_event_get_date_start (event);
|
||||||
event_end = gcal_event_get_date_end (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 */
|
/* 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);
|
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))
|
if (subscribers_at_range)
|
||||||
continue;
|
queue_event_data (self, ADD_EVENT, subscribers_at_range, event, NULL, TRUE);
|
||||||
|
|
||||||
add_event_to_subscriber (subscriber, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
GCAL_EXIT;
|
GCAL_EXIT;
|
||||||
}
|
}
|
||||||
@@ -421,37 +485,20 @@ on_calendar_monitor_event_updated_cb (GcalCalendarMonitor *monitor,
|
|||||||
GcalTimeline *self)
|
GcalTimeline *self)
|
||||||
{
|
{
|
||||||
g_autoptr (GPtrArray) subscribers_at_range = NULL;
|
g_autoptr (GPtrArray) subscribers_at_range = NULL;
|
||||||
GDateTime *old_event_start;
|
|
||||||
GDateTime *old_event_end;
|
|
||||||
GDateTime *event_start;
|
GDateTime *event_start;
|
||||||
GDateTime *event_end;
|
GDateTime *event_end;
|
||||||
gint i;
|
|
||||||
|
|
||||||
GCAL_ENTRY;
|
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 */
|
/* Add the updated event to the (potentially new) range */
|
||||||
event_start = gcal_event_get_date_start (event);
|
event_start = gcal_event_get_date_start (event);
|
||||||
event_end = gcal_event_get_date_end (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 */
|
/* 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);
|
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))
|
if (subscribers_at_range)
|
||||||
continue;
|
queue_event_data (self, UPDATE_EVENT, subscribers_at_range, event, old_event, TRUE);
|
||||||
|
|
||||||
update_subscriber_event (subscriber, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
GCAL_EXIT;
|
GCAL_EXIT;
|
||||||
}
|
}
|
||||||
@@ -464,7 +511,6 @@ on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor,
|
|||||||
g_autoptr (GPtrArray) subscribers_at_range = NULL;
|
g_autoptr (GPtrArray) subscribers_at_range = NULL;
|
||||||
GDateTime *event_start;
|
GDateTime *event_start;
|
||||||
GDateTime *event_end;
|
GDateTime *event_end;
|
||||||
gint i;
|
|
||||||
|
|
||||||
GCAL_ENTRY;
|
GCAL_ENTRY;
|
||||||
|
|
||||||
@@ -473,17 +519,9 @@ on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor,
|
|||||||
|
|
||||||
/* Add to all subscribers within the event range */
|
/* 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);
|
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))
|
if (subscribers_at_range)
|
||||||
continue;
|
queue_event_data (self, REMOVE_EVENT, subscribers_at_range, event, NULL, TRUE);
|
||||||
|
|
||||||
remove_event_from_subscriber (subscriber, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
gcal_range_tree_remove_range (self->events, event_start, event_end, event);
|
|
||||||
|
|
||||||
GCAL_EXIT;
|
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);
|
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
|
* GObject overrides
|
||||||
@@ -550,6 +704,13 @@ gcal_timeline_finalize (GObject *object)
|
|||||||
g_clear_pointer (&self->calendars, g_hash_table_destroy);
|
g_clear_pointer (&self->calendars, g_hash_table_destroy);
|
||||||
g_clear_pointer (&self->subscribers, 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->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);
|
G_OBJECT_CLASS (gcal_timeline_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@@ -653,11 +814,23 @@ gcal_timeline_class_init (GcalTimelineClass *klass)
|
|||||||
static void
|
static void
|
||||||
gcal_timeline_init (GcalTimeline *self)
|
gcal_timeline_init (GcalTimeline *self)
|
||||||
{
|
{
|
||||||
|
TimelineSource *timeline_source;
|
||||||
|
|
||||||
self->cancellable = g_cancellable_new ();
|
self->cancellable = g_cancellable_new ();
|
||||||
self->events = gcal_range_tree_new_with_free_func (g_object_unref);
|
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->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->subscribers = g_hash_table_new_full (NULL, NULL, g_object_unref, (GDestroyNotify) subscriber_data_free);
|
||||||
self->subscriber_ranges = gcal_range_tree_new ();
|
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 ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user