Index: rhythmdb/rhythmdb-private.h
===================================================================
--- rhythmdb/rhythmdb-private.h	(Revision 6278)
+++ rhythmdb/rhythmdb-private.h	(Arbeitskopie)
@@ -155,9 +155,8 @@
 	GVolumeMonitor *volume_monitor;
 	GHashTable *monitored_directories;
 	GHashTable *changed_files;
-	guint library_location_notify_id;
 	guint changed_files_id;
-	GSList *library_locations;
+	GSList *monitored_locations;
 	guint monitor_notify_id;
 	GMutex *monitor_mutex;
 
Index: rhythmdb/rhythmdb-monitor.c
===================================================================
--- rhythmdb/rhythmdb-monitor.c	(Revision 6278)
+++ rhythmdb/rhythmdb-monitor.c	(Arbeitskopie)
@@ -159,8 +159,8 @@
 
 		loc = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
 
-		/* don't add add monitor if it's in the library path */
-		for (l = db->priv->library_locations; l != NULL; l = g_slist_next (l)) {
+		/* don't add a monitor if it's in the library path */
+		for (l = db->priv->monitored_locations; l != NULL; l = g_slist_next (l)) {
 			if (g_str_has_prefix (loc, (const char*)l->data))
 				return;
 				
@@ -264,8 +264,8 @@
 	g_thread_create ((GThreadFunc)_monitor_entry_thread, g_object_ref (db), FALSE, NULL);
 
 	/* monitor all library locations */
-	if (db->priv->library_locations)
-		g_slist_foreach (db->priv->library_locations, (GFunc) monitor_library_directory, db);
+	if (db->priv->monitored_locations)
+		g_slist_foreach (db->priv->monitored_locations, (GFunc) monitor_library_directory, db);
 }
 
 static void
@@ -300,23 +300,20 @@
         case G_FILE_MONITOR_EVENT_CREATED:
 		{
 			GSList *cur;
-			gboolean in_library = FALSE;
+			gboolean in_monitored_location = FALSE;
 
-			if (!eel_gconf_get_boolean (CONF_MONITOR_LIBRARY))
-				break;
-
 			if (rb_uri_is_hidden (canon_uri))
 				break;
 
-			/* ignore new files outside of the library locations */
-			for (cur = db->priv->library_locations; cur != NULL; cur = g_slist_next (cur)) {
+			/* ignore new files outside of a monitored location */
+			for (cur = db->priv->monitored_locations; cur != NULL; cur = g_slist_next (cur)) {
 				if (g_str_has_prefix (canon_uri, cur->data)) {
-					in_library = TRUE;
+					in_monitored_location = TRUE;
 					break;
 				}
 			}
 
-			if (!in_library)
+			if (!in_monitored_location)
 				break;
 		}
 
Index: rhythmdb/rhythmdb.c
===================================================================
--- rhythmdb/rhythmdb.c	(Revision 6278)
+++ rhythmdb/rhythmdb.c	(Arbeitskopie)
@@ -136,11 +136,7 @@
  					    const gchar *realuri);
 
 static gboolean rhythmdb_idle_save (RhythmDB *db);
-static void library_location_changed_cb (GConfClient *client,
-					  guint cnxn_id,
-					  GConfEntry *entry,
-					  RhythmDB *db);
-static void rhythmdb_sync_library_location (RhythmDB *db);
+static void rhythmdb_sync_monitored_locations (RhythmDB *db);
 static void rhythmdb_entry_sync_mirrored (RhythmDBEntry *entry,
 					  guint propid);
 static void rhythmdb_register_core_entry_types (RhythmDB *db);
@@ -700,7 +696,7 @@
 	rhythmdb_init_monitoring (db);
 
 	db->priv->monitor_notify_id = 
-		eel_gconf_notification_add (CONF_MONITOR_LIBRARY,
+		eel_gconf_notification_add (CONF_MONITOR_LIBRARY_LOCATIONS,
 					   (GConfClientNotifyFunc)rhythmdb_monitor_library_changed_cb,
 					   db);
 }
@@ -961,14 +957,10 @@
 	action->type = RHYTHMDB_ACTION_QUIT;
 	g_async_queue_push (db->priv->action_queue, action);
 
-	eel_gconf_notification_remove (db->priv->library_location_notify_id);
-	db->priv->library_location_notify_id = 0;
-	g_slist_foreach (db->priv->library_locations, (GFunc) g_free, NULL);
-	g_slist_free (db->priv->library_locations);
-	db->priv->library_locations = NULL;
-
 	eel_gconf_notification_remove (db->priv->monitor_notify_id);
 	db->priv->monitor_notify_id = 0;
+	rb_slist_deep_free (db->priv->monitored_locations);
+	db->priv->monitored_locations = NULL;
 
 	/* abort all async io operations */
 	g_mutex_lock (db->priv->stat_mutex);
@@ -2326,8 +2318,11 @@
 
 	/* monitor the file for changes */
 	/* FIXME: watch for errors */
-	if (eel_gconf_get_boolean (CONF_MONITOR_LIBRARY) && event->entry_type == RHYTHMDB_ENTRY_TYPE_SONG)
+	/* rhyhtmdb_monitor_uri_path calls actually_add_monitor, which checks
+	 * if entry->location is in one of the monitored dirs */
+	if (event->entry_type == RHYTHMDB_ENTRY_TYPE_SONG) {
 		rhythmdb_monitor_uri_path (event->db, rb_refstring_get (entry->location), NULL);
+	}
 
 	rhythmdb_add_timeout_commit (event->db, FALSE);
 
@@ -3063,7 +3058,7 @@
 static gboolean
 rhythmdb_sync_library_idle (RhythmDB *db)
 {
-	rhythmdb_sync_library_location (db);
+	rhythmdb_sync_monitored_locations (db);
 	g_object_unref (db);
 	return FALSE;
 }
@@ -4830,33 +4825,27 @@
 }
 
 static void
