Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.150
diff -u -r1.150 configure.ac
--- configure.ac	10 Aug 2005 13:35:53 -0000	1.150
+++ configure.ac	21 Aug 2005 17:26:41 -0000
@@ -52,6 +52,8 @@
 dnl function was added in that release.
 dnl enable_ipod = "no"
 
+HAL_REQUIRED=0.2.92
+
 AC_ARG_ENABLE(ipod,
 	      AC_HELP_STRING([--enable-ipod],
 			     [Enable iPod support in Rhythmbox]))
@@ -59,10 +61,11 @@
 if test x"$enable_ipod" = xyes; then
 	AC_DEFINE(WITH_IPOD_SUPPORT, 1, [Define if iPod support is enabled])
 	USE_HAL=""
-	PKG_CHECK_MODULES(HAL, hal >= $HAL_MIN_REQS hal < $HAL_MAX_REQS gnome-vfs-2.0 >= 2.7.4,
-		[ AC_DEFINE([HAVE_HAL], 1, [Use the HAL library]) ]
-		[ USE_HAL="dbus-glib-1 hal >= $HAL_MIN_REQS hal < $HAL_MAX_REQS" ], :)
+dnl	PKG_CHECK_MODULES(HAL, hal >= $HAL_REQUIRED gnome-vfs-2.0 >= 2.7.4,
+dnl		[ AC_DEFINE([HAVE_HAL], 1, [Use the HAL library]) ]
+dnl		[ USE_HAL="dbus-glib-1 hal >= $HAL_REQUIRED" ], :)
 fi
+AM_CONDITIONAL(WITH_IPOD_SUPPORT, test "x$enable_ipod" = "xyes")
 
 PKG_CHECK_MODULES(RHYTHMBOX,				\
 		  gtk+-2.0 >= $GTK_REQS			\
@@ -230,15 +233,11 @@
 fi
 
 dnl CD Audio support		  
-dnl AC_ARG_ENABLE(audiocd, AC_HELP_STRING([--enable-audiocd],
-dnl				[build with Audio CD support]),enable_audiocd=yes)
-dnl For now.
-enable_audiocd=no
-
-if test "x$enable_audiocd" = "xyes"; then
-  if test x"$enable_musicbrainz" != xyes; then
-	AC_MSG_ERROR([MusicBrainz is required for AudioCD support])
-  fi
+AC_ARG_WITH(audiocd, AC_HELP_STRING([--with-audiocd],
+			[build with Audio CD support]),with_audiocd=yes)
+
+if test "x$with_audiocd" = "xyes"; then
+  AC_DEFINE(WITH_AUDIOCD_SUPPORT, 1, [Define if audio cd support is enabled])
   AC_CHECK_HEADER(linux/cdrom.h,[enable_linux_cdrom=yes],)
   if test "x$enable_linux_cdrom" = "xyes"; then
     AC_MSG_CHECKING([whether linux/cdrom.h actually works])
@@ -262,15 +261,16 @@
 else
   AC_MSG_NOTICE([CD audio support disabled])
 fi
-if test "x$enable_audiocd" = "xyes"; then
-  AM_GST_ELEMENT_CHECK(cdparanoia,,missing_gst_elements="$missing_gst_elements cdparanoia")
+if test "x$with_audiocd" = "xyes"; then
+  if test x"$have_gstreamer" = xyes; then
+    AM_GST_ELEMENT_CHECK(cdparanoia,,missing_gst_elements="$missing_gst_elements cdparanoia")
+  fi
   AC_DEFINE(HAVE_AUDIOCD,,[Define if we have CD Audio support])
-  AC_SUBST(AUDIOCD_INCLUDES, ["#include \"monkey-media-audio-cd.h\""])
 else
   :
   AC_SUBST(AUDIOCD_INCLUDES, [])
 fi
-AM_CONDITIONAL(HAVE_AUDIOCD, test "x$enable_audiocd" = "xyes")
+AM_CONDITIONAL(WITH_AUDIOCD_SUPPORT, test "x$with_audiocd" = "xyes")
 AM_CONDITIONAL(HAVE_LINUX_CDROM, test "x$enable_linux_cdrom" = "xyes")
 
 dnl CD burner support
@@ -497,12 +497,11 @@
 	AC_MSG_NOTICE([   D-BUS control/activation disabled])
 fi
 
-dnl if test "x$enable_audiocd" != "xyes"; then
-dnl 	AC_MSG_NOTICE([   Audio CD support is disabled])
-dnl else
-dnl 	AC_MSG_NOTICE([** Audio CD support is enabled])
-dnl 	AC_MSG_WARN([Audio CD support is experimental!])
-dnl fi
+if test x"$with_audiocd" = xyes; then
+	AC_MSG_NOTICE([** Audio CD support enabled])
+else
+	AC_MSG_NOTICE([   Audio CD support disabled])
+fi
 if test x"$missing_gst_output_element" != x; then
 	AC_MSG_WARN([Neither osssink nor alsasink could be found on your system])
 fi	
Index: lib/rb-util.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-util.c,v
retrieving revision 1.14
diff -u -r1.14 rb-util.c
--- lib/rb-util.c	19 Jun 2005 18:29:44 -0000	1.14
+++ lib/rb-util.c	21 Aug 2005 17:26:48 -0000
@@ -38,6 +38,12 @@
 	return FALSE;
 }
 
+gpointer
+rb_null_function (gpointer dummy)
+{
+	return NULL;
+}
+
 int
 rb_gvalue_compare (GValue *a, GValue *b)
 {
Index: lib/rb-util.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-util.h,v
retrieving revision 1.11
diff -u -r1.11 rb-util.h
--- lib/rb-util.h	12 Jun 2005 17:16:48 -0000	1.11
+++ lib/rb-util.h	21 Aug 2005 17:26:48 -0000
@@ -32,6 +32,7 @@
 
 gboolean rb_true_function (gpointer dummy);
 gboolean rb_false_function (gpointer dummy);
+gpointer rb_null_function (gpointer dummy);
 
 gboolean rb_gvalue_compare (GValue *a, GValue *b);
 
Index: player/rb-player-gst.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/player/rb-player-gst.c,v
retrieving revision 1.40
diff -u -r1.40 rb-player-gst.c
--- player/rb-player-gst.c	21 Aug 2005 09:58:26 -0000	1.40
+++ player/rb-player-gst.c	21 Aug 2005 17:26:54 -0000
@@ -37,8 +37,35 @@
 #include "rb-debug.h"
 #include "rb-marshal.h"
 
+#define RB_TYPE_PLAYER_SUBTYPE 		(rb_player_subtype_get_type ())
+#define RB_PLAYER_SUBTYPE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_PLAYER_SUBTYPE, RBPlayerSubtype))
+#define RB_PLAYER_SUBTYPE_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_PLAYER_SUBTYPE, RBPlayerSubtypeClass))
+#define RB_IS_PLAYER_SUBTYPE(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_PLAYER_SUBTYPE))
+#define RB_IS_PLAYER_SUBTYPE_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_PLAYER_SUBTYPE))
+#define RB_PLAYER_SUBTYPE_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_PLAYER_SUBTYPE, RBPlayerSubtypeClass))
+
+GType rb_player_cdda_subtype_get_type (void);
+
 G_DEFINE_TYPE(RBPlayer, rb_player, G_TYPE_OBJECT)
 
+typedef struct
+{
+	GObject parent;
+} RBPlayerSubtype;
+
+typedef struct
+{
+	GObjectClass parent_class;
+
+	gboolean (*pre_open)		(RBPlayerSubtype *subtype, GstElement *playbin, const char *uri, GError **error);
+	void (*got_source)		(RBPlayerSubtype *subtype, GstElement *playbin, GstElement *source);
+	void (*pre_close)		(RBPlayerSubtype *subtype, GstElement *playbin, GError **error);
+} RBPlayerSubtypeClass;
+
+GType rb_player_subtype_get_type (void);
+	
+G_DEFINE_TYPE(RBPlayerSubtype, rb_player_subtype, G_TYPE_OBJECT)
+	
 static void rb_player_finalize (GObject *object);
 
 struct RBPlayerPrivate
@@ -57,6 +84,8 @@
 	float cur_volume;
 
 	guint tick_timeout_id;
+
+	RBPlayerSubtype *subtype;
 };
 
 typedef enum
@@ -357,6 +386,20 @@
 }
 
 static void
+got_source_cb (GObject *object, GParamSpec *pspec, RBPlayer *player)
+{
+	GstElement *playbin = GST_ELEMENT (object);
+	GstElement *source;
+
+	gst_element_get (playbin, "source", &source, NULL);
+	rb_debug ("got source %p", source);
+	if (source && player->priv->subtype) {
+		RBPlayerSubtypeClass *subtype_class = RB_PLAYER_SUBTYPE_GET_CLASS (player->priv->subtype);
+		(*subtype_class->got_source) (player->priv->subtype, playbin, source);
+	}
+}
+
+static void
 rb_player_construct (RBPlayer *mp, GError **error)
 {
 	char *element_name = NULL;
@@ -372,6 +415,10 @@
 				 "found_tag",
 				 G_CALLBACK (found_tag_cb),
 				 mp, 0);
