void MonitorDesktopFileDirs (GLib.File dir)
		{
			// build a list of all the subdirectories
			List<GLib.File> dirs = new List<GLib.File> () {dir};
			try {
				dirs = dirs.Union (dir.SubDirs ()).ToList ();	
			} catch {}
			
			foreach (GLib.File d in dirs) {
				GLib.FileMonitor mon = d.Monitor (GLib.FileMonitorFlags.None, null);
				mon.RateLimit = 2500;
				mon.Changed += delegate(object o, GLib.ChangedArgs args) {
					// bug in GIO#, calling args.File or args.OtherFile crashes hard
					GLib.File file = GLib.FileAdapter.GetObject ((GLib.Object) args.Args [0]);
					GLib.File otherFile = GLib.FileAdapter.GetObject ((GLib.Object) args.Args [1]);

					// according to GLib documentation, the change signal runs on the same
					// thread that the monitor was created on.  Without running this part on a thread
					// docky freezes up for about 500-800 ms while the .desktop files are parsed.
					DockServices.System.RunOnThread (() => {
						// if a new directory was created, make sure we watch that dir as well
						if (file.QueryFileType (GLib.FileQueryInfoFlags.NofollowSymlinks, null) == GLib.FileType.Directory)
							MonitorDesktopFileDirs (file);
						
						// we only care about .desktop files
						if (!file.Path.EndsWith (".desktop"))
							return;

						lock (update_lock) {
							UpdateDesktopItemsList ();
							DesktopItemsChanged ();
							SaveDesktopItemsCache();
						}
						
						// Make sure to trigger event on main thread
						DockServices.System.RunOnMainThread (() => {
							if (DesktopFileChanged != null)
								DesktopFileChanged (this, new DesktopFileChangedEventArgs (args.EventType, file, otherFile));
						});
					});
				};
			}
		}