Skip to content

Commit b5495c4

Browse files
committed
entry-directories.c: Monitor mimeinfo.cache file and re-attempt
failed .desktop files when it changes (which is usually just after the .desktop file is added, causing loading to fail due to unavailable GAppInfo). See inline comments.
1 parent 5b8c902 commit b5495c4

File tree

1 file changed

+66
-3
lines changed

1 file changed

+66
-3
lines changed

libmenu/entry-directories.c

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct CachedDir
5757

5858
GSList *entries;
5959
GSList *subdirs;
60+
GSList *retry_later_desktop_entries;
6061

6162
MenuMonitor *dir_monitor;
6263
GSList *monitors;
@@ -161,6 +162,9 @@ cached_dir_free (CachedDir *dir)
161162
g_slist_free (dir->subdirs);
162163
dir->subdirs = NULL;
163164

165+
g_slist_free_full (dir->retry_later_desktop_entries, g_free);
166+
dir->retry_later_desktop_entries = NULL;
167+
164168
g_free (dir->name);
165169
g_free (dir);
166170
}
@@ -317,7 +321,12 @@ cached_dir_add_entry (CachedDir *dir,
317321

318322
entry = desktop_entry_new (path);
319323
if (entry == NULL)
320-
return FALSE;
324+
{
325+
menu_verbose ("Adding %s to the retry list (mimeinfo.cache maybe isn't done getting updated yet\n", path);
326+
327+
dir->retry_later_desktop_entries = g_slist_prepend (dir->retry_later_desktop_entries, g_strdup (path));
328+
return FALSE;
329+
}
321330

322331
dir->entries = g_slist_prepend (dir->entries, entry);
323332

@@ -525,6 +534,8 @@ handle_cached_dir_changed (MenuMonitor *monitor,
525534
CachedDir *dir)
526535
{
527536
gboolean handled = FALSE;
537+
gboolean retry_changes = FALSE;
538+
528539
char *basename;
529540
char *dirname;
530541

@@ -558,6 +569,58 @@ handle_cached_dir_changed (MenuMonitor *monitor,
558569
break;
559570
}
560571
}
572+
else if (g_strcmp0 (basename, "mimeinfo.cache") == 0)
573+
{
574+
/* The observed file notifies when a new desktop file is added
575+
* (but fails to load) go something like:
576+
*
577+
* NOTIFY: foo.desktop
578+
* NOTIFY: mimeinfo.cache.tempfile
579+
* NOTIFY: mimeinfo.cache.tempfile
580+
* NOTIFY: mimeinfo.cache
581+
*
582+
* Additionally, the failure is not upon trying to read the file,
583+
* but attempting to get its GAppInfo (g_desktop_app_info_new_from_filename()
584+
* in desktop-entries.c ln 277). If you jigger desktop_entry_load() around
585+
* and read the file as a keyfile *first*, it succeeds. If you then try
586+
* to run g_desktop_app_info_new_from_keyfile(), *then* it fails.
587+
*
588+
* The theory here is there is a race condition where app info (which includes
589+
* mimetype stuff) is unavailable because mimeinfo.cache is updated immediately
590+
* after the app is installed.
591+
*
592+
* What we do here is, when a desktop fails to load, we add it to a temporary
593+
* list. We wait until mimeinfo.cache changes, then retry that desktop file,
594+
* which succeeds this second time.
595+
*
596+
* Note: An alternative fix (presented more as a proof than a suggestion) is to
597+
* change line 151 in menu-monitor.c to use g_timeout_add_seconds, and delay
598+
* for one second. This also avoids the issue (but it remains a race condition).
599+
*/
600+
601+
GSList *iter;
602+
603+
menu_verbose ("mimeinfo changed, checking for failed entries\n");
604+
605+
for (iter = dir->retry_later_desktop_entries; iter != NULL; iter = iter->next)
606+
{
607+
const gchar *retry_path = iter->data;
608+
609+
menu_verbose ("retrying %s\n", retry_path);
610+
611+
char *retry_basename = g_path_get_basename (retry_path);
612+
613+
if (cached_dir_update_entry (dir, retry_basename, retry_path))
614+
retry_changes = TRUE;
615+
616+
g_free (retry_basename);
617+
}
618+
619+
g_slist_free_full (dir->retry_later_desktop_entries, g_free);
620+
dir->retry_later_desktop_entries = NULL;
621+
622+
handled = retry_changes;
623+
}
561624
else /* Try recursing */
562625
{
563626
switch (event)
@@ -584,8 +647,8 @@ handle_cached_dir_changed (MenuMonitor *monitor,
584647

585648
if (handled)
586649
{
587-
/* CHANGED events don't change the set of desktop entries */
588-
if (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED)
650+
/* CHANGED events don't change the set of desktop entries, unless it's the mimeinfo.cache file changing */
651+
if (retry_changes || (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED))
589652
{
590653
_entry_directory_list_empty_desktop_cache ();
591654
}

0 commit comments

Comments
 (0)