app info: tweak default application algorithm

Always run the full algorithm for a given mime type before considering
fallback types.

This includes considering installed applications capable of handling a
particular mimetype, even if such an app is not explicitly marked as
default, and there is a default app for a less-specific type.

Specifically, this often helps with cases of installing apps that can
handle a particular subtype of text/plain.  We want to take those apps
in preference to a generic text editor, even if that editor is listed as
the default for text/plain and there is no default listed for the more
specific type.

Because of the more holistic approach taken by the algorithm, it is now
more complicated, but it also means that we can do more work while
holding the lock.  In turn, that lets us avoid duplicating some strings,
which is nice.

https://bugzilla.gnome.org/show_bug.cgi?id=744282
This commit is contained in:
Ryan Lortie 2015-04-02 17:17:35 -04:00
parent cf940b66bc
commit 2bb898c60f

View File

@ -1162,7 +1162,7 @@ desktop_file_dir_unindexed_mime_lookup (DesktopFileDir *dir,
if (!desktop_file_dir_app_name_is_masked (dir, app_name) && if (!desktop_file_dir_app_name_is_masked (dir, app_name) &&
!array_contains (blacklist, app_name) && !array_contains (hits, app_name)) !array_contains (blacklist, app_name) && !array_contains (hits, app_name))
g_ptr_array_add (hits, g_strdup (app_name)); g_ptr_array_add (hits, app_name);
} }
} }
@ -1197,7 +1197,7 @@ desktop_file_dir_unindexed_default_lookup (DesktopFileDir *dir,
gchar *app_name = tweaks->defaults[i]; gchar *app_name = tweaks->defaults[i];
if (!array_contains (results, app_name)) if (!array_contains (results, app_name))
g_ptr_array_add (results, g_strdup (app_name)); g_ptr_array_add (results, app_name);
} }
} }
@ -3838,6 +3838,10 @@ g_desktop_app_info_get_desktop_ids_for_content_type (const gchar *content_type,
for (j = 0; j < n_desktop_file_dirs; j++) for (j = 0; j < n_desktop_file_dirs; j++)
desktop_file_dir_mime_lookup (&desktop_file_dirs[j], types[i], hits, blacklist); desktop_file_dir_mime_lookup (&desktop_file_dirs[j], types[i], hits, blacklist);
/* We will keep the hits past unlocking, so we must dup them */
for (i = 0; i < hits->len; i++)
hits->pdata[i] = g_strdup (hits->pdata[i]);
desktop_file_dirs_unlock (); desktop_file_dirs_unlock ();
g_ptr_array_add (hits, NULL); g_ptr_array_add (hits, NULL);
@ -3848,30 +3852,6 @@ g_desktop_app_info_get_desktop_ids_for_content_type (const gchar *content_type,
return (gchar **) g_ptr_array_free (hits, FALSE); return (gchar **) g_ptr_array_free (hits, FALSE);
} }
static gchar **
g_desktop_app_info_get_defaults_for_content_type (const gchar *content_type)
{
GPtrArray *results;
gchar **types;
gint i, j;
types = get_list_of_mimetypes (content_type, TRUE);
results = g_ptr_array_new ();
desktop_file_dirs_lock ();
for (i = 0; types[i]; i++)
for (j = 0; j < n_desktop_file_dirs; j++)
desktop_file_dir_default_lookup (&desktop_file_dirs[j], types[i], results);
desktop_file_dirs_unlock ();
g_ptr_array_add (results, NULL);
g_strfreev (types);
return (gchar **) g_ptr_array_free (results, FALSE);
}
/** /**
* g_app_info_get_recommended_for_type: * g_app_info_get_recommended_for_type:
* @content_type: the content type to find a #GAppInfo for * @content_type: the content type to find a #GAppInfo for
@ -4039,57 +4019,64 @@ GAppInfo *
g_app_info_get_default_for_type (const char *content_type, g_app_info_get_default_for_type (const char *content_type,
gboolean must_support_uris) gboolean must_support_uris)
{ {
gchar **desktop_ids; GPtrArray *blacklist;
GPtrArray *results;
GAppInfo *info; GAppInfo *info;
gint i; gchar **types;
gint i, j, k;
g_return_val_if_fail (content_type != NULL, NULL); g_return_val_if_fail (content_type != NULL, NULL);
desktop_ids = g_desktop_app_info_get_defaults_for_content_type (content_type); types = get_list_of_mimetypes (content_type, TRUE);
blacklist = g_ptr_array_new ();
results = g_ptr_array_new ();
info = NULL; info = NULL;
for (i = 0; desktop_ids[i]; i++)
desktop_file_dirs_lock ();
for (i = 0; types[i]; i++)
{ {
info = (GAppInfo *) g_desktop_app_info_new (desktop_ids[i]); /* Collect all the default apps for this type */
for (j = 0; j < n_desktop_file_dirs; j++)
desktop_file_dir_default_lookup (&desktop_file_dirs[j], types[i], results);
if (info) /* Consider the associations as well... */
for (j = 0; j < n_desktop_file_dirs; j++)
desktop_file_dir_mime_lookup (&desktop_file_dirs[j], types[i], results, blacklist);
/* (If any), see if one of those apps is installed... */
for (j = 0; j < results->len; j++)
{ {
if (!must_support_uris || g_app_info_supports_uris (info)) const gchar *desktop_id = g_ptr_array_index (results, j);
break;
g_object_unref (info); for (k = 0; k < n_desktop_file_dirs; k++)
info = NULL;
}
}
g_strfreev (desktop_ids);
/* If we can't find a default app for this content type, pick one from
* the list of all supported apps. This will be ordered by the user's
* preference and by "recommended" apps first, so the first one we
* find is probably the best fallback.
*/
if (info == NULL)
{
desktop_ids = g_desktop_app_info_get_desktop_ids_for_content_type (content_type, TRUE);
for (i = 0; desktop_ids[i]; i++)
{
info = (GAppInfo *) g_desktop_app_info_new (desktop_ids[i]);
if (info)
{ {
if (!must_support_uris || g_app_info_supports_uris (info)) info = (GAppInfo *) desktop_file_dir_get_app (&desktop_file_dirs[k], desktop_id);
break;
g_object_unref (info); if (info)
info = NULL; {
if (!must_support_uris || g_app_info_supports_uris (info))
goto out;
g_clear_object (&info);
}
} }
} }
g_strfreev (desktop_ids); /* Reset the list, ready to try again with the next (parent)
* mimetype, but keep the blacklist in place.
*/
g_ptr_array_set_size (results, 0);
} }
out:
desktop_file_dirs_unlock ();
g_ptr_array_unref (blacklist);
g_ptr_array_unref (results);
g_strfreev (types);
return info; return info;
} }