-rhythmdb_sync_library_location (RhythmDB *db)
+rhythmdb_sync_monitored_locations (RhythmDB *db)
 {
-	gboolean reload = (db->priv->library_locations != NULL);
+	GSList *list;
 
-	if (db->priv->library_location_notify_id == 0) {
-		db->priv->library_location_notify_id =
-			eel_gconf_notification_add (CONF_LIBRARY_LOCATION,
-						    (GConfClientNotifyFunc) library_location_changed_cb,
-						    db);
-	}
-
-	if (reload) {
+	if (db->priv->monitored_locations != NULL) {
 		rb_debug ("ending monitor of old library directories");
 
 		rhythmdb_stop_monitoring (db);
 
-		g_slist_foreach (db->priv->library_locations, (GFunc) g_free, NULL);
-		g_slist_free (db->priv->library_locations);
-		db->priv->library_locations = NULL;
+		rb_slist_deep_free (db->priv->monitored_locations);
+		db->priv->monitored_locations = NULL;
 	}
 
-	if (eel_gconf_get_boolean (CONF_MONITOR_LIBRARY)) {
+	list = eel_gconf_get_string_list (CONF_MONITOR_LIBRARY_LOCATIONS);
+	if (g_slist_length (list) > 0) {
 		rb_debug ("starting library monitoring");
-		db->priv->library_locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+		db->priv->monitored_locations = rb_string_slist_copy (list);
 
 		rhythmdb_start_monitoring (db);
 	}
+	rb_slist_deep_free (list);
 }
 
 static
@@ -4865,19 +4854,10 @@
 					  GConfEntry *entry,
 					  RhythmDB *db)
 {
-	rb_debug ("'watch library' key changed");
-	rhythmdb_sync_library_location (db);
+	rb_debug ("'monitor_locations' key changed");
+	rhythmdb_sync_monitored_locations (db);
 }
 
-static void
-library_location_changed_cb (GConfClient *client,
-			     guint cnxn_id,
-			     GConfEntry *entry,
-			     RhythmDB *db)
-{
-	rhythmdb_sync_library_location (db);
-}
-
 char *
 rhythmdb_entry_dup_string (RhythmDBEntry *entry,
 			   RhythmDBPropType propid)
Index: sources/rb-library-child-source.c
===================================================================
--- sources/rb-library-child-source.c	(Revision 0)
+++ sources/rb-library-child-source.c	(Revision 0)
@@ -0,0 +1,393 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2008 Christian Becke <christianbecke@gmail.com>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gconf/gconf.h>
+
+#include "rhythmdb.h"
+#include "rb-debug.h"
+#include "rb-preferences.h"
+#include "rb-browser-source.h"
+#include "rb-library-child-source.h"
+#include "eel-gconf-extensions.h"
+
+static void rb_library_child_source_class_init (RBLibraryChildSourceClass *klass);
+static void rb_library_child_source_init (RBLibraryChildSource *source);
+static void rb_library_child_source_finalize (GObject *object);
+static void rb_library_child_source_set_property (GObject *object,
+							guint prop_id,
+							const GValue *value,
+							GParamSpec *pspec);
+static void rb_library_child_source_get_property (GObject *object,
+							guint prop_id,
+							GValue *value,
+							GParamSpec *pspec);
+static void impl_delete_thyself (RBSource *source);
+
+static char *get_state_dir (const char *path);
+static gboolean delete_entry (GtkTreeModel *model,
+				GtkTreePath *path,
+				GtkTreeIter *iter,
+				RhythmDB *db);
+static char *get_display_name_for_uri (const char *uri);
+
+/* RBSource implementations */
+static char *impl_get_browser_key (RBSource *source);
+static char *impl_get_paned_key (RBBrowserSource *source);
+
+#define CONF_STATE_LIBRARY_DIR CONF_PREFIX "/state/library" /* Move this one to rb-preferences.h? */
+#define CONF_STATE_LIBRARY_CHILD_SORTING "/sorting"
+#define CONF_STATE_LIBRARY_CHILD_PANED_POSITION "/paned_position"
+#define CONF_STATE_LIBRARY_CHILD_SHOW_BROWSER "/show_browser"
+
+struct _RBLibraryChildSourcePrivate
+{
+	char *path;
+	
+	char *browser_key;
+	char *paned_key;
+
+	gboolean keep_songs_and_state;
+};
+
+enum
+{
+	PROP_0,
+	PROP_PATH
+};
+
+#define RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSourcePrivate))
+G_DEFINE_TYPE (RBLibraryChildSource, rb_library_child_source, RB_TYPE_BROWSER_SOURCE);
+
+static void
+rb_library_child_source_class_init (RBLibraryChildSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+	RBBrowserSourceClass *browser_source_class = RB_BROWSER_SOURCE_CLASS (klass);
+
+	object_class->finalize = rb_library_child_source_finalize;
+	object_class->get_property = rb_library_child_source_get_property;
+	object_class->set_property = rb_library_child_source_set_property;
+
+	source_class->impl_get_browser_key = impl_get_browser_key;
+	source_class->impl_delete_thyself = impl_delete_thyself;
+
+	browser_source_class->impl_get_paned_key = impl_get_paned_key;
+
+	g_object_class_install_property (object_class,
+					PROP_PATH,
+					g_param_spec_string ("path",
+							"path",
+							"Path to library",
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	
+	g_type_class_add_private (klass, sizeof (RBLibraryChildSourcePrivate));
+}
+
+static void
+rb_library_child_source_init (RBLibraryChildSource *source)
+{
+	source->priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (source);
+
+	source->priv->keep_songs_and_state = FALSE;
+}
+
+static void
+rb_library_child_source_finalize (GObject *object)
+{
+	RBLibraryChildSource *source;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (RB_IS_LIBRARY_CHILD_SOURCE (object));
+
+	source = RB_LIBRARY_CHILD_SOURCE (object);
+
+	g_return_if_fail (source->priv != NULL);
+
+	g_free (source->priv->path);
+	g_free (source->priv->browser_key);
+	g_free (source->priv->paned_key);
+
+	G_OBJECT_CLASS (rb_library_child_source_parent_class)->finalize (object);
+}
+
+static void
+rb_library_child_source_set_property (GObject *object,
+					guint prop_id,
+					const GValue *value,
+					GParamSpec *pspec)
+{
+	RBLibraryChildSource *source = RB_LIBRARY_CHILD_SOURCE (object);
+
+	switch (prop_id) {
+	case PROP_PATH:
+		source->priv->path = g_strdup (g_value_get_string (value));	
+		char *state_dir;
+		state_dir = get_state_dir (source->priv->path);
+		source->priv->browser_key = g_strconcat (state_dir,
+				CONF_STATE_LIBRARY_CHILD_SHOW_BROWSER, NULL);
+		source->priv->paned_key = g_strconcat (state_dir,
+				CONF_STATE_LIBRARY_CHILD_PANED_POSITION, NULL);	
+		g_free (state_dir);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_library_child_source_get_property (GObject *object,
+					guint prop_id,
+					GValue *value,
+					GParamSpec *pspec)
+{
+	RBLibraryChildSource *source = RB_LIBRARY_CHILD_SOURCE (object);
+
+	switch (prop_id) {
+	case PROP_PATH:
+		g_value_set_string (value, source->priv->path);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static char *
+get_display_name_for_uri (const char *uri)
+{
+	GFile *file;
+	GFileInfo *file_info;
+	GError *err = NULL;
+	char *name = NULL;
+
+	file = g_file_new_for_uri (uri);
+	file_info = g_file_query_info (file,
+			G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+			G_FILE_QUERY_INFO_NONE,
+			NULL,
+			&err);
+	
+	if (file != NULL) {
+		g_object_unref (file);
+	}
+
+	if (file_info == NULL) {
+		if (err != NULL) {
+			rb_debug ("g_file_query_info failed for '%s': %s",
+					uri, err->message);
+			g_error_free (err);
+		} else {
+			rb_debug ("g_file_query_info failed for '%s'", uri);
+		}
+		return NULL;
+	}
+
+	name = g_file_info_get_attribute_as_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
+	g_object_unref (file_info);
+	if (name == NULL) {
+		rb_debug ("g_file_info_get_attribute_string failed!");
+	}
+	
+	return name;
+}
+
+RBSource *
+rb_library_child_source_new (RBSource *parent_source, const char *path)
+{
+	RBSource *source;
+	RBShell *shell;
+	RhythmDB *db;
+	RhythmDBEntryType *entry_type;
+	GPtrArray *query;
+	GdkPixbuf *icon;
+	char *name;
+	char *state_dir;
+	char *sorting_key;
+
+	name = get_display_name_for_uri (path);
+
+	g_object_get (parent_source,
+			"shell", &shell,
+			"entry-type", &entry_type,
+			"icon", &icon,
+			NULL);
+
+	g_object_get (shell, "db", &db, NULL);
+	query = rhythmdb_query_parse (db,
+			RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
+			RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_LOCATION, path,
+			RHYTHMDB_QUERY_END);
+	g_object_unref (db);
+	
+	state_dir = get_state_dir (path);
+	sorting_key = g_strconcat (state_dir, CONF_STATE_LIBRARY_CHILD_SORTING, NULL);
+	g_free (state_dir);
+
+	source = RB_SOURCE (g_object_new (RB_TYPE_LIBRARY_CHILD_SOURCE,
+					"name", name,
+					"shell", shell,
+					"path", path,
+					"entry-type", entry_type,
+					"sorting-key", sorting_key,
+					"source-group", RB_SOURCE_GROUP_LIBRARY,
+					"icon", icon,
+					"query", query,
+					NULL));
+	
+	if (name != NULL) {
+		g_free (name);
+	}
+	g_object_unref (shell);
+	rhythmdb_query_free (query);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);	
+	g_free (sorting_key);
+	if (icon != NULL) {
+		g_object_unref (icon);
+	}
+
+	return source;
+}
+
+static char *
+get_state_dir (const char *path)
+{
+	char *state_dir;
+	char *path_escaped;
+
+	path_escaped = gconf_escape_key (path, strlen (path));
+	state_dir = g_strconcat (CONF_STATE_LIBRARY_DIR, "/", path_escaped, NULL);
+	g_free (path_escaped);
+	
+	return state_dir;
+}
+
+static char *
+impl_get_browser_key (RBSource *source)
+{
+	RBLibraryChildSourcePrivate *priv;
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (RB_LIBRARY_CHILD_SOURCE (source));
+
+	return g_strdup (priv->browser_key);
+}
+
+static char *
+impl_get_paned_key (RBBrowserSource *source)
+{
+	RBLibraryChildSourcePrivate *priv;
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (RB_LIBRARY_CHILD_SOURCE (source));
+
+	return g_strdup (priv->paned_key);
+}
+
+static gboolean
+delete_entry (GtkTreeModel *model,
+		GtkTreePath *path,
+		GtkTreeIter *iter,
+		RhythmDB *db)
+{
+	RhythmDBEntry *entry;
+	int position;
+	
+	gtk_tree_model_get (model, iter, 0, &entry, 1, &position, -1);
+
+	rb_debug ("deleting: %2d - '%s' - '%s' - '%s'",
+			position,
+			rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST),
+			rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM),
+		 	rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE));
+
+	rhythmdb_entry_delete (db, entry);
+
+	rhythmdb_entry_unref (entry);
+
+	return FALSE;
+}
+
+void
+rb_library_child_source_set_keep_songs_and_state (RBLibraryChildSource *source,
+							gboolean keep)
+{
+	RBLibraryChildSourcePrivate *priv;
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (source);
+
+	priv->keep_songs_and_state = keep;
+}
+
+static void
+impl_delete_thyself (RBSource *source)
+{
+	RBLibraryChildSourcePrivate *priv;
+
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (RB_LIBRARY_CHILD_SOURCE (source));
+	
+	if (priv->keep_songs_and_state == TRUE) {
+		rb_debug ("keeping songs and state.");
+		RB_SOURCE_CLASS (rb_library_child_source_parent_class)->impl_delete_thyself (source);
+		return;
+	}
+
+	rb_debug ("deleting songs and state.");
+
+	RBShell *shell;
+	RhythmDBQueryModel *model;
+	RhythmDB *db;
+	char *path;
+	char *state_dir;
+
+	g_object_get (source,
+			"shell", &shell,
+			"base-query-model", &model,
+			"path", &path,
+			NULL);
+	g_object_get (shell, "db", &db, NULL);
+	g_object_unref (shell);
+
+	/* remove songs from db */
+	gtk_tree_model_foreach (GTK_TREE_MODEL (model),
+			(GtkTreeModelForeachFunc)delete_entry,
+			db);
+	rhythmdb_commit (db);
+	g_object_unref (db);
+
+	state_dir = get_state_dir (path);
+	g_free (path);
+
+	/* remove state gconf keys */
+	eel_gconf_recursive_unset (state_dir);
+	eel_gconf_suggest_sync ();	
+	g_free (state_dir);
+
+	RB_SOURCE_CLASS (rb_library_child_source_parent_class)->impl_delete_thyself (source);
+}
+
Index: sources/rb-library-child-source.h
===================================================================
--- sources/rb-library-child-source.h	(Revision 0)
+++ sources/rb-library-child-source.h	(Revision 0)
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (C) 2008 Christian Becke <christianbecke@gmail.com>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __RB_LIBRARY_CHILD_SOURCE_H
+#define __RB_LIBRARY_CHILD_SOURCE_H
+
+#include "rb-browser-source.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_LIBRARY_CHILD_SOURCE         (rb_library_child_source_get_type ())
+#define RB_LIBRARY_CHILD_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSource))
+#define RB_LIBRARY_CHILD_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSourceClass))
+#define RB_IS_LIBRARY_CHILD_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_LIBRARY_CHILD_SOURCE))
+#define RB_IS_LIBRARY_CHILD_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_LIBRARY_CHILD_SOURCE))
+#define RB_LIBRARY_CHILD_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSourceClass))
+
+typedef struct _RBLibraryChildSourcePrivate RBLibraryChildSourcePrivate;
+
+typedef struct
+{
+	RBBrowserSource parent;
+
+	RBLibraryChildSourcePrivate *priv;
+} RBLibraryChildSource;
+
+typedef struct
+{
+	RBBrowserSourceClass parent;
+} RBLibraryChildSourceClass;
+
+GType		rb_library_child_source_get_type 	(void);
+RBSource *	rb_library_child_source_new		(RBSource *parent_source, const char *path);
+void		rb_library_child_source_set_keep_songs_and_state (RBLibraryChildSource *source, gboolean keep);
+G_END_DECLS
+
+#endif /* __RB_LIBRARY_CHILD_SOURCE_H */
Index: sources/rb-library-source.c
===================================================================
--- sources/rb-library-source.c	(Revision 6278)
+++ sources/rb-library-source.c	(Arbeitskopie)
@@ -67,6 +67,7 @@
 #include "rb-library-source.h"
 #include "rb-removable-media-manager.h"
 #include "rb-auto-playlist-source.h"
+#include "rb-library-child-source.h"
 
 static void rb_library_source_class_init (RBLibrarySourceClass *klass);
 static void rb_library_source_init (RBLibrarySource *source);
@@ -108,11 +109,12 @@
 					       guint cnxn_id,
 					       GConfEntry *entry,
 					       RBLibrarySource *source);
-static gboolean rb_library_source_library_location_cb (GtkEntry *entry,
-						       GdkEventFocus *event,
-						       RBLibrarySource *source);
-static void rb_library_source_watch_toggled_cb (GtkToggleButton *button,
-						RBLibrarySource *source);
+
+static void rb_library_source_add_child_source (RBLibrarySource *library_source,
+		const char *path);
+static void rb_library_source_remove_child_source (RBLibrarySource *library_source,
+		RBLibraryChildSource *child_source);
+
 static void rb_library_source_sync_child_sources (RBLibrarySource *source);
 static void rb_library_source_path_changed_cb (GtkComboBox *box,
 						RBLibrarySource *source);
@@ -122,6 +124,39 @@
 						 RBLibrarySource *source);
 static void layout_example_label_update (RBLibrarySource *source);
 
+static GSList *run_location_file_chooser (RBLibrarySource *source);
+static void show_invalid_locations_error_dialog (RBLibrarySource *source,
+		GSList *invalid_locations);
+static gboolean location_is_valid (GSList *library_locations,
+		const char *uri);
+static void rb_library_source_add_location_button_clicked_cb (GtkButton *button,
+		RBLibrarySource *source);
+
+static void rb_library_source_default_location_toggled_cb (GtkCellRendererToggle *cell,
+		const char *path,
+		RBLibrarySource *source);
+
+static RBLibraryChildSource *rb_library_source_get_child_source_for_uri (RBLibrarySource *source,
+		const char *uri);
+static void rb_library_source_remove_location_button_clicked_cb (GtkButton *button,
+		RBLibrarySource *source);
+static gint show_remove_library_location_message_dialog (RBLibrarySource *source,
+		GtkWidget *keep_metadata_button);
+
+static void rb_library_source_monitor_library_locations_changed (GConfClient *client,
+					    guint cnxn_id,
+					    GConfEntry *entry,
+					    RBLibrarySource *source);
+static void rb_library_source_monitor_library_locations_toggled_cb (GtkCellRendererToggle *cell,
+		const char *path,
+		RBLibrarySource *source);
+static void sync_monitored_locations (void);
+static void rb_library_source_default_library_location_changed (GConfClient *client,
+					    guint cnxn_id,
+					    GConfEntry *entry,
+					    RBLibrarySource *source);
+static void sync_default_library_location (void);
+
 #define CONF_UI_LIBRARY_DIR CONF_PREFIX "/ui/library"
 #define CONF_STATE_LIBRARY_DIR CONF_PREFIX "/state/library"
 #define CONF_STATE_LIBRARY_SORTING CONF_PREFIX "/state/library/sorting"
@@ -152,6 +187,13 @@
 };
 const int num_library_layout_filenames = G_N_ELEMENTS (library_layout_filenames);
 
