diff --git a/src/core/gcal-calendar-monitor.c b/src/core/gcal-calendar-monitor.c index c786e4b2..20df3446 100644 --- a/src/core/gcal-calendar-monitor.c +++ b/src/core/gcal-calendar-monitor.c @@ -59,6 +59,9 @@ struct _GcalCalendarMonitor GcalCalendar *calendar; gboolean complete; + const GcalCalendarMonitorListener *listener; + gpointer listener_user_data; + /* * These fields are only accessed on the monitor thread, and * never on the main thread. @@ -88,14 +91,6 @@ static gboolean complete_in_idle_cb (gpointer G_DEFINE_TYPE (GcalCalendarMonitor, gcal_calendar_monitor, G_TYPE_OBJECT) -enum -{ - EVENT_ADDED, - EVENT_UPDATED, - EVENT_REMOVED, - N_SIGNALS, -}; - enum { PROP_0, @@ -104,7 +99,6 @@ enum N_PROPS }; -static gulong signals[N_SIGNALS] = { 0, }; static GParamSpec *properties [N_PROPS] = { NULL, }; /* @@ -957,6 +951,7 @@ remove_events_outside_range (GcalCalendarMonitor *self, GcalRange *range) { g_autoptr (GRWLockWriterLocker) writer_locker = NULL; + g_autoptr (GPtrArray) events_to_remove = NULL; GHashTableIter iter; GcalEvent *event; @@ -964,6 +959,9 @@ remove_events_outside_range (GcalCalendarMonitor *self, writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock); + events_to_remove = g_ptr_array_new_full (g_hash_table_size (self->shared.events), + g_object_unref); + g_hash_table_iter_init (&iter, self->shared.events); while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &event)) { @@ -972,36 +970,28 @@ remove_events_outside_range (GcalCalendarMonitor *self, if (gcal_range_calculate_overlap (range, event_range, NULL) != GCAL_RANGE_NO_OVERLAP) continue; - g_object_ref (event); - - g_hash_table_iter_remove (&iter); - g_signal_emit (self, signals[EVENT_REMOVED], 0, event); - - g_object_unref (event); + g_ptr_array_add (events_to_remove, event); + g_hash_table_iter_steal (&iter); } + + if (events_to_remove->len > 0) + self->listener->remove_events (self, events_to_remove, self->listener_user_data); } static void remove_all_events (GcalCalendarMonitor *self) { g_autoptr (GRWLockWriterLocker) writer_locker = NULL; - GHashTableIter iter; - GcalEvent *event; + g_autoptr (GPtrArray) events_to_remove = NULL; GCAL_TRACE_MSG ("Removing all events from view"); writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock); - g_hash_table_iter_init (&iter, self->shared.events); - while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &event)) - { - g_object_ref (event); + events_to_remove = g_hash_table_steal_all_values (self->shared.events); - g_hash_table_iter_remove (&iter); - g_signal_emit (self, signals[EVENT_REMOVED], 0, event); - - g_object_unref (event); - } + if (events_to_remove->len > 0) + self->listener->remove_events (self, events_to_remove, self->listener_user_data); } static void @@ -1026,6 +1016,7 @@ static gboolean add_events_to_timeline_in_idle_cb (gpointer user_data) { g_autoptr (GRWLockWriterLocker) writer_locker = NULL; + g_autoptr (GPtrArray) events_to_add = NULL; GcalCalendarMonitor *self; GPtrArray *events; IdleData *idle_data; @@ -1037,6 +1028,8 @@ add_events_to_timeline_in_idle_cb (gpointer user_data) events = idle_data->events; g_assert (idle_data->event_ids == NULL); + events_to_add = g_ptr_array_sized_new (events->len); + writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock); for (guint i = 0; i < events->len; i++) { @@ -1049,10 +1042,13 @@ add_events_to_timeline_in_idle_cb (gpointer user_data) if (!g_hash_table_contains (self->shared.events, uid)) { g_hash_table_insert (self->shared.events, g_strdup (uid), g_object_ref (event)); - g_signal_emit (self, signals[EVENT_ADDED], 0, event); + g_ptr_array_add (events_to_add, event); } } + if (events_to_add->len > 0) + self->listener->add_events (self, events_to_add, self->listener_user_data); + GCAL_RETURN (G_SOURCE_REMOVE); } @@ -1060,6 +1056,8 @@ static gboolean update_events_in_idle_cb (gpointer user_data) { g_autoptr (GRWLockWriterLocker) writer_locker = NULL; + g_autoptr (GPtrArray) old_events = NULL; + g_autoptr (GPtrArray) new_events = NULL; g_autoptr (GPtrArray) events = NULL; GcalCalendarMonitor *self; IdleData *idle_data; @@ -1071,26 +1069,36 @@ update_events_in_idle_cb (gpointer user_data) events = g_steal_pointer (&idle_data->events); g_assert (idle_data->event_ids == NULL); + old_events = g_ptr_array_new_full (events->len, g_object_unref); + new_events = g_ptr_array_sized_new (events->len); + writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock); for (guint i = 0; i < events->len; i++) { g_autoptr (GcalEvent) old_event = NULL; + g_autofree gchar *old_event_id = NULL; GcalEvent *event; const gchar *event_id; event = g_ptr_array_index (events, i); event_id = gcal_event_get_uid (event); - old_event = g_hash_table_lookup (self->shared.events, event_id); - if (old_event) + if (g_hash_table_steal_extended (self->shared.events, + event_id, + (gpointer*) &old_event_id, + (gpointer*) &old_event)) { - g_object_ref (old_event); - g_hash_table_insert (self->shared.events, g_strdup (event_id), g_object_ref (event)); - g_signal_emit (self, signals[EVENT_UPDATED], 0, old_event, event); + g_ptr_array_add (old_events, g_steal_pointer (&old_event)); + g_ptr_array_add (new_events, event); } } + g_assert (old_events->len == new_events->len); + + if (new_events->len > 0) + self->listener->update_events (self, old_events, new_events, self->listener_user_data); + GCAL_RETURN (G_SOURCE_REMOVE); } @@ -1098,6 +1106,7 @@ static gboolean remove_events_from_timeline_in_idle_cb (gpointer user_data) { g_autoptr (GRWLockWriterLocker) writer_locker = NULL; + g_autoptr (GPtrArray) events_to_remove = NULL; g_autoptr (GPtrArray) event_ids = NULL; GcalCalendarMonitor *self; IdleData *idle_data; @@ -1109,6 +1118,8 @@ remove_events_from_timeline_in_idle_cb (gpointer user_data) event_ids = g_steal_pointer (&idle_data->event_ids); g_assert (idle_data->events == NULL); + events_to_remove = g_ptr_array_new_full (event_ids->len, g_object_unref); + writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock); for (guint i = 0; i < event_ids->len; i++) @@ -1121,14 +1132,15 @@ remove_events_from_timeline_in_idle_cb (gpointer user_data) if (event) { - /* Keep the event alive until the signal is emitted */ - g_object_ref (event); - + /* Keep the event alive until the listener process it*/ + g_ptr_array_add (events_to_remove, g_object_ref (event)); g_hash_table_remove (self->shared.events, event_id); - g_signal_emit (self, signals[EVENT_REMOVED], 0, event); } } + if (events_to_remove->len > 0) + self->listener->remove_events (self, events_to_remove, self->listener_user_data); + GCAL_RETURN (G_SOURCE_REMOVE); } @@ -1250,31 +1262,6 @@ gcal_calendar_monitor_class_init (GcalCalendarMonitorClass *klass) object_class->get_property = gcal_calendar_monitor_get_property; object_class->set_property = gcal_calendar_monitor_set_property; - signals[EVENT_ADDED] = g_signal_new ("event-added", - GCAL_TYPE_CALENDAR_MONITOR, - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, - 1, - GCAL_TYPE_EVENT); - - signals[EVENT_UPDATED] = g_signal_new ("event-updated", - GCAL_TYPE_CALENDAR_MONITOR, - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, - 2, - GCAL_TYPE_EVENT, - GCAL_TYPE_EVENT); - - signals[EVENT_REMOVED] = g_signal_new ("event-removed", - GCAL_TYPE_CALENDAR_MONITOR, - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, - 1, - GCAL_TYPE_EVENT); - properties[PROP_CALENDAR] = g_param_spec_object ("calendar", "Calendar", "Calendar to be monitored", @@ -1304,11 +1291,23 @@ gcal_calendar_monitor_init (GcalCalendarMonitor *self) } GcalCalendarMonitor* -gcal_calendar_monitor_new (GcalCalendar *calendar) +gcal_calendar_monitor_new (GcalCalendar *calendar, + const GcalCalendarMonitorListener *listener, + gpointer user_data) { - return g_object_new (GCAL_TYPE_CALENDAR_MONITOR, - "calendar", calendar, - NULL); + g_autoptr (GcalCalendarMonitor) monitor = NULL; + + g_assert (calendar != NULL && GCAL_IS_CALENDAR (calendar)); + g_assert (listener != NULL); + + monitor = g_object_new (GCAL_TYPE_CALENDAR_MONITOR, + "calendar", calendar, + NULL); + + monitor->listener = listener; + monitor->listener_user_data = user_data; + + return g_steal_pointer (&monitor); } /** diff --git a/src/core/gcal-calendar-monitor.h b/src/core/gcal-calendar-monitor.h index fb8577c9..6a6c2138 100644 --- a/src/core/gcal-calendar-monitor.h +++ b/src/core/gcal-calendar-monitor.h @@ -30,7 +30,24 @@ G_BEGIN_DECLS #define GCAL_TYPE_CALENDAR_MONITOR (gcal_calendar_monitor_get_type()) G_DECLARE_FINAL_TYPE (GcalCalendarMonitor, gcal_calendar_monitor, GCAL, CALENDAR_MONITOR, GObject) -GcalCalendarMonitor* gcal_calendar_monitor_new (GcalCalendar *calendar); +typedef struct { + void (*add_events) (GcalCalendarMonitor *self, + GPtrArray *events, + gpointer user_data); + + void (*update_events) (GcalCalendarMonitor *self, + GPtrArray *old_events, + GPtrArray *events, + gpointer user_data); + + void (*remove_events) (GcalCalendarMonitor *self, + GPtrArray *events, + gpointer user_data); +} GcalCalendarMonitorListener; + +GcalCalendarMonitor* gcal_calendar_monitor_new (GcalCalendar *calendar, + const GcalCalendarMonitorListener *listener, + gpointer user_data); void gcal_calendar_monitor_set_range (GcalCalendarMonitor *self, GcalRange *range); diff --git a/src/core/gcal-timeline.c b/src/core/gcal-timeline.c index dcec4cb3..f815ed05 100644 --- a/src/core/gcal-timeline.c +++ b/src/core/gcal-timeline.c @@ -473,97 +473,135 @@ update_calendar_monitor_filters (GcalTimeline *self) gcal_calendar_monitor_set_filter (monitor, self->filter); } +/* + * GcalCalendarMonitorListener events + */ + +static void +calendar_monitor_add_events_cb (GcalCalendarMonitor *monitor, + GPtrArray *events, + gpointer user_data) +{ + GcalTimeline *self; + + GCAL_ENTRY; + + self = GCAL_TIMELINE (user_data); + + for (guint i = 0; i < events->len; i++) + { + g_autoptr (GPtrArray) subscribers_at_range = NULL; + GcalRange *event_range; + GcalEvent *event; + + event = g_ptr_array_index (events, i); + event_range = gcal_event_get_range (event); + + /* Add to all subscribers within the event range */ + subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range); + + queue_event_data (self, ADD_EVENT, NULL, event, NULL, TRUE); + + for (guint j = 0; subscribers_at_range && j < subscribers_at_range->len; j++) + { + GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, j); + + queue_event_data (self, ADD_EVENT, subscriber, event, NULL, FALSE); + } + } + + GCAL_EXIT; +} + +static void +calendar_monitor_update_events_cb (GcalCalendarMonitor *monitor, + GPtrArray *old_events, + GPtrArray *events, + gpointer user_data) +{ + GcalTimeline *self; + + GCAL_ENTRY; + + g_assert (old_events->len == events->len); + + self = GCAL_TIMELINE (user_data); + + for (guint i = 0; i < events->len; i++) + { + g_autoptr (GPtrArray) subscribers_at_range = NULL; + GcalRange *event_range; + GcalEvent *old_event; + GcalEvent *event; + + event = g_ptr_array_index (events, i); + old_event = g_ptr_array_index (old_events, i); + event_range = gcal_event_get_range (event); + + /* Add to all subscribers within the event range */ + subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range); + + queue_event_data (self, UPDATE_EVENT, NULL, event, old_event, TRUE); + + for (guint j = 0; subscribers_at_range && j < subscribers_at_range->len; j++) + { + GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, j); + + queue_event_data (self, UPDATE_EVENT, subscriber, event, old_event, FALSE); + } + + } + + GCAL_EXIT; +} + +static void +calendar_monitor_remove_events_cb (GcalCalendarMonitor *monitor, + GPtrArray *events, + gpointer user_data) +{ + GcalTimeline *self; + + GCAL_ENTRY; + + self = GCAL_TIMELINE (user_data); + + for (guint i = 0; i < events->len; i++) + { + g_autoptr (GPtrArray) subscribers_at_range = NULL; + GcalRange *event_range; + GcalEvent *event; + + event = g_ptr_array_index (events, i); + event_range = gcal_event_get_range (event); + + /* Add to all subscribers within the event range */ + subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range); + + for (guint j = 0; subscribers_at_range && j < subscribers_at_range->len; j++) + { + GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, j); + + queue_event_data (self, REMOVE_EVENT, subscriber, event, NULL, FALSE); + } + + queue_event_data (self, REMOVE_EVENT, NULL, event, NULL, TRUE); + } + + GCAL_EXIT; +} + +static const GcalCalendarMonitorListener monitor_listener = { + calendar_monitor_add_events_cb, + calendar_monitor_update_events_cb, + calendar_monitor_remove_events_cb, +}; + /* * Callbacks */ -static void -on_calendar_monitor_event_added_cb (GcalCalendarMonitor *monitor, - GcalEvent *event, - GcalTimeline *self) -{ - g_autoptr (GPtrArray) subscribers_at_range = NULL; - GcalRange *event_range; - gint i; - - GCAL_ENTRY; - - event_range = gcal_event_get_range (event); - - /* Add to all subscribers within the event range */ - subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range); - - queue_event_data (self, ADD_EVENT, NULL, event, NULL, TRUE); - - for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++) - { - GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i); - - queue_event_data (self, ADD_EVENT, subscriber, event, NULL, FALSE); - } - - GCAL_EXIT; -} - -static void -on_calendar_monitor_event_updated_cb (GcalCalendarMonitor *monitor, - GcalEvent *old_event, - GcalEvent *event, - GcalTimeline *self) -{ - g_autoptr (GPtrArray) subscribers_at_range = NULL; - GcalRange *event_range; - gint i; - - GCAL_ENTRY; - - /* Add the updated event to the (potentially new) range */ - event_range = gcal_event_get_range (event); - - /* Add to all subscribers within the event range */ - subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range); - - queue_event_data (self, UPDATE_EVENT, NULL, event, old_event, TRUE); - - for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++) - { - GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i); - - queue_event_data (self, UPDATE_EVENT, subscriber, event, old_event, FALSE); - } - - GCAL_EXIT; -} - -static void -on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor, - GcalEvent *event, - GcalTimeline *self) -{ - g_autoptr (GPtrArray) subscribers_at_range = NULL; - GcalRange *event_range; - gint i; - - GCAL_ENTRY; - - event_range = gcal_event_get_range (event); - - /* Add to all subscribers within the event range */ - subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range); - - for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++) - { - GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i); - - queue_event_data (self, REMOVE_EVENT, subscriber, event, NULL, FALSE); - } - - queue_event_data (self, REMOVE_EVENT, NULL, event, NULL, TRUE); - - GCAL_EXIT; -} - static void on_calendar_monitor_completed_cb (GcalCalendarMonitor *monitor, GParamSpec *pspec, @@ -933,10 +971,7 @@ gcal_timeline_add_calendar (GcalTimeline *self, GCAL_TRACE_MSG ("Adding calendar '%s' to timeline %p", gcal_calendar_get_name (calendar), self); - monitor = gcal_calendar_monitor_new (calendar); - g_signal_connect (monitor, "event-added", G_CALLBACK (on_calendar_monitor_event_added_cb), self); - g_signal_connect (monitor, "event-updated", G_CALLBACK (on_calendar_monitor_event_updated_cb), self); - g_signal_connect (monitor, "event-removed", G_CALLBACK (on_calendar_monitor_event_removed_cb), self); + monitor = gcal_calendar_monitor_new (calendar, &monitor_listener, self); g_signal_connect (monitor, "notify::complete", G_CALLBACK (on_calendar_monitor_completed_cb), self); g_hash_table_insert (self->calendars, calendar, g_object_ref (monitor));