Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.196
diff -u -u -r1.196 configure.ac
--- configure.ac	14 Dec 2005 20:37:02 -0000	1.196
+++ configure.ac	2 Jan 2006 11:29:49 -0000
@@ -324,6 +324,29 @@
 fi
 AM_CONDITIONAL(USE_DAAP, test "x$enable_daap" = "xyes")
 
+
+AC_ARG_ENABLE(libnotify,
+            AC_HELP_STRING([--disable-libnotify],
+			   [Disable libnotify support]),,
+	      enable_libnotify=auto)
+if test "x$enable_libnotify" != "xno"; then
+	PKG_CHECK_MODULES(NOTIFY,                            \
+			  libnotify,
+			  have_libnotify=yes,
+			  have_libnotify=no)
+	if test "x$have_libnotify" = "xno" -a "x$enable_libnotify" = "xyes"; then
+	  AC_MSG_ERROR([libnotify support explicitly requested, but libnotify couldn't be found])
+	fi
+	if test "x$have_libnotify" = "xyes"; then
+	     AC_DEFINE(HAVE_NOTIFY, 1, [Define if libnotify support is enabled])
+	     enable_libnotify=yes
+	     AC_SUBST(NOTIFY_CFLAGS)
+	     AC_SUBST(NOTIFY_LIBS)
+	fi
+fi			  
+AM_CONDITIONAL(USE_NOTIFY, test x"$enable_libnotify" = xyes)
+
+
 dnl Check for libsoup, needed for DAAP and audioscrobbler
 if test "x$enable_daap" = "xyes" || test "x$enable_audioscrobbler" != "xno"; then
 	dnl We want libsoup now
@@ -682,6 +705,11 @@
 	AC_MSG_NOTICE([** DAAP (music sharing) support is enabled])
 else
 	AC_MSG_NOTICE([   DAAP (music sharing) support is disabled])
+fi
+if test x"$have_libnotify" = xyes; then
+	AC_MSG_NOTICE([** libnotify support is enabled])
+else
+	AC_MSG_NOTICE([   libnotify support is disabled])
 fi
 if test x"$enable_bonobo" = xyes; then
 	AC_MSG_NOTICE([** Bonobo control/activation enabled])
Index: data/rhythmbox.schemas
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/rhythmbox.schemas,v
retrieving revision 1.60
diff -u -u -r1.60 rhythmbox.schemas
--- data/rhythmbox.schemas	15 Dec 2005 03:48:24 -0000	1.60
+++ data/rhythmbox.schemas	2 Jan 2006 11:29:49 -0000
@@ -562,5 +562,16 @@
 	<long>Whether to enable Audioscrobbler support. Audioscrobbler is a computer system that builds up a detailed profile of your musical taste. See Audioscrobbler.com for more information.</long>
         </locale>
       </schema>
+      <schema>
+        <key>/schemas/apps/rhythmbox/ui/show_notifications</key>
+        <applyto>/apps/rhythmbox/ui/show_notifications</applyto>
+        <owner>rhythmbox</owner>
+        <type>bool</type>
+        <default>1</default>
+        <locale name="C">
+	<short>Whether to show notifications from the tray icon</short>
+	<long>When enabled, Rhythmbox will display notification bubbles when the playing track changes, a podcast is downloaded, a CD finished burning, etc.</long>
+        </locale>
+      </schema>
     </schemalist>
 </gconfschemafile>
Index: data/ui/rhythmbox-ui.xml
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/ui/rhythmbox-ui.xml,v
retrieving revision 1.33
diff -u -u -r1.33 rhythmbox-ui.xml
--- data/ui/rhythmbox-ui.xml	15 Dec 2005 03:48:24 -0000	1.33
+++ data/ui/rhythmbox-ui.xml	2 Jan 2006 11:29:50 -0000
@@ -92,6 +92,7 @@
       <menuitem name="NextTray" action="ControlNext"/>
       <separator/>
       <menuitem name="ShowWindowTray" action="TrayShowWindow"/>
+      <menuitem name="ShowNotifications" action="TrayShowNotifications"/>
       <menuitem name="QuitTray" action="MusicQuit"/>
   </popup>
 
Index: lib/rb-preferences.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-preferences.h,v
retrieving revision 1.23
diff -u -u -r1.23 rb-preferences.h
--- lib/rb-preferences.h	15 Dec 2005 03:48:25 -0000	1.23
+++ lib/rb-preferences.h	2 Jan 2006 11:29:50 -0000
@@ -43,6 +43,7 @@
 #define CONF_UI_COLUMNS_SETUP CONF_PREFIX "/ui/rhythmdb_columns_setup"
 #define CONF_UI_TIME_DISPLAY CONF_PREFIX "/ui/time_display"
 #define CONF_UI_BROWSER_VIEWS CONF_PREFIX "/ui/browser_views"
+#define CONF_UI_SHOW_NOTIFICATIONS CONF_PREFIX "/ui/show_notifications"
 #define CONF_STATE_PLAY_ORDER	CONF_PREFIX "/state/play_order"
 #define CONF_STATE_VOLUME	CONF_PREFIX "/state/volume"
 #define CONF_STATE_BURN_DEVICE	CONF_PREFIX "/state/burn_device"
Index: shell/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/Makefile.am,v
retrieving revision 1.65
diff -u -u -r1.65 Makefile.am
--- shell/Makefile.am	10 Dec 2005 12:08:24 -0000	1.65
+++ shell/Makefile.am	2 Jan 2006 11:29:50 -0000
@@ -166,6 +166,11 @@
 INCLUDES += $(SOUP_CFLAGS)
 endif
 
+if USE_NOTIFY
+rhythmbox_LDADD += $(NOTIFY_LIBS)
+INCLUDES += $(NOTIFY_CFLAGS)
+endif
+
 BUILT_SOURCES += $(tab_files)
 
 CLEANFILES += $(BUILT_SOURCES)
Index: shell/rb-tray-icon.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-tray-icon.c,v
retrieving revision 1.24
diff -u -u -r1.24 rb-tray-icon.c
--- shell/rb-tray-icon.c	30 Nov 2005 19:03:33 -0000	1.24
+++ shell/rb-tray-icon.c	2 Jan 2006 11:29:51 -0000
@@ -61,6 +61,8 @@
 						RBTrayIcon *icon);
 static void rb_tray_icon_show_window_changed_cb (GtkAction *action,
 						 RBTrayIcon *icon);
+static void rb_tray_icon_show_notifications_changed_cb (GtkAction *action,
+							RBTrayIcon *icon);
 static void rb_tray_icon_drop_cb (GtkWidget *widget,
 				  GdkDragContext *context,
 				  gint x,
@@ -73,15 +75,14 @@
 struct RBTrayIconPrivate
 {
 	GtkTooltips *tooltips;
-
-	EggNotificationBubble *bubble;
-
 	GtkUIManager *ui_manager;
 	GtkActionGroup *actiongroup;
 
 	GtkWidget *ebox;
 
 	RBRemoteProxy *proxy;
+
+	gboolean show_notifications;
 };
 
 #define RB_TRAY_ICON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_TRAY_ICON, RBTrayIconPrivate))
@@ -103,49 +104,22 @@
 {
 	{ "TrayShowWindow", NULL, N_("_Show Music Player"), NULL,
 	  N_("Choose music to play"),
-	  G_CALLBACK (rb_tray_icon_show_window_changed_cb) }
+	  G_CALLBACK (rb_tray_icon_show_window_changed_cb) },
+	{ "TrayShowNotifications", NULL, N_("Show _Notifications"), NULL,
+	  N_("Show notifications of song changes and other events"),
+	  G_CALLBACK (rb_tray_icon_show_notifications_changed_cb) }
 };
 static guint rb_tray_icon_n_toggle_entries = G_N_ELEMENTS (rb_tray_icon_toggle_entries);
 
 static const GtkTargetEntry target_uri [] = {{ "text/uri-list", 0, 0 }};
 
-static GObjectClass *parent_class = NULL;
-
-GType
-rb_tray_icon_get_type (void)
-{
-	static GType rb_tray_icon_type = 0;
-
-	if (rb_tray_icon_type == 0)
-	{
-		static const GTypeInfo our_info =
-		{
-			sizeof (RBTrayIconClass),
-			NULL,
-			NULL,
-			(GClassInitFunc) rb_tray_icon_class_init,
-			NULL,
-			NULL,
-			sizeof (RBTrayIcon),
-			0,
-			(GInstanceInitFunc) rb_tray_icon_init
-		};
-
-		rb_tray_icon_type = g_type_register_static (EGG_TYPE_TRAY_ICON,
-							    "RBTrayIcon",
-							    &our_info, 0);
-	}
-
-	return rb_tray_icon_type;
-}
+G_DEFINE_TYPE (RBTrayIcon, rb_tray_icon, EGG_TYPE_TRAY_ICON)
 
 static void
 rb_tray_icon_class_init (RBTrayIconClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	parent_class = g_type_class_peek_parent (klass);
-
 	object_class->finalize = rb_tray_icon_finalize;
 	object_class->constructor = rb_tray_icon_constructor;
 
@@ -218,13 +192,14 @@
 {
 	RBTrayIcon *tray;
 	RBTrayIconClass *klass;
-	GObjectClass *parent_class;  
 
 	klass = RB_TRAY_ICON_CLASS (g_type_class_peek (RB_TYPE_TRAY_ICON));
 
-	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
-	tray = RB_TRAY_ICON (parent_class->constructor (type, n_construct_properties,
-							construct_properties));
+	tray = RB_TRAY_ICON (G_OBJECT_CLASS (rb_tray_icon_parent_class)->constructor 
+				(type, n_construct_properties,
+				 construct_properties));
+
+	tray->priv->show_notifications = eel_gconf_get_boolean (CONF_UI_SHOW_NOTIFICATIONS);
 
 	tray->priv->actiongroup = gtk_action_group_new ("TrayActions");
 	gtk_action_group_set_translation_domain (tray->priv->actiongroup,
@@ -259,7 +234,7 @@
 	
 	gtk_object_destroy (GTK_OBJECT (tray->priv->tooltips));
 
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	G_OBJECT_CLASS (rb_tray_icon_parent_class)->finalize (object);
 }
 
 static void
@@ -271,6 +246,11 @@
 						      "TrayShowWindow");
 		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
 					      rb_remote_proxy_get_visibility (tray->priv->proxy));
+
+		action = gtk_action_group_get_action (tray->priv->actiongroup,
+						      "TrayShowNotifications");
+		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+					      tray->priv->show_notifications);
 	}
 }
 