+enum {
+	LOCATION_COLUMN_PATH,
+	LOCATION_COLUMN_DEFAULT_LIBRARY_LOCATION,
+	LOCATION_COLUMN_MONITOR_LIBRARY_LOCATIONS,
+	LOCATION_N_COLUMNS
+};
+
 struct RBLibrarySourcePrivate
 {
 	RhythmDB *db;
@@ -164,16 +206,18 @@
 	GList *child_sources;
 
 	GtkWidget *library_location_entry;
-	GtkWidget *watch_library_check;
 	GtkWidget *layout_path_menu;
 	GtkWidget *layout_filename_menu;
 	GtkWidget *preferred_format_menu;
 	GtkWidget *layout_example_label;
+	GtkWidget *locations_tree;
 
 	guint library_location_notify_id;
+	guint default_library_location_notify_id;
 	guint ui_dir_notify_id;
 	guint layout_path_notify_id;
 	guint layout_filename_notify_id;
+	guint monitor_library_locations_notify_id;
 };
 
 #define RB_LIBRARY_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_LIBRARY_SOURCE, RBLibrarySourcePrivate))
@@ -240,6 +284,11 @@
 		source->priv->library_location_notify_id = 0;
 	}
 
+	if (source->priv->default_library_location_notify_id != 0) {
+		eel_gconf_notification_remove (source->priv->default_library_location_notify_id);
+		source->priv->default_library_location_notify_id = 0;
+	}
+
 	if (source->priv->layout_path_notify_id != 0) {
 		eel_gconf_notification_remove (source->priv->layout_path_notify_id);
 		source->priv->layout_path_notify_id = 0;
@@ -250,6 +299,11 @@
 		source->priv->layout_filename_notify_id = 0;
 	}
 
+	if (source->priv->monitor_library_locations_notify_id != 0) {
+		eel_gconf_notification_remove (source->priv->monitor_library_locations_notify_id);
+		source->priv->monitor_library_locations_notify_id = 0;
+	}
+
 	G_OBJECT_CLASS (rb_library_source_parent_class)->dispose (object);
 }
 
@@ -307,7 +361,7 @@
 
 	rb_library_source_ui_prefs_sync (source);
 
-	/* Set up the default library location if there's no library location set */
+	/* Set up a library location if there's no library location set */
 	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
 	if (g_slist_length (list) == 0) {
 		char *music_dir_uri;
@@ -342,14 +396,28 @@
 	}
 	rb_slist_deep_free (list);
 
+	/* make sure default library location is sane */
+	sync_default_library_location ();
+	
+	/* make sure monitored library locations are sane */
+	sync_monitored_locations ();
+
 	source->priv->library_location_notify_id =
 		eel_gconf_notification_add (CONF_LIBRARY_LOCATION,
 				    (GConfClientNotifyFunc) rb_library_source_library_location_changed, source);
 
+	source->priv->default_library_location_notify_id =
+		eel_gconf_notification_add (CONF_DEFAULT_LIBRARY_LOCATION,
+				(GConfClientNotifyFunc) rb_library_source_default_library_location_changed, source);
+
 	source->priv->ui_dir_notify_id =
 		eel_gconf_notification_add (CONF_UI_LIBRARY_DIR,
 				    (GConfClientNotifyFunc) rb_library_source_ui_pref_changed, source);
 
+	source->priv->monitor_library_locations_notify_id =
+		eel_gconf_notification_add (CONF_MONITOR_LIBRARY_LOCATIONS,
+				(GConfClientNotifyFunc) rb_library_source_monitor_library_locations_changed, source);
+
 	songs = rb_source_get_entry_view (RB_SOURCE (source));
 
 	rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_RATING, FALSE);
@@ -416,34 +484,342 @@
 	gtk_dialog_run (GTK_DIALOG (dialog));
 }
 
-static void
-rb_library_source_location_button_clicked_cb (GtkButton *button, RBLibrarySource *source)
+static GSList *
+run_location_file_chooser (RBLibrarySource *source)
 {
 	GtkWidget *dialog;
+	GSList *uris = NULL;
 
+	rb_debug ("running location file chooser dialog");
+
 	dialog = rb_file_chooser_new (_("Choose Library Location"), GTK_WINDOW (source->priv->shell_prefs),
-				      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, FALSE);
+			GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, FALSE);
+	gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
-		char *uri;
-		char *path;
+		uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
+	}
+	gtk_widget_destroy (dialog);
+	return uris;
+}
 
