Index: gio/gfilemonitor.c
===================================================================
--- gio/gfilemonitor.c	(revision 7271)
+++ gio/gfilemonitor.c	(working copy)
@@ -193,8 +193,8 @@
   /**
    * GFileMonitor::changed:
    * @monitor: a #GFileMonitor.
-   * @file: a #GFile.
-   * @other_file: a #GFile.
+   * @file: monitored #GFile which triggered the event.
+   * @other_file: a #GFile object, not used at the moment.
    * @event_type: a #GFileMonitorEvent.
    * 
    * Emitted when a file has been changed. 
@@ -585,8 +585,8 @@
 /**
  * g_file_monitor_emit_event:
  * @monitor: a #GFileMonitor.
- * @child: a #GFile.
- * @other_file: a #GFile.
+ * @child: monitored #GFile which triggered the event.
+ * @other_file: a #GFile object, not used at the moment.
  * @event_type: a set of #GFileMonitorEvent flags.
  * 
  * Emits the #GFileMonitor::changed signal if a change
Index: gio/inotify/inotify-helper.c
===================================================================
--- gio/inotify/inotify-helper.c	(revision 7271)
+++ gio/inotify/inotify-helper.c	(working copy)
@@ -139,46 +139,109 @@
 }
 
 
+
+typedef struct {
+  GRecreateCallback recreate_cb;
+  gpointer          user_data;
+} RecreateWatch;
+
+static gboolean
+idle_cb (gpointer data)
+{
+  RecreateWatch *change = data;
+  
+  change->recreate_cb (change->user_data);
+  g_slice_free (RecreateWatch, data);
+
+  return FALSE;
+}
+
 static void
+emit_in_idle (GRecreateCallback recreate_cb,
+              gpointer          user_data)
+{
+  GSource *source;
+  RecreateWatch *change;
+
+  change = g_slice_new (RecreateWatch);
+
+  change->recreate_cb = recreate_cb;
+  change->user_data = user_data;
+
+  source = g_idle_source_new ();
+  g_source_set_priority (source, 0);
+
+  g_source_set_callback (source, idle_cb, change, NULL);
+  g_source_attach (source, NULL);
+  g_source_unref (source);
+}
+
+static void
 ih_event_callback (ik_event_t  *event, 
                    inotify_sub *sub)
 {
+  const gchar *dirname, *filename;
   gchar *fullpath;
   GFileMonitorEvent eflags;
   GFile* parent;
   GFile* child;
-  
+
   eflags = ih_mask_to_EventFlags (event->mask);
   parent = g_file_new_for_path (sub->dirname);
+  
+  if (sub->mask_dirname)
+    dirname = sub->mask_dirname;
+  else 
+    dirname = sub->dirname;
+  if (sub->mask_filename)
+    filename = sub->mask_filename;
+  else 
+    filename = event->name;
+    
   if (event->name)
-    fullpath = g_strdup_printf ("%s/%s", sub->dirname, event->name);
+    fullpath = g_strdup_printf ("%s/%s", dirname, filename);
   else
-    fullpath = g_strdup_printf ("%s/", sub->dirname);
-  
+    fullpath = g_strdup_printf ("%s/", dirname);
+
   child = g_file_new_for_path (fullpath);
   g_free (fullpath);
 
   g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
 			     child, NULL, eflags);
-
+ 
   g_object_unref (child);
   g_object_unref (parent);
+  
+  /*  If symlink target has changed, recreate watch on target  */
+  if (sub->recreate_cb)
+    emit_in_idle (sub->recreate_cb, sub->user_data);
 }
 
 static void
 ih_not_missing_callback (inotify_sub *sub)
 {
+  const gchar *dirname, *filename;
   gchar *fullpath;
   GFileMonitorEvent eflags;
   guint32 mask;
   GFile* parent;
   GFile* child;
-  
-  parent = g_file_new_for_path (sub->dirname);
 
-  if (sub->filename)
+
+  if (sub->mask_dirname)
+    dirname = sub->mask_dirname;
+  else 
+    dirname = sub->dirname;
+  if (sub->mask_filename)
+    filename = sub->mask_filename;
+  else 
+    filename = sub->filename;
+
+  parent = g_file_new_for_path (dirname);
+
+  if (filename)
     {
-      fullpath = g_strdup_printf ("%s/%s", sub->dirname, sub->filename);
+      fullpath = g_strdup_printf ("%s/%s", dirname, filename);
       g_warning ("Missing callback called fullpath = %s\n", fullpath);
       if (!g_file_test (fullpath, G_FILE_TEST_EXISTS))
 	{
@@ -189,7 +252,7 @@
     }
   else
     {
-      fullpath = g_strdup_printf ("%s", sub->dirname);
+      fullpath = g_strdup_printf ("%s", dirname);
       mask = IN_CREATE|IN_ISDIR;
     }
 
@@ -202,6 +265,9 @@
 
   g_object_unref (child);
   g_object_unref (parent);
+
+  /*  We don't need symlink recreate call here 
+   *  but keep this in mind when design changes  */
 }
 
 /* Transforms a inotify event to a GVFS event. */
Index: gio/inotify/ginotifyfilemonitor.c
===================================================================
--- gio/inotify/ginotifyfilemonitor.c	(revision 7271)
+++ gio/inotify/ginotifyfilemonitor.c	(working copy)
@@ -30,6 +30,7 @@
 
 #define USE_INOTIFY 1
 #include "inotify-helper.h"
+#include "inotify-path.h"
 
 #include "gioalias.h"
 
@@ -39,9 +40,11 @@
   gchar *filename;
   gchar *dirname;
   inotify_sub *sub;
+  inotify_sub *sub_symlink;
 };
 
 static gboolean g_inotify_file_monitor_cancel (GFileMonitor* monitor);