@@ -495,6 +475,15 @@
 					gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
 }
 
+static void
+rb_tray_icon_show_notifications_changed_cb (GtkAction *action,
+					    RBTrayIcon *icon)
+{
+	rb_debug ("show notifications clicked for %p", icon);
+	icon->priv->show_notifications = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+	eel_gconf_set_boolean (CONF_UI_SHOW_NOTIFICATIONS, icon->priv->show_notifications);
+}
+
 void
 rb_tray_icon_get_geom (RBTrayIcon *icon, int *x, int *y, int *width, int *height)
 {
@@ -519,24 +508,6 @@
 			      tooltip, NULL);
 }
 
-static void
-rb_tray_icon_hide_notify_cb (EggNotificationBubble *bubble, gpointer data)
-{
-	gboolean visible;
-	RBTrayIcon *icon;
-
-	icon = RB_TRAY_ICON (data);
-
-	rb_debug ("hiding notification");
-
-	egg_notification_bubble_hide (bubble);
-	visible = rb_remote_proxy_get_visibility (icon->priv->proxy);	
-	if (!visible) {
-		rb_debug ("setting visible");
-		rb_remote_proxy_set_visibility (icon->priv->proxy, TRUE);
-	}
-}
-
 void
 rb_tray_icon_notify (RBTrayIcon *icon,
 		     guint timeout,
@@ -544,24 +515,21 @@
 		     GtkWidget *msgicon,
 		     const char *secondary)
 {
-	if (icon->priv->bubble) {
-		g_object_unref (icon->priv->bubble);
-		g_signal_handlers_disconnect_by_func (icon->priv->bubble,
-						      rb_tray_icon_hide_notify_cb,
-						      icon);
+	if (!egg_tray_icon_have_manager (EGG_TRAY_ICON (icon))) {
+		rb_debug ("not showing notification: %s", primary);
+		return;
 	}
+	if (!icon->priv->show_notifications) {
+		rb_debug ("ignoring notification: %s", primary);
+		return;
+	}
+	
 	rb_debug ("doing notify: %s", primary);
-	icon->priv->bubble = egg_tray_icon_notify (EGG_TRAY_ICON (icon), timeout, primary, msgicon, secondary);
-	g_object_ref (icon->priv->bubble);
-	g_signal_connect_object (icon->priv->bubble,
-				 "clicked",
-				 G_CALLBACK (rb_tray_icon_hide_notify_cb),
-				 icon, 0);
+	egg_tray_icon_notify (EGG_TRAY_ICON (icon), timeout, primary, msgicon, secondary);
 }
 
 void
 rb_tray_icon_cancel_notify (RBTrayIcon *icon)
 {
-	if (icon->priv->bubble)
-		egg_notification_bubble_hide (icon->priv->bubble);
+	egg_tray_icon_cancel_message (EGG_TRAY_ICON (icon), 1);
 }
Index: widgets/eggtrayicon.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/widgets/eggtrayicon.c,v
retrieving revision 1.4
diff -u -u -r1.4 eggtrayicon.c
--- widgets/eggtrayicon.c	2 Sep 2005 01:53:09 -0000	1.4
+++ widgets/eggtrayicon.c	2 Jan 2006 11:29:51 -0000
@@ -23,14 +23,20 @@
 #include <libintl.h>
 
 #include "eggtrayicon.h"
+#include "rb-stock-icons.h"
+#include "rb-file-helpers.h"
 
 #include <gdkconfig.h>
+#include <gtk/gtkimage.h>
 #if defined (GDK_WINDOWING_X11)
 #include <gdk/gdkx.h>
 #include <X11/Xatom.h>
 #elif defined (GDK_WINDOWING_WIN32)
 #include <gdk/gdkwin32.h>
 #endif
+#ifdef HAVE_NOTIFY
+#include <libnotify/notify.h>
+#endif
 
 #ifndef EGG_COMPILATION
 #ifndef _
@@ -53,6 +59,14 @@
   PROP_0,
   PROP_ORIENTATION
 };