-		uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+static void
+show_invalid_locations_error_dialog (RBLibrarySource *source, GSList *invalid_locations)
+{
+	GSList *i;
+	char *uris, *tmp, *uri;
+
+	uris = g_strdup ("");
+	for (i = invalid_locations; i != NULL; i = g_slist_next (i)) {
+		if (i->data == NULL) {
+			continue;
+		}
+		tmp = g_uri_unescape_string ((char *)i->data, NULL);
+		uri = g_strdup_printf ("%s\n", tmp);
+		g_free (tmp);
+
+		tmp = g_strconcat (uris, uri, NULL);
+		g_free (uris);
+		g_free (uri);
+
+		uris = tmp;
+	}
+
+	rb_error_dialog (GTK_WINDOW (source->priv->shell_prefs),
+			_("Some locations could not be added"),
+			_("The following locations could not be added to the list of library locations:\n\n"
+				"%s\n"
+				"Possible reasons: either the location itself, one of its subfolders, "
+				"or one of its parent folders is already added.\n"
+				"Nested folders can not be added as library locations."),
+			uris);
+	g_free (uris);
+}
+
+static gboolean
+location_is_valid (GSList *library_locations, const char *uri)
+{
+	GSList *i;
+	gboolean is_valid = TRUE;
+	GFile *new, *tmp;
+
+	new = g_file_new_for_uri (uri);
+	for (i = library_locations; i != NULL; i = g_slist_next (i)) {
+		tmp = g_file_new_for_uri ((char *)i->data);
+		is_valid = !(g_file_equal (tmp, new) || g_file_has_prefix (tmp, new) || g_file_has_prefix (new, tmp));
+		g_object_unref (G_OBJECT (tmp));
+		if (!is_valid) {
+			break;
+		}
+	}
+	g_object_unref (G_OBJECT (new));
+
+	return is_valid;
+}
+
+static void
+rb_library_source_add_location_button_clicked_cb (GtkButton *button, RBLibrarySource *source)
+{
+	GSList *uris, *i;
+	GSList *invalid_locations = NULL;
+	GSList *library_locations;
+	char *uri;
+	gboolean location_added = FALSE;
+
+	rb_debug ("add_location button clicked");
+
+	library_locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+
+	uris = run_location_file_chooser (source);
+	for (i = uris; i != NULL; i = g_slist_next (i)) {
+		uri = (char *)i->data;
 		if (uri == NULL) {
-			uri = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
+			rb_debug ("got NULL uri from GtkFileChooser!");
+			continue;
 		}
+		
+		if (location_is_valid (library_locations, uri)) {
+			library_locations = g_slist_prepend (library_locations, g_strdup (uri));
+			location_added = TRUE;
+			rb_debug ("location '%s' added", uri);
+		} else {
+			invalid_locations = g_slist_prepend (invalid_locations, g_strdup (uri));
+			rb_debug ("invalid location '%s'", uri);
+		}
+	}
+	rb_slist_deep_free (uris);
 
-		path = g_uri_unescape_string (uri, NULL);
+	if (location_added) {
+		eel_gconf_set_string_list (CONF_LIBRARY_LOCATION, library_locations);
+	}
+	rb_slist_deep_free (library_locations);
 
-		gtk_entry_set_text (GTK_ENTRY (source->priv->library_location_entry), path);
-		rb_library_source_library_location_cb (GTK_ENTRY (source->priv->library_location_entry),
-						       NULL, source);
-		g_free (uri);
+	if (g_slist_length (invalid_locations) > 0) {
+		show_invalid_locations_error_dialog (source, invalid_locations);
+	}
+	rb_slist_deep_free (invalid_locations);
+}
+
+static void
+rb_library_source_monitor_library_locations_toggled_cb (GtkCellRendererToggle *cell,
+		const char *path,
+		RBLibrarySource *source)
+{
+	GtkTreeModel *model;
+	GtkTreeIter it;
+	char *uri;
+	gboolean do_monitor;
+	GSList *monitor_locations, *found;
+	gboolean update = FALSE;
+	
+	rb_debug ("monitor library location toggled");
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (source->priv->locations_tree));
+
+	if (!gtk_tree_model_get_iter_from_string (model, &it, path)) {
+		rb_debug ("invalid tree path '%s'", path);
+		return;
+	}
+
+	gtk_tree_model_get (model, &it,
+			LOCATION_COLUMN_PATH, &uri,
+			LOCATION_COLUMN_MONITOR_LIBRARY_LOCATIONS, &do_monitor,
+			-1);
+
+	if (uri == NULL) {
+		rb_debug ("NULL uri in locations_tree!");
+		return;
+	}
+
+	do_monitor = (!do_monitor); /* toggle! */
+
+	monitor_locations = eel_gconf_get_string_list (CONF_MONITOR_LIBRARY_LOCATIONS);
+	found = g_slist_find_custom (monitor_locations, uri, (GCompareFunc)strcmp);
+	if (do_monitor) {
+		if (found == NULL) {
+			monitor_locations = g_slist_prepend (monitor_locations, g_strdup (uri));
+			update = TRUE;
+		}
+	} else {
+		if (found != NULL) {
+			monitor_locations = g_slist_delete_link (monitor_locations, found);
+			update = TRUE;
+		}
+	}
+	g_free (uri);
+
+	if (update) {
+		eel_gconf_set_string_list (CONF_MONITOR_LIBRARY_LOCATIONS, monitor_locations);
+	}
+	rb_slist_deep_free (monitor_locations);
+}
+
+static void
+rb_library_source_default_location_toggled_cb (GtkCellRendererToggle *cell,
+		const char *path,
+		RBLibrarySource *source)
+{
+	GtkTreeModel *model;
+	GtkTreeIter it;
+	char *uri;
+
+	rb_debug ("default dest toggled");
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (source->priv->locations_tree));
+
+	if (!gtk_tree_model_get_iter_from_string (model, &it, path)) {
+		rb_debug ("invalid tree path '%s'", path);
+		return;
+	}
+
+	gtk_tree_model_get (model, &it, LOCATION_COLUMN_PATH, &uri, -1);
+	if (uri == NULL) {
+		rb_debug ("NULL uri in locations_tree!");
+		return;
+	}
+	
+	eel_gconf_set_string (CONF_DEFAULT_LIBRARY_LOCATION, uri);
+	g_free (uri);
+}
+
+static RBLibraryChildSource *
+rb_library_source_get_child_source_for_uri (RBLibrarySource *source, const char *uri)
+{
+	GList *i;
+	RBLibraryChildSource *child_source, *found = NULL;
+	char *path;
+
+	rb_debug ("searching child_source for uri '%s'", uri);
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	for (i = source->priv->child_sources; i != NULL; i = g_list_next (i)) {
+		child_source = (RBLibraryChildSource *)i->data;
+		g_object_get (G_OBJECT (child_source),
+				"path", &path,
+				NULL);
+
+		if (path == NULL) {
+			rb_debug ("child source [%p] with path == NULL!", child_source);
+			continue;
+		}
+
+		if (strcmp (uri, path) == 0) {
+			rb_debug ("found child_source [%p]", child_source);
+			found = child_source;
+		}
 		g_free (path);
+
+		if (found != NULL) {
+			break;
+		}
 	}
 
+	return found;
+}
+
+static gint
+show_remove_library_location_message_dialog (RBLibrarySource *source, GtkWidget *keep_metadata_button)
+{
+	GtkWidget *dialog;
+	GtkWidget *content_area;
+	gint ret;
+
+	dialog = gtk_message_dialog_new (GTK_WINDOW (source->priv->shell_prefs),
+			GTK_DIALOG_DESTROY_WITH_PARENT,
+			GTK_MESSAGE_QUESTION,
+			GTK_BUTTONS_OK_CANCEL,
+			"%s", _("Remove Library Location"));
+
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+			"%s", _("Rhythmbox will no longer track changes for the removed library location.\n"
+				"If you want to remove all tracks stored in this location from your library, "
+				"and remove all meta data (e.g. ratings, playcounts) for these tracks as well, "
+				"uncheck the check button below.\n"
+				"No files will actually be deleted."));
+
+	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+	g_object_ref (G_OBJECT (keep_metadata_button));
+	gtk_box_pack_end (GTK_BOX (content_area), keep_metadata_button, FALSE, FALSE, 6);
+	gtk_widget_show (keep_metadata_button);
+
+	gtk_window_set_title (GTK_WINDOW (dialog), "");
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+
+	ret = gtk_dialog_run (GTK_DIALOG (dialog));
 	gtk_widget_destroy (GTK_WIDGET (dialog));
+	return ret;
 }
 
