Commit d509f47a authored by Federico Mena Quintero's avatar Federico Mena Quintero Committed by Federico Mena Quintero

Removed unused arguments. Load the initial alarms here. (load_alarms): New

2000-05-11  Federico Mena Quintero  <federico@helixcode.com>

	* gui/gnome-cal.c (gnome_calendar_update_all): Removed unused
	arguments.  Load the initial alarms here.
	(load_alarms): New function to load a day's worth of alarms.
	(gnome_calendar_class_init): Eeeek!  This was taking in an
	incorrect argument type.
	(gnome_calendar_init): Now the calendar keeps a hash table of
	UIDs->queued alarms.  Create the hash table here.
	(gnome_calendar_destroy): Destroy the alarms hash table.
	(gnome_calendar_object_updated_cb): Remove the alarms for the
	object and regenerate them.
	(gnome_calendar_object_removed_cb): Remove the alarms for the
	object.

	* gui/alarm.c (alarm_add): Do not take in a CalendarAlarm, just
	the trigger time, the callback and the closure data.  Return an
	opaque identifier for the alarm so that it can be removed by the
	client code if needed.  Use the queue_alarm() helper function.
	(queue_alarm): Helper function to actually queue the alarm and set
	up the itimer.  Deal with a nonzero return value from
	setitimer().
	(alarm_remove): New function to remove an alarm based on its ID.
	(pop_alarm): New helper function; pops the first alarm of the
	queue and resets the timer as appropriate.
	(alarm_ready): Simplified a lot by using pop_alarm().

	* idl/evolution-calendar.idl (Cal): Added get_alarms_in_range().

	* pcs/cal.c (build_instance_seq): New function to build a CORBA
	sequence from the internal list of instances.
	(Cal_get_events_in_range): Use build_instance_seq().
	(Cal_get_alarms_in_range): Implemented new method.

	* pcs/cal-backend.c (cal_backend_get_alarms_in_range): New
	function with the get_alarms_in_range() engine.

	* pcs/cal-backend-imc.c (cal_backend_imc_get_alarms_in_range):
	Implemented the get_alarms_in_range() method.

	* cal-client/cal-client.c (cal_client_get_alarms_in_range): New
	client-side function for getting the alarms.
	(build_instance_list): New helper function to build the
	CalObjInstance list from the CORBA sequence.
	(cal_client_get_events_in_range): Use build_instance_list().

	* gui/calendar-commands.h: #include <cal-util/calobj.h>.  #include
	"gnome-cal.h".

	* gui/e-week-view.c: #include "calendar-commands.h" instead of
	main.h; the latter is an obsolete file and will be killed.

	* gui/evolution-calendar-control.c (main): Call init_bonobo()
	before anything else.  We need the GTK+ object system initialized.

	* gui/Makefile.am (evolution_calendar_SOURCES): Do not use main.h.

	* cal-util/cal-util.c (cal_alarm_instance_list_free): New function.