+static void g_inotify_file_monitor_recreate_symlink_watch (GInotifyFileMonitor* monitor);
 
 #define g_inotify_file_monitor_get_type _g_inotify_file_monitor_get_type
 G_DEFINE_TYPE_WITH_CODE (GInotifyFileMonitor, g_inotify_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
@@ -55,6 +58,7 @@
 {
   GInotifyFileMonitor *inotify_monitor = G_INOTIFY_FILE_MONITOR (object);
   inotify_sub *sub = inotify_monitor->sub;
+  inotify_sub *sub_symlink = inotify_monitor->sub_symlink;
 
   if (sub)
     {
@@ -63,6 +67,13 @@
       inotify_monitor->sub = NULL;
     }
 
+  if (sub_symlink)
+    {
+      _ih_sub_cancel (sub_symlink);
+      _ih_sub_free (sub_symlink);
+      inotify_monitor->sub_symlink = NULL;
+    }
+
   if (inotify_monitor->filename)
     {
       g_free (inotify_monitor->filename);
@@ -117,7 +128,14 @@
   g_assert (sub != NULL);
   g_assert (_ih_sub_add (sub));
 
+  /*  If file changes, re-check if it's symlink  */
+  sub->recreate_cb = G_RECREATE_CALLBACK (g_inotify_file_monitor_recreate_symlink_watch);
+
   inotify_monitor->sub = sub;
+  inotify_monitor->sub_symlink = NULL;
+  
+  /*  resolve symlink and watch the target if succeeded  */
+  g_inotify_file_monitor_recreate_symlink_watch (inotify_monitor);
 
   return obj;
 }
@@ -152,7 +170,15 @@
 {
   GInotifyFileMonitor *inotify_monitor = G_INOTIFY_FILE_MONITOR (monitor);
   inotify_sub *sub = inotify_monitor->sub;
+  inotify_sub *sub_symlink = inotify_monitor->sub_symlink;
 
+  if (sub_symlink)
+    {
+      _ih_sub_cancel (sub_symlink);
+      _ih_sub_free (sub_symlink);
+      inotify_monitor->sub_symlink = NULL;
+    }
+
   if (sub) 
     {
       _ih_sub_cancel (sub);
@@ -166,3 +192,44 @@
   return TRUE;
 }
 
+static void 
+g_inotify_file_monitor_recreate_symlink_watch (GInotifyFileMonitor* monitor)
+{
+  gchar *filename;
+  inotify_sub *sub_symlink = NULL;
+  gchar *real_symlink_path = NULL;
+  gchar *symlink_filename, *symlink_dirname;
+
+
+  if (monitor->sub_symlink)
+    {
+      _ih_sub_cancel (monitor->sub_symlink);
+      _ih_sub_free (monitor->sub_symlink);
+      monitor->sub_symlink = NULL;
+    }
+  
+  g_assert (monitor->dirname != NULL);
+  g_assert (monitor->filename != NULL);
+
+  filename = g_build_filename (monitor->dirname, G_DIR_SEPARATOR_S, monitor->filename, NULL);
+  if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) 
+    {
+      real_symlink_path = resolve_symlink (filename);
+      
+      if (real_symlink_path)
+        {
+          symlink_filename = g_path_get_basename (real_symlink_path);
+          symlink_dirname = g_path_get_dirname (real_symlink_path);
+          sub_symlink = _ih_sub_new (symlink_dirname, symlink_filename, monitor);
+          sub_symlink->mask_dirname = monitor->dirname;
+          sub_symlink->mask_filename = monitor->filename; 
+          g_assert (sub_symlink != NULL);
+          g_assert (_ih_sub_add (sub_symlink));
+          monitor->sub_symlink = sub_symlink;
+          g_free (symlink_filename);
+          g_free (symlink_dirname);
+          g_free (real_symlink_path);
+        }
+    }
+  g_free (filename);
+}    
Index: gio/inotify/inotify-sub.c
===================================================================
--- gio/inotify/inotify-sub.c	(revision 7271)
+++ gio/inotify/inotify-sub.c	(working copy)
@@ -55,6 +55,9 @@
   sub->dirname = dup_dirname (dirname);
   sub->filename = g_strdup (filename);
   sub->user_data = user_data;
+  sub->mask_dirname = NULL;
+  sub->mask_filename = NULL;
+  sub->recreate_cb = NULL;
   
   IS_W ("new subscription for %s being setup\n", sub->dirname);
   
Index: gio/inotify/inotify-path.c
===================================================================
--- gio/inotify/inotify-path.c	(revision 7271)
+++ gio/inotify/inotify-path.c	(working copy)
@@ -30,7 +30,9 @@
 
 #include <sys/inotify.h>
 #include <string.h>
+#include <stdlib.h>
 #include <glib.h>
+#include <gio.h>
 #include "inotify-kernel.h"
 #include "inotify-path.h"
 #include "inotify-missing.h"
@@ -83,6 +85,23 @@
 
 static void (*event_callback)(ik_event_t *event, inotify_sub *sub);
 
+
+/*  for debugging purposes  */
+static void
+_ip_list_watches ()
+{
+  ip_watched_dir_t *dir;
+  GList *list;
+  
+  for (list = g_hash_table_get_values (path_dir_hash); list; list = list->next)
+    {
+      dir = list->data;
+      g_print ("  (II) _ip_list_watches: %s\n", dir->path);
+    }
+  g_list_free (list);
+}
+
+
 gboolean
 _ip_startup (void (*cb)(ik_event_t *event, inotify_sub *sub))
 {
@@ -320,6 +339,11 @@
 	{
 	  inotify_sub *sub = subl->data;
 	  
+	  /* Sub might have been modified by 
+	   * g_inotify_file_monitor_recreate_symlink_watch */
+	  if (! sub)
+	    continue;
+	  
 	  /* If the subscription and the event
 	   * contain a filename and they don't
 	   * match, we don't deliver this event.
@@ -420,3 +444,54 @@
   
   _ik_event_free (event);
 }
+
+
+gchar *
+resolve_symlink (const gchar *filename)
+{
+  gchar *real_symlink_path = NULL;
+  static char real_path [PATH_MAX];
+  gchar *symlink = NULL;
+  gchar *dirname = NULL;
+  GError *error = NULL;
+  GFile *file = NULL;
+  GFile *rfile = NULL;
+
+  if (filename == NULL)
+    return NULL;
+  
+  if (realpath (filename, &real_path[0]))
+    {
+      return g_strdup (&real_path[0]);
+    }
+  else
+    {
+      /*  symlink probably doesn't exist, create path manually for the MISSING watch  */
+      /*  Please note this will resolve symlink only one level deep  */
+      symlink = g_file_read_link (filename, &error);
+      if (error) 
+        {
+          IP_W ("resolve_symlink error: %s", error->message);
+          g_error_free (error);
+          return NULL;
+        }
+      if (symlink)
+        {
+          if (g_path_is_absolute (symlink))
+            return symlink;
+          
+          /*  assuming relative path  */
+          /*  construct GFile object and let it cannonicalize filename  */
+          dirname = g_path_get_dirname (filename);
+          file = g_file_new_for_path (dirname);
+          rfile = g_file_resolve_relative_path (file, symlink);
+          real_symlink_path = g_file_get_path (rfile);
+          g_object_unref (file);
+          g_object_unref (rfile);
+          g_free (dirname);
+          g_free (symlink);
+          return real_symlink_path;
+        }
+      return NULL;
+    }  
+}
Index: gio/inotify/inotify-sub.h
===================================================================
--- gio/inotify/inotify-sub.h	(revision 7271)
+++ gio/inotify/inotify-sub.h	(working copy)
@@ -24,12 +24,19 @@
 #ifndef __INOTIFY_SUB_H
 #define __INOTIFY_SUB_H
 
+typedef void  (*GRecreateCallback)  (gpointer user_data);
+#define G_RECREATE_CALLBACK(f)      ((GRecreateCallback) (f))
+
+
 typedef struct
 {
 	gchar*   dirname;
 	gchar*   filename;
 	gboolean cancelled;
 	gpointer user_data;
+	const gchar* mask_dirname;
+	const gchar* mask_filename;
+	GRecreateCallback recreate_cb;
 } inotify_sub;
 
 inotify_sub* _ih_sub_new (const gchar* dirname, const gchar* filename, gpointer user_data);
Index: gio/inotify/inotify-path.h
===================================================================
--- gio/inotify/inotify-path.h	(revision 7271)
+++ gio/inotify/inotify-path.h	(working copy)
@@ -30,4 +30,7 @@
 gboolean _ip_start_watching (inotify_sub *sub);
 gboolean _ip_stop_watching  (inotify_sub *sub);
 
+/*  Utilities  */
+gchar *  resolve_symlink (const gchar *filename);
+
 #endif
Index: gio/inotify/ginotifydirectorymonitor.c
===================================================================
--- gio/inotify/ginotifydirectorymonitor.c	(revision 7271)
+++ gio/inotify/ginotifydirectorymonitor.c	(working copy)
@@ -23,6 +23,7 @@
  *          Sebastian Dröge <slomo@circular-chaos.org>
  */
 
+
 #include "config.h"
 
 #include "ginotifydirectorymonitor.h"
@@ -30,6 +31,7 @@
 
 #define USE_INOTIFY 1
 #include "inotify-helper.h"
+#include "inotify-path.h"
 
 #include "gioalias.h"
 
@@ -37,9 +39,11 @@
 {
   GLocalDirectoryMonitor parent_instance;
   inotify_sub *sub;
+  inotify_sub *sub_symlink;
 };
 
 static gboolean g_inotify_directory_monitor_cancel (GFileMonitor* monitor);
+static void g_inotify_directory_monitor_recreate_watch (GInotifyDirectoryMonitor* monitor);
 
 #define g_inotify_directory_monitor_get_type _g_inotify_directory_monitor_get_type
 G_DEFINE_TYPE_WITH_CODE (GInotifyDirectoryMonitor, g_inotify_directory_monitor, G_TYPE_LOCAL_DIRECTORY_MONITOR,
@@ -53,7 +57,15 @@
 {
   GInotifyDirectoryMonitor *inotify_monitor = G_INOTIFY_DIRECTORY_MONITOR (object);
   inotify_sub *sub = inotify_monitor->sub;
+  inotify_sub *sub_symlink = inotify_monitor->sub_symlink;
 
+  if (sub_symlink)
+    {
+      _ih_sub_cancel (sub_symlink);
+      _ih_sub_free (sub_symlink);
+      inotify_monitor->sub_symlink = NULL;
+    }
+
   if (sub)
     {
       _ih_sub_cancel (sub);
@@ -75,7 +87,8 @@
   GObjectClass *parent_class;
   GInotifyDirectoryMonitor *inotify_monitor;
   const gchar *dirname = NULL;
-  inotify_sub *sub = NULL;
+  inotify_sub *sub_symlink = NULL;
+  gchar *symlink_filename, *symlink_dirname;
   
   klass = G_INOTIFY_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_INOTIFY_DIRECTORY_MONITOR));
   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
@@ -91,15 +104,22 @@
   /* Will never fail as is_supported() should be called before instanciating
    * anyway */
   g_assert (_ih_startup ());
+  inotify_monitor->sub = NULL;
+  inotify_monitor->sub_symlink = NULL;
+  
+  /*  if watched directory is a symlink, watch itself and update watch accordingly  */
+  symlink_filename = g_path_get_basename (dirname);
+  symlink_dirname = g_path_get_dirname (dirname);
+  sub_symlink = _ih_sub_new (symlink_dirname, symlink_filename, inotify_monitor);
+  sub_symlink->recreate_cb = G_RECREATE_CALLBACK (g_inotify_directory_monitor_recreate_watch);
+  g_assert (sub_symlink != NULL);
+  g_assert (_ih_sub_add (sub_symlink));
+  inotify_monitor->sub_symlink = sub_symlink;
+  g_free (symlink_filename);
+  g_free (symlink_dirname);
+  
+  g_inotify_directory_monitor_recreate_watch (inotify_monitor);
 
-  sub = _ih_sub_new (dirname, NULL, inotify_monitor);
-  /* FIXME: what to do about errors here? we can't return NULL or another
-   * kind of error and an assertion is probably too hard */
-  g_assert (sub != NULL);
-  g_assert (_ih_sub_add (sub));
-
-  inotify_monitor->sub = sub;
-
   return obj;
 }
 
@@ -134,7 +154,15 @@
 {
   GInotifyDirectoryMonitor *inotify_monitor = G_INOTIFY_DIRECTORY_MONITOR (monitor);
   inotify_sub *sub = inotify_monitor->sub;
+  inotify_sub *sub_symlink = inotify_monitor->sub_symlink;
 
+  if (sub_symlink) 
+    {
+      _ih_sub_cancel (sub_symlink);
+      _ih_sub_free (sub_symlink);
+      inotify_monitor->sub_symlink = NULL;
+    }
+
   if (sub) 
     {
       _ih_sub_cancel (sub);
@@ -148,3 +176,39 @@
   return TRUE;
 }
 
+static void 
+g_inotify_directory_monitor_recreate_watch (GInotifyDirectoryMonitor* monitor)
+{
+  const gchar *dirname = NULL;
+  gchar *monitor_path = NULL;
+  inotify_sub *sub = NULL;
+
+
+  if (monitor->sub)
+    {
+      _ih_sub_cancel (monitor->sub);
+      _ih_sub_free (monitor->sub);
+      monitor->sub = NULL;
+    }
+
+  dirname = G_LOCAL_DIRECTORY_MONITOR (monitor)->dirname;
+  g_assert (dirname != NULL);
+
+  monitor_path = NULL;
+  if (g_file_test (dirname, G_FILE_TEST_IS_SYMLINK)) 
+    monitor_path = resolve_symlink (dirname);
+  
+  /*  if symlink resolve fails, watch itself and hope inotify will follow symlinks  */
+  if (monitor_path == NULL)
+    monitor_path = g_strdup (dirname);
+
+  sub = _ih_sub_new (monitor_path, NULL, monitor);
+  /* FIXME: what to do about errors here? we can't return NULL or another
+   * kind of error and an assertion is probably too hard */
+  sub->mask_dirname = dirname;
+  g_assert (sub != NULL);
+  g_assert (_ih_sub_add (sub));
+  monitor->sub = sub;
+  
+  g_free (monitor_path);
+}    
