--- 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 #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 #include #include +#include #include +#include #include #include #include @@ -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); +}