Index: mail/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/mail/Makefile.am,v
retrieving revision 1.259
diff -u -u -r1.259 Makefile.am
--- mail/Makefile.am	25 Jan 2005 02:26:33 -0000	1.259
+++ mail/Makefile.am	6 Apr 2005 01:40:17 -0000
@@ -180,7 +180,9 @@
 	message-tag-editor.c			\
 	message-tag-editor.h			\
 	message-tag-followup.c			\
-	message-tag-followup.h
+	message-tag-followup.h			\
+	em-notify.c				\
+	em-notify.h
 
 if ENABLE_SMIME
 SMIME_LIB=$(top_builddir)/smime/gui/libevolution-smime.la
Index: mail/em-mailer-prefs.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-mailer-prefs.c,v
retrieving revision 1.29
diff -u -u -r1.29 em-mailer-prefs.c
--- mail/em-mailer-prefs.c	2 Mar 2005 05:23:45 -0000	1.29
+++ mail/em-mailer-prefs.c	6 Apr 2005 01:40:23 -0000
@@ -28,6 +28,7 @@
 
 #include "em-mailer-prefs.h"
 #include "em-format.h"
+#include "em-notify.h"
 
 #include <libedataserver/e-iconv.h>
 #include <gtkhtml/gtkhtml-properties.h>
@@ -639,14 +640,14 @@
 static void
 notify_type_changed (GtkWidget *widget, EMMailerPrefs *prefs)
 {
-	int type;
+	int type = 0;
 	
-	if (gtk_toggle_button_get_active (prefs->notify_not))
-		type = MAIL_CONFIG_NOTIFY_NOT;
-	else if (gtk_toggle_button_get_active (prefs->notify_beep))
-		type = MAIL_CONFIG_NOTIFY_BEEP;
-	else
-		type = MAIL_CONFIG_NOTIFY_PLAY_SOUND;
+	if (gtk_toggle_button_get_active (prefs->notify_tray))
+		type |= MAIL_NOTIFY_TYPE_TRAY;
+	if (gtk_toggle_button_get_active (prefs->notify_beep))
+		type |= MAIL_NOTIFY_TYPE_BEEP;
+	if (gtk_toggle_button_get_active (prefs->notify_play_sound))
+		type |= MAIL_NOTIFY_TYPE_SOUND;
 	
 	gconf_client_set_int (prefs->gconf, "/apps/evolution/mail/notify/type", type, NULL);
 }
@@ -775,20 +776,21 @@
 	locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/notify/type", NULL);
 	
 	val = gconf_client_get_int (prefs->gconf, "/apps/evolution/mail/notify/type", NULL);
-	prefs->notify_not = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radNotifyNot"));
-	gtk_toggle_button_set_active (prefs->notify_not, val == MAIL_CONFIG_NOTIFY_NOT);
-	g_signal_connect (prefs->notify_not, "toggled", G_CALLBACK (notify_type_changed), prefs);
-	if (locked)
-		gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_not, FALSE);
 	
-	prefs->notify_beep = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radNotifyBeep"));
-	gtk_toggle_button_set_active (prefs->notify_beep, val == MAIL_CONFIG_NOTIFY_BEEP);
+	prefs->notify_tray = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "checkNotifyTray"));
+	gtk_toggle_button_set_active (prefs->notify_tray, val & MAIL_NOTIFY_TYPE_TRAY);
+	g_signal_connect (prefs->notify_tray, "toggled", G_CALLBACK (notify_type_changed), prefs);
+	if (locked)
+		gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_tray, FALSE);
+
+	prefs->notify_beep = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "checkNotifyBeep"));
+	gtk_toggle_button_set_active (prefs->notify_beep, val & MAIL_NOTIFY_TYPE_BEEP);
 	g_signal_connect (prefs->notify_beep, "toggled", G_CALLBACK (notify_type_changed), prefs);
 	if (locked)
 		gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_beep, FALSE);
 	
-	prefs->notify_play_sound = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radNotifyPlaySound"));
-	gtk_toggle_button_set_active (prefs->notify_play_sound, val == MAIL_CONFIG_NOTIFY_PLAY_SOUND);
+	prefs->notify_play_sound = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "checkNotifySound"));
+	gtk_toggle_button_set_active (prefs->notify_play_sound, val & MAIL_NOTIFY_TYPE_SOUND);
 	g_signal_connect (prefs->notify_play_sound, "toggled", G_CALLBACK (notify_type_changed), prefs);
 	if (locked)
 		gtk_widget_set_sensitive ((GtkWidget *) prefs->notify_play_sound, FALSE);
