From b353c9f2590133a80ac9dde6cfbabe5448644164 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Sat, 2 May 2026 16:18:42 -0300 Subject: [PATCH] core/timeline: Add support for augmented timelines Augmented timelines increase the range of dates from its subscribers by the specified factor. They're useful for the interactive views, since they prevent fetching new events so often as when views change. Add the necessary API. Part-of: --- src/core/gcal-timeline.c | 107 +++++++++++++++++++++++++++++++++++++-- src/core/gcal-timeline.h | 2 + 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/core/gcal-timeline.c b/src/core/gcal-timeline.c index 9950b7f5..0e657f06 100644 --- a/src/core/gcal-timeline.c +++ b/src/core/gcal-timeline.c @@ -36,8 +36,11 @@ struct _GcalTimeline { GObject parent_instance; + double augmentation_factor; + guint update_range_idle_id; GcalRange *range; + GcalRange *augmented_range; GcalRangeTree *events; gchar *filter; @@ -184,6 +187,50 @@ set_model_on_subscriber (GcalTimelineSubscriber *subscriber, GCAL_TIMELINE_SUBSCRIBER_GET_IFACE (subscriber)->set_model (subscriber, model); } +static GcalRange * +augment_range (GcalRange *range, + double augmentation_factor) +{ + g_autoptr (GcalRange) augmented_range = NULL; + g_autoptr (GDateTime) range_start = NULL; + g_autoptr (GDateTime) range_end = NULL; + GTimeSpan timespan; + GTimeSpan offset; + + g_assert (range != NULL); + g_assert (augmentation_factor >= 1.0 || G_APPROX_VALUE (augmentation_factor, 1.0, DBL_EPSILON)); + + if (G_APPROX_VALUE (augmentation_factor, 1.0, DBL_EPSILON)) + { +#ifdef GCAL_ENABLE_TRACE + GCAL_TRACE_MSG ("%s: Augmenting range by 1.0, skipping", G_STRFUNC); +#endif + return gcal_range_ref (range); + } + + range_start = gcal_range_get_start (range); + range_end = gcal_range_get_end (range); + + timespan = g_date_time_difference (range_end, range_start); + g_assert (timespan > 0); + + offset = (timespan / 2) * augmentation_factor; + + augmented_range = gcal_range_new_take (g_date_time_add (range_start, -offset), + g_date_time_add (range_end, offset), + gcal_range_get_range_type (range)); +#ifdef GCAL_ENABLE_TRACE + { + g_autofree char *range_str = gcal_range_to_string (range); + g_autofree char *augmented_range_str = gcal_range_to_string (augmented_range); + + GCAL_TRACE_MSG ("%s: Range %s augmented to %s", G_STRFUNC, range_str, augmented_range_str); + } +#endif + + return g_steal_pointer (&augmented_range); +} + static void update_range (GcalTimeline *self) { @@ -224,15 +271,43 @@ update_range (GcalTimeline *self) if (!self->range || gcal_range_compare (self->range, new_range) != 0) { + g_autoptr (GcalRange) new_augmented_range = NULL; + g_clear_pointer (&self->range, gcal_range_unref); self->range = g_steal_pointer (&new_range); - range_changed = TRUE; + + if (self->augmented_range) + { + switch (gcal_range_calculate_overlap (self->range, self->augmented_range, NULL)) + { + case GCAL_RANGE_NO_OVERLAP: + case GCAL_RANGE_INTERSECTS: + case GCAL_RANGE_SUPERSET: + g_clear_pointer (&self->augmented_range, gcal_range_unref); + self->augmented_range = augment_range (self->range, self->augmentation_factor); + range_changed = TRUE; + break; + + case GCAL_RANGE_SUBSET: + case GCAL_RANGE_EQUAL: + break; + + default: + g_assert_not_reached (); + } + } + else + { + self->augmented_range = augment_range (self->range, self->augmentation_factor); + range_changed = TRUE; + } } } else if (self->range) { g_clear_pointer (&self->range, gcal_range_unref); + g_clear_pointer (&self->augmented_range, gcal_range_unref); range_changed = TRUE; } @@ -242,7 +317,7 @@ update_range (GcalTimeline *self) g_hash_table_iter_init (&iter, self->calendars); while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &monitor)) - gcal_calendar_monitor_set_range (monitor, self->range); + gcal_calendar_monitor_set_range (monitor, self->augmented_range); } GCAL_EXIT; @@ -375,6 +450,9 @@ 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->augmented_range, gcal_range_unref); + g_clear_pointer (&self->range, gcal_range_unref); + G_OBJECT_CLASS (gcal_timeline_parent_class)->finalize (object); } @@ -457,6 +535,8 @@ gcal_timeline_class_init (GcalTimelineClass *klass) static void gcal_timeline_init (GcalTimeline *self) { + self->augmentation_factor = 1.0; + 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); @@ -480,6 +560,25 @@ gcal_timeline_new (void) NULL); } +/** + * gcal_timeline_new_augmented: + * + * Creates a new #GcalTimeline that augments its ranges by + * @augmentation_factor. This is + * + * Returns: (transfer full): a #GcalTimeline + */ +GcalTimeline* +gcal_timeline_new_augmented (double augmentation_factor) +{ + g_autoptr (GcalTimeline) self = NULL; + + self = g_object_new (GCAL_TYPE_TIMELINE, NULL); + self->augmentation_factor = augmentation_factor; + + return g_steal_pointer (&self); +} + /** * gcal_timeline_add_calendar: * @self: a #GcalTimeline @@ -510,8 +609,8 @@ gcal_timeline_add_calendar (GcalTimeline *self, g_hash_table_insert (self->calendars, calendar, g_object_ref (monitor)); g_list_store_append (self->calendar_monitors, monitor); - if (self->range) - gcal_calendar_monitor_set_range (monitor, self->range); + if (self->augmented_range) + gcal_calendar_monitor_set_range (monitor, self->augmented_range); update_completed_calendars (self); diff --git a/src/core/gcal-timeline.h b/src/core/gcal-timeline.h index f7fa10a0..6dbd581f 100644 --- a/src/core/gcal-timeline.h +++ b/src/core/gcal-timeline.h @@ -31,6 +31,8 @@ G_DECLARE_FINAL_TYPE (GcalTimeline, gcal_timeline, GCAL, TIMELINE, GObject) GcalTimeline* gcal_timeline_new (void); +GcalTimeline* gcal_timeline_new_augmented (double augmentation_factor); + void gcal_timeline_add_calendar (GcalTimeline *self, GcalCalendar *calendar);