app info: tweak default application algorithm
authorRyan Lortie <desrt@desrt.ca>
Thu, 2 Apr 2015 21:17:35 +0000 (17:17 -0400)
committerRyan Lortie <desrt@desrt.ca>
Wed, 22 Apr 2015 09:52:10 +0000 (10:52 +0100)
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

gio/gdesktopappinfo.c

index 0b34235ce35b7e8f841eb2c94c2ba4740082b709..b2297886f88ad5519c9a5a78de7ec4f4b5c86c23 100644 (file)
@@ -1162,7 +1162,7 @@ desktop_file_dir_unindexed_mime_lookup (DesktopFileDir *dir,
 
           if (!desktop_file_dir_app_name_is_masked (dir, 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];
 
       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++)
       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 ();
 
   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);
 }
 
-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:
  * @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,
                                  gboolean    must_support_uris)
 {
-  gchar **desktop_ids;
+  GPtrArray *blacklist;
+  GPtrArray *results;
   GAppInfo *info;
-  gint i;
+  gchar **types;
+  gint i, j, k;
 
   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;
-  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))
-            break;
-
-          g_object_unref (info);
-          info = NULL;
-        }
-    }
 
-  g_strfreev (desktop_ids);
+  desktop_file_dirs_lock ();
 
-  /* 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)
+  for (i = 0; types[i]; i++)
     {
-      desktop_ids = g_desktop_app_info_get_desktop_ids_for_content_type (content_type, TRUE);
+      /* 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);
 
-      for (i = 0; desktop_ids[i]; i++)
+      /* 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++)
         {
-          info = (GAppInfo *) g_desktop_app_info_new (desktop_ids[i]);
+          const gchar *desktop_id = g_ptr_array_index (results, j);
 
-          if (info)
+          for (k = 0; k < n_desktop_file_dirs; k++)
             {
-              if (!must_support_uris || g_app_info_supports_uris (info))
-                break;
+              info = (GAppInfo *) desktop_file_dir_get_app (&desktop_file_dirs[k], desktop_id);
+
+              if (info)
+                {
+                  if (!must_support_uris || g_app_info_supports_uris (info))
+                    goto out;
 
-              g_object_unref (info);
-              info = NULL;
+                  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;
 }