@@ -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