--- /dev/null
+--- desktop-file-utils-0.6/src/menu-process.c.directory-change-notify 2004-05-03 23:46:00.074881280 -0400
++++ desktop-file-utils-0.6/src/menu-process.c 2004-05-03 23:47:09.124384160 -0400
+@@ -41,8 +41,16 @@
+ const char *name,
+ gboolean create_if_not_found);
+
++static DesktopEntryTreeDirAddCallback dir_add_callback = NULL;
++void desktop_entry_tree_dir_add_notify (void *element, void *user_data);
+
+
++void
++desktop_entry_tree_diradd_callback_set (DesktopEntryTreeDirAddCallback proc)
++{
++ dir_add_callback = proc;
++}
++
+ static MenuNode*
+ find_menu_child (MenuNode *node)
+ {
+@@ -1005,6 +1013,7 @@
+ MenuNode *orig_node;
+ MenuNode *resolved_node;
+ TreeNode *root;
++ GSList *monitored_dirs;
+ };
+
+ static void build_tree (DesktopEntryTree *tree);
+@@ -1015,6 +1024,21 @@
+ static char* localized_path_for_entry (TreeNode *parent,
+ Entry *entry);
+ static char* localized_path_for_node (TreeNode *node);
++static TreeNode* tree_node_from_menu_node (TreeNode *parent,
++ MenuNode *menu_node,
++ GHashTable *allocated,
++ const DesktopEntryTree *tree);
++static void remove_empty_submenus (TreeNode * node);
++static void process_only_unallocated (TreeNode *node,
++ GHashTable *allocated);
++
++const char *desktop_entry_tree_get_menu_file_name (DesktopEntryTree *tree)
++{
++ g_return_val_if_fail (tree != NULL, NULL);
++
++ return tree->menu_file;
++}
++
+
+ DesktopEntryTree*
+ desktop_entry_tree_load (const char *filename,
+@@ -1083,6 +1107,7 @@
+ tree->orig_node = orig_node;
+ tree->resolved_node = resolved_node;
+ tree->root = NULL;
++ tree->monitored_dirs = NULL;
+
+ return tree;
+ }
+@@ -1096,6 +1121,14 @@
+ tree->refcount += 1;
+ }
+
++static void
++monitored_dir_list_clear (void *element,
++ void *user_data)
++{
++ GSList *list = element;
++ g_free (list->data);
++}
++
+ void
+ desktop_entry_tree_unref (DesktopEntryTree *tree)
+ {
+@@ -1111,10 +1144,15 @@
+ menu_node_unref (tree->orig_node);
+ menu_node_unref (tree->resolved_node);
+ if (tree->root)
++ {
+ tree_node_free (tree->root);
++ tree->root = NULL;
++ }
++ g_slist_foreach (tree->monitored_dirs, monitored_dir_list_clear, NULL);
++ g_slist_free (tree->monitored_dirs);
+ entry_cache_unref (tree->entry_cache);
+ menu_cache_unref (tree->menu_cache);
+-#if 1
++#if 0
+ /* debugging, to make memory stuff fail */
+ memset (tree, 0xff, sizeof (*tree));
+ tree->refcount = -5;
+@@ -1125,12 +1163,42 @@
+
+ void
+ desktop_entry_tree_invalidate (DesktopEntryTree *tree,
+- const char *dirname)
++ const char *menu_file,
++ const char *entry_path)
+ {
+- menu_cache_invalidate (tree->menu_cache, dirname);
++ GHashTable *allocated;
++ TreeNode *new_node;
++ char *dirname;
++
++ /* menu_file: the actual .menu file to reload */
++ /* entry_dir: actual FS directory of .desktop files to reload */
++ menu_cache_invalidate (tree->menu_cache, menu_file);
++ dirname = g_path_get_dirname (entry_path);
+ entry_cache_invalidate (tree->entry_cache, dirname);
++ g_free (dirname);
++
++ /* FIXME For the actual DesktopEntryTree itself, there aren't really
++ * invalidation functions yet (FIXME). Therefore, we blow away the root
++ * and rebuild it every time.
++ */
++ allocated = g_hash_table_new (NULL, NULL);
++
++ new_node = tree_node_from_menu_node (NULL,
++ find_menu_child (tree->resolved_node),
++ allocated,
++ tree);
++ if (new_node)
++ {
++ tree_node_free (tree->root);
++ tree->root = new_node;
++ process_only_unallocated (tree->root, allocated);
++ remove_empty_submenus (tree->root);
++ }
++
++ g_hash_table_destroy (allocated);
+ }
+
++
+ static TreeNode*
+ find_subdir (TreeNode *parent,
+ const char *subdir)
+@@ -1634,7 +1702,11 @@
+ {
+ GSList *tmp;
+
++ if (!node)
++ return;
++
+ g_free (node->name);
++ node->name = NULL;
+
+ tmp = node->subdirs;
+ while (tmp != NULL)
+@@ -1812,10 +1884,39 @@
+ }
+ #endif
+
++/* Called from an entry_directory_list_foreach()... */
++void
++desktop_entry_tree_dir_add_notify (void *element, void *user_data)
++{
++ EntryDirectory *dir = element;
++ DesktopEntryTree *tree = user_data;
++ GSList *tmp;
++ const char *path;
++
++ g_return_if_fail (dir != NULL);
++ path = entry_directory_get_absolute_path (dir);
++
++ /* Ensure we haven't already set a callback for this directory with
++ * this tree.
++ */
++ tmp = tree->monitored_dirs;
++ while (tmp != NULL)
++ {
++ if (strcmp (tmp->data, path) == 0)
++ return;
++ tmp = tmp->next;
++ }
++
++ tree->monitored_dirs = g_slist_append (tree->monitored_dirs, g_strdup (path));
++ if (dir_add_callback)
++ (*dir_add_callback) (tree, path);
++}
++
+ static TreeNode*
+ tree_node_from_menu_node (TreeNode *parent,
+ MenuNode *menu_node,
+- GHashTable *allocated)
++ GHashTable *allocated,
++ const DesktopEntryTree *tree)
+ {
+ MenuNode *child;
+ EntryDirectoryList *app_dirs;
+@@ -1854,7 +1955,8 @@
+
+ child_tree = tree_node_from_menu_node (tree_node,
+ child,
+- allocated);
++ allocated,
++ tree);
+ if (child_tree)
+ tree_node->subdirs = g_slist_prepend (tree_node->subdirs,
+ child_tree);
+@@ -2012,7 +2114,12 @@
+ if (tree_node_free_if_broken (tree_node))
+ return NULL;
+ else
++ {
++ /* Monitor directories containing .desktop & .directory files for changes */
++ entry_directory_list_foreach (app_dirs, desktop_entry_tree_dir_add_notify, tree);
++ entry_directory_list_foreach (dir_dirs, desktop_entry_tree_dir_add_notify, tree);
+ return tree_node;
++ }
+ }
+
+ static void
+@@ -2102,7 +2209,8 @@
+
+ tree->root = tree_node_from_menu_node (NULL,
+ find_menu_child (tree->resolved_node),
+- allocated);
++ allocated,
++ tree);
+ if (tree->root)
+ process_only_unallocated (tree->root, allocated);
+
+--- desktop-file-utils-0.6/src/menu-process.h.directory-change-notify 2004-03-21 23:46:20.000000000 -0500
++++ desktop-file-utils-0.6/src/menu-process.h 2004-05-03 23:46:00.403831272 -0400
+@@ -67,7 +67,8 @@
+
+ /* after calling this, the tree is out-of-date vs. what's on disk */
+ void desktop_entry_tree_invalidate (DesktopEntryTree *tree,
+- const char *dirname);
++ const char *menu_file,
++ const char *entry_path);
+
+ /* These don't return references; the DesktopEntryTree is just immutable. */
+ gboolean desktop_entry_tree_get_node (DesktopEntryTree *tree,
+@@ -134,6 +135,11 @@
+ const char *menu_path_basename,
+ const char *override_fs_dirname_dest,
+ GError **error);
++const char *desktop_entry_tree_get_menu_file_name (DesktopEntryTree *tree);
++
++/* Callback for each .desktop directory added */
++typedef void (*DesktopEntryTreeDirAddCallback)(DesktopEntryTree * tree, const char *path);
++void desktop_entry_tree_diradd_callback_set (DesktopEntryTreeDirAddCallback proc);
+
+
+ /* Diff */
+--- desktop-file-utils-0.6/src/menu-tree-cache.c.directory-change-notify 2004-05-03 23:45:59.753930072 -0400
++++ desktop-file-utils-0.6/src/menu-tree-cache.c 2004-05-03 23:46:00.407830664 -0400
+@@ -491,7 +491,7 @@
+ /* tell the tree that it needs to reload the .desktop file
+ * cache
+ */
+- desktop_entry_tree_invalidate (tree, override_dir);
++ desktop_entry_tree_invalidate (tree, override_dir, override_dir);
+
+ /* Now include the .desktop file in the .menu file */
+ if (!desktop_entry_tree_include (tree,
+@@ -583,7 +583,7 @@
+ /* tell the tree that it needs to reload the .desktop file
+ * cache
+ */
+- desktop_entry_tree_invalidate (tree, override_dir);
++ desktop_entry_tree_invalidate (tree, override_dir, override_dir);
+
+ /* Now include the .desktop file in the .menu file */
+ if (!desktop_entry_tree_exclude (tree,
+--- desktop-file-utils-0.6/src/menu-entries.c.directory-change-notify 2004-03-21 23:46:20.000000000 -0500
++++ desktop-file-utils-0.6/src/menu-entries.c 2004-05-03 23:46:00.413829752 -0400
+@@ -247,32 +247,29 @@
+ const char *path)
+ {
+ CachedDir* dir;
+- char *dirname;
+ char *basename;
++ char *dirname;
+ char *canonical;
+ Entry *retval;
+
+ retval = NULL;
+- dirname = g_path_get_basename (path);
+-
+- canonical = g_canonicalize_file_name (dirname, FALSE);
++ canonical = g_canonicalize_file_name (path, FALSE);
+ if (canonical == NULL)
+ {
+ menu_verbose ("Error %d getting entry \"%s\": %s\n", errno, path,
+ g_strerror (errno));
+- g_free (dirname);
+ return NULL;
+ }
+
+- basename = g_path_get_dirname (path);
+-
++ dirname = g_path_get_dirname (path);
+ dir = cached_dir_load (cache, dirname, 0, NULL);
+-
+ if (dir != NULL)
+- retval = cached_dir_find_entry (dir, basename);
+-
++ {
++ basename = g_path_get_basename (path);
++ retval = cached_dir_find_entry (dir, basename);
++ g_free (basename);
++ }
+ g_free (dirname);
+- g_free (basename);
+
+ if (retval)
+ entry_ref (retval);
+@@ -344,6 +341,12 @@
+ }
+ }
+
++const char*
++entry_directory_get_absolute_path (EntryDirectory *dir)
++{
++ return dir->absolute_path;
++}
++
+ static Entry*
+ entry_from_cached_entry (EntryDirectory *ed,
+ Entry *src,
+@@ -681,6 +684,12 @@
+ }
+
+ void
++entry_directory_list_foreach (EntryDirectoryList *list, EntryDirectoryListForeachProc proc, DesktopEntryTree *tree)
++{
++ g_slist_foreach (list->dirs, proc, tree);
++}
++
++void
+ entry_directory_list_prepend (EntryDirectoryList *list,
+ EntryDirectory *dir)
+ {
+@@ -1501,6 +1510,7 @@
+ while (tmp != NULL)
+ {
+ g_string_append (str, tmp->data);
++ g_string_append (str, "/");
+
+ tmp = tmp->next;
+ }
+@@ -2173,6 +2183,10 @@
+ static EntryCache*
+ cached_dir_get_cache (CachedDir *dir)
+ {
++ if (!dir->have_read_entries)
++ {
++ cached_dir_scan_recursive (dir, NULL);
++ }
+ return dir->cache;
+ }
+
+--- desktop-file-utils-0.6/src/menu-entries.h.directory-change-notify 2004-03-21 23:46:20.000000000 -0500
++++ desktop-file-utils-0.6/src/menu-entries.h 2004-05-03 23:46:00.416829296 -0400
+@@ -24,6 +24,7 @@
+
+ #include <glib.h>
+ #include "menu-layout.h"
++#include "menu-process.h"
+
+ /* This API is about actually loading directories full of .desktop
+ * files and the .desktop/.directory files themselves. It also has
+@@ -84,12 +85,19 @@
+ void entry_directory_get_by_category (EntryDirectory *dir,
+ const char *category,
+ EntrySet *add_to_set);
++const char* entry_directory_get_absolute_path (EntryDirectory *dir);
++
++typedef void (*EntryDirectoryListForeachProc)(void *element, void *user_data);
+
+ EntryDirectoryList* entry_directory_list_new (void);
+
+ void entry_directory_list_ref (EntryDirectoryList *list);
+ void entry_directory_list_unref (EntryDirectoryList *list);
+ void entry_directory_list_clear (EntryDirectoryList *list);
++void entry_directory_list_foreach (EntryDirectoryList *list,
++ EntryDirectoryListForeachProc proc,
++ DesktopEntryTree *tree);
++
+ /* prepended dirs are searched first */
+ void entry_directory_list_prepend (EntryDirectoryList *list,
+ EntryDirectory *dir);
+--- desktop-file-utils-0.6/src/menu-method.c.directory-change-notify 2004-05-03 23:45:59.440977648 -0400
++++ desktop-file-utils-0.6/src/menu-method.c 2004-05-03 23:46:00.423828232 -0400
+@@ -29,9 +29,11 @@
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <errno.h>
++#include <stdio.h>
+
+ #include <config.h>
+
++#include <libgnomevfs/gnome-vfs-ops.h>
+ #include <libgnomevfs/gnome-vfs-method.h>
+ #include <libgnomevfs/gnome-vfs-module-shared.h>
+ #include <libgnomevfs/gnome-vfs-module.h>
+@@ -46,6 +48,8 @@
+
+ #include "menu-tree-cache.h"
+ #include "menu-util.h"
++#include "menu-entries.h"
++#include "menu-process.h"
+
+ /* FIXME - we have a gettext domain problem while not included in libgnomevfs */
+ #define _(x) x
+@@ -151,6 +155,14 @@
+ static void monitor_handle_ref (MonitorHandle *handle);
+ static void monitor_handle_unref (MonitorHandle *handle);
+
++
++static void directory_add_callback (DesktopEntryTree * tree, const char * path);
++void directory_monitor_callback (GnomeVFSMonitorHandle *handle,
++ const gchar *monitor_uri,
++ const gchar *info_uri,
++ GnomeVFSMonitorEventType event_type,
++ gpointer user_data);
++
+ struct {
+ const char *scheme;
+ const char *menu_file;
+@@ -737,6 +749,7 @@
+ GnomeVFSMethod *
+ vfs_module_init (const char *method_name, const char *args)
+ {
++ desktop_entry_tree_diradd_callback_set (directory_add_callback);
+ return &vtable;
+ }
+
+@@ -1988,3 +2001,33 @@
+ g_free (handle);
+ }
+ }
++
++static void
++directory_add_callback (DesktopEntryTree * tree, const char * path)
++{
++ GnomeVFSMonitorHandle* handle;
++
++ gnome_vfs_monitor_add (&handle, path,
++ GNOME_VFS_MONITOR_DIRECTORY,
++ directory_monitor_callback, tree);
++}
++
++
++void directory_monitor_callback (GnomeVFSMonitorHandle *handle,
++ const gchar *monitor_uri,
++ const gchar *info_uri,
++ GnomeVFSMonitorEventType event_type,
++ gpointer user_data)
++{
++ MenuMethod * method;
++ DesktopEntryTree * tree = user_data;
++
++ method = method_checkout ();
++
++ if (tree)
++ desktop_entry_tree_invalidate( tree,
++ desktop_entry_tree_get_menu_file_name (tree),
++ gnome_vfs_get_local_path_from_uri (info_uri));
++
++ method_return (method);
++}
--- /dev/null
+--- desktop-file-utils-0.6/src/menu-process.c.directory-mtime 2004-05-03 23:09:03.888792776 -0400
++++ desktop-file-utils-0.6/src/menu-process.c 2004-05-03 23:09:03.934785784 -0400
+@@ -1005,6 +1005,10 @@
+ /* make a shorter name */
+ typedef struct DesktopEntryTreeNode TreeNode;
+
++/* FIXME modification time is kept on the tree right now,
++ * but should really be kept on the individual Entries and
++ * subdirs themselves.
++ */
+ struct DesktopEntryTree
+ {
+ int refcount;
+@@ -1015,6 +1019,7 @@
+ MenuNode *orig_node;
+ MenuNode *resolved_node;
+ TreeNode *root;
++ time_t mtime;
+ GSList *monitored_dirs;
+ };
+
+@@ -1039,6 +1044,12 @@
+ return tree->menu_file;
+ }
+
++const time_t desktop_entry_tree_get_mtime (DesktopEntryTree *tree)
++{
++ g_return_val_if_fail (tree != NULL, 0);
++
++ return tree->mtime;
++}
+
+ DesktopEntryTree*
+ desktop_entry_tree_load (const char *filename,
+@@ -1107,6 +1118,7 @@
+ tree->orig_node = orig_node;
+ tree->resolved_node = resolved_node;
+ tree->root = NULL;
++ tree->mtime = time (NULL); /* Initial modification time of now */
+ tree->monitored_dirs = NULL;
+
+ return tree;
+@@ -1193,6 +1205,11 @@
+ tree->root = new_node;
+ process_only_unallocated (tree->root, allocated);
+ remove_empty_submenus (tree->root);
++
++ /* Update the modification time for the tree, so the
++ * panel knows to reload the VFS directory.
++ */
++ tree->mtime = time (NULL);
+ }
+
+ g_hash_table_destroy (allocated);
+--- desktop-file-utils-0.6/src/menu-process.h.directory-mtime 2004-05-03 23:09:03.891792320 -0400
++++ desktop-file-utils-0.6/src/menu-process.h 2004-05-03 23:09:03.937785328 -0400
+@@ -23,6 +23,7 @@
+ #define MENU_PROCESS_H
+
+ #include <glib.h>
++#include <time.h>
+ #include "desktop_file.h"
+
+ typedef struct DesktopEntryTree DesktopEntryTree;
+@@ -137,6 +138,8 @@
+ GError **error);
+ const char *desktop_entry_tree_get_menu_file_name (DesktopEntryTree *tree);
+
++const time_t desktop_entry_tree_get_mtime (DesktopEntryTree *tree);
++
+ /* Callback for each .desktop directory added */
+ typedef void (*DesktopEntryTreeDirAddCallback)(DesktopEntryTree * tree, const char *path);
+ void desktop_entry_tree_diradd_callback_set (DesktopEntryTreeDirAddCallback proc);
+--- desktop-file-utils-0.6/src/menu-method.c.directory-mtime 2004-05-03 23:09:03.912789128 -0400
++++ desktop-file-utils-0.6/src/menu-method.c 2004-05-03 23:42:05.910479680 -0400
+@@ -1024,8 +1024,9 @@
+
+ /* Fill in dir info that's true for all dirs in the vfs */
+ static void
+-fill_in_generic_dir_info (GnomeVFSFileInfo *info,
+- GnomeVFSFileInfoOptions options)
++fill_in_generic_dir_info (GnomeVFSFileInfo *info,
++ GnomeVFSFileInfoOptions options,
++ DesktopEntryTree *tree)
+ {
+ info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
+
+@@ -1048,10 +1049,16 @@
+ /* We always own it */
+ info->uid = getuid ();
+ info->gid = getgid ();
+-
++
++ /* FIXME mtime is currently taken from the tree itself,
++ * and is not stored on the actual VFS objects themselves.
++ */
++ info->mtime = desktop_entry_tree_get_mtime (tree);
++
+ info->valid_fields |=
+ GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+- GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
++ GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS |
++ GNOME_VFS_FILE_INFO_FIELDS_MTIME;
+ }
+
+ static void
+@@ -1064,13 +1071,14 @@
+ g_assert (node != NULL);
+ g_assert (file_info != NULL);
+
+- fill_in_generic_dir_info (file_info, options);
++ fill_in_generic_dir_info (file_info, options, tree);
+ }
+
+ /* Fill in file info that's true for all .desktop files */
+ static void
+ fill_in_generic_file_info (GnomeVFSFileInfo *info,
+- GnomeVFSFileInfoOptions options)
++ GnomeVFSFileInfoOptions options,
++ DesktopEntryTree *tree)
+ {
+ info->type = GNOME_VFS_FILE_TYPE_REGULAR;
+
+@@ -1097,8 +1105,14 @@
+ info->uid = getuid ();
+ info->gid = getgid ();
+
++ /* FIXME mtime is currently taken from the tree itself,
++ * and is not stored on the actual VFS objects themselves.
++ */
++ info->mtime = desktop_entry_tree_get_mtime (tree);
++
+ info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+- GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
++ GNOME_VFS_FILE_INFO_FIELDS_MTIME |
++ GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
+ }
+
+ static void
+@@ -1113,7 +1127,7 @@
+ g_assert (path != NULL);
+ g_assert (file_info != NULL);
+
+- fill_in_generic_file_info (file_info, options);
++ fill_in_generic_file_info (file_info, options, tree);
+ }
+
+ static GnomeVFSResult
+@@ -1452,9 +1466,9 @@
+ handle->current += 1;
+
+ if (handle->current <= handle->n_entries_that_are_subdirs) {
+- fill_in_generic_dir_info (info, handle->options);
++ fill_in_generic_dir_info (info, handle->options, handle->tree);
+ } else {
+- fill_in_generic_file_info (info, handle->options);
++ fill_in_generic_file_info (info, handle->options, handle->tree);
+ }
+
+ info->valid_fields &= ~ UNSUPPORTED_INFO_FIELDS;