diff -Nru menu-cache-0.3.2/debian/changelog menu-cache-0.3.2/debian/changelog --- menu-cache-0.3.2/debian/changelog 2010-03-14 10:58:12.000000000 +0000 +++ menu-cache-0.3.2/debian/changelog 2011-01-25 21:04:48.000000000 +0000 @@ -1,3 +1,12 @@ +menu-cache (0.3.2-2ubuntu1~ppa6) natty; urgency=low + + * debian/patches/initialize-locale.patch + - Correctly initialize locale to get Ubuntu translations (LP: #551281). + - debian/patches/gmenu-2.30.5.patch: + - Update internal copy of gmenu files to 2.30.5. + + -- Julien Lavergne Tue, 25 Jan 2011 21:55:36 +0100 + menu-cache (0.3.2-2) unstable; urgency=low * Added soname in libexec dir path. (Closes:#573119) diff -Nru menu-cache-0.3.2/debian/control menu-cache-0.3.2/debian/control --- menu-cache-0.3.2/debian/control 2010-03-14 07:13:00.000000000 +0000 +++ menu-cache-0.3.2/debian/control 2011-01-25 20:57:36.000000000 +0000 @@ -1,6 +1,7 @@ Source: menu-cache Priority: extra -Maintainer: Debian LXDE Packaging Team +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian LXDE Packaging Team Uploaders: Andrew Lee (李健秋) Build-Depends: debhelper (>= 7), autotools-dev, libglib2.0-dev, intltool Standards-Version: 3.8.4 diff -Nru menu-cache-0.3.2/debian/patches/gmenu-2.30.5.patch menu-cache-0.3.2/debian/patches/gmenu-2.30.5.patch --- menu-cache-0.3.2/debian/patches/gmenu-2.30.5.patch 1970-01-01 00:00:00.000000000 +0000 +++ menu-cache-0.3.2/debian/patches/gmenu-2.30.5.patch 2011-01-25 20:53:53.000000000 +0000 @@ -0,0 +1,3508 @@ +--- menu-cache-0.3.2.orig/menu-cache-gen/entry-directories.c ++++ menu-cache-0.3.2/menu-cache-gen/entry-directories.c +@@ -454,6 +454,12 @@ handle_cached_dir_changed (MenuMonitor + + if (handled) + { ++ /* CHANGED events don't change the set of desktop entries */ ++ if (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED) ++ { ++ _entry_directory_list_empty_desktop_cache (); ++ } ++ + cached_dir_invoke_monitors (dir); + } + } +@@ -1078,6 +1084,31 @@ entry_directory_list_get_directory (Entr + return retval; + } + ++gboolean ++_entry_directory_list_compare (const EntryDirectoryList *a, ++ const EntryDirectoryList *b) ++{ ++ GList *al, *bl; ++ ++ if (a == NULL && b == NULL) ++ return TRUE; ++ ++ if ((a == NULL || b == NULL)) ++ return FALSE; ++ ++ if (a->length != b->length) ++ return FALSE; ++ ++ al = a->dirs; bl = b->dirs; ++ while (al && bl && al->data == bl->data) ++ { ++ al = al->next; ++ bl = bl->next; ++ } ++ ++ return (al == NULL && bl == NULL); ++} ++ + static gboolean + get_all_func (EntryDirectory *ed, + DesktopEntry *entry, +@@ -1101,14 +1132,26 @@ get_all_func (EntryDirectory *ed, + return TRUE; + } + ++static DesktopEntrySet *entry_directory_last_set = NULL; ++static EntryDirectoryList *entry_directory_last_list = NULL; ++ + void +-entry_directory_list_get_all_desktops (EntryDirectoryList *list, +- DesktopEntrySet *set) ++_entry_directory_list_empty_desktop_cache (void) + { +- GList *tmp; ++ if (entry_directory_last_set != NULL) ++ desktop_entry_set_unref (entry_directory_last_set); ++ entry_directory_last_set = NULL; + +- menu_verbose (" Storing all of list %p in set %p\n", +- list, set); ++ if (entry_directory_last_list != NULL) ++ entry_directory_list_unref (entry_directory_last_list); ++ entry_directory_last_list = NULL; ++} ++ ++DesktopEntrySet * ++_entry_directory_list_get_all_desktops (EntryDirectoryList *list) ++{ ++ GList *tmp; ++ DesktopEntrySet *set; + + /* The only tricky thing here is that desktop files later + * in the search list with the same relative path +@@ -1123,6 +1166,23 @@ entry_directory_list_get_all_desktops (E + * entry) + */ + ++ /* This method is -extremely- slow, so we have a simple ++ one-entry cache here */ ++ if (_entry_directory_list_compare (list, entry_directory_last_list)) ++ { ++ menu_verbose (" Hit desktop list (%p) cache\n", list); ++ return desktop_entry_set_ref (entry_directory_last_set); ++ } ++ ++ if (entry_directory_last_set != NULL) ++ desktop_entry_set_unref (entry_directory_last_set); ++ if (entry_directory_last_list != NULL) ++ entry_directory_list_unref (entry_directory_last_list); ++ ++ set = desktop_entry_set_new (); ++ menu_verbose (" Storing all of list %p in set %p\n", ++ list, set); ++ + tmp = g_list_last (list->dirs); + while (tmp != NULL) + { +@@ -1130,6 +1190,11 @@ entry_directory_list_get_all_desktops (E + + tmp = tmp->prev; + } ++ ++ entry_directory_last_list = entry_directory_list_ref (list); ++ entry_directory_last_set = desktop_entry_set_ref (set); ++ ++ return set; + } + + void +--- menu-cache-0.3.2.orig/menu-cache-gen/desktop-entries.h ++++ menu-cache-0.3.2/menu-cache-gen/desktop-entries.h +@@ -46,10 +46,10 @@ const char *desktop_entry_get_base + + const char *desktop_entry_get_name (DesktopEntry *entry); + const char *desktop_entry_get_generic_name (DesktopEntry *entry); ++const char *desktop_entry_get_full_name (DesktopEntry *entry); + const char *desktop_entry_get_comment (DesktopEntry *entry); + const char *desktop_entry_get_icon (DesktopEntry *entry); + const char *desktop_entry_get_exec (DesktopEntry *entry); +-const GQuark *desktop_entry_get_categories (DesktopEntry *entry); + gboolean desktop_entry_get_launch_in_terminal (DesktopEntry *entry); + gboolean desktop_entry_get_use_startup_notify (DesktopEntry *entry); + +--- menu-cache-0.3.2.orig/menu-cache-gen/menu-cache-gen.c ++++ menu-cache-0.3.2/menu-cache-gen/menu-cache-gen.c +@@ -179,8 +179,8 @@ static void write_entry( FILE* of, GMenu + fprintf( of, "\n-1\n" ); + } + +- /* GenericName */ +- str = gmenu_tree_entry_get_generic_name( item ); ++ /* DisplayName */ ++ str = gmenu_tree_entry_get_display_name( item ); + fprintf( of, "%s\n", str ? str : "" ); + + /* Exec */ +--- menu-cache-0.3.2.orig/menu-cache-gen/menu-monitor.c ++++ menu-cache-0.3.2/menu-cache-gen/menu-monitor.c +@@ -256,8 +256,6 @@ static MenuMonitor * + lookup_monitor (const char *path, + gboolean is_directory) + { +- return NULL; +-#if 0 + MenuMonitor *retval; + char *registry_key; + +@@ -290,7 +288,6 @@ lookup_monitor (const char *path, + + return menu_monitor_ref (retval); + } +-#endif + } + + MenuMonitor * +@@ -416,7 +413,6 @@ menu_monitor_add_notify (MenuMonitor + MenuMonitorNotifyFunc notify_func, + gpointer user_data) + { +-#if 0 + MenuMonitorNotify *notify; + GSList *tmp; + +@@ -444,7 +440,6 @@ menu_monitor_add_notify (MenuMonitor + + monitor->notifies = g_slist_append (monitor->notifies, notify); + } +-#endif + } + + void +@@ -452,7 +447,6 @@ menu_monitor_remove_notify (MenuMonitor + MenuMonitorNotifyFunc notify_func, + gpointer user_data) + { +-#if 0 + GSList *tmp; + + tmp = monitor->notifies; +@@ -473,5 +467,4 @@ menu_monitor_remove_notify (MenuMonitor + + tmp = next; + } +-#endif + } +--- menu-cache-0.3.2.orig/menu-cache-gen/gmenu-tree.h ++++ menu-cache-0.3.2/menu-cache-gen/gmenu-tree.h +@@ -66,6 +66,14 @@ typedef enum + GMENU_TREE_FLAGS_MASK = 0x0f + } GMenuTreeFlags; + ++typedef enum ++{ ++ #define GMENU_TREE_SORT_FIRST GMENU_TREE_SORT_NAME ++ GMENU_TREE_SORT_NAME = 0, ++ GMENU_TREE_SORT_DISPLAY_NAME ++ #define GMENU_TREE_SORT_LAST GMENU_TREE_SORT_DISPLAY_NAME ++} GMenuTreeSortKey; ++ + GMenuTree *gmenu_tree_lookup (const char *menu_file, + GMenuTreeFlags flags); + +@@ -77,15 +85,17 @@ void gmenu_tree_set_user_data (GMenu + GDestroyNotify dnotify); + gpointer gmenu_tree_get_user_data (GMenuTree *tree); + +-GSList *gmenu_tree_get_menu_file_monitors (GMenuTree *tree); +-GSList *gmenu_tree_get_monitors (GMenuTree *tree); +- + const char *gmenu_tree_get_menu_file (GMenuTree *tree); +-const char *gmenu_tree_get_menu_file_full_path (GMenuTree *tree); + GMenuTreeDirectory *gmenu_tree_get_root_directory (GMenuTree *tree); + GMenuTreeDirectory *gmenu_tree_get_directory_from_path (GMenuTree *tree, + const char *path); + ++GMenuTreeSortKey gmenu_tree_get_sort_key (GMenuTree *tree); ++void gmenu_tree_set_sort_key (GMenuTree *tree, ++ GMenuTreeSortKey sort_key); ++ ++ ++ + gpointer gmenu_tree_item_ref (gpointer item); + void gmenu_tree_item_unref (gpointer item); + +@@ -114,6 +124,7 @@ char *gmenu_tree_directory_make_path (GM + + const char *gmenu_tree_entry_get_name (GMenuTreeEntry *entry); + const char *gmenu_tree_entry_get_generic_name (GMenuTreeEntry *entry); ++const char *gmenu_tree_entry_get_display_name (GMenuTreeEntry *entry); + const char *gmenu_tree_entry_get_comment (GMenuTreeEntry *entry); + const char *gmenu_tree_entry_get_icon (GMenuTreeEntry *entry); + const char *gmenu_tree_entry_get_exec (GMenuTreeEntry *entry); +@@ -128,8 +139,6 @@ const char *gmenu_tree_entry_get_desktop + gboolean gmenu_tree_entry_get_is_excluded (GMenuTreeEntry *entry); + gboolean gmenu_tree_entry_get_is_nodisplay (GMenuTreeEntry *entry); + +-const GQuark *gmenu_tree_entry_get_categories (GMenuTreeEntry *entry); +- + GMenuTreeDirectory *gmenu_tree_header_get_directory (GMenuTreeHeader *header); + + GMenuTreeDirectory *gmenu_tree_alias_get_directory (GMenuTreeAlias *alias); +--- menu-cache-0.3.2.orig/menu-cache-gen/gmenu-tree.c ++++ menu-cache-0.3.2/menu-cache-gen/gmenu-tree.c +@@ -51,6 +51,7 @@ struct GMenuTree + char *canonical_path; + + GMenuTreeFlags flags; ++ GMenuTreeSortKey sort_key; + + GSList *menu_file_monitors; + +@@ -102,6 +103,10 @@ struct GMenuTreeDirectory + guint is_root : 1; + guint is_nodisplay : 1; + guint layout_pending_separator : 1; ++ guint preprocessed : 1; ++ ++ /* 16 bits should be more than enough; G_MAXUINT16 means no inline header */ ++ guint will_inline_header : 16; + }; + + typedef struct +@@ -143,16 +148,16 @@ struct GMenuTreeAlias + }; + + static GMenuTree *gmenu_tree_new (GMenuTreeType type, +- const char *menu_file, +- gboolean canonical, +- GMenuTreeFlags flags); ++ const char *menu_file, ++ gboolean canonical, ++ GMenuTreeFlags flags); + static void gmenu_tree_load_layout (GMenuTree *tree); + static void gmenu_tree_force_reload (GMenuTree *tree); + static void gmenu_tree_build_from_layout (GMenuTree *tree); + static void gmenu_tree_force_rebuild (GMenuTree *tree); + static void gmenu_tree_resolve_files (GMenuTree *tree, +- GHashTable *loaded_menu_files, +- MenuLayoutNode *layout); ++ GHashTable *loaded_menu_files, ++ MenuLayoutNode *layout); + static void gmenu_tree_force_recanonicalize (GMenuTree *tree); + static void gmenu_tree_invoke_monitors (GMenuTree *tree); + +@@ -179,7 +184,7 @@ GSList* all_used_files = NULL; + + static inline char * + get_cache_key (GMenuTree *tree, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + const char *tree_name; + +@@ -203,7 +208,7 @@ get_cache_key (GMenuTree *tree, + + static void + gmenu_tree_add_to_cache (GMenuTree *tree, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + char *cache_key; + +@@ -222,7 +227,7 @@ gmenu_tree_add_to_cache (GMenuTree + + static void + gmenu_tree_remove_from_cache (GMenuTree *tree, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + char *cache_key; + +@@ -238,12 +243,14 @@ gmenu_tree_remove_from_cache (GMenuTree + { + g_hash_table_destroy (gmenu_tree_cache); + gmenu_tree_cache = NULL; ++ ++ _entry_directory_list_empty_desktop_cache (); + } + } + + static GMenuTree * + gmenu_tree_lookup_from_cache (const char *tree_name, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + GMenuTree *retval; + char *cache_key; +@@ -278,9 +285,9 @@ typedef struct + + static void + handle_nonexistent_menu_file_changed (MenuMonitor *monitor, +- MenuMonitorEvent event, +- const char *path, +- GMenuTree *tree) ++ MenuMonitorEvent event, ++ const char *path, ++ GMenuTree *tree) + { + if (event == MENU_MONITOR_EVENT_CHANGED || + event == MENU_MONITOR_EVENT_CREATED) +@@ -296,14 +303,14 @@ handle_nonexistent_menu_file_changed (Me + + static void + handle_menu_file_changed (MenuMonitor *monitor, +- MenuMonitorEvent event, +- const char *path, ++ MenuMonitorEvent event, ++ const char *path, + GMenuTree *tree) + { + menu_verbose ("\"%s\" %s, marking tree for recanicalization\n", +- path, +- event == MENU_MONITOR_EVENT_CREATED ? "created" : +- event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted"); ++ path, ++ event == MENU_MONITOR_EVENT_CREATED ? "created" : ++ event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted"); + + gmenu_tree_force_recanonicalize (tree); + gmenu_tree_invoke_monitors (tree); +@@ -311,17 +318,17 @@ handle_menu_file_changed (MenuMonitor + + static void + handle_menu_file_directory_changed (MenuMonitor *monitor, +- MenuMonitorEvent event, +- const char *path, +- GMenuTree *tree) ++ MenuMonitorEvent event, ++ const char *path, ++ GMenuTree *tree) + { + if (!g_str_has_suffix (path, ".menu")) + return; + + menu_verbose ("\"%s\" %s, marking tree for recanicalization\n", +- path, +- event == MENU_MONITOR_EVENT_CREATED ? "created" : +- event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted"); ++ path, ++ event == MENU_MONITOR_EVENT_CREATED ? "created" : ++ event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted"); + + gmenu_tree_force_recanonicalize (tree); + gmenu_tree_invoke_monitors (tree); +@@ -329,10 +336,9 @@ handle_menu_file_directory_changed (Menu + + static void + gmenu_tree_add_menu_file_monitor (GMenuTree *tree, +- const char *path, +- MenuFileMonitorType type) ++ const char *path, ++ MenuFileMonitorType type) + { +-#if 0 + MenuFileMonitor *monitor; + + monitor = g_new0 (MenuFileMonitor, 1); +@@ -346,8 +352,8 @@ gmenu_tree_add_menu_file_monitor (GMenuT + + monitor->monitor = menu_get_file_monitor (path); + menu_monitor_add_notify (monitor->monitor, +- (MenuMonitorNotifyFunc) handle_menu_file_changed, +- tree); ++ (MenuMonitorNotifyFunc) handle_menu_file_changed, ++ tree); + break; + + case MENU_FILE_MONITOR_NONEXISTENT_FILE: +@@ -355,8 +361,8 @@ gmenu_tree_add_menu_file_monitor (GMenuT + + monitor->monitor = menu_get_file_monitor (path); + menu_monitor_add_notify (monitor->monitor, +- (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed, +- tree); ++ (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed, ++ tree); + break; + + case MENU_FILE_MONITOR_DIRECTORY: +@@ -364,8 +370,8 @@ gmenu_tree_add_menu_file_monitor (GMenuT + + monitor->monitor = menu_get_directory_monitor (path); + menu_monitor_add_notify (monitor->monitor, +- (MenuMonitorNotifyFunc) handle_menu_file_directory_changed, +- tree); ++ (MenuMonitorNotifyFunc) handle_menu_file_directory_changed, ++ tree); + break; + + default: +@@ -374,32 +380,30 @@ gmenu_tree_add_menu_file_monitor (GMenuT + } + + tree->menu_file_monitors = g_slist_prepend (tree->menu_file_monitors, monitor); +-#endif + } + + static void + remove_menu_file_monitor (MenuFileMonitor *monitor, +- GMenuTree *tree) ++ GMenuTree *tree) + { +-#if 0 + switch (monitor->type) + { + case MENU_FILE_MONITOR_FILE: + menu_monitor_remove_notify (monitor->monitor, +- (MenuMonitorNotifyFunc) handle_menu_file_changed, +- tree); ++ (MenuMonitorNotifyFunc) handle_menu_file_changed, ++ tree); + break; + + case MENU_FILE_MONITOR_NONEXISTENT_FILE: + menu_monitor_remove_notify (monitor->monitor, +- (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed, +- tree); ++ (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed, ++ tree); + break; + + case MENU_FILE_MONITOR_DIRECTORY: + menu_monitor_remove_notify (monitor->monitor, +- (MenuMonitorNotifyFunc) handle_menu_file_directory_changed, +- tree); ++ (MenuMonitorNotifyFunc) handle_menu_file_directory_changed, ++ tree); + break; + + default: +@@ -413,13 +417,11 @@ remove_menu_file_monitor (MenuFileMonito + monitor->type = MENU_FILE_MONITOR_INVALID; + + g_free (monitor); +-#endif + } + + static void + gmenu_tree_remove_menu_file_monitors (GMenuTree *tree) + { +-#if 0 + menu_verbose ("Removing all menu file monitors\n"); + + g_slist_foreach (tree->menu_file_monitors, +@@ -427,12 +429,11 @@ gmenu_tree_remove_menu_file_monitors (GM + tree); + g_slist_free (tree->menu_file_monitors); + tree->menu_file_monitors = NULL; +-#endif + } + + static GMenuTree * + gmenu_tree_lookup_absolute (const char *absolute, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + GMenuTree *tree; + gboolean canonical; +@@ -466,7 +467,7 @@ gmenu_tree_lookup_absolute (const char + + static GMenuTree * + gmenu_tree_lookup_basename (const char *basename, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + GMenuTree *tree; + +@@ -492,14 +493,14 @@ canonicalize_basename_with_config_dir (G + { + tree->canonical = TRUE; + gmenu_tree_add_menu_file_monitor (tree, +- tree->canonical_path, +- MENU_FILE_MONITOR_FILE); ++ tree->canonical_path, ++ MENU_FILE_MONITOR_FILE); + } + else + { + gmenu_tree_add_menu_file_monitor (tree, +- path, +- MENU_FILE_MONITOR_NONEXISTENT_FILE); ++ path, ++ MENU_FILE_MONITOR_NONEXISTENT_FILE); + } + + g_free (path); +@@ -575,15 +576,15 @@ gmenu_tree_canonicalize_path (GMenuTree + menu_verbose ("Successfully looked up menu_file for \"%s\": %s\n", + tree->absolute_path, tree->canonical_path); + +- /* +- * Replace the cache entry with the canonicalized version +- */ ++ /* ++ * Replace the cache entry with the canonicalized version ++ */ + gmenu_tree_remove_from_cache (tree, tree->flags); + + gmenu_tree_remove_menu_file_monitors (tree); + gmenu_tree_add_menu_file_monitor (tree, +- tree->canonical_path, +- MENU_FILE_MONITOR_FILE); ++ tree->canonical_path, ++ MENU_FILE_MONITOR_FILE); + + tree->canonical = TRUE; + +@@ -617,7 +618,7 @@ gmenu_tree_force_recanonicalize (GMenuTr + + GMenuTree * + gmenu_tree_lookup (const char *menu_file, +- GMenuTreeFlags flags) ++ GMenuTreeFlags flags) + { + GMenuTree *retval; + +@@ -637,9 +638,9 @@ gmenu_tree_lookup (const char *menu_ + + static GMenuTree * + gmenu_tree_new (GMenuTreeType type, +- const char *menu_file, +- gboolean canonical, +- GMenuTreeFlags flags) ++ const char *menu_file, ++ gboolean canonical, ++ GMenuTreeFlags flags) + { + GMenuTree *tree; + +@@ -649,6 +650,8 @@ gmenu_tree_new (GMenuTreeType type, + tree->flags = flags; + tree->refcount = 1; + ++ tree->sort_key = GMENU_TREE_SORT_NAME; ++ + if (tree->type == GMENU_TREE_BASENAME) + { + g_assert (canonical == FALSE); +@@ -660,18 +663,18 @@ gmenu_tree_new (GMenuTreeType type, + tree->absolute_path = g_strdup (menu_file); + + if (tree->canonical) +- { +- tree->canonical_path = g_strdup (menu_file); +- gmenu_tree_add_menu_file_monitor (tree, +- tree->canonical_path, +- MENU_FILE_MONITOR_FILE); +- } ++ { ++ tree->canonical_path = g_strdup (menu_file); ++ gmenu_tree_add_menu_file_monitor (tree, ++ tree->canonical_path, ++ MENU_FILE_MONITOR_FILE); ++ } + else +- { +- gmenu_tree_add_menu_file_monitor (tree, +- tree->absolute_path, +- MENU_FILE_MONITOR_NONEXISTENT_FILE); +- } ++ { ++ gmenu_tree_add_menu_file_monitor (tree, ++ tree->absolute_path, ++ MENU_FILE_MONITOR_NONEXISTENT_FILE); ++ } + } + + gmenu_tree_add_to_cache (tree, tree->flags); +@@ -725,8 +728,8 @@ gmenu_tree_unref (GMenuTree *tree) + + void + gmenu_tree_set_user_data (GMenuTree *tree, +- gpointer user_data, +- GDestroyNotify dnotify) ++ gpointer user_data, ++ GDestroyNotify dnotify) + { + g_return_if_fail (tree != NULL); + +@@ -745,16 +748,6 @@ gmenu_tree_get_user_data (GMenuTree *tre + return tree->user_data; + } + +-GSList *gmenu_tree_get_monitors (GMenuTree *tree) +-{ +- return tree->monitors; +-} +- +-GSList *gmenu_tree_get_menu_file_monitors (GMenuTree *tree) +-{ +- return tree->menu_file_monitors; +-} +- + const char * + gmenu_tree_get_menu_file (GMenuTree *tree) + { +@@ -785,17 +778,6 @@ gmenu_tree_get_menu_file (GMenuTree *tre + return tree->absolute_path; + } + +-const char * +-gmenu_tree_get_menu_file_full_path (GMenuTree *tree) +-{ +- if( ! tree->canonical_path ) +- { +- if (!gmenu_tree_canonicalize_path (tree)) +- return NULL; +- } +- return tree->canonical_path; +-} +- + GMenuTreeDirectory * + gmenu_tree_get_root_directory (GMenuTree *tree) + { +@@ -814,7 +796,7 @@ gmenu_tree_get_root_directory (GMenuTree + + static GMenuTreeDirectory * + find_path (GMenuTreeDirectory *directory, +- const char *path) ++ const char *path) + { + const char *name; + char *slash; +@@ -851,14 +833,14 @@ find_path (GMenuTreeDirectory *directory + } + + if (!strcmp (name, GMENU_TREE_DIRECTORY (item)->name)) +- { +- g_free (freeme); ++ { ++ g_free (freeme); + +- if (path) +- return find_path (GMENU_TREE_DIRECTORY (item), path); +- else +- return GMENU_TREE_DIRECTORY (item); +- } ++ if (path) ++ return find_path (GMENU_TREE_DIRECTORY (item), path); ++ else ++ return GMENU_TREE_DIRECTORY (item); ++ } + + tmp = tmp->next; + } +@@ -870,7 +852,7 @@ find_path (GMenuTreeDirectory *directory + + GMenuTreeDirectory * + gmenu_tree_get_directory_from_path (GMenuTree *tree, +- const char *path) ++ const char *path) + { + GMenuTreeDirectory *root; + GMenuTreeDirectory *directory; +@@ -891,12 +873,36 @@ gmenu_tree_get_directory_from_path (GMen + return directory ? gmenu_tree_item_ref (directory) : NULL; + } + ++GMenuTreeSortKey ++gmenu_tree_get_sort_key (GMenuTree *tree) ++{ ++ g_return_val_if_fail (tree != NULL, GMENU_TREE_SORT_NAME); ++ g_return_val_if_fail (tree->refcount > 0, GMENU_TREE_SORT_NAME); ++ ++ return tree->sort_key; ++} ++ ++void ++gmenu_tree_set_sort_key (GMenuTree *tree, ++ GMenuTreeSortKey sort_key) ++{ ++ g_return_if_fail (tree != NULL); ++ g_return_if_fail (tree->refcount > 0); ++ g_return_if_fail (sort_key >= GMENU_TREE_SORT_FIRST); ++ g_return_if_fail (sort_key <= GMENU_TREE_SORT_LAST); ++ ++ if (sort_key == tree->sort_key) ++ return; ++ ++ tree->sort_key = sort_key; ++ gmenu_tree_force_rebuild (tree); ++} ++ + void + gmenu_tree_add_monitor (GMenuTree *tree, + GMenuTreeChangedFunc callback, + gpointer user_data) + { +-#if 0 + GMenuTreeMonitor *monitor; + GSList *tmp; + +@@ -924,13 +930,12 @@ gmenu_tree_add_monitor (GMenuTree + + tree->monitors = g_slist_append (tree->monitors, monitor); + } +-#endif + } + + void + gmenu_tree_remove_monitor (GMenuTree *tree, +- GMenuTreeChangedFunc callback, +- gpointer user_data) ++ GMenuTreeChangedFunc callback, ++ gpointer user_data) + { + GSList *tmp; + +@@ -989,7 +994,7 @@ gmenu_tree_item_get_parent (GMenuTreeIte + + static void + gmenu_tree_item_set_parent (GMenuTreeItem *item, +- GMenuTreeDirectory *parent) ++ GMenuTreeDirectory *parent) + { + g_return_if_fail (item != NULL); + +@@ -1072,7 +1077,7 @@ gmenu_tree_directory_get_menu_id (GMenuT + + static void + gmenu_tree_directory_set_tree (GMenuTreeDirectory *directory, +- GMenuTree *tree) ++ GMenuTree *tree) + { + GMenuTreeDirectoryRoot *root; + +@@ -1115,7 +1120,7 @@ gmenu_tree_directory_get_is_nodisplay (G + + static void + append_directory_path (GMenuTreeDirectory *directory, +- GString *path) ++ GString *path) + { + + if (!directory->item.parent) +@@ -1132,7 +1137,7 @@ append_directory_path (GMenuTreeDirector + + char * + gmenu_tree_directory_make_path (GMenuTreeDirectory *directory, +- GMenuTreeEntry *entry) ++ GMenuTreeEntry *entry) + { + GString *path; + +@@ -1144,7 +1149,7 @@ gmenu_tree_directory_make_path (GMenuTre + + if (entry != NULL) + g_string_append (path, +- desktop_entry_get_basename (entry->desktop_entry)); ++ desktop_entry_get_basename (entry->desktop_entry)); + + return g_string_free (path, FALSE); + } +@@ -1166,6 +1171,20 @@ gmenu_tree_entry_get_generic_name (GMenu + } + + const char * ++gmenu_tree_entry_get_display_name (GMenuTreeEntry *entry) ++{ ++ const char *display_name; ++ ++ g_return_val_if_fail (entry != NULL, NULL); ++ ++ display_name = desktop_entry_get_full_name (entry->desktop_entry); ++ if (!display_name || display_name[0] == '\0') ++ display_name = desktop_entry_get_name (entry->desktop_entry); ++ ++ return display_name; ++} ++ ++const char * + gmenu_tree_entry_get_comment (GMenuTreeEntry *entry) + { + g_return_val_if_fail (entry != NULL, NULL); +@@ -1189,14 +1208,6 @@ gmenu_tree_entry_get_exec (GMenuTreeEntr + return desktop_entry_get_exec (entry->desktop_entry); + } + +-const GQuark * +-gmenu_tree_entry_get_categories (GMenuTreeEntry *entry) +-{ +- g_return_val_if_fail (entry != NULL, NULL); +- +- return desktop_entry_get_categories (entry->desktop_entry); +-} +- + gboolean + gmenu_tree_entry_get_launch_in_terminal (GMenuTreeEntry *entry) + { +@@ -1205,22 +1216,6 @@ gmenu_tree_entry_get_launch_in_terminal + return desktop_entry_get_launch_in_terminal (entry->desktop_entry); + } + +-gboolean +-gmenu_tree_entry_get_use_startup_notify (GMenuTreeEntry *entry) +-{ +- g_return_val_if_fail (entry != NULL, FALSE); +- +- return desktop_entry_get_use_startup_notify (entry->desktop_entry); +-} +- +-guint32 +-gmenu_tree_entry_get_show_in_flags (GMenuTreeEntry *entry) +-{ +- g_return_val_if_fail (entry != NULL, FALSE); +- +- return desktop_entry_get_show_in_flags (entry->desktop_entry); +-} +- + const char * + gmenu_tree_entry_get_desktop_file_path (GMenuTreeEntry *entry) + { +@@ -1253,6 +1248,22 @@ gmenu_tree_entry_get_is_nodisplay (GMenu + return entry->is_nodisplay; + } + ++gboolean ++gmenu_tree_entry_get_use_startup_notify (GMenuTreeEntry *entry) ++{ ++ g_return_val_if_fail (entry != NULL, FALSE); ++ ++ return desktop_entry_get_use_startup_notify (entry->desktop_entry); ++} ++ ++guint32 ++gmenu_tree_entry_get_show_in_flags (GMenuTreeEntry *entry) ++{ ++ g_return_val_if_fail (entry != NULL, FALSE); ++ ++ return desktop_entry_get_show_in_flags (entry->desktop_entry); ++} ++ + GMenuTreeDirectory * + gmenu_tree_header_get_directory (GMenuTreeHeader *header) + { +@@ -1279,8 +1290,8 @@ gmenu_tree_alias_get_item (GMenuTreeAlia + + static GMenuTreeDirectory * + gmenu_tree_directory_new (GMenuTreeDirectory *parent, +- const char *name, +- gboolean is_root) ++ const char *name, ++ gboolean is_root) + { + GMenuTreeDirectory *retval; + +@@ -1313,6 +1324,9 @@ gmenu_tree_directory_new (GMenuTreeDirec + retval->contents = NULL; + retval->only_unallocated = FALSE; + retval->is_nodisplay = FALSE; ++ retval->layout_pending_separator = FALSE; ++ retval->preprocessed = FALSE; ++ retval->will_inline_header = G_MAXUINT16; + + retval->default_layout_values.mask = MENU_LAYOUT_VALUES_NONE; + retval->default_layout_values.show_empty = FALSE; +@@ -1330,32 +1344,32 @@ gmenu_tree_directory_finalize (GMenuTree + g_assert (directory->item.refcount == 0); + + g_slist_foreach (directory->contents, +- (GFunc) gmenu_tree_item_unref_and_unset_parent, +- NULL); ++ (GFunc) gmenu_tree_item_unref_and_unset_parent, ++ NULL); + g_slist_free (directory->contents); + directory->contents = NULL; + + g_slist_foreach (directory->default_layout_info, +- (GFunc) menu_layout_node_unref, +- NULL); ++ (GFunc) menu_layout_node_unref, ++ NULL); + g_slist_free (directory->default_layout_info); + directory->default_layout_info = NULL; + + g_slist_foreach (directory->layout_info, +- (GFunc) menu_layout_node_unref, +- NULL); ++ (GFunc) menu_layout_node_unref, ++ NULL); + g_slist_free (directory->layout_info); + directory->layout_info = NULL; + + g_slist_foreach (directory->subdirs, +- (GFunc) gmenu_tree_item_unref_and_unset_parent, +- NULL); ++ (GFunc) gmenu_tree_item_unref_and_unset_parent, ++ NULL); + g_slist_free (directory->subdirs); + directory->subdirs = NULL; + + g_slist_foreach (directory->entries, +- (GFunc) gmenu_tree_item_unref_and_unset_parent, +- NULL); ++ (GFunc) gmenu_tree_item_unref_and_unset_parent, ++ NULL); + g_slist_free (directory->entries); + directory->entries = NULL; + +@@ -1367,26 +1381,6 @@ gmenu_tree_directory_finalize (GMenuTree + directory->name = NULL; + } + +-static int +-gmenu_tree_directory_compare (GMenuTreeDirectory *a, +- GMenuTreeDirectory *b) +-{ +- const char *name_a; +- const char *name_b; +- +- if (a->directory_entry) +- name_a = desktop_entry_get_name (a->directory_entry); +- else +- name_a = a->name; +- +- if (b->directory_entry) +- name_b = desktop_entry_get_name (b->directory_entry); +- else +- name_b = b->name; +- +- return g_utf8_collate (name_a, name_b); +-} +- + static GMenuTreeSeparator * + gmenu_tree_separator_new (GMenuTreeDirectory *parent) + { +@@ -1403,7 +1397,7 @@ gmenu_tree_separator_new (GMenuTreeDirec + + static GMenuTreeHeader * + gmenu_tree_header_new (GMenuTreeDirectory *parent, +- GMenuTreeDirectory *directory) ++ GMenuTreeDirectory *directory) + { + GMenuTreeHeader *retval; + +@@ -1432,8 +1426,8 @@ gmenu_tree_header_finalize (GMenuTreeHea + + static GMenuTreeAlias * + gmenu_tree_alias_new (GMenuTreeDirectory *parent, +- GMenuTreeDirectory *directory, +- GMenuTreeItem *item) ++ GMenuTreeDirectory *directory, ++ GMenuTreeItem *item) + { + GMenuTreeAlias *retval; + +@@ -1444,7 +1438,10 @@ gmenu_tree_alias_new (GMenuTreeDirectory + retval->item.refcount = 1; + + retval->directory = gmenu_tree_item_ref (directory); +- retval->aliased_item = gmenu_tree_item_ref (item); ++ if (item->type != GMENU_TREE_ITEM_ALIAS) ++ retval->aliased_item = gmenu_tree_item_ref (item); ++ else ++ retval->aliased_item = gmenu_tree_item_ref (gmenu_tree_alias_get_item (GMENU_TREE_ALIAS (item))); + + gmenu_tree_item_set_parent (GMENU_TREE_ITEM (retval->directory), NULL); + gmenu_tree_item_set_parent (retval->aliased_item, NULL); +@@ -1468,9 +1465,9 @@ gmenu_tree_alias_finalize (GMenuTreeAlia + + static GMenuTreeEntry * + gmenu_tree_entry_new (GMenuTreeDirectory *parent, +- DesktopEntry *desktop_entry, +- const char *desktop_file_id, +- gboolean is_excluded, ++ DesktopEntry *desktop_entry, ++ const char *desktop_file_id, ++ gboolean is_excluded, + gboolean is_nodisplay) + { + GMenuTreeEntry *retval; +@@ -1503,11 +1500,17 @@ gmenu_tree_entry_finalize (GMenuTreeEntr + } + + static int +-gmenu_tree_entry_compare (GMenuTreeEntry *a, +- GMenuTreeEntry *b) ++gmenu_tree_entry_compare_by_id (GMenuTreeItem *a, ++ GMenuTreeItem *b) + { +- return g_utf8_collate (desktop_entry_get_name (a->desktop_entry), +- desktop_entry_get_name (b->desktop_entry)); ++ if (a->type == GMENU_TREE_ITEM_ALIAS) ++ a = GMENU_TREE_ALIAS (a)->aliased_item; ++ ++ if (b->type == GMENU_TREE_ITEM_ALIAS) ++ b = GMENU_TREE_ALIAS (b)->aliased_item; ++ ++ return strcmp (GMENU_TREE_ENTRY (a)->desktop_file_id, ++ GMENU_TREE_ENTRY (b)->desktop_file_id); + } + + gpointer +@@ -1538,33 +1541,33 @@ gmenu_tree_item_unref (gpointer itemp) + if (--item->refcount == 0) + { + switch (item->type) +- { +- case GMENU_TREE_ITEM_DIRECTORY: +- gmenu_tree_directory_finalize (GMENU_TREE_DIRECTORY (item)); +- break; +- +- case GMENU_TREE_ITEM_ENTRY: +- gmenu_tree_entry_finalize (GMENU_TREE_ENTRY (item)); +- break; +- +- case GMENU_TREE_ITEM_SEPARATOR: +- break; +- +- case GMENU_TREE_ITEM_HEADER: +- gmenu_tree_header_finalize (GMENU_TREE_HEADER (item)); +- break; +- +- case GMENU_TREE_ITEM_ALIAS: +- gmenu_tree_alias_finalize (GMENU_TREE_ALIAS (item)); +- break; +- +- default: +- g_assert_not_reached (); +- break; +- } ++ { ++ case GMENU_TREE_ITEM_DIRECTORY: ++ gmenu_tree_directory_finalize (GMENU_TREE_DIRECTORY (item)); ++ break; ++ ++ case GMENU_TREE_ITEM_ENTRY: ++ gmenu_tree_entry_finalize (GMENU_TREE_ENTRY (item)); ++ break; ++ ++ case GMENU_TREE_ITEM_SEPARATOR: ++ break; ++ ++ case GMENU_TREE_ITEM_HEADER: ++ gmenu_tree_header_finalize (GMENU_TREE_HEADER (item)); ++ break; ++ ++ case GMENU_TREE_ITEM_ALIAS: ++ gmenu_tree_alias_finalize (GMENU_TREE_ALIAS (item)); ++ break; ++ ++ default: ++ g_assert_not_reached (); ++ break; ++ } + + if (item->dnotify) +- item->dnotify (item->user_data); ++ item->dnotify (item->user_data); + item->user_data = NULL; + item->dnotify = NULL; + +@@ -1589,8 +1592,8 @@ gmenu_tree_item_unref_and_unset_parent ( + + void + gmenu_tree_item_set_user_data (GMenuTreeItem *item, +- gpointer user_data, +- GDestroyNotify dnotify) ++ gpointer user_data, ++ GDestroyNotify dnotify) + { + g_return_if_fail (item != NULL); + +@@ -1609,55 +1612,70 @@ gmenu_tree_item_get_user_data (GMenuTree + return item->user_data; + } + +-static int +-gmenu_tree_item_compare (GMenuTreeItem *a, +- GMenuTreeItem *b) ++static inline const char * ++gmenu_tree_item_compare_get_name_helper (GMenuTreeItem *item, ++ GMenuTreeSortKey sort_key) + { +- const char *name_a; +- const char *name_b; ++ const char *name; ++ ++ name = NULL; + +- switch (a->type) ++ switch (item->type) + { + case GMENU_TREE_ITEM_DIRECTORY: +- if (GMENU_TREE_DIRECTORY (a)->directory_entry) +- name_a = desktop_entry_get_name (GMENU_TREE_DIRECTORY (a)->directory_entry); ++ if (GMENU_TREE_DIRECTORY (item)->directory_entry) ++ name = desktop_entry_get_name (GMENU_TREE_DIRECTORY (item)->directory_entry); + else +- name_a = GMENU_TREE_DIRECTORY (a)->name; ++ name = GMENU_TREE_DIRECTORY (item)->name; + break; + + case GMENU_TREE_ITEM_ENTRY: +- name_a = desktop_entry_get_name (GMENU_TREE_ENTRY (a)->desktop_entry); ++ switch (sort_key) ++ { ++ case GMENU_TREE_SORT_NAME: ++ name = desktop_entry_get_name (GMENU_TREE_ENTRY (item)->desktop_entry); ++ break; ++ case GMENU_TREE_SORT_DISPLAY_NAME: ++ name = gmenu_tree_entry_get_display_name (GMENU_TREE_ENTRY (item)); ++ break; ++ default: ++ g_assert_not_reached (); ++ break; ++ } + break; + +- case GMENU_TREE_ITEM_SEPARATOR: +- case GMENU_TREE_ITEM_HEADER: + case GMENU_TREE_ITEM_ALIAS: +- default: +- g_assert_not_reached (); +- break; +- } +- +- switch (b->type) +- { +- case GMENU_TREE_ITEM_DIRECTORY: +- if (GMENU_TREE_DIRECTORY (b)->directory_entry) +- name_b = desktop_entry_get_name (GMENU_TREE_DIRECTORY (b)->directory_entry); +- else +- name_b = GMENU_TREE_DIRECTORY (b)->name; +- break; +- +- case GMENU_TREE_ITEM_ENTRY: +- name_b = desktop_entry_get_name (GMENU_TREE_ENTRY (b)->desktop_entry); ++ { ++ GMenuTreeItem *dir; ++ dir = GMENU_TREE_ITEM (GMENU_TREE_ALIAS (item)->directory); ++ name = gmenu_tree_item_compare_get_name_helper (dir, sort_key); ++ } + break; + + case GMENU_TREE_ITEM_SEPARATOR: + case GMENU_TREE_ITEM_HEADER: +- case GMENU_TREE_ITEM_ALIAS: + default: + g_assert_not_reached (); + break; + } + ++ return name; ++} ++ ++static int ++gmenu_tree_item_compare (GMenuTreeItem *a, ++ GMenuTreeItem *b, ++ gpointer sort_key_p) ++{ ++ const char *name_a; ++ const char *name_b; ++ GMenuTreeSortKey sort_key; ++ ++ sort_key = GPOINTER_TO_INT (sort_key_p); ++ ++ name_a = gmenu_tree_item_compare_get_name_helper (a, sort_key); ++ name_b = gmenu_tree_item_compare_get_name_helper (b, sort_key); ++ + return g_utf8_collate (name_a, name_b); + } + +@@ -1675,7 +1693,7 @@ find_menu_child (MenuLayoutNode *layout) + + static void + merge_resolved_children (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *where, + MenuLayoutNode *from) + { +@@ -1728,16 +1746,16 @@ merge_resolved_children (GMenuTree + + static gboolean + load_merge_file (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + const char *filename, + gboolean is_canonical, +- gboolean add_monitor, ++ gboolean add_monitor, + MenuLayoutNode *where) + { + MenuLayoutNode *to_merge; + const char *canonical; +- char *freeme; + char *dirname; ++ char *freeme; + gboolean retval; + + freeme = NULL; +@@ -1748,14 +1766,14 @@ load_merge_file (GMenuTree *tree, + canonical = freeme = menu_canonicalize_file_name (filename, FALSE); + if (canonical == NULL) + { +- if (add_monitor) +- gmenu_tree_add_menu_file_monitor (tree, +- filename, +- MENU_FILE_MONITOR_NONEXISTENT_FILE); ++ if (add_monitor) ++ gmenu_tree_add_menu_file_monitor (tree, ++ filename, ++ MENU_FILE_MONITOR_NONEXISTENT_FILE); + + menu_verbose ("Failed to canonicalize merge file path \"%s\": %s\n", + filename, g_strerror (errno)); +- goto out; ++ goto out; + } + } + else +@@ -1772,7 +1790,7 @@ load_merge_file (GMenuTree *tree, + if (g_hash_table_lookup (loaded_menu_files, canonical) != NULL) + { + g_warning ("Not loading \"%s\": recursive loop detected in .menu files", +- canonical); ++ canonical); + retval = TRUE; + goto out; + } +@@ -1793,8 +1811,8 @@ load_merge_file (GMenuTree *tree, + + if (add_monitor) + gmenu_tree_add_menu_file_monitor (tree, +- canonical, +- MENU_FILE_MONITOR_FILE); ++ canonical, ++ MENU_FILE_MONITOR_FILE); + + merge_resolved_children (tree, loaded_menu_files, where, to_merge); + +@@ -1811,10 +1829,10 @@ load_merge_file (GMenuTree *tree, + + static gboolean + load_merge_file_with_config_dir (GMenuTree *tree, +- GHashTable *loaded_menu_files, +- const char *menu_file, +- const char *config_dir, +- MenuLayoutNode *where) ++ GHashTable *loaded_menu_files, ++ const char *menu_file, ++ const char *config_dir, ++ MenuLayoutNode *where) + { + char *merge_file; + gboolean loaded; +@@ -1833,14 +1851,14 @@ load_merge_file_with_config_dir (GMenuTr + + static gboolean + compare_basedir_to_config_dir (const char *canonical_basedir, +- const char *config_dir) ++ const char *config_dir) + { + char *dirname; + char *canonical_menus_dir; + gboolean retval; + + menu_verbose ("Checking to see if basedir '%s' is in '%s'\n", +- canonical_basedir, config_dir); ++ canonical_basedir, config_dir); + + dirname = g_build_filename (config_dir, "menus", NULL); + +@@ -1862,7 +1880,7 @@ compare_basedir_to_config_dir (const cha + static gboolean + load_parent_merge_file_from_basename (GMenuTree *tree, + GHashTable *loaded_menu_files, +- MenuLayoutNode *layout, ++ MenuLayoutNode *layout, + const char *menu_file, + const char *canonical_basedir) + { +@@ -1873,7 +1891,7 @@ load_parent_merge_file_from_basename (GM + /* We're not interested in menu files that are in directories which are not a + * parent of the base directory of this menu file */ + found_basedir = compare_basedir_to_config_dir (canonical_basedir, +- g_get_user_config_dir ()); ++ g_get_user_config_dir ()); + + system_config_dirs = g_get_system_config_dirs (); + +@@ -1881,24 +1899,24 @@ load_parent_merge_file_from_basename (GM + while (system_config_dirs[i] != NULL) + { + if (!found_basedir) +- { +- found_basedir = compare_basedir_to_config_dir (canonical_basedir, +- system_config_dirs[i]); +- } ++ { ++ found_basedir = compare_basedir_to_config_dir (canonical_basedir, ++ system_config_dirs[i]); ++ } + else +- { +- menu_verbose ("Looking for parent menu file '%s' in '%s'\n", +- menu_file, system_config_dirs[i]); +- +- if (load_merge_file_with_config_dir (tree, +- loaded_menu_files, +- menu_file, +- system_config_dirs[i], +- layout)) +- { +- break; +- } +- } ++ { ++ menu_verbose ("Looking for parent menu file '%s' in '%s'\n", ++ menu_file, system_config_dirs[i]); ++ ++ if (load_merge_file_with_config_dir (tree, ++ loaded_menu_files, ++ menu_file, ++ system_config_dirs[i], ++ layout)) ++ { ++ break; ++ } ++ } + + ++i; + } +@@ -1908,8 +1926,8 @@ load_parent_merge_file_from_basename (GM + + static gboolean + load_parent_merge_file (GMenuTree *tree, +- GHashTable *loaded_menu_files, +- MenuLayoutNode *layout) ++ GHashTable *loaded_menu_files, ++ MenuLayoutNode *layout) + { + MenuLayoutNode *root; + const char *basedir; +@@ -1927,7 +1945,7 @@ load_parent_merge_file (GMenuTree * + if (canonical_basedir == NULL) + { + menu_verbose ("Menu basedir '%s' no longer exists, not merging parent\n", +- basedir); ++ basedir); + return FALSE; + } + +@@ -1962,7 +1980,7 @@ load_parent_merge_file (GMenuTree * + + static void + load_merge_dir (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + const char *dirname, + MenuLayoutNode *where) + { +@@ -1975,8 +1993,8 @@ load_merge_dir (GMenuTree *tree, + all_used_dirs = g_slist_append( all_used_dirs, g_strdup(dirname) ); + + gmenu_tree_add_menu_file_monitor (tree, +- dirname, +- MENU_FILE_MONITOR_DIRECTORY); ++ dirname, ++ MENU_FILE_MONITOR_DIRECTORY); + + if ((dir = g_dir_open (dirname, 0, NULL)) == NULL) + return; +@@ -2000,7 +2018,7 @@ load_merge_dir (GMenuTree *tree, + + static void + load_merge_dir_with_config_dir (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + const char *config_dir, + const char *dirname, + MenuLayoutNode *where) +@@ -2016,7 +2034,7 @@ load_merge_dir_with_config_dir (GMenuTre + + static void + resolve_merge_file (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *layout) + { + char *filename; +@@ -2045,7 +2063,7 @@ resolve_merge_file (GMenuTree *tree + + static void + resolve_merge_dir (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *layout) + { + char *path; +@@ -2099,8 +2117,8 @@ resolve_default_app_dirs (GMenuTree + system_data_dirs = g_get_system_data_dirs (); + + before = add_app_dir (tree, +- menu_layout_node_ref (layout), +- g_get_user_data_dir ()); ++ menu_layout_node_ref (layout), ++ g_get_user_data_dir ()); + + i = 0; + while (system_data_dirs[i] != NULL) +@@ -2149,8 +2167,8 @@ resolve_default_directory_dirs (GMenuTre + system_data_dirs = g_get_system_data_dirs (); + + before = add_directory_dir (tree, +- menu_layout_node_ref (layout), +- g_get_user_data_dir ()); ++ menu_layout_node_ref (layout), ++ g_get_user_data_dir ()); + + i = 0; + while (system_data_dirs[i] != NULL) +@@ -2168,7 +2186,7 @@ resolve_default_directory_dirs (GMenuTre + + static void + resolve_default_merge_dirs (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *layout) + { + MenuLayoutNode *root; +@@ -2191,14 +2209,14 @@ resolve_default_merge_dirs (GMenuTree + { + i--; + load_merge_dir_with_config_dir (tree, +- loaded_menu_files, ++ loaded_menu_files, + system_config_dirs[i], + merge_name, + layout); + } + + load_merge_dir_with_config_dir (tree, +- loaded_menu_files, ++ loaded_menu_files, + g_get_user_config_dir (), + merge_name, + layout); +@@ -2228,8 +2246,8 @@ add_filename_include (const char *de + + static void + is_dot_directory (const char *basename, +- DesktopEntry *entry, +- gboolean *has_dot_directory) ++ DesktopEntry *entry, ++ gboolean *has_dot_directory) + { + if (!strcmp (basename, ".directory")) + *has_dot_directory = TRUE; +@@ -2238,7 +2256,7 @@ is_dot_directory (const char *basename + static gboolean + add_menu_for_legacy_dir (MenuLayoutNode *parent, + const char *legacy_dir, +- const char *relative_path, ++ const char *relative_path, + const char *legacy_prefix, + const char *menu_name) + { +@@ -2265,8 +2283,8 @@ add_menu_for_legacy_dir (MenuLayoutNode + + has_dot_directory = FALSE; + desktop_entry_set_foreach (directory_entries, +- (DesktopEntrySetForeachFunc) is_dot_directory, +- &has_dot_directory); ++ (DesktopEntrySetForeachFunc) is_dot_directory, ++ &has_dot_directory); + desktop_entry_set_unref (directory_entries); + + menu_added = FALSE; +@@ -2293,37 +2311,37 @@ add_menu_for_legacy_dir (MenuLayoutNode + menu_layout_node_unref (node); + + if (has_dot_directory) +- { +- node = menu_layout_node_new (MENU_LAYOUT_NODE_DIRECTORY); +- if (relative_path != NULL) +- { +- char *directory_entry_path; +- +- directory_entry_path = g_strdup_printf ("%s/.directory", relative_path); +- menu_layout_node_set_content (node, directory_entry_path); +- g_free (directory_entry_path); +- } +- else +- { +- menu_layout_node_set_content (node, ".directory"); +- } +- menu_layout_node_append_child (menu, node); +- menu_layout_node_unref (node); +- } ++ { ++ node = menu_layout_node_new (MENU_LAYOUT_NODE_DIRECTORY); ++ if (relative_path != NULL) ++ { ++ char *directory_entry_path; ++ ++ directory_entry_path = g_strdup_printf ("%s/.directory", relative_path); ++ menu_layout_node_set_content (node, directory_entry_path); ++ g_free (directory_entry_path); ++ } ++ else ++ { ++ menu_layout_node_set_content (node, ".directory"); ++ } ++ menu_layout_node_append_child (menu, node); ++ menu_layout_node_unref (node); ++ } + + if (desktop_entry_set_get_count (desktop_entries) > 0) +- { +- MenuLayoutNode *include; ++ { ++ MenuLayoutNode *include; + +- include = menu_layout_node_new (MENU_LAYOUT_NODE_INCLUDE); +- menu_layout_node_append_child (menu, include); ++ include = menu_layout_node_new (MENU_LAYOUT_NODE_INCLUDE); ++ menu_layout_node_append_child (menu, include); + +- desktop_entry_set_foreach (desktop_entries, +- (DesktopEntrySetForeachFunc) add_filename_include, +- include); ++ desktop_entry_set_foreach (desktop_entries, ++ (DesktopEntrySetForeachFunc) add_filename_include, ++ include); + +- menu_layout_node_unref (include); +- } ++ menu_layout_node_unref (include); ++ } + + subdir_path = g_string_new (legacy_dir); + legacy_dir_len = strlen (legacy_dir); +@@ -2339,15 +2357,15 @@ add_menu_for_legacy_dir (MenuLayoutNode + g_string_append_c (subdir_path, G_DIR_SEPARATOR); + g_string_append (subdir_path, subdir); + +- if (relative_path_len) +- { +- g_string_append_c (subdir_relative, G_DIR_SEPARATOR); +- } ++ if (relative_path_len) ++ { ++ g_string_append_c (subdir_relative, G_DIR_SEPARATOR); ++ } + g_string_append (subdir_relative, subdir); + + add_menu_for_legacy_dir (menu, + subdir_path->str, +- subdir_relative->str, ++ subdir_relative->str, + legacy_prefix, + subdir); + +@@ -2373,7 +2391,7 @@ add_menu_for_legacy_dir (MenuLayoutNode + + static void + resolve_legacy_dir (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *legacy) + { + MenuLayoutNode *to_merge; +@@ -2386,7 +2404,7 @@ resolve_legacy_dir (GMenuTree *tree + + if (add_menu_for_legacy_dir (to_merge, + menu_layout_node_get_content (legacy), +- NULL, ++ NULL, + menu_layout_node_legacy_dir_get_prefix (legacy), + menu_layout_node_menu_get_name (menu))) + { +@@ -2398,7 +2416,7 @@ resolve_legacy_dir (GMenuTree *tree + + static MenuLayoutNode * + add_legacy_dir (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *before, + const char *data_dir) + { +@@ -2425,7 +2443,7 @@ add_legacy_dir (GMenuTree *tree, + + static void + resolve_kde_legacy_dirs (GMenuTree *tree, +- GHashTable *loaded_menu_files, ++ GHashTable *loaded_menu_files, + MenuLayoutNode *layout) + { + MenuLayoutNode *before; +@@ -2435,9 +2453,9 @@ resolve_kde_legacy_dirs (GMenuTree + system_data_dirs = g_get_system_data_dirs (); + + before = add_legacy_dir (tree, +- loaded_menu_files, +- menu_layout_node_ref (layout), +- g_get_user_data_dir ()); ++ loaded_menu_files, ++ menu_layout_node_ref (layout), ++ g_get_user_data_dir ()); + + i = 0; + while (system_data_dirs[i] != NULL) +@@ -2455,8 +2473,8 @@ resolve_kde_legacy_dirs (GMenuTree + + static void + gmenu_tree_resolve_files (GMenuTree *tree, +- GHashTable *loaded_menu_files, +- MenuLayoutNode *layout) ++ GHashTable *loaded_menu_files, ++ MenuLayoutNode *layout) + { + MenuLayoutNode *child; + +@@ -2607,7 +2625,7 @@ node_menu_compare_func (const void *a, + + static void + gmenu_tree_strip_duplicate_children (GMenuTree *tree, +- MenuLayoutNode *layout) ++ MenuLayoutNode *layout) + { + MenuLayoutNode *child; + GSList *simple_nodes; +@@ -2673,8 +2691,8 @@ gmenu_tree_strip_duplicate_children (GMe + { + /* nuke it! */ + menu_layout_node_unlink (n); +- simple_nodes = g_slist_delete_link (simple_nodes, tmp); +- tmp = prev; ++ simple_nodes = g_slist_delete_link (simple_nodes, tmp); ++ tmp = prev; + } + } + +@@ -2690,7 +2708,7 @@ gmenu_tree_strip_duplicate_children (GMe + * the list is backward. + */ + menu_layout_nodes = g_slist_sort (menu_layout_nodes, +- node_menu_compare_func); ++ node_menu_compare_func); + + prev = NULL; + tmp = menu_layout_nodes; +@@ -2710,8 +2728,8 @@ gmenu_tree_strip_duplicate_children (GMe + */ + move_children (n, p); + menu_layout_node_unlink (n); +- menu_layout_nodes = g_slist_delete_link (menu_layout_nodes, tmp); +- tmp = prev; ++ menu_layout_nodes = g_slist_delete_link (menu_layout_nodes, tmp); ++ tmp = prev; + } + } + +@@ -2831,8 +2849,8 @@ find_submenu (MenuLayoutNode *layout, + */ + static void + gmenu_tree_execute_moves (GMenuTree *tree, +- MenuLayoutNode *layout, +- gboolean *need_remove_dups_p) ++ MenuLayoutNode *layout, ++ gboolean *need_remove_dups_p) + { + MenuLayoutNode *child; + gboolean need_remove_dups; +@@ -2954,7 +2972,6 @@ gmenu_tree_load_layout (GMenuTree *tree) + loaded_menu_files = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (loaded_menu_files, tree->canonical_path, GUINT_TO_POINTER (TRUE)); + gmenu_tree_resolve_files (tree, loaded_menu_files, tree->layout); +- + g_hash_table_destroy (loaded_menu_files); + + gmenu_tree_strip_duplicate_children (tree, tree->layout); +@@ -2979,8 +2996,8 @@ typedef struct + + static void + get_by_category_foreach (const char *file_id, +- DesktopEntry *entry, +- GetByCategoryForeachData *data) ++ DesktopEntry *entry, ++ GetByCategoryForeachData *data) + { + if (desktop_entry_has_category (entry, data->category)) + desktop_entry_set_add_entry (data->set, entry, file_id); +@@ -2988,8 +3005,8 @@ get_by_category_foreach (const char + + static void + get_by_category (DesktopEntrySet *entry_pool, +- DesktopEntrySet *set, +- const char *category) ++ DesktopEntrySet *set, ++ const char *category) + { + GetByCategoryForeachData data; + +@@ -2997,13 +3014,13 @@ get_by_category (DesktopEntrySet *entry_ + data.category = category; + + desktop_entry_set_foreach (entry_pool, +- (DesktopEntrySetForeachFunc) get_by_category_foreach, +- &data); ++ (DesktopEntrySetForeachFunc) get_by_category_foreach, ++ &data); + } + + static DesktopEntrySet * + process_include_rules (MenuLayoutNode *layout, +- DesktopEntrySet *entry_pool) ++ DesktopEntrySet *entry_pool) + { + DesktopEntrySet *set = NULL; + +@@ -3013,7 +3030,7 @@ process_include_rules (MenuLayoutNode * + { + MenuLayoutNode *child; + +- menu_verbose ("Processing \n"); ++ menu_verbose ("Processing \n"); + + child = menu_layout_node_get_children (layout); + while (child != NULL) +@@ -3040,7 +3057,7 @@ process_include_rules (MenuLayoutNode * + + child = menu_layout_node_get_next (child); + } +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + } + break; + +@@ -3048,7 +3065,7 @@ process_include_rules (MenuLayoutNode * + { + MenuLayoutNode *child; + +- menu_verbose ("Processing \n"); ++ menu_verbose ("Processing \n"); + + child = menu_layout_node_get_children (layout); + while (child != NULL) +@@ -3069,7 +3086,7 @@ process_include_rules (MenuLayoutNode * + + child = menu_layout_node_get_next (child); + } +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + } + break; + +@@ -3078,7 +3095,7 @@ process_include_rules (MenuLayoutNode * + /* First get the OR of all the rules */ + MenuLayoutNode *child; + +- menu_verbose ("Processing \n"); ++ menu_verbose ("Processing \n"); + + child = menu_layout_node_get_children (layout); + while (child != NULL) +@@ -3102,16 +3119,16 @@ process_include_rules (MenuLayoutNode * + + if (set != NULL) + { +- DesktopEntrySet *inverted; ++ DesktopEntrySet *inverted; + +- /* Now invert the result */ +- inverted = desktop_entry_set_new (); +- desktop_entry_set_union (inverted, entry_pool); +- desktop_entry_set_subtract (inverted, set); +- desktop_entry_set_unref (set); +- set = inverted; ++ /* Now invert the result */ ++ inverted = desktop_entry_set_new (); ++ desktop_entry_set_union (inverted, entry_pool); ++ desktop_entry_set_subtract (inverted, set); ++ desktop_entry_set_unref (set); ++ set = inverted; + } +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + } + break; + +@@ -3126,11 +3143,11 @@ process_include_rules (MenuLayoutNode * + { + DesktopEntry *entry; + +- menu_verbose ("Processing %s\n", +- menu_layout_node_get_content (layout)); ++ menu_verbose ("Processing %s\n", ++ menu_layout_node_get_content (layout)); + + entry = desktop_entry_set_lookup (entry_pool, +- menu_layout_node_get_content (layout)); ++ menu_layout_node_get_content (layout)); + if (entry != NULL) + { + set = desktop_entry_set_new (); +@@ -3138,18 +3155,18 @@ process_include_rules (MenuLayoutNode * + entry, + menu_layout_node_get_content (layout)); + } +- menu_verbose ("Processed %s\n", +- menu_layout_node_get_content (layout)); ++ menu_verbose ("Processed %s\n", ++ menu_layout_node_get_content (layout)); + } + break; + + case MENU_LAYOUT_NODE_CATEGORY: + menu_verbose ("Processing %s\n", +- menu_layout_node_get_content (layout)); ++ menu_layout_node_get_content (layout)); + set = desktop_entry_set_new (); + get_by_category (entry_pool, set, menu_layout_node_get_content (layout)); + menu_verbose ("Processed %s\n", +- menu_layout_node_get_content (layout)); ++ menu_layout_node_get_content (layout)); + break; + + default: +@@ -3166,13 +3183,13 @@ process_include_rules (MenuLayoutNode * + + static void + collect_layout_info (MenuLayoutNode *layout, +- GSList **layout_info) ++ GSList **layout_info) + { + MenuLayoutNode *iter; + + g_slist_foreach (*layout_info, +- (GFunc) menu_layout_node_unref, +- NULL); ++ (GFunc) menu_layout_node_unref, ++ NULL); + g_slist_free (*layout_info); + *layout_info = NULL; + +@@ -3180,18 +3197,18 @@ collect_layout_info (MenuLayoutNode *la + while (iter != NULL) + { + switch (menu_layout_node_get_type (iter)) +- { +- case MENU_LAYOUT_NODE_MENUNAME: +- case MENU_LAYOUT_NODE_FILENAME: +- case MENU_LAYOUT_NODE_SEPARATOR: +- case MENU_LAYOUT_NODE_MERGE: +- *layout_info = g_slist_prepend (*layout_info, +- menu_layout_node_ref (iter)); +- break; +- +- default: +- break; +- } ++ { ++ case MENU_LAYOUT_NODE_MENUNAME: ++ case MENU_LAYOUT_NODE_FILENAME: ++ case MENU_LAYOUT_NODE_SEPARATOR: ++ case MENU_LAYOUT_NODE_MERGE: ++ *layout_info = g_slist_prepend (*layout_info, ++ menu_layout_node_ref (iter)); ++ break; ++ ++ default: ++ break; ++ } + + iter = menu_layout_node_get_next (iter); + } +@@ -3206,7 +3223,7 @@ entries_listify_foreach (const char + { + directory->entries = + g_slist_prepend (directory->entries, +- gmenu_tree_entry_new (directory, ++ gmenu_tree_entry_new (directory, + desktop_entry, + desktop_file_id, + FALSE, +@@ -3215,15 +3232,15 @@ entries_listify_foreach (const char + + static void + excluded_entries_listify_foreach (const char *desktop_file_id, +- DesktopEntry *desktop_entry, +- GMenuTreeDirectory *directory) ++ DesktopEntry *desktop_entry, ++ GMenuTreeDirectory *directory) + { + directory->entries = + g_slist_prepend (directory->entries, +- gmenu_tree_entry_new (directory, +- desktop_entry, +- desktop_file_id, +- TRUE, ++ gmenu_tree_entry_new (directory, ++ desktop_entry, ++ desktop_file_id, ++ TRUE, + desktop_entry_get_no_display (desktop_entry))); + } + +@@ -3234,10 +3251,12 @@ set_default_layout_values (GMenuTreeDire + GSList *tmp; + + /* if the child has a defined default layout, we don't want to override its +- * values, and if the parent doesn't have a defined default layout, then +- * everybody already uses the default values */ +- if (parent->default_layout_info == NULL || +- child->default_layout_info != NULL) ++ * values. The parent might have a non-defined layout info (ie, no child of ++ * the DefaultLayout node) but it doesn't meant the default layout values ++ * (ie, DefaultLayout attributes) aren't different from the global defaults. ++ */ ++ if (child->default_layout_info != NULL || ++ child->default_layout_values.mask != MENU_LAYOUT_VALUES_NONE) + return; + + child->default_layout_values = parent->default_layout_values; +@@ -3273,8 +3292,8 @@ process_layout (GMenuTree *tree + g_assert (menu_layout_node_menu_get_name (layout) != NULL); + + directory = gmenu_tree_directory_new (parent, +- menu_layout_node_menu_get_name (layout), +- parent == NULL); ++ menu_layout_node_menu_get_name (layout), ++ parent == NULL); + + menu_verbose ("=== Menu name = %s ===\n", directory->name); + +@@ -3290,9 +3309,7 @@ process_layout (GMenuTree *tree + else + excluded_set = NULL; + +- entry_pool = desktop_entry_set_new (); +- entry_directory_list_get_all_desktops (menu_layout_node_menu_get_app_dirs (layout), +- entry_pool); ++ entry_pool = _entry_directory_list_get_all_desktops (menu_layout_node_menu_get_app_dirs (layout)); + + layout_iter = menu_layout_node_get_children (layout); + while (layout_iter != NULL) +@@ -3304,7 +3321,7 @@ process_layout (GMenuTree *tree + { + GMenuTreeDirectory *child_dir; + +- menu_verbose ("Processing \n"); ++ menu_verbose ("Processing \n"); + + child_dir = process_layout (tree, + directory, +@@ -3314,7 +3331,7 @@ process_layout (GMenuTree *tree + directory->subdirs = g_slist_prepend (directory->subdirs, + child_dir); + +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + } + break; + +@@ -3326,8 +3343,8 @@ process_layout (GMenuTree *tree + */ + MenuLayoutNode *rule; + +- menu_verbose ("Processing (%d entries)\n", +- desktop_entry_set_get_count (entries)); ++ menu_verbose ("Processing (%d entries)\n", ++ desktop_entry_set_get_count (entries)); + + rule = menu_layout_node_get_children (layout_iter); + while (rule != NULL) +@@ -3339,16 +3356,16 @@ process_layout (GMenuTree *tree + { + desktop_entry_set_union (entries, rule_set); + desktop_entry_set_union (allocated_set, rule_set); +- if (excluded_set != NULL) +- desktop_entry_set_subtract (excluded_set, rule_set); ++ if (excluded_set != NULL) ++ desktop_entry_set_subtract (excluded_set, rule_set); + desktop_entry_set_unref (rule_set); + } + + rule = menu_layout_node_get_next (rule); + } + +- menu_verbose ("Processed (%d entries)\n", +- desktop_entry_set_get_count (entries)); ++ menu_verbose ("Processed (%d entries)\n", ++ desktop_entry_set_get_count (entries)); + } + break; + +@@ -3360,8 +3377,8 @@ process_layout (GMenuTree *tree + */ + MenuLayoutNode *rule; + +- menu_verbose ("Processing (%d entries)\n", +- desktop_entry_set_get_count (entries)); ++ menu_verbose ("Processing (%d entries)\n", ++ desktop_entry_set_get_count (entries)); + + rule = menu_layout_node_get_children (layout_iter); + while (rule != NULL) +@@ -3371,17 +3388,17 @@ process_layout (GMenuTree *tree + rule_set = process_include_rules (rule, entry_pool); + if (rule_set != NULL) + { +- if (excluded_set != NULL) +- desktop_entry_set_union (excluded_set, rule_set); +- desktop_entry_set_subtract (entries, rule_set); +- desktop_entry_set_unref (rule_set); ++ if (excluded_set != NULL) ++ desktop_entry_set_union (excluded_set, rule_set); ++ desktop_entry_set_subtract (entries, rule_set); ++ desktop_entry_set_unref (rule_set); + } + + rule = menu_layout_node_get_next (rule); + } + +- menu_verbose ("Processed (%d entries)\n", +- desktop_entry_set_get_count (entries)); ++ menu_verbose ("Processed (%d entries)\n", ++ desktop_entry_set_get_count (entries)); + } + break; + +@@ -3389,10 +3406,10 @@ process_layout (GMenuTree *tree + { + DesktopEntry *entry; + +- menu_verbose ("Processing %s\n", +- menu_layout_node_get_content (layout_iter)); ++ menu_verbose ("Processing %s\n", ++ menu_layout_node_get_content (layout_iter)); + +- /* ++ /* + * The last to exist wins, so we always try overwriting + */ + entry = entry_directory_list_get_directory (menu_layout_node_menu_get_directory_dirs (layout), +@@ -3414,41 +3431,41 @@ process_layout (GMenuTree *tree + + menu_verbose ("Processed new directory entry = %p (%s)\n", + directory->directory_entry, +- directory->directory_entry? desktop_entry_get_path (directory->directory_entry) : "null"); ++ directory->directory_entry? desktop_entry_get_path (directory->directory_entry) : "null"); + } + break; + + case MENU_LAYOUT_NODE_DELETED: +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + deleted = TRUE; + break; + + case MENU_LAYOUT_NODE_NOT_DELETED: +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + deleted = FALSE; + break; + + case MENU_LAYOUT_NODE_ONLY_UNALLOCATED: +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + only_unallocated = TRUE; + break; + + case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED: +- menu_verbose ("Processed \n"); ++ menu_verbose ("Processed \n"); + only_unallocated = FALSE; + break; + +- case MENU_LAYOUT_NODE_DEFAULT_LAYOUT: +- menu_layout_node_default_layout_get_values (layout_iter, +- &directory->default_layout_values); +- collect_layout_info (layout_iter, &directory->default_layout_info); +- menu_verbose ("Processed \n"); +- break; +- +- case MENU_LAYOUT_NODE_LAYOUT: +- collect_layout_info (layout_iter, &directory->layout_info); +- menu_verbose ("Processed \n"); +- break; ++ case MENU_LAYOUT_NODE_DEFAULT_LAYOUT: ++ menu_layout_node_default_layout_get_values (layout_iter, ++ &directory->default_layout_values); ++ collect_layout_info (layout_iter, &directory->default_layout_info); ++ menu_verbose ("Processed \n"); ++ break; ++ ++ case MENU_LAYOUT_NODE_LAYOUT: ++ collect_layout_info (layout_iter, &directory->layout_info); ++ menu_verbose ("Processed \n"); ++ break; + + default: + break; +@@ -3491,7 +3508,7 @@ process_layout (GMenuTree *tree + if (deleted) + { + if (excluded_set != NULL) +- desktop_entry_set_unref (excluded_set); ++ desktop_entry_set_unref (excluded_set); + desktop_entry_set_unref (entries); + gmenu_tree_item_unref (directory); + return NULL; +@@ -3505,8 +3522,8 @@ process_layout (GMenuTree *tree + if (excluded_set != NULL) + { + desktop_entry_set_foreach (excluded_set, +- (DesktopEntrySetForeachFunc) excluded_entries_listify_foreach, +- directory); ++ (DesktopEntrySetForeachFunc) excluded_entries_listify_foreach, ++ directory); + desktop_entry_set_unref (excluded_set); + } + +@@ -3573,8 +3590,8 @@ process_layout (GMenuTree *tree + + static void + process_only_unallocated (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- DesktopEntrySet *allocated) ++ GMenuTreeDirectory *directory, ++ DesktopEntrySet *allocated) + { + GSList *tmp; + +@@ -3612,122 +3629,462 @@ process_only_unallocated (GMenuTree + } + } + +-static void process_layout_info (GMenuTree *tree, +- GMenuTreeDirectory *directory); ++static void preprocess_layout_info (GMenuTree *tree, ++ GMenuTreeDirectory *directory); + +-static void +-check_pending_separator (GMenuTreeDirectory *directory) ++static GSList * ++get_layout_info (GMenuTreeDirectory *directory, ++ gboolean *is_default_layout) + { +- if (directory->layout_pending_separator) ++ GMenuTreeDirectory *iter; ++ ++ if (directory->layout_info != NULL) + { +- menu_verbose ("Adding pending separator in '%s'\n", directory->name); ++ if (is_default_layout) ++ { ++ *is_default_layout = FALSE; ++ } ++ return directory->layout_info; ++ } + +- directory->contents = g_slist_append (directory->contents, +- gmenu_tree_separator_new (directory)); +- directory->layout_pending_separator = FALSE; ++ /* Even if there's no layout information at all, the result will be an ++ * implicit default layout */ ++ if (is_default_layout) ++ { ++ *is_default_layout = TRUE; + } ++ ++ iter = directory; ++ while (iter != NULL) ++ { ++ /* FIXME: this is broken: we might skip real parent in the ++ * XML structure, that are hidden because of inlining. */ ++ if (iter->default_layout_info != NULL) ++ { ++ return iter->default_layout_info; ++ } ++ ++ iter = GMENU_TREE_ITEM (iter)->parent; ++ } ++ ++ return NULL; + } + + static void +-merge_subdir (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- GMenuTreeDirectory *subdir, +- MenuLayoutValues *layout_values) ++get_values_with_defaults (MenuLayoutNode *node, ++ MenuLayoutValues *layout_values, ++ MenuLayoutValues *default_layout_values) + { +- gboolean removed; ++ menu_layout_node_menuname_get_values (node, layout_values); + +- menu_verbose ("Merging subdir '%s' in directory '%s'\n", +- subdir->name, directory->name); ++ if (!(layout_values->mask & MENU_LAYOUT_VALUES_SHOW_EMPTY)) ++ layout_values->show_empty = default_layout_values->show_empty; + +- process_layout_info (tree, subdir); ++ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_MENUS)) ++ layout_values->inline_menus = default_layout_values->inline_menus; + +- removed = FALSE; ++ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_LIMIT)) ++ layout_values->inline_limit = default_layout_values->inline_limit; + +- if (subdir->contents == NULL) +- { +- if (!(tree->flags & GMENU_TREE_FLAGS_SHOW_EMPTY) && !layout_values->show_empty) ++ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_HEADER)) ++ layout_values->inline_header = default_layout_values->inline_header; ++ ++ if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_ALIAS)) ++ layout_values->inline_alias = default_layout_values->inline_alias; ++} ++ ++static guint ++get_real_subdirs_len (GMenuTreeDirectory *directory) ++{ ++ guint len; ++ GSList *tmp; ++ ++ len = 0; ++ ++ tmp = directory->subdirs; ++ while (tmp != NULL) + { +- menu_verbose ("Not showing empty menu '%s'\n", subdir->name); +- removed = TRUE; ++ GMenuTreeDirectory *subdir = tmp->data; ++ ++ tmp = tmp->next; ++ ++ if (subdir->will_inline_header != G_MAXUINT16) ++ { ++ len += get_real_subdirs_len (subdir) + g_slist_length (subdir->entries) + 1; ++ } ++ else ++ len += 1; + } ++ ++ return len; ++} ++ ++static void ++preprocess_layout_info_subdir_helper (GMenuTree *tree, ++ GMenuTreeDirectory *directory, ++ GMenuTreeDirectory *subdir, ++ MenuLayoutValues *layout_values, ++ gboolean *contents_added, ++ gboolean *should_remove) ++{ ++ preprocess_layout_info (tree, subdir); ++ ++ *should_remove = FALSE; ++ *contents_added = FALSE; ++ ++ if (subdir->subdirs == NULL && subdir->entries == NULL) ++ { ++ if (!(tree->flags & GMENU_TREE_FLAGS_SHOW_EMPTY) && ++ !layout_values->show_empty) ++ { ++ menu_verbose ("Not showing empty menu '%s'\n", subdir->name); ++ *should_remove = TRUE; ++ } + } ++ + else if (layout_values->inline_menus) + { +- check_pending_separator (directory); ++ guint real_subdirs_len; + +- if (layout_values->inline_alias && g_slist_length (subdir->contents) == 1) +- { +- GMenuTreeAlias *alias; +- GMenuTreeItem *item; ++ real_subdirs_len = get_real_subdirs_len (subdir); + +- item = GMENU_TREE_ITEM (subdir->contents->data); ++ if (layout_values->inline_alias && ++ real_subdirs_len + g_slist_length (subdir->entries) == 1) ++ { ++ GMenuTreeAlias *alias; ++ GMenuTreeItem *item; ++ GSList *list; + +- menu_verbose ("Inline aliasing '%s' to '%s'\n", +- subdir->name, +- item->type == GMENU_TREE_ITEM_ENTRY ? +- gmenu_tree_entry_get_name (GMENU_TREE_ENTRY (item)) : +- GMENU_TREE_DIRECTORY (directory)->name); ++ if (subdir->subdirs != NULL) ++ list = subdir->subdirs; ++ else ++ list = subdir->entries; + +- alias = gmenu_tree_alias_new (directory, subdir, item); ++ item = GMENU_TREE_ITEM (list->data); + +- g_slist_foreach (subdir->contents, +- (GFunc) gmenu_tree_item_unref_and_unset_parent, +- NULL); +- g_slist_free (subdir->contents); +- subdir->contents = NULL; ++ menu_verbose ("Inline aliasing '%s' to '%s'\n", ++ item->type == GMENU_TREE_ITEM_ENTRY ? ++ gmenu_tree_entry_get_name (GMENU_TREE_ENTRY (item)) : ++ (item->type == GMENU_TREE_ITEM_DIRECTORY ? ++ gmenu_tree_directory_get_name (GMENU_TREE_DIRECTORY (item)) : ++ gmenu_tree_directory_get_name (GMENU_TREE_ALIAS (item)->directory)), ++ subdir->name); ++ ++ alias = gmenu_tree_alias_new (directory, subdir, item); ++ ++ g_slist_foreach (list, ++ (GFunc) gmenu_tree_item_unref_and_unset_parent, ++ NULL); ++ g_slist_free (list); ++ subdir->subdirs = NULL; ++ subdir->entries = NULL; + +- directory->contents = g_slist_append (directory->contents, alias); ++ if (item->type == GMENU_TREE_ITEM_DIRECTORY) ++ directory->subdirs = g_slist_append (directory->subdirs, alias); ++ else ++ directory->entries = g_slist_append (directory->entries, alias); ++ ++ *contents_added = TRUE; ++ *should_remove = TRUE; ++ } + +- removed = TRUE; +- } + else if (layout_values->inline_limit == 0 || +- layout_values->inline_limit >= g_slist_length (subdir->contents)) ++ layout_values->inline_limit >= real_subdirs_len + g_slist_length (subdir->entries)) ++ { ++ if (layout_values->inline_header) ++ { ++ menu_verbose ("Creating inline header with name '%s'\n", subdir->name); ++ /* we're limited to 16-bits to spare some memory; if the limit is ++ * higher than that (would be crazy), we just consider it's ++ * unlimited */ ++ if (layout_values->inline_limit < G_MAXUINT16) ++ subdir->will_inline_header = layout_values->inline_limit; ++ else ++ subdir->will_inline_header = 0; ++ } ++ else ++ { ++ g_slist_foreach (subdir->subdirs, ++ (GFunc) gmenu_tree_item_set_parent, ++ directory); ++ directory->subdirs = g_slist_concat (directory->subdirs, ++ subdir->subdirs); ++ subdir->subdirs = NULL; ++ ++ g_slist_foreach (subdir->entries, ++ (GFunc) gmenu_tree_item_set_parent, ++ directory); ++ directory->entries = g_slist_concat (directory->entries, ++ subdir->entries); ++ subdir->entries = NULL; ++ ++ *contents_added = TRUE; ++ *should_remove = TRUE; ++ } ++ ++ menu_verbose ("Inlining directory contents of '%s' to '%s'\n", ++ subdir->name, directory->name); ++ } ++ } ++} ++ ++static void ++preprocess_layout_info (GMenuTree *tree, ++ GMenuTreeDirectory *directory) ++{ ++ GSList *tmp; ++ GSList *layout_info; ++ gboolean using_default_layout; ++ GSList *last_subdir; ++ gboolean strip_duplicates; ++ gboolean contents_added; ++ gboolean should_remove; ++ GSList *subdirs_sentinel; ++ ++ /* Note: we need to preprocess all menus, even if the layout mask for a menu ++ * is MENU_LAYOUT_VALUES_NONE: in this case, we need to remove empty menus; ++ * and the layout mask can be different for a submenu anyway */ ++ ++ menu_verbose ("Processing menu layout inline hints for %s\n", directory->name); ++ g_assert (!directory->preprocessed); ++ ++ strip_duplicates = FALSE; ++ /* we use last_subdir to track the last non-inlined subdirectory */ ++ last_subdir = g_slist_last (directory->subdirs); ++ ++ /* ++ * First process subdirectories with explicit layout ++ */ ++ layout_info = get_layout_info (directory, &using_default_layout); ++ tmp = layout_info; ++ /* see comment below about Menuname to understand why we leave the loop if ++ * last_subdir is NULL */ ++ while (tmp != NULL && last_subdir != NULL) ++ { ++ MenuLayoutNode *node = tmp->data; ++ MenuLayoutValues layout_values; ++ const char *name; ++ GMenuTreeDirectory *subdir; ++ GSList *subdir_l; ++ ++ tmp = tmp->next; ++ ++ /* only Menuname nodes are relevant here */ ++ if (menu_layout_node_get_type (node) != MENU_LAYOUT_NODE_MENUNAME) ++ continue; ++ ++ get_values_with_defaults (node, ++ &layout_values, ++ &directory->default_layout_values); ++ ++ /* find the subdirectory that is affected by those attributes */ ++ name = menu_layout_node_get_content (node); ++ subdir = NULL; ++ subdir_l = directory->subdirs; ++ while (subdir_l != NULL) ++ { ++ subdir = subdir_l->data; ++ ++ if (!strcmp (subdir->name, name)) ++ break; ++ ++ subdir = NULL; ++ subdir_l = subdir_l->next; ++ ++ /* We do not want to use Menuname on a menu that appeared via ++ * inlining: without inlining, the Menuname wouldn't have matched ++ * anything, and we want to keep the same behavior. ++ * Unless the layout is a default layout, in which case the Menuname ++ * does match the subdirectory. */ ++ if (!using_default_layout && subdir_l == last_subdir) ++ { ++ subdir_l = NULL; ++ break; ++ } ++ } ++ ++ if (subdir == NULL) ++ continue; ++ ++ preprocess_layout_info_subdir_helper (tree, directory, ++ subdir, &layout_values, ++ &contents_added, &should_remove); ++ strip_duplicates = strip_duplicates || contents_added; ++ if (should_remove) ++ { ++ if (last_subdir == subdir_l) ++ { ++ /* we need to recompute last_subdir since we'll remove it from ++ * the list */ ++ GSList *buf; ++ ++ if (subdir_l == directory->subdirs) ++ last_subdir = NULL; ++ else ++ { ++ buf = directory->subdirs; ++ while (buf != NULL && buf->next != subdir_l) ++ buf = buf->next; ++ last_subdir = buf; ++ } ++ } ++ ++ directory->subdirs = g_slist_remove (directory->subdirs, subdir); ++ gmenu_tree_item_unref_and_unset_parent (GMENU_TREE_ITEM (subdir)); ++ } ++ } ++ ++ /* ++ * Now process the subdirectories with no explicit layout ++ */ ++ /* this is bogus data, but we just need the pointer anyway */ ++ subdirs_sentinel = g_slist_prepend (directory->subdirs, PACKAGE); ++ directory->subdirs = subdirs_sentinel; ++ ++ tmp = directory->subdirs; ++ while (tmp->next != NULL) ++ { ++ GMenuTreeDirectory *subdir = tmp->next->data; ++ ++ if (subdir->preprocessed) ++ { ++ tmp = tmp->next; ++ continue; ++ } ++ ++ preprocess_layout_info_subdir_helper (tree, directory, ++ subdir, &directory->default_layout_values, ++ &contents_added, &should_remove); ++ strip_duplicates = strip_duplicates || contents_added; ++ if (should_remove) ++ { ++ tmp = g_slist_delete_link (tmp, tmp->next); ++ gmenu_tree_item_unref_and_unset_parent (GMENU_TREE_ITEM (subdir)); ++ } ++ else ++ tmp = tmp->next; ++ } ++ ++ /* remove the sentinel */ ++ directory->subdirs = g_slist_delete_link (directory->subdirs, ++ directory->subdirs); ++ ++ /* ++ * Finally, remove duplicates if needed ++ */ ++ if (strip_duplicates) + { +- if (layout_values->inline_header) ++ /* strip duplicate entries; there should be no duplicate directories */ ++ directory->entries = g_slist_sort (directory->entries, ++ (GCompareFunc) gmenu_tree_entry_compare_by_id); ++ tmp = directory->entries; ++ while (tmp != NULL && tmp->next != NULL) + { +- GMenuTreeHeader *header; ++ GMenuTreeItem *a = tmp->data; ++ GMenuTreeItem *b = tmp->next->data; ++ ++ if (a->type == GMENU_TREE_ITEM_ALIAS) ++ a = GMENU_TREE_ALIAS (a)->aliased_item; + +- menu_verbose ("Creating inline header with name '%s'\n", subdir->name); ++ if (b->type == GMENU_TREE_ITEM_ALIAS) ++ b = GMENU_TREE_ALIAS (b)->aliased_item; + +- header = gmenu_tree_header_new (directory, subdir); +- directory->contents = g_slist_append (directory->contents, header); ++ if (strcmp (GMENU_TREE_ENTRY (a)->desktop_file_id, ++ GMENU_TREE_ENTRY (b)->desktop_file_id) == 0) ++ { ++ tmp = g_slist_delete_link (tmp, tmp->next); ++ gmenu_tree_item_unref (b); ++ } ++ else ++ tmp = tmp->next; + } ++ } + +- menu_verbose ("Inlining directory contents of '%s' to '%s'\n", +- subdir->name, directory->name); ++ directory->preprocessed = TRUE; ++} + +- g_slist_foreach (subdir->contents, +- (GFunc) gmenu_tree_item_set_parent, +- directory); +- directory->contents = g_slist_concat (directory->contents, subdir->contents); +- subdir->contents = NULL; ++static void process_layout_info (GMenuTree *tree, ++ GMenuTreeDirectory *directory); ++ ++static void ++check_pending_separator (GMenuTreeDirectory *directory) ++{ ++ if (directory->layout_pending_separator) ++ { ++ menu_verbose ("Adding pending separator in '%s'\n", directory->name); + +- removed = TRUE; ++ directory->contents = g_slist_append (directory->contents, ++ gmenu_tree_separator_new (directory)); ++ directory->layout_pending_separator = FALSE; + } ++} ++ ++static void ++merge_alias (GMenuTree *tree, ++ GMenuTreeDirectory *directory, ++ GMenuTreeAlias *alias) ++{ ++ menu_verbose ("Merging alias '%s' in directory '%s'\n", ++ alias->directory->name, directory->name); ++ ++ if (alias->aliased_item->type == GMENU_TREE_ITEM_DIRECTORY) ++ { ++ process_layout_info (tree, GMENU_TREE_DIRECTORY (alias->aliased_item)); + } + +- if (removed) ++ check_pending_separator (directory); ++ ++ directory->contents = g_slist_append (directory->contents, ++ gmenu_tree_item_ref (alias)); ++} ++ ++static void ++merge_subdir (GMenuTree *tree, ++ GMenuTreeDirectory *directory, ++ GMenuTreeDirectory *subdir) ++{ ++ menu_verbose ("Merging subdir '%s' in directory '%s'\n", ++ subdir->name, directory->name); ++ ++ process_layout_info (tree, subdir); ++ ++ check_pending_separator (directory); ++ ++ if (subdir->will_inline_header == 0 || ++ (subdir->will_inline_header != G_MAXUINT16 && ++ g_slist_length (subdir->contents) <= subdir->will_inline_header)) + { ++ GMenuTreeHeader *header; ++ ++ header = gmenu_tree_header_new (directory, subdir); ++ directory->contents = g_slist_append (directory->contents, header); ++ ++ g_slist_foreach (subdir->contents, ++ (GFunc) gmenu_tree_item_set_parent, ++ directory); ++ directory->contents = g_slist_concat (directory->contents, ++ subdir->contents); ++ subdir->contents = NULL; ++ subdir->will_inline_header = G_MAXUINT16; ++ + gmenu_tree_item_set_parent (GMENU_TREE_ITEM (subdir), NULL); + } + else + { +- check_pending_separator (directory); + directory->contents = g_slist_append (directory->contents, +- gmenu_tree_item_ref (subdir)); ++ gmenu_tree_item_ref (subdir)); + } + } + + static void + merge_subdir_by_name (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- const char *subdir_name, +- MenuLayoutValues *values) ++ GMenuTreeDirectory *directory, ++ const char *subdir_name) + { + GSList *tmp; + + menu_verbose ("Attempting to merge subdir '%s' in directory '%s'\n", +- subdir_name, directory->name); ++ subdir_name, directory->name); + + tmp = directory->subdirs; + while (tmp != NULL) +@@ -3735,12 +4092,17 @@ merge_subdir_by_name (GMenuTree + GMenuTreeDirectory *subdir = tmp->data; + GSList *next = tmp->next; + ++ /* if it's an alias, then it cannot be affected by ++ * the Merge nodes in the layout */ ++ if (GMENU_TREE_ITEM (subdir)->type == GMENU_TREE_ITEM_ALIAS) ++ continue; ++ + if (!strcmp (subdir->name, subdir_name)) +- { +- directory->subdirs = g_slist_delete_link (directory->subdirs, tmp); +- merge_subdir (tree, directory, subdir, values); +- gmenu_tree_item_unref (subdir); +- } ++ { ++ directory->subdirs = g_slist_delete_link (directory->subdirs, tmp); ++ merge_subdir (tree, directory, subdir); ++ gmenu_tree_item_unref (subdir); ++ } + + tmp = next; + } +@@ -3748,26 +4110,26 @@ merge_subdir_by_name (GMenuTree + + static void + merge_entry (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- GMenuTreeEntry *entry) ++ GMenuTreeDirectory *directory, ++ GMenuTreeEntry *entry) + { + menu_verbose ("Merging entry '%s' in directory '%s'\n", +- entry->desktop_file_id, directory->name); ++ entry->desktop_file_id, directory->name); + + check_pending_separator (directory); + directory->contents = g_slist_append (directory->contents, +- gmenu_tree_item_ref (entry)); ++ gmenu_tree_item_ref (entry)); + } + + static void + merge_entry_by_id (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- const char *file_id) ++ GMenuTreeDirectory *directory, ++ const char *file_id) + { + GSList *tmp; + + menu_verbose ("Attempting to merge entry '%s' in directory '%s'\n", +- file_id, directory->name); ++ file_id, directory->name); + + tmp = directory->entries; + while (tmp != NULL) +@@ -3775,12 +4137,17 @@ merge_entry_by_id (GMenuTree *t + GMenuTreeEntry *entry = tmp->data; + GSList *next = tmp->next; + ++ /* if it's an alias, then it cannot be affected by ++ * the Merge nodes in the layout */ ++ if (GMENU_TREE_ITEM (entry)->type == GMENU_TREE_ITEM_ALIAS) ++ continue; ++ + if (!strcmp (entry->desktop_file_id, file_id)) +- { +- directory->entries = g_slist_delete_link (directory->entries, tmp); +- merge_entry (tree, directory, entry); +- gmenu_tree_item_unref (entry); +- } ++ { ++ directory->entries = g_slist_delete_link (directory->entries, tmp); ++ merge_entry (tree, directory, entry); ++ gmenu_tree_item_unref (entry); ++ } + + tmp = next; + } +@@ -3788,12 +4155,12 @@ merge_entry_by_id (GMenuTree *t + + static inline gboolean + find_name_in_list (const char *name, +- GSList *list) ++ GSList *list) + { + while (list != NULL) + { + if (!strcmp (name, list->data)) +- return TRUE; ++ return TRUE; + + list = list->next; + } +@@ -3803,8 +4170,8 @@ find_name_in_list (const char *name, + + static void + merge_subdirs (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- GSList *except) ++ GMenuTreeDirectory *directory, ++ GSList *except) + { + GSList *subdirs; + GSList *tmp; +@@ -3814,24 +4181,30 @@ merge_subdirs (GMenuTree *tree, + subdirs = directory->subdirs; + directory->subdirs = NULL; + +- subdirs = g_slist_sort (subdirs, +- (GCompareFunc) gmenu_tree_directory_compare); ++ subdirs = g_slist_sort_with_data (subdirs, ++ (GCompareDataFunc) gmenu_tree_item_compare, ++ GINT_TO_POINTER (GMENU_TREE_SORT_NAME)); + + tmp = subdirs; + while (tmp != NULL) + { + GMenuTreeDirectory *subdir = tmp->data; + +- if (!find_name_in_list (subdir->name, except)) +- { +- merge_subdir (tree, directory, subdir, &directory->default_layout_values); +- gmenu_tree_item_unref (subdir); +- } ++ if (GMENU_TREE_ITEM (subdir)->type == GMENU_TREE_ITEM_ALIAS) ++ { ++ merge_alias (tree, directory, GMENU_TREE_ALIAS (subdir)); ++ gmenu_tree_item_unref (subdir); ++ } ++ else if (!find_name_in_list (subdir->name, except)) ++ { ++ merge_subdir (tree, directory, subdir); ++ gmenu_tree_item_unref (subdir); ++ } + else +- { +- menu_verbose ("Not merging directory '%s' yet\n", subdir->name); +- directory->subdirs = g_slist_append (directory->subdirs, subdir); +- } ++ { ++ menu_verbose ("Not merging directory '%s' yet\n", subdir->name); ++ directory->subdirs = g_slist_append (directory->subdirs, subdir); ++ } + + tmp = tmp->next; + } +@@ -3842,8 +4215,8 @@ merge_subdirs (GMenuTree *tree, + + static void + merge_entries (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- GSList *except) ++ GMenuTreeDirectory *directory, ++ GSList *except) + { + GSList *entries; + GSList *tmp; +@@ -3853,24 +4226,30 @@ merge_entries (GMenuTree *tree, + entries = directory->entries; + directory->entries = NULL; + +- entries = g_slist_sort (entries, +- (GCompareFunc) gmenu_tree_entry_compare); ++ entries = g_slist_sort_with_data (entries, ++ (GCompareDataFunc) gmenu_tree_item_compare, ++ GINT_TO_POINTER (tree->sort_key)); + + tmp = entries; + while (tmp != NULL) + { + GMenuTreeEntry *entry = tmp->data; + +- if (!find_name_in_list (entry->desktop_file_id, except)) +- { +- merge_entry (tree, directory, entry); +- gmenu_tree_item_unref (entry); +- } ++ if (GMENU_TREE_ITEM (entry)->type == GMENU_TREE_ITEM_ALIAS) ++ { ++ merge_alias (tree, directory, GMENU_TREE_ALIAS (entry)); ++ gmenu_tree_item_unref (entry); ++ } ++ else if (!find_name_in_list (entry->desktop_file_id, except)) ++ { ++ merge_entry (tree, directory, entry); ++ gmenu_tree_item_unref (entry); ++ } + else +- { +- menu_verbose ("Not merging entry '%s' yet\n", entry->desktop_file_id); +- directory->entries = g_slist_append (directory->entries, entry); +- } ++ { ++ menu_verbose ("Not merging entry '%s' yet\n", entry->desktop_file_id); ++ directory->entries = g_slist_append (directory->entries, entry); ++ } + + tmp = tmp->next; + } +@@ -3881,60 +4260,72 @@ merge_entries (GMenuTree *tree, + + static void + merge_subdirs_and_entries (GMenuTree *tree, +- GMenuTreeDirectory *directory, +- GSList *except_subdirs, +- GSList *except_entries) ++ GMenuTreeDirectory *directory, ++ GSList *except_subdirs, ++ GSList *except_entries) + { + GSList *items; + GSList *tmp; + + menu_verbose ("Merging subdirs and entries together in directory %s\n", +- directory->name); ++ directory->name); + + items = g_slist_concat (directory->subdirs, directory->entries); + + directory->subdirs = NULL; + directory->entries = NULL; + +- items = g_slist_sort (items, +- (GCompareFunc) gmenu_tree_item_compare); ++ items = g_slist_sort_with_data (items, ++ (GCompareDataFunc) gmenu_tree_item_compare, ++ GINT_TO_POINTER (tree->sort_key)); + + tmp = items; + while (tmp != NULL) + { +- GMenuTreeItem *item = tmp->data; ++ GMenuTreeItem *item = tmp->data; ++ GMenuTreeItemType type; + +- if (gmenu_tree_item_get_type (item) == GMENU_TREE_ITEM_DIRECTORY) +- { +- if (!find_name_in_list (GMENU_TREE_DIRECTORY (item)->name, except_subdirs)) +- { +- merge_subdir (tree, +- directory, +- GMENU_TREE_DIRECTORY (item), +- &directory->default_layout_values); +- gmenu_tree_item_unref (item); +- } +- else +- { +- menu_verbose ("Not merging directory '%s' yet\n", +- GMENU_TREE_DIRECTORY (item)->name); +- directory->subdirs = g_slist_append (directory->subdirs, item); +- } +- } +- else +- { +- if (!find_name_in_list (GMENU_TREE_ENTRY (item)->desktop_file_id, except_entries)) ++ type = gmenu_tree_item_get_type (item); ++ ++ if (type == GMENU_TREE_ITEM_ALIAS) + { +- merge_entry (tree, directory, GMENU_TREE_ENTRY (item)); ++ merge_alias (tree, directory, GMENU_TREE_ALIAS (item)); + gmenu_tree_item_unref (item); + } ++ else if (type == GMENU_TREE_ITEM_DIRECTORY) ++ { ++ if (!find_name_in_list (GMENU_TREE_DIRECTORY (item)->name, except_subdirs)) ++ { ++ merge_subdir (tree, ++ directory, ++ GMENU_TREE_DIRECTORY (item)); ++ gmenu_tree_item_unref (item); ++ } ++ else ++ { ++ menu_verbose ("Not merging directory '%s' yet\n", ++ GMENU_TREE_DIRECTORY (item)->name); ++ directory->subdirs = g_slist_append (directory->subdirs, item); ++ } ++ } ++ else if (type == GMENU_TREE_ITEM_ENTRY) ++ { ++ if (!find_name_in_list (GMENU_TREE_ENTRY (item)->desktop_file_id, except_entries)) ++ { ++ merge_entry (tree, directory, GMENU_TREE_ENTRY (item)); ++ gmenu_tree_item_unref (item); ++ } ++ else ++ { ++ menu_verbose ("Not merging entry '%s' yet\n", ++ GMENU_TREE_ENTRY (item)->desktop_file_id); ++ directory->entries = g_slist_append (directory->entries, item); ++ } ++ } + else + { +- menu_verbose ("Not merging entry '%s' yet\n", +- GMENU_TREE_ENTRY (item)->desktop_file_id); +- directory->entries = g_slist_append (directory->entries, item); ++ g_assert_not_reached (); + } +- } + + tmp = tmp->next; + } +@@ -3944,53 +4335,6 @@ merge_subdirs_and_entries (GMenuTree + g_slist_free (except_entries); + } + +-static void +-get_values_with_defaults (MenuLayoutNode *node, +- MenuLayoutValues *layout_values, +- MenuLayoutValues *default_layout_values) +-{ +- menu_layout_node_menuname_get_values (node, layout_values); +- +- if (!(layout_values->mask & MENU_LAYOUT_VALUES_SHOW_EMPTY)) +- layout_values->show_empty = default_layout_values->show_empty; +- +- if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_MENUS)) +- layout_values->inline_menus = default_layout_values->inline_menus; +- +- if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_LIMIT)) +- layout_values->inline_limit = default_layout_values->inline_limit; +- +- if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_HEADER)) +- layout_values->inline_header = default_layout_values->inline_header; +- +- if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_ALIAS)) +- layout_values->inline_alias = default_layout_values->inline_alias; +-} +- +-static GSList * +-get_layout_info (GMenuTreeDirectory *directory) +-{ +- GMenuTreeDirectory *iter; +- +- if (directory->layout_info != NULL) +- { +- return directory->layout_info; +- } +- +- iter = directory; +- while (iter != NULL) +- { +- if (iter->default_layout_info != NULL) +- { +- return iter->default_layout_info; +- } +- +- iter = GMENU_TREE_ITEM (iter)->parent; +- } +- +- return NULL; +-} +- + static GSList * + get_subdirs_from_layout_info (GSList *layout_info) + { +@@ -4005,10 +4349,10 @@ get_subdirs_from_layout_info (GSList *la + MenuLayoutNode *node = tmp->data; + + if (menu_layout_node_get_type (node) == MENU_LAYOUT_NODE_MENUNAME) +- { +- subdirs = g_slist_append (subdirs, +- (char *) menu_layout_node_get_content (node)); +- } ++ { ++ subdirs = g_slist_append (subdirs, ++ (char *) menu_layout_node_get_content (node)); ++ } + + tmp = tmp->next; + } +@@ -4030,10 +4374,10 @@ get_entries_from_layout_info (GSList *la + MenuLayoutNode *node = tmp->data; + + if (menu_layout_node_get_type (node) == MENU_LAYOUT_NODE_FILENAME) +- { +- entries = g_slist_append (entries, +- (char *) menu_layout_node_get_content (node)); +- } ++ { ++ entries = g_slist_append (entries, ++ (char *) menu_layout_node_get_content (node)); ++ } + + tmp = tmp->next; + } +@@ -4043,20 +4387,22 @@ get_entries_from_layout_info (GSList *la + + static void + process_layout_info (GMenuTree *tree, +- GMenuTreeDirectory *directory) ++ GMenuTreeDirectory *directory) + { + GSList *layout_info; + + menu_verbose ("Processing menu layout hints for %s\n", directory->name); + + g_slist_foreach (directory->contents, +- (GFunc) gmenu_tree_item_unref_and_unset_parent, +- NULL); ++ (GFunc) gmenu_tree_item_unref_and_unset_parent, ++ NULL); + g_slist_free (directory->contents); + directory->contents = NULL; + directory->layout_pending_separator = FALSE; + +- if ((layout_info = get_layout_info (directory)) == NULL) ++ layout_info = get_layout_info (directory, NULL); ++ ++ if (layout_info == NULL) + { + merge_subdirs (tree, directory, NULL); + merge_entries (tree, directory, NULL); +@@ -4067,118 +4413,109 @@ process_layout_info (GMenuTree + + tmp = layout_info; + while (tmp != NULL) +- { +- MenuLayoutNode *node = tmp->data; ++ { ++ MenuLayoutNode *node = tmp->data; + +- switch (menu_layout_node_get_type (node)) +- { +- case MENU_LAYOUT_NODE_MENUNAME: +- { +- MenuLayoutValues layout_values; +- +- get_values_with_defaults (node, +- &layout_values, +- &directory->default_layout_values); +- +- merge_subdir_by_name (tree, +- directory, +- menu_layout_node_get_content (node), +- &layout_values); +- } +- break; +- +- case MENU_LAYOUT_NODE_FILENAME: +- merge_entry_by_id (tree, +- directory, +- menu_layout_node_get_content (node)); +- break; +- +- case MENU_LAYOUT_NODE_SEPARATOR: +- /* Unless explicitly told to show all separators, do not show a +- * separator at the beginning of a menu. Note that we don't add +- * the separators now, and instead make it pending. This way, we +- * won't show two consecutive separators nor will we show a +- * separator at the end of a menu. */ ++ switch (menu_layout_node_get_type (node)) ++ { ++ case MENU_LAYOUT_NODE_MENUNAME: ++ merge_subdir_by_name (tree, ++ directory, ++ menu_layout_node_get_content (node)); ++ break; ++ ++ case MENU_LAYOUT_NODE_FILENAME: ++ merge_entry_by_id (tree, ++ directory, ++ menu_layout_node_get_content (node)); ++ break; ++ ++ case MENU_LAYOUT_NODE_SEPARATOR: ++ /* Unless explicitly told to show all separators, do not show a ++ * separator at the beginning of a menu. Note that we don't add ++ * the separators now, and instead make it pending. This way, we ++ * won't show two consecutive separators nor will we show a ++ * separator at the end of a menu. */ + if (tree->flags & GMENU_TREE_FLAGS_SHOW_ALL_SEPARATORS) +- { +- directory->layout_pending_separator = TRUE; +- check_pending_separator (directory); +- } +- else if (directory->contents) +- { +- menu_verbose ("Adding a potential separator in '%s'\n", +- directory->name); +- +- directory->layout_pending_separator = TRUE; +- } +- else +- { +- menu_verbose ("Skipping separator at the beginning of '%s'\n", +- directory->name); +- } +- break; +- +- case MENU_LAYOUT_NODE_MERGE: +- switch (menu_layout_node_merge_get_type (node)) +- { +- case MENU_LAYOUT_MERGE_NONE: +- break; +- +- case MENU_LAYOUT_MERGE_MENUS: +- merge_subdirs (tree, +- directory, +- get_subdirs_from_layout_info (tmp->next)); +- break; +- +- case MENU_LAYOUT_MERGE_FILES: +- merge_entries (tree, +- directory, +- get_entries_from_layout_info (tmp->next)); +- break; ++ { ++ directory->layout_pending_separator = TRUE; ++ check_pending_separator (directory); ++ } ++ else if (directory->contents) ++ { ++ menu_verbose ("Adding a potential separator in '%s'\n", ++ directory->name); ++ ++ directory->layout_pending_separator = TRUE; ++ } ++ else ++ { ++ menu_verbose ("Skipping separator at the beginning of '%s'\n", ++ directory->name); ++ } ++ break; ++ ++ case MENU_LAYOUT_NODE_MERGE: ++ switch (menu_layout_node_merge_get_type (node)) ++ { ++ case MENU_LAYOUT_MERGE_NONE: ++ break; ++ ++ case MENU_LAYOUT_MERGE_MENUS: ++ merge_subdirs (tree, ++ directory, ++ get_subdirs_from_layout_info (tmp->next)); ++ break; ++ ++ case MENU_LAYOUT_MERGE_FILES: ++ merge_entries (tree, ++ directory, ++ get_entries_from_layout_info (tmp->next)); ++ break; ++ ++ case MENU_LAYOUT_MERGE_ALL: ++ merge_subdirs_and_entries (tree, ++ directory, ++ get_subdirs_from_layout_info (tmp->next), ++ get_entries_from_layout_info (tmp->next)); ++ break; ++ ++ default: ++ g_assert_not_reached (); ++ break; ++ } ++ break; ++ ++ default: ++ g_assert_not_reached (); ++ break; ++ } + +- case MENU_LAYOUT_MERGE_ALL: +- merge_subdirs_and_entries (tree, +- directory, +- get_subdirs_from_layout_info (tmp->next), +- get_entries_from_layout_info (tmp->next)); +- break; +- +- default: +- g_assert_not_reached (); +- break; +- } +- break; +- +- default: +- g_assert_not_reached (); +- break; +- } +- +- tmp = tmp->next; +- } ++ tmp = tmp->next; ++ } + } + + g_slist_foreach (directory->subdirs, +- (GFunc) gmenu_tree_item_unref, +- NULL); ++ (GFunc) gmenu_tree_item_unref, ++ NULL); + g_slist_free (directory->subdirs); + directory->subdirs = NULL; + + g_slist_foreach (directory->entries, +- (GFunc) gmenu_tree_item_unref, +- NULL); ++ (GFunc) gmenu_tree_item_unref, ++ NULL); + g_slist_free (directory->entries); + directory->entries = NULL; + + g_slist_foreach (directory->default_layout_info, +- (GFunc) menu_layout_node_unref, +- NULL); ++ (GFunc) menu_layout_node_unref, ++ NULL); + g_slist_free (directory->default_layout_info); + directory->default_layout_info = NULL; + + g_slist_foreach (directory->layout_info, +- (GFunc) menu_layout_node_unref, +- NULL); ++ (GFunc) menu_layout_node_unref, ++ NULL); + g_slist_free (directory->layout_info); + directory->layout_info = NULL; + } +@@ -4210,6 +4547,7 @@ gmenu_tree_build_from_layout (GMenuTree + + allocated = desktop_entry_set_new (); + ++ /* create the menu structure */ + tree->root = process_layout (tree, + NULL, + find_menu_child (tree->layout), +@@ -4220,6 +4558,11 @@ gmenu_tree_build_from_layout (GMenuTree + + process_only_unallocated (tree, tree->root, allocated); + ++ /* process the layout info part that can move/remove items: ++ * inline, show_empty, etc. */ ++ preprocess_layout_info (tree, tree->root); ++ /* populate the menu structure that we got with the items, and order it ++ * according to the layout info */ + process_layout_info (tree, tree->root); + + menu_layout_node_root_add_entries_monitor (tree->layout, +--- menu-cache-0.3.2.orig/menu-cache-gen/entry-directories.h ++++ menu-cache-0.3.2/menu-cache-gen/entry-directories.h +@@ -52,6 +52,9 @@ EntryDirectoryList *entry_directory_list + void entry_directory_list_unref (EntryDirectoryList *list); + + int entry_directory_list_get_length (EntryDirectoryList *list); ++gboolean _entry_directory_list_compare (const EntryDirectoryList *a, ++ const EntryDirectoryList *b); ++ + void entry_directory_list_prepend (EntryDirectoryList *list, + EntryDirectory *ed); + void entry_directory_list_append_list (EntryDirectoryList *list, +@@ -67,8 +70,8 @@ void entry_directory_list_remove_monitor + DesktopEntry* entry_directory_list_get_directory (EntryDirectoryList *list, + const char *relative_path); + +-void entry_directory_list_get_all_desktops (EntryDirectoryList *list, +- DesktopEntrySet *set); ++DesktopEntrySet *_entry_directory_list_get_all_desktops (EntryDirectoryList *list); ++void _entry_directory_list_empty_desktop_cache (void); + + G_END_DECLS + +--- menu-cache-0.3.2.orig/menu-cache-gen/desktop-entries.c ++++ menu-cache-0.3.2/menu-cache-gen/desktop-entries.c +@@ -45,10 +45,11 @@ struct DesktopEntry + + char *name; + char *generic_name; ++ char *full_name; + char *comment; + char *icon; + char *exec; +- gboolean terminal : 1; ++ gboolean terminal; + gboolean startup_notify : 1; + + guint32 show_in_flags; +@@ -64,13 +65,13 @@ struct DesktopEntrySet + GHashTable *hash; + }; + +-/* defined in menu-cache-gen.c */ +-guint32 menu_cache_get_de_flag( const char* de_name ); +- + /* + * Desktop entries + */ + ++/* defined in menu-cache-gen.c */ ++guint32 menu_cache_get_de_flag( const char* de_name ); ++ + static guint + get_flags_from_key_file (DesktopEntry *entry, + GKeyFile *key_file, +@@ -156,7 +157,7 @@ get_flags_from_key_file (DesktopEntry *e + } + } + g_strfreev (strv); +- /* printf( "DE flag of %s is %d\n", entry->name, entry->show_in_flags); */ ++ + tryexec_failed = FALSE; + tryexec = g_key_file_get_string (key_file, + desktop_entry_group, +@@ -302,6 +303,16 @@ desktop_entry_load (DesktopEntry *entry) + + retval->name = GET_LOCALE_STRING ("Name"); + retval->generic_name = GET_LOCALE_STRING ("GenericName"); ++ retval->full_name = GET_LOCALE_STRING ("X-GNOME-FullName"); ++/* ++ GError *err; ++ err = NULL; ++ g_print("Display : %s\n", g_key_file_get_locale_string (key_file, desktop_entry_group, "X-GNOME-FullName", NULL, &err)); ++ if (err) { ++ g_print("Error : %s\n", err->message); ++ g_error_free (err); ++ } ++*/ + retval->comment = GET_LOCALE_STRING ("Comment"); + retval->icon = GET_LOCALE_STRING ("Icon"); + retval->flags = get_flags_from_key_file (retval, key_file, desktop_entry_group); +@@ -316,9 +327,11 @@ desktop_entry_load (DesktopEntry *entry) + + #undef GET_LOCALE_STRING + +- menu_verbose ("Desktop entry \"%s\" (%s, %s, %s) flags: NoDisplay=%s, Hidden=%s, ShowInGNOME=%s, TryExecFailed=%s\n", ++ menu_verbose ("Desktop entry \"%s\" (%s, %s, %s, %s, %s) flags: NoDisplay=%s, Hidden=%s, ShowInGNOME=%s, TryExecFailed=%s\n", + retval->basename, + retval->name, ++ retval->generic_name ? retval->generic_name : "(null)", ++ retval->full_name ? retval->full_name : "(null)", + retval->comment ? retval->comment : "(null)", + retval->icon ? retval->icon : "(null)", + retval->flags & DESKTOP_ENTRY_NO_DISPLAY ? "(true)" : "(false)", +@@ -384,6 +397,9 @@ desktop_entry_reload (DesktopEntry *entr + g_free (entry->generic_name); + entry->generic_name = NULL; + ++ g_free (entry->full_name); ++ entry->full_name = NULL; ++ + g_free (entry->comment); + entry->comment = NULL; + +@@ -422,16 +438,17 @@ desktop_entry_copy (DesktopEntry *entry) + + retval = g_new0 (DesktopEntry, 1); + +- retval->refcount = 1; +- retval->type = entry->type; +- retval->basename = g_strdup (entry->basename); +- retval->path = g_strdup (entry->path); +- retval->name = g_strdup (entry->name); ++ retval->refcount = 1; ++ retval->type = entry->type; ++ retval->basename = g_strdup (entry->basename); ++ retval->path = g_strdup (entry->path); ++ retval->name = g_strdup (entry->name); + retval->generic_name = g_strdup (entry->generic_name); +- retval->comment = g_strdup (entry->comment); +- retval->icon = g_strdup (entry->icon); +- retval->exec = g_strdup (entry->exec); +- retval->terminal = entry->terminal; ++ retval->full_name = g_strdup (entry->full_name); ++ retval->comment = g_strdup (entry->comment); ++ retval->icon = g_strdup (entry->icon); ++ retval->exec = g_strdup (entry->exec); ++ retval->terminal = entry->terminal; + retval->startup_notify = entry->startup_notify; + retval->flags = entry->flags; + +@@ -471,6 +488,9 @@ desktop_entry_unref (DesktopEntry *entry + g_free (entry->generic_name); + entry->generic_name = NULL; + ++ g_free (entry->full_name); ++ entry->full_name = NULL; ++ + g_free (entry->comment); + entry->comment = NULL; + +@@ -521,6 +541,12 @@ desktop_entry_get_generic_name (DesktopE + } + + const char * ++desktop_entry_get_full_name (DesktopEntry *entry) ++{ ++ return entry->full_name; ++} ++ ++const char * + desktop_entry_get_comment (DesktopEntry *entry) + { + return entry->comment; +@@ -538,12 +564,6 @@ desktop_entry_get_exec (DesktopEntry *en + return entry->exec; + } + +-const GQuark * +-desktop_entry_get_categories (DesktopEntry *entry) +-{ +- return entry->categories; +-} +- + gboolean + desktop_entry_get_launch_in_terminal (DesktopEntry *entry) + { diff -Nru menu-cache-0.3.2/debian/patches/initialize-locale.patch menu-cache-0.3.2/debian/patches/initialize-locale.patch --- menu-cache-0.3.2/debian/patches/initialize-locale.patch 1970-01-01 00:00:00.000000000 +0000 +++ menu-cache-0.3.2/debian/patches/initialize-locale.patch 2011-01-25 20:55:18.000000000 +0000 @@ -0,0 +1,51 @@ +Description: Upstream changes introduced in version 0.3.2-2 + This patch has been created by dpkg-source during the package build. + Here's the last changelog entry, hopefully it gives details on why + those changes were made: + . + menu-cache (0.3.2-2) unstable; urgency=low + . + * Added soname in libexec dir path. (Closes:#573119) + * Added soname for -dev binary package name + * Enable team maintenance: + - mailing list on alioth: Debian LXDE Packaging Team + + - git repo on collab-maint: + http://git.debian.org/?p=collab-maint/lxsession.git;a=summary + . + The person named in the Author field signed this changelog entry. +Author: Andrew Lee (李健秋) +Bug-Debian: http://bugs.debian.org/573119 + +--- +The information above should follow the Patch Tagging Guidelines, please +checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here +are templates for supplementary fields that you might want to add: + +Origin: , +Bug: +Bug-Debian: http://bugs.debian.org/ +Bug-Ubuntu: https://launchpad.net/bugs/ +Forwarded: +Reviewed-By: +Last-Update: + +--- menu-cache-0.3.2.orig/menu-cache-gen/menu-cache-gen.c ++++ menu-cache-0.3.2/menu-cache-gen/menu-cache-gen.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -307,6 +308,8 @@ int main(int argc, char** argv) + char* menu_prefix; + char* menu_file; + ++ setlocale (LC_ALL, ""); ++ + opt_ctx = g_option_context_new("Generate cache for freedeskotp.org compliant menus."); + g_option_context_add_main_entries( opt_ctx, opt_entries, NULL ); + if( ! g_option_context_parse( opt_ctx, &argc, &argv, &err ) ) diff -Nru menu-cache-0.3.2/debian/patches/series menu-cache-0.3.2/debian/patches/series --- menu-cache-0.3.2/debian/patches/series 2010-02-20 18:12:42.000000000 +0000 +++ menu-cache-0.3.2/debian/patches/series 2011-01-25 20:56:10.000000000 +0000 @@ -1 +1,3 @@ libtool-fix.patch +gmenu-2.30.5.patch +initialize-locale.patch