+	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
+				 "notify::source",
+				 G_CALLBACK (got_source_cb),
+				 mp, 0);
 
 	mp->priv->buffering_signal_id =
 		g_signal_connect_object (G_OBJECT (mp->priv->playbin),
@@ -483,6 +530,7 @@
 void
 rb_player_open (RBPlayer *mp,
 		const char *uri,
+		GObject *subtype,
 		GError **error)
 {
 	g_return_if_fail (RB_IS_PLAYER (mp));
@@ -502,6 +550,20 @@
 		mp->priv->playing = FALSE;
 		return;
 	}
+
+	if (subtype) {
+		RBPlayerSubtypeClass *subtype_class;
+
+		g_return_if_fail (RB_IS_PLAYER_SUBTYPE (subtype));
+
+		g_object_ref (subtype);
+		mp->priv->subtype = RB_PLAYER_SUBTYPE (subtype);
+
+		subtype_class = RB_PLAYER_SUBTYPE_GET_CLASS (mp->priv->subtype);
+		if ((*subtype_class->pre_open) (mp->priv->subtype, mp->priv->playbin, uri, error) == FALSE)
+			return;
+	}
+	
 	g_object_set (G_OBJECT (mp->priv->playbin), "uri", uri, NULL);	
 	mp->priv->uri = g_strdup (uri);
 
@@ -523,6 +585,14 @@
 	if (mp->priv->playbin == NULL)
 		return;
 
+	if (mp->priv->subtype) {
+		RBPlayerSubtypeClass *subtype_class = RB_PLAYER_SUBTYPE_GET_CLASS (mp->priv->subtype);
+		(*subtype_class->pre_close) (mp->priv->subtype, mp->priv->playbin, error);
+
+		g_object_unref (mp->priv->subtype);
+		mp->priv->subtype = NULL;
+	}
+
 	if (gst_element_set_state (mp->priv->playbin,
 				   GST_STATE_READY) != GST_STATE_SUCCESS) {
 		g_set_error (error,
@@ -688,3 +758,98 @@
 	} else
 		return -1;
 }
+
+/**** subtype handling ****/
+	
+static gboolean default_subtype_pre_open (RBPlayerSubtype *subtype, GstElement *playbin, const char *uri, GError **error);
+static void default_subtype_got_source (RBPlayerSubtype *subtype, GstElement *playbin, GstElement *source);
+static void default_subtype_pre_close (RBPlayerSubtype *subtype, GstElement *playbin, GError **error);
+
+static void
+rb_player_subtype_class_init (RBPlayerSubtypeClass *klass)
+{
+	klass->pre_open = default_subtype_pre_open;
+	klass->got_source = default_subtype_got_source;
+	klass->pre_close = default_subtype_pre_close;
+}
+
+static void
+rb_player_subtype_init (RBPlayerSubtype *subtype)
+{
+	/* nothing */
+}
+
+static gboolean
+default_subtype_pre_open (RBPlayerSubtype *subtype, GstElement *playbin, const char *uri, GError **error)
+{
+	return TRUE;
+}
+
+static void
+default_subtype_got_source (RBPlayerSubtype *subtype, GstElement *playbin, GstElement *source)
+{
+	/* nothing */
+}
+
+static void
+default_subtype_pre_close (RBPlayerSubtype *subtype, GstElement *playbin, GError **error)
+{
+	/* nothing */
+}
+
+/* CD audio subtype implementation */
+
+#define RB_TYPE_PLAYER_CDDA_SUBTYPE 	(rb_player_cdda_subtype_get_type ())
+#define RB_PLAYER_CDDA_SUBTYPE(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_PLAYER_CDDA_SUBTYPE, RBPlayerCDDASubtype))
+
+typedef struct
+{
+	RBPlayerSubtype parent;
+	char *cdda_device;
+} RBPlayerCDDASubtype;
+	
+typedef struct
+{
+	RBPlayerSubtypeClass parent_class;
+} RBPlayerCDDASubtypeClass;
+
+G_DEFINE_TYPE(RBPlayerCDDASubtype, rb_player_cdda_subtype, RB_TYPE_PLAYER_SUBTYPE)
+
+static void rb_player_cdda_subtype_got_source (RBPlayerSubtype *subtype, 
+					       GstElement *playbin, 
+					       GstElement *source);
+
+static void
+rb_player_cdda_subtype_class_init (RBPlayerCDDASubtypeClass *klass)
+{
+	RBPlayerSubtypeClass *subtype_class = RB_PLAYER_SUBTYPE_CLASS (klass);
+	subtype_class->got_source = rb_player_cdda_subtype_got_source;
+}
+
+static void
+rb_player_cdda_subtype_init (RBPlayerCDDASubtype *subtype)
+{
+	/* nothing */
+}
+
+static void 
+rb_player_cdda_subtype_got_source (RBPlayerSubtype *subtype, 
+				   GstElement *playbin, 
+				   GstElement *source)
+{
+	RBPlayerCDDASubtype *st = RB_PLAYER_CDDA_SUBTYPE (subtype);
+
+	if (source && st->cdda_device) {
+		rb_debug ("setting device %s on source element", st->cdda_device);
+		gst_element_set (source, "device", st->cdda_device, NULL);
+	}
+}
+
+GObject *
+rb_player_cdda_subtype_new (const char *device)
+{
+	RBPlayerCDDASubtype *subtype = g_object_new (RB_TYPE_PLAYER_CDDA_SUBTYPE, NULL);
+	subtype->cdda_device = g_strdup (device);
+	return G_OBJECT (subtype);
+}
+
Index: player/rb-player.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/player/rb-player.h,v
retrieving revision 1.9
diff -u -r1.9 rb-player.h
--- player/rb-player.h	29 Jul 2005 14:53:09 -0000	1.9
+++ player/rb-player.h	21 Aug 2005 17:26:54 -0000
@@ -24,7 +24,7 @@
 #define __RB_PLAYER_H
 
 #include <glib-object.h>
-#include "rb-metadata.h"
+#include "metadata/rb-metadata.h"
 
 G_BEGIN_DECLS
 
@@ -80,6 +80,7 @@
 
 void		rb_player_open       (RBPlayer *mp,
 				      const char *uri,
+				      GObject *subtype,
 				      GError **error);
 
 gboolean	rb_player_opened     (RBPlayer *mp);
@@ -104,6 +105,8 @@
 void		rb_player_set_time   (RBPlayer *mp,
 				      long time);
 long		rb_player_get_time   (RBPlayer *mp);
+
+GObject *	rb_player_cdda_subtype_new (const char *device);
 
 G_END_DECLS
 
Index: shell/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/Makefile.am,v
retrieving revision 1.48
diff -u -r1.48 Makefile.am
--- shell/Makefile.am	10 Aug 2005 13:35:54 -0000	1.48
+++ shell/Makefile.am	21 Aug 2005 17:27:53 -0000
@@ -36,6 +36,8 @@
 	rb-shell-clipboard.h				\
 	rb-playlist-manager.c				\
 	rb-playlist-manager.h				\
+	rb-device-manager.c				\
+	rb-device-manager.h				\
 	rb-history.c					\
 	rb-history.h					\
 	rb-play-order.c					\
Index: shell/rb-shell-player.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell-player.c,v
retrieving revision 1.161
diff -u -r1.161 rb-shell-player.c
--- shell/rb-shell-player.c	17 Aug 2005 16:32:53 -0000	1.161
+++ shell/rb-shell-player.c	21 Aug 2005 17:28:29 -0000
@@ -924,11 +924,13 @@
 					RBShellPlayer *player)
 {
 	GError *error = NULL;
+	GObject *player_subtype;
 
 	if (rb_player_playing (player->priv->mmplayer))
 		return;
 
-	rb_player_open (player->priv->mmplayer, uri, &error);
+	g_object_get (player->priv->source, "player-subtype", &player_subtype, NULL);
+	rb_player_open (player->priv->mmplayer, uri, player_subtype, &error);
 	if (error != NULL) {
 		if (player->priv->playlist_parse_error != NULL) {
 			g_error_free (player->priv->playlist_parse_error);
@@ -983,7 +985,9 @@
 	g_object_unref (playlist);
 	if (!playlist_parsed) {
 		/* We get here if we failed to parse as a playlist */
-		rb_player_open (player->priv->mmplayer, location, error);
+		GObject *player_subtype;
+		g_object_get (player->priv->source, "player-subtype", &player_subtype, NULL);
+		rb_player_open (player->priv->mmplayer, location, player_subtype, error);
 	} else if (playlist_result == TOTEM_PL_PARSER_RESULT_ERROR
 		   && error
 		   && player->priv->playlist_parse_error) {
Index: shell/rb-shell.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell.c,v
retrieving revision 1.311
diff -u -r1.311 rb-shell.c
--- shell/rb-shell.c	15 Aug 2005 13:18:02 -0000	1.311
+++ shell/rb-shell.c	21 Aug 2005 17:28:48 -0000
@@ -54,6 +54,7 @@
 #include "rb-file-helpers.h"
 #include "rb-source.h"
 #include "rb-playlist-manager.h"
+#include "rb-device-manager.h"
 #include "rb-preferences.h"
 #include "rb-druid.h"
 #include "rb-shell-clipboard.h"
@@ -64,15 +65,8 @@
 #include "rb-statusbar.h"
 #include "rb-shell-preferences.h"
 #include "rb-library-source.h"
-#ifdef WITH_IPOD_SUPPORT
-#include "rb-ipod-source.h"
-#endif /* WITH_IPOD_SUPPORT */
 #include "rb-load-failure-dialog.h"
 #include "rb-new-station-dialog.h"
-#include "rb-iradio-source.h"
-#ifdef HAVE_AUDIOCD
-#include "rb-audiocd-source.h"
-#endif
 #include "rb-shell-preferences.h"
 #include "rb-playlist-source.h"
 #include "eel-gconf-extensions.h"
@@ -137,6 +131,7 @@
 static void rb_shell_playlist_created_cb (RBPlaylistManager *mgr, RBSource *source, RBShell *shell);
 static void rb_shell_playlist_load_start_cb (RBPlaylistManager *mgr, RBShell *shell);
 static void rb_shell_playlist_load_finish_cb (RBPlaylistManager *mgr, RBShell *shell);
+static void rb_shell_device_added_cb (RBDeviceManager *mgr, RBSource *source, RBShell *shell);
 static void rb_shell_source_deleted_cb (RBSource *source, RBShell *shell);
 static void rb_shell_set_window_title (RBShell *shell, const char *window_title);
 static void rb_shell_set_duration (RBShell *shell, const char *duration);
@@ -197,11 +192,6 @@
 					guint cnxn_id,
 					GConfEntry *entry,
 					RBShell *shell);
-#ifdef HAVE_AUDIOCD
-static void audiocd_changed_cb (MonkeyMediaAudioCD *cd,
-				gboolean available,
-				gpointer data);
-#endif
 static void sourcelist_drag_received_cb (RBSourceList *sourcelist,
 					 RBSource *source,
 					 GtkSelectionData *data,
@@ -254,9 +244,6 @@
 static SourceCreateFunc known_sources[] = {
 	rb_library_source_new,
 	rb_iradio_source_new,
-#ifdef WITH_IPOD_SUPPORT
-	rb_ipod_source_new,	
-#endif /* WITH_IPOD_SUPPORT */
 	NULL,
 };
 
@@ -339,15 +326,12 @@
 	RBSourceHeader *source_header;
 	RBStatusbar *statusbar;
 	RBPlaylistManager *playlist_manager;
+	RBDeviceManager *device_manager;
 
 	GtkWidget *load_error_dialog;
 	GList *supported_media_extensions;
 	gboolean show_db_errors;
 
-#ifdef HAVE_AUDIOCD
- 	MonkeyMediaAudioCD *cd;
-#endif
-
 	RBSource *selected_source;
 
 	GtkWidget *prefs;
@@ -356,6 +340,11 @@
 
 	char *cached_title;
 	char *cached_duration;
+
+	guint selected_source_notify_id;
+	guint sourcelist_visibility_notify_id;
+	guint smalldisplay_notify_id;
+	guint paned_changed_notify_id;
 };
 
 static GtkActionEntry rb_shell_actions [] =
@@ -768,10 +757,16 @@
 	g_hash_table_destroy (shell->priv->sources_hash);
 
 	g_object_unref (G_OBJECT (shell->priv->playlist_manager));
+	g_object_unref (G_OBJECT (shell->priv->device_manager));
 
 	g_object_unref (G_OBJECT (shell->priv->clipboard_shell));
 
 	gtk_widget_destroy (shell->priv->window);
+	
+	eel_gconf_notification_remove (shell->priv->selected_source_notify_id);
+	eel_gconf_notification_remove (shell->priv->sourcelist_visibility_notify_id);
+	eel_gconf_notification_remove (shell->priv->smalldisplay_notify_id);
+	eel_gconf_notification_remove (shell->priv->paned_changed_notify_id);
 
 	rb_debug ("shutting down DB");
 	rhythmdb_shutdown (shell->priv->db);
@@ -960,18 +955,22 @@
 
 	rb_debug ("shell: adding gconf notification");
 	/* sync state */
-	eel_gconf_notification_add (CONF_STATE_SELECTED_SOURCE,
-				    (GConfClientNotifyFunc) selected_source_changed_cb,
-				    shell);
-	eel_gconf_notification_add (CONF_UI_SOURCELIST_HIDDEN,
-				    (GConfClientNotifyFunc) sourcelist_visibility_changed_cb,
-				    shell);
-	eel_gconf_notification_add (CONF_UI_SMALL_DISPLAY,
-				    (GConfClientNotifyFunc) smalldisplay_changed_cb,
-				    shell);
-	eel_gconf_notification_add (CONF_STATE_PANED_POSITION,
-				    (GConfClientNotifyFunc) paned_changed_cb,
-				    shell);
+	shell->priv->selected_source_notify_id =
+		eel_gconf_notification_add (CONF_STATE_SELECTED_SOURCE,
+			(GConfClientNotifyFunc) selected_source_changed_cb,
+			shell);
+	shell->priv->sourcelist_visibility_notify_id =
+		eel_gconf_notification_add (CONF_UI_SOURCELIST_HIDDEN,
+			(GConfClientNotifyFunc) sourcelist_visibility_changed_cb,
+		shell);
+	shell->priv->smalldisplay_notify_id =
+		eel_gconf_notification_add (CONF_UI_SMALL_DISPLAY,
+			(GConfClientNotifyFunc) smalldisplay_changed_cb,
+			shell);
+	shell->priv->paned_changed_notify_id =
+		eel_gconf_notification_add (CONF_STATE_PANED_POSITION,
+			(GConfClientNotifyFunc) paned_changed_cb,
+			shell);
 
 	rb_debug ("shell: syncing with gconf");
 	rb_shell_sync_sourcelist_visibility (shell);
@@ -1019,6 +1018,14 @@
 	g_signal_connect_object (G_OBJECT (shell->priv->playlist_manager), "load_finish",
 				 G_CALLBACK (rb_shell_playlist_load_finish_cb), shell, 0);
 
+	/* Initialize device manager */
+	rb_debug ("shell: creating device manager");
+	shell->priv->device_manager = rb_device_manager_new (shell,
+								 RB_SOURCELIST (shell->priv->sourcelist));
+
+	g_signal_connect_object (G_OBJECT (shell->priv->device_manager), "device_added",
+				 G_CALLBACK (rb_shell_device_added_cb), shell, 0);
+
 	rb_debug ("shell: loading ui");
 	gtk_ui_manager_insert_action_group (shell->priv->ui_manager,
 					    shell->priv->actiongroup, 0);
@@ -1053,27 +1060,6 @@
 	rb_shell_sync_window_state (shell);
 
 	rb_shell_select_source_internal (shell, library_source);
-
-#ifdef HAVE_AUDIOCD
-        if (rb_audiocd_is_any_device_available () == TRUE) {
-		rb_debug ("AudioCD device is available");
-		shell->priv->cd = monkey_media_audio_cd_new (NULL);
-
-		if (monkey_media_audio_cd_available (shell->priv->cd, NULL)) {
-			rb_debug ("Calling audiocd_changed_cb");
-			audiocd_changed_cb (shell->priv->cd,
-					    TRUE,
-					    shell);
-		}
-		else
-			rb_debug("CD is not available");
-
-		g_signal_connect_object (G_OBJECT (shell->priv->cd), "cd_changed",
-					 G_CALLBACK (audiocd_changed_cb), shell, 0);
-        }
-	else
-		rb_debug ("No AudioCD device is available!");
-#endif
 	
 	/* GO GO GO! */
 	if (rhythmdb_exists) {
@@ -1329,9 +1315,17 @@
 }
 
 static void
+rb_shell_device_added_cb (RBDeviceManager *mgr, RBSource *source, RBShell *shell)
+{
+	rb_shell_append_source (shell, source);
+}
+
+static void
 rb_shell_source_deleted_cb (RBSource *source,
 			    RBShell *shell)
 {
+	rb_debug ("removing source %p", source);
+
 	if (source == rb_shell_player_get_playing_source (shell->priv->player_shell)) {
 		rb_shell_player_set_playing_source (shell->priv->player_shell, NULL);
 	}
@@ -1782,6 +1776,7 @@
 	rb_debug ("load complete");
 
 	rb_playlist_manager_load_playlists (shell->priv->playlist_manager);
+	rb_device_manager_load_devices (shell->priv->device_manager);
 	rb_shell_sync_selected_source (shell);
 	shell->priv->load_complete = TRUE;
 
Index: sources/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/Makefile.am,v
retrieving revision 1.18
diff -u -r1.18 Makefile.am
--- sources/Makefile.am	12 Jun 2005 13:57:38 -0000	1.18
+++ sources/Makefile.am	21 Aug 2005 17:28:53 -0000
@@ -13,8 +13,10 @@
 	rb-library-source.h		\
 	rb-iradio-source.c		\
 	rb-iradio-source.h		\
+	rb-removable-media-source.c	\
+	rb-removable-media-source.h	\
 	rb-playlist-source.c            \
-	rb-playlist-source.h		
+	rb-playlist-source.h
 
 INCLUDES =						\
         -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
@@ -24,7 +26,7 @@
 	-I$(top_builddir)/lib 				\
 	-I$(top_srcdir)/corba 				\
 	-I$(top_builddir)/corba				\
-	-I$(top_srcdir)/rhythmdb			\
+	-I$(top_srcdir)/rhythmdb				\
 	-I$(top_srcdir)/widgets 			\
 	-I$(top_srcdir)/library 			\
 	-I$(top_srcdir)/player	 			\
@@ -39,17 +41,23 @@
 libsources_la_LDFLAGS = -export-dynamic
 libsourcesimpl_la_LDFLAGS = -export-dynamic
 
-if USE_IPOD
-libsourcesimpl_la_SOURCES +=         \
-	rb-ipod-source.c             \
-	rb-ipod-source.h	     \
-	itunesdb.c		     \
+if WITH_IPOD_SUPPORT
+libsourcesimpl_la_SOURCES +=		\
+	rb-ipod-source.c		\
+	rb-ipod-source.h		\
+	itunesdb.c			\
 	itunesdb.h
 endif
 
+if WITH_AUDIOCD_SUPPORT
+libsourcesimpl_la_SOURCES +=		\
+	rb-audiocd-source.c		\
+	rb-audiocd-source.h
+endif
+
 if USE_CD_BURNER
 libsourcesimpl_la_SOURCES += 		\
-	rb-playlist-source-recorder.c   \
+	rb-playlist-source-recorder.c	\
 	rb-playlist-source-recorder.h	
 
 INCLUDES += $(LIBNAUTILUS_BURN_CFLAGS)
Index: sources/rb-ipod-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.c,v
retrieving revision 1.14
diff -u -r1.14 rb-ipod-source.c
--- sources/rb-ipod-source.c	11 Aug 2005 23:27:18 -0000	1.14
+++ sources/rb-ipod-source.c	21 Aug 2005 17:28:55 -0000
@@ -38,36 +38,24 @@
 #include "rb-stock-icons.h"
 #include "rb-debug.h"
 
-static void rb_ipod_source_init (RBiPodSource *source);
-static void rb_ipod_source_finalize (GObject *object);
+static void rb_ipod_source_dispose (GObject *object);
 static void rb_ipod_source_class_init (RBiPodSourceClass *klass);
-static GObject *rb_ipod_source_constructor (GType type, 
-					    guint n_construct_properties,
-					    GObjectConstructParam *construct_properties);
-
-static gboolean rb_ipod_is_volume_ipod (GnomeVFSVolume *volume);
-static void rb_ipod_volume_mounted_cb (GnomeVFSVolumeMonitor *monitor, 
-				       GnomeVFSVolume *volume, gpointer data);
-static void rb_ipod_volume_unmounted_cb (GnomeVFSVolumeMonitor *monitor,
-					 GnomeVFSVolume *volume, 
-					 gpointer data);
-static void rb_ipod_plugged   (RBiPodSource *source, 
-			       const gchar *mount_path,
-			       GnomeVFSVolume *volume);
-static void rb_ipod_unplugged (RBiPodSource *source);
+
+static void impl_ipod_plugged (RBRemovableMediaSource *source);
+static void impl_ipod_unplugged (RBRemovableMediaSource *source);
 static gchar *rb_ipod_get_mount_path (GnomeVFSVolume *volume);
 
-static void rb_ipod_monitor (RBiPodSource *source, gboolean enable);
 #ifdef HAVE_HAL
 static gboolean hal_udi_is_ipod (const char *udi);
 #endif
 
-struct RBiPodSourcePrivate
+typedef struct
 {
-	GnomeVFSVolume *ipod_volume;
 	iPodParser *parser;
 	gchar *ipod_mount_path;
-};
+} RBiPodSourcePrivate;
+
+#define IPOD_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_IPOD_SOURCE, RBiPodSourcePrivate))
 
 static GObjectClass *parent_class = NULL;
 
@@ -89,7 +77,7 @@
 			NULL,
 			sizeof (RBiPodSource),
 			0,
-			(GInstanceInitFunc) rb_ipod_source_init
+			NULL
 		};
 
 		rb_ipod_source_type = g_type_register_static (RB_TYPE_LIBRARY_SOURCE,
@@ -105,103 +93,32 @@
 rb_ipod_source_class_init (RBiPodSourceClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBRemovableMediaSourceClass *removable_media_source_class = RB_REMOVABLE_MEDIA_SOURCE_CLASS (klass);
 
 	parent_class = g_type_class_peek_parent (klass);
 
-	object_class->finalize = rb_ipod_source_finalize;
-	object_class->constructor = rb_ipod_source_constructor;
-}
+	object_class->dispose = rb_ipod_source_dispose;
 
+	removable_media_source_class->impl_media_plugged = impl_ipod_plugged;
+	removable_media_source_class->impl_media_unplugged = impl_ipod_unplugged;
 
-static GObject *
-rb_ipod_source_constructor (GType type, guint n_construct_properties,
-			    GObjectConstructParam *construct_properties)
-{
-	GObject *object;
-	RBiPodSourceClass *klass;
-	GObjectClass *parent_class;  
-
-	/* Invoke parent constructor. */
-	klass = RB_IPOD_SOURCE_CLASS (g_type_class_peek (RB_TYPE_IPOD_SOURCE));
-	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
-	object = parent_class->constructor (type,
-					    n_construct_properties,
-					    construct_properties);
-  
-	/* This needs to be done once the GObject properties are set
-	 * since rb_ipod_monitor expect the properties on the
-	 * RBiPodSource to be set (especially the "db" property)
-	 */
-	rb_ipod_monitor (RB_IPOD_SOURCE (object), TRUE);
-	return object;
-}
-
-
-static void
-rb_ipod_monitor (RBiPodSource *source, gboolean enable)
-{
-	GnomeVFSVolumeMonitor *monitor;
-	
-	monitor = gnome_vfs_get_volume_monitor ();
-
-	if (enable) {
-		GList *volumes;
-		GList *it;
-
-		/* Look for already plugged iPod */
-		volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
-		for (it = volumes; it != NULL; it = it->next) {
-			if (rb_ipod_is_volume_ipod (GNOME_VFS_VOLUME (it->data))) {
-				rb_ipod_plugged (source, NULL,
-						 GNOME_VFS_VOLUME (it->data));
-			}
-		}
-		
-		/* Monitor new (un)mounted file systems to look for an iPod */
-		g_signal_connect (G_OBJECT (monitor), "volume-mounted", 
-				  G_CALLBACK (rb_ipod_volume_mounted_cb), 
-				  source);
-		g_signal_connect (G_OBJECT (monitor), "volume-unmounted", 
-				  G_CALLBACK (rb_ipod_volume_unmounted_cb), 
-				  source);
-	} else {
-		g_signal_handlers_disconnect_by_func (G_OBJECT (monitor), 
-						      G_CALLBACK (rb_ipod_volume_mounted_cb), 
-						      source);
-		g_signal_handlers_disconnect_by_func (G_OBJECT (monitor), 
-						      G_CALLBACK (rb_ipod_volume_unmounted_cb), 
-						      source);
-
-	}
-}
-
-static void
-rb_ipod_source_init (RBiPodSource *source)
-{
-	source->priv = g_new0 (RBiPodSourcePrivate, 1);
+	g_type_class_add_private (klass, sizeof (RBiPodSourcePrivate));
 }
 
 
 static void 
-rb_ipod_source_finalize (GObject *object)
+rb_ipod_source_dispose (GObject *object)
 {
-	RBiPodSource *source = RB_IPOD_SOURCE (object);
-
-	rb_ipod_monitor (source, FALSE);
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (object);
 
-	if (source->priv->parser != NULL) {
-		ipod_parser_destroy (source->priv->parser);
-		source->priv->parser = NULL;
+	if (priv->parser != NULL) {
+		ipod_parser_destroy (priv->parser);
+		priv->parser = NULL;
 	}
 
-	if (source->priv->ipod_volume != NULL) {
-		gnome_vfs_volume_unref (source->priv->ipod_volume);
-		source->priv->ipod_volume = NULL;
-	}
-	g_free (source->priv->ipod_mount_path);
-	g_free (source->priv);
+	g_free (priv->ipod_mount_path);
 
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static GdkPixbuf *
@@ -229,21 +146,25 @@
 	return icon;
 }
 
-RBSource *
-rb_ipod_source_new (RBShell *shell)
+RBRemovableMediaSource *
+rb_ipod_source_new (RBShell *shell, GnomeVFSVolume *volume)
 {
-	RBSource *source;
+	char *display_name = gnome_vfs_volume_get_display_name (volume);
+	char *internal_name = g_strdup_printf ("<ipod:%s>", gnome_vfs_volume_get_device_path (volume));
+	RBRemovableMediaSource *source;
 
-	source = RB_SOURCE (g_object_new (RB_TYPE_IPOD_SOURCE,
-					  "name", _("iPod"),
+	source = RB_REMOVABLE_MEDIA_SOURCE (g_object_new (RB_TYPE_IPOD_SOURCE,
+					  "name", display_name,
 					  "entry-type", RHYTHMDB_ENTRY_TYPE_IPOD,
-					  "internal-name", "<ipod>",
+					  "internal-name", internal_name,
 					  "icon", rb_ipod_get_icon (),
 					  "shell", shell,
 					  "visibility", FALSE,
 					  NULL));
 
-	rb_shell_register_entry_type_for_source (shell, source, 
+	g_free (internal_name);
+
+	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), 
 						 RHYTHMDB_ENTRY_TYPE_IPOD);
 
 	return source;
@@ -277,13 +198,14 @@
 	RBShell *shell;
 	RhythmDB *db;
 	int i;
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 
 	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 	g_object_get (G_OBJECT (shell), "db", &db, NULL);
 	g_object_unref (G_OBJECT (shell));
 
 	g_assert (db != NULL);
-	g_assert (source->priv->parser != NULL);
+	g_assert (priv->parser != NULL);
 
 	for (i = 0; i < MAX_SONGS_LOADED_AT_ONCE; i++) {
 		gchar *pc_path;
@@ -291,18 +213,18 @@
 		iPodItem *item;
 		iPodSong *song;
 		
-		item = ipod_get_next_item (source->priv->parser);
+		item = ipod_get_next_item (priv->parser);
 		if ((item == NULL) || (item->type != IPOD_ITEM_SONG)) {
 			ipod_item_destroy (item);
-			ipod_parser_destroy (source->priv->parser);
-			source->priv->parser = NULL;
+			ipod_parser_destroy (priv->parser);
+			priv->parser = NULL;
 			g_object_unref (G_OBJECT (db));
 			return FALSE;
 		}
 		song = (iPodSong *)item->data;
 				
 		/* Set URI */
-		mount_path = source->priv->ipod_mount_path;
+		mount_path = priv->ipod_mount_path;
 		pc_path = itunesdb_get_track_name_on_ipod (mount_path, song);
 		entry = rhythmdb_entry_new (RHYTHMDB (db), 
 					    RHYTHMDB_ENTRY_TYPE_IPOD,
@@ -394,8 +316,10 @@
 static int
 rb_ipod_load_songs (RBiPodSource *source)
 {
-	source->priv->parser = ipod_parser_new (source->priv->ipod_mount_path);
-	if (source->priv->parser == NULL) {
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+
+	priv->parser = ipod_parser_new (priv->ipod_mount_path);
+	if (priv->parser == NULL) {
 		return -1;
 	}
 	g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, 
@@ -418,48 +342,24 @@
 
 
 static void
-rb_ipod_plugged (RBiPodSource *source, 
-		 const gchar *mount_path,
-		 GnomeVFSVolume *volume)
+impl_ipod_plugged (RBRemovableMediaSource *source)
 {
-	int res;
+	RBiPodSource *ipod_source = RB_IPOD_SOURCE (source);
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (ipod_source);
+	GnomeVFSVolume *volume;
 
-	rb_debug ("iPod plugged\n");
-
-	if (source->priv->ipod_mount_path != NULL) {
-		/* Only one iPod can be recognized at once */
-		return;
-	}
+	g_object_get (G_OBJECT (source), "volume", &volume, NULL);
+	priv->ipod_mount_path = rb_ipod_get_mount_path (volume);
 	
-	source->priv->ipod_mount_path = rb_ipod_get_mount_path (volume);
-	res = rb_ipod_load_songs (source);
-	if (res == 0) {
-		source->priv->ipod_volume = volume;
-		gnome_vfs_volume_ref (volume);
-		g_object_set (G_OBJECT (source), "visibility", TRUE, NULL);
-	} else {
-		g_free (source->priv->ipod_mount_path);
-		source->priv->ipod_mount_path = NULL;
-	}
-	/* FIXME: should we suspend this monitor until the iPod 
-	 * database has been read and fed to rhythmbox?
-	 */
+	rb_ipod_load_songs (ipod_source);
 }
 
 static void
-rb_ipod_unplugged (RBiPodSource *source)
+impl_ipod_unplugged (RBRemovableMediaSource *source)
 {
-	rb_debug ("iPod unplugged\n");
-	
-	g_assert (source->priv->ipod_mount_path != NULL);
+	RBiPodSource *ipod_source = RB_IPOD_SOURCE (source);
 
-	gnome_vfs_volume_unref (source->priv->ipod_volume);
-	source->priv->ipod_volume = NULL;
-	
-	g_free (source->priv->ipod_mount_path);
-	source->priv->ipod_mount_path = NULL;
-	g_object_set (G_OBJECT (source), "visibility", FALSE, NULL);
-	rb_ipod_unload_songs (source);
+	rb_ipod_unload_songs (ipod_source);
 }
 
 RhythmDBEntryType rhythmdb_entry_ipod_get_type (void) 
@@ -511,7 +411,7 @@
 	return result;
 }
 
-static gboolean
+gboolean
 rb_ipod_is_volume_ipod (GnomeVFSVolume *volume)
 {
 	gchar *itunesdb_path;
@@ -541,37 +441,6 @@
 	}
 
 	return result;
-}
-
-static void 
-rb_ipod_volume_mounted_cb (GnomeVFSVolumeMonitor *monitor,
-			   GnomeVFSVolume *volume, 
-			   gpointer data)
-{
-	RBiPodSource *source = RB_IPOD_SOURCE (data);
-
-	if (source->priv->ipod_volume != NULL) {
-		rb_debug ("iPod plugged while another one is already present, ignoring the new one");
-		return;
-	}
-
-	if (rb_ipod_is_volume_ipod (volume)) {
-		rb_ipod_plugged (source, NULL, volume);
-	}
-}
-
-static void 
-rb_ipod_volume_unmounted_cb (GnomeVFSVolumeMonitor *monitor,
-			     GnomeVFSVolume *volume, 
-			     gpointer data)
-{
-	RBiPodSource *source = RB_IPOD_SOURCE (data);
-
-	g_assert (volume != NULL);
-
-	if (source->priv->ipod_volume == volume) {
-		rb_ipod_unplugged (source);
-	}
 }
 
 
Index: sources/rb-ipod-source.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-ipod-source.h,v
retrieving revision 1.3
diff -u -r1.3 rb-ipod-source.h
--- sources/rb-ipod-source.h	10 Sep 2004 05:12:59 -0000	1.3
+++ sources/rb-ipod-source.h	21 Aug 2005 17:28:55 -0000
@@ -23,7 +23,7 @@
 #define __RB_IPOD_SOURCE_H
 
 #include "rb-shell.h"
-#include "rb-library-source.h"
+#include "rb-removable-media-source.h"
 #include "rhythmdb.h"
 
 G_BEGIN_DECLS
@@ -37,25 +37,22 @@
 
 #define RHYTHMDB_ENTRY_TYPE_IPOD (rhythmdb_entry_ipod_get_type ())
 
-typedef struct RBiPodSourcePrivate RBiPodSourcePrivate;
-
 typedef struct
 {
-	RBLibrarySource parent;
-
-	RBiPodSourcePrivate *priv;
+	RBRemovableMediaSource parent;
 } RBiPodSource;
 
 typedef struct
 {
-	RBLibrarySourceClass parent;
+	RBRemovableMediaSourceClass parent;
 } RBiPodSourceClass;
 
-RBSource *	rb_ipod_source_new		(RBShell *shell);
+RBRemovableMediaSource*	rb_ipod_source_new		(RBShell *shell, GnomeVFSVolume *volume);
+gboolean		rb_ipod_is_volume_ipod		(GnomeVFSVolume *volume);
 
-GType		rb_ipod_source_get_type	        (void);
+GType			rb_ipod_source_get_type	        (void);
 
-RhythmDBEntryType rhythmdb_entry_ipod_get_type  (void);
+RhythmDBEntryType 	rhythmdb_entry_ipod_get_type  (void);
 
 G_END_DECLS
 
Index: sources/rb-library-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.c,v
retrieving revision 1.109
diff -u -r1.109 rb-library-source.c
--- sources/rb-library-source.c	17 Aug 2005 16:32:54 -0000	1.109
+++ sources/rb-library-source.c	21 Aug 2005 17:29:02 -0000
@@ -124,6 +124,7 @@
 static const char * impl_get_album (RBSource *player);
 static gboolean impl_receive_drag (RBSource *source, GtkSelectionData *data);
 static gboolean impl_show_popup (RBSource *source);
+static const char * default_get_paned_key (RBLibrarySource *status);
 static void rb_library_source_do_query (RBLibrarySource *source, RBLibraryQueryType qtype);
 
 void rb_library_source_browser_views_activated_cb (GtkWidget *widget,
@@ -140,10 +141,10 @@
 #define CONF_UI_LIBRARY_DIR CONF_PREFIX "/ui/library"
 #define CONF_UI_LIBRARY_BROWSER_VIEWS CONF_PREFIX "/ui/library/browser_views"
 #define CONF_STATE_LIBRARY_DIR CONF_PREFIX "/state/library"
-#define CONF_STATE_LIBRARY_SORTING CONF_PREFIX "/state/library/sorting"
-#define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/library/paned_position"
-#define CONF_STATE_SHOW_BROWSER   CONF_PREFIX "/state/library/show_browser"
-#define CONF_STATE_SEARCH_TEXT   CONF_PREFIX "/state/library/search_text"
+#define CONF_STATE_LIBRARY_SORTING CONF_STATE_LIBRARY_DIR "/sorting"
+#define CONF_STATE_PANED_POSITION CONF_STATE_LIBRARY_DIR "/paned_position"
+#define CONF_STATE_SHOW_BROWSER   CONF_STATE_LIBRARY_DIR "/show_browser"
+#define CONF_STATE_SEARCH_TEXT   CONF_STATE_LIBRARY_DIR "/search_text"
 
 struct RBLibrarySourcePrivate
 {
@@ -189,7 +190,8 @@
 	GSList *browser_views_group;
 	
 	RhythmDBEntryType entry_type;
-	
+
+	char * sorting_key;
 	guint ui_dir_notify_id;
 	guint state_dir_notify_id;
 	guint browser_view_notify_id;
@@ -214,7 +216,8 @@
 {
 	PROP_0,
 	PROP_ICON,
-	PROP_ENTRY_TYPE
+	PROP_ENTRY_TYPE,
+	PROP_SORTING_KEY
 };
 
 static GObjectClass *parent_class = NULL;
@@ -286,6 +289,8 @@
 	source_class->impl_receive_drag = impl_receive_drag;
 	source_class->impl_show_popup = impl_show_popup;
 
+	klass->impl_get_paned_key = default_get_paned_key;
+
 	g_object_class_install_property (object_class,
 					 PROP_ICON,
 					 g_param_spec_object ("icon",
@@ -303,6 +308,14 @@
 							    RHYTHMDB_ENTRY_TYPE_SONG,
 							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+	g_object_class_install_property (object_class,
+					 PROP_SORTING_KEY,
+					 g_param_spec_string ("sorting-key",
+							      "Sorting key",
+							      "GConf key for storing sort-order",
+							      CONF_STATE_LIBRARY_SORTING,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 }
 
 static void
@@ -440,6 +453,7 @@
 	eel_gconf_notification_remove (source->priv->state_dir_notify_id);
 	eel_gconf_notification_remove (source->priv->browser_view_notify_id);
 
+	g_free (source->priv->sorting_key);
 	g_free (source->priv->artist);
 	g_free (source->priv->album);
 
@@ -524,7 +538,7 @@
 	source->priv->browser = gtk_hbox_new (TRUE, 5);
 
 	/* set up songs tree view */
-	source->priv->songs = rb_entry_view_new (source->priv->db, CONF_STATE_LIBRARY_SORTING,
+	source->priv->songs = rb_entry_view_new (source->priv->db, source->priv->sorting_key,
 						 TRUE, FALSE);
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TRACK_NUMBER);
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TITLE);
@@ -651,6 +665,10 @@
 	case PROP_ENTRY_TYPE:
 		source->priv->entry_type = g_value_get_uint (value);
 		break;
+	case PROP_SORTING_KEY:
+		g_free (source->priv->sorting_key);
+		source->priv->sorting_key = g_strdup (g_value_get_string (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -673,6 +691,9 @@
 	case PROP_ENTRY_TYPE:
 		g_value_set_uint (value, source->priv->entry_type);
 		break;
+	case PROP_SORTING_KEY:
+		g_value_set_string (value, source->priv->sorting_key);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -941,6 +962,12 @@
 	rb_library_source_do_query (source, RB_LIBRARY_QUERY_TYPE_SEARCH);
 }
 
+static const char *
+default_get_paned_key (RBLibrarySource *status)
+{
+	return CONF_STATE_PANED_POSITION;
+}
+
 static char *
 impl_get_status (RBSource *asource)
 {
@@ -1190,21 +1217,26 @@
 {
 	/* save state */
 	rb_debug ("paned size allocate");
-	eel_gconf_set_integer (CONF_STATE_PANED_POSITION,
+	eel_gconf_set_integer (rb_library_source_get_paned_key (source),
 			       gtk_paned_get_position (GTK_PANED (source->priv->paned)));
 }
 
 static void
 rb_library_source_state_prefs_sync (RBLibrarySource *source)
 {
+	const char *key;
+
 	rb_debug ("syncing state");
-	gtk_paned_set_position (GTK_PANED (source->priv->paned),
-				eel_gconf_get_integer (CONF_STATE_PANED_POSITION));
-	
-	if (eel_gconf_get_boolean (CONF_STATE_SHOW_BROWSER))
-		gtk_widget_show (source->priv->browser);
-	else
-		gtk_widget_hide (source->priv->browser);
+	key = rb_library_source_get_paned_key (source);
+	if (key)
+		gtk_paned_set_position (GTK_PANED (source->priv->paned),
+					eel_gconf_get_integer (key));
+
+	key = rb_source_get_browser_key (RB_SOURCE (source));
+	if (key && eel_gconf_get_boolean (key))
+			gtk_widget_show (source->priv->browser);
+		else
+			gtk_widget_hide (source->priv->browser);
 }
 
 static void
@@ -1333,6 +1365,14 @@
 {
 	_rb_source_show_popup (RB_SOURCE (source), "/LibrarySourcePopup");
 	return TRUE;
+}
+
+const char *
+rb_library_source_get_paned_key (RBLibrarySource *source)
+{
+	RBLibrarySourceClass *klass = RB_LIBRARY_SOURCE_GET_CLASS (source);
+
+	return klass->impl_get_paned_key (source);
 }
 
 static void
Index: sources/rb-library-source.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.h,v
retrieving revision 1.12
diff -u -r1.12 rb-library-source.h
--- sources/rb-library-source.h	10 Sep 2004 05:12:59 -0000	1.12
+++ sources/rb-library-source.h	21 Aug 2005 17:29:02 -0000
@@ -50,19 +50,20 @@
 typedef struct
 {
 	RBSourceClass parent;
+
+	const char *	(*impl_get_paned_key)	(RBLibrarySource *source);
 } RBLibrarySourceClass;
 
 GType		rb_library_source_get_type	(void);
 
 RBSource *      rb_library_source_new           (RBShell *shell);
 
-void		rb_library_source_show_browser	(RBLibrarySource *source,
-						 gboolean show);
-
 void		rb_library_source_add_location	(RBLibrarySource *source, GtkWindow *win);
 
 void            rb_library_source_class_add_actions (RBShell *shell, 
 						     GtkActionGroup *uimgr);
+
+const char *	rb_library_source_get_paned_key	(RBLibrarySource *source);
 
 G_END_DECLS
 
Index: sources/rb-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-source.c,v
retrieving revision 1.36
diff -u -r1.36 rb-source.c
--- sources/rb-source.c	7 Jul 2005 14:30:20 -0000	1.36
+++ sources/rb-source.c	21 Aug 2005 17:29:20 -0000
@@ -67,6 +67,7 @@
 	
 	RBShell *shell;
 	gboolean visible;
+	GObject *player_subtype;
 };
 
 enum
@@ -76,7 +77,8 @@
 	PROP_INTERNAL_NAME,
 	PROP_SHELL,
 	PROP_UI_MANAGER,
-	PROP_VISIBLE
+	PROP_VISIBLE,
+	PROP_PLAYER_SUBTYPE
 };
 
 enum
@@ -194,6 +196,14 @@
 							       TRUE,
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
+	g_object_class_install_property (object_class,
+					 PROP_PLAYER_SUBTYPE,
+					 g_param_spec_object ("player-subtype",
+							      "GObject",
+							      "RBPlayerSubtype object",
+							      G_TYPE_OBJECT,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 	rb_source_signals[DELETED] =
 		g_signal_new ("deleted",
 			      RB_TYPE_SOURCE,
@@ -285,6 +295,9 @@
 			  source->priv->name, 
 			  source->priv->visible);
 		break;
+	case PROP_PLAYER_SUBTYPE:
+		source->priv->player_subtype = g_value_get_object (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -323,6 +336,9 @@
 		g_object_unref (G_OBJECT(manager));
 		break;
 	}
+	case PROP_PLAYER_SUBTYPE:
+		g_value_set_object (value, source->priv->player_subtype);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -691,4 +707,14 @@
 
 	klass->impl_delete_thyself (source);
 	g_signal_emit (G_OBJECT (source), rb_source_signals[DELETED], 0);
+}
+
+
+RhythmDBEntryType
+rb_source_get_entry_type (RBSource *source)
+{
+	RhythmDBEntryType entry_type;
+
+	g_object_get (G_OBJECT (source), "entry_type", &entry_type, NULL);
+	return entry_type;
 }
Index: sources/rb-source.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-source.h,v
retrieving revision 1.22
diff -u -r1.22 rb-source.h
--- sources/rb-source.h	12 Jun 2005 16:02:15 -0000	1.22
+++ sources/rb-source.h	21 Aug 2005 17:29:20 -0000
@@ -163,6 +163,8 @@
 
 void		rb_source_delete_thyself	(RBSource *source);
 
+RhythmDBEntryType rb_source_get_entry_type	(RBSource *source);
+
 /* Protected method, should only be used by objects inheriting from RBSource */
 void            _rb_source_show_popup           (RBSource *source, 
 						 const char *ui_path);
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/tests/Makefile.am,v
retrieving revision 1.9
diff -u -r1.9 Makefile.am
--- tests/Makefile.am	16 Dec 2003 15:36:45 -0000	1.9
+++ tests/Makefile.am	21 Aug 2005 17:29:20 -0000
@@ -57,7 +57,7 @@
 
 test_cmdline_LDFLAGS = -export-dynamic
 
-if HAVE_AUDIOCD
+if WITH_AUDIOCD_SUPPORT
 noinst_PROGRAMS += test-cd
 
 test_cd_SOURCES = test-cd.c
--- /dev/null	2005-08-18 18:12:49.785368488 +1000
+++ sources/rb-removable-media-source.c	2005-08-17 21:08:25.000000000 +1000
@@ -0,0 +1,216 @@
+/*
+ *  arch-tag: Implementation of removable media source object (based of the ipod source)
+ *
+ *  Copyright (C) 2004 Christophe Fergeau  <teuf@gnome.org>
+ *  Copyright (C) 2005 James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkicontheme.h>
+#include <string.h>
+#include "rhythmdb.h"
+#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-volume.h>
+#include <libgnomevfs/gnome-vfs-volume-monitor.h>
+#include "eel-gconf-extensions.h"
+#include "rb-removable-media-source.h"
+#include "rb-stock-icons.h"
+#include "rb-debug.h"
+#include "rb-dialog.h"
+
+static void rb_removable_media_source_dispose (GObject *object);
+static void rb_removable_media_source_class_init (RBRemovableMediaSourceClass *klass);
+static GObject *rb_removable_media_source_constructor (GType type, 
+					    guint n_construct_properties,
+					    GObjectConstructParam *construct_properties);
+
+static void rb_removable_media_source_set_property (GObject *object,
+			                  guint prop_id,
+			                  const GValue *value,
+			                  GParamSpec *pspec);
+static void rb_removable_media_source_get_property (GObject *object,
+			                  guint prop_id,
+			                  GValue *value,
+			                  GParamSpec *pspec);
+
+static GObjectClass *parent_class = NULL;
+
+typedef struct
+{
+	GnomeVFSVolume *volume;
+} RBRemovableMediaSourcePrivate;
+
+#define REMOVABLE_MEDIA_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_REMOVABLE_MEDIA_SOURCE, RBRemovableMediaSourcePrivate))
+
+enum
+{
+	PROP_0,
+	PROP_VOLUME,
+};
+
+
+GType
+rb_removable_media_source_get_type (void)
+{
+	static GType rb_removable_media_source_type = 0;
+
+	if (rb_removable_media_source_type == 0)
+	{
+		static const GTypeInfo our_info =
+		{
+			sizeof (RBRemovableMediaSourceClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) rb_removable_media_source_class_init,
+			NULL,
+			NULL,
+			sizeof (RBRemovableMediaSource),
+			0,
+			NULL
+		};
+
+		rb_removable_media_source_type = g_type_register_static (RB_TYPE_LIBRARY_SOURCE,
+									 "RBRemovableMediaSource",
+									 &our_info, 0);
+
+	}
+
+	return rb_removable_media_source_type;
+}
+
+static void
+rb_removable_media_source_class_init (RBRemovableMediaSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->dispose = rb_removable_media_source_dispose;
+	object_class->constructor = rb_removable_media_source_constructor;
+
+	object_class->set_property = rb_removable_media_source_set_property;
+	object_class->get_property = rb_removable_media_source_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_VOLUME,
+					 g_param_spec_object ("volume",
+							      "Volume",
+							      "GnomeVfs Volume",
+							      GNOME_VFS_TYPE_VOLUME,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_type_class_add_private (klass, sizeof (RBRemovableMediaSourcePrivate));
+}
+
+static GObject *
+rb_removable_media_source_constructor (GType type, guint n_construct_properties,
+				       GObjectConstructParam *construct_properties)
+{
+	GObject *object;
+	RBRemovableMediaSourceClass *klass;
+	GObjectClass *parent_class;
+	
+	/*
+	 * TODO
+	 * read the volume from the construction params
+	 * and the create a new param for the icon
+	 */
+
+	/* Invoke parent constructor. */
+	klass = RB_REMOVABLE_MEDIA_SOURCE_CLASS (g_type_class_peek (RB_TYPE_REMOVABLE_MEDIA_SOURCE));
+	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
+	object = parent_class->constructor (type,
+					    n_construct_properties,
+					    construct_properties);
+	return object;
+}
+
+
+static void 
+rb_removable_media_source_dispose (GObject *object)
+{
+	RBRemovableMediaSourcePrivate *priv = REMOVABLE_MEDIA_SOURCE_GET_PRIVATE (object);
+	
+	if (priv->volume) {
+		gnome_vfs_volume_unref (priv->volume);
+		priv->volume = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+rb_removable_media_source_set_property (GObject *object,
+				        guint prop_id,
+				        const GValue *value,
+				        GParamSpec *pspec)
+{
+	RBRemovableMediaSourcePrivate *priv = REMOVABLE_MEDIA_SOURCE_GET_PRIVATE (object);
+
+	switch (prop_id)
+	{
+	case PROP_VOLUME:
+		if (priv->volume) {
+			g_object_unref (G_OBJECT (priv->volume));
+		}
+		priv->volume = g_value_get_object (value);
+		g_object_ref (priv->volume);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_removable_media_source_get_property (GObject *object,
+				        guint prop_id,
+				        GValue *value,
+				        GParamSpec *pspec)
+{
+	RBRemovableMediaSourcePrivate *priv = REMOVABLE_MEDIA_SOURCE_GET_PRIVATE (object);
+
+	switch (prop_id)
+	{
+	case PROP_VOLUME:
+		g_value_set_object (value, priv->volume);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+
+void
+rb_removable_media_source_plugged (RBRemovableMediaSource *source)
+{
+	RBRemovableMediaSourceClass *klass = RB_REMOVABLE_MEDIA_SOURCE_GET_CLASS (source);
+
+	return klass->impl_media_plugged (source);
+}
+
+void
+rb_removable_media_source_unplugged (RBRemovableMediaSource *source)
+{
+	RBRemovableMediaSourceClass *klass = RB_REMOVABLE_MEDIA_SOURCE_GET_CLASS (source);
+
+	return klass->impl_media_unplugged (source);
+}
--- /dev/null	2005-08-18 18:12:49.785368488 +1000
+++ sources/rb-removable-media-source.h	2005-08-17 21:05:03.000000000 +1000
@@ -0,0 +1,61 @@
+/*
+ *  arch-tag: Header for removable media source object
+ *
+ *  Copyright (C) 2005 James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __RB_REMOVABLE_MEDIA_SOURCE_H
+#define __RB_REMOVABLE_MEDIA_SOURCE_H
+
+#include "rb-shell.h"
+#include "rb-library-source.h"
+#include "rhythmdb.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_REMOVABLE_MEDIA_SOURCE         (rb_removable_media_source_get_type ())
+#define RB_REMOVABLE_MEDIA_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_REMOVABLE_MEDIA_SOURCE, RBRemovableMediaSource))
+#define RB_REMOVABLE_MEDIA_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_REMOVABLE_MEDIA_SOURCE, RBRemovableMediaSourceClass))
+#define RB_IS_REMOVABLE_MEDIA_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_REMOVABLE_MEDIA_SOURCE))
+#define RB_IS_REMOVABLE_MEDIA_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_REMOVABLE_MEDIA_SOURCE))
+#define RB_REMOVABLE_MEDIA_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_REMOVABLE_MEDIA_SOURCE, RBRemovableMediaSourceClass))
+
+typedef struct
+{
+	RBLibrarySource parent;
+} RBRemovableMediaSource;
+
+typedef struct
+{
+	RBLibrarySourceClass parent;
+
+	/* methods */
+	void	        (*impl_media_plugged)		(RBRemovableMediaSource *source);
+	void	        (*impl_media_unplugged)		(RBRemovableMediaSource *source);
+} RBRemovableMediaSourceClass;
+
+GType			rb_removable_media_source_get_type	(void);
+
+/* method calls */
+void	        rb_removable_media_source_plugged		(RBRemovableMediaSource *source);
+void	        rb_removable_media_source_unplugged		(RBRemovableMediaSource *source);
+
+
+G_END_DECLS
+
+#endif /* __RB_REMOVABLE_MEDIA_SOURCE_H */
--- /dev/null	2005-08-18 18:12:49.785368488 +1000
+++ shell/rb-device-manager.c	2005-08-18 12:17:19.000000000 +1000
@@ -0,0 +1,392 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  arch-tag: Implementation of Rhythmbox playlist management object
+ *
+ *  Copyright (C) 2003,2004 Colin Walters <walters@gnome.org>
+ *  Copyright (C) 2005 James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <libgnome/gnome-i18n.h>
+#include <libxml/tree.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include <string.h>
+
+#include "rb-device-manager.h"
+#include "rb-sourcelist.h"
+#ifdef WITH_AUDIOCD_SUPPORT
+#include "rb-audiocd-source.h"
+#endif
+#ifdef WITH_IPOD_SUPPORT
+#include "rb-ipod-source.h"
+#endif
+
+#include "rb-file-helpers.h"
+#include "rb-debug.h"
+#include "rb-dialog.h"
+#include "rhythmdb.h"
+#include "rb-stock-icons.h"
+#include "eel-gconf-extensions.h"
+
+static void rb_device_manager_class_init (RBDeviceManagerClass *klass);
+static void rb_device_manager_dispose (GObject *object);
+static void rb_device_manager_set_property (GObject *object,
+					      guint prop_id,
+					      const GValue *value,
+					      GParamSpec *pspec);
+static void rb_device_manager_get_property (GObject *object,
+					      guint prop_id,
+					      GValue *value,
+					      GParamSpec *pspec);
+					 
+static void rb_device_manager_monitor (RBDeviceManager *mgr, gboolean enable);
+static void rb_device_manager_append_media_source (RBDeviceManager *mgr, RBRemovableMediaSource *source);
+
+static void rb_device_manager_mount_volume (RBDeviceManager *mgr,
+				GnomeVFSVolume *volume);
+static void rb_device_manager_unmount_volume (RBDeviceManager *mgr,
+				GnomeVFSVolume *volume);
+
+static void  rb_device_manager_volume_mounted_cb (GnomeVFSVolumeMonitor *monitor,
+				GnomeVFSVolume *volume, 
+				gpointer data);
+static void  rb_device_manager_volume_unmounted_cb (GnomeVFSVolumeMonitor *monitor,
+				GnomeVFSVolume *volume, 
+				gpointer data);
+typedef struct
+{
+	RBShell *shell;
+
+	RBSourceList *sourcelist;
+	RBSource *selected_source;
+
+	GtkWindow *window;
+
+	GList *sources;
+} RBDeviceManagerPrivate;
+
+#define DEVICE_MANAGER_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DEVICE_MANAGER, RBDeviceManagerPrivate))
+
+enum
+{
+	PROP_0,
+	PROP_SHELL,
+	PROP_SOURCELIST,
+	PROP_SOURCE,
+};
+
+enum
+{
+	DEVICE_ADDED,
+	LAST_SIGNAL
+};
+
+static guint rb_device_manager_signals[LAST_SIGNAL] = { 0 };
+
+static GObjectClass *parent_class = NULL;
+
+GType
+rb_device_manager_get_type (void)
+{
+	static GType rb_device_manager_type = 0;
+
+	if (rb_device_manager_type == 0)
+	{
+		static const GTypeInfo our_info =
+		{
+			sizeof (RBDeviceManagerClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) rb_device_manager_class_init,
+			NULL,
+			NULL,
+			sizeof (RBDeviceManagerClass),
+			0,
+			NULL
+		};
+
+		rb_device_manager_type = g_type_register_static (G_TYPE_OBJECT,
+								   "RBDeviceManager",
+								   &our_info, 0);
+	}
+
+	return rb_device_manager_type;
+}
+
+static void
+rb_device_manager_class_init (RBDeviceManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->dispose = rb_device_manager_dispose;
+
+	object_class->set_property = rb_device_manager_set_property;
+	object_class->get_property = rb_device_manager_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_SHELL,
+					 g_param_spec_object ("shell",
+							      "RBShell",
+							      "RBShell object",
+							      RB_TYPE_SHELL,
+							      G_PARAM_READWRITE));
+	
+	g_object_class_install_property (object_class,
+					 PROP_SOURCELIST,
+					 g_param_spec_object ("sourcelist",
+							      "RBSourceList",
+							      "RBSourceList",
+							      RB_TYPE_SOURCELIST,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	rb_device_manager_signals[DEVICE_ADDED] =
+		g_signal_new ("device_added",
+			      RB_TYPE_DEVICE_MANAGER,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDeviceManagerClass, device_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1, G_TYPE_OBJECT);
+
+	g_type_class_add_private (klass, sizeof (RBDeviceManagerPrivate));
+}
+
+static void
+rb_device_manager_dispose (GObject *object)
+{
+	RBDeviceManager *mgr = RB_DEVICE_MANAGER (object);
+	RBDeviceManagerPrivate *priv = DEVICE_MANAGER_GET_PRIVATE (mgr);
+
+	rb_device_manager_monitor (mgr, FALSE);
+	
+	if (priv->sources) {
+		g_list_free (priv->sources);
+		priv->sources = NULL;
+	}
+}
+
+static void
+rb_device_manager_set_property (GObject *object,
+				  guint prop_id,
+				  const GValue *value,
+				  GParamSpec *pspec)
+{
+	RBDeviceManagerPrivate *priv = DEVICE_MANAGER_GET_PRIVATE (object);
+
+	switch (prop_id)
+	{
+	case PROP_SOURCE:
+	{
+		/*gboolean device_active;*/
+		priv->selected_source = g_value_get_object (value);
+
+		/*device_active = g_list_find (priv->sources,
+					       priv->selected_source) != NULL;*/
+		break;
+	}
+	case PROP_SHELL:
+	{
+		priv->shell = g_value_get_object (value);
+		break;
+	}
+	case PROP_SOURCELIST:
+		priv->sourcelist = g_value_get_object (value);
+		priv->window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (priv->sourcelist)));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void 
+rb_device_manager_get_property (GObject *object,
+			      guint prop_id,
+			      GValue *value,
+			      GParamSpec *pspec)
+{
+	RBDeviceManagerPrivate *priv = DEVICE_MANAGER_GET_PRIVATE (object);
+
+	switch (prop_id)
+	{
+	case PROP_SOURCE:
+		g_value_set_object (value, priv->selected_source);
+		break;
+	case PROP_SHELL:
+		g_value_set_object (value, priv->shell);
+		break;
+	case PROP_SOURCELIST:
+		g_value_set_object (value, priv->sourcelist);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+RBDeviceManager *
+rb_device_manager_new (RBShell *shell,
+			 RBSourceList *sourcelist)
+{
+	return g_object_new (RB_TYPE_DEVICE_MANAGER,
+			     "shell", shell,
+			     "sourcelist", sourcelist,
+			     NULL);
+}
+
+void
+rb_device_manager_load_devices (RBDeviceManager *mgr)
+{
+	rb_device_manager_monitor (mgr, TRUE);
+}
+
+static void
+rb_device_manager_monitor (RBDeviceManager *mgr, gboolean enable)
+{
+	GnomeVFSVolumeMonitor *monitor;
+	
+	monitor = gnome_vfs_get_volume_monitor ();
+
+	if (enable) {
+		GList *volumes;
+		GList *it;
+
+		/* Look for already plugged devices */
+		volumes = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
+		for (it = volumes; it != NULL; it = it->next)
+			rb_device_manager_mount_volume (mgr, GNOME_VFS_VOLUME (it->data));
+		
+		/* Monitor new (un)mounted file systems to look for an devices */
+		g_signal_connect (G_OBJECT (monitor), "volume-mounted", 
+				  G_CALLBACK (rb_device_manager_volume_mounted_cb), 
+				  mgr);
+		g_signal_connect (G_OBJECT (monitor), "volume-unmounted", 
+				  G_CALLBACK (rb_device_manager_volume_unmounted_cb), 
+				  mgr);
+	} else {
+		g_signal_handlers_disconnect_by_func (G_OBJECT (monitor), 
+						      G_CALLBACK (rb_device_manager_volume_mounted_cb), 
+						      mgr);
+		g_signal_handlers_disconnect_by_func (G_OBJECT (monitor), 
+						      G_CALLBACK (rb_device_manager_volume_unmounted_cb), 
+						      mgr);
+
+	}
+}
+
+static void 
+rb_device_manager_volume_mounted_cb (GnomeVFSVolumeMonitor *monitor,
+			   GnomeVFSVolume *volume, 
+			   gpointer data)
+{
+	RBDeviceManager *mgr = RB_DEVICE_MANAGER (data);
+
+	rb_device_manager_mount_volume (mgr, volume);
+}
+
+
+
+
+
+static void
+rb_device_manager_volume_unmounted_cb (GnomeVFSVolumeMonitor *monitor,
+			     GnomeVFSVolume *volume, 
+			     gpointer data)
+{
+	RBDeviceManager *mgr = RB_DEVICE_MANAGER (data);
+
+	g_assert (volume != NULL);
+	rb_device_manager_unmount_volume (mgr, volume);
+}
+
+
+static void
+rb_device_manager_mount_volume (RBDeviceManager *mgr, GnomeVFSVolume *volume)
+{
+	RBRemovableMediaSource *source = NULL;
+	RBShell *shell;
+	
+	g_object_get (G_OBJECT (mgr), "shell", &shell, NULL);
+
+	rb_debug ("detecting new device - device_type=%d", gnome_vfs_volume_get_device_type (volume));
+	rb_debug ("detecting new device - volumd_type=%d", gnome_vfs_volume_get_volume_type (volume));
+	rb_debug ("detecting new device - fs type=%s", gnome_vfs_volume_get_filesystem_type (volume));
+	rb_debug ("detecting new device - device path=%s", gnome_vfs_volume_get_device_path (volume));
+	rb_debug ("detecting new device - display name=%s", gnome_vfs_volume_get_display_name (volume));
+	rb_debug ("detecting new device - hal udi=%s", gnome_vfs_volume_get_hal_udi (volume));
+	rb_debug ("detecting new device - icon=%s", gnome_vfs_volume_get_icon (volume));
+	rb_debug ("detecting new device - hal udi=%s", gnome_vfs_volume_get_hal_udi (volume));
+
+#ifdef WITH_AUDIOCD_SUPPORT
+	if (source == NULL && rb_audiocd_is_volume_audiocd (volume))
+		source = rb_audiocd_source_new (shell, volume);
+#endif
+#ifdef WITH_IPOD_SUPPORT
+	if (source == NULL &&rb_ipod_is_volume_ipod (volume))
+		source = rb_ipod_source_new (shell, volume);
+#endif
+
+	g_object_unref (G_OBJECT (shell));
+
+	if (source) {
+		g_object_set_data (G_OBJECT (volume), "rb-removable-media-source", source);
+		rb_device_manager_append_media_source (mgr, source);
+		rb_removable_media_source_plugged (source);
+	} else
+		rb_debug ("Unhanded device");
+}
+
+static void
+rb_device_manager_unmount_volume (RBDeviceManager *mgr, GnomeVFSVolume *volume)
+{
+	RBRemovableMediaSource *source;
+
+	g_assert (volume != NULL);
+
+	source = g_object_get_data (G_OBJECT (volume), "rb-removable-media-source");
+	if (source) {
+		rb_removable_media_source_unplugged (source);
+		rb_source_delete_thyself (RB_SOURCE (source));
+	}
+}
+
+static void
+rb_device_manager_source_deleted_cb (RBSource *source, RBDeviceManager *mgr)
+{
+	RBDeviceManagerPrivate *priv = DEVICE_MANAGER_GET_PRIVATE (mgr);
+
+	rb_debug ("removing source %p", source);
+	priv->sources = g_list_remove (priv->sources, source);
+}
+
+static void
+rb_device_manager_append_media_source (RBDeviceManager *mgr, RBRemovableMediaSource *source)
+{
+	RBDeviceManagerPrivate *priv = DEVICE_MANAGER_GET_PRIVATE (mgr);
+
+	priv->sources = g_list_append (priv->sources, source);
+	g_signal_connect_object (G_OBJECT (source), "deleted",
+				 G_CALLBACK (rb_device_manager_source_deleted_cb), mgr, 0);
+	g_signal_emit (G_OBJECT (mgr), rb_device_manager_signals[DEVICE_ADDED], 0,
+		       source);
+}
--- /dev/null	2005-08-18 18:12:49.785368488 +1000
+++ shell/rb-device-manager.h	2005-08-17 21:13:12.000000000 +1000
@@ -0,0 +1,61 @@
+/*
+ *  arch-tag: Header for Rhythmbox device management object
+ *
+ *  Copyright (C) 2005 James Livingston <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __RB_DEVICE_MANAGER_H
+#define __RB_DEVICE_MANAGER_H
+
+#include "rb-source.h"
+#include "rhythmdb.h"
+#include "rb-shell.h"
+#include "rb-sourcelist.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DEVICE_MANAGER         (rb_device_manager_get_type ())
+#define RB_DEVICE_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DEVICE_MANAGER, RBDeviceManager))
+#define RB_DEVICE_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DEVICE_MANAGER, RBDeviceManagerClass))
+#define RB_IS_DEVICE_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DEVICE_MANAGER))
+#define RB_IS_DEVICE_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DEVICE_MANAGER))
+#define RB_DEVICE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DEVICE_MANAGER, RBDeviceManagerClass))
+
+typedef struct
+{
+	GObject parent;
+} RBDeviceManager;
+
+typedef struct
+{
+	GObjectClass parent_class;
+
+	/* signals */
+	void	(*device_added) (RBSource *source);
+} RBDeviceManagerClass;
+
+GType			rb_device_manager_get_type	(void);
+
+RBDeviceManager *	rb_device_manager_new		(RBShell *shell,
+							 RBSourceList *sourcelist);
+
+void			rb_device_manager_load_devices (RBDeviceManager *mgr);
+
+G_END_DECLS
+
+#endif /* __RB_DEVICE_MANAGER_H */
--- /dev/null	2005-08-18 18:12:49.785368488 +1000
+++ sources/rb-audiocd-source.c	2005-08-18 16:09:50.000000000 +1000
@@ -0,0 +1,449 @@
+/*
+ *  arch-tag: Implementation of audiocd source object (based of the ipod source)
+ *
+ *  Copyright (C) 2004 Christophe Fergeau  <teuf@gnome.org>
+ *  Copyright (C) 2005 James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+/*
+ * TODO
+ *    + sort by track # by default
+ *    + CDDB/MusicBrains metadata
+ *    + context menu on source, with "Eject"
+ *
+ * BUGS
+ *    + duration always gets value of first track
+ */
+
+#include <config.h>
+
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkicontheme.h>
+#include <string.h>
+#include "rhythmdb.h"
+#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-volume.h>
+#include <libgnomevfs/gnome-vfs-volume-monitor.h>
+#include <gst/gst.h>
+#include <totem-disc.h>
+#include "eel-gconf-extensions.h"
+#include "rb-audiocd-source.h"
+#include "rb-util.h"
+#include "rb-stock-icons.h"
+#include "rb-debug.h"
+#include "rb-dialog.h"
+#include "rb-player.h"
+#include "rhythmdb.h"
+
+static void rb_audiocd_source_finalize (GObject *object);
+static void rb_audiocd_source_class_init (RBAudioCdSourceClass *klass);
+
+static gboolean impl_show_popup (RBSource *source);
+static GtkWidget *impl_get_config_widget (RBSource *source);
+static gboolean impl_receive_drag (RBSource *source, GtkSelectionData *data);
+
+static void impl_audiocd_plugged (RBRemovableMediaSource *source);
+static void impl_audiocd_unplugged (RBRemovableMediaSource *source);
+
+static GObjectClass *parent_class = NULL;
+
+typedef struct
+{
+	gint64 num_tracks;
+	GList *tracks;
+	gchar *disc_id;
+	gchar *device_path;
+} RBAudioCdSourcePrivate;
+
+#define AUDIOCD_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_AUDIOCD_SOURCE, RBAudioCdSourcePrivate))
+
+
+typedef const char * (*RBSourceStringFunc) (RBSource *source);
+
+
+GType
+rb_audiocd_source_get_type (void)
+{
+	static GType rb_audiocd_source_type = 0;
+
+	if (rb_audiocd_source_type == 0)
+	{
+		static const GTypeInfo our_info =
+		{
+			sizeof (RBAudioCdSourceClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) rb_audiocd_source_class_init,
+			NULL,
+			NULL,
+			sizeof (RBAudioCdSource),
+			0,
+			NULL
+		};
+
+		rb_audiocd_source_type = g_type_register_static (RB_TYPE_REMOVABLE_MEDIA_SOURCE,
+							      "RBAudioCdSource",
+							      &our_info, 0);
+
+	}
+
+	return rb_audiocd_source_type;
+}
+
+static void
+rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+	RBRemovableMediaSourceClass *removable_media_source_class = RB_REMOVABLE_MEDIA_SOURCE_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize = rb_audiocd_source_finalize;
+
+	/* don't bother showing the browser/search bits */
+	source_class->impl_get_browser_key = (RBSourceStringFunc) rb_null_function;
+	source_class->impl_get_search_key = (RBSourceStringFunc) rb_null_function;
+	source_class->impl_can_search = (RBSourceFeatureFunc) rb_false_function;
+
+	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
+
+	source_class->impl_show_popup = impl_show_popup;
+	source_class->impl_get_config_widget = impl_get_config_widget;
+	source_class->impl_receive_drag = impl_receive_drag;
+
+	removable_media_source_class->impl_media_plugged = impl_audiocd_plugged;
+	removable_media_source_class->impl_media_unplugged = impl_audiocd_unplugged;
+
+	g_type_class_add_private (klass, sizeof (RBAudioCdSourcePrivate));
+}
+
+
+static void 
+rb_audiocd_source_finalize (GObject *object)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (object);
+
+	g_free (priv->disc_id);
+	g_free (priv->device_path);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+RBRemovableMediaSource *
+rb_audiocd_source_new (RBShell *shell, GnomeVFSVolume *volume)
+{
+	char *display_name, *device_path, *internal_name;
+	RBAudioCdSource *source;
+	GObject *subtype;
+	RhythmDBEntryType entry_type;
+
+	display_name = gnome_vfs_volume_get_display_name (volume);
+	device_path = gnome_vfs_volume_get_device_path (volume);
+	internal_name = g_strdup_printf ("<audiocd:%s>", device_path);
+
+	char *icon_name = gnome_vfs_volume_get_icon (volume);
+	GtkIconTheme *theme = gtk_icon_theme_get_default ();
+	GdkPixbuf *icon = gtk_icon_theme_load_icon (theme, icon_name, 24, 0, NULL);
+
+	subtype = rb_player_cdda_subtype_new (device_path);
+	entry_type =  rhythmdb_entry_register_type ();
+
+	source = RB_AUDIOCD_SOURCE (g_object_new (RB_TYPE_AUDIOCD_SOURCE,
+					  "name", display_name,
+					  "entry-type", entry_type,
+					  "internal-name", internal_name,
+					  "icon", icon,
+					  "volume", volume,
+					  "shell", shell,
+					  "player-subtype", subtype,
+					  "sorting-key", NULL,
+					  NULL));
+
+	g_free (internal_name);
+	g_free (device_path);
+	g_free (display_name);
+
+	return RB_REMOVABLE_MEDIA_SOURCE (source);
+}
+
+static void 
+entry_set_string_prop (RhythmDB *db, RhythmDBEntry *entry,
+		       RhythmDBPropType propid, const char *str)
+{
+	GValue value = {0,};
+
+	g_value_init (&value, G_TYPE_STRING);
+	g_value_set_string (&value, str ? str : _("Unknown"));
+	rhythmdb_entry_set (RHYTHMDB (db), entry, propid, &value);
+	g_value_unset (&value);
+}
+
+static RhythmDBEntry*
+cddasrc_create_track_entry (RBAudioCdSource *source, RhythmDB *db, GstElement *cdda, guint i)
+{
+	RhythmDBEntry *entry;
+	char *audio_path = g_strdup_printf ("cdda://%d", i);
+	GValue value = {0, };
+	gchar *str;
+	GstFormat fmt;
+	gint64 track_duration = 0;
+
+	rb_debug ("Audio CD - create entry for track %d from %s", i, audio_path);
+	entry = rhythmdb_entry_new (db, rb_source_get_entry_type (RB_SOURCE (source)), audio_path);
+#if 0
+	g_value_init (&value, G_TYPE_UINT);
+	g_value_set_uint (&value, i);
+	g_object_set_property (G_OBJECT (cdda), "track", &value);
+	g_value_unset (&value);
+
+	/* process duration */
+	fmt = GST_FORMAT_TIME;
+	gst_pad_query (gst_element_get_pad (cdda, "src"), GST_QUERY_TOTAL, &fmt, &track_duration);
+
+	if (track_duration != 0) {
+		g_value_init (&value, G_TYPE_ULONG);
+		g_value_set_ulong (&value, track_duration / 1000000000);
+		rhythmdb_entry_set (RHYTHMDB (db), entry, 
+				    RHYTHMDB_PROP_DURATION, 
+				    &value);
+		g_value_unset (&value);
+	}
+#endif
+
+	/* generate track # */
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value, i);
+	rhythmdb_entry_set (RHYTHMDB (db), entry,
+			    RHYTHMDB_PROP_TRACK_NUMBER, 
+			    &value);
+	g_value_unset (&value);
+
+	/* generate track name */
+	g_value_init (&value, G_TYPE_STRING);
+	str = g_strdup_printf (_("Track %u"), i);
+	g_value_take_string (&value, str);
+	rhythmdb_entry_set (RHYTHMDB (db), entry,
+			    RHYTHMDB_PROP_TITLE, 
+			    &value);
+	g_value_unset (&value);
+
+
+	entry_set_string_prop (db, entry, RHYTHMDB_PROP_ARTIST, NULL);
+	entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM, NULL);
+	entry_set_string_prop (db, entry, RHYTHMDB_PROP_GENRE, NULL);
+
+	rhythmdb_commit (RHYTHMDB (db));
+
+	return entry;
+}
+
+static gboolean
+cddasrc_get_cd_info (GstElement *cdda, gint64 *num_tracks, char **disc_id)
+{
+	GstFormat fmt = gst_format_get_by_nick ("track");
+	if (!fmt) {
+		rb_debug ("failed to create cd track format");
+		return FALSE;
+	}
+	if (!gst_pad_query (gst_element_get_pad (cdda, "src"),
+				GST_QUERY_TOTAL, &fmt, num_tracks)) {
+		rb_debug ("failed to read cd track count");
+		gst_element_set_state (cdda, GST_STATE_NULL);
+		return FALSE;
+	}
+
+	{
+		GValue value = {0, };
+		g_value_init (&value, G_TYPE_STRING);
+		g_object_get_property (G_OBJECT(cdda), "discid", &value);
+		*disc_id = g_strdup (g_value_get_string (&value));
+		g_value_unset (&value);
+	}
+
+	return TRUE;
+}
+
+static void
+rb_audiocd_load_songs_cddasrc (RBAudioCdSource *source, RhythmDB *db, GstElement *cdda)
+{
+	gint64 i;
+	GValue value = {0, };
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+
+	g_value_init (&value, G_TYPE_STRING);
+	g_value_set_string (&value, priv->device_path);
+	g_object_set_property (G_OBJECT (cdda), "device", &value);
+	g_value_unset (&value);
+
+	if (gst_element_set_state (cdda, GST_STATE_PAUSED) != GST_STATE_SUCCESS) {
+		rb_error_dialog (NULL, _("Couldn't load Audio CD"),
+					_("Rhythmbox couldn't access the cd."));
+		return;
+	}
+
+	if (!cddasrc_get_cd_info (cdda, &priv->num_tracks, &priv->disc_id))
+	{
+		rb_error_dialog (NULL, _("Couldn't load Audio CD"),
+					_("Rhythmbox could read the cd information."));
+		return;
+	}
+
+	rb_debug ("importing Audio Cd %s - %d tracks", priv->disc_id, priv->num_tracks);
+	for (i = 1; i <= priv->num_tracks; i++) {
+		RhythmDBEntry *entry = cddasrc_create_track_entry (source, db, cdda, i);
+		if (entry)
+			priv->tracks = g_list_append (priv->tracks, entry);
+		else
+			g_warning("Couldn't create entry for audio cd track");
+	}
+
+	if (gst_element_set_state (cdda, GST_STATE_NULL) != GST_STATE_SUCCESS) {
+		rb_debug ("failed to set cd state");
+	}
+}
+
+static void
+rb_audiocd_load_songs (RBAudioCdSource *source)
+{
+	RBShell *shell;
+	RhythmDB *db;
+	GnomeVFSVolume *volume;
+	GstElement *cdda;
+	RBEntryView *entry_view;
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+	
+	g_object_get (G_OBJECT (source), "volume", &volume, NULL);
+	priv->device_path = gnome_vfs_volume_get_device_path (volume);
+	g_object_unref (G_OBJECT (volume));
+	
+	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+	g_object_unref (G_OBJECT (shell));
+
+
+	rb_debug ("loading Audio CD from %s", priv->device_path);
+	/* create a cdda gstreamer element, to get cd info from */
+	cdda = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL);
+	if (!cdda) {
+		rb_error_dialog (NULL, _("Couldn't load Audio CD"),
+					_("Rhythmbox could not get access to the CD device."));
+		return;
+	}
+
+	/*
+	CD Audio (cdda) Source, Paranoia IV
+	*/
+	rb_debug ("cdda longname: %s", gst_element_factory_get_longname (gst_element_get_factory (cdda)));
+	rb_audiocd_load_songs_cddasrc (source, db, cdda);
+
+	/* we want audio cds to sort by track# by default */
+	entry_view = rb_source_get_entry_view (RB_SOURCE (source));
+	rb_entry_view_set_sorting_order (entry_view, "Track", GTK_SORT_DESCENDING);
+	/*rb_source_reset_filters (RB_SOURCE (source));*/
+
+	gst_object_unref (GST_OBJECT (cdda));
+	g_object_unref (G_OBJECT (db));
+
+	return;
+}
+
+static void
+rb_audiocd_unload_songs (RBAudioCdSource *source)
+{
+	RhythmDB *db;
+	RBShell *shell;
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+
+	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+	g_object_unref (G_OBJECT (shell));
+
+	rhythmdb_entry_delete_by_type (db, rb_source_get_entry_type (RB_SOURCE (source)));
+	rhythmdb_commit (db);
+	g_object_unref (db);
+
+	g_list_free (priv->tracks);
+}
+
+static void
+impl_audiocd_plugged (RBRemovableMediaSource *source)
+{
+	RBAudioCdSource *audiocd_source = RB_AUDIOCD_SOURCE (source);
+
+	rb_debug ("audio cd inserted\n");
+	rb_audiocd_load_songs (audiocd_source);
+}
+
+static void
+impl_audiocd_unplugged (RBRemovableMediaSource *source)
+{
+	RBAudioCdSource *audiocd_source = RB_AUDIOCD_SOURCE (source);
+
+	rb_debug ("audio cd ejected\n");
+	rb_audiocd_unload_songs (audiocd_source);
+}
+
+
+gboolean
+rb_audiocd_is_volume_audiocd (GnomeVFSVolume *volume)
+{
+	char *device_path;
+	GnomeVFSDeviceType device_type;
+	gboolean result = FALSE;
+
+	device_type = gnome_vfs_volume_get_device_type (volume);
+	device_path = gnome_vfs_volume_get_device_path (volume);
+	
+	/* for sometimes device_type is GNOME_VFS_DEVICE_TYPE_CDROM */
+	if (device_type == GNOME_VFS_DEVICE_TYPE_AUDIO_CD || device_type == GNOME_VFS_DEVICE_TYPE_CDROM) {
+		GError *error;
+		MediaType media_type;
+		
+		media_type = totem_cd_detect_type (device_path, &error);
+		rb_debug ("detecting new cd - totem cd media type=%d", media_type);
+		return (media_type == MEDIA_TYPE_CDDA);
+	}
+
+	return result;
+}
+
+
+static gboolean
+impl_show_popup (RBSource *source)
+{
+	_rb_source_show_popup (RB_SOURCE (source), "/AudioCdSourcePopup");
+	return TRUE;
+}
+
+static GtkWidget *
+impl_get_config_widget (RBSource *source)
+{
+	return NULL;
+}
+
+gboolean
+impl_receive_drag (RBSource *source, GtkSelectionData *data)
+{
+	rb_error_dialog (NULL,
+			 _("Not supported"),
+			 _("Audio CDs do not support drag and drop."));
+	return FALSE;
+}
--- /dev/null	2005-08-18 18:12:49.785368488 +1000
+++ sources/rb-audiocd-source.h	2005-08-17 20:51:37.000000000 +1000
@@ -0,0 +1,55 @@
+/*
+ *  arch-tag: Header for Audio CD source object
+ *
+ *  Copyright (C) 2005 James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __RB_AUDIOCD_SOURCE_H
+#define __RB_AUDIOCD_SOURCE_H
+
+#include "rb-shell.h"
+#include "rb-removable-media-source.h"
+#include "rhythmdb.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_AUDIOCD_SOURCE         (rb_audiocd_source_get_type ())
+#define RB_AUDIOCD_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_AUDIOCD_SOURCE, RBAudioCdSource))
+#define RB_AUDIOCD_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_AUDIOCD_SOURCE, RBAudioCdSourceClass))
+#define RB_IS_AUDIOCD_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_AUDIOCD_SOURCE))
+#define RB_IS_AUDIOCD_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_AUDIOCD_SOURCE))
+#define RB_AUDIOCD_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_AUDIOCD_SOURCE, RBAudioCdSourceClass))
+
+typedef struct
+{
+	RBRemovableMediaSource parent;
+} RBAudioCdSource;
+
+typedef struct
+{
+	RBRemovableMediaSourceClass parent;
+} RBAudioCdSourceClass;
+
+RBRemovableMediaSource *	rb_audiocd_source_new			(RBShell *shell, GnomeVFSVolume *volume);
+GType			rb_audiocd_source_get_type		(void);
+
+gboolean		rb_audiocd_is_volume_audiocd		(GnomeVFSVolume *volume);
+
+G_END_DECLS
+
+#endif /* __RB_AUDIOCD_SOURCE_H */
