aboutsummaryrefslogtreecommitdiffstats
path: root/calendar
diff options
context:
space:
mode:
authorChenthill Palanisamy <pchen@src.gnome.org>2005-11-24 23:28:11 +0800
committerChenthill Palanisamy <pchen@src.gnome.org>2005-11-24 23:28:11 +0800
commit25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b (patch)
tree47828615efb7cefb23ca816cda38a35423cc5697 /calendar
parent9c0eef3dd90ab8e7db04901b3079e097cdd7f400 (diff)
downloadgsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.tar
gsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.tar.gz
gsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.tar.bz2
gsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.tar.lz
gsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.tar.xz
gsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.tar.zst
gsoc2013-evolution-25d053c312af01acc9cb2ba1672f3f7ed4ea5e8b.zip
Changes for alarm notification bubble
svn path=/trunk/; revision=30661
Diffstat (limited to 'calendar')
-rw-r--r--calendar/ChangeLog37
-rw-r--r--calendar/gui/alarm-notify/alarm-notify.c24
-rw-r--r--calendar/gui/alarm-notify/alarm-notify.h2
-rw-r--r--calendar/gui/alarm-notify/alarm-queue.c556
-rw-r--r--calendar/gui/alarm-notify/alarm-queue.h2
-rw-r--r--calendar/gui/alarm-notify/config-data.c78
-rw-r--r--calendar/gui/alarm-notify/config-data.h3
-rw-r--r--calendar/gui/alarm-notify/util.c49
-rw-r--r--calendar/gui/alarm-notify/util.h2
9 files changed, 631 insertions, 122 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index 8e259fd42c..b87657764f 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,3 +1,40 @@
+2005-11-24 Srinivasa Ragavan and P.S.Chakravarthi <sragavan@novell.com>, <pchakravarthi@novell.com>
+
+ (simultaneously a patch for configure.in in evolution source dir is
+ applied to include libnotify, if present)
+ * gui/alarm-notify/alarm-notify.c (alarm_notify_get_selected_calendars):
+ added a field in _AlarmNotifyPrivate called selected_calendars and relevant
+ code elsewhere for use in disabling and enabling alarms for particular calendars.
+ * gui/alarm-notify/alarm-queue.c (free_tray_icon_data):added
+ (notify_dialog_cb): modified to free the non snoozed alarms on close.
+ (open_alarm_dialog): code added to set up tooltip on the panel icon if there
+ are alarms present.
+ (alarm_quit): added. Call back when "Quit" option is chosen on right click of the
+ panel icon.
+ (alarms_configure): added. The call back function for generating the "Configure Alarms"
+ dialog on right click on the panel icon.
+ (menu_item_toggle_cb): added. Call back when a particular calendar is selected
+ or deselected in the "Configure Alarms" dialog.
+ (populate): added. Function to populate the view in the dialog that appears when
+ "Configure Alarms" option is chosen on right click of the panel icon.
+ (alarm_preference_response):added. Called when the "Configure Alarms" dialog is
+ closed.
+ (tray_icon_clicked_cb): modified to get tooltip, giving alarm summary on mouse over
+ the panel icon, to have the panel icon blink in case of active alarms.
+ (display_notification): modified the code to change the strings shown in the alarm
+ dialog.
+ (popup_notification): added. Compiles if there is libnotify. If present, gives
+ a small notification bubble on alarm trigger giving necesary information on the
+ appointment.
+ (alarm_queue_init): modified to add the panel icon that is being used in above
+ functions.
+ * gui/alarm-notify/config-data.[ch](config_data_get_calendars):added. Gets calendar
+ information for notification from a gconf key.
+ (config_data_replace_string_list): added. To replace an old gconf key with a new one.
+ * gui/alarm-notify/util.[ch] (calculate_time):added. An utility function which
+ gives a time difference between two time_t instances in hours, minutes and seconds.
+
+
2005-11-24 Tor Lillqvist <tml@novell.com>
* gui/e-alarm-list.c
diff --git a/calendar/gui/alarm-notify/alarm-notify.c b/calendar/gui/alarm-notify/alarm-notify.c
index a74908bb2c..edef6d34bb 100644
--- a/calendar/gui/alarm-notify/alarm-notify.c
+++ b/calendar/gui/alarm-notify/alarm-notify.c
@@ -33,7 +33,6 @@
#include "config-data.h"
#include "common/authentication.h"
-
/* Private part of the AlarmNotify structure */
struct _AlarmNotifyPrivate {
/* Mapping from EUri's to LoadedClient structures */
@@ -41,6 +40,7 @@ struct _AlarmNotifyPrivate {
just need to hash based on source */
GHashTable *uri_client_hash [E_CAL_SOURCE_TYPE_LAST];
ESourceList *source_lists [E_CAL_SOURCE_TYPE_LAST];
+ ESourceList *selected_calendars;
GMutex *mutex;
};
@@ -54,7 +54,6 @@ static void alarm_notify_finalize (GObject *object);
static BonoboObjectClass *parent_class;
-
BONOBO_TYPE_FUNC_FULL(AlarmNotify, GNOME_Evolution_Calendar_AlarmNotify, BONOBO_TYPE_OBJECT, alarm_notify)
/* Class initialization function for the alarm notify service */
@@ -140,6 +139,10 @@ list_changed_cb (ESourceList *source_list, gpointer data)
for (q = sources; q != NULL; q = q->next) {
ESource *source = E_SOURCE (q->data);
char *uri;
+ const char *uid = e_source_peek_uid (source);
+
+ if (!e_source_list_peek_source_by_uid (priv->selected_calendars, uid))
+ continue;
uri = e_source_get_uri (source);
if (!g_hash_table_lookup (priv->uri_client_hash[source_type], uri)) {
@@ -163,6 +166,11 @@ list_changed_cb (ESourceList *source_list, gpointer data)
g_list_free (prd.removals);
}
+ESourceList *
+alarm_notify_get_selected_calendars (AlarmNotify *an)
+{
+ return an->priv->selected_calendars;
+}
static void
load_calendars (AlarmNotify *an, ECalSourceType source_type)
{
@@ -187,6 +195,10 @@ load_calendars (AlarmNotify *an, ECalSourceType source_type)
for (q = sources; q != NULL; q = q->next) {
ESource *source = E_SOURCE (q->data);
char *uri;
+ const char *uid = e_source_peek_uid (source);
+
+ if (!e_source_list_peek_source_by_uid (priv->selected_calendars, uid))
+ continue;
uri = e_source_get_uri (source);
g_message ("Loading %s", uri);
@@ -224,11 +236,13 @@ alarm_notify_init (AlarmNotify *an, AlarmNotifyClass *klass)
priv = g_new0 (AlarmNotifyPrivate, 1);
an->priv = priv;
priv->mutex = g_mutex_new ();
+ priv->selected_calendars = config_data_get_calendars ("/apps/evolution/calendar/notify/calendars");
+
for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++)
priv->uri_client_hash[i] = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
- alarm_queue_init ();
+ alarm_queue_init (an);
for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++)
load_calendars (an, i);
@@ -344,6 +358,7 @@ alarm_notify_add_calendar (AlarmNotify *an, ECalSourceType source_type, ESource
if (g_hash_table_lookup (priv->uri_client_hash[source_type], str_uri)) {
g_mutex_unlock (an->priv->mutex);
g_free (str_uri);
+ g_free (pass_key);
return;
}
/* if loading of this requires password and password is not currently availble in e-password
@@ -356,6 +371,7 @@ alarm_notify_add_calendar (AlarmNotify *an, ECalSourceType source_type, ESource
g_free (pass_key);
return;
}
+
client = auth_new_cal_from_source (source, source_type);
if (client) {
@@ -363,8 +379,8 @@ alarm_notify_add_calendar (AlarmNotify *an, ECalSourceType source_type, ESource
g_signal_connect (G_OBJECT (client), "cal_opened", G_CALLBACK (cal_opened_cb), an);
e_cal_open_async (client, FALSE);
}
- g_free (pass_key);
g_free (str_uri);
+ g_free (pass_key);
g_mutex_unlock (an->priv->mutex);
}
diff --git a/calendar/gui/alarm-notify/alarm-notify.h b/calendar/gui/alarm-notify/alarm-notify.h
index 4d8b5f194f..beb58acc1e 100644
--- a/calendar/gui/alarm-notify/alarm-notify.h
+++ b/calendar/gui/alarm-notify/alarm-notify.h
@@ -26,7 +26,6 @@
#include "evolution-calendar.h"
-
#define TYPE_ALARM_NOTIFY (alarm_notify_get_type ())
#define ALARM_NOTIFY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ALARM_NOTIFY, AlarmNotify))
#define ALARM_NOTIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ALARM_NOTIFY, \
@@ -58,6 +57,7 @@ AlarmNotify *alarm_notify_new (void);
void alarm_notify_add_calendar (AlarmNotify *an, ECalSourceType source_type, ESource *source, gboolean load_afterwards);
void alarm_notify_remove_calendar (AlarmNotify *an, ECalSourceType source_type, const char *str_uri);
+ESourceList *alarm_notify_get_selected_calendars (AlarmNotify *);
diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c
index 40a43b674a..83372f886f 100644
--- a/calendar/gui/alarm-notify/alarm-queue.c
+++ b/calendar/gui/alarm-notify/alarm-queue.c
@@ -27,14 +27,19 @@
#include <bonobo-activation/bonobo-activation.h>
#include <bonobo/bonobo-object.h>
#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-main.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkhbox.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkeventbox.h>
#include <gtk/gtkimage.h>
+#include <gtk/gtkframe.h>
#include <gtk/gtkimagemenuitem.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkstock.h>
#include <gtk/gtktooltips.h>
#include <libgnome/gnome-i18n.h>
@@ -45,10 +50,18 @@
#include <e-util/eggtrayicon.h>
#include <e-util/e-icon-factory.h>
#include <libecal/e-cal-time-util.h>
+#include <libecal/e-cal-component.h>
+
+
+#ifdef HAVE_LIBNOTIFY
+#include <libnotify/notify.h>
+#endif
+
#include "evolution-calendar.h"
#include "alarm.h"
#include "alarm-notify-dialog.h"
#include "alarm-queue.h"
+#include "alarm-notify.h"
#include "config-data.h"
#include "util.h"
#include "e-util/e-popup.h"
@@ -73,6 +86,13 @@ static GHashTable *client_alarms_hash = NULL;
/* List of tray icons being displayed */
static GList *tray_icons_list = NULL;
+/* Top Tray Image */
+static GtkWidget *tray_image = NULL;
+static GtkWidget *tray_event_box = NULL;
+static int tray_blink_id = -1;
+static int tray_blink_state = FALSE;
+static AlarmNotify *an;
+
/* Structure that stores a client we are monitoring */
typedef struct {
/* Monitored client */
@@ -136,7 +156,10 @@ static void display_notification (time_t trigger, CompQueuedAlarms *cqa,
static void audio_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id);
static void mail_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id);
static void procedure_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id);
-
+#ifdef HAVE_LIBNOTIFY
+static void popup_notification (time_t trigger, CompQueuedAlarms *cqa,
+ gpointer alarm_id, gboolean use_description);
+#endif
static void query_objects_changed_cb (ECal *client, GList *objects, gpointer data);
static void query_objects_removed_cb (ECal *client, GList *objects, gpointer data);
@@ -309,6 +332,9 @@ alarm_trigger_cb (gpointer alarm_id, time_t trigger, gpointer data)
alarm = e_cal_component_get_alarm (comp, qa->instance->auid);
g_assert (alarm != NULL);
+ /* Show it independent of what the notification is?*/
+ display_notification (trigger, cqa, alarm_id, TRUE);
+
e_cal_component_alarm_get_action (alarm, &action);
e_cal_component_alarm_free (alarm);
@@ -318,7 +344,9 @@ alarm_trigger_cb (gpointer alarm_id, time_t trigger, gpointer data)
break;
case E_CAL_COMPONENT_ALARM_DISPLAY:
- display_notification (trigger, cqa, alarm_id, TRUE);
+#ifdef HAVE_LIBNOTIFY
+ popup_notification (trigger, cqa, alarm_id, TRUE);
+#endif
break;
case E_CAL_COMPONENT_ALARM_EMAIL:
@@ -735,6 +763,7 @@ typedef struct {
char *description;
char *location;
gboolean blink_state;
+ gboolean snooze_set;
gint blink_id;
time_t trigger;
CompQueuedAlarms *cqa;
@@ -748,6 +777,43 @@ typedef struct {
} TrayIconData;
static void
+free_tray_icon_data (TrayIconData *tray_data)
+{
+ g_return_if_fail (tray_data != NULL);
+
+ if (tray_data->summary){
+ g_free (tray_data->summary);
+ tray_data->summary = NULL;
+ }
+
+ if (tray_data->description){
+ g_free (tray_data->description);
+ tray_data->description = NULL;
+ }
+
+ if (tray_data->location){
+ g_free (tray_data->description);
+ tray_data->location = NULL;
+ }
+
+ g_object_unref (tray_data->client);
+ tray_data->client = NULL;
+
+ g_object_unref (tray_data->query);
+ tray_data->query = NULL;
+
+ g_object_unref (tray_data->comp);
+ tray_data->comp = NULL;
+
+ tray_data->cqa = NULL;
+ tray_data->alarm_id = NULL;
+ tray_data->tray_icon = NULL;
+ tray_data->image = NULL;
+
+ g_free (tray_data);
+}
+
+static void
on_dialog_objs_removed_cb (ECal *client, GList *objects, gpointer data)
{
const char *our_uid;
@@ -766,8 +832,8 @@ on_dialog_objs_removed_cb (ECal *client, GList *objects, gpointer data)
if (!strcmp (uid, our_uid)) {
tray_data->cqa = NULL;
tray_data->alarm_id = NULL;
-
- gtk_widget_destroy (tray_data->tray_icon);
+ tray_icons_list = g_list_remove (tray_icons_list, tray_data);
+ tray_data = NULL;
}
}
}
@@ -784,8 +850,7 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data)
switch (result) {
case ALARM_NOTIFY_SNOOZE:
create_snooze (tray_data->cqa, tray_data->alarm_id, snooze_mins);
- tray_data->cqa = NULL;
-
+ tray_data->snooze_set = TRUE;
if (alarm_notifications_dialog) {
GtkTreeSelection *selection =
gtk_tree_view_get_selection (
@@ -793,7 +858,7 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data)
GtkTreeIter iter;
GtkTreeModel *model = NULL;
- /* We can also use tray_data->iter */
+ /* We can` also use tray_data->iter */
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
if (!gtk_tree_model_get_iter_first (model, &iter)) {
@@ -814,18 +879,12 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data)
case ALARM_NOTIFY_EDIT:
edit_component (tray_data->client, tray_data->comp);
- gtk_widget_destroy (alarm_notifications_dialog->dialog);
- g_free (alarm_notifications_dialog);
- alarm_notifications_dialog = NULL;
-
- gtk_widget_destroy (tray_data->tray_icon);
-
break;
case ALARM_NOTIFY_CLOSE:
-
if (alarm_notifications_dialog) {
+ GList *list;
GtkTreeIter iter;
GtkTreeModel *model =
gtk_tree_view_get_model (
@@ -841,56 +900,37 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data)
gtk_widget_destroy (alarm_notifications_dialog->dialog);
g_free (alarm_notifications_dialog);
alarm_notifications_dialog = NULL;
- }
-
- gtk_widget_destroy (tray_data->tray_icon);
- break;
+ /* FIXME tray_icons_list is a global data structure - make this thread safe */
- default:
- g_assert_not_reached ();
- }
+ list = tray_icons_list;
+ while (list != NULL) {
- return;
-}
-
-static gint
-tray_icon_destroyed_cb (GtkWidget *tray, gpointer user_data)
-{
- TrayIconData *tray_data = user_data;
+ tray_data = list->data;
- g_signal_handlers_disconnect_matched (tray_data->query, G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL, on_dialog_objs_removed_cb, NULL);
-
- if (tray_data->cqa != NULL)
+ if (!tray_data->snooze_set){
+ GList *temp = list->next;
+ tray_icons_list = g_list_remove_link (tray_icons_list, list);
remove_queued_alarm (tray_data->cqa, tray_data->alarm_id, TRUE, TRUE);
-
- if (tray_data->summary != NULL) {
- g_free (tray_data->summary);
- tray_data->summary = NULL;
+ free_tray_icon_data (tray_data);
+ tray_data = NULL;
+ g_list_free_1 (list);
+ if (tray_icons_list != list) /* List head is modified */
+ list = tray_icons_list;
+ else
+ list = temp;
+ } else
+ list = list->next;
}
-
- if (tray_data->description != NULL) {
- g_free (tray_data->description);
- tray_data->description = NULL;
- }
-
- if (tray_data->location != NULL) {
- g_free (tray_data->location);
- tray_data->location = NULL;
}
- if (tray_data->blink_id)
- g_source_remove (tray_data->blink_id);
-
- g_object_unref (tray_data->comp);
- g_object_unref (tray_data->client);
- g_object_unref (tray_data->query);
+ break;
- tray_icons_list = g_list_remove (tray_icons_list, tray_data);
- g_free (tray_data);
+ default:
+ g_assert_not_reached ();
+ }
- return TRUE;
+ return;
}
/* Callbacks. */
@@ -901,8 +941,19 @@ open_alarm_dialog (TrayIconData *tray_data)
qa = lookup_queued_alarm (tray_data->cqa, tray_data->alarm_id);
if (qa) {
+ GdkPixbuf *pixbuf;
+ GtkTooltips *tooltips = gtk_tooltips_new ();
+
+ pixbuf = e_icon_factory_get_icon ("stock_appointment-reminder", E_ICON_SIZE_LARGE_TOOLBAR);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (tray_image), pixbuf);
+ g_object_unref (pixbuf);
+
+ if (tray_blink_id > -1)
+ g_source_remove (tray_blink_id);
+ tray_blink_id = -1;
- gtk_widget_hide (tray_data->tray_icon);
+ gtk_tooltips_set_tip (tooltips, tray_event_box, NULL, NULL);
if (!alarm_notifications_dialog)
alarm_notifications_dialog = notified_alarms_dialog_new ();
@@ -938,37 +989,193 @@ open_alarm_dialog (TrayIconData *tray_data)
}
static void
-popup_dismiss_cb (EPopup *ep, EPopupItem *pitem, void *data)
+alarm_quit (EPopup *ep, EPopupItem *pitem, void *data)
{
- TrayIconData *tray_data = data;
-
- gtk_widget_destroy (tray_data->tray_icon);
+ bonobo_main_quit ();
}
static void
-popup_dismiss_all_cb (EPopup *ep, EPopupItem *pitem, void *data)
+menu_item_toggle_callback (GtkToggleButton *item, void *data)
+{
+ gboolean state = gtk_toggle_button_get_active (item);
+ ESource *source = e_source_copy ((ESource *) data);
+ GSList *groups, *p;
+
+ if (e_source_get_uri ((ESource *)data)) {
+ g_free (e_source_get_uri (source));
+ e_source_set_absolute_uri (source, g_strdup (e_source_get_uri ((ESource *)data)));
+ }
+
+ if (state) {
+ const char *uid = e_source_peek_uid (source);
+ ESourceList *selected_cal = alarm_notify_get_selected_calendars (an);
+ ESourceList *all_cal;
+ ESourceGroup *sel_group = NULL;
+ const char *grp_name=NULL;
+ ESourceGroup *group;
+ ESource *del_source;
+
+ e_cal_get_sources (&all_cal, E_CAL_SOURCE_TYPE_EVENT, NULL);
+
+ alarm_notify_add_calendar (an, E_CAL_SOURCE_TYPE_EVENT, source, FALSE);
+
+ /* Browse the list of calendars for the newly added calendar*/
+ groups = e_source_list_peek_groups (all_cal);
+ for (p = groups; p != NULL; p = p->next) {
+ ESourceGroup *group = E_SOURCE_GROUP (p->data);
+ ESource *sel_source = e_source_group_peek_source_by_uid (group, uid);
+
+ if (sel_source) {
+ sel_group = group;
+ grp_name = e_source_group_peek_name (sel_group);
+ /* You have got the group name*/
+ break;
+ }
+}
+
+ /* Add the source the the group name in the alarms calendar list*/
+ group = e_source_list_peek_group_by_name (selected_cal, grp_name);
+ del_source = e_source_group_peek_source_by_uid (group, uid);
+
+ if (!del_source) {
+ char *xml, *old_xml;
+
+ old_xml = e_source_group_to_xml (group);
+ e_source_group_add_source (group, source, -1);
+ xml = e_source_group_to_xml (group);
+ config_data_replace_string_list ("/apps/evolution/calendar/notify/calendars", old_xml, xml);
+
+ g_free (xml);
+ g_free (old_xml);
+ }
+
+ g_object_unref (all_cal);
+
+ } else {
+ const char *uid = e_source_peek_uid (source);
+ ESourceList *selected_cal = alarm_notify_get_selected_calendars (an);
+ alarm_notify_remove_calendar (an, E_CAL_SOURCE_TYPE_EVENT, e_source_get_uri (source));
+
+ /* Browse the calendar for alarms and remove the source */
+ groups = e_source_list_peek_groups (selected_cal);
+ for (p = groups; p != NULL; p = p->next) {
+ ESourceGroup *group = E_SOURCE_GROUP (p->data);
+ ESource *del_source;
+
+ del_source = e_source_group_peek_source_by_uid (group, uid);
+ if (del_source) {
+ char *xml, *old_xml;
+
+ old_xml = e_source_group_to_xml (group);
+
+ e_source_group_remove_source_by_uid (group, uid);
+
+ xml = e_source_group_to_xml (group);
+
+ config_data_replace_string_list ("/apps/evolution/calendar/notify/calendars", old_xml, xml);
+
+ g_free (xml);
+ g_free (old_xml);
+ break;
+ }
+ }
+ }
+
+}
+
+static GtkWidget *
+populate ()
{
- while (tray_icons_list != NULL) {
- TrayIconData *tray_data = tray_icons_list->data;
+ GtkWidget *frame = gtk_frame_new (NULL);
+ GtkWidget *label1 = gtk_label_new (NULL);
+ GtkWidget *box = gtk_vbox_new(FALSE, 0);
+ ESourceList *selected_cal = alarm_notify_get_selected_calendars (an);
+ GSList *groups;
+ GSList *p;
+ ESourceList *source_list;
+
+ gtk_label_set_markup (GTK_LABEL(label1), _("<b>Calendars</b>"));
+ gtk_frame_set_label_widget (GTK_FRAME(frame), label1);
+
+ if (!e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_EVENT, NULL)) {
+ g_message (G_STRLOC ": Could not get the list of sources to load");
+
+ return NULL;
+ }
+
+ groups = e_source_list_peek_groups (source_list);
+
+ for (p = groups; p != NULL; p = p->next) {
+ ESourceGroup *group = E_SOURCE_GROUP (p->data);
+ char *txt = g_strdup_printf ("<b>%s</b>", e_source_group_peek_name (group));
+ GtkWidget *item = gtk_label_new (NULL);
+ GSList *q;
+ GtkWidget *hbox, *image;
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ image = e_icon_factory_get_image ("stock_appointment-reminder", E_ICON_SIZE_SMALL_TOOLBAR);
+
+ gtk_box_pack_start ((GtkBox *)hbox, image, FALSE, FALSE, 2);
+ gtk_box_pack_start ((GtkBox *)hbox, item, FALSE, FALSE, 2);
+
+ gtk_label_set_markup (GTK_LABEL(item), txt);
+ gtk_label_set_justify (GTK_LABEL(item), GTK_JUSTIFY_LEFT);
+ g_free (txt);
+
+ gtk_box_pack_start (GTK_BOX(box), hbox, TRUE, TRUE, 4);
+ gtk_widget_show_all (hbox);
- gtk_widget_destroy (tray_data->tray_icon);
+ for (q = e_source_group_peek_sources (group); q != NULL; q = q->next) {
+ ESource *source = E_SOURCE (q->data);
+ GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
+ GtkWidget *item = gtk_check_button_new_with_label (e_source_peek_name (source));
- tray_icons_list = g_list_remove (tray_icons_list, tray_icons_list);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(item), e_source_list_peek_source_by_uid (selected_cal, e_source_peek_uid (source)) ? TRUE:FALSE);
+
+ gtk_box_pack_start ((GtkBox *)hbox, item, FALSE, FALSE, 24);
+ gtk_object_set_data_full (GTK_OBJECT (item), "ESourceMenu", source,
+ (GtkDestroyNotify) g_object_unref);
+
+ g_signal_connect (item, "toggled", G_CALLBACK (menu_item_toggle_callback), source);
+
+ gtk_box_pack_start (GTK_BOX(box), hbox, FALSE, FALSE, 2);
+ gtk_widget_show_all (hbox);
+ }
}
+
+ gtk_container_add (GTK_CONTAINER(frame), box);
+ gtk_container_set_border_width (GTK_CONTAINER(frame), 6);
+ return frame;
}
static void
-popup_open_cb (EPopup *ep, EPopupItem *pitem, void *data)
+alarm_pref_response (GtkWidget *widget, int response, gpointer dummy)
{
- TrayIconData *tray_data = data;
+ gtk_widget_destroy (widget);
+}
- open_alarm_dialog (tray_data);
+static void
+alarms_configure (EPopup *ep, EPopupItem *pitem, void *data)
+{
+ GtkWidget *box = populate ();
+ GtkWidget *dialog;
+
+ dialog = gtk_dialog_new_with_buttons (_("Preferences"),
+ NULL,0,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_HELP, GTK_RESPONSE_HELP,
+ NULL);
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), box);
+ gtk_dialog_set_has_separator (GTK_DIALOG(dialog), FALSE);
+ g_signal_connect (dialog, "response", G_CALLBACK (alarm_pref_response), NULL);
+ gtk_widget_show_all (dialog);
}
static EPopupItem tray_items[] = {
- { E_POPUP_ITEM, "00.open", N_("Open"), popup_open_cb, NULL, GTK_STOCK_OPEN },
- { E_POPUP_ITEM, "10.dismiss", N_("Dismiss"), popup_dismiss_cb, NULL, NULL },
- { E_POPUP_ITEM, "20.dismissall", N_("Dismiss All"), popup_dismiss_all_cb, NULL, NULL },
+ { E_POPUP_ITEM, "00.configure", N_("_Configure Alarms"), alarms_configure, NULL, GTK_STOCK_PREFERENCES },
+ { E_POPUP_BAR , "10.bar" },
+ { E_POPUP_ITEM, "10.quit", N_("_Quit"), alarm_quit, NULL, GTK_STOCK_QUIT },
};
static void
@@ -983,13 +1190,35 @@ tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_da
TrayIconData *tray_data = user_data;
if (event->type == GDK_BUTTON_PRESS) {
- if (event->button == 1) {
- return open_alarm_dialog (tray_data);
+ if (event->button == 1 && g_list_length (tray_icons_list) > 0) {
+ GList *tmp;
+ for (tmp = tray_icons_list; tmp; tmp = tmp->next) {
+ open_alarm_dialog (tmp->data);
+ }
+
+ return TRUE;
} else if (event->button == 3) {
GtkMenu *menu;
GSList *menus = NULL;
EPopup *ep;
int i;
+ GdkPixbuf *pixbuf;
+ GtkTooltips *tooltips = gtk_tooltips_new ();
+
+ tray_blink_state = FALSE;
+ pixbuf = e_icon_factory_get_icon (tray_blink_state == TRUE ?
+ "stock_appointment-reminder-excl" :
+ "stock_appointment-reminder",
+ E_ICON_SIZE_LARGE_TOOLBAR);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (tray_image), pixbuf);
+ g_object_unref (pixbuf);
+
+ if (tray_blink_id > -1)
+ g_source_remove (tray_blink_id);
+ tray_blink_id = -1;
+
+ gtk_tooltips_set_tip (tooltips, tray_event_box, NULL, NULL);
ep = e_popup_new("org.gnome.evolution.alarmNotify.popup");
for (i=0;i<sizeof(tray_items)/sizeof(tray_items[0]);i++)
@@ -1008,16 +1237,16 @@ tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_da
static gboolean
tray_icon_blink_cb (gpointer data)
{
- TrayIconData *tray_data = data;
GdkPixbuf *pixbuf;
- tray_data->blink_state = tray_data->blink_state == TRUE ? FALSE : TRUE;
- pixbuf = e_icon_factory_get_icon (tray_data->blink_state == TRUE ?
+ tray_blink_state = tray_blink_state == TRUE ? FALSE: TRUE;
+
+ pixbuf = e_icon_factory_get_icon (tray_blink_state == TRUE?
"stock_appointment-reminder-excl" :
"stock_appointment-reminder",
E_ICON_SIZE_LARGE_TOOLBAR);
- gtk_image_set_from_pixbuf (GTK_IMAGE (tray_data->image), pixbuf);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (tray_image), pixbuf);
g_object_unref (pixbuf);
return TRUE;
@@ -1031,13 +1260,14 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
QueuedAlarm *qa;
ECalComponent *comp;
const char *summary, *description, *location;
- GtkWidget *tray_icon, *image, *ebox;
+ GtkWidget *tray_icon=NULL, *image=NULL;
GtkTooltips *tooltips;
TrayIconData *tray_data;
ECalComponentText text;
GSList *text_list;
- char *str, *start_str, *end_str, *alarm_str;
+ char *str, *start_str, *end_str, *alarm_str, *time_str;
icaltimezone *current_zone;
+ ECalComponentOrganizer organiser;
comp = cqa->alarms->comp;
qa = lookup_queued_alarm (cqa, alarm_id);
@@ -1046,6 +1276,7 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
/* get a sensible description for the event */
e_cal_component_get_summary (comp, &text);
+ e_cal_component_get_organizer (comp, &organiser);
if (text.value)
summary = text.value;
@@ -1074,30 +1305,14 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
/* create the tray icon */
tooltips = gtk_tooltips_new ();
- tray_icon = GTK_WIDGET (egg_tray_icon_new (qa->instance->auid));
- image = e_icon_factory_get_image ("stock_appointment-reminder", E_ICON_SIZE_LARGE_TOOLBAR);
- ebox = gtk_event_box_new ();
-
- gtk_widget_show (image);
- gtk_widget_show (ebox);
-
current_zone = config_data_get_timezone ();
alarm_str = timet_to_str_with_zone (trigger, current_zone);
start_str = timet_to_str_with_zone (qa->instance->occur_start, current_zone);
end_str = timet_to_str_with_zone (qa->instance->occur_end, current_zone);
- str = g_strdup_printf (_("Alarm on %s\n%s\nStarting at %s\nEnding at %s"),
- alarm_str, summary, start_str, end_str);
- gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), ebox, str, str);
- g_free (start_str);
- g_free (end_str);
- g_free (alarm_str);
- g_free (str);
-
- g_object_set_data (G_OBJECT (tray_icon), "image", image);
- g_object_set_data (G_OBJECT (tray_icon), "available", GINT_TO_POINTER (1));
+ time_str = calculate_time (qa->instance->occur_start, qa->instance->occur_end);
- gtk_container_add (GTK_CONTAINER (ebox), image);
- gtk_container_add (GTK_CONTAINER (tray_icon), ebox);
+ str = g_strdup_printf ("%s\n%s %s",
+ summary, start_str, time_str);
/* create the private structure */
tray_data = g_new0 (TrayIconData, 1);
@@ -1107,32 +1322,132 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa,
tray_data->trigger = trigger;
tray_data->cqa = cqa;
tray_data->alarm_id = alarm_id;
- tray_data->comp = e_cal_component_clone (comp);
+ tray_data->comp = g_object_ref (e_cal_component_clone (comp));
tray_data->client = cqa->parent_client->client;
tray_data->query = g_object_ref (cqa->parent_client->query);
tray_data->image = image;
tray_data->blink_state = FALSE;
+ tray_data->snooze_set = FALSE;
g_object_ref (tray_data->client);
tray_data->tray_icon = tray_icon;
tray_icons_list = g_list_prepend (tray_icons_list, tray_data);
- g_signal_connect (G_OBJECT (tray_icon), "destroy",
- G_CALLBACK (tray_icon_destroyed_cb), tray_data);
- g_signal_connect (G_OBJECT (ebox), "button_press_event",
- G_CALLBACK (tray_icon_clicked_cb), tray_data);
+ if (g_list_length (tray_icons_list) > 1) {
+ char *tip;
+
+ tip = g_strdup_printf (_("You have %d alarms"), g_list_length (tray_icons_list));
+ gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), tray_event_box, tip, NULL);
+ g_free (tip);
+ }
+ else
+ gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), tray_event_box, str, NULL);
+
+ g_free (start_str);
+ g_free (end_str);
+ g_free (alarm_str);
+ g_free (time_str);
+ g_free (str);
+
g_signal_connect (G_OBJECT (tray_data->query), "objects_removed",
G_CALLBACK (on_dialog_objs_removed_cb), tray_data);
+ // FIXME: We should remove this check
if (!config_data_get_notify_with_tray ()) {
- tray_data->blink_id = -1;
+ tray_blink_id = -1;
open_alarm_dialog (tray_data);
gtk_window_stick (GTK_WINDOW (alarm_notifications_dialog->dialog));
} else {
- tray_data->blink_id = g_timeout_add (500, tray_icon_blink_cb, tray_data);
- gtk_widget_show (tray_icon);
+ if (tray_blink_id == -1)
+ tray_blink_id = g_timeout_add (500, tray_icon_blink_cb, tray_data);
}
+ }
+
+#ifdef HAVE_LIBNOTIFY
+static void
+popup_notification (time_t trigger, CompQueuedAlarms *cqa,
+ gpointer alarm_id, gboolean use_description)
+{
+ QueuedAlarm *qa;
+ ECalComponent *comp;
+ const char *summary, *location;
+ GtkTooltips *tooltips;
+ ECalComponentText text;
+ char *str, *start_str, *end_str, *alarm_str, *time_str;
+ icaltimezone *current_zone;
+ ECalComponentOrganizer organiser;
+ NotifyIcon *icon;
+ char *filename;
+ char *body;
+
+ comp = cqa->alarms->comp;
+ qa = lookup_queued_alarm (cqa, alarm_id);
+ if (!qa)
+ return;
+ if (!notify_is_initted ())
+ notify_init("Evolution Alarm Notify");
+ filename = e_icon_factory_get_icon_filename ("stock_appointment-reminder", E_ICON_SIZE_DIALOG);
+ icon = notify_icon_new_from_uri (filename);
+ g_free (filename);
+
+ /* get a sensible description for the event */
+ e_cal_component_get_summary (comp, &text);
+ e_cal_component_get_organizer (comp, &organiser);
+
+
+ if (text.value)
+ summary = text.value;
+ else
+ summary = _("No summary available.");
+
+ e_cal_component_get_location (comp, &location);
+
+ /* create the tray icon */
+ tooltips = gtk_tooltips_new ();
+
+ current_zone = config_data_get_timezone ();
+ alarm_str = timet_to_str_with_zone (trigger, current_zone);
+ start_str = timet_to_str_with_zone (qa->instance->occur_start, current_zone);
+ end_str = timet_to_str_with_zone (qa->instance->occur_end, current_zone);
+ time_str = calculate_time (qa->instance->occur_start, qa->instance->occur_end);
+
+ str = g_strdup_printf ("%s %s",
+ start_str, time_str);
+
+ if (organiser.cn) {
+ if (location)
+ body = g_strdup_printf ("<b>%s</b>\n%s %s\n%s %s", organiser.cn, _("Location:"), location, start_str, time_str);
+ else
+ body = g_strdup_printf ("<b>%s</b>\n%s %s", organiser.cn, start_str, time_str);
+ }
+ else {
+ if (location)
+ body = g_strdup_printf ("%s %s\n%s %s", _("Location:"), location, start_str, time_str);
+ else
+ body = g_strdup_printf ("%s %s", start_str, time_str);
+}
+
+ if (!notify_send_notification (
+ NULL, "device", NOTIFY_URGENCY_NORMAL,
+ summary,
+ body, /* body text */
+ icon, /* icon */
+ TRUE, 0, /* expiry, server default */
+ NULL, /* hints */
+ NULL, /* no user_data */
+ 0)) /* no actions */
+ g_warning ("Could not send notification to daemon\n");
+
+ /* create the private structure */
+ g_free (start_str);
+ g_free (end_str);
+ g_free (alarm_str);
+ g_free (time_str);
+ g_free (str);
+
+
}
+#endif
/* Performs notification of an audio alarm */
static void
@@ -1173,8 +1488,6 @@ audio_notification (time_t trigger, CompQueuedAlarms *cqa,
if (attach)
icalattach_unref (attach);
- /* We present a notification message in addition to playing the sound */
- display_notification (trigger, cqa, alarm_id, FALSE);
}
/* Performs notification of a mail alarm */
@@ -1186,8 +1499,6 @@ mail_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id)
/* FIXME */
- display_notification (trigger, cqa, alarm_id, FALSE);
-
dialog = gtk_dialog_new_with_buttons (_("Warning"),
NULL, 0,
GTK_STOCK_OK, GTK_RESPONSE_CANCEL,
@@ -1301,7 +1612,6 @@ procedure_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id
if (result < 0)
goto fallback;
- remove_queued_alarm (cqa, alarm_id, TRUE, TRUE);
return;
fallback:
@@ -1337,8 +1647,10 @@ check_midnight_refresh (gpointer user_data)
* beginning of the program.
**/
void
-alarm_queue_init (void)
+alarm_queue_init (gpointer data)
{
+ GtkWidget *tray_icon;
+ an = data;
g_return_if_fail (alarm_queue_inited == FALSE);
client_alarms_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
@@ -1353,6 +1665,19 @@ alarm_queue_init (void)
/* install timeout handler (every 30 mins) for not missing the midnight refresh */
g_timeout_add (1800000, (GSourceFunc) check_midnight_refresh, NULL);
+ tray_icon = GTK_WIDGET (egg_tray_icon_new ("Evolution Alarm"));
+ tray_image = e_icon_factory_get_image ("stock_appointment-reminder", E_ICON_SIZE_LARGE_TOOLBAR);
+ tray_event_box = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER (tray_event_box), tray_image);
+ gtk_container_add (GTK_CONTAINER (tray_icon), tray_event_box);
+ g_signal_connect (G_OBJECT (tray_event_box), "button_press_event",
+ G_CALLBACK (tray_icon_clicked_cb), NULL);
+ gtk_widget_show_all (tray_icon);
+
+#ifdef HAVE_LIBNOTIFY
+ notify_init("Evolution Alarms");
+#endif
+
alarm_queue_inited = TRUE;
}
@@ -1479,11 +1804,12 @@ alarm_queue_add_client (ECal *client)
static void
add_id_cb (gpointer key, gpointer value, gpointer data)
{
- GSList **ids;
- const ECalComponentId *id;
+ GSList **ids = (GSList **) data;
+ ECalComponentId *id = g_new0 (ECalComponentId, 1);
+ ECalComponentId *temp = (ECalComponentId *)key;
- ids = data;
- id = key;
+ id->uid = g_strdup (temp->uid);
+ id->rid = g_strdup (temp->rid);
*ids = g_slist_prepend (*ids, (ECalComponentId *) id);
}
diff --git a/calendar/gui/alarm-notify/alarm-queue.h b/calendar/gui/alarm-notify/alarm-queue.h
index 12802750ec..60e1abde46 100644
--- a/calendar/gui/alarm-notify/alarm-queue.h
+++ b/calendar/gui/alarm-notify/alarm-queue.h
@@ -24,7 +24,7 @@
#include <libecal/e-cal.h>
-void alarm_queue_init (void);
+void alarm_queue_init (gpointer);
void alarm_queue_done (void);
void alarm_queue_add_client (ECal *client);
diff --git a/calendar/gui/alarm-notify/config-data.c b/calendar/gui/alarm-notify/config-data.c
index cd3f7ed885..c8a35fada5 100644
--- a/calendar/gui/alarm-notify/config-data.c
+++ b/calendar/gui/alarm-notify/config-data.c
@@ -95,6 +95,84 @@ ensure_inited (void)
}
+ESourceList *
+config_data_get_calendars (const char *key)
+{
+ ESourceList *cal_sources;
+ gboolean state;
+ GSList *gconf_list;
+
+ if (!inited)
+ conf_client = gconf_client_get_default ();
+
+ gconf_list = gconf_client_get_list (conf_client,
+ key,
+ GCONF_VALUE_STRING,
+ NULL);
+ cal_sources = e_source_list_new_for_gconf (conf_client, key);
+
+ if (cal_sources && g_slist_length (gconf_list))
+ return cal_sources;
+
+ state = gconf_client_get_bool (conf_client,
+ "/apps/evolution/calendar/notify/notify_with_tray",
+ NULL);
+ if (!state) /* Should be old client*/ {
+ GSList *source;
+ gconf_client_set_bool (conf_client,
+ "/apps/evolution/calendar/notify/notify_with_tray",
+ TRUE,
+ NULL);
+ source = gconf_client_get_list (conf_client,
+ "/apps/evolution/calendar/sources",
+ GCONF_VALUE_STRING,
+ NULL);
+ gconf_client_set_list (conf_client,
+ key,
+ GCONF_VALUE_STRING,
+ source,
+ NULL);
+ cal_sources = e_source_list_new_for_gconf (conf_client, key);
+ }
+
+
+ return cal_sources;
+
+}
+
+void
+config_data_replace_string_list (const char *key,
+ const char *old,
+ const char *new)
+{
+ GSList *source, *tmp;
+
+ if (!inited)
+ conf_client = gconf_client_get_default ();
+
+ source = gconf_client_get_list (conf_client,
+ key,
+ GCONF_VALUE_STRING,
+ NULL);
+
+ for (tmp = source; tmp; tmp = tmp->next) {
+
+ if (strcmp (tmp->data, old) == 0) {
+ gboolean state;
+
+ g_free (tmp->data);
+ tmp->data = g_strdup ((gchar *) new);
+
+ state = gconf_client_set_list (conf_client,
+ key,
+ GCONF_VALUE_STRING,
+ source,
+ NULL);
+ break;
+ }
+ }
+}
+
GConfClient *
config_data_get_conf_client (void)
{
diff --git a/calendar/gui/alarm-notify/config-data.h b/calendar/gui/alarm-notify/config-data.h
index e5b2c3d689..d8274ad7e7 100644
--- a/calendar/gui/alarm-notify/config-data.h
+++ b/calendar/gui/alarm-notify/config-data.h
@@ -24,6 +24,7 @@
#include <glib.h>
#include <libical/ical.h>
#include <gconf/gconf-client.h>
+#include <libedataserver/e-source-list.h>
GConfClient *config_data_get_conf_client (void);
@@ -34,5 +35,7 @@ void config_data_set_last_notification_time (time_t t);
time_t config_data_get_last_notification_time (void);
void config_data_save_blessed_program (const char *program);
gboolean config_data_is_blessed_program (const char *program);
+ESourceList *config_data_get_calendars (const char *);
+void config_data_replace_string_list (const char *, const char *, const char *);
#endif
diff --git a/calendar/gui/alarm-notify/util.c b/calendar/gui/alarm-notify/util.c
index ac24bbb56d..900d20e67d 100644
--- a/calendar/gui/alarm-notify/util.c
+++ b/calendar/gui/alarm-notify/util.c
@@ -47,3 +47,52 @@ timet_to_str_with_zone (time_t t, icaltimezone *zone)
FALSE, FALSE, buf, sizeof (buf));
return g_strdup (buf);
}
+
+char *
+calculate_time (time_t start, time_t end)
+{
+ time_t difference = end - start;
+ char *str;
+
+ if (difference < 60) {/* Can't be zero */
+ str = g_strdup_printf (_("(%d seconds)"), difference);
+ } else if (difference > 60 && difference < 3600) { /* It will be x minutes y seconds*/
+ int minutes, seconds;
+ minutes = difference / 60;
+ seconds = difference % 60;
+ if (seconds)
+ str = g_strdup_printf (_("(%d %s %d %s)"), minutes, ngettext(_("minute"), _("minutes"), minutes), seconds, ngettext(_("second"), _("seconds"), seconds));
+ else
+ str = g_strdup_printf (_("(%d %s)"), minutes, ngettext(_("minute"), _("minutes"), minutes));
+ } else {
+ guint hours, minutes, seconds;
+ char *s_hours = NULL, *s_minutes = NULL, *s_seconds = NULL;
+
+ hours = difference / 3600;
+ minutes = (difference % 3600)/60;
+ seconds = difference % 60;
+
+
+ if (seconds)
+ s_seconds = g_strdup_printf (ngettext(_(" %u second"), _(" %u seconds"), seconds), seconds);
+ if (minutes)
+ s_minutes = g_strdup_printf (ngettext(_(" %u minute"), _(" %u minutes"), minutes), minutes);
+ if (hours)
+ s_hours = g_strdup_printf (ngettext(_("%u hour"),_("%u hours"), hours), hours);
+
+ if (s_minutes && s_seconds)
+ str = g_strconcat ("(", s_hours, s_minutes, s_seconds, ")", NULL);
+ else if (s_minutes)
+ str = g_strconcat ("(", s_hours, s_minutes, ")", NULL);
+ else if (s_seconds)
+ str = g_strconcat ("(", s_hours, s_seconds, ")", NULL);
+ else
+ str = g_strconcat ("(", s_hours, ")", NULL);
+
+ g_free (s_hours);
+ g_free (s_minutes);
+ g_free (s_seconds);
+ }
+
+ return g_strchug(str);
+}
diff --git a/calendar/gui/alarm-notify/util.h b/calendar/gui/alarm-notify/util.h
index 7dae3dd7fe..59abd072be 100644
--- a/calendar/gui/alarm-notify/util.h
+++ b/calendar/gui/alarm-notify/util.h
@@ -25,5 +25,5 @@
#include <libecal/e-cal-component.h>
char *timet_to_str_with_zone (time_t t, icaltimezone *zone);
-
+char *calculate_time (time_t start, time_t end);
#endif