+static void
+rb_library_source_remove_location_button_clicked_cb (GtkButton *button, RBLibrarySource *source)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GList *selected_rows, *i;
+	GtkWidget *keep_metadata_button;
+	gboolean location_removed = FALSE;
+
+	rb_debug ("removing location");
+	
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source->priv->locations_tree));
+	selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
+	keep_metadata_button = gtk_check_button_new_with_mnemonic (_("_Keep tracks and meta data"));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (keep_metadata_button), TRUE);
+	if (GTK_RESPONSE_OK == show_remove_library_location_message_dialog (source, keep_metadata_button)) {
+		GSList *library_locations, *found;
+		gboolean keep_metadata;
+		GtkTreePath *path;
+		GtkTreeIter it;
+		char *uri;
+		RBLibraryChildSource *child_source;
+		
+		library_locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+		
+		keep_metadata = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (keep_metadata_button));
+
+		for (i = selected_rows; i != NULL; i = g_list_next (i)) {
+			path = (GtkTreePath *)i->data;
+			if (!gtk_tree_model_get_iter (model, &it, path)) {
+				rb_debug ("invalid GtkTreePath in selected_rows: '%s'",
+						gtk_tree_path_to_string (path));
+				continue;
+			}
+			
+			gtk_tree_model_get (model, &it, LOCATION_COLUMN_PATH, &uri, -1);
+			
+			if (uri == NULL) {
+				rb_debug ("NULL uri in locations_tree!");
+				continue;
+			}
+
+			found = g_slist_find_custom (library_locations, uri, (GCompareFunc)strcmp);
+			if (found != NULL) {
+				/* remove location */				
+				child_source = rb_library_source_get_child_source_for_uri (source, uri);
+				if (child_source != NULL) {
+					rb_debug ("setting keep_metadata for child_source [%p] to %s",
+							child_source, (keep_metadata)?"true":"false");
+					rb_library_child_source_set_keep_songs_and_state (child_source, keep_metadata);
+				}
+
+				library_locations = g_slist_delete_link (library_locations, found);
+				location_removed = TRUE;
+				rb_debug ("location '%s' removed", uri);
+			}
+
+			g_free (uri);
+		}
+
+		if (location_removed) {		
+			eel_gconf_set_string_list (CONF_LIBRARY_LOCATION, library_locations);
+		}
+		rb_slist_deep_free (library_locations);
+	}
+	gtk_widget_destroy (keep_metadata_button);
+	rb_list_destroy_free (selected_rows, (GDestroyNotify)gtk_tree_path_free);
+}
+
 static GtkWidget *
 impl_get_config_widget (RBSource *asource, RBShellPreferences *prefs)
 {
@@ -452,10 +828,17 @@
 	GladeXML *xml;
 	GtkWidget *label;
 	int i;
+	GtkListStore *liststore;
+	GtkCellRenderer *cell;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
 
+	rb_debug ("impl_get_config_widget");
+
 	if (source->priv->config_widget)
 		return source->priv->config_widget;
 
+
 	g_object_ref (G_OBJECT (prefs));
 	source->priv->shell_prefs = prefs;
 
@@ -465,22 +848,59 @@
 
 	rb_glade_boldify_label (xml, "library_location_label");
 
-	source->priv->library_location_entry = glade_xml_get_widget (xml, "library_location_entry");
-	tmp = glade_xml_get_widget (xml, "library_location_button");
+	source->priv->locations_tree = glade_xml_get_widget (xml, "library_locations_treeview");
+	liststore = gtk_list_store_new (LOCATION_N_COLUMNS,
+			G_TYPE_STRING,
+			G_TYPE_BOOLEAN,
+			G_TYPE_BOOLEAN);
+	gtk_tree_view_set_model (GTK_TREE_VIEW (source->priv->locations_tree), GTK_TREE_MODEL (liststore));
+	g_object_unref (G_OBJECT (liststore));
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source->priv->locations_tree));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+		
+	cell = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes (_("Locations"),
+			cell,
+			"text", LOCATION_COLUMN_PATH,
+			NULL);
+	gtk_tree_view_column_set_expand (column, TRUE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (source->priv->locations_tree), column);
+
+	cell = gtk_cell_renderer_toggle_new ();
+	gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (cell), TRUE);
+	g_signal_connect (G_OBJECT (cell),
+		"toggled",
+		G_CALLBACK (rb_library_source_default_location_toggled_cb),
+		asource);
+	column = gtk_tree_view_column_new_with_attributes (_("Default Location"),
+		cell,
+		"active", LOCATION_COLUMN_DEFAULT_LIBRARY_LOCATION,
+		NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (source->priv->locations_tree), column);
+
+	cell = gtk_cell_renderer_toggle_new ();
+	g_signal_connect (G_OBJECT (cell),
+			"toggled",
+			G_CALLBACK (rb_library_source_monitor_library_locations_toggled_cb),
+			asource);
+	column = gtk_tree_view_column_new_with_attributes (_("Watch for new files"),
+			cell,
+			"active", LOCATION_COLUMN_MONITOR_LIBRARY_LOCATIONS,
+			NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (source->priv->locations_tree), column);
+
+	tmp = glade_xml_get_widget (xml, "add_library_location_button");
 	g_signal_connect (G_OBJECT (tmp),
-			  "clicked",
-			  G_CALLBACK (rb_library_source_location_button_clicked_cb),
-			  asource);
-	g_signal_connect (G_OBJECT (source->priv->library_location_entry),
-			  "focus-out-event",
-			  G_CALLBACK (rb_library_source_library_location_cb),
-			  asource);
+			"clicked",
+			G_CALLBACK (rb_library_source_add_location_button_clicked_cb),
+			asource);
 
-	source->priv->watch_library_check = glade_xml_get_widget (xml, "watch_library_check");
-	g_signal_connect (G_OBJECT (source->priv->watch_library_check),
-			  "toggled",
-			  G_CALLBACK (rb_library_source_watch_toggled_cb),
-			  asource);
+	tmp = glade_xml_get_widget (xml, "remove_library_location_button");
+	g_signal_connect (G_OBJECT (tmp),
+			"clicked",
+			G_CALLBACK (rb_library_source_remove_location_button_clicked_cb),
+			asource);
 
 	rb_glade_boldify_label (xml, "library_structure_label");
 
@@ -538,11 +958,106 @@
 }
 
 static void
+sync_default_library_location (void)
+{
+	GSList *library_locations;
+	char *default_library_location;
+
+	library_locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	default_library_location = eel_gconf_get_string (CONF_DEFAULT_LIBRARY_LOCATION);
+	if (default_library_location == NULL || !rb_string_slist_contains (library_locations, default_library_location)) {
+		if (library_locations != NULL && library_locations->data != NULL) {
+			eel_gconf_set_string (CONF_DEFAULT_LIBRARY_LOCATION, (char *)library_locations->data);
+		} else {
+			eel_gconf_set_string (CONF_DEFAULT_LIBRARY_LOCATION, "");
+		}
+	}
+	g_free (default_library_location);
+	rb_slist_deep_free (library_locations);
+}
+
+static void
+sync_default_library_location_internal (RBLibrarySource *source)
+{
+	gboolean removed = FALSE;
+
+	if (source->priv->default_library_location_notify_id != 0) {
+		eel_gconf_notification_remove (source->priv->default_library_location_notify_id);
+		removed = TRUE;
+	}
+	
+	sync_default_library_location ();
+	
+	if (removed) {
+		source->priv->default_library_location_notify_id =
+			eel_gconf_notification_add (CONF_DEFAULT_LIBRARY_LOCATION,
+					(GConfClientNotifyFunc) rb_library_source_default_library_location_changed,
+					source);
+	}
+}
+
+static void
+sync_monitored_locations (void)
+{
+	GSList *monitored_locations;
+
+	monitored_locations = eel_gconf_get_string_list (CONF_MONITOR_LIBRARY_LOCATIONS);
+	if (monitored_locations != NULL) {
+		GSList *library_locations, *i, *remove = NULL;
+		gboolean location_removed = FALSE;
+
+		library_locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+
+		for (i = monitored_locations; i != NULL; i = g_slist_next (i)) {
+			if (!rb_string_slist_contains (library_locations, (char *)i->data)) {
+				remove = g_slist_prepend (remove, i);
+				location_removed = TRUE;
+			}
+		}
+		rb_slist_deep_free (library_locations);
+		
+		for (i = remove; i != NULL; i = g_slist_next (i)) {
+			monitored_locations = g_slist_remove_link (monitored_locations, (GSList *)i->data);
+		}
+
+		if (location_removed) {
+			eel_gconf_set_string_list (CONF_MONITOR_LIBRARY_LOCATIONS, monitored_locations);
+		}
+	}
+	rb_slist_deep_free (monitored_locations);
+}
+
+static void
+sync_monitored_locations_internal (RBLibrarySource *source)
+{
+	gboolean removed = FALSE;
+
+	if (source->priv->monitor_library_locations_notify_id != 0) {
+		eel_gconf_notification_remove (source->priv->monitor_library_locations_notify_id);
+		removed = TRUE;
+	}
+	
+	sync_monitored_locations ();
+	
+	if (removed) {
+		source->priv->monitor_library_locations_notify_id =
+			eel_gconf_notification_add (CONF_MONITOR_LIBRARY_LOCATIONS,
+					(GConfClientNotifyFunc) rb_library_source_monitor_library_locations_changed,
+					source);
+	}
+}
+
+static void
 rb_library_source_library_location_changed (GConfClient *client,
 					    guint cnxn_id,
 					    GConfEntry *entry,
 					    RBLibrarySource *source)
 {
+	rb_debug ("library locations changed");
+
+	sync_default_library_location ();
+	sync_monitored_locations ();
+
 	if (source->priv->config_widget)
 		rb_library_source_preferences_sync (source);
 
@@ -550,6 +1065,37 @@
 }
 
 static void