+
+#ifdef HAVE_NOTIFY
+struct _Notify {
+  NotifyHints *hints;
+  NotifyIcon *icon;
+  NotifyHandle *handle;
+};
+#endif
          
 static GtkPlugClass *parent_class = NULL;
 
@@ -104,7 +118,12 @@
 {
   icon->stamp = 1;
   icon->orientation = GTK_ORIENTATION_HORIZONTAL;
-  
+#ifdef HAVE_NOTIFY
+  icon->notify = g_new0 (Notify, 1);
+  icon->notify->handle = NULL;
+  icon->notify->hints = NULL;
+  icon->notify->icon = NULL;
+#endif  
   gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
 }
 
@@ -265,6 +284,11 @@
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 #endif
+#ifdef HAVE_NOTIFY
+  if (EGG_TRAY_ICON (widget)->notify->handle)
+    notify_close (EGG_TRAY_ICON (widget)->notify->handle);
+  g_free (EGG_TRAY_ICON(widget)->notify);
+#endif
 }
 
 #ifdef GDK_WINDOWING_X11
@@ -448,6 +472,9 @@
   g_return_val_if_fail (timeout >= 0, 0);
   g_return_val_if_fail (message != NULL, 0);
 		     
+#ifdef HAVE_NOTIFY
+  egg_tray_icon_notify (icon, timeout, _("Notification"), NULL, message);
+#else
   if (!icon->bubble)
     {
       icon->bubble = egg_notification_bubble_new ();
@@ -457,6 +484,7 @@
   egg_notification_bubble_set (icon->bubble, _("Notification"),
 			       NULL, message);
   egg_notification_bubble_show (icon->bubble, timeout);
+#endif
 
   return 1;
 }
