mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 00:12:19 +01:00 
			
		
		
		
	appinfo: add g_app_info_set_as_last_used_for_type()
This commit also changes (maintaining compatibility) the way user-specified default applications are stored (as in, those for which g_app_info_set_as_default_for_type() has been called. We now store the default application for a content type in a new group in the mimeapps.list keyfile, and "Added Associations" tracks only the applications that have been added by the user, following a most-recently-used first order. This is useful in GtkAppChooser-like widgets to pre-select the last used application when constructing a widget. https://bugzilla.gnome.org/show_bug.cgi?id=636311
This commit is contained in:
		| @@ -1256,6 +1256,7 @@ g_app_info_delete | |||||||
| g_app_info_reset_type_associations | g_app_info_reset_type_associations | ||||||
| g_app_info_set_as_default_for_type | g_app_info_set_as_default_for_type | ||||||
| g_app_info_set_as_default_for_extension | g_app_info_set_as_default_for_extension | ||||||
|  | g_app_info_set_as_last_used_for_type | ||||||
| g_app_info_add_supports_type | g_app_info_add_supports_type | ||||||
| g_app_info_can_remove_supports_type | g_app_info_can_remove_supports_type | ||||||
| g_app_info_remove_supports_type | g_app_info_remove_supports_type | ||||||
|   | |||||||
| @@ -308,6 +308,33 @@ g_app_info_set_as_default_for_type (GAppInfo    *appinfo, | |||||||
|   return (* iface->set_as_default_for_type) (appinfo, content_type, error); |   return (* iface->set_as_default_for_type) (appinfo, content_type, error); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * g_app_info_set_as_last_used_for_type: | ||||||
|  |  * @appinfo: a #GAppInfo. | ||||||
|  |  * @content_type: the content type. | ||||||
|  |  * @error: a #GError. | ||||||
|  |  *  | ||||||
|  |  * Sets the application as the last used application for a given type. | ||||||
|  |  * This will make the application appear as first in the list returned by | ||||||
|  |  * #g_app_info_get_recommended_for_type, regardless of the default application | ||||||
|  |  * for that content type. | ||||||
|  |  * | ||||||
|  |  * Returns: %TRUE on success, %FALSE on error. | ||||||
|  |  **/ | ||||||
|  | gboolean | ||||||
|  | g_app_info_set_as_last_used_for_type (GAppInfo    *appinfo, | ||||||
|  |                                       const char  *content_type, | ||||||
|  |                                       GError     **error) | ||||||
|  | { | ||||||
|  |   GAppInfoIface *iface; | ||||||
|  |    | ||||||
|  |   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE); | ||||||
|  |   g_return_val_if_fail (content_type != NULL, FALSE); | ||||||
|  |  | ||||||
|  |   iface = G_APP_INFO_GET_IFACE (appinfo); | ||||||
|  |  | ||||||
|  |   return (* iface->set_as_last_used_for_type) (appinfo, content_type, error); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * g_app_info_set_as_default_for_extension: |  * g_app_info_set_as_default_for_extension: | ||||||
|   | |||||||
| @@ -128,6 +128,9 @@ struct _GAppInfoIface | |||||||
|   gboolean     (* do_delete)                    (GAppInfo           *appinfo); |   gboolean     (* do_delete)                    (GAppInfo           *appinfo); | ||||||
|   const char * (* get_commandline)              (GAppInfo           *appinfo); |   const char * (* get_commandline)              (GAppInfo           *appinfo); | ||||||
|   const char * (* get_display_name)             (GAppInfo           *appinfo); |   const char * (* get_display_name)             (GAppInfo           *appinfo); | ||||||
|  |   gboolean     (* set_as_last_used_for_type)    (GAppInfo           *appinfo, | ||||||
|  |                                                  const char         *content_type, | ||||||
|  |                                                  GError            **error); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| GType       g_app_info_get_type                     (void) G_GNUC_CONST; | GType       g_app_info_get_type                     (void) G_GNUC_CONST; | ||||||
| @@ -173,6 +176,10 @@ gboolean    g_app_info_remove_supports_type         (GAppInfo             *appin | |||||||
| gboolean    g_app_info_can_delete                   (GAppInfo   *appinfo); | gboolean    g_app_info_can_delete                   (GAppInfo   *appinfo); | ||||||
| gboolean    g_app_info_delete                       (GAppInfo   *appinfo); | gboolean    g_app_info_delete                       (GAppInfo   *appinfo); | ||||||
|  |  | ||||||
|  | gboolean    g_app_info_set_as_last_used_for_type    (GAppInfo             *appinfo, | ||||||
|  | 						     const char           *content_type, | ||||||
|  | 						     GError              **error); | ||||||
|  |  | ||||||
| GList *   g_app_info_get_all                     (void); | GList *   g_app_info_get_all                     (void); | ||||||
| GList *   g_app_info_get_all_for_type            (const char  *content_type); | GList *   g_app_info_get_all_for_type            (const char  *content_type); | ||||||
| GList *   g_app_info_get_recommended_for_type    (const gchar *content_type); | GList *   g_app_info_get_recommended_for_type    (const gchar *content_type); | ||||||
|   | |||||||
| @@ -69,7 +69,8 @@ | |||||||
| static void     g_desktop_app_info_iface_init         (GAppInfoIface    *iface); | static void     g_desktop_app_info_iface_init         (GAppInfoIface    *iface); | ||||||
| static GList *  get_all_desktop_entries_for_mime_type (const char       *base_mime_type, | static GList *  get_all_desktop_entries_for_mime_type (const char       *base_mime_type, | ||||||
| 						       const char      **except, | 						       const char      **except, | ||||||
| 						       gboolean          include_fallback); | 						       gboolean          include_fallback, | ||||||
|  |                                                        char            **explicit_default); | ||||||
| static void     mime_info_cache_reload                (const char       *dir); | static void     mime_info_cache_reload                (const char       *dir); | ||||||
| static gboolean g_desktop_app_info_ensure_saved       (GDesktopAppInfo  *info, | static gboolean g_desktop_app_info_ensure_saved       (GDesktopAppInfo  *info, | ||||||
| 						       GError          **error); | 						       GError          **error); | ||||||
| @@ -107,6 +108,14 @@ struct _GDesktopAppInfo | |||||||
|   /* FIXME: what about StartupWMClass ? */ |   /* FIXME: what about StartupWMClass ? */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   UPDATE_MIME_NONE = 1 << 0, | ||||||
|  |   UPDATE_MIME_SET_DEFAULT = 1 << 1, | ||||||
|  |   UPDATE_MIME_SET_NON_DEFAULT = 1 << 2, | ||||||
|  |   UPDATE_MIME_REMOVE = 1 << 3, | ||||||
|  |   UPDATE_MIME_SET_LAST_USED = 1 << 4, | ||||||
|  | } UpdateMimeFlags; | ||||||
|  |  | ||||||
| G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT, | G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT, | ||||||
| 			 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO, | 			 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO, | ||||||
| 						g_desktop_app_info_iface_init)) | 						g_desktop_app_info_iface_init)) | ||||||
| @@ -1169,25 +1178,23 @@ ensure_dir (DirType   type, | |||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| update_mimeapps_list (const char  *desktop_id,  | update_mimeapps_list (const char  *desktop_id,  | ||||||
| 		      const char  *content_type,  | 		      const char  *content_type, | ||||||
| 		      gboolean     add_as_default, |                       UpdateMimeFlags flags, | ||||||
| 		      gboolean     add_non_default, |  | ||||||
| 		      gboolean     remove,  |  | ||||||
| 		      GError     **error) | 		      GError     **error) | ||||||
| { | { | ||||||
|   char *dirname, *filename; |   char *dirname, *filename, *string; | ||||||
|   GKeyFile *key_file; |   GKeyFile *key_file; | ||||||
|   gboolean load_succeeded, res; |   gboolean load_succeeded, res; | ||||||
|   char **old_list, **list; |   char **old_list, **list; | ||||||
|   GList *system_list, *l; |  | ||||||
|   gsize length, data_size; |   gsize length, data_size; | ||||||
|   char *data; |   char *data; | ||||||
|   int i, j, k; |   int i, j, k; | ||||||
|   char **content_types; |   char **content_types; | ||||||
|  |  | ||||||
|   /* Don't add both at start and end */ |   /* Don't add both at start and end */ | ||||||
|   g_assert (!(add_as_default && add_non_default)); |   g_assert (!((flags & UPDATE_MIME_SET_DEFAULT) && | ||||||
|    |               (flags & UPDATE_MIME_SET_NON_DEFAULT))); | ||||||
|  |  | ||||||
|   dirname = ensure_dir (APP_DIR, error); |   dirname = ensure_dir (APP_DIR, error); | ||||||
|   if (!dirname) |   if (!dirname) | ||||||
|     return FALSE; |     return FALSE; | ||||||
| @@ -1211,9 +1218,51 @@ update_mimeapps_list (const char  *desktop_id, | |||||||
|     } |     } | ||||||
|   else |   else | ||||||
|     { |     { | ||||||
|       content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL); |       content_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP, NULL, NULL); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |   for (k = 0; content_types && content_types[k]; k++) | ||||||
|  |     { | ||||||
|  |       /* set as default, if requested so */ | ||||||
|  |       string = g_key_file_get_string (key_file, | ||||||
|  |                                       DEFAULT_APPLICATIONS_GROUP, | ||||||
|  |                                       content_types[k], | ||||||
|  |                                       NULL); | ||||||
|  |  | ||||||
|  |       if (g_strcmp0 (string, desktop_id) != 0 && | ||||||
|  |           (flags & UPDATE_MIME_SET_DEFAULT)) | ||||||
|  |         { | ||||||
|  |           g_free (string); | ||||||
|  |           string = g_strdup (desktop_id); | ||||||
|  |  | ||||||
|  |           /* add in the non-default list too, if it's not already there */ | ||||||
|  |           flags |= UPDATE_MIME_SET_NON_DEFAULT; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       if (string == NULL || desktop_id == NULL) | ||||||
|  |         g_key_file_remove_key (key_file, | ||||||
|  |                                DEFAULT_APPLICATIONS_GROUP, | ||||||
|  |                                content_types[k], | ||||||
|  |                                NULL); | ||||||
|  |       else | ||||||
|  |         g_key_file_set_string (key_file, | ||||||
|  |                                DEFAULT_APPLICATIONS_GROUP, | ||||||
|  |                                content_types[k], | ||||||
|  |                                string); | ||||||
|  |  | ||||||
|  |       g_free (string); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   if (content_type) | ||||||
|  |     { | ||||||
|  |       /* reuse the list from above */ | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       g_strfreev (content_types); | ||||||
|  |       content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL); | ||||||
|  |     } | ||||||
|  |    | ||||||
|   for (k = 0; content_types && content_types[k]; k++) |   for (k = 0; content_types && content_types[k]; k++) | ||||||
|     {  |     {  | ||||||
|       /* Add to the right place in the list */ |       /* Add to the right place in the list */ | ||||||
| @@ -1225,48 +1274,41 @@ update_mimeapps_list (const char  *desktop_id, | |||||||
|       list = g_new (char *, 1 + length + 1); |       list = g_new (char *, 1 + length + 1); | ||||||
|  |  | ||||||
|       i = 0; |       i = 0; | ||||||
|       if (add_as_default) |  | ||||||
|         list[i++] = g_strdup (desktop_id); |       /* if we're adding a last-used hint, just put the application in front of the list */ | ||||||
|  |       if (flags & UPDATE_MIME_SET_LAST_USED) | ||||||
|  |         { | ||||||
|  |           /* avoid adding this again as non-default later */ | ||||||
|  |           if (flags & UPDATE_MIME_SET_NON_DEFAULT) | ||||||
|  |             flags ^= UPDATE_MIME_SET_NON_DEFAULT; | ||||||
|  |  | ||||||
|  |           list[i++] = g_strdup (desktop_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|       if (old_list) |       if (old_list) | ||||||
|         { |         { | ||||||
|           for (j = 0; old_list[j] != NULL; j++) |           for (j = 0; old_list[j] != NULL; j++) | ||||||
| 	    { | 	    { | ||||||
| 	      if (g_strcmp0 (old_list[j], desktop_id) != 0) | 	      if (g_strcmp0 (old_list[j], desktop_id) != 0) | ||||||
| 	        list[i++] = g_strdup (old_list[j]); |                 { | ||||||
| 	      else if (add_non_default) |                   /* rewrite other entries if they're different from the new one */ | ||||||
|  |                   list[i++] = g_strdup (old_list[j]); | ||||||
|  |                 } | ||||||
|  | 	      else if (flags & UPDATE_MIME_SET_NON_DEFAULT) | ||||||
| 		{ | 		{ | ||||||
| 		  /* If adding as non-default, and it's already in, |                   /* we encountered an old entry which is equal to the one we're adding as non-default, | ||||||
| 		     don't change order of desktop ids */ |                    * don't change its position in the list. | ||||||
| 		  add_non_default = FALSE; |                    */ | ||||||
|  | 		  flags ^= UPDATE_MIME_SET_NON_DEFAULT; | ||||||
| 		  list[i++] = g_strdup (old_list[j]); | 		  list[i++] = g_strdup (old_list[j]); | ||||||
| 		} | 		} | ||||||
| 	    } | 	    } | ||||||
|         } |         } | ||||||
|        |  | ||||||
|       if (add_non_default) |  | ||||||
| 	{ |  | ||||||
| 	  /* We're adding as non-default, and it wasn't already in the list, |  | ||||||
| 	     so we add at the end. But to avoid listing the app before the |  | ||||||
| 	     current system default (thus changing the default) we have to |  | ||||||
| 	     add the current list of (not yet listed) apps before it. */ |  | ||||||
|  |  | ||||||
| 	  list[i] = NULL; /* Terminate current list so we can use it */ |       /* add it at the end of the list */ | ||||||
| 	  system_list =  get_all_desktop_entries_for_mime_type (content_type, (const char **)list, FALSE); |       if (flags & UPDATE_MIME_SET_NON_DEFAULT) | ||||||
|  |         list[i++] = g_strdup (desktop_id); | ||||||
|  |  | ||||||
| 	  list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1); |  | ||||||
|  |  | ||||||
| 	  for (l = system_list; l != NULL; l = l->next) |  | ||||||
| 	    { |  | ||||||
| 	      list[i++] = l->data; /* no strdup, taking ownership */ |  | ||||||
| 	      if (g_strcmp0 (l->data, desktop_id) == 0) |  | ||||||
| 		add_non_default = FALSE; |  | ||||||
| 	    } |  | ||||||
| 	  g_list_free (system_list); |  | ||||||
| 		   |  | ||||||
| 	  if (add_non_default) |  | ||||||
| 	    list[i++] = g_strdup (desktop_id); |  | ||||||
| 	} |  | ||||||
|        |  | ||||||
|       list[i] = NULL; |       list[i] = NULL; | ||||||
|    |    | ||||||
|       g_strfreev (old_list); |       g_strfreev (old_list); | ||||||
| @@ -1306,7 +1348,7 @@ update_mimeapps_list (const char  *desktop_id, | |||||||
|       list = g_new (char *, 1 + length + 1); |       list = g_new (char *, 1 + length + 1); | ||||||
|  |  | ||||||
|       i = 0; |       i = 0; | ||||||
|       if (remove) |       if (flags & UPDATE_MIME_REMOVE) | ||||||
|         list[i++] = g_strdup (desktop_id); |         list[i++] = g_strdup (desktop_id); | ||||||
|       if (old_list) |       if (old_list) | ||||||
|         { |         { | ||||||
| @@ -1333,7 +1375,7 @@ update_mimeapps_list (const char  *desktop_id, | |||||||
|  |  | ||||||
|       g_strfreev (list); |       g_strfreev (list); | ||||||
|     } |     } | ||||||
|    |  | ||||||
|   g_strfreev (content_types);   |   g_strfreev (content_types);   | ||||||
|  |  | ||||||
|   data = g_key_file_to_data (key_file, &data_size, error); |   data = g_key_file_to_data (key_file, &data_size, error); | ||||||
| @@ -1349,6 +1391,23 @@ update_mimeapps_list (const char  *desktop_id, | |||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | g_desktop_app_info_set_as_last_used_for_type (GAppInfo    *appinfo, | ||||||
|  |                                               const char  *content_type, | ||||||
|  |                                               GError     **error) | ||||||
|  | { | ||||||
|  |   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo); | ||||||
|  |  | ||||||
|  |   if (!g_desktop_app_info_ensure_saved (info, error)) | ||||||
|  |     return FALSE; | ||||||
|  |  | ||||||
|  |   /* both add support for the content type and set as last used */ | ||||||
|  |   return update_mimeapps_list (info->desktop_id, content_type, | ||||||
|  |                                UPDATE_MIME_SET_NON_DEFAULT | | ||||||
|  |                                UPDATE_MIME_SET_LAST_USED, | ||||||
|  |                                error); | ||||||
|  | } | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| g_desktop_app_info_set_as_default_for_type (GAppInfo    *appinfo, | g_desktop_app_info_set_as_default_for_type (GAppInfo    *appinfo, | ||||||
| 					    const char  *content_type, | 					    const char  *content_type, | ||||||
| @@ -1359,7 +1418,9 @@ g_desktop_app_info_set_as_default_for_type (GAppInfo    *appinfo, | |||||||
|   if (!g_desktop_app_info_ensure_saved (info, error)) |   if (!g_desktop_app_info_ensure_saved (info, error)) | ||||||
|     return FALSE;   |     return FALSE;   | ||||||
|    |    | ||||||
|   return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error); |   return update_mimeapps_list (info->desktop_id, content_type, | ||||||
|  |                                UPDATE_MIME_SET_DEFAULT, | ||||||
|  |                                error); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -1476,7 +1537,9 @@ g_desktop_app_info_add_supports_type (GAppInfo    *appinfo, | |||||||
|   if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error)) |   if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error)) | ||||||
|     return FALSE;   |     return FALSE;   | ||||||
|    |    | ||||||
|   return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error); |   return update_mimeapps_list (info->desktop_id, content_type, | ||||||
|  |                                UPDATE_MIME_SET_NON_DEFAULT, | ||||||
|  |                                error); | ||||||
| } | } | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| @@ -1495,7 +1558,9 @@ g_desktop_app_info_remove_supports_type (GAppInfo    *appinfo, | |||||||
|   if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error)) |   if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error)) | ||||||
|     return FALSE; |     return FALSE; | ||||||
|    |    | ||||||
|   return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error); |   return update_mimeapps_list (info->desktop_id, content_type, | ||||||
|  |                                UPDATE_MIME_REMOVE, | ||||||
|  |                                error); | ||||||
| } | } | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| @@ -1616,7 +1681,9 @@ g_desktop_app_info_delete (GAppInfo *appinfo) | |||||||
|     {  |     {  | ||||||
|       if (g_remove (info->filename) == 0) |       if (g_remove (info->filename) == 0) | ||||||
|         { |         { | ||||||
|           update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL); |           update_mimeapps_list (info->desktop_id, NULL, | ||||||
|  |                                 UPDATE_MIME_NONE, | ||||||
|  |                                 NULL); | ||||||
|  |  | ||||||
|           g_free (info->filename); |           g_free (info->filename); | ||||||
|           info->filename = NULL; |           info->filename = NULL; | ||||||
| @@ -1709,6 +1776,7 @@ g_desktop_app_info_iface_init (GAppInfoIface *iface) | |||||||
|   iface->do_delete = g_desktop_app_info_delete; |   iface->do_delete = g_desktop_app_info_delete; | ||||||
|   iface->get_commandline = g_desktop_app_info_get_commandline; |   iface->get_commandline = g_desktop_app_info_get_commandline; | ||||||
|   iface->get_display_name = g_desktop_app_info_get_display_name; |   iface->get_display_name = g_desktop_app_info_get_display_name; | ||||||
|  |   iface->set_as_last_used_for_type = g_desktop_app_info_set_as_last_used_for_type; | ||||||
| } | } | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| @@ -1731,6 +1799,9 @@ app_info_in_list (GAppInfo *info, | |||||||
|  * Gets a list of recommended #GAppInfos for a given content type, i.e. |  * Gets a list of recommended #GAppInfos for a given content type, i.e. | ||||||
|  * those applications which claim to support the given content type exactly, |  * those applications which claim to support the given content type exactly, | ||||||
|  * and not by MIME type subclassing. |  * and not by MIME type subclassing. | ||||||
|  |  * Note that the first application of the list is the last used one, i.e. | ||||||
|  |  * the last one for which #g_app_info_set_as_last_used_for_type has been | ||||||
|  |  * called. | ||||||
|  * |  * | ||||||
|  * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos |  * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos | ||||||
|  *     for given @content_type or %NULL on error. |  *     for given @content_type or %NULL on error. | ||||||
| @@ -1746,7 +1817,7 @@ g_app_info_get_recommended_for_type (const gchar *content_type) | |||||||
|  |  | ||||||
|   g_return_val_if_fail (content_type != NULL, NULL); |   g_return_val_if_fail (content_type != NULL, NULL); | ||||||
|  |  | ||||||
|   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, FALSE); |   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, FALSE, NULL); | ||||||
|  |  | ||||||
|   infos = NULL; |   infos = NULL; | ||||||
|   for (l = desktop_entries; l != NULL; l = l->next) |   for (l = desktop_entries; l != NULL; l = l->next) | ||||||
| @@ -1765,7 +1836,7 @@ g_app_info_get_recommended_for_type (const gchar *content_type) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|   g_list_free (desktop_entries); |   g_list_free (desktop_entries); | ||||||
|    |  | ||||||
|   return g_list_reverse (infos); |   return g_list_reverse (infos); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1791,7 +1862,7 @@ g_app_info_get_fallback_for_type (const gchar *content_type) | |||||||
|  |  | ||||||
|   g_return_val_if_fail (content_type != NULL, NULL); |   g_return_val_if_fail (content_type != NULL, NULL); | ||||||
|  |  | ||||||
|   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE); |   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE, NULL); | ||||||
|   recommended_infos = g_app_info_get_recommended_for_type (content_type); |   recommended_infos = g_app_info_get_recommended_for_type (content_type); | ||||||
|  |  | ||||||
|   infos = NULL; |   infos = NULL; | ||||||
| @@ -1831,13 +1902,25 @@ g_app_info_get_all_for_type (const char *content_type) | |||||||
| { | { | ||||||
|   GList *desktop_entries, *l; |   GList *desktop_entries, *l; | ||||||
|   GList *infos; |   GList *infos; | ||||||
|  |   char *user_default = NULL; | ||||||
|   GDesktopAppInfo *info; |   GDesktopAppInfo *info; | ||||||
|  |  | ||||||
|   g_return_val_if_fail (content_type != NULL, NULL); |   g_return_val_if_fail (content_type != NULL, NULL); | ||||||
|    |    | ||||||
|   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE); |   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE, &user_default); | ||||||
|  |  | ||||||
|   infos = NULL; |   infos = NULL; | ||||||
|  |  | ||||||
|  |   /* put the user default in front of the list, for compatibility */ | ||||||
|  |   if (user_default != NULL) | ||||||
|  |     { | ||||||
|  |       info = g_desktop_app_info_new (user_default); | ||||||
|  |  | ||||||
|  |       if (info != NULL) | ||||||
|  |         infos = g_list_prepend (infos, info); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   g_free (user_default); | ||||||
|  |  | ||||||
|   for (l = desktop_entries; l != NULL; l = l->next) |   for (l = desktop_entries; l != NULL; l = l->next) | ||||||
|     { |     { | ||||||
|       char *desktop_entry = l->data; |       char *desktop_entry = l->data; | ||||||
| @@ -1872,7 +1955,9 @@ g_app_info_get_all_for_type (const char *content_type) | |||||||
| void | void | ||||||
| g_app_info_reset_type_associations (const char *content_type) | g_app_info_reset_type_associations (const char *content_type) | ||||||
| { | { | ||||||
|   update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL); |   update_mimeapps_list (NULL, content_type, | ||||||
|  |                         UPDATE_MIME_NONE, | ||||||
|  |                         NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -1890,13 +1975,40 @@ g_app_info_get_default_for_type (const char *content_type, | |||||||
| 				 gboolean    must_support_uris) | 				 gboolean    must_support_uris) | ||||||
| { | { | ||||||
|   GList *desktop_entries, *l; |   GList *desktop_entries, *l; | ||||||
|  |   char *user_default = NULL; | ||||||
|   GAppInfo *info; |   GAppInfo *info; | ||||||
|  |  | ||||||
|   g_return_val_if_fail (content_type != NULL, NULL); |   g_return_val_if_fail (content_type != NULL, NULL); | ||||||
|    |    | ||||||
|   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE); |   desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE, &user_default); | ||||||
|  |  | ||||||
|   info = NULL; |   info = NULL; | ||||||
|  |  | ||||||
|  |   if (user_default != NULL) | ||||||
|  |     { | ||||||
|  |       info = (GAppInfo *) g_desktop_app_info_new (user_default); | ||||||
|  |  | ||||||
|  |       if (info) | ||||||
|  |         { | ||||||
|  | 	  if (must_support_uris && !g_app_info_supports_uris (info)) | ||||||
|  | 	    { | ||||||
|  | 	      g_object_unref (info); | ||||||
|  | 	      info = NULL; | ||||||
|  | 	    } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   g_free (user_default); | ||||||
|  |  | ||||||
|  |   if (info != NULL) | ||||||
|  |     { | ||||||
|  |       g_list_free_full (desktop_entries, g_free); | ||||||
|  |       return info; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   /* pick the first from the other list that matches our URI | ||||||
|  |    * requirements. | ||||||
|  |    */ | ||||||
|   for (l = desktop_entries; l != NULL; l = l->next) |   for (l = desktop_entries; l != NULL; l = l->next) | ||||||
|     { |     { | ||||||
|       char *desktop_entry = l->data; |       char *desktop_entry = l->data; | ||||||
| @@ -1914,9 +2026,8 @@ g_app_info_get_default_for_type (const char *content_type, | |||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|    |    | ||||||
|   g_list_foreach  (desktop_entries, (GFunc)g_free, NULL); |   g_list_free_full (desktop_entries, g_free); | ||||||
|   g_list_free (desktop_entries); |  | ||||||
|    |  | ||||||
|   return info; |   return info; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -2066,6 +2177,7 @@ typedef struct { | |||||||
|   GHashTable *defaults_list_map; |   GHashTable *defaults_list_map; | ||||||
|   GHashTable *mimeapps_list_added_map; |   GHashTable *mimeapps_list_added_map; | ||||||
|   GHashTable *mimeapps_list_removed_map; |   GHashTable *mimeapps_list_removed_map; | ||||||
|  |   GHashTable *mimeapps_list_defaults_map; | ||||||
|   time_t mime_info_cache_timestamp; |   time_t mime_info_cache_timestamp; | ||||||
|   time_t defaults_list_timestamp; |   time_t defaults_list_timestamp; | ||||||
|   time_t mimeapps_list_timestamp; |   time_t mimeapps_list_timestamp; | ||||||
| @@ -2318,6 +2430,7 @@ mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir) | |||||||
|   gchar *filename, **mime_types; |   gchar *filename, **mime_types; | ||||||
|   char *unaliased_type; |   char *unaliased_type; | ||||||
|   char **desktop_file_ids; |   char **desktop_file_ids; | ||||||
|  |   char *desktop_id; | ||||||
|   int i; |   int i; | ||||||
|   struct stat buf; |   struct stat buf; | ||||||
|  |  | ||||||
| @@ -2339,6 +2452,11 @@ mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir) | |||||||
|   dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal, |   dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal, | ||||||
| 							  g_free, (GDestroyNotify)g_strfreev); | 							  g_free, (GDestroyNotify)g_strfreev); | ||||||
|  |  | ||||||
|  |   if (dir->mimeapps_list_defaults_map != NULL) | ||||||
|  |     g_hash_table_destroy (dir->mimeapps_list_defaults_map); | ||||||
|  |   dir->mimeapps_list_defaults_map = g_hash_table_new_full (g_str_hash, g_str_equal, | ||||||
|  |                                                            g_free, g_free); | ||||||
|  |  | ||||||
|   key_file = g_key_file_new (); |   key_file = g_key_file_new (); | ||||||
|    |    | ||||||
|   filename = g_build_filename (dir->path, "mimeapps.list", NULL); |   filename = g_build_filename (dir->path, "mimeapps.list", NULL); | ||||||
| @@ -2403,6 +2521,28 @@ mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir) | |||||||
|       g_strfreev (mime_types); |       g_strfreev (mime_types); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |   mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP, | ||||||
|  |                                     NULL, NULL); | ||||||
|  |   if (mime_types != NULL) | ||||||
|  |     { | ||||||
|  |       for (i = 0; mime_types[i] != NULL; i++) | ||||||
|  |         { | ||||||
|  |           desktop_id = g_key_file_get_string (key_file, | ||||||
|  |                                               DEFAULT_APPLICATIONS_GROUP, | ||||||
|  |                                               mime_types[i], | ||||||
|  |                                               NULL); | ||||||
|  |           if (desktop_id == NULL) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |           unaliased_type = _g_unix_content_type_unalias (mime_types[i]); | ||||||
|  |           g_hash_table_replace (dir->mimeapps_list_defaults_map, | ||||||
|  |                                 unaliased_type, | ||||||
|  |                                 desktop_id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       g_strfreev (mime_types); | ||||||
|  |     } | ||||||
|  |  | ||||||
|   g_key_file_free (key_file); |   g_key_file_free (key_file); | ||||||
|   return; |   return; | ||||||
|    |    | ||||||
| @@ -2458,7 +2598,13 @@ mime_info_cache_dir_free (MimeInfoCacheDir *dir) | |||||||
|       g_hash_table_destroy (dir->mimeapps_list_removed_map); |       g_hash_table_destroy (dir->mimeapps_list_removed_map); | ||||||
|       dir->mimeapps_list_removed_map = NULL; |       dir->mimeapps_list_removed_map = NULL; | ||||||
|     } |     } | ||||||
|    |  | ||||||
|  |   if (dir->mimeapps_list_defaults_map != NULL) | ||||||
|  |     { | ||||||
|  |       g_hash_table_destroy (dir->mimeapps_list_defaults_map); | ||||||
|  |       dir->mimeapps_list_defaults_map = NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|   g_free (dir); |   g_free (dir); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -2635,13 +2781,15 @@ append_desktop_entry (GList      *list, | |||||||
|  *    to handle @mime_type. |  *    to handle @mime_type. | ||||||
|  */ |  */ | ||||||
| static GList * | static GList * | ||||||
| get_all_desktop_entries_for_mime_type (const char *base_mime_type, | get_all_desktop_entries_for_mime_type (const char  *base_mime_type, | ||||||
| 				       const char **except, | 				       const char **except, | ||||||
| 				       gboolean include_fallback) | 				       gboolean     include_fallback, | ||||||
|  |                                        char       **explicit_default) | ||||||
| { | { | ||||||
|   GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp; |   GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp; | ||||||
|   MimeInfoCacheDir *dir; |   MimeInfoCacheDir *dir; | ||||||
|   char *mime_type; |   char *mime_type, *default_entry = NULL; | ||||||
|  |   const char *entry; | ||||||
|   char **mime_types; |   char **mime_types; | ||||||
|   char **default_entries; |   char **default_entries; | ||||||
|   char **removed_associations; |   char **removed_associations; | ||||||
| @@ -2696,17 +2844,27 @@ get_all_desktop_entries_for_mime_type (const char *base_mime_type, | |||||||
|     { |     { | ||||||
|       mime_type = mime_types[i]; |       mime_type = mime_types[i]; | ||||||
|  |  | ||||||
|       /* Go through all apps listed as defaults */ |       /* Go through all apps listed in user and system dirs */ | ||||||
|       for (dir_list = mime_info_cache->dirs; |       for (dir_list = mime_info_cache->dirs; | ||||||
| 	   dir_list != NULL; | 	   dir_list != NULL; | ||||||
| 	   dir_list = dir_list->next) | 	   dir_list = dir_list->next) | ||||||
| 	{ | 	{ | ||||||
| 	  dir = dir_list->data; | 	  dir = dir_list->data; | ||||||
|  |  | ||||||
| 	  /* First added associations from mimeapps.list */ |           /* Pick the explicit default application */ | ||||||
|  |           entry = g_hash_table_lookup (dir->mimeapps_list_defaults_map, mime_type); | ||||||
|  |  | ||||||
|  |           if (entry != NULL) | ||||||
|  |             { | ||||||
|  |               /* Save the default entry if it's the first one we encounter */ | ||||||
|  |               if (default_entry == NULL) | ||||||
|  |                 default_entry = g_strdup (entry); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  | 	  /* Then added associations from mimeapps.list */ | ||||||
| 	  default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type); | 	  default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type); | ||||||
| 	  for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++) | 	  for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++) | ||||||
| 	    desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries); |             desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries); | ||||||
|  |  | ||||||
| 	  /* Then removed associations from mimeapps.list */ | 	  /* Then removed associations from mimeapps.list */ | ||||||
| 	  removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type); | 	  removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type); | ||||||
| @@ -2736,9 +2894,14 @@ get_all_desktop_entries_for_mime_type (const char *base_mime_type, | |||||||
|  |  | ||||||
|   g_strfreev (mime_types); |   g_strfreev (mime_types); | ||||||
|  |  | ||||||
|  |   if (explicit_default != NULL) | ||||||
|  |     *explicit_default = default_entry; | ||||||
|  |   else | ||||||
|  |     g_free (default_entry); | ||||||
|  |  | ||||||
|   g_list_foreach (removed_entries, (GFunc)g_free, NULL); |   g_list_foreach (removed_entries, (GFunc)g_free, NULL); | ||||||
|   g_list_free (removed_entries); |   g_list_free (removed_entries); | ||||||
|    |  | ||||||
|   desktop_entries = g_list_reverse (desktop_entries); |   desktop_entries = g_list_reverse (desktop_entries); | ||||||
|    |    | ||||||
|   return desktop_entries; |   return desktop_entries; | ||||||
|   | |||||||
| @@ -84,6 +84,7 @@ g_app_info_launch_uris | |||||||
| g_app_info_should_show | g_app_info_should_show | ||||||
| g_app_info_set_as_default_for_type | g_app_info_set_as_default_for_type | ||||||
| g_app_info_set_as_default_for_extension | g_app_info_set_as_default_for_extension | ||||||
|  | g_app_info_set_as_last_used_for_type | ||||||
| g_app_info_add_supports_type | g_app_info_add_supports_type | ||||||
| g_app_info_can_remove_supports_type | g_app_info_can_remove_supports_type | ||||||
| g_app_info_remove_supports_type | g_app_info_remove_supports_type | ||||||
|   | |||||||
| @@ -242,6 +242,56 @@ test_fallback (void) | |||||||
|   g_object_unref (info2); |   g_object_unref (info2); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | test_last_used (void) | ||||||
|  | { | ||||||
|  |   GList *applications; | ||||||
|  |   GAppInfo *info1, *info2, *default_app; | ||||||
|  |   GError *error = NULL; | ||||||
|  |  | ||||||
|  |   info1 = create_app_info ("Test1"); | ||||||
|  |   info2 = create_app_info ("Test2"); | ||||||
|  |  | ||||||
|  |   g_app_info_set_as_default_for_type (info1, "application/x-test", &error); | ||||||
|  |   g_assert (error == NULL); | ||||||
|  |  | ||||||
|  |   g_app_info_add_supports_type (info2, "application/x-test", &error); | ||||||
|  |   g_assert (error == NULL); | ||||||
|  |  | ||||||
|  |   applications = g_app_info_get_recommended_for_type ("application/x-test"); | ||||||
|  |   g_assert (g_list_length (applications) == 2); | ||||||
|  |  | ||||||
|  |   /* the first should be the default app now */ | ||||||
|  |   g_assert (g_app_info_equal (g_list_nth_data (applications, 0), info1)); | ||||||
|  |   g_assert (g_app_info_equal (g_list_nth_data (applications, 1), info2)); | ||||||
|  |  | ||||||
|  |   g_list_free_full (applications, g_object_unref); | ||||||
|  |  | ||||||
|  |   g_app_info_set_as_last_used_for_type (info2, "application/x-test", &error); | ||||||
|  |   g_assert (error == NULL); | ||||||
|  |  | ||||||
|  |   applications = g_app_info_get_recommended_for_type ("application/x-test"); | ||||||
|  |   g_assert (g_list_length (applications) == 2); | ||||||
|  |  | ||||||
|  |   default_app = g_app_info_get_default_for_type ("application/x-test", FALSE); | ||||||
|  |   g_assert (g_app_info_equal (default_app, info1)); | ||||||
|  |  | ||||||
|  |   /* the first should be the other app now */ | ||||||
|  |   g_assert (g_app_info_equal (g_list_nth_data (applications, 0), info2)); | ||||||
|  |   g_assert (g_app_info_equal (g_list_nth_data (applications, 1), info1)); | ||||||
|  |  | ||||||
|  |   g_list_free_full (applications, g_object_unref); | ||||||
|  |  | ||||||
|  |   g_app_info_reset_type_associations ("application/x-test"); | ||||||
|  |  | ||||||
|  |   g_app_info_delete (info1); | ||||||
|  |   g_app_info_delete (info2); | ||||||
|  |  | ||||||
|  |   g_object_unref (info1); | ||||||
|  |   g_object_unref (info2); | ||||||
|  |   g_object_unref (default_app); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| cleanup_dir_recurse (GFile *parent, GFile *root) | cleanup_dir_recurse (GFile *parent, GFile *root) | ||||||
| { | { | ||||||
| @@ -319,6 +369,7 @@ main (int   argc, | |||||||
|   g_test_add_func ("/desktop-app-info/delete", test_delete); |   g_test_add_func ("/desktop-app-info/delete", test_delete); | ||||||
|   g_test_add_func ("/desktop-app-info/default", test_default); |   g_test_add_func ("/desktop-app-info/default", test_default); | ||||||
|   g_test_add_func ("/desktop-app-info/fallback", test_fallback); |   g_test_add_func ("/desktop-app-info/fallback", test_fallback); | ||||||
|  |   g_test_add_func ("/desktop-app-info/lastused", test_last_used); | ||||||
|  |  | ||||||
|   result = g_test_run (); |   result = g_test_run (); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user