Index: mail/em-mailer-prefs.h
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-mailer-prefs.h,v
retrieving revision 1.12
diff -u -u -r1.12 em-mailer-prefs.h
--- mail/em-mailer-prefs.h	3 May 2004 10:30:59 -0000	1.12
+++ mail/em-mailer-prefs.h	6 Apr 2005 01:40:24 -0000
@@ -84,7 +84,7 @@
 	struct _GtkToggleButton *confirm_expunge;
 	
 	/* New Mail Notification */
-	struct _GtkToggleButton *notify_not;
+	struct _GtkToggleButton *notify_tray;
 	struct _GtkToggleButton *notify_beep;
 	struct _GtkToggleButton *notify_play_sound;
 	struct _GnomeFileEntry *notify_sound_file;
Index: mail/mail-component-factory.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-component-factory.c,v
retrieving revision 1.15
diff -u -u -r1.15 mail-component-factory.c
--- mail/mail-component-factory.c	8 Dec 2004 01:58:48 -0000	1.15
+++ mail/mail-component-factory.c	6 Apr 2005 01:40:24 -0000
@@ -42,6 +42,8 @@
 #include "em-format-hook.h"
 #include "em-format-html-display.h"
 
+#include "em-notify.h"
+
 #include "importers/mail-importer.h"
 
 #include <bonobo-activation/bonobo-activation.h>
