From 2eeec5bdc657477ae623e84aa3036f6cad19515a Mon Sep 17 00:00:00 2001 From: Hans Petter Jansson Date: Thu, 28 Aug 2003 20:11:57 +0000 Subject: Added alarm-notify utils. 2003-08-28 Hans Petter Jansson * gui/alarm-notify/util.[ch]: Added alarm-notify utils. * gui/alarm-notify/Makefile.am: Added alarm-notify utils. * gui/alarm-notify/alarm-notify-dialog.c (timet_to_str_with_zone): Move to util.c. * gui/alarm-notify/alarm-queue.c (notify_dialog_cb) (on_dialog_removed_cb) (notify_dialog_cb) (tray_icon_destroyed_cb) (tray_icon_clicked_cb) (tray_icon_blink_cb) (display_notification): Add Rodrigo Moya's code for tray icon notification of appointments, with some fixes and blink code by me. Requires HEAD gnome-icon-theme for now. svn path=/trunk/; revision=22406 --- calendar/gui/alarm-notify/Makefile.am | 6 +- calendar/gui/alarm-notify/alarm-notify-dialog.c | 20 +- calendar/gui/alarm-notify/alarm-queue.c | 279 +++++++++++++++++------- calendar/gui/alarm-notify/util.c | 45 ++++ calendar/gui/alarm-notify/util.h | 29 +++ 5 files changed, 284 insertions(+), 95 deletions(-) create mode 100644 calendar/gui/alarm-notify/util.c create mode 100644 calendar/gui/alarm-notify/util.h (limited to 'calendar/gui') diff --git a/calendar/gui/alarm-notify/Makefile.am b/calendar/gui/alarm-notify/Makefile.am index 20432cb615..8d8ba5df4b 100644 --- a/calendar/gui/alarm-notify/Makefile.am +++ b/calendar/gui/alarm-notify/Makefile.am @@ -47,7 +47,9 @@ evolution_alarm_notify_SOURCES = \ config-data.h \ notify-main.c \ save.c \ - save.h + save.h \ + util.c \ + util.h evolution_alarm_notify_LDADD = \ $(top_builddir)/calendar/cal-client/libcal-client.la \ @@ -72,4 +74,4 @@ BUILT_SOURCES = $(CORBA_GENERATED) $(server_DATA) CLEANFILES = $(BUILT_SOURCES) dist-hook: - cd $(distdir); rm -f $(BUILT_SOURCES) \ No newline at end of file + cd $(distdir); rm -f $(BUILT_SOURCES) diff --git a/calendar/gui/alarm-notify/alarm-notify-dialog.c b/calendar/gui/alarm-notify/alarm-notify-dialog.c index 203fa39cb4..3697fc1290 100644 --- a/calendar/gui/alarm-notify/alarm-notify-dialog.c +++ b/calendar/gui/alarm-notify/alarm-notify-dialog.c @@ -40,6 +40,7 @@ #include "cal-util/timeutil.h" #include "alarm-notify-dialog.h" #include "config-data.h" +#include "util.h" GtkWidget *make_html_display (gchar *widget_name, char *s1, char *s2, int scroll, int shadow); @@ -215,25 +216,6 @@ write_times (GtkHTMLStream *stream, char *start, char *end) } -/* Converts a time_t to a string, relative to the specified timezone */ -static char * -timet_to_str_with_zone (time_t t, icaltimezone *zone) -{ - struct icaltimetype itt; - struct tm tm; - char buf[256]; - - if (t == -1) - return g_strdup (_("invalid time")); - - itt = icaltime_from_timet_with_zone (t, FALSE, zone); - tm = icaltimetype_to_tm (&itt); - - e_time_format_date_and_time (&tm, config_data_get_24_hour_format (), - FALSE, FALSE, buf, sizeof (buf)); - return g_strdup (buf); -} - /* Creates a heading for the alarm notification dialog */ static void write_html_heading (GtkHTMLStream *stream, const char *message, diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c index 8aed099252..e1e77bed52 100644 --- a/calendar/gui/alarm-notify/alarm-queue.c +++ b/calendar/gui/alarm-notify/alarm-queue.c @@ -29,20 +29,25 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include #include #include +#include #include #include "alarm.h" #include "alarm-notify-dialog.h" #include "alarm-queue.h" #include "config-data.h" #include "save.h" +#include "util.h" @@ -649,13 +654,53 @@ edit_component (CalClient *client, CalComponent *comp) CORBA_exception_free (&ev); } -struct notify_dialog_closure { + +/* /\* Callback used from the alarm notify dialog *\/ */ +/* static void */ +/* notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) */ +/* { */ + +/* switch (result) { */ +/* case ALARM_NOTIFY_SNOOZE: */ +/* create_snooze (c->cqa, c->alarm_id, snooze_mins); */ + +/* g_object_unref (c->comp); */ +/* g_object_unref (c->client); */ +/* g_free (c); */ +/* return; */ + +/* case ALARM_NOTIFY_EDIT: */ +/* edit_component (c->client, c->comp); */ +/* break; */ + +/* case ALARM_NOTIFY_CLOSE: */ +/* /\* Do nothing *\/ */ +/* break; */ + +/* default: */ +/* g_assert_not_reached (); */ +/* } */ + +/* if (c->cqa != NULL) */ +/* remove_queued_alarm (c->cqa, c->alarm_id, TRUE, TRUE); */ +/* g_object_unref (c->comp); */ +/* g_object_unref (c->client); */ +/* g_free (c); */ +/* } */ + +typedef struct { + char *message; + gboolean blink_state; + gint blink_id; + time_t trigger; CompQueuedAlarms *cqa; gpointer alarm_id; - CalClient *client; CalComponent *comp; - gpointer dialog; -}; + CalClient *client; + GtkWidget *tray_icon; + GtkWidget *image; + GtkWidget *alarm_dialog; +} TrayIconData; static void on_dialog_obj_updated_cb (CalClient *client, const char *uid, gpointer data) @@ -669,15 +714,15 @@ static void on_dialog_obj_removed_cb (CalClient *client, const char *uid, gpointer data) { const char *our_uid; - struct notify_dialog_closure *c = data; + TrayIconData *tray_data = data; - cal_component_get_uid (c->comp, &our_uid); + cal_component_get_uid (tray_data->comp, &our_uid); g_return_if_fail (our_uid && *our_uid); if (!strcmp (uid, our_uid)) { - alarm_notify_dialog_disable_buttons (c->dialog); - c->cqa = NULL; - c->alarm_id = NULL; + alarm_notify_dialog_disable_buttons (tray_data->alarm_dialog); + tray_data->cqa = NULL; + tray_data->alarm_id = NULL; } } @@ -685,26 +730,19 @@ on_dialog_obj_removed_cb (CalClient *client, const char *uid, gpointer data) static void notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) { - struct notify_dialog_closure *c; + TrayIconData *tray_data = data; - c = data; - - g_signal_handlers_disconnect_matched (c->client, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_dialog_obj_updated_cb, NULL); - g_signal_handlers_disconnect_matched (c->client, G_SIGNAL_MATCH_FUNC, + g_signal_handlers_disconnect_matched (tray_data->client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, on_dialog_obj_removed_cb, NULL); switch (result) { case ALARM_NOTIFY_SNOOZE: - create_snooze (c->cqa, c->alarm_id, snooze_mins); - - g_object_unref (c->comp); - g_object_unref (c->client); - g_free (c); + create_snooze (tray_data->cqa, tray_data->alarm_id, snooze_mins); + tray_data->cqa = NULL; return; case ALARM_NOTIFY_EDIT: - edit_component (c->client, c->comp); + edit_component (tray_data->client, tray_data->comp); break; case ALARM_NOTIFY_CLOSE: @@ -715,11 +753,81 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) g_assert_not_reached (); } - if (c->cqa != NULL) - remove_queued_alarm (c->cqa, c->alarm_id, TRUE, TRUE); - g_object_unref (c->comp); - g_object_unref (c->client); - g_free (c); + tray_data->alarm_dialog = NULL; + gtk_widget_destroy (tray_data->tray_icon); +} + +static gint +tray_icon_destroyed_cb (GtkWidget *tray, gpointer user_data) +{ + TrayIconData *tray_data = user_data; + + if (tray_data->cqa != NULL) + remove_queued_alarm (tray_data->cqa, tray_data->alarm_id, TRUE, TRUE); + + if (tray_data->message != NULL) { + g_free (tray_data->message); + tray_data->message = NULL; + } + + g_source_remove (tray_data->blink_id); + + g_object_unref (tray_data->comp); + g_object_unref (tray_data->client); + g_free (tray_data); + + return TRUE; +} + +static gint +tray_icon_clicked_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + TrayIconData *tray_data = user_data; + + if (event->type == GDK_BUTTON_PRESS) { + if (event->button == 1) { + QueuedAlarm *qa; + + if (tray_data->alarm_dialog != NULL) + return FALSE; + + qa = lookup_queued_alarm (tray_data->cqa, tray_data->alarm_id); + if (qa) { + gtk_widget_hide (tray_data->tray_icon); + tray_data->alarm_dialog = alarm_notify_dialog ( + tray_data->trigger, + qa->instance->occur_start, + qa->instance->occur_end, + cal_component_get_vtype (tray_data->comp), + tray_data->message, + notify_dialog_cb, tray_data); + if (tray_data->alarm_dialog) { + g_signal_connect (G_OBJECT (tray_data->client), "obj_removed", + G_CALLBACK (on_dialog_obj_removed_cb), tray_data); + } + } + + return TRUE; + } else if (event->button == 2) { + return TRUE; + } + } + + return FALSE; +} + +static gboolean +tray_icon_blink_cb (gpointer data) +{ + TrayIconData *tray_data = data; + + tray_data->blink_state = tray_data->blink_state == TRUE ? FALSE : TRUE; + gtk_image_set_from_stock (GTK_IMAGE (tray_data->image), + tray_data->blink_state == TRUE ? + "appointment-reminder-excl" : "appointment-reminder", + GTK_ICON_SIZE_LARGE_TOOLBAR); + + return TRUE; } /* Performs notification of a display alarm */ @@ -727,13 +835,18 @@ static void display_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id, gboolean use_description) { + QueuedAlarm *qa; CalComponent *comp; + CalClient *client; CalComponentVType vtype; - CalComponentText text; - QueuedAlarm *qa; const char *message; - struct notify_dialog_closure *c; - gboolean use_summary; + CalComponentAlarm *alarm; + GtkWidget *tray_icon, *image, *ebox; + GtkTooltips *tooltips; + TrayIconData *tray_data; + CalComponentText text; + char *str, *start_str, *end_str, *alarm_str; + icaltimezone *current_zone; comp = cqa->alarms->comp; qa = lookup_queued_alarm (cqa, alarm_id); @@ -742,54 +855,72 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa, vtype = cal_component_get_vtype (comp); - /* Pick a sensible notification message. First we try the DESCRIPTION - * from the alarm, then the SUMMARY of the component. - */ - - use_summary = TRUE; - message = NULL; - - if (use_description) { - CalComponentAlarm *alarm; - - alarm = cal_component_get_alarm (comp, qa->instance->auid); - g_assert (alarm != NULL); - - cal_component_alarm_get_description (alarm, &text); - cal_component_alarm_free (alarm); - - if (text.value) { - message = text.value; - use_summary = FALSE; - } - } + /* get a sensible description for the event */ + alarm = cal_component_get_alarm (comp, qa->instance->auid); + g_assert (alarm != NULL); - if (use_summary) { - cal_component_get_summary (comp, &text); - if (text.value) - message = text.value; - else - message = _("No description available."); - } + cal_component_alarm_get_description (alarm, &text); + cal_component_alarm_free (alarm); - c = g_new (struct notify_dialog_closure, 1); - c->cqa = cqa; - c->alarm_id = alarm_id; - c->comp = cal_component_clone (comp); - c->client = c->cqa->parent_client->client; - g_object_ref (c->client); - - if (!(c->dialog = alarm_notify_dialog (trigger, - qa->instance->occur_start, qa->instance->occur_end, - vtype, message, - notify_dialog_cb, c))) - g_message ("display_notification(): Could not create the alarm notify dialog"); + if (text.value) + message = text.value; else { - g_signal_connect (c->client, "obj_updated", - G_CALLBACK (on_dialog_obj_updated_cb), c); - g_signal_connect (c->client, "obj_removed", - G_CALLBACK (on_dialog_obj_removed_cb), c); + cal_component_get_summary (comp, &text); + if (text.value) + message = text.value; + else + message = _("No description available."); } + + /* create the tray icon */ + tooltips = gtk_tooltips_new (); + + tray_icon = egg_tray_icon_new (qa->instance->auid); + image = gtk_image_new_from_stock ("appointment-reminder", GTK_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, message, 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)); + + gtk_container_add (GTK_CONTAINER (ebox), image); + gtk_container_add (GTK_CONTAINER (tray_icon), ebox); + + /* create the private structure */ + tray_data = g_new0 (TrayIconData, 1); + tray_data->message = g_strdup (message); + tray_data->trigger = trigger; + tray_data->cqa = cqa; + tray_data->alarm_id = alarm_id; + tray_data->comp = cal_component_clone (comp); + tray_data->client = cqa->parent_client->client; + tray_data->image = image; + tray_data->blink_state = FALSE; + g_object_ref (tray_data->client); + tray_data->tray_icon = tray_icon; + + 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); + + tray_data->blink_id = g_timeout_add (500, tray_icon_blink_cb, tray_data); + + gtk_widget_show (tray_icon); } /* Performs notification of an audio alarm */ diff --git a/calendar/gui/alarm-notify/util.c b/calendar/gui/alarm-notify/util.c new file mode 100644 index 0000000000..f40943d9b0 --- /dev/null +++ b/calendar/gui/alarm-notify/util.c @@ -0,0 +1,45 @@ +/* Evolution calendar - utility functions + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2001 Ximian, Inc. + * + * Author: Federico Mena-Quintero + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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 +#include +#include +#include "config-data.h" +#include "util.h" + +/* Converts a time_t to a string, relative to the specified timezone */ +char * +timet_to_str_with_zone (time_t t, icaltimezone *zone) +{ + struct icaltimetype itt; + struct tm tm; + char buf[256]; + + if (t == -1) + return g_strdup (_("invalid time")); + + itt = icaltime_from_timet_with_zone (t, FALSE, zone); + tm = icaltimetype_to_tm (&itt); + + e_time_format_date_and_time (&tm, config_data_get_24_hour_format (), + FALSE, FALSE, buf, sizeof (buf)); + return g_strdup (buf); +} diff --git a/calendar/gui/alarm-notify/util.h b/calendar/gui/alarm-notify/util.h new file mode 100644 index 0000000000..ab4cc4f995 --- /dev/null +++ b/calendar/gui/alarm-notify/util.h @@ -0,0 +1,29 @@ +/* Evolution calendar - utility functions + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2001 Ximian, Inc. + * + * Author: Federico Mena-Quintero + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include + +char *timet_to_str_with_zone (time_t t, icaltimezone *zone); + +#endif -- cgit