@@ -466,10 +494,18 @@
 			      guint        id)
 {
   g_return_if_fail (EGG_IS_TRAY_ICON (icon));
+#ifdef HAVE_NOTIFY
+  if (icon->notify->handle)
+  {
+    notify_close (icon->notify->handle);
+    icon->notify->handle = NULL;
+  }
+#else
   g_return_if_fail (id > 0);
   g_return_if_fail (icon->bubble != NULL);
 
   egg_notification_bubble_hide (icon->bubble);
+#endif
 }
 
 GtkOrientation
@@ -480,13 +516,88 @@
   return icon->orientation;
 }
 
-EggNotificationBubble *
+#ifndef HAVE_NOTIFY
+static void 
+egg_tray_icon_hide_notify_cb (EggNotificationBubble *bubble, gpointer data)
+{
+  egg_tray_icon_cancel_message (EGG_TRAY_ICON (data), 1);
+}
+#endif
+
+void
 egg_tray_icon_notify (EggTrayIcon *icon,
 		      guint timeout,
 		      const char *primary,
 		      GtkWidget *msgicon,
 		      const char *secondary)
 {
+#ifdef HAVE_NOTIFY
+  gint x, y;
+  GtkRequisition size;
+  NotifyIcon *icon_notify = NULL;
+  NotifyHints *hints;
+  char *fn;
+  
+  
+  if (!notify_is_initted ())
+    if (!notify_init ("rhythmbox"))
+      return;
+  
+  gdk_window_get_origin (GTK_WIDGET (icon)->window, &x, &y);
+  gtk_widget_size_request (GTK_WIDGET (icon), &size);
+  x += size.width / 2;
+  y += size.height;
+		  
+  hints = notify_hints_new ();
+  notify_hints_set_int (hints, "x", x);
+  notify_hints_set_int (hints, "y", y);
+
+  if (msgicon) 
+    {
+      GdkPixbuf *pix;
+      pix = gtk_image_get_pixbuf (GTK_IMAGE (msgicon));
+      if (pix) 
+        {
+	  char *tmp;
+	  GError *error = NULL;
+	  tmp = g_strdup_printf ("%s/.gnome2/rb-notify-icon.png", g_get_home_dir ());	
+	  if (gdk_pixbuf_save (pix, tmp, "png", &error, NULL))
+	    {
+	      icon_notify = notify_icon_new_from_uri (tmp);
+	    }
+	  else
+	    {
+	      icon_notify = NULL;	      
+	    }
+	  g_free (pix);
+	  g_free (tmp);
+	}	
+    } 
+  else
+    {	  
+      fn = g_strconcat (RB_STOCK_TRAY_ICON, ".png", NULL);	  
+      icon_notify = notify_icon_new_from_uri (rb_file (fn));
+      g_free (fn);
+    }
+
+  if (icon->notify->handle)
+    {
+      notify_close (icon->notify->handle);
+    }
+	  
+  icon->notify->hints = hints;
+  icon->notify->icon = icon_notify;
+  icon->notify->handle = notify_send_notification (NULL, "transfer",
+ 	 	  	  	            	   NOTIFY_URGENCY_LOW,
+			           	    	   primary,
+			    	   	    	   secondary,
+			    	   	           icon_notify,
+			    	   	           TRUE, timeout/1000,
+			    	   	           hints,
+			    	   	           NULL,
+			    	   	           0);  
+  return;
+#else
   gint x, y;
   gdk_window_get_origin (GTK_WIDGET (icon)->window,
 			 &x, &y);
@@ -494,10 +605,15 @@
     {
       icon->bubble = egg_notification_bubble_new ();
       egg_notification_bubble_attach (icon->bubble, GTK_WIDGET (icon));
+      g_signal_connect_object (icon->bubble,
+			       "clicked",
+			       G_CALLBACK (egg_tray_icon_hide_notify_cb),
+			       icon, 0);
     }
   
   egg_notification_bubble_set (icon->bubble, primary,
 			       msgicon, secondary);
   egg_notification_bubble_show (icon->bubble, timeout);
-  return icon->bubble;
+  return;
+#endif
 }
