Index: lib/rb-file-helpers.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-file-helpers.c,v
retrieving revision 1.53
diff -u -p -r1.53 rb-file-helpers.c
--- lib/rb-file-helpers.c	17 Jul 2006 14:51:23 -0000	1.53
+++ lib/rb-file-helpers.c	11 Aug 2006 15:11:16 -0000
@@ -629,12 +629,36 @@ escape_extra_gnome_vfs_chars (char *uri)
 }
 
 typedef struct {
-	const char *uri;
-	GFunc func;
+	char *uri;
+	RBUriRecurseFunc func;
 	gpointer user_data;
 	gboolean *cancel_flag;
+	GDestroyNotify data_destroy;
 } RBUriHandleRecursivelyData;
 
+typedef struct {
+	RBUriHandleRecursivelyData data;
+
+	/* real data */
+	RBUriRecurseFunc func;
+	gpointer user_data;
+
+	GMutex *results_lock;
+	guint results_idle_id;
+	GList *uri_results;
+	GList *dir_results;
+} RBUriHandleRecursivelyAsyncData;
+
+static void
+_rb_uri_recurse_data_free (RBUriHandleRecursivelyData *data)
+{
+	g_free (data->uri);
+	if (data->data_destroy)
+		data->data_destroy (data->user_data);
+
+	g_free (data);
+}
+
 static gboolean
 rb_uri_handle_recursively_cb (const gchar *rel_path,
 			      GnomeVFSFileInfo *info,
@@ -642,6 +666,11 @@ rb_uri_handle_recursively_cb (const gcha
 			      RBUriHandleRecursivelyData *data,
 			      gboolean *recurse)
 {
+	char *path, *escaped_rel_path;
+	gboolean dir;
+
+	dir = (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY);
+
 	if (data->cancel_flag && *data->cancel_flag)
 		return TRUE;
 
@@ -653,16 +682,12 @@ rb_uri_handle_recursively_cb (const gcha
 		return TRUE;
 	}
 
-	if (info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
-		char *path, *escaped_rel_path;
-
-		escaped_rel_path = gnome_vfs_escape_path_string (rel_path);
-		escaped_rel_path = escape_extra_gnome_vfs_chars (escaped_rel_path);
-		path = g_build_filename (data->uri, escaped_rel_path, NULL);
-		(data->func) (path, data->user_data);
-		g_free (escaped_rel_path);
-		g_free (path);
-	}
+	escaped_rel_path = gnome_vfs_escape_path_string (rel_path);
+	escaped_rel_path = escape_extra_gnome_vfs_chars (escaped_rel_path);
+	path = g_build_filename (data->uri, escaped_rel_path, NULL);
+	(data->func) (path, dir, data->user_data);
+	g_free (escaped_rel_path);
+	g_free (path);
 
 	*recurse = !recursing_will_loop;
 	return TRUE;
@@ -670,7 +695,7 @@ rb_uri_handle_recursively_cb (const gcha
 
 void
 rb_uri_handle_recursively (const char *text_uri,
-		           GFunc func,
+		           RBUriRecurseFunc func,
 			   gboolean *cancelflag,
 		           gpointer user_data)
 {
@@ -678,10 +703,11 @@ rb_uri_handle_recursively (const char *t
 	GnomeVFSFileInfoOptions flags;
 	GnomeVFSResult result;
 	
-	data->uri = text_uri;
+	data->uri = g_strdup (text_uri);
 	data->func = func;
 	data->user_data = user_data;
 	data->cancel_flag = cancelflag;
+	data->data_destroy = NULL;
 
 	flags = GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
 		GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE |
@@ -692,8 +718,114 @@ rb_uri_handle_recursively (const char *t
 					    GNOME_VFS_DIRECTORY_VISIT_LOOPCHECK,
 					    (GnomeVFSDirectoryVisitFunc)rb_uri_handle_recursively_cb,
 					    data);
-	g_free (data);
+	_rb_uri_recurse_data_free (data);
+}
+
+/* runs in main thread */
+static gboolean
+_recurse_async_idle_cb (RBUriHandleRecursivelyAsyncData *data)
+{
+	GList *ul, *dl;
+
+	g_mutex_lock (data->results_lock);
+
+	for (ul = data->uri_results, dl = data->dir_results;
+	     ul != NULL;
+	     ul = g_list_next (ul), dl = g_list_next (dl)) {
+		g_assert (dl != NULL);
+
+		data->func ((const char*)ul->data, (GPOINTER_TO_INT (dl->data) == 1), data->user_data);
+		g_free (ul->data);
+	}
+	g_assert (dl == NULL);
+
+
+	g_list_free (data->uri_results);
+	data->uri_results = NULL;
+	g_list_free (data->dir_results);
+	data->dir_results = NULL;
+
+	data->results_idle_id = 0;
+	g_mutex_unlock (data->results_lock);
+	return FALSE;
 }
+
+/* runs in main thread */
+static gboolean
+_recurse_async_data_free (RBUriHandleRecursivelyAsyncData *data)
+{
+	if (data->results_idle_id) {
+		g_source_remove (data->results_idle_id);
+		_recurse_async_idle_cb (data); /* process last results */
+	}
+
+	g_list_free (data->uri_results);
+	data->uri_results = NULL;
+	g_list_free (data->dir_results);
+	data->dir_results = NULL;
+
+	g_mutex_free (data->results_lock);
+	_rb_uri_recurse_data_free (&data->data);
+
+	return FALSE;
+}
+
+/* runs in worker thread */
+static void
+_recurse_async_cb (const char *uri, gboolean dir, RBUriHandleRecursivelyAsyncData *data)
+{
+	g_mutex_lock (data->results_lock);
+
+	data->uri_results = g_list_prepend (data->uri_results, g_strdup (uri));
+	data->dir_results = g_list_prepend (data->dir_results, GINT_TO_POINTER (dir ? 1 : 0));
+	if (data->results_idle_id == 0)
+		g_idle_add ((GSourceFunc)_recurse_async_idle_cb, data);
+
+	g_mutex_unlock (data->results_lock);
+}
+
+static gpointer
+_recurse_async_func (RBUriHandleRecursivelyAsyncData *data)
+{
+	GnomeVFSFileInfoOptions flags;
+	GnomeVFSResult result;
+
+	flags = GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
+		GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE |
+		GNOME_VFS_FILE_INFO_FOLLOW_LINKS |
+		GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS;
+	result = gnome_vfs_directory_visit (data->data.uri,
+					    flags,
+					    GNOME_VFS_DIRECTORY_VISIT_LOOPCHECK,
+					    (GnomeVFSDirectoryVisitFunc)rb_uri_handle_recursively_cb,
+					    &data->data);
+	
+	g_idle_add ((GSourceFunc)_recurse_async_data_free, data);
+	return NULL;
+}
+
+void
+rb_uri_handle_recursively_async (const char *text_uri,
+			         RBUriRecurseFunc func,
+				 gboolean *cancelflag,
+			         gpointer user_data,
+				 GDestroyNotify data_destroy)
+{
+	RBUriHandleRecursivelyAsyncData *data = g_new0 (RBUriHandleRecursivelyAsyncData, 1);
+	
+	data->data.uri = g_strdup (text_uri);
+	data->func = (RBUriRecurseFunc)_recurse_async_cb;
+	data->data.user_data = user_data;
+	data->data.cancel_flag = cancelflag;
+	data->data.data_destroy = data_destroy;
+
+	data->results_lock = g_mutex_new ();
+	data->data.func = func;
+	data->user_data = data;
+
+	g_thread_create ((GThreadFunc)_recurse_async_func, data, FALSE, NULL);
+}
+
 
 GnomeVFSResult
 rb_uri_mkstemp (const char *prefix, char **uri_ret, GnomeVFSHandle **ret)
Index: lib/rb-file-helpers.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-file-helpers.h,v
retrieving revision 1.24
diff -u -p -r1.24 rb-file-helpers.h
--- lib/rb-file-helpers.h	20 Apr 2006 20:43:21 -0000	1.24
+++ lib/rb-file-helpers.h	11 Aug 2006 15:11:17 -0000
@@ -44,10 +44,18 @@ gboolean	rb_uri_is_writable	(const char 
 gboolean	rb_uri_is_local		(const char *uri);
 char *		rb_uri_get_dir_name	(const char *uri);
 
+typedef void (*RBUriRecurseFunc) (const char *uri, gboolean dir, gpointer data);
+
 void		rb_uri_handle_recursively(const char *uri,
-					  GFunc func,
+					  RBUriRecurseFunc func,
 					  gboolean *cancelflag,
 					  gpointer user_data);
+
+void		rb_uri_handle_recursively_async(const char *uri,
+						RBUriRecurseFunc func,
+						gboolean *cancelflag,
+						gpointer user_data,
+						GDestroyNotify data_destroy);
 
 char*		rb_uri_append_path	(const char *uri,
 					 const char *path);
Index: plugins/rb-plugins-engine.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/plugins/rb-plugins-engine.c,v
retrieving revision 1.11
diff -u -p -r1.11 rb-plugins-engine.c
--- plugins/rb-plugins-engine.c	10 Aug 2006 15:12:24 -0000	1.11
+++ plugins/rb-plugins-engine.c	11 Aug 2006 15:11:18 -0000
@@ -247,14 +247,14 @@ error:
 }
 
 static void
-rb_plugins_engine_load_cb (const char *uri, gpointer userdata)
+rb_plugins_engine_load_cb (const char *uri, gboolean dir, gpointer userdata)
 {
 	gchar *plugin_file;
 	RBPluginInfo *info;
 	char *key_name;
 	gboolean activate;
 
-	if (!g_str_has_suffix (uri, PLUGIN_EXT))
+	if (dir || !g_str_has_suffix (uri, PLUGIN_EXT))
 		return;
 
 	plugin_file = gnome_vfs_get_local_path_from_uri (uri);
@@ -296,7 +296,7 @@ rb_plugins_engine_load_dir (const gchar 
 	char *uri;
 
 	uri = rb_uri_resolve_relative (path);
-	rb_uri_handle_recursively (uri, (GFunc)rb_plugins_engine_load_cb, NULL, NULL);
+	rb_uri_handle_recursively (uri, (RBUriRecurseFunc)rb_plugins_engine_load_cb, NULL, NULL);
 	g_free (uri);
 }
 
Index: rhythmdb/rhythmdb-monitor.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-monitor.c,v
retrieving revision 1.6
diff -u -p -r1.6 rhythmdb-monitor.c
--- rhythmdb/rhythmdb-monitor.c	27 Jul 2006 02:11:51 -0000	1.6
+++ rhythmdb/rhythmdb-monitor.c	11 Aug 2006 15:11:19 -0000
@@ -29,6 +29,7 @@
 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
 
 #include "rb-debug.h"
+#include "rb-util.h"
 #include "rhythmdb.h"
 #include "rhythmdb-private.h"
 #include "rb-file-helpers.h"
@@ -49,7 +50,7 @@ rhythmdb_init_monitoring (RhythmDB *db)
 {
 	db->priv->monitored_directories = g_hash_table_new_full (g_str_hash, g_str_equal,
 								 (GDestroyNotify) g_free,
-								 NULL);
+								 (GDestroyNotify)gnome_vfs_monitor_cancel);
 
 	db->priv->changed_files = g_hash_table_new_full (rb_refstring_hash, rb_refstring_equal,
 							 (GDestroyNotify) rb_refstring_unref,
@@ -81,60 +82,45 @@ rhythmdb_finalize_monitoring (RhythmDB *
 	g_hash_table_destroy (db->priv->changed_files);
 }
 
-static gboolean
-rhythmdb_unmonitor_directories (char *dir, GnomeVFSMonitorHandle *handle, RhythmDB *db)
-{
-	gnome_vfs_monitor_cancel (handle);
-	return TRUE;
-}
-
 void
 rhythmdb_stop_monitoring (RhythmDB *db)
 {
 	g_hash_table_foreach_remove (db->priv->monitored_directories,
-				     (GHRFunc) rhythmdb_unmonitor_directories,
+				     (GHRFunc) rb_true_function,
 				     db);
 }
 
 static void
 monitor_entry_file (RhythmDBEntry *entry, RhythmDB *db)
 {
-	GError *error = NULL;
-
 	if (entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
 		const char *loc;
+		GSList *l;
 
 		loc = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
-		rhythmdb_monitor_uri_path (db, loc, &error);
-	}
 
-	if (error) {
-		/* FIXME: should we complain to the user? */
-		rb_debug ("error while attempting to monitor library track: %s", error->message);
+		/* 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)) {
+			if (g_str_has_prefix (loc, (const char*)l->data))
+				return;
+				
+		}
+		rhythmdb_monitor_uri_path (db, loc, NULL);
 	}
 }
 
 static void
-monitor_subdirectory (const char *uri, RhythmDB *db)
+monitor_subdirectory (const char *uri, gboolean dir, RhythmDB *db)
 {
-	GError *error = NULL;
-
-	if (!rb_uri_is_directory (uri))
-		return;
-
-	rhythmdb_monitor_uri_path (db, uri, &error);
-
-	if (error) {
-		/* FIXME: should we complain to the user? */
-		rb_debug ("error while attempting to monitor the library directory: %s", error->message);
-	}
+	if (dir)
+		rhythmdb_monitor_uri_path (db, uri, NULL);
+	else
+		rhythmdb_add_uri (db, uri);
 }
 
 static void
 monitor_library_directory (const char *uri, RhythmDB *db)
 {
-	GError *error = NULL;
-
 	if ((strcmp (uri, "file:///") == 0) ||
 	    (strcmp (uri, "file://") == 0)) {
 		/* display an error to the user? */
@@ -142,16 +128,9 @@ monitor_library_directory (const char *u
 	}
 
 	rb_debug ("beginning monitor of the library directory %s", uri);
-	rhythmdb_monitor_uri_path (db, uri, &error);
-	rb_uri_handle_recursively (uri, (GFunc) monitor_subdirectory, NULL, db);
-
-	if (error) {
-		/* FIXME: should we complain to the user? */
-		rb_debug ("error while attempting to monitor the library directory: %s", error->message);
-	}
-
-	rb_debug ("loading new tracks from library directory %s", uri);
-	rhythmdb_add_uri (db, uri);
+	rhythmdb_monitor_uri_path (db, uri, NULL);
+	rb_uri_handle_recursively_async (uri, (RBUriRecurseFunc) monitor_subdirectory, NULL,
+					 g_object_ref (db), (GDestroyNotify)g_object_unref);
 }
 
 static gboolean
@@ -186,18 +165,25 @@ rhythmdb_process_changed_files (RhythmDB
 	return TRUE;
 }
 
+static gpointer
+_monitor_entry_thread (RhythmDB *db)
+{
+	rhythmdb_entry_foreach (db, (GFunc) monitor_entry_file, db);
+	g_object_unref (G_OBJECT (db));
+	return NULL;
+}
+
 void
 rhythmdb_start_monitoring (RhythmDB *db)
 {
 	db->priv->changed_files_id = g_timeout_add (RHYTHMDB_FILE_MODIFY_PROCESS_TIME * 1000,
 						    (GSourceFunc) rhythmdb_process_changed_files, db);
 
-	if (db->priv->library_locations) {
-		g_slist_foreach (db->priv->library_locations, (GFunc) monitor_library_directory, db);
-	}
+	g_thread_create ((GThreadFunc)_monitor_entry_thread, g_object_ref (db), FALSE, NULL);
 
-	/* monitor every directory that contains a (TYPE_SONG) track */
-	rhythmdb_entry_foreach (db, (GFunc) monitor_entry_file, db);
+	/* monitor all library locations */
+	if (db->priv->library_locations)
+		g_slist_foreach (db->priv->library_locations, (GFunc) monitor_library_directory, db);
 }
 
 static void
@@ -269,7 +255,7 @@ rhythmdb_monitor_uri_path (RhythmDB *db,
 {
 	char *directory;
 	GnomeVFSResult vfsresult;
-	GnomeVFSMonitorHandle **handle;
+	GnomeVFSMonitorHandle *handle = NULL;
 
 	if (rb_uri_is_directory (uri)) {
 		if (g_str_has_suffix(uri, G_DIR_SEPARATOR_S)) {
@@ -287,18 +273,19 @@ rhythmdb_monitor_uri_path (RhythmDB *db,
 		gnome_vfs_uri_unref (parent);
 	}
 
-	if (directory == NULL || g_hash_table_lookup (db->priv->monitored_directories, directory))
+	if (directory == NULL || g_hash_table_lookup (db->priv->monitored_directories, directory)) {
+		g_free (directory);
 		return;
+	}
 
-	handle = g_new0 (GnomeVFSMonitorHandle *, 1);
-	vfsresult = gnome_vfs_monitor_add (handle, directory,
+	vfsresult = gnome_vfs_monitor_add (&handle, directory,
 					   GNOME_VFS_MONITOR_DIRECTORY,
 					   (GnomeVFSMonitorCallback) rhythmdb_directory_change_cb,
 					   db);
 	if (vfsresult == GNOME_VFS_OK) {
 		rb_debug ("monitoring: %s", directory);
 		g_hash_table_insert (db->priv->monitored_directories,
-				     directory, *handle);
+				     directory, handle);
 	} else {
 		g_set_error (error,
 			     RHYTHMDB_ERROR,
@@ -308,7 +295,6 @@ rhythmdb_monitor_uri_path (RhythmDB *db,
 			     gnome_vfs_result_to_string (vfsresult));
 		rb_debug ("failed to monitor %s", directory);
 		g_free (directory);
-		g_free (handle);
 	}
 }
 
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.248
diff -u -p -r1.248 rhythmdb.c
--- rhythmdb/rhythmdb.c	7 Aug 2006 12:38:26 -0000	1.248
+++ rhythmdb/rhythmdb.c	11 Aug 2006 15:11:22 -0000
@@ -1505,9 +1505,6 @@ rhythmdb_process_stat_event (RhythmDB *d
 
 			if (mtime == event->vfsinfo->mtime) {
 				rb_debug ("not modified: %s", rb_refstring_get (event->real_uri));
-				/* monitor the file for changes */
-				if (eel_gconf_get_boolean (CONF_MONITOR_LIBRARY))
-					rhythmdb_monitor_uri_path (db, rb_refstring_get (entry->location), NULL /* FIXME */);
 			} else {
 				RhythmDBEvent *new_event;
 
@@ -2024,9 +2021,11 @@ queue_stat_uri (const char *uri,
 
 static void
 queue_stat_uri_tad (const char *uri,
+		    gboolean dir,
 		    RhythmDBAddThreadData *data)
 {
-	queue_stat_uri (uri, data->db, data->type);
+	if (!dir)
+		queue_stat_uri (uri, data->db, data->type);
 }
 
 static gpointer
@@ -2034,7 +2033,7 @@ add_thread_main (RhythmDBAddThreadData *
 {
 	RhythmDBEvent *result;
 
-	rb_uri_handle_recursively (data->uri, (GFunc) queue_stat_uri_tad,
+	rb_uri_handle_recursively (data->uri, (RBUriRecurseFunc) queue_stat_uri_tad,
 				   &data->db->priv->exiting, data);
 
 	rb_debug ("exiting");
Index: sources/rb-static-playlist-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-static-playlist-source.c,v
retrieving revision 1.31
diff -u -p -r1.31 rb-static-playlist-source.c
--- sources/rb-static-playlist-source.c	7 Aug 2006 22:49:23 -0000	1.31
+++ sources/rb-static-playlist-source.c	11 Aug 2006 15:11:25 -0000
@@ -618,10 +618,12 @@ rb_static_playlist_source_add_location_i
 }
 
 static void
-rb_static_playlist_source_add_location_swapped (const char *uri,
-						RBStaticPlaylistSource *source)
+rb_static_playlist_source_add_location_cb (const char *uri,
+					   gboolean dir,
+					   RBStaticPlaylistSource *source)
 {
-	rb_static_playlist_source_add_location_internal (source, uri, -1);
+	if (!dir)
+		rb_static_playlist_source_add_location_internal (source, uri, -1);
 }
 
 void
@@ -638,7 +640,7 @@ rb_static_playlist_source_add_location (
 	/* if there is an entry, it won't be a directory */
 	if (entry == NULL && rb_uri_is_directory (location))
 		rb_uri_handle_recursively (location,
-					   (GFunc) rb_static_playlist_source_add_location_swapped,
+					   (RBUriRecurseFunc) rb_static_playlist_source_add_location_cb,
 					   NULL,
 					   source);
 	else