+rb_library_source_default_library_location_changed (GConfClient *client,
+					    guint cnxn_id,
+					    GConfEntry *entry,
+					    RBLibrarySource *source)
+{
+	rb_debug ("default library location changed");
+	/* Check if changes are sane, but make sure this callback isn't called
+	 * again if some changes have to be reverted. */
+	sync_default_library_location_internal (source);
+
+	if (source->priv->config_widget)
+		rb_library_source_preferences_sync (source);
+}
+
+static void
+rb_library_source_monitor_library_locations_changed (GConfClient *client,
+					    guint cnxn_id,
+					    GConfEntry *entry,
+					    RBLibrarySource *source)
+{
+	rb_debug ("monitored library locations changed");
+
+	/* Check if changes are sane, but make sure this callback isn't called
+	 * again if some changes have to be reverted. */
+	sync_monitored_locations_internal (source);
+
+	if (source->priv->config_widget)
+		rb_library_source_preferences_sync (source);
+}
+
+static void
 rb_library_source_ui_prefs_sync (RBLibrarySource *source)
 {
 	if (source->priv->config_widget)
@@ -569,48 +1115,40 @@
 static void
 rb_library_source_preferences_sync (RBLibrarySource *source)
 {
-	GSList *list;
+	GSList *list, *i;
 	char *str;
 	GConfClient *gconf_client;
+	GtkTreeModel *model;
+	GtkTreeIter it;
+	char *uri;
+	char *default_dest_uri;
+	gboolean is_default_dest;
+	GSList *monitor_locations;
+	gboolean is_monitored;
 
 	rb_debug ("syncing pref dialog state");
 
 	/* library location */
 	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
-
-	/* don't trigger the change notification */
-	g_signal_handlers_block_by_func (G_OBJECT (source->priv->library_location_entry),
-					 G_CALLBACK (rb_library_source_library_location_cb),
-					 source);
-
-	if (g_slist_length (list) == 1) {
-		char *path;
-
-		gtk_widget_set_sensitive (source->priv->library_location_entry, TRUE);
-
-		path = g_uri_unescape_string (list->data, NULL);
-		gtk_entry_set_text (GTK_ENTRY (source->priv->library_location_entry), path);
-		g_free (path);
-	} else if (g_slist_length (list) == 0) {
-		/* no library directories */
-		gtk_widget_set_sensitive (source->priv->library_location_entry, TRUE);
-		gtk_entry_set_text (GTK_ENTRY (source->priv->library_location_entry), "");
-	} else {
-		/* multiple library directories */
-		gtk_widget_set_sensitive (source->priv->library_location_entry, FALSE);
-		gtk_entry_set_text (GTK_ENTRY (source->priv->library_location_entry), _("Multiple locations set"));
+	default_dest_uri = eel_gconf_get_string (CONF_DEFAULT_LIBRARY_LOCATION);
+	monitor_locations = eel_gconf_get_string_list (CONF_MONITOR_LIBRARY_LOCATIONS);
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (source->priv->locations_tree));
+	gtk_list_store_clear (GTK_LIST_STORE (model));
+	for (i = list; i != NULL; i = g_slist_next (i)) {
+		uri = (char *)i->data;
+		is_default_dest = (uri != NULL && default_dest_uri != NULL && strcmp (uri, default_dest_uri) == 0)? TRUE : FALSE;
+		is_monitored = rb_string_slist_contains (monitor_locations, uri);
+		gtk_list_store_append (GTK_LIST_STORE (model), &it);
+		gtk_list_store_set (GTK_LIST_STORE (model), &it,
+				LOCATION_COLUMN_PATH, uri,
+				LOCATION_COLUMN_DEFAULT_LIBRARY_LOCATION, is_default_dest,
+				LOCATION_COLUMN_MONITOR_LIBRARY_LOCATIONS, is_monitored,
+				-1);
 	}
-
-	g_signal_handlers_unblock_by_func (G_OBJECT (source->priv->library_location_entry),
-					   G_CALLBACK (rb_library_source_library_location_cb),
-					   source);
-
+	g_free (default_dest_uri);
 	rb_slist_deep_free (list);
+	rb_slist_deep_free (monitor_locations);
 
-	/* watch checkbox */
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (source->priv->watch_library_check),
-				      eel_gconf_get_boolean (CONF_MONITOR_LIBRARY));
-
 	/* preferred format */
 	str = eel_gconf_get_string (CONF_LIBRARY_PREFERRED_FORMAT);
 	if (str) {
@@ -636,40 +1174,6 @@
 						   source);
 }
 
-static gboolean
-rb_library_source_library_location_cb (GtkEntry *entry,
-				       GdkEventFocus *event,
-				       RBLibrarySource *source)
-{
-	GSList *list = NULL;
-	const char *path;
-	GFile *file;
-	char *uri;
-
-	path = gtk_entry_get_text (entry);
-	file = g_file_parse_name (path);
-	uri = g_file_get_uri (file);
-	g_object_unref (file);
-
-	if (uri && uri[0])
-		list = g_slist_prepend (NULL, (gpointer)uri);
-
-	eel_gconf_set_string_list (CONF_LIBRARY_LOCATION, list);
-
-	rb_slist_deep_free (list);
-
-	return FALSE;
-}
-
-static void
-rb_library_source_watch_toggled_cb (GtkToggleButton *button, RBLibrarySource *source)
-{
-	gboolean active;
-
-	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (source->priv->watch_library_check));
-	eel_gconf_set_boolean (CONF_MONITOR_LIBRARY, active);
-}
-
 static char *
 impl_get_browser_key (RBSource *source)
 {
@@ -1088,17 +1592,17 @@
 	char *string = NULL;
 	char *extension = NULL;
 	char *tmp;
-	GSList *list;
+	char *default_library_location;
 	char *layout_path;
 	char *layout_filename;
 	char *preferred_format;
 
-	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	default_library_location = eel_gconf_get_string (CONF_DEFAULT_LIBRARY_LOCATION);
 	layout_path = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_PATH);
 	layout_filename = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_FILENAME);
 	preferred_format = eel_gconf_get_string (CONF_LIBRARY_PREFERRED_FORMAT);
 
-	if (list == NULL || layout_path == NULL || layout_filename == NULL || preferred_format == NULL) {
+	if (default_library_location == NULL || layout_path == NULL || layout_filename == NULL || preferred_format == NULL) {
 		/* emit warning */
 		rb_debug ("Could not retrieve settings from GConf");
 		goto out;
@@ -1110,7 +1614,7 @@
 
 	realpath = filepath_parse_pattern (layout_path, entry);
 
-	library_location = g_file_new_for_uri ((const char *)list->data);
+	library_location = g_file_new_for_uri (default_library_location);
 	dir = g_file_resolve_relative_path (library_location, realpath);
 	g_object_unref (library_location);
 	g_free (realpath);
@@ -1158,7 +1662,7 @@
 	string = g_file_get_uri (dest);
 	g_object_unref (dest);
  out:
-	rb_slist_deep_free (list);
+	g_free (default_library_location);
 	g_free (layout_path);
 	g_free (layout_filename);
 	g_free (preferred_format);
@@ -1169,13 +1673,13 @@
 static gboolean
 impl_can_paste (RBSource *asource)
 {
-	GSList *list;
+	char *default_library_location;
 	gboolean can_paste = TRUE;
 	char *str;
 
-	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
-	can_paste = (list != NULL);
-	rb_slist_deep_free (list);
+	default_library_location = eel_gconf_get_string (CONF_DEFAULT_LIBRARY_LOCATION);
+	can_paste = (default_library_location != NULL);
+	g_free (default_library_location);
 
 	str = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_PATH);
 	can_paste &= (str != NULL);
@@ -1285,69 +1789,86 @@
 }
 
 static void
-rb_library_source_add_child_source (const char *path, RBLibrarySource *library_source)
+rb_library_source_add_child_source (RBLibrarySource *library_source, const char *path)
 {
 	RBSource *source;
-	GPtrArray *query;
 	RBShell *shell;
-	char *name;
-	GdkPixbuf *icon;
-	RhythmDBEntryType entry_type;
-	char *sort_column;
-	int sort_order;
-	GFile *file;
 
 	g_object_get (library_source,
 		      "shell", &shell,
-		      "entry-type", &entry_type,
 		      NULL);
 
-	file = g_file_new_for_uri (path);		/* ? */
-	name = g_file_get_basename (file);
-	g_object_unref (file);
+	source = rb_library_child_source_new (RB_SOURCE (library_source), path);
 
-	rb_entry_view_get_sorting_order (rb_source_get_entry_view (RB_SOURCE (library_source)),
-					 &sort_column, &sort_order);
-
-	source = rb_auto_playlist_source_new (shell, name, FALSE);
-	query = rhythmdb_query_parse (library_source->priv->db,
-				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
-				      RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_LOCATION, path,
-				      RHYTHMDB_QUERY_END);
-	rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (source), query,
-					   RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
-					   sort_column, sort_order);
-	rhythmdb_query_free (query);
-	g_free (sort_column);
-
-	g_object_get (library_source, "icon", &icon, NULL);
-	g_object_set (source, "icon", icon, NULL);
-	if (icon != NULL) {
-		g_object_unref (icon);
-	}
-
 	rb_shell_append_source (shell, source, RB_SOURCE (library_source));
 	library_source->priv->child_sources = g_list_prepend (library_source->priv->child_sources, source);
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	rb_debug ("added child source [%p] for uri '%s'", source, path);
+
 	g_object_unref (shell);
-	g_free (name);
 }
 
 static void
