Index: daemon/gvfsbackendnetwork.c
===================================================================
--- daemon/gvfsbackendnetwork.c	(revision 1347)
+++ daemon/gvfsbackendnetwork.c	(working copy)
@@ -39,11 +39,6 @@
 #include "gvfsjobqueryinfo.h"
 #include "gvfsmonitor.h"
 
-/**
- * TODO: Support monitoring the directories that are monitored
- *       so we see new dns-sd files, etc.
- */
-
 #define PATH_GCONF_GVFS_SMB "/system/smb"
 #define PATH_GCONF_GVFS_SMB_WORKGROUP "/system/smb/workgroup"
 #define DEFAULT_WORKGROUP_NAME "X-GNOME-DEFAULT-WORKGROUP"
@@ -78,11 +73,14 @@
   /* SMB Stuff */
   gboolean have_smb;
   char *current_workgroup;
+  gboolean workgroup_changed;
+  GFileMonitor *smb_monitor;
 
   /* DNS-SD Stuff */
   gboolean have_dnssd;
   NetworkLocalSetting local_setting;
   char *extra_domains;
+  GFileMonitor *dnssd_monitor;
 
   /* Icons */
   GIcon *workgroup_icon; /* GThemedIcon = "network-workgroup" */
@@ -240,17 +238,27 @@
 }
 
 static void
