Codebase list cinnamon-menus / b5495c4
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. Michael Webster 7 years ago
1 changed file(s) with 66 addition(s) and 3 deletion(s). Raw diff Collapse all Expand all
5656
5757 GSList *entries;
5858 GSList *subdirs;
59 GSList *retry_later_desktop_entries;
5960
6061 MenuMonitor *dir_monitor;
6162 GSList *monitors;
160161 g_slist_free (dir->subdirs);
161162 dir->subdirs = NULL;
162163
164 g_slist_free_full (dir->retry_later_desktop_entries, g_free);
165 dir->retry_later_desktop_entries = NULL;
166
163167 g_free (dir->name);
164168 g_free (dir);
165169 }
316320
317321 entry = desktop_entry_new (path);
318322 if (entry == NULL)
319 return FALSE;
323 {
324 menu_verbose ("Adding %s to the retry list (mimeinfo.cache maybe isn't done getting updated yet\n", path);
325
326 dir->retry_later_desktop_entries = g_slist_prepend (dir->retry_later_desktop_entries, g_strdup (path));
327 return FALSE;
328 }
320329
321330 dir->entries = g_slist_prepend (dir->entries, entry);
322331
524533 CachedDir *dir)
525534 {
526535 gboolean handled = FALSE;
536 gboolean retry_changes = FALSE;
537
527538 char *basename;
528539 char *dirname;
529540
557568 break;
558569 }
559570 }
571 else if (g_strcmp0 (basename, "mimeinfo.cache") == 0)
572 {
573 /* The observed file notifies when a new desktop file is added
574 * (but fails to load) go something like:
575 *
576 * NOTIFY: foo.desktop
577 * NOTIFY: mimeinfo.cache.tempfile
578 * NOTIFY: mimeinfo.cache.tempfile
579 * NOTIFY: mimeinfo.cache
580 *
581 * Additionally, the failure is not upon trying to read the file,
582 * but attempting to get its GAppInfo (g_desktop_app_info_new_from_filename()
583 * in desktop-entries.c ln 277). If you jigger desktop_entry_load() around
584 * and read the file as a keyfile *first*, it succeeds. If you then try
585 * to run g_desktop_app_info_new_from_keyfile(), *then* it fails.
586 *
587 * The theory here is there is a race condition where app info (which includes
588 * mimetype stuff) is unavailable because mimeinfo.cache is updated immediately
589 * after the app is installed.
590 *
591 * What we do here is, when a desktop fails to load, we add it to a temporary
592 * list. We wait until mimeinfo.cache changes, then retry that desktop file,
593 * which succeeds this second time.
594 *
595 * Note: An alternative fix (presented more as a proof than a suggestion) is to
596 * change line 151 in menu-monitor.c to use g_timeout_add_seconds, and delay
597 * for one second. This also avoids the issue (but it remains a race condition).
598 */
599
600 GSList *iter;
601
602 menu_verbose ("mimeinfo changed, checking for failed entries\n");
603
604 for (iter = dir->retry_later_desktop_entries; iter != NULL; iter = iter->next)
605 {
606 const gchar *retry_path = iter->data;
607
608 menu_verbose ("retrying %s\n", retry_path);
609
610 char *retry_basename = g_path_get_basename (retry_path);
611
612 if (cached_dir_update_entry (dir, retry_basename, retry_path))
613 retry_changes = TRUE;
614
615 g_free (retry_basename);
616 }
617
618 g_slist_free_full (dir->retry_later_desktop_entries, g_free);
619 dir->retry_later_desktop_entries = NULL;
620
621 handled = retry_changes;
622 }
560623 else /* Try recursing */
561624 {
562625 switch (event)
583646
584647 if (handled)
585648 {
586 /* CHANGED events don't change the set of desktop entries */
587 if (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED)
649 /* CHANGED events don't change the set of desktop entries, unless it's the mimeinfo.cache file changing */
650 if (retry_changes || (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED))
588651 {
589652 _entry_directory_list_empty_desktop_cache ();
590653 }