+rb_library_source_remove_child_source (RBLibrarySource *library_source,
+		RBLibraryChildSource *child_source)
+{
+	char *path;
+
+	g_object_get (G_OBJECT (child_source), "path", &path, NULL);
+	rb_debug ("removing child source [%p] for uri '%s'", child_source, path);
+	g_free (path);
+
+	library_source->priv->child_sources = g_list_remove (library_source->priv->child_sources, child_source);
+	rb_source_delete_thyself (RB_SOURCE (child_source));
+}
+
+static void
 rb_library_source_sync_child_sources (RBLibrarySource *source)
 {
-	GSList *list;
+	GSList *locations, *l;
+	RBLibraryChildSource *found;
+	GList *child_sources, *s;
+	char *path;
 
-	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	if (g_slist_length (locations) > 1) {
+		for (l = locations; l != NULL; l = g_slist_next (l)) {
+			found = rb_library_source_get_child_source_for_uri (source,
+					(char *)l->data);
+			if (found == NULL) {
+				rb_library_source_add_child_source (source, (char *)l->data);
+			}
+		}
+	}
 
-	/* FIXME: don't delete and re-create sources that are still there */
-	g_list_foreach (source->priv->child_sources, (GFunc)rb_source_delete_thyself, NULL);
-	g_list_free (source->priv->child_sources);
-	source->priv->child_sources = NULL;
+	child_sources = g_list_copy (source->priv->child_sources);
+	for (s = child_sources; s != NULL; s = g_list_next (s)) {
+		g_object_get (G_OBJECT (s->data),
+				"path", &path,
+				NULL);
+		
+		if (path == NULL) {
+			continue;
+		}
 
-	if (g_slist_length (list) > 1)
-		g_slist_foreach (list, (GFunc)rb_library_source_add_child_source, source);
-	rb_slist_deep_free (list);
+		if (! rb_string_slist_contains (locations, path)) {
+			rb_library_source_remove_child_source (source, RB_LIBRARY_CHILD_SOURCE (s->data));
+		}
+
+		g_free (path);
+	}
+
+	if (g_list_length (source->priv->child_sources) < 2) {
+		if (source->priv->child_sources != NULL && source->priv->child_sources->data != NULL) {
+			rb_debug ("only one child source, removing it");
+			rb_library_child_source_set_keep_songs_and_state (
+					RB_LIBRARY_CHILD_SOURCE (source->priv->child_sources->data),
+					TRUE);
+			rb_library_source_remove_child_source (source,
+					RB_LIBRARY_CHILD_SOURCE (source->priv->child_sources->data));
+		}
+	}
+	rb_slist_deep_free (locations);
+	g_list_free (child_sources);
 }
 
Index: sources/rb-browser-source.c
===================================================================
--- sources/rb-browser-source.c	(Revision 6278)
+++ sources/rb-browser-source.c	(Arbeitskopie)
@@ -136,6 +136,7 @@
 	RBEntryView *songs;
 	GtkWidget *paned;
 
+	GPtrArray *base_query;
 	RhythmDBQueryModel *cached_all_query;
 	RhythmDBQuery *search_query;
 	RhythmDBPropType search_prop;
@@ -189,7 +190,8 @@
 	PROP_SORTING_KEY,
 	PROP_BASE_QUERY_MODEL,
 	PROP_POPULATE,
-	PROP_SEARCH_TYPE
+	PROP_SEARCH_TYPE,
+	PROP_QUERY
 };
 
 G_DEFINE_ABSTRACT_TYPE (RBBrowserSource, rb_browser_source, RB_TYPE_SOURCE)
@@ -252,6 +254,13 @@
 					  PROP_SEARCH_TYPE,
 					  "search-type");
 
+	g_object_class_install_property (object_class,
+					 PROP_QUERY,
+					 g_param_spec_pointer ("query",
+							      "Query",
+							      "RhythmDBQuery",
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 	g_type_class_add_private (klass, sizeof (RBBrowserSourcePrivate));
 }
 
@@ -284,6 +293,11 @@
 		source->priv->search_query = NULL;
 	}
 
