diff options
Diffstat (limited to 'calendar/alarm.c')
-rw-r--r-- | calendar/alarm.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/calendar/alarm.c b/calendar/alarm.c new file mode 100644 index 0000000000..bb5c4c1b8d --- /dev/null +++ b/calendar/alarm.c @@ -0,0 +1,145 @@ +/* + * Alarm handling for the GNOME Calendar. + * + * (C) 1998 the Free Software Foundation + * + * Author: Miguel de Icaza (miguel@kernel.org) + */ +#include <config.h> +#include <time.h> +#include <gnome.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/time.h> +#include "alarm.h" + +/* The pipes used to notify about an alarm */ +int alarm_pipes [2]; + +/* The list of pending alarms */ +static GList *alarms; + +static void *head_alarm; + +typedef struct { + time_t activation_time; + AlarmFunction fn; + void *closure; +} AlarmRecord; + +/* + * SIGALRM handler. Notifies the callback about the alarm + */ +static void +alarm_activate () +{ + char c = 0; + + printf ("ALARMA!\n"); + write (alarm_pipes [1], &c, 1); +} + +static void +alarm_ready (void *closure, int fd, GdkInputCondition cond) +{ + AlarmRecord *ar = head_alarm; + char c; + + if (read (alarm_pipes [0], &c, 1) != 1) + return; + + if (ar == NULL){ + g_warning ("Empty events. This should not happen\n"); + return; + } + (*ar->fn)(ar->activation_time, ar->closure); + alarms = g_list_remove (alarms, head_alarm); + if (alarms) + head_alarm = alarms->data; + else + head_alarm = NULL; + g_free (ar); +} + +static int +alarm_compare_by_time (gpointer a, gpointer b) +{ + AlarmRecord *ara = a; + AlarmRecord *arb = b; + time_t diff; + + diff = ara->activation_time - arb->activation_time; + return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; +} + +void +alarm_add (time_t alarm_time, AlarmFunction fn, void *closure) +{ + time_t now = time (NULL); + AlarmRecord *ar; + + /* If it already expired, do not add it */ + if (alarm_time < now) + return; + + ar = g_new0 (AlarmRecord, 1); + ar->activation_time = alarm_time; + ar->fn = fn; + ar->closure = closure; + + alarms = g_list_insert_sorted (alarms, ar, alarm_compare_by_time); + + /* If first alarm is not the previous first alarm, reschedule SIGALRM */ + if (head_alarm != alarms->data){ + struct itimerval itimer; + int v; + + /* Set the timer to disable upon activation */ + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 0; + itimer.it_value.tv_sec = alarm_time - now; + itimer.it_value.tv_usec = 0; + v = setitimer (ITIMER_REAL, &itimer, NULL); + head_alarm = alarms->data; + } +} + +void +alarm_kill (void *closure_key) +{ + GList *p; + + for (p = alarms; p; p = p->next){ + AlarmRecord *ar = p->data; + + if (ar->closure == closure_key){ + alarms = g_list_remove (alarms, p->data); + if (alarms) + head_alarm = alarms->data; + else + head_alarm = NULL; + return; + } + } +} + +void +alarm_init (void) +{ + struct sigaction sa; + int flags; + + pipe (alarm_pipes); + + /* set non blocking mode */ + fcntl (alarm_pipes [0], F_GETFL, &flags); + fcntl (alarm_pipes [0], F_SETFL, flags | O_NONBLOCK); + gdk_input_add (alarm_pipes [0], GDK_INPUT_READ, alarm_ready, 0); + + /* Setup the signal handler */ + sa.sa_handler = alarm_activate; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction (SIGALRM, &sa, NULL); +} + |