@@ -63,6 +65,10 @@
 
 	if (strcmp (component_id, COMPONENT_ID) == 0) {
 		MailComponent *component = mail_component_peek ();
+		EmNotify *notify = em_notify_peek ();
+
+		g_object_weak_ref(G_OBJECT(component),
+				(GWeakNotify) g_object_unref, notify);
 
 		bonobo_object_ref (BONOBO_OBJECT (component));
 		return BONOBO_OBJECT (component);
Index: mail/mail-config.glade
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-config.glade,v
retrieving revision 1.158
diff -u -u -r1.158 mail-config.glade
--- mail/mail-config.glade	30 Mar 2005 07:57:45 -0000	1.158
+++ mail/mail-config.glade	6 Apr 2005 01:40:50 -0000
@@ -376,7 +376,7 @@
 				  <property name="max_length">0</property>
 				  <property name="text" translatable="yes"></property>
 				  <property name="has_frame">True</property>
-				  <property name="invisible_char">*</property>
+				  <property name="invisible_char" translatable="yes">*</property>
 				  <property name="activates_default">False</property>
 				</widget>
 				<packing>
@@ -503,7 +503,7 @@
 			      <property name="max_length">0</property>
 			      <property name="text" translatable="yes"></property>
 			      <property name="has_frame">True</property>
-			      <property name="invisible_char">*</property>
+			      <property name="invisible_char" translatable="yes">*</property>
 			      <property name="activates_default">False</property>
 			    </widget>
 			    <packing>
@@ -574,7 +574,7 @@
 			      <property name="max_length">0</property>
 			      <property name="text" translatable="yes"></property>
 			      <property name="has_frame">True</property>
-			      <property name="invisible_char">*</property>
+			      <property name="invisible_char" translatable="yes">*</property>
 			      <property name="activates_default">False</property>
 			    </widget>
 			    <packing>
@@ -761,7 +761,7 @@
 			  <property name="max_length">0</property>
 			  <property name="text" translatable="yes"></property>
 			  <property name="has_frame">True</property>
-			  <property name="invisible_char">*</property>
+			  <property name="invisible_char" translatable="yes">*</property>
 			  <property name="activates_default">False</property>
 			</widget>
 			<packing>
@@ -807,7 +807,7 @@
 			  <property name="max_length">0</property>
 			  <property name="text" translatable="yes"></property>
 			  <property name="has_frame">True</property>
-			  <property name="invisible_char">*</property>
+			  <property name="invisible_char" translatable="yes">*</property>
 			  <property name="activates_default">False</property>
 			</widget>
 			<packing>
@@ -1174,7 +1174,7 @@
 				  <property name="max_length">0</property>
 				  <property name="text" translatable="yes"></property>
 				  <property name="has_frame">True</property>
-				  <property name="invisible_char">*</property>
+				  <property name="invisible_char" translatable="yes">*</property>
 				  <property name="activates_default">False</property>
 				</widget>
 				<packing>
@@ -1195,7 +1195,7 @@
 				  <property name="max_length">0</property>
 				  <property name="text" translatable="yes"></property>
 				  <property name="has_frame">True</property>
-				  <property name="invisible_char">*</property>
+				  <property name="invisible_char" translatable="yes">*</property>
 				  <property name="activates_default">False</property>
 				</widget>
 				<packing>
@@ -1240,7 +1240,6 @@
 				  <property name="directory_entry">False</property>
 				  <property name="modal">False</property>
 				  <property name="use_filechooser">True</property>
-				  <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
 
 				  <child internal-child="entry">
 				    <widget class="GtkEntry" id="source_path">
@@ -1251,7 +1250,7 @@
 				      <property name="max_length">0</property>
 				      <property name="text" translatable="yes"></property>
 				      <property name="has_frame">True</property>
-				      <property name="invisible_char">*</property>
+				      <property name="invisible_char" translatable="yes">*</property>
 				      <property name="activates_default">False</property>
 				    </widget>
 				  </child>
@@ -1901,7 +1900,7 @@
 					  <property name="max_length">0</property>
 					  <property name="text" translatable="yes"></property>
 					  <property name="has_frame">True</property>
-					  <property name="invisible_char">*</property>
+					  <property name="invisible_char" translatable="yes">*</property>
 					  <property name="activates_default">False</property>
 					</widget>
 					<packing>
@@ -2287,7 +2286,7 @@
 					  <property name="max_length">0</property>
 					  <property name="text" translatable="yes"></property>
 					  <property name="has_frame">True</property>
-					  <property name="invisible_char">*</property>
+					  <property name="invisible_char" translatable="yes">*</property>
 					  <property name="activates_default">False</property>
 					</widget>
 					<packing>
@@ -2872,7 +2871,7 @@
 					      <property name="max_length">0</property>
 					      <property name="text" translatable="yes"></property>
 					      <property name="has_frame">True</property>
-					      <property name="invisible_char">*</property>
+					      <property name="invisible_char" translatable="yes">*</property>
 					      <property name="activates_default">False</property>
 					    </widget>
 					    <packing>
@@ -2988,7 +2987,7 @@
 					      <property name="max_length">0</property>
 					      <property name="text" translatable="yes"></property>
 					      <property name="has_frame">True</property>
-					      <property name="invisible_char">*</property>
+					      <property name="invisible_char" translatable="yes">*</property>
 					      <property name="activates_default">False</property>
 					    </widget>
 					    <packing>
@@ -3195,7 +3194,7 @@
 				  <property name="max_length">0</property>
 				  <property name="text" translatable="yes"></property>
 				  <property name="has_frame">True</property>
-				  <property name="invisible_char">*</property>
+				  <property name="invisible_char" translatable="yes">*</property>
 				  <property name="activates_default">False</property>
 				</widget>
 				<packing>
@@ -3389,7 +3388,7 @@
 			  <property name="max_length">0</property>
 			  <property name="text" translatable="yes"></property>
 			  <property name="has_frame">True</property>
-			  <property name="invisible_char">*</property>
+			  <property name="invisible_char" translatable="yes">*</property>
 			  <property name="activates_default">False</property>
 			</widget>
 			<packing>
@@ -3410,7 +3409,7 @@
 			  <property name="max_length">0</property>
 			  <property name="text" translatable="yes"></property>
 			  <property name="has_frame">True</property>
-			  <property name="invisible_char">*</property>
+			  <property name="invisible_char" translatable="yes">*</property>
 			  <property name="activates_default">False</property>
 			</widget>
 			<packing>
@@ -4926,10 +4925,10 @@
 			  <property name="spacing">6</property>
 
 			  <child>
-			    <widget class="GtkRadioButton" id="radNotifyNot">
+			    <widget class="GtkCheckButton" id="checkNotifyTray">
 			      <property name="visible">True</property>
 			      <property name="can_focus">True</property>
-			      <property name="label" translatable="yes">_Do not notify me when new mail arrives</property>
+			      <property name="label" translatable="yes">Show icon in the system tray</property>
 			      <property name="use_underline">True</property>
 			      <property name="relief">GTK_RELIEF_NORMAL</property>
 			      <property name="focus_on_click">True</property>
@@ -4945,7 +4944,7 @@
 			  </child>
 
 			  <child>
-			    <widget class="GtkRadioButton" id="radNotifyBeep">
+			    <widget class="GtkCheckButton" id="checkNotifyBeep">
 			      <property name="visible">True</property>
 			      <property name="can_focus">True</property>
 			      <property name="label" translatable="yes">Beep w_hen new mail arrives</property>
@@ -4955,7 +4954,6 @@
 			      <property name="active">False</property>
 			      <property name="inconsistent">False</property>
 			      <property name="draw_indicator">True</property>
-			      <property name="group">radNotifyNot</property>
 			    </widget>
 			    <packing>
 			      <property name="padding">0</property>
@@ -4965,7 +4963,7 @@
 			  </child>
 
 			  <child>
-			    <widget class="GtkRadioButton" id="radNotifyPlaySound">
+			    <widget class="GtkCheckButton" id="checkNotifySound">
 			      <property name="visible">True</property>
 			      <property name="can_focus">True</property>
 			      <property name="label" translatable="yes">Play sound file when new mail arri_ves</property>
@@ -4975,7 +4973,6 @@
 			      <property name="active">False</property>
 			      <property name="inconsistent">False</property>
 			      <property name="draw_indicator">True</property>
-			      <property name="group">radNotifyNot</property>
 			    </widget>
 			    <packing>
 			      <property name="padding">0</property>
@@ -5031,7 +5027,7 @@
 				      <property name="max_length">0</property>
 				      <property name="text" translatable="yes"></property>
 				      <property name="has_frame">True</property>
-				      <property name="invisible_char">*</property>
+				      <property name="invisible_char" translatable="yes">*</property>
 				      <property name="activates_default">False</property>
 				    </widget>
 				  </child>
@@ -5550,7 +5546,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes">Important</property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -5572,7 +5568,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes">Work</property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -5594,7 +5590,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes">Personal</property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -5616,7 +5612,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes">To Do</property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -5638,7 +5634,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes">Later</property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -5793,7 +5789,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes"></property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -5821,7 +5817,7 @@
 			  <property name="reorderable">False</property>
 			  <property name="enable_search">True</property>
 			  <accessibility>
-			     <atkproperty name="AtkObject::accessible_name" translatable="yes">Mail Headers Table</atkproperty>
+			    <atkproperty name="AtkObject::accessible_name" translatable="yes">Mail Headers Table</atkproperty>
 			  </accessibility>
 			</widget>
 		      </child>
@@ -6403,7 +6399,7 @@
 			      <child>
 				<widget class="GtkAlignment" id="alignment25">
 				  <property name="visible">True</property>
-				  <property name="xalign">7.45058015283e-09</property>
+				  <property name="xalign">7.45058e-09</property>
 				  <property name="yalign">0.5</property>
 				  <property name="xscale">0</property>
 				  <property name="yscale">1</property>
@@ -7337,7 +7333,7 @@
 					  <property name="enable_search">True</property>
 					  <accessibility>
 					    <atkproperty name="AtkObject::accessible_name" translatable="yes">Languages Table</atkproperty>
-					  </accessibility> 
+					  </accessibility>
 					</widget>
 				      </child>
 				    </widget>
@@ -8075,7 +8071,7 @@
 		      <property name="max_length">0</property>
 		      <property name="text" translatable="yes"></property>
 		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
+		      <property name="invisible_char" translatable="yes">*</property>
 		      <property name="activates_default">False</property>
 		    </widget>
 		    <packing>
@@ -8095,7 +8091,6 @@
 		      <property name="directory_entry">False</property>
 		      <property name="modal">False</property>
 		      <property name="use_filechooser">True</property>
-		      <property name="filechooser_action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
 
 		      <child internal-child="entry">
 			<widget class="GtkEntry" id="combo-entry2">
@@ -8106,7 +8101,7 @@
 			  <property name="max_length">0</property>
 			  <property name="text" translatable="yes"></property>
 			  <property name="has_frame">True</property>
-			  <property name="invisible_char">*</property>
+			  <property name="invisible_char" translatable="yes">*</property>
 			  <property name="activates_default">False</property>
 			</widget>
 		      </child>
Index: mail/mail-folder-cache.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-folder-cache.c,v
retrieving revision 1.99
diff -u -u -r1.99 mail-folder-cache.c
--- mail/mail-folder-cache.c	6 Jan 2005 22:12:57 -0000	1.99
+++ mail/mail-folder-cache.c	6 Apr 2005 01:40:55 -0000
@@ -54,6 +54,7 @@
 #include "mail-autofilter.h"
 #include "mail-config.h"
 #include "em-folder-tree-model.h"
+#include "em-notify.h"
 
 #include "em-event.h"
 
@@ -98,6 +99,7 @@
 
 	int unread;
 	CamelStore *store;
+	CamelFolder *folder;
 };
 
 struct _store_info {
@@ -117,9 +119,6 @@
 static guint ping_id = 0;
 static gboolean ping_cb (gpointer user_data);
 
-static guint notify_id = 0;
-static int notify_type = -1;
-
 static time_t last_notify = 0;
 static guint notify_idle_id = 0;
 static gboolean notify_idle_cb (gpointer user_data);
@@ -151,25 +150,9 @@
 static gboolean
 notify_idle_cb (gpointer user_data)
 {
-	GConfClient *gconf;
-	char *filename;
-	
-	gconf = mail_config_get_gconf_client ();
-	
-	switch (notify_type) {
-	case MAIL_CONFIG_NOTIFY_PLAY_SOUND:
-		filename = gconf_client_get_string (gconf, "/apps/evolution/mail/notify/sound", NULL);
-		if (filename != NULL) {
-			gnome_sound_play (filename);
-			g_free (filename);
-		}
-		break;
-	case MAIL_CONFIG_NOTIFY_BEEP:
-		gdk_beep ();
-		break;
-	default:
-		break;
-	}
+	EmNotify *n = em_notify_peek();
+	em_notify_notify(n, GPOINTER_TO_INT(user_data));
+	g_object_unref(n);
 	
 	time (&last_notify);
 	
@@ -179,15 +162,9 @@
 }
 
 static void
-notify_type_changed (GConfClient *client, guint cnxn_id,
-		     GConfEntry *entry, gpointer user_data)
-{
-	notify_type = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL);
-}
-
-static void
 real_flush_updates(void *o, void *event_data, void *data)
 {
+	static GSList *folders_with_new = NULL;
 	struct _MailComponent *component;
 	struct _EMFolderTreeModel *model;
 	struct _folder_update *up;
@@ -225,22 +202,16 @@
 		/* update unread counts */
 		em_folder_tree_model_set_unread_count (model, up->store, up->full_name, up->unread);
 		
-		/* new mail notification */
-		if (notify_type == -1) {
-			/* need to track the user's new-mail-notification settings... */
-			GConfClient *gconf;
-			
-			gconf = mail_config_get_gconf_client ();
-			gconf_client_add_dir (gconf, "/apps/evolution/mail/notify",
-					      GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
-			notify_id = gconf_client_notify_add (gconf, "/apps/evolution/mail/notify",
-							     notify_type_changed, NULL, NULL, NULL);
-			notify_type = gconf_client_get_int (gconf, "/apps/evolution/mail/notify/type", NULL);
-		}
-		
 		time (&now);
-		if (notify_type != 0 && up->new && notify_idle_id == 0 && (now - last_notify >= 5))
-			notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb, NULL, NULL);
+		if(up->new)
+			if(!g_slist_find(folders_with_new, up->folder))
+				folders_with_new = g_slist_append(folders_with_new, up->folder);
+
+		if (notify_idle_id == 0 && (now - last_notify >= 5)){
+		    if(g_slist_find(folders_with_new, up->folder))
+				notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb,
+						GINT_TO_POINTER((gint32) up->new), NULL);
+		}
 		
 		if (up->uri) {
 			EMEvent *e = em_event_peek();
@@ -375,6 +346,7 @@
 	up->new = new ? 1 : 0;
 	up->store = mfi->store_info->store;
 	up->uri = g_strdup(mfi->uri);
+	up->folder = folder;
 	camel_object_ref(up->store);
 	e_dlist_addtail(&updates, (EDListNode *)up);
 	flush_updates();
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mail/em-notify.c	2005-04-06 01:34:36.882140072 +0000
@@ -0,0 +1,372 @@
+/* Evolution new mail notification
+ *
+ * Copyright (C) 2005 Stéphane Konstantaropoulos
+ *
+ * Author: Stéphane Konstantaropoulos <stephane@cs.york.ac.uk>
+ *
+ * This is a GObject that handles notification of new mails.
+ * Callers obtain a reference with em_notify_peek() as this is supposed
+ * to be singleton
+ *
+ * Notification is done at em_notify_notify(), that receives one parameter
+ * new or not. Simple as it is.
+ *
+ * This can be extended to receive some more complex parameter like a
+ * CamelFolder and allow for notification of only selected folders or
+ * accounts...
+ * 
+ * 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.
+ */
+
+#define selfp (self->_priv)
+
+#include "em-notify.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mail-config.h"
+#include <e-util/e-icon-factory.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <libgnome/libgnome.h>
+
+static const GFlagsValue _em_notify_flags_values[] = {
+	{ MAIL_NOTIFY_TYPE_BEEP, (char *)"MAIL_NOTIFY_TYPE_BEEP", (char *)"beep" },
+	{ MAIL_NOTIFY_TYPE_SOUND, (char *)"MAIL_NOTIFY_TYPE_SOUND", (char *)"sound" },
+	{ MAIL_NOTIFY_TYPE_TRAY, (char *)"MAIL_NOTIFY_TYPE_TRAY", (char *)"tray" },
+	{ 0, NULL, NULL }
+};
+
+GType
+em_notify_flags_get_type (void)
+{
+	static GType type = 0;
+	if G_UNLIKELY(type == 0)
+		type = g_flags_register_static ("EmNotifyFlags", _em_notify_flags_values);
+	return type;
+}
+
+/* self casting macros */
+#define SELF(x) EM_NOTIFY(x)
+#define SELF_CONST(x) EM_NOTIFY_CONST(x)
+#define IS_SELF(x) EM_IS_NOTIFY(x)
+#define TYPE_SELF EM_TYPE_NOTIFY
+#define SELF_CLASS(x) EM_NOTIFY_CLASS(x)
+
+#define SELF_GET_CLASS(x) EM_NOTIFY_GET_CLASS(x)
+
+/* self typedefs */
+typedef EmNotify Self;
+typedef EmNotifyClass SelfClass;
+
+struct _EmNotifyPrivate {
+	EggTrayIcon * tray_icon;
+	GtkTooltips * tooltip;
+	GConfClient * client;
+	EmNotifyFlags notify_type;
+	gchar * notify_sound;
+	guint notify_id_type;
+	guint notify_id_sound;
+};
+/* here are local prototypes */
+static void ___object_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static void em_notify_class_init (EmNotifyClass * c) G_GNUC_UNUSED;
+static void em_notify_init (EmNotify * self) G_GNUC_UNUSED;
+static void ___2_em_notify_dispose (GObject * object) G_GNUC_UNUSED;
+static void em_notify_init_tray (EmNotify * self) G_GNUC_UNUSED;
+static gboolean em_notify_tray_destroyed (GtkWidget * widget, GdkEvent * event, Self * self) G_GNUC_UNUSED;
+static void em_notify_notify_changed_cb (GConfClient * client, guint cnxn_id, GConfEntry * entry, Self * self) G_GNUC_UNUSED;
+
+enum {
+	PROP_0,
+	PROP_TIP
+};
+
+/* pointer to the class of our parent */
+static GObjectClass *parent_class = NULL;
+
+/* Short form macros */
+#define self_peek em_notify_peek
+#define self_set_tip em_notify_set_tip
+#define self_notify em_notify_notify
+#define self_init_tray em_notify_init_tray
+#define self_tray_destroyed em_notify_tray_destroyed
+#define self_notify_changed_cb em_notify_notify_changed_cb
+GType
+em_notify_get_type (void)
+{
+	static GType type = 0;
+
+	if G_UNLIKELY(type == 0) {
+		static const GTypeInfo info = {
+			sizeof (EmNotifyClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) em_notify_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL /* class_data */,
+			sizeof (EmNotify),
+			0 /* n_preallocs */,
+			(GInstanceInitFunc) em_notify_init,
+			NULL
+		};
+
+		type = g_type_register_static (G_TYPE_OBJECT, "EmNotify", &info, (GTypeFlags)0);
+	}
+
+	return type;
+}
+
+/* a macro for creating a new object of our type */
+#define GET_NEW ((EmNotify *)g_object_new(em_notify_get_type(), NULL))
+
+/* a function for creating a new object of our type */
+#include <stdarg.h>
+static EmNotify * GET_NEW_VARG (const char *first, ...) G_GNUC_UNUSED;
+static EmNotify *
+GET_NEW_VARG (const char *first, ...)
+{
+	EmNotify *ret;
+	va_list ap;
+	va_start (ap, first);
+	ret = (EmNotify *)g_object_new_valist (em_notify_get_type (), first, ap);
+	va_end (ap);
+	return ret;
+}
+
+
+static void
+___dispose (GObject *obj_self)
+{
+	EmNotify *self G_GNUC_UNUSED = EM_NOTIFY (obj_self);
+	___2_em_notify_dispose(obj_self);
+	if(self->_priv->tray_icon) { gtk_widget_destroy ((gpointer) self->_priv->tray_icon); self->_priv->tray_icon = NULL; }
+	if(self->_priv->tooltip) { gtk_object_destroy ((gpointer) self->_priv->tooltip); self->_priv->tooltip = NULL; }
+	if(self->_priv->client) { g_object_unref ((gpointer) self->_priv->client); self->_priv->client = NULL; }
+	if(self->_priv->notify_sound) { g_free ((gpointer) self->_priv->notify_sound); self->_priv->notify_sound = NULL; }
+}
+
+
+static void
+___finalize(GObject *obj_self)
+{
+	EmNotify *self G_GNUC_UNUSED = EM_NOTIFY (obj_self);
+	gpointer priv G_GNUC_UNUSED = self->_priv;
+	if(G_OBJECT_CLASS(parent_class)->finalize) \
+		(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+}
+
+static void 
+em_notify_class_init (EmNotifyClass * c G_GNUC_UNUSED)
+{
+	GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
+
+	g_type_class_add_private(c,sizeof(EmNotifyPrivate));
+
+	parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+	g_object_class->dispose = ___dispose;
+	g_object_class->finalize = ___finalize;
+	g_object_class->set_property = ___object_set_property;
+    {
+	GParamSpec   *param_spec;
+
+	param_spec = g_param_spec_string
+		("tip" /* name */,
+		 _("Tooltip") /* nick */,
+		 _("Tooltip of the tray icon") /* blurb */,
+		 NULL /* default_value */,
+		 (GParamFlags)(G_PARAM_WRITABLE));
+	g_object_class_install_property (g_object_class,
+		PROP_TIP,
+		param_spec);
+    }
+}
+static void 
+em_notify_init (EmNotify * self G_GNUC_UNUSED)
+{
+	self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self,TYPE_SELF,EmNotifyPrivate);
+	self->_priv->tray_icon = NULL;
+	self->_priv->tooltip = gtk_tooltips_new ();
+	self->_priv->client = g_object_ref(mail_config_get_gconf_client ());
+	self->_priv->notify_sound = NULL;
+	self->_priv->notify_id_type = FALSE;
+	self->_priv->notify_id_sound = FALSE;
+ {
+
+		self_init_tray(self);
+		// get GConf values
+		gconf_client_add_dir(selfp->client, "/apps/evolution/notify",
+				GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+		selfp->notify_sound = gconf_client_get_string (selfp->client, "/apps/evolution/mail/notify/sound", NULL);
+		selfp->notify_type = gconf_client_get_int (selfp->client, "/apps/evolution/mail/notify/type", NULL);
+
+		//register GConf listeners
+		selfp->notify_id_type = gconf_client_notify_add(selfp->client,
+				"/apps/evolution/mail/notify/type",
+				(GConfClientNotifyFunc)	self_notify_changed_cb, self, NULL, NULL);
+		selfp->notify_id_sound = gconf_client_notify_add(selfp->client,
+				"/apps/evolution/mail/notify/sound",
+				(GConfClientNotifyFunc) self_notify_changed_cb, self, NULL, NULL);
+	
+ }
+}
+
+static void
+___object_set_property (GObject *object,
+	guint property_id,
+	const GValue *VAL G_GNUC_UNUSED,
+	GParamSpec *pspec G_GNUC_UNUSED)
+{
+	EmNotify *self G_GNUC_UNUSED;
+
+	self = EM_NOTIFY (object);
+
+	switch (property_id) {
+	case PROP_TIP:
+		{
+
+			gtk_tooltips_set_tip(selfp->tooltip,
+			GTK_WIDGET (selfp->tray_icon), g_value_get_string(VAL), NULL);
+		
+		}
+		break;
+	default:
+/* Apparently in g++ this is needed, glib is b0rk */
+#ifndef __PRETTY_FUNCTION__
+#  undef G_STRLOC
+#  define G_STRLOC	__FILE__ ":" G_STRINGIFY (__LINE__)
+#endif
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+
+static void 
+___2_em_notify_dispose (GObject * object G_GNUC_UNUSED)
+#define PARENT_HANDLER(___object) \
+	{ if(G_OBJECT_CLASS(parent_class)->dispose) \
+		(* G_OBJECT_CLASS(parent_class)->dispose)(___object); }
+{
+{
+	
+		Self *self = SELF(object);
+		puts(G_STRLOC);
+		gconf_client_notify_remove(selfp->client, selfp->notify_id_type);
+		gconf_client_notify_remove(selfp->client, selfp->notify_id_sound);
+		PARENT_HANDLER(object);
+	}}
+#undef PARENT_HANDLER
+
+EmNotify * 
+em_notify_peek (void)
+{
+{
+	
+		static Self *self = NULL;
+		if (G_UNLIKELY(self == NULL)){
+			self = GET_NEW;
+			g_object_add_weak_pointer(G_OBJECT(self), (gpointer) &self);
+			return self;
+		}
+		return (Self *) g_object_ref(self);
+	}}
+
+void 
+em_notify_set_tip (EmNotify * self, const gchar * text)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (EM_IS_NOTIFY (self));
+{
+	
+		gboolean ret; //unused
+		gtk_tooltips_set_tip (selfp->tooltip,
+			GTK_WIDGET (selfp->tray_icon), text, NULL);
+		//show tooltip
+		g_signal_emit_by_name(selfp->tray_icon,"show-help", GTK_WIDGET_HELP_TOOLTIP, &ret);
+	}}
+
+void 
+em_notify_notify (EmNotify * self, gboolean new)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (EM_IS_NOTIFY (self));
+{
+	
+		if(new){
+			if (selfp->notify_type & MAIL_NOTIFY_TYPE_SOUND)
+				if (selfp->notify_sound != NULL)
+					gnome_sound_play (selfp->notify_sound);
+			if (selfp->notify_type & MAIL_NOTIFY_TYPE_BEEP)
+				gdk_beep ();
+			if (selfp->notify_type & MAIL_NOTIFY_TYPE_TRAY){
+				gtk_widget_show_all(GTK_WIDGET(selfp->tray_icon));
+				self_set_tip(self, _("You have mail!"));
+			}
+		} else 
+			gtk_widget_hide(GTK_WIDGET(selfp->tray_icon));
+	}}
+
+static void 
+em_notify_init_tray (EmNotify * self)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (EM_IS_NOTIFY (self));
+{
+	
+		GtkWidget *image = e_icon_factory_get_image("stock_mail",
+				E_ICON_SIZE_MENU);
+		GtkWidget *evbox = gtk_event_box_new ();
+		selfp->tray_icon = egg_tray_icon_new("EmNotify");
+		gtk_container_add (GTK_CONTAINER (evbox), image);
+		gtk_container_add (GTK_CONTAINER(selfp->tray_icon), evbox);
+		g_signal_connect (G_OBJECT (selfp->tray_icon), "destroy-event",
+			G_CALLBACK (self_tray_destroyed), self);
+
+		//add drag and drop, event handling and popup menu
+	}}
+
+static gboolean 
+em_notify_tray_destroyed (GtkWidget * widget, GdkEvent * event, Self * self)
+{
+	g_return_val_if_fail (!(self) || IS_SELF (self), (gboolean )0);
+{
+	
+		g_object_unref(widget);
+		g_idle_add((GSourceFunc) self_init_tray, self);
+		return TRUE;
+	}}
+
+static void 
+em_notify_notify_changed_cb (GConfClient * client, guint cnxn_id, GConfEntry * entry, Self * self)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (IS_SELF (self));
+{
+	
+		if(cnxn_id == selfp->notify_id_sound){
+			if(selfp->notify_sound)
+				g_free(selfp->notify_sound);
+			selfp->notify_sound = gconf_client_get_string (client, "/apps/evolution/mail/notify/sound", NULL);
+		} else if(cnxn_id == selfp->notify_id_type){
+			selfp->notify_type = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL);
+
+		} else {
+			g_warning(G_STRLOC" - wrong cnx_id given by GConf.");
+		}
+	}}
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ mail/em-notify.h	2005-04-05 19:47:46.054866704 +0000
@@ -0,0 +1,104 @@
+/* Evolution new mail notification
+ *
+ * Copyright (C) 2005 Stéphane Konstantaropoulos
+ *
+ * Author: Stéphane Konstantaropoulos <stephane@cs.york.ac.uk>
+ *
+ * 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 <glib.h>
+#include <glib-object.h>
+#ifndef __EM_NOTIFY_H__
+#define __EM_NOTIFY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <e-util/eggtrayicon.h>
+
+typedef enum {
+	MAIL_NOTIFY_TYPE_BEEP = 1<<0,
+	MAIL_NOTIFY_TYPE_SOUND = 1<<1,
+	MAIL_NOTIFY_TYPE_TRAY = 1<<2
+} EmNotifyFlags;
+#define EM_TYPE_NOTIFY_FLAGS em_notify_flags_get_type()
+GType em_notify_flags_get_type (void);
+
+
+/*
+ * Type checking and casting macros
+ */
+#define EM_TYPE_NOTIFY	(em_notify_get_type())
+#define EM_NOTIFY(obj)	G_TYPE_CHECK_INSTANCE_CAST((obj), em_notify_get_type(), EmNotify)
+#define EM_NOTIFY_CONST(obj)	G_TYPE_CHECK_INSTANCE_CAST((obj), em_notify_get_type(), EmNotify const)
+#define EM_NOTIFY_CLASS(klass)	G_TYPE_CHECK_CLASS_CAST((klass), em_notify_get_type(), EmNotifyClass)
+#define EM_IS_NOTIFY(obj)	G_TYPE_CHECK_INSTANCE_TYPE((obj), em_notify_get_type ())
+
+#define EM_NOTIFY_GET_CLASS(obj)	G_TYPE_INSTANCE_GET_CLASS((obj), em_notify_get_type(), EmNotifyClass)
+
+/* Private structure type */
+typedef struct _EmNotifyPrivate EmNotifyPrivate;
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_EM_NOTIFY__
+#define __TYPEDEF_EM_NOTIFY__
+typedef struct _EmNotify EmNotify;
+#endif
+struct _EmNotify {
+	GObject __parent__;
+	/*< private >*/
+	EmNotifyPrivate *_priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _EmNotifyClass EmNotifyClass;
+struct _EmNotifyClass {
+	GObjectClass __parent__;
+};
+
+/*
+ * Public methods
+ */
+GType	em_notify_get_type	(void);
+/* use this and NOT g_object_new as this is singleton
+ * caller owns a reference to the EmNotify
+ * it has to be unreffed */
+EmNotify * 	em_notify_peek	(void);
+void 	em_notify_set_tip	(EmNotify * self,
+					const gchar * text);
+void 	em_notify_notify	(EmNotify * self,
+					gboolean new);
+
+/*
+ * Argument wrapping macros
+ */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define EM_NOTIFY_PROP_TIP(arg)    	"tip", __extension__ ({gchar *z = (arg); z;})
+#else /* __GNUC__ && !__STRICT_ANSI__ */
+#define EM_NOTIFY_PROP_TIP(arg)    	"tip",(gchar *)(arg)
+#endif /* __GNUC__ && !__STRICT_ANSI__ */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