+notify_dnssd_local_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, 
+                            GFileMonitorEvent event_type, gpointer user_data);
+
+static void
+notify_smb_files_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, 
+                          GFileMonitorEvent event_type, gpointer user_data);
+
+static void
 recompute_files (GVfsBackendNetwork *backend)
 {
   GFile *server_file;
   GFileEnumerator *enumer;
   GFileInfo *info;
+  GFileMonitor *monitor;
+  GError *error;
   GList *files;
   NetworkFile *file;
   char *file_name, *link_uri;
 
   files = NULL;
-
+  error = NULL;
   if (backend->have_smb) 
     {
       char *workgroup;
@@ -266,8 +274,31 @@
       else 
         workgroup = g_strconcat ("smb://", backend->current_workgroup, "/", NULL);    
 
+      server_file = g_file_new_for_uri (workgroup);
+
+      /* recreate monitor if our workgroup changed or we don't have a monitor */
+      if (backend->workgroup_changed || backend->smb_monitor == NULL)
+        {
+          monitor = g_file_monitor_directory (server_file, G_FILE_MONITOR_NONE, NULL, &error);
+          if (monitor) 
+            {
+              g_signal_connect (monitor, "changed", 
+                                (GCallback)notify_smb_files_changed, (gpointer)backend); 
+              /* takes ref */
+              backend->smb_monitor = monitor;
+              monitor = NULL;
+            }
+          else
+            {
+              g_warning("Couldn't create directory monitor on %s. Error: %s", 
+                                 g_file_get_uri(server_file), error->message);
+              g_error_free(error);
+              error = NULL;
+            }
+          backend->workgroup_changed = FALSE;
+        }
+
       /* children of current workgroup */
-      server_file = g_file_new_for_uri (workgroup);
       enumer = g_file_enumerate_children (server_file, 
                                           "standard::name,standard::display-name", 
                                           G_FILE_QUERY_INFO_NONE, 
@@ -301,37 +332,52 @@
 
   if (backend->have_dnssd)
     {
+      server_file = g_file_new_for_uri ("dns-sd://local/");
+      /* create directory monitor if we haven't already */
+      monitor = g_file_monitor_directory (server_file, G_FILE_MONITOR_NONE, NULL, &error);
+      if (monitor) 
+        {
+          g_signal_connect (monitor, "changed", 
+                            (GCallback)notify_dnssd_local_changed, (gpointer)backend); 
+          /* takes ref */
+          backend->dnssd_monitor = monitor;
+        }
+      else
+        {
+          g_warning("Couldn't create directory monitor on %s. Error: %s", 
+                    g_file_get_uri(server_file), error->message);
+          g_error_free(error);
+        }
+
       if (backend->local_setting == NETWORK_LOCAL_MERGED)
         {
           /* "merged": add local domains to network:/// */
-          server_file = g_file_new_for_uri ("dns-sd://local/");
           enumer = g_file_enumerate_children (server_file, 
                                               "standard::name,standard::display-name", 
                                               G_FILE_QUERY_INFO_NONE, 
                                               NULL, NULL);
-        if (enumer != NULL)
-          {
-            info = g_file_enumerator_next_file (enumer, NULL, NULL);
-            while (info != NULL)
-              {
-                file_name = g_strconcat("dnssd-domain-", g_file_info_get_name (info), NULL);
-                link_uri = g_strconcat("dns-sd://", g_file_info_get_name (info), NULL);
-                file = network_file_new (file_name, 
-                                         g_file_info_get_display_name (info), 
-                                         link_uri, 
-                                         backend->server_icon);
-                files = g_list_prepend (files, file);
+          if (enumer != NULL)
+            {
+              info = g_file_enumerator_next_file (enumer, NULL, NULL);
+              while (info != NULL)
+                {
+                  file_name = g_strconcat("dnssd-domain-", g_file_info_get_name (info), NULL);
+                  link_uri = g_strconcat("dns-sd://local/", g_file_info_get_name (info), NULL);
+                  file = network_file_new (file_name, 
+                                          g_file_info_get_display_name (info), 
+                                          link_uri, 
+                                          backend->server_icon);
+                  files = g_list_prepend (files, file);
 
-                g_free(link_uri);
-                g_free(file_name);
-                g_object_unref(info);
-                info = g_file_enumerator_next_file (enumer, NULL, NULL);
-              }
-           }
+                  g_free(link_uri);
+                  g_free(file_name);
+                  g_object_unref(info);
+                  info = g_file_enumerator_next_file (enumer, NULL, NULL);
+                }
+            }
     
           g_file_enumerator_close(enumer, NULL, NULL);
           g_object_unref(enumer);
-          g_object_unref(server_file);
         }
       else
         {
@@ -341,6 +387,7 @@
           files = g_list_prepend (files, file);   
         }
 
+    g_object_unref(server_file);
     /* If gconf setting "/system/dns_sd/extra_domains" is set to a list of domains:
      * links to dns-sd://$domain/ */
     if (backend->extra_domains != NULL &&
@@ -379,6 +426,60 @@
 }
 
 static void
+notify_smb_files_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, 
+                          GFileMonitorEvent event_type, gpointer user_data)
+{
+  GVfsBackendNetwork *backend = G_VFS_BACKEND_NETWORK(user_data);
+  switch (event_type)
+    {
+    case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+    case G_FILE_MONITOR_EVENT_CREATED:
+    case G_FILE_MONITOR_EVENT_DELETED:
+      if (backend->idle_tag == 0)
+        backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+      break;
+    case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+    case G_FILE_MONITOR_EVENT_UNMOUNTED:
+      /* in either event, our smb backend is/will be gone. */
+      backend->have_smb = FALSE;
+      if (backend->idle_tag == 0)
+        backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+      /* stop monitoring as the backend's gone. */
+      g_file_monitor_cancel (monitor);
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+notify_dnssd_local_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, 
+                            GFileMonitorEvent event_type, gpointer user_data)
+{
+  GVfsBackendNetwork *backend = G_VFS_BACKEND_NETWORK(user_data);
+  switch (event_type)
+    {
+    case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+    case G_FILE_MONITOR_EVENT_CREATED:
+    case G_FILE_MONITOR_EVENT_DELETED:
+      if (backend->idle_tag == 0)
+        backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+      break;
+    case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+    case G_FILE_MONITOR_EVENT_UNMOUNTED:
+      /* in either event, our dns-sd backend is/will be gone. */
+      backend->have_dnssd = FALSE;
+      if (backend->idle_tag == 0)
+        backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+      /* stop monitoring as the backend's gone. */
+      g_file_monitor_cancel (monitor);
+      break;
+    default:
+      break;
+    }
+}
+
+static void
 notify_gconf_dnssd_domains_changed (GConfClient *client,
 				    guint        cnxn_id,
 				    GConfEntry  *entry,
@@ -392,10 +493,9 @@
   g_free(backend->extra_domains);
   backend->extra_domains = extra_domains;
 
-  if (backend->idle_tag != 0)
-    g_source_remove (backend->idle_tag);
-  
-  backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+  /* don't re-issue recomputes if we've already queued one. */
+  if (backend->idle_tag == 0)
+    backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
 }
 
 static void
@@ -413,10 +513,9 @@
   backend->local_setting = parse_network_local_setting (display_local);
   g_free(display_local);
 
-  if (backend->idle_tag != 0)
-    g_source_remove (backend->idle_tag);
-  
-  backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+  /* don't re-issue recomputes if we've already queued one. */
+  if (backend->idle_tag == 0)
+    backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
 }
 
 static void
@@ -434,11 +533,19 @@
   g_free(backend->current_workgroup);
   backend->current_workgroup = current_workgroup;
 
-  if (backend->idle_tag != 0)
-    g_source_remove (backend->idle_tag);
-  
-  backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
+  /* cancel the smb monitor */
+  g_signal_handlers_disconnect_by_func(backend->smb_monitor,
+                                       notify_smb_files_changed,
+                                       backend->smb_monitor);
+  g_file_monitor_cancel (backend->smb_monitor);
+  g_object_unref(backend->smb_monitor);
 
+  /* set workgroup_changed so recompute_files will create a new smb monitor */
+  backend->workgroup_changed = TRUE;
+
+  /* don't re-issue recomputes if we've already queued one. */
+  if (backend->idle_tag == 0)
+    backend->idle_tag = g_idle_add ((GSourceFunc)idle_add_recompute, backend);
 }
 
 static NetworkFile *
@@ -591,8 +698,10 @@
   return TRUE;
 }
 
-/* handles both file and dir monitors, 
- * as we really don't "support" (e.g. fire events for) either, yet. */
+/* handles both file and dir monitors
+ * for now we only fire events on the root directory.
+ * are individual file monitors needed for this backend?
+ */
 static gboolean
 try_create_monitor (GVfsBackend *backend,
                     GVfsJobCreateMonitor *job,
@@ -634,6 +743,7 @@
   supported_vfs = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
 
   network_backend->have_smb = FALSE;
+  network_backend->have_dnssd = FALSE;
   for (i=0; supported_vfs[i]!=NULL; i++)
     {
       if (strcmp(supported_vfs[i], "smb") == 0)
