How the Wombat generates alarm instances
This chapter describes the algorithm that the &Wombat; uses
internally to generate instances of a calendar component's
alarms. You do not need to read this chapter if you are simply
using the client-side functions.
What makes up an alarm trigger
VTODO and VEVENT calendar components can have any number of
alarms defined for them. Each alarm has a trigger
specification, an alarm type (display, audio, email, or
procedure), and data corresponding to the alarm type. The
Wombat side of things is interested only in the trigger
specification, since this is all that the Wombat needs to
produce alarm instances.
An alarm trigger can be relative or absolute. Relative
triggers occur a certain time before or after the start or end
of a calendar component's occurrence. For example, you could
configure a trigger to notify you 15 minutes before an
appointment starts, so that you can get to its location on
time; or another one to notify you 5 minutes after another
person's meeting has ended, so that you can call that person
on the phone after the meeting and not disturb him while
there. Absolute triggers occur at a specific point in time;
you can configure an alarm to trigger exactly at a particular
date and time that has no relation to the component's
occurrences at all.
Generating trigger instances
Generating absolute triggers is trivial; you just use the date
and time they specify. However, relative triggers are
associated to recurrence instances, so in order to generate
trigger instances we must generate the corresponding
recurrence instances and compute the trigger times based on
those.
Since relative triggers are specified as occurring a certain
amount of time before or after each of a calendar component's
recurrence instances, we can compute a trigger time by adding
or subtracting that amount of time to the corresponding
recurrence instance's time.
Recurrence instances are generated by specifying a range of
time and asking the Wombat to generate the instances that
occur within that range. We shall see that the range of time
in which instances occur is not necessarily the same range of
time in which those instances' alarm triggers occur.
Consider an alarm that is set to trigger 10 minutes before the
start time of an event's occurrence, that is, the trigger has
an offset of -10 minutes. Say this event recurs every hour at
5 minutes past the hour: it would occur at 1:05, 2:05, 3:05,
etc.; the corresponding triggers would occur at 12:55, 1:55,
2:55, etc. If we wish to compute the alarm triggers that
occur between 4:00 and 6:00 (which would be at 4:55 and 5:55),
then we cannot just generate recurrence instances between 4:00
and 6:00 because we will miss the 6:05 occurrence which
corresponds to the 5:55 trigger.
The solution is to expand the range of time on both sides to
fit the relative triggers that have the largest time periods.
If a trigger's offset is negative, like the -10 minutes in the
example above, then we must expand the
end of the time range: in the case above,
the range's ending time of 6:00 must be grown by 10 minutes to
6:10 so that the last recurrence instance will be that of
6:05; computing the trigger's offset we will get the 5:55
trigger, which is what we wanted. For triggers with positive
offsets, like if an alarm were to trigger 20 minutes after an
event's occurrence, we must expand the
start of the time range in an analogous
way, by subtracting the time offset from it.
Again, absolute triggers need no special computation. We can
just see if the trigger time is within the requested range of
time, and if so, we take that trigger occurrence into account
for the final result.
In addition, alarms may specify a number of repetitions and a
duration time. For example, an alarm may be configured to
repeat 3 extra times after the original occurrence with 5
minutes between each repetition. Again, for absolute triggers
this does not present a problem, as we can just generate the
repetitions starting from the absolute trigger time. For
relative triggers, we expand the range as described above and
also add the total offset for the repetitions to the start of
the range, i.e. 15 extra minutes for the case of 3 repetitions
with 5 minutes between each. We do not need to modify the end
of the range because alarm repetitions always have positive
offsets, so they are equivalent to relative alarm triggers
with positive offsets.
Alarm trigger generation code
The main function to generate alarm trigger instances is
generate_alarms_for_comp() in
evolution/calendar/pcs/cal-backend-file.c.
This function calls compute_alarm_range()
to expand the specified range of time in the way described in
the previous section. It then generates the instances for
relative alarm triggers inside the
add_alarm_occurrences_cb() callback,
which is used by
cal_recur_generate_instances() with the
expanded range of time. The callback goes through all of the
calendar component's relative alarm triggers and adds the
trigger offsets to the occurrence's time; the results are
added as CalAlarmInstance structures
to the final list of trigger instances. Finally,
generate_alarms_for_comp() calls
generate_absolute_triggers(), which
simply adds the instances for absolute alarm triggers; these
are the absolute times that are within the time range that was
requested originally. In the very end, the list of instances
is sorted to produce nicer results.