svn path=/trunk/; revision=2987
parent d91a0645
2000-05-11 Federico Mena Quintero <federico@helixcode.com>
* gui/gnome-cal.c (gnome_calendar_update_all): Removed unused
arguments. Load the initial alarms here.
(load_alarms): New function to load a day's worth of alarms.
(gnome_calendar_class_init): Eeeek! This was taking in an
incorrect argument type.
(gnome_calendar_init): Now the calendar keeps a hash table of
UIDs->queued alarms. Create the hash table here.
(gnome_calendar_destroy): Destroy the alarms hash table.
(gnome_calendar_object_updated_cb): Remove the alarms for the
object and regenerate them.
(gnome_calendar_object_removed_cb): Remove the alarms for the
object.
* gui/alarm.c (alarm_add): Do not take in a CalendarAlarm, just
the trigger time, the callback and the closure data. Return an
opaque identifier for the alarm so that it can be removed by the
client code if needed. Use the queue_alarm() helper function.
(queue_alarm): Helper function to actually queue the alarm and set
up the itimer. Deal with a nonzero return value from
setitimer().
(alarm_remove): New function to remove an alarm based on its ID.
(pop_alarm): New helper function; pops the first alarm of the
queue and resets the timer as appropriate.
(alarm_ready): Simplified a lot by using pop_alarm().
* idl/evolution-calendar.idl (Cal): Added get_alarms_in_range().
* pcs/cal.c (build_instance_seq): New function to build a CORBA
sequence from the internal list of instances.
(Cal_get_events_in_range): Use build_instance_seq().
(Cal_get_alarms_in_range): Implemented new method.
* pcs/cal-backend.c (cal_backend_get_alarms_in_range): New
function with the get_alarms_in_range() engine.
* pcs/cal-backend-imc.c (cal_backend_imc_get_alarms_in_range):
Implemented the get_alarms_in_range() method.
* cal-client/cal-client.c (cal_client_get_alarms_in_range): New
client-side function for getting the alarms.
(build_instance_list): New helper function to build the
CalObjInstance list from the CORBA sequence.
(cal_client_get_events_in_range): Use build_instance_list().
* gui/calendar-commands.h: #include <cal-util/calobj.h>. #include
"gnome-cal.h".
* gui/e-week-view.c: #include "calendar-commands.h" instead of
main.h; the latter is an obsolete file and will be killed.
* gui/evolution-calendar-control.c (main): Call init_bonobo()
before anything else. We need the GTK+ object system initialized.
* gui/Makefile.am (evolution_calendar_SOURCES): Do not use main.h.
* cal-util/cal-util.c (cal_alarm_instance_list_free): New function.
2000-05-10 Matt Loper <matt@helixcode.com>
* gui/calendar-commands.c (calendar_control_activate): Move
......
......@@ -654,6 +654,34 @@ cal_client_get_uids (CalClient *client, CalObjType type)
return uids;
}
/* Builds a GList of CalObjInstance structures from the CORBA sequence */
static GList *
build_object_instance_list (Evolution_Calendar_CalObjInstanceSeq *seq)
{
GList *list;
int i;
/* Create the list in reverse order */
list = NULL;
for (i = 0; i < seq->_length; i++) {
Evolution_Calendar_CalObjInstance *corba_icoi;
CalObjInstance *icoi;
corba_icoi = &seq->_buffer[i];
icoi = g_new (CalObjInstance, 1);
icoi->uid = g_strdup (corba_icoi->uid);
icoi->start = corba_icoi->start;
icoi->end = corba_icoi->end;
list = g_list_prepend (list, icoi);
}
list = g_list_reverse (list);
return list;
}
/**
* cal_client_get_events_in_range:
* @client: A calendar client.
......@@ -671,22 +699,18 @@ cal_client_get_events_in_range (CalClient *client, time_t start, time_t end)
CalClientPrivate *priv;
CORBA_Environment ev;
Evolution_Calendar_CalObjInstanceSeq *seq;
GList *elist;
int i;
GList *events;
g_return_val_if_fail (client != NULL, NULL);
g_return_val_if_fail (IS_CAL_CLIENT (client), NULL);
priv = client->priv;
/*g_return_val_if_fail (priv->load_state == LOAD_STATE_LOADED, NULL);*/
if (priv->load_state != LOAD_STATE_LOADED)
return NULL;
g_return_val_if_fail (start != -1 && end != -1, NULL);
g_return_val_if_fail (start <= end, NULL);
priv = client->priv;
CORBA_exception_init (&ev);
seq = Evolution_Calendar_Cal_get_events_in_range (priv->cal, start, end, &ev);
......@@ -697,28 +721,107 @@ cal_client_get_events_in_range (CalClient *client, time_t start, time_t end)
}
CORBA_exception_free (&ev);
/* Create the list in reverse order */
events = build_object_instance_list (seq);
CORBA_free (seq);
return events;
}
/* Translates the CORBA representation of an AlarmType */
static enum AlarmType
uncorba_alarm_type (Evolution_Calendar_AlarmType corba_type)
{
switch (corba_type) {
case Evolution_Calendar_MAIL:
return ALARM_MAIL;
case Evolution_Calendar_PROGRAM:
return ALARM_PROGRAM;
case Evolution_Calendar_DISPLAY:
return ALARM_DISPLAY;
case Evolution_Calendar_AUDIO:
return ALARM_AUDIO;
default:
g_assert_not_reached ();
return ALARM_DISPLAY;
}
}
/* Builds a GList of CalAlarmInstance structures from the CORBA sequence */
static GList *
build_alarm_instance_list (Evolution_Calendar_CalAlarmInstanceSeq *seq)
{
GList *list;
int i;
elist = NULL;
/* Create the list in reverse order */
list = NULL;
for (i = 0; i < seq->_length; i++) {
Evolution_Calendar_CalObjInstance *corba_icoi;
CalObjInstance *icoi;
Evolution_Calendar_CalAlarmInstance *corba_ai;
CalAlarmInstance *ai;
corba_icoi = &seq->_buffer[i];
icoi = g_new (CalObjInstance, 1);
corba_ai = &seq->_buffer[i];
ai = g_new (CalAlarmInstance, 1);
icoi->uid = g_strdup (corba_icoi->uid);
icoi->start = corba_icoi->start;
icoi->end = corba_icoi->end;
ai->uid = g_strdup (corba_ai->uid);
ai->type = uncorba_alarm_type (corba_ai->type);
ai->trigger = corba_ai->trigger;
ai->occur = corba_ai->occur;
elist = g_list_prepend (elist, icoi);
list = g_list_prepend (list, ai);
}
list = g_list_reverse (list);
return list;
}
/**
* cal_client_get_alarms_in_range:
* @client: A calendar client.
* @start: Start time for query.
* @end: End time for query.
*
* Queries a calendar for the alarms that trigger in the specified range of
* time.
*
* Return value: A list of #CalAlarmInstance structures.
**/
GList *
cal_client_get_alarms_in_range (CalClient *client, time_t start, time_t end)
{
CalClientPrivate *priv;
CORBA_Environment ev;
Evolution_Calendar_CalAlarmInstanceSeq *seq;
GList *alarms;
g_return_val_if_fail (client != NULL, NULL);
g_return_val_if_fail (IS_CAL_CLIENT (client), NULL);
priv = client->priv;
if (priv->load_state != LOAD_STATE_LOADED)
return NULL;
g_return_val_if_fail (start != -1 && end != -1, NULL);
g_return_val_if_fail (start <= end, NULL);
CORBA_exception_init (&ev);
seq = Evolution_Calendar_Cal_get_alarms_in_range (priv->cal, start, end, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_message ("cal_client_get_alarms_in_range(): could not get the alarm range");
CORBA_exception_free (&ev);
return NULL;
}
CORBA_exception_free (&ev);
alarms = build_alarm_instance_list (seq);
CORBA_free (seq);
elist = g_list_reverse (elist);
return elist;
return alarms;
}
/**
......
......@@ -80,6 +80,8 @@ GList *cal_client_get_uids (CalClient *client, CalObjType type);
GList *cal_client_get_events_in_range (CalClient *client, time_t start, time_t end);
GList *cal_client_get_alarms_in_range (CalClient *client, time_t start, time_t end);
gboolean cal_client_update_object (CalClient *client, const char *uid, const char *calobj);
gboolean cal_client_remove_object (CalClient *client, const char *uid);
......
......@@ -28,9 +28,9 @@
/**
* cal_obj_instance_list_free:
* @list: List of CalObjInstance structures.
* @list: List of #CalObjInstance structures.
*
* Frees a list of CalObjInstance structures.
* Frees a list of #CalObjInstance structures.
**/
void
cal_obj_instance_list_free (GList *list)
......@@ -51,6 +51,31 @@ cal_obj_instance_list_free (GList *list)
g_list_free (list);
}
/**
* cal_alarm_instance_list_free:
* @list: List of #CalAlarmInstance structures.
*
* Frees a list of #CalAlarmInstance structures.
**/
void
cal_alarm_instance_list_free (GList *list)
{
CalAlarmInstance *i;
GList *l;
for (l = list; l; l = l->next) {
i = l->data;
g_assert (i != NULL);
g_assert (i->uid != NULL);
g_free (i->uid);
g_free (i);
}
g_list_free (list);
}
/**
* cal_obj_uid_list_free:
* @list: List of strings with unique identifiers.
......
......@@ -42,6 +42,16 @@ typedef struct {
void cal_obj_instance_list_free (GList *list);
/* Instance of an alarm trigger */
typedef struct {
char *uid; /* UID of object */
enum AlarmType type; /* Type of alarm */
time_t trigger; /* Alarm trigger time */
time_t occur; /* Occurrence time */
} CalAlarmInstance;
void cal_alarm_instance_list_free (GList *list);
/* Used for multiple UID queries */
typedef enum {
CALOBJ_TYPE_EVENT = 1 << 0,
......
......@@ -60,7 +60,6 @@ evolution_calendar_SOURCES = \
goto.c \
mark.c \
mark.h \
main.h \
popup-menu.c \
popup-menu.h \
prop.c \
......
/*
* Alarm handling for the GNOME Calendar.
/* Evolution calendar - alarm notification support
*
* (C) 1998 the Free Software Foundation
* Copyright (C) 2000 Helix Code, Inc.
*
* Author: Miguel de Icaza (miguel@kernel.org)
* Authors: Miguel de Icaza <miguel@helixcode.com>
* Federico Mena-Quintero <federico@helixcode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <time.h>
#include <gnome.h>
......@@ -14,237 +29,277 @@
#include <cal-util/calobj.h>
#include "alarm.h"
/* The pipes used to notify about an alarm */
int alarm_pipes [2];
static int alarm_pipes [2];
/* The list of pending alarms */
static GList *alarms;
static void *head_alarm;
/* A queued alarm structure */
typedef struct {
time_t activation_time;
AlarmFunction fn;
void *closure;
CalendarAlarm *alarm;
time_t trigger;
AlarmFunction alarm_fn;
gpointer data;
AlarmDestroyNotify destroy_notify_fn;
} AlarmRecord;
enum DebugAction {
ALARM_ACTIVATED,
ALARM_ADDED,
ALARM_NOT_ADDED
};
void debug_alarm (AlarmRecord* ar, enum DebugAction action);
void calendar_notify (time_t time, CalendarAlarm *which, void *data);
extern int debug_alarms;
/*
* SIGALRM handler. Notifies the callback about the alarm
*/
/* SIGALRM handler. Notifies the callback about the alarm. */
static void
alarm_activate ()
alarm_signal (int arg)
{
char c = 0;
write (alarm_pipes [1], &c, 1);
}
/*
* SIGUSR1 handler. Toggles debugging output
/* Sets up an itimer and returns a success code */
static gboolean
setup_itimer (time_t diff)
{
struct itimerval itimer;
int v;
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = diff;
itimer.it_value.tv_usec = 0;
v = setitimer (ITIMER_REAL, &itimer, NULL);
return (v == 0) ? TRUE : FALSE;
}
/* Removes the head alarm, returns it, and schedules the next alarm in the
* queue.
*/
static void
toggle_debugging ()
static AlarmRecord *
pop_alarm (void)
{
debug_alarms = !debug_alarms;
AlarmRecord *ar;
GList *l;
if (!alarms)
return NULL;
ar = alarms->data;
l = alarms;
alarms = g_list_remove_link (alarms, l);
g_list_free_1 (l);
if (alarms) {
time_t now;
AlarmRecord *new_ar;
now = time (NULL);
new_ar = alarms->data;
if (!setup_itimer (new_ar->trigger)) {
g_message ("pop_alarm(): Could not reset the timer! "
"Weird things will happen.");
/* FIXME: should we free the alarm list? What
* about further alarm removal requests that
* will fail?
*/
}
} else {
struct itimerval itimer;
int v;
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = 0;
itimer.it_value.tv_usec = 0;
v = setitimer (ITIMER_REAL, &itimer, NULL);
if (v != 0)
g_message ("pop_alarm(): Could not clear the timer! "
"Weird things may happen.");
}
return ar;
}
/* Input handler for our own alarm notification pipe */
static void
alarm_ready (void *closure, int fd, GdkInputCondition cond)
alarm_ready (gpointer data, gint fd, GdkInputCondition cond)
{
AlarmRecord *ar = head_alarm;
time_t now = time (NULL);
AlarmRecord *ar;
char c;
if (read (alarm_pipes [0], &c, 1) != 1)
return;
if (ar == NULL){
g_warning ("Empty events. This should not happen\n");
if (read (alarm_pipes [0], &c, 1) != 1) {
g_message ("alarm_ready(): Uh? Could not read from notification pipe.");
return;
}
while (head_alarm){
if (debug_alarms)
debug_alarm (ar, ALARM_ACTIVATED);
(*ar->fn)(ar->activation_time, ar->alarm, ar->closure);
alarms = g_list_remove (alarms, head_alarm);
/* Schedule next alarm */
if (alarms){
AlarmRecord *next;
head_alarm = alarms->data;
next = head_alarm;
if (next->activation_time > now){
struct itimerval itimer;
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = next->activation_time - now;
itimer.it_value.tv_usec = 0;
setitimer (ITIMER_REAL, &itimer, NULL);
break;
} else {
g_free (ar);
ar = next;
}
} else
head_alarm = NULL;
}
g_assert (alarms != NULL);
ar = pop_alarm ();
g_message ("alarm_ready(): Notifying about alarm on %s", ctime (&ar->trigger));
(* ar->alarm_fn) (ar, ar->trigger, ar->data);
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar->data);
g_free (ar);
}
static int
alarm_compare_by_time (gconstpointer a, gconstpointer b)
compare_alarm_by_time (gconstpointer a, gconstpointer b)
{
const AlarmRecord *ara = a;
const AlarmRecord *arb = b;
time_t diff;
diff = ara->activation_time - arb->activation_time;
diff = ara->trigger - arb->trigger;
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
/* Adds an alarm to the queue and sets up the timer */
static gboolean
queue_alarm (time_t now, AlarmRecord *ar)
{
time_t diff;
AlarmRecord *old_head;
if (alarms)
old_head = alarms->data;
else
old_head = NULL;
alarms = g_list_insert_sorted (alarms, ar, compare_alarm_by_time);
if (old_head == alarms->data)
return TRUE;
/* Set the timer for removal upon activation */
diff = ar->trigger - now;
if (!setup_itimer (diff)) {
GList *l;
g_message ("queue_alarm(): Could not set up timer! Not queueing alarm.");
l = g_list_find (alarms, ar);
g_assert (l != NULL);
alarms = g_list_remove_link (alarms, l);
g_list_free_1 (l);
return FALSE;
}
return TRUE;
}
/**
* alarm_add:
* @trigger: Time at which alarm will trigger.
* @alarm_fn: Callback for trigger.
* @data: Closure data for callback.
*
* Tries to schedule @alarm.
* Adds an alarm to trigger at the specified time. The @alarm_fn will be called
* with the provided data and the alarm will be removed from the trigger list.
*
* Returns TRUE if the alarm was scheduled.
*/
gboolean
alarm_add (CalendarAlarm *alarm, AlarmFunction fn, void *closure)
* Return value: An identifier for this alarm; it can be used to remove the
* alarm later with alarm_remove(). If the trigger time occurs in the past, then
* the alarm will not be queued and the function will return NULL.
**/
gpointer
alarm_add (time_t trigger, AlarmFunction alarm_fn, gpointer data,
AlarmDestroyNotify destroy_notify_fn)
{
time_t now = time (NULL);
time_t now;
AlarmRecord *ar;
time_t alarm_time = alarm->trigger;
ar = g_new0 (AlarmRecord, 1);
ar->activation_time = alarm_time;
ar->fn = fn;
ar->closure = closure;
ar->alarm = alarm;
/* If it already expired, do not add it */
if (alarm_time < now) {
if (debug_alarms)
debug_alarm (ar, ALARM_NOT_ADDED);
return FALSE;
}
alarms = g_list_insert_sorted (alarms, ar, alarm_compare_by_time);
now = time (NULL);
if (trigger < now)
return NULL;
/* 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;
ar = g_new (AlarmRecord, 1);
ar->trigger = trigger;
ar->alarm_fn = alarm_fn;
ar->data = data;
ar->destroy_notify_fn = destroy_notify_fn;
g_message ("alarm_add(): Adding alarm for %s", ctime (&trigger));
if (!queue_alarm (now, ar)) {
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar->data);
g_free (ar);
ar = NULL;
}
if (debug_alarms)
debug_alarm (ar, ALARM_ADDED);
return TRUE;
return ar;
}
int
alarm_kill (void *closure_key)
/**
* alarm_remove:
* @alarm: A queued alarm identifier.
*
* Removes an alarm from the alarm queue.
**/
void
alarm_remove (gpointer alarm)
{
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 1;
}
AlarmRecord *ar;
AlarmRecord *old_head;
GList *l;
ar = alarm;
l = g_list_find (alarms, ar);
if (!l) {
g_message ("alarm_remove(): Requested removal of nonexistent alarm!");
return;
}
return 0;
old_head = alarms->data;
if (old_head == ar)
pop_alarm ();
else {
alarms = g_list_remove_link (alarms, l);
g_list_free_1 (l);
}
if (ar->destroy_notify_fn)
(* ar->destroy_notify_fn) (ar->data);
g_free (ar);
}
/**
* alarm_init:
* @void:
*
* Initializes the alarm notification system. This must be called near the
* beginning of the program.
**/
void
alarm_init (void)
{
struct sigaction sa;
struct sigaction debug_sa;
int flags = 0;
int flags;