It’s been a long time since I last wrong a blog post about GNOME Calendar only. That doesn’t mean work has stalled!
Since pretty much its inception, Calendar used copy-pasted code from Evolution to retrieve events from Evolution Data Server (EDS). It was a pair of classes called ECalDataModelSubscriber, and ECalDataModel. The first is an interface that classes implement when they handle adding, updating, and removing events. It was implemented by the week, month, and year views. The second Evolution class, ECalDataModel, is responsible for storing multiple subscribers, the time range of each subscriber, fetching the calendar data from EDS, and keeping subscribers aware of which events they should display.
ECalDataModel is a fairly complicated code, full of threads and locks and synchronization points. It was hard to investigate and fix bugs related to it. In addition to that, Calendar tries to use the GDateTime API everywhere, but ECalDataModel (and most Evolution-related code) uses other time types such as
GTimeVal. Over time, those points were growing the pain of maintaining Calendar.
Even though ECalDataModel and ECalDataModelSubscriber worked mostly well for a long time, I thought it wouldn’t hurt to experiment with a new backend that uses more modern APIs and techniques, threads the heavy stuff away, and is closer to the style and idiosyncrasy of Calendar.
After some testing and validating the core concepts of the new backend, and asking a few community members for targeted testing, I finally landed it. I’ll be fixing a few remaining bugs introduced by it, but so far so good!
The core component of this new engine is what I called “timeline”. Conceptually, a timeline is a straightforward concept: it’s a virtual representation of the time.
Events are added to this timeline, and subscribers can subscriber to a well defined time slice. The timeline matches which events are visible by which subscribers, and updates subscribers accordingly.
In the picture above, the timeline object would detect that “Subscriber 1” should only display “Event 1”, whereas “Subscriber 2” would display all the 3 events available.
The subscriber concept is directly borrowed from Evolution’s design. Anything can be a subscriber, as long as it knows what slice of time it wants to display. The week, month, and year views continue to implement this concept, but so does the search – which uses a more sophisticated calculation of time, but is still time-based – and the shell search provider.
GcalTimeline takes over the responsibility of aggregating events and subscribers, and deciding which events each subscriber should display. Gathering the events from EDS is done in a different class called GcalCalendarMonitor. This class is very specific and limited in what it does, and is where most of the complexities of multiple threads is handled. It also tries really hard to be efficient and never do heavy operations in tight loops in the main thread.
In order to implement that, the data structure used by Calendar to store and query time ranges was further improved to be able to handle a much larger range of dates and times.
Calendar implements an augmented AVL tree that stores data based on ranges instead of single values. This allows us to have a good compromise of memory efficiency, lookup speeds, and insertion and removal speeds. For practical purposes, on a daily usage, the time ranges this range tree is capable of handling is virtually infinite. People will be able to schedule their appointments from year 1 to 9999 in the Gregorian calendar.
I have a few more improvements in the pipeline, such as the introduction of another data structure to handle ranges and compare them with potentially different comparison strategies, since sometimes we want to compare non-exclusive ranges with exclusive ones, or half-exclusive ranges between each other.
Personally, I’m quite satisfied with this new architecture and how much it is a better fit for Calendar. Slowly but steadily, Calendar is being reworked to be more consistent internally and ultimately that will mean less bugs and, who knows!, more features as well.