Index: widgets/eggtrayicon.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/widgets/eggtrayicon.h,v
retrieving revision 1.3
diff -u -u -r1.3 eggtrayicon.h
--- widgets/eggtrayicon.h	2 Sep 2005 01:53:09 -0000	1.3
+++ widgets/eggtrayicon.h	2 Jan 2006 11:29:51 -0000
@@ -21,11 +21,17 @@
 #ifndef __EGG_TRAY_ICON_H__
 #define __EGG_TRAY_ICON_H__
 
+#include <config.h>
+
 #include <gtk/gtkplug.h>
 #ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
 #endif
+#ifdef HAVE_NOTIFY
+#include <libnotify/notify.h>
+#else
 #include "eggnotificationbubble.h"
+#endif
 
 G_BEGIN_DECLS
 
@@ -38,6 +44,9 @@
 	
 typedef struct _EggTrayIcon	  EggTrayIcon;
 typedef struct _EggTrayIconClass  EggTrayIconClass;
+#ifdef HAVE_NOTIFY
+typedef struct _Notify		  Notify;
+#endif
 
 struct _EggTrayIcon
 {
@@ -53,7 +62,11 @@
   Window manager_window;
 #endif
   GtkOrientation orientation;
+#ifdef HAVE_NOTIFY
+  Notify *notify;
+#else
   EggNotificationBubble *bubble;
+#endif
 };
 
 struct _EggTrayIconClass
@@ -77,12 +90,12 @@
 
 gboolean     egg_tray_icon_have_manager   (EggTrayIcon *icon);
 
-EggNotificationBubble *egg_tray_icon_notify         (EggTrayIcon *icon,
-						     guint timeout,
-						     const char *primary,
-						     GtkWidget *msgicon,
-						     const char *secondary);
-					   
+void 	     egg_tray_icon_notify         (EggTrayIcon *icon,
+					   guint timeout,
+					   const char *primary,
+					   GtkWidget *msgicon,
+					   const char *secondary);
+
 
 GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon);
 					    
