Index: ChangeLog =================================================================== RCS file: /cvs/gnome/gnome-menus/ChangeLog,v retrieving revision 1.123 diff -u -p -r1.123 ChangeLog --- ChangeLog 11 Jul 2005 13:12:18 -0000 1.123 +++ ChangeLog 20 Jul 2005 15:01:08 -0000 @@ -0,0 +1,56 @@ +2005-07-20 Mark McLoughlin + + * libmenu/menu-monitor.c: (free_event_info): plug + a leak. + + * libmenu/entry-directories.c: + (cached_dir_find_file_id), + (entry_directory_get_desktop), + (entry_directory_list_get_desktop): remove some unused code. + It became unused when we switched to matching s + against a DesktopEntrySet of all the desktop entries. + +2005-07-20 Mark McLoughlin + + Fix things up so that we correctly handle different + filename encodings. Fixes bug #310939 + + As far as the API goes, the rule is that the return value + from gmenu_tree_entry_get_desktop_file_path() is in + the filename encoding; everything else is UTF-8 + + * libmenu/gmenu-tree.c: (gmenu_tree_directory_make_path): + Convert filename encoded basename to UTF-8 before appending + to returned menu path. + + * libmenu/desktop-entries.c: (desktop_entry_new): don't + load any .desktop files whose filenames aren't in a + recognised encoding. + + * libmenu/entry-directories.[ch]: + (entry_directory_new_full): convert UTF-8 path to filename + encoding before loading; fallback to original path if UTF-8 + conversion fails. + (get_desktop_file_id_from_path): convert the filename + encoded path to a UTF-8 desktop-file-id + (entry_directory_foreach_recursive): don't pass the + path and file_id to the callback; use the path as + a file_id for .directory files. + (entry_directory_get_flat_contents): convert filename + encoded path of .directory file to UTF-8 before using as + a desktop-file-id. + (entry_directory_list_get_directory): convert UTF-8 path + to filename encoding; fallback to original path if conversion + fails. + (get_all_func): we don't get passed the path anymore. + (entry_directory_list_get_all_desktops): munge the code + from entry_directory_list_add() in here since it was + its only user. + + * util/Makefile.am: define GNOMELOCALEDIR in CFLAGS. + + * util/test-menu-spec.c: + (print_entry): convert desktop entry path to UTF-8 before + printing + (handle_tree_changed), (main): i18nize. + Index: libmenu/desktop-entries.c =================================================================== RCS file: /cvs/gnome/gnome-menus/libmenu/desktop-entries.c,v retrieving revision 1.9 diff -u -p -r1.9 desktop-entries.c --- libmenu/desktop-entries.c 5 May 2005 06:58:24 -0000 1.9 +++ libmenu/desktop-entries.c 20 Jul 2005 15:01:09 -0000 @@ -306,6 +306,7 @@ desktop_entry_new (const char *path) { DesktopEntryType type; DesktopEntry *retval; + char *utf8_path; menu_verbose ("Loading desktop entry \"%s\"\n", path); @@ -324,6 +325,18 @@ desktop_entry_new (const char *path) return NULL; } + utf8_path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL); + if (utf8_path == NULL) + { + menu_verbose ("Unrecognised filename encoding in '%s'\n", + path); + return NULL; + } + else + { + g_free (utf8_path); + } + retval = g_new0 (DesktopEntry, 1); retval->refcount = 1; @@ -451,12 +464,20 @@ desktop_entry_get_type (DesktopEntry *en return entry->type; } +/* + * Return value is in filename encoding, but we're also + * guaranteed that it will convert to UTF-8 + */ const char * desktop_entry_get_path (DesktopEntry *entry) { return entry->path; } +/* + * Return value is in filename encoding, but we're also + * guaranteed that it will convert to UTF-8 + */ const char * desktop_entry_get_basename (DesktopEntry *entry) { Index: libmenu/entry-directories.c =================================================================== RCS file: /cvs/gnome/gnome-menus/libmenu/entry-directories.c,v retrieving revision 1.10 diff -u -p -r1.10 entry-directories.c --- libmenu/entry-directories.c 22 Apr 2005 14:55:56 -0000 1.10 +++ libmenu/entry-directories.c 20 Jul 2005 15:01:09 -0000 @@ -215,74 +215,6 @@ cached_dir_find_relative_path (CachedDir return retval; } -static DesktopEntry * -cached_dir_find_file_id (CachedDir *dir, - const char *file_id, - gboolean legacy) -{ - DesktopEntry *retval = NULL; - - if (!legacy) - { - char *p; - char *freeme; - - p = freeme = g_strdup (file_id); - while (p != NULL) - { - char *q; - - if ((retval = find_entry (dir, p))) - break; - - q = strchr (p, '-'); - if (q) - { - CachedDir *subdir; - - *(q++) = '\0'; - - if ((subdir = find_subdir (dir, p))) - { - retval = cached_dir_find_file_id (subdir, q, legacy); - if (retval) - break; - } - } - - p = q; - } - - g_free (freeme); - } - else /* legacy */ - { - retval = find_entry (dir, file_id); - - /* Ignore entries with categories in legacy trees - */ - if (retval && desktop_entry_has_categories (retval)) - retval = NULL; - - if (!retval) - { - GSList *tmp; - - tmp = dir->subdirs; - while (tmp != NULL) - { - retval = cached_dir_find_file_id (tmp->data, file_id, legacy); - if (retval) - break; - - tmp = tmp->next; - } - } - } - - return retval; -} - static CachedDir * cached_dir_lookup (const char *canonical) { @@ -747,14 +679,20 @@ cached_dir_get_entries (CachedDir *dir static EntryDirectory * entry_directory_new_full (DesktopEntryType entry_type, - const char *path, + const char *utf8_path, gboolean is_legacy, const char *legacy_prefix) { EntryDirectory *ed; CachedDir *cd; + const char *path; + char *freeme; char *canonical; + path = freeme = g_filename_from_utf8 (utf8_path, -1, NULL, NULL, NULL); + if (!path) + path = utf8_path; + menu_verbose ("Loading entry directory \"%s\" (legacy %s)\n", path, is_legacy ? "" : ""); @@ -764,6 +702,7 @@ entry_directory_new_full (DesktopEntryTy { menu_verbose ("Failed to canonicalize \"%s\": %s\n", path, g_strerror (errno)); + g_free (freeme); return NULL; } @@ -779,23 +718,24 @@ entry_directory_new_full (DesktopEntryTy ed->refcount = 1; g_free (canonical); + g_free (freeme); return ed; } EntryDirectory * entry_directory_new (DesktopEntryType entry_type, - const char *path) + const char *utf8_path) { - return entry_directory_new_full (entry_type, path, FALSE, NULL); + return entry_directory_new_full (entry_type, utf8_path, FALSE, NULL); } EntryDirectory * entry_directory_new_legacy (DesktopEntryType entry_type, - const char *path, + const char *utf8_path, const char *legacy_prefix) { - return entry_directory_new_full (entry_type, path, TRUE, legacy_prefix); + return entry_directory_new_full (entry_type, utf8_path, TRUE, legacy_prefix); } EntryDirectory * @@ -845,47 +785,6 @@ entry_directory_remove_monitor (EntryDir } static DesktopEntry * -entry_directory_get_desktop (EntryDirectory *ed, - const char *file_id) -{ - DesktopEntry *entry; - const char *unprefixed_id; - - if (ed->entry_type != DESKTOP_ENTRY_DESKTOP) - return NULL; - - unprefixed_id = NULL; - - if (ed->is_legacy && ed->legacy_prefix) - { - if (!g_str_has_prefix (file_id, ed->legacy_prefix)) - return NULL; - - unprefixed_id = file_id + strlen (ed->legacy_prefix); - - if (unprefixed_id[0] != '-') - return NULL; - - unprefixed_id++; - } - - entry = cached_dir_find_file_id (ed->dir, - unprefixed_id ? unprefixed_id : file_id, - ed->is_legacy); - if (entry == NULL || desktop_entry_get_type (entry) != DESKTOP_ENTRY_DESKTOP) - return NULL; - - if (ed->is_legacy && !desktop_entry_has_categories (entry)) - { - entry = desktop_entry_copy (entry); - desktop_entry_add_legacy_category (entry); - return entry; - } - - return desktop_entry_ref (entry); -} - -static DesktopEntry * entry_directory_get_directory (EntryDirectory *ed, const char *relative_path) { @@ -903,37 +802,51 @@ entry_directory_get_directory (EntryDire static char * get_desktop_file_id_from_path (EntryDirectory *ed, - const char *relative_path) + const char *relative_path) { char *retval; + char *utf8_path; + + utf8_path = g_filename_to_utf8 (relative_path, -1, NULL, NULL, NULL); + g_assert (utf8_path != NULL); - if (!ed->is_legacy) + if (ed->entry_type == DESKTOP_ENTRY_DESKTOP) { - retval = g_strdelimit (g_strdup (relative_path), "/", '-'); + if (!ed->is_legacy) + { + retval = g_strdelimit (utf8_path, "/", '-'); + utf8_path = NULL; + } + else + { + char *basename; + + basename = g_path_get_basename (utf8_path); + + if (ed->legacy_prefix) + { + retval = g_strjoin ("-", ed->legacy_prefix, basename, NULL); + g_free (basename); + } + else + { + retval = basename; + } + } } else { - char *basename; - - basename = g_path_get_basename (relative_path); - - if (ed->legacy_prefix) - { - retval = g_strjoin ("-", ed->legacy_prefix, basename, NULL); - g_free (basename); - } - else - { - retval = basename; - } + retval = utf8_path; + utf8_path = NULL; } + g_free (utf8_path); + return retval; } typedef gboolean (* EntryDirectoryForeachFunc) (EntryDirectory *ed, DesktopEntry *entry, - const char *relative_path, const char *file_id, DesktopEntrySet *set, gpointer user_data); @@ -964,11 +877,9 @@ entry_directory_foreach_recursive (Entry g_string_append (relative_path, desktop_entry_get_basename (entry)); - file_id = NULL; - if (ed->entry_type == DESKTOP_ENTRY_DESKTOP) - file_id = get_desktop_file_id_from_path (ed, relative_path->str); + file_id = get_desktop_file_id_from_path (ed, relative_path->str); - ret = func (ed, entry, relative_path->str, file_id, set, user_data); + ret = func (ed, entry, file_id, set, user_data); g_free (file_id); @@ -1061,9 +972,16 @@ entry_directory_get_flat_contents (Entry if (directory_entries && desktop_entry_get_type (entry) == DESKTOP_ENTRY_DIRECTORY) { + char *utf8_basename; + + utf8_basename = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL); + g_assert (utf8_basename != NULL); + desktop_entry_set_add_entry (directory_entries, - entry, - g_strdup (basename)); + entry, + utf8_basename); + + g_free (utf8_basename); } tmp = tmp->next; @@ -1172,30 +1090,17 @@ entry_directory_list_append_list (EntryD } DesktopEntry * -entry_directory_list_get_desktop (EntryDirectoryList *list, - const char *file_id) -{ - DesktopEntry *retval = NULL; - GList *tmp; - - tmp = list->dirs; - while (tmp != NULL) - { - if ((retval = entry_directory_get_desktop (tmp->data, file_id)) != NULL) - break; - - tmp = tmp->next; - } - - return retval; -} - -DesktopEntry * entry_directory_list_get_directory (EntryDirectoryList *list, - const char *relative_path) + const char *utf8_relative_path) { DesktopEntry *retval = NULL; GList *tmp; + const char *relative_path; + char *freeme; + + relative_path = freeme = g_filename_from_utf8 (utf8_relative_path, -1, NULL, NULL, NULL); + if (relative_path == NULL) + relative_path = utf8_relative_path; tmp = list->dirs; while (tmp != NULL) @@ -1206,43 +1111,14 @@ entry_directory_list_get_directory (Entr tmp = tmp->next; } - return retval; -} - -static void -entry_directory_list_add (EntryDirectoryList *list, - EntryDirectoryForeachFunc func, - DesktopEntrySet *set, - gpointer user_data) -{ - GList *tmp; - - /* The only tricky thing here is that desktop files later - * in the search list with the same relative path - * are "hidden" by desktop files earlier in the path, - * so we have to do the earlier files first causing - * the later files to replace the earlier files - * in the DesktopEntrySet - * - * We go from the end of the list so we can just - * g_hash_table_replace and not have to do two - * hash lookups (check for existing entry, then insert new - * entry) - */ - - tmp = g_list_last (list->dirs); - while (tmp != NULL) - { - entry_directory_foreach (tmp->data, func, set, user_data); + g_free (freeme); - tmp = tmp->prev; - } + return retval; } static gboolean get_all_func (EntryDirectory *ed, DesktopEntry *entry, - const char *relative_path, const char *file_id, DesktopEntrySet *set, gpointer user_data) @@ -1257,9 +1133,7 @@ get_all_func (EntryDirectory *ed, entry = desktop_entry_ref (entry); } - desktop_entry_set_add_entry (set, - entry, - file_id ? file_id : relative_path); + desktop_entry_set_add_entry (set, entry, file_id); desktop_entry_unref (entry); return TRUE; @@ -1269,10 +1143,31 @@ void entry_directory_list_get_all_desktops (EntryDirectoryList *list, DesktopEntrySet *set) { + GList *tmp; + menu_verbose (" Storing all of list %p in set %p\n", list, set); - entry_directory_list_add (list, get_all_func, set, NULL); + /* The only tricky thing here is that desktop files later + * in the search list with the same relative path + * are "hidden" by desktop files earlier in the path, + * so we have to do the earlier files first causing + * the later files to replace the earlier files + * in the DesktopEntrySet + * + * We go from the end of the list so we can just + * g_hash_table_replace and not have to do two + * hash lookups (check for existing entry, then insert new + * entry) + */ + + tmp = g_list_last (list->dirs); + while (tmp != NULL) + { + entry_directory_foreach (tmp->data, get_all_func, set, NULL); + + tmp = tmp->prev; + } } void Index: libmenu/entry-directories.h =================================================================== RCS file: /cvs/gnome/gnome-menus/libmenu/entry-directories.h,v retrieving revision 1.2 diff -u -p -r1.2 entry-directories.h --- libmenu/entry-directories.h 15 Apr 2005 09:59:18 -0000 1.2 +++ libmenu/entry-directories.h 20 Jul 2005 15:01:09 -0000 @@ -31,9 +31,9 @@ typedef void (*EntryDirectoryChangedFunc gpointer user_data); EntryDirectory *entry_directory_new (DesktopEntryType entry_type, - const char *path); + const char *utf8_path); EntryDirectory *entry_directory_new_legacy (DesktopEntryType entry_type, - const char *path, + const char *utf8_path, const char *legacy_prefix); EntryDirectory *entry_directory_ref (EntryDirectory *ed); @@ -64,10 +64,8 @@ void entry_directory_list_remove_monitor EntryDirectoryChangedFunc callback, gpointer user_data); -DesktopEntry* entry_directory_list_get_desktop (EntryDirectoryList *list, - const char *file_id); DesktopEntry* entry_directory_list_get_directory (EntryDirectoryList *list, - const char *relative_path); + const char *utf8_relative_path); void entry_directory_list_get_all_desktops (EntryDirectoryList *list, DesktopEntrySet *set); Index: libmenu/gmenu-tree.c =================================================================== RCS file: /cvs/gnome/gnome-menus/libmenu/gmenu-tree.c,v retrieving revision 1.35 diff -u -p -r1.35 gmenu-tree.c --- libmenu/gmenu-tree.c 28 Jun 2005 08:59:07 -0000 1.35 +++ libmenu/gmenu-tree.c 20 Jul 2005 15:01:11 -0000 @@ -1039,8 +1039,17 @@ gmenu_tree_directory_make_path (GMenuTre append_directory_path (directory, path); if (entry != NULL) - g_string_append (path, - desktop_entry_get_basename (entry->desktop_entry)); + { + char *utf8_basename; + + utf8_basename = g_filename_to_utf8 (desktop_entry_get_basename (entry->desktop_entry), + -1, NULL, NULL, NULL); + g_assert (utf8_basename != NULL); + + g_string_append (path, utf8_basename); + + g_free (utf8_basename); + } return g_string_free (path, FALSE); } @@ -1077,6 +1086,9 @@ gmenu_tree_entry_get_exec (GMenuTreeEntr return desktop_entry_get_exec (entry->desktop_entry); } +/* + * Return value is in filename encoding + */ const char * gmenu_tree_entry_get_desktop_file_path (GMenuTreeEntry *entry) { Index: libmenu/menu-monitor.c =================================================================== RCS file: /cvs/gnome/gnome-menus/libmenu/menu-monitor.c,v retrieving revision 1.3 diff -u -p -r1.3 menu-monitor.c --- libmenu/menu-monitor.c 12 May 2005 15:49:11 -0000 1.3 +++ libmenu/menu-monitor.c 20 Jul 2005 15:01:11 -0000 @@ -494,6 +494,8 @@ free_event_info (MenuMonitorEventInfo *e event->monitor = NULL; event->event = MENU_MONITOR_EVENT_INVALID; + + g_free (event); } #endif /* HAVE_FAM */ Index: po/ChangeLog =================================================================== RCS file: /cvs/gnome/gnome-menus/po/ChangeLog,v retrieving revision 1.138 diff -u -p -r1.138 ChangeLog --- po/ChangeLog 19 Jul 2005 13:02:02 -0000 1.138 +++ po/ChangeLog 20 Jul 2005 15:01:11 -0000 @@ -1,3 +1,7 @@ +2005-07-20 Mark McLoughlin + + * POTFILES.in: add util/test-menu-spec.c + 2005-07-19 Clytie Siddall * vi.po: Updated Vietnamese translation. Index: po/POTFILES.in =================================================================== RCS file: /cvs/gnome/gnome-menus/po/POTFILES.in,v retrieving revision 1.5 diff -u -p -r1.5 POTFILES.in --- po/POTFILES.in 11 Jul 2005 13:12:34 -0000 1.5 +++ po/POTFILES.in 20 Jul 2005 15:01:11 -0000 @@ -20,3 +20,4 @@ desktop-directories/System-Tools.directo simple-editor/gmenu-simple-editor.glade simple-editor/GMenuSimpleEditor/maindialog.py simple-editor/GMenuSimpleEditor/menufilewriter.py +util/test-menu-spec.c Index: util/Makefile.am =================================================================== RCS file: /cvs/gnome/gnome-menus/util/Makefile.am,v retrieving revision 1.3 diff -u -p -r1.3 Makefile.am --- util/Makefile.am 22 Apr 2005 14:55:58 -0000 1.3 +++ util/Makefile.am 20 Jul 2005 15:01:11 -0000 @@ -1,12 +1,13 @@ NULL = -INCLUDES = \ - -DGMENU_I_KNOW_THIS_IS_UNSTABLE \ - -I$(srcdir)/../libmenu \ - $(GLIB_CFLAGS) \ - $(DISABLE_DEPRECATED_CFLAGS) \ - $(DEBUG_CFLAGS) \ - $(WARN_CFLAGS) \ +INCLUDES = \ + -DGMENU_I_KNOW_THIS_IS_UNSTABLE \ + -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -I$(srcdir)/../libmenu \ + $(GLIB_CFLAGS) \ + $(DISABLE_DEPRECATED_CFLAGS) \ + $(DEBUG_CFLAGS) \ + $(WARN_CFLAGS) \ $(NULL) bin_PROGRAMS = \ Index: util/test-menu-spec.c =================================================================== RCS file: /cvs/gnome/gnome-menus/util/test-menu-spec.c,v retrieving revision 1.9 diff -u -p -r1.9 test-menu-spec.c --- util/test-menu-spec.c 22 Apr 2005 14:55:58 -0000 1.9 +++ util/test-menu-spec.c 20 Jul 2005 15:01:11 -0000 @@ -21,6 +21,7 @@ #include "gmenu-tree.h" +#include #include static char *menu_file = NULL; @@ -28,9 +29,9 @@ static gboolean monitor = FALSE; static gboolean include_excluded = FALSE; static GOptionEntry options[] = { - { "file", 'f', 0, G_OPTION_ARG_STRING, &menu_file, "Menu file", "MENU_FILE" }, - { "monitor", 'm', 0, G_OPTION_ARG_NONE, &monitor, "Monitor for menu changes", NULL }, - { "include-excluded", 'i', 0, G_OPTION_ARG_NONE, &include_excluded, "Include d entries", NULL }, + { "file", 'f', 0, G_OPTION_ARG_STRING, &menu_file, N_("Menu file"), N_("MENU_FILE") }, + { "monitor", 'm', 0, G_OPTION_ARG_NONE, &monitor, N_("Monitor for menu changes"), NULL }, + { "include-excluded", 'i', 0, G_OPTION_ARG_NONE, &include_excluded, N_("Include d entries"), NULL }, { NULL } }; @@ -74,11 +75,18 @@ static void print_entry (GMenuTreeEntry *entry, const char *path) { + char *utf8_path; + + utf8_path = g_filename_to_utf8 (gmenu_tree_entry_get_desktop_file_path (entry), + -1, NULL, NULL, NULL); + g_print ("%s\t%s\t%s%s\n", path, gmenu_tree_entry_get_desktop_file_id (entry), - gmenu_tree_entry_get_desktop_file_path (entry), - gmenu_tree_entry_get_is_excluded (entry) ? " " : ""); + utf8_path ? utf8_path : _("[Invalid Filename]"), + gmenu_tree_entry_get_is_excluded (entry) ? _(" ") : ""); + + g_free (utf8_path); } static void @@ -146,12 +154,12 @@ handle_tree_changed (GMenuTree *tree) { GMenuTreeDirectory *root; - g_print ("\n\n\n==== Menu changed, reloading ====\n\n\n"); + g_print (_("\n\n\n==== Menu changed, reloading ====\n\n\n")); root = gmenu_tree_get_root_directory (tree); if (root == NULL) { - g_warning ("Menu tree is empty"); + g_warning (_("Menu tree is empty")); return; } @@ -166,9 +174,14 @@ main (int argc, char **argv) GMenuTree *tree; GMenuTreeDirectory *root; - options_context = g_option_context_new ("- test GNOME's implementation of the Desktop Menu Specification"); + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + options_context = g_option_context_new (_("- test GNOME's implementation of the Desktop Menu Specification")); g_option_context_add_main_entries (options_context, options, GETTEXT_PACKAGE); g_option_context_parse (options_context, &argc, &argv, NULL); + g_option_context_free (options_context); tree = gmenu_tree_lookup (menu_file ? menu_file : "applications.menu", include_excluded ? GMENU_TREE_FLAGS_INCLUDE_EXCLUDED : GMENU_TREE_FLAGS_NONE); @@ -182,7 +195,7 @@ main (int argc, char **argv) } else { - g_warning ("Menu tree is empty"); + g_warning (_("Menu tree is empty")); } if (monitor)