Ejemplo n.º 1
0
static void
cached_dir_unref (CachedDir *dir)
{
  if (--dir->references == 0)
    {
      CachedDir *parent;

      parent = dir->parent;

      if (parent != NULL)
        cached_dir_remove_subdir (parent, dir->name);

      if (dir->notify)
        dir->notify (dir, dir->notify_data);

      cached_dir_free (dir);
    }
}
static void
cached_dir_unref (CachedDir *dir)
{
  gboolean is_zero;

  is_zero = g_atomic_int_dec_and_test (&dir->references);
  if (is_zero)
    {
      CachedDir *parent;

      parent = dir->parent;

      if (parent != NULL)
        cached_dir_remove_subdir (parent, dir->name);

      if (dir->notify)
        dir->notify (dir, dir->notify_data);

      cached_dir_free (dir);
    }
}
static void
handle_cached_dir_changed (MenuMonitor      *monitor,
			   MenuMonitorEvent  event,
			   const char       *path,
                           CachedDir        *dir)
{
  gboolean  handled = FALSE;
  char     *basename;
  char     *dirname;

  menu_verbose ("'%s' notified of '%s' %s - invalidating cache\n",
		dir->name,
                path,
                event == MENU_MONITOR_EVENT_CREATED ? ("created") :
                event == MENU_MONITOR_EVENT_DELETED ? ("deleted") : ("changed"));

  dirname  = g_path_get_dirname  (path);
  basename = g_path_get_basename (path);

  dir = cached_dir_lookup (dirname);

  if (g_str_has_suffix (basename, ".desktop") ||
      g_str_has_suffix (basename, ".directory"))
    {
      switch (event)
        {
        case MENU_MONITOR_EVENT_CREATED:
        case MENU_MONITOR_EVENT_CHANGED:
          handled = cached_dir_update_entry (dir, basename, path);
          break;

        case MENU_MONITOR_EVENT_DELETED:
          handled = cached_dir_remove_entry (dir, basename);
          break;

        default:
          g_assert_not_reached ();
          break;
        }
    }
  else /* Try recursing */
    {
      switch (event)
        {
        case MENU_MONITOR_EVENT_CREATED:
          handled = cached_dir_add_subdir (dir, basename, path) != NULL;
          break;

        case MENU_MONITOR_EVENT_CHANGED:
          break;

        case MENU_MONITOR_EVENT_DELETED:
          handled = cached_dir_remove_subdir (dir, basename);
          break;

        default:
          g_assert_not_reached ();
          break;
        }
    }

  g_free (basename);
  g_free (dirname);

  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_queue_monitor_event (dir);
    }
}
Ejemplo n.º 4
0
static void
handle_cached_dir_changed (MenuMonitor      *monitor,
			   MenuMonitorEvent  event,
			   const char       *path,
                           CachedDir        *dir)
{
  gboolean  handled = FALSE;
  gboolean  retry_changes = FALSE;

  char     *basename;
  char     *dirname;

  dirname  = g_path_get_dirname  (path);
  basename = g_path_get_basename (path);

  dir = cached_dir_lookup (dirname);
  cached_dir_add_reference (dir);

  if (g_str_has_suffix (basename, ".desktop") ||
      g_str_has_suffix (basename, ".directory"))
    {
      switch (event)
        {
        case MENU_MONITOR_EVENT_CREATED:
        case MENU_MONITOR_EVENT_CHANGED:
          handled = cached_dir_update_entry (dir, basename, path);
          break;

        case MENU_MONITOR_EVENT_DELETED:
          handled = cached_dir_remove_entry (dir, basename);
          break;

        default:
          g_assert_not_reached ();
          break;
        }
    }
  else if (g_strcmp0 (basename, "mimeinfo.cache") == 0)
    {
        /* The observed file notifies when a new desktop file is added
         * (but fails to load) go something like:
         *
         * NOTIFY: foo.desktop
         * NOTIFY: mimeinfo.cache.tempfile
         * NOTIFY: mimeinfo.cache.tempfile
         * NOTIFY: mimeinfo.cache
         *
         * Additionally, the failure is not upon trying to read the file,
         * but attempting to get its GAppInfo (g_desktop_app_info_new_from_filename()
         * in desktop-entries.c ln 277).  If you jigger desktop_entry_load() around
         * and read the file as a keyfile *first*, it succeeds.  If you then try
         * to run g_desktop_app_info_new_from_keyfile(), *then* it fails.
         *
         * The theory here is there is a race condition where app info (which includes
         * mimetype stuff) is unavailable because mimeinfo.cache is updated immediately
         * after the app is installed.
         *
         * What we do here is, when a desktop fails to load, we add it to a temporary
         * list.  We wait until mimeinfo.cache changes, then retry that desktop file,
         * which succeeds this second time.
         *
         * Note: An alternative fix (presented more as a proof than a suggestion) is to
         * change line 151 in menu-monitor.c to use g_timeout_add_seconds, and delay
         * for one second.  This also avoids the issue (but it remains a race condition).
         */

        GSList *iter;

        menu_verbose ("mimeinfo changed, checking for failed entries\n");

        for (iter = dir->retry_later_desktop_entries; iter != NULL; iter = iter->next)
          {
            const gchar *retry_path = iter->data;

            menu_verbose ("retrying %s\n", retry_path);

            char *retry_basename = g_path_get_basename (retry_path);

            if (cached_dir_update_entry (dir, retry_basename, retry_path))
              retry_changes = TRUE;

            g_free (retry_basename);
          }

        g_slist_free_full (dir->retry_later_desktop_entries, g_free);
        dir->retry_later_desktop_entries = NULL;

        handled = retry_changes;
    }
  else /* Try recursing */
    {
      switch (event)
        {
        case MENU_MONITOR_EVENT_CREATED:
          handled = cached_dir_add_subdir (dir, basename, path) != NULL;
          break;

        case MENU_MONITOR_EVENT_CHANGED:
          break;

        case MENU_MONITOR_EVENT_DELETED:
          handled = cached_dir_remove_subdir (dir, basename);
          break;

        default:
          g_assert_not_reached ();
          break;
        }
    }

  g_free (basename);
  g_free (dirname);

  if (handled)
    {
      menu_verbose ("'%s' notified of '%s' %s - invalidating cache\n",
                    dir->name,
                    path,
                    event == MENU_MONITOR_EVENT_CREATED ? ("created") :
                    event == MENU_MONITOR_EVENT_DELETED ? ("deleted") : ("changed"));

      /* CHANGED events don't change the set of desktop entries, unless it's the mimeinfo.cache file changing */
      if (retry_changes || (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED))
        {
          _entry_directory_list_empty_desktop_cache ();
        }

      cached_dir_queue_monitor_event (dir);
    }

  cached_dir_remove_reference (dir);
}