+	if (source->priv->base_query != NULL) {
+		rhythmdb_query_free (source->priv->base_query);
+		source->priv->base_query = NULL;
+	}
+
 	if (source->priv->cached_all_query != NULL) {
 		g_object_unref (source->priv->cached_all_query);
 		source->priv->cached_all_query = NULL;
@@ -517,6 +531,12 @@
 	case PROP_SEARCH_TYPE:
 		/* ignored */
 		break;
+	case PROP_QUERY:
+		if (source->priv->base_query != NULL) {
+			rhythmdb_query_free (source->priv->base_query);
+		}
+		source->priv->base_query = rhythmdb_query_copy (g_value_get_pointer (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -544,6 +564,9 @@
 	case PROP_SEARCH_TYPE:
 		g_value_set_enum (value, RB_SOURCE_SEARCH_INCREMENTAL);
 		break;
+	case PROP_QUERY:
+		source->priv->base_query = rhythmdb_query_copy (g_value_get_pointer (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -575,11 +598,17 @@
 				 source, 0);
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
-	rhythmdb_do_full_query_async (source->priv->db,
+	if (source->priv->base_query == NULL) {
+		rb_debug ("No query set, creating new one.");
+		source->priv->base_query = rhythmdb_query_parse (source->priv->db,
+				RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
+				RHYTHMDB_QUERY_END);
+	}	
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	
+	rhythmdb_do_full_query_async_parsed (source->priv->db,
 				      RHYTHMDB_QUERY_RESULTS (source->priv->cached_all_query),
-				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
-				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+				      source->priv->base_query);
 }
 
 
@@ -908,8 +937,8 @@
 rb_browser_source_do_query (RBBrowserSource *source, gboolean subset)
 {
 	RhythmDBQueryModel *query_model;
+	GPtrArray *base_query;
 	GPtrArray *query;
-	RhythmDBEntryType entry_type;
 
 	/* use the cached 'all' query to optimise the no-search case */
 	if (source->priv->search_query == NULL) {
@@ -919,15 +948,13 @@
 		return;
 	}
 
-	g_object_get (source, "entry-type", &entry_type, NULL);
-	query = rhythmdb_query_parse (source->priv->db,
-				      RHYTHMDB_QUERY_PROP_EQUALS,
-				      RHYTHMDB_PROP_TYPE,
-				      entry_type,
-				      RHYTHMDB_QUERY_SUBQUERY,
-				      source->priv->search_query,
-				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_get (source->priv->cached_all_query, "query", &base_query, NULL);
+	query = rhythmdb_query_copy (base_query);
+	rhythmdb_query_append (source->priv->db,
+				query,
+				RHYTHMDB_QUERY_SUBQUERY,
+				source->priv->search_query,
+				RHYTHMDB_QUERY_END);
 
 	if (subset) {
 		/* if we're appending text to an existing search string, the results will be a subset
Index: sources/Makefile.am
===================================================================
--- sources/Makefile.am	(Revision 6278)
+++ sources/Makefile.am	(Arbeitskopie)
@@ -41,6 +41,8 @@
 	rb-import-errors-source.h	\
 	rb-source-search-basic.c	\
 	rb-source-search-basic.h	\
+	rb-library-child-source.c	\
+	rb-library-child-source.h	\
 	$(NULL)
 
 INCLUDES =						\
Index: lib/rb-util.c
===================================================================
--- lib/rb-util.c	(Revision 6278)
+++ lib/rb-util.c	(Arbeitskopie)
@@ -690,6 +690,26 @@
 	return copy;
 }
 
+static void
+slist_copy_cb (const char *s, GSList **list)
+{
+	*list = g_slist_prepend (*list, g_strdup (s));
+}
+
+GSList *
+rb_string_slist_copy (GSList *list)
+{
+	GSList *copy = NULL;
+
+	if (list == NULL)
+		return NULL;
+
+	g_slist_foreach (list, (GFunc)slist_copy_cb, &copy);
+	copy = g_slist_reverse (copy);
+
+	return copy;
+}
+
 gboolean
 rb_string_list_contains (GList *list, const char *s)
 {
@@ -703,6 +723,19 @@
 	return FALSE;
 }
 
+gboolean
+rb_string_slist_contains (GSList *list, const char *s)
+{
+	GSList *l;
+
+	for (l = list; l != NULL; l = g_slist_next (l)) {
+		if (strcmp ((const char *)l->data, s) == 0)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 void
 rb_list_destroy_free (GList *list, GDestroyNotify destroyer)
 {
Index: lib/rb-util.h
===================================================================
--- lib/rb-util.h	(Revision 6278)
+++ lib/rb-util.h	(Arbeitskopie)
@@ -64,7 +64,9 @@
 
 gboolean rb_string_list_equal (GList *a, GList *b);
 gboolean rb_string_list_contains (GList *list, const char *s);
+gboolean rb_string_slist_contains (GSList *list, const char *s);
 GList* rb_string_list_copy (GList *list);
+GSList* rb_string_slist_copy (GSList *list);
 
 void rb_list_deep_free (GList *list);
 void rb_list_destroy_free (GList *list, GDestroyNotify destroyer);
Index: lib/eel-gconf-extensions.c
===================================================================
--- lib/eel-gconf-extensions.c	(Revision 6278)
+++ lib/eel-gconf-extensions.c	(Arbeitskopie)
@@ -348,6 +348,26 @@
         eel_gconf_handle_error (&error);
 }
 
+/* This code wasn't part of the original eel-gconf-extensions.c */
+void
+eel_gconf_recursive_unset (const char *key)
+{
+	GConfClient *client;
+	GError *error = NULL;
+
+	g_return_if_fail (key != NULL);
+
+	client = eel_gconf_client_get_global ();
+	g_return_if_fail (client != NULL);
+
+	gconf_client_recursive_unset (client,
+			key,
+			GCONF_UNSET_INCLUDING_SCHEMA_NAMES,
+			&error);
+	eel_gconf_handle_error (&error);
+}
+/* End of added code */
+
 gboolean
 eel_gconf_monitor_add (const char *directory)
 {
Index: lib/eel-gconf-extensions.h
===================================================================
--- lib/eel-gconf-extensions.h	(Revision 6278)
+++ lib/eel-gconf-extensions.h	(Arbeitskopie)
@@ -72,6 +72,7 @@
 void         eel_gconf_notification_remove (guint notification_id);
 
 void	     eel_gconf_unset 		   (const char *key);
+void	eel_gconf_recursive_unset	(const char *key);
 
 #ifdef __cplusplus
 }
Index: lib/rb-preferences.h
===================================================================
--- lib/rb-preferences.h	(Revision 6278)
+++ lib/rb-preferences.h	(Arbeitskopie)
@@ -66,7 +66,8 @@
 #define CONF_DAAP_REQUIRE_PASSWORD CONF_PREFIX "/sharing/require_password"
 
 #define CONF_LIBRARY_LOCATION	CONF_PREFIX "/library_locations"
-#define CONF_MONITOR_LIBRARY	CONF_PREFIX "/monitor_library"
+#define CONF_DEFAULT_LIBRARY_LOCATION CONF_PREFIX "/default_library_location"
+#define CONF_MONITOR_LIBRARY_LOCATIONS CONF_PREFIX "/monitor_library_locations"
 #define CONF_LIBRARY_STRIP_CHARS	CONF_PREFIX "/library_strip_chars"
 #define CONF_LIBRARY_LAYOUT_PATH	CONF_PREFIX "/library_layout_path"
 #define CONF_LIBRARY_LAYOUT_FILENAME	CONF_PREFIX "/library_layout_filename"
Index: data/rhythmbox.schemas
===================================================================
--- data/rhythmbox.schemas	(Revision 6278)
+++ data/rhythmbox.schemas	(Arbeitskopie)
@@ -45,6 +45,17 @@
         </locale>
       </schema>
       <schema>
+        <key>/schemas/apps/rhythmbox/default_library_location</key>
+        <applyto>/apps/rhythmbox/default_library_location</applyto>
+        <owner>rhythmbox</owner>
+        <type>string</type>
+        <default></default>
+        <locale name="C">
+        <short>Directory where Rhyhtmbox should put files</short>
+        <long>The URI of the directory where Rhythmbox puts files from e.g. ripped CDs or tracks transferred from portable media players</long>
+        </locale>
+      </schema>
+      <schema>
         <key>/schemas/apps/rhythmbox/library_locations</key>
         <applyto>/apps/rhythmbox/library_locations</applyto>
         <owner>rhythmbox</owner>
@@ -101,14 +112,15 @@
 	</locale>
       </schema>
       <schema>
-        <key>/schemas/apps/rhythmbox/monitor_library</key>
-        <applyto>/apps/rhythmbox/monitor_library</applyto>
+        <key>/schemas/apps/rhythmbox/monitor_library_locations</key>
+        <applyto>/apps/rhythmbox/monitor_library_locations</applyto>
         <owner>rhythmbox</owner>
-        <type>bool</type>
-        <default>FALSE</default>
+        <type>list</type>
+        <list_type>string</list_type>
+        <default>[]</default>
         <locale name="C">
-          <short>Whether the library location are monitored</short>
-          <long>If true, the locations listed in /apps/rhythmbox/library_locations are monitored for new files</long>
+          <short>Library locations which are monitored for new tracks</short>
+          <long>A list of directory URIs Rhythmbox monitors for new tracks. This is a subset of the list in library_locations.</long>
         </locale>
       </schema>
       <schema>
Index: data/glade/library-prefs.glade
===================================================================
--- data/glade/library-prefs.glade	(Revision 6278)
+++ data/glade/library-prefs.glade	(Arbeitskopie)
@@ -107,124 +107,94 @@
 		      <property name="spacing">3</property>
 
 		      <child>
-			<widget class="GtkHBox" id="hbox15">
+			<widget class="GtkLabel" id="label25">
 			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">_Music files are placed in:</property>
+			  <property name="use_underline">True</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkHBox" id="hbox20">
+			  <property name="visible">True</property>
 			  <property name="homogeneous">False</property>
 			  <property name="spacing">6</property>
 
 			  <child>
-			    <widget class="GtkLabel" id="label25">
+			    <widget class="GtkScrolledWindow" id="scrolledwindow1">
 			      <property name="visible">True</property>
-			      <property name="label" translatable="yes">_Music files are placed in:</property>
-			      <property name="use_underline">True</property>
-			      <property name="use_markup">False</property>
-			      <property name="justify">GTK_JUSTIFY_LEFT</property>
-			      <property name="wrap">False</property>
-			      <property name="selectable">False</property>
-			      <property name="xalign">0.5</property>
-			      <property name="yalign">0.5</property>
-			      <property name="xpad">0</property>
-			      <property name="ypad">0</property>
-			      <property name="mnemonic_widget">library_location_entry</property>
-			      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			      <property name="width_chars">-1</property>
-			      <property name="single_line_mode">False</property>
-			      <property name="angle">0</property>
-			    </widget>
-			    <packing>
-			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</property>
-			    </packing>
-			  </child>
-
-			  <child>
-			    <widget class="GtkEntry" id="library_location_entry">
-			      <property name="visible">True</property>
 			      <property name="can_focus">True</property>
-			      <property name="editable">True</property>
-			      <property name="visibility">True</property>
-			      <property name="max_length">0</property>
-			      <property name="text"></property>
-			      <property name="has_frame">True</property>
-			      <property name="invisible_char">*</property>
-			      <property name="activates_default">False</property>
+			      <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+			      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+			      <property name="shadow_type">GTK_SHADOW_IN</property>
+			      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+			      <child>
+				<widget class="GtkTreeView" id="library_locations_treeview">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="headers_visible">True</property>
+				  <property name="rules_hint">False</property>
+				  <property name="reorderable">False</property>
+				  <property name="enable_search">False</property>
+				  <property name="fixed_height_mode">False</property>
+				  <property name="hover_selection">False</property>
+				  <property name="hover_expand">False</property>
+				  <property name="height_request">100</property>
+				</widget>
+			      </child>
 			    </widget>
 			    <packing>
 			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</property>
+			      <property name="expand">True</property>
+			      <property name="fill">True</property>
 			    </packing>
 			  </child>
 
 			  <child>
-			    <widget class="GtkButton" id="library_location_button">
+			    <widget class="GtkVButtonBox" id="vbuttonbox1">
 			      <property name="visible">True</property>
-			      <property name="can_focus">True</property>
-			      <property name="relief">GTK_RELIEF_NORMAL</property>
-			      <property name="focus_on_click">True</property>
+			      <property name="layout_style">GTK_BUTTONBOX_START</property>
+			      <property name="spacing">6</property>
 
 			      <child>
-				<widget class="GtkAlignment" id="alignment3">
+				<widget class="GtkButton" id="add_library_location_button">
 				  <property name="visible">True</property>
-				  <property name="xalign">0.5</property>
-				  <property name="yalign">0.5</property>
-				  <property name="xscale">0</property>
-				  <property name="yscale">0</property>
-				  <property name="top_padding">0</property>
-				  <property name="bottom_padding">0</property>
-				  <property name="left_padding">0</property>
-				  <property name="right_padding">0</property>
+				  <property name="can_default">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="label">gtk-add</property>
+				  <property name="use_stock">True</property>
+				  <property name="relief">GTK_RELIEF_NORMAL</property>
+				  <property name="focus_on_click">True</property>
+				</widget>
+			      </child>
 
-				  <child>
-				    <widget class="GtkHBox" id="hbox16">
-				      <property name="visible">True</property>
-				      <property name="homogeneous">False</property>
-				      <property name="spacing">2</property>
-
-				      <child>
-					<widget class="GtkImage" id="image1">
-					  <property name="visible">True</property>
-					  <property name="stock">gtk-directory</property>
-					  <property name="icon_size">4</property>
-					  <property name="xalign">0.5</property>
-					  <property name="yalign">0.5</property>
-					  <property name="xpad">0</property>
-					  <property name="ypad">0</property>
-					</widget>
-					<packing>
-					  <property name="padding">0</property>
-					  <property name="expand">False</property>
-					  <property name="fill">False</property>
-					</packing>
-				      </child>
-
-				      <child>
-					<widget class="GtkLabel" id="label21">
-					  <property name="visible">True</property>
-					  <property name="label" translatable="yes">_Browse...</property>
-					  <property name="use_underline">True</property>
-					  <property name="use_markup">False</property>
-					  <property name="justify">GTK_JUSTIFY_LEFT</property>
-					  <property name="wrap">False</property>
-					  <property name="selectable">False</property>
-					  <property name="xalign">0.5</property>
-					  <property name="yalign">0.5</property>
-					  <property name="xpad">0</property>
-					  <property name="ypad">0</property>
-					  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-					  <property name="width_chars">-1</property>
-					  <property name="single_line_mode">False</property>
-					  <property name="angle">0</property>
-					</widget>
-					<packing>
-					  <property name="padding">0</property>
-					  <property name="expand">False</property>
-					  <property name="fill">False</property>
-					</packing>
-				      </child>
-				    </widget>
-				  </child>
+			      <child>
+				<widget class="GtkButton" id="remove_library_location_button">
+				  <property name="visible">True</property>
+				  <property name="can_default">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="label">gtk-remove</property>
+				  <property name="use_stock">True</property>
+				  <property name="relief">GTK_RELIEF_NORMAL</property>
+				  <property name="focus_on_click">True</property>
 				</widget>
 			      </child>
 			    </widget>
@@ -237,29 +207,10 @@
 			</widget>
 			<packing>
 			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
 			</packing>
 		      </child>
-
-		      <child>
-			<widget class="GtkCheckButton" id="watch_library_check">
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="label" translatable="yes">_Watch my library for new files</property>
-			  <property name="use_underline">True</property>
-			  <property name="relief">GTK_RELIEF_NORMAL</property>
-			  <property name="focus_on_click">True</property>
-			  <property name="active">False</property>
-			  <property name="inconsistent">False</property>
-			  <property name="draw_indicator">True</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
-			</packing>
-		      </child>
 		    </widget>
 		    <packing>
 		      <property name="padding">0</property>
