1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright © 2007 Ryan Lortie
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Author: Alexander Larsson <alexl@redhat.com>
31 #ifdef HAVE_CRT_EXTERNS_H
32 #include <crt_externs.h>
35 #include "gcontenttypeprivate.h"
36 #include "gdesktopappinfo.h"
39 #include "gthemedicon.h"
40 #include "gfileicon.h"
41 #include <glib/gstdio.h>
43 #include "giomodule-priv.h"
49 * SECTION:gdesktopappinfo
50 * @short_description: Application information from desktop files
51 * @include: gio/gdesktopappinfo.h
53 * #GDesktopAppInfo is an implementation of #GAppInfo based on
56 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
57 * the UNIX-specific GIO interfaces, thus you have to use the
58 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
61 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
62 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
63 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
64 #define MIME_CACHE_GROUP "MIME Cache"
66 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
67 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
69 static void mime_info_cache_reload (const char *dir);
70 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
76 * Information about an installed application from a desktop file.
78 struct _GDesktopAppInfo
80 GObject parent_instance;
86 /* FIXME: what about GenericName ? */
100 guint startup_notify : 1;
102 /* FIXME: what about StartupWMClass ? */
105 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
106 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
107 g_desktop_app_info_iface_init))
110 search_path_init (gpointer data)
113 const char * const *data_dirs;
114 const char *user_data_dir;
117 data_dirs = g_get_system_data_dirs ();
118 length = g_strv_length ((char **) data_dirs);
120 args = g_new (char *, length + 2);
123 user_data_dir = g_get_user_data_dir ();
124 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
125 for (i = 0; i < length; i++)
126 args[j++] = g_build_filename (data_dirs[i],
127 "applications", NULL);
133 static const char * const *
134 get_applications_search_path (void)
136 static GOnce once_init = G_ONCE_INIT;
137 return g_once (&once_init, search_path_init, NULL);
141 g_desktop_app_info_finalize (GObject *object)
143 GDesktopAppInfo *info;
145 info = G_DESKTOP_APP_INFO (object);
147 g_free (info->desktop_id);
148 g_free (info->filename);
150 g_free (info->comment);
151 g_free (info->icon_name);
153 g_object_unref (info->icon);
154 g_strfreev (info->only_show_in);
155 g_strfreev (info->not_show_in);
156 g_free (info->try_exec);
158 g_free (info->binary);
161 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
165 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
167 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
169 gobject_class->finalize = g_desktop_app_info_finalize;
173 g_desktop_app_info_init (GDesktopAppInfo *local)
178 binary_from_exec (const char *exec)
180 const char *p, *start;
186 while (*p != ' ' && *p != 0)
189 return g_strndup (start, p - start);
194 * g_desktop_app_info_new_from_keyfile:
195 * @key_file: an opened #GKeyFile
197 * Creates a new #GDesktopAppInfo.
199 * Returns: a new #GDesktopAppInfo or %NULL on error.
204 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
206 GDesktopAppInfo *info;
211 start_group = g_key_file_get_start_group (key_file);
212 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
214 g_free (start_group);
217 g_free (start_group);
219 type = g_key_file_get_string (key_file,
220 G_KEY_FILE_DESKTOP_GROUP,
221 G_KEY_FILE_DESKTOP_KEY_TYPE,
223 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
230 try_exec = g_key_file_get_string (key_file,
231 G_KEY_FILE_DESKTOP_GROUP,
232 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
234 if (try_exec && try_exec[0] != '\0')
237 t = g_find_program_in_path (try_exec);
246 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
247 info->filename = NULL;
249 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
250 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
251 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
252 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
253 info->only_show_in = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, NULL, NULL);
254 info->not_show_in = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, NULL, NULL);
255 info->try_exec = try_exec;
256 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
257 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
258 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
259 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
260 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
261 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
266 if (g_path_is_absolute (info->icon_name))
270 file = g_file_new_for_path (info->icon_name);
271 info->icon = g_file_icon_new (file);
272 g_object_unref (file);
278 /* Work around a common mistake in desktop files */
279 if ((p = strrchr (info->icon_name, '.')) != NULL &&
280 (strcmp (p, ".png") == 0 ||
281 strcmp (p, ".xpm") == 0 ||
282 strcmp (p, ".svg") == 0))
285 info->icon = g_themed_icon_new (info->icon_name);
290 info->binary = binary_from_exec (info->exec);
292 if (info->path && info->path[0] == '\0')
302 * g_desktop_app_info_new_from_filename:
303 * @filename: the path of a desktop file, in the GLib filename encoding
305 * Creates a new #GDesktopAppInfo.
307 * Returns: a new #GDesktopAppInfo or %NULL on error.
310 g_desktop_app_info_new_from_filename (const char *filename)
313 GDesktopAppInfo *info = NULL;
315 key_file = g_key_file_new ();
317 if (g_key_file_load_from_file (key_file,
322 info = g_desktop_app_info_new_from_keyfile (key_file);
324 info->filename = g_strdup (filename);
327 g_key_file_free (key_file);
333 * g_desktop_app_info_new:
334 * @desktop_id: the desktop file id
336 * Creates a new #GDesktopAppInfo based on a desktop file id.
338 * A desktop file id is the basename of the desktop file, including the
339 * .desktop extension. GIO is looking for a desktop file with this name
340 * in the <filename>applications</filename> subdirectories of the XDG data
341 * directories (i.e. the directories specified in the
342 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
343 * variables). GIO also supports the prefix-to-subdirectory mapping that is
344 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
345 * (i.e. a desktop id of kde-foo.desktop will match
346 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
348 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
351 g_desktop_app_info_new (const char *desktop_id)
353 GDesktopAppInfo *appinfo;
354 const char * const *dirs;
358 dirs = get_applications_search_path ();
360 basename = g_strdup (desktop_id);
362 for (i = 0; dirs[i] != NULL; i++)
367 filename = g_build_filename (dirs[i], desktop_id, NULL);
368 appinfo = g_desktop_app_info_new_from_filename (filename);
374 while ((p = strchr (p, '-')) != NULL)
378 filename = g_build_filename (dirs[i], basename, NULL);
379 appinfo = g_desktop_app_info_new_from_filename (filename);
394 appinfo->desktop_id = g_strdup (desktop_id);
396 if (g_desktop_app_info_get_is_hidden (appinfo))
398 g_object_unref (appinfo);
406 g_desktop_app_info_dup (GAppInfo *appinfo)
408 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
409 GDesktopAppInfo *new_info;
411 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
413 new_info->filename = g_strdup (info->filename);
414 new_info->desktop_id = g_strdup (info->desktop_id);
416 new_info->name = g_strdup (info->name);
417 new_info->comment = g_strdup (info->comment);
418 new_info->nodisplay = info->nodisplay;
419 new_info->icon_name = g_strdup (info->icon_name);
421 new_info->icon = g_object_ref (info->icon);
422 new_info->only_show_in = g_strdupv (info->only_show_in);
423 new_info->not_show_in = g_strdupv (info->not_show_in);
424 new_info->try_exec = g_strdup (info->try_exec);
425 new_info->exec = g_strdup (info->exec);
426 new_info->binary = g_strdup (info->binary);
427 new_info->path = g_strdup (info->path);
428 new_info->hidden = info->hidden;
429 new_info->terminal = info->terminal;
430 new_info->startup_notify = info->startup_notify;
432 return G_APP_INFO (new_info);
436 g_desktop_app_info_equal (GAppInfo *appinfo1,
439 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
440 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
442 if (info1->desktop_id == NULL ||
443 info2->desktop_id == NULL)
444 return info1 == info2;
446 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
450 g_desktop_app_info_get_id (GAppInfo *appinfo)
452 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
454 return info->desktop_id;
458 g_desktop_app_info_get_name (GAppInfo *appinfo)
460 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
462 if (info->name == NULL)
468 * g_desktop_app_info_get_is_hidden:
469 * @info: a #GDesktopAppInfo.
471 * A desktop file is hidden if the Hidden key in it is
474 * Returns: %TRUE if hidden, %FALSE otherwise.
477 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
483 g_desktop_app_info_get_description (GAppInfo *appinfo)
485 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
487 return info->comment;
491 g_desktop_app_info_get_executable (GAppInfo *appinfo)
493 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
499 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
501 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
507 g_desktop_app_info_get_icon (GAppInfo *appinfo)
509 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
515 expand_macro_single (char macro, char *uri)
521 file = g_file_new_for_uri (uri);
522 path = g_file_get_path (file);
523 g_object_unref (file);
529 result = g_shell_quote (uri);
534 result = g_shell_quote (path);
540 name = g_path_get_dirname (path);
541 result = g_shell_quote (name);
549 name = g_path_get_basename (path);
550 result = g_shell_quote (name);
562 expand_macro (char macro,
564 GDesktopAppInfo *info,
567 GList *uris = *uri_list;
569 gboolean force_file_uri;
570 char force_file_uri_macro;
573 g_return_if_fail (exec != NULL);
575 /* On %u and %U, pass POSIX file path pointing to the URI via
576 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
577 * running or the URI doesn't have a POSIX file path via FUSE
578 * we'll just pass the URI.
580 force_file_uri_macro = macro;
581 force_file_uri = FALSE;
587 force_file_uri_macro = 'f';
588 force_file_uri = TRUE;
591 force_file_uri_macro = 'F';
592 force_file_uri = TRUE;
608 if (!force_file_uri ||
609 /* Pass URI if it contains an anchor */
610 strchr (uri, '#') != NULL)
612 expanded = expand_macro_single (macro, uri);
616 expanded = expand_macro_single (force_file_uri_macro, uri);
617 if (expanded == NULL)
618 expanded = expand_macro_single (macro, uri);
623 g_string_append (exec, expanded);
639 if (!force_file_uri ||
640 /* Pass URI if it contains an anchor */
641 strchr (uri, '#') != NULL)
643 expanded = expand_macro_single (macro, uri);
647 expanded = expand_macro_single (force_file_uri_macro, uri);
648 if (expanded == NULL)
649 expanded = expand_macro_single (macro, uri);
654 g_string_append (exec, expanded);
660 if (uris != NULL && expanded)
661 g_string_append_c (exec, ' ');
669 g_string_append (exec, "--icon ");
670 g_string_append (exec, info->icon_name);
676 g_string_append (exec, info->name);
681 g_string_append (exec, info->filename);
684 case 'm': /* deprecated */
688 g_string_append_c (exec, '%');
696 expand_application_parameters (GDesktopAppInfo *info,
702 GList *uri_list = *uris;
703 const char *p = info->exec;
704 GString *expanded_exec = g_string_new (NULL);
707 if (info->exec == NULL)
709 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
710 _("Desktop file didn't specify Exec field"));
716 if (p[0] == '%' && p[1] != '\0')
718 expand_macro (p[1], expanded_exec, info, uris);
722 g_string_append_c (expanded_exec, *p);
727 /* No file substitutions */
728 if (uri_list == *uris && uri_list != NULL)
730 /* If there is no macro default to %f. This is also what KDE does */
731 g_string_append_c (expanded_exec, ' ');
732 expand_macro ('f', expanded_exec, info, uris);
735 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
736 g_string_free (expanded_exec, TRUE);
741 prepend_terminal_to_vector (int *argc,
748 char **term_argv = NULL;
753 g_return_val_if_fail (argc != NULL, FALSE);
754 g_return_val_if_fail (argv != NULL, FALSE);
762 /* compute size if not given */
765 for (i = 0; the_argv[i] != NULL; i++)
771 term_argv = g_new0 (char *, 3);
773 check = g_find_program_in_path ("gnome-terminal");
776 term_argv[0] = check;
777 /* Note that gnome-terminal takes -x and
778 * as -e in gnome-terminal is broken we use that. */
779 term_argv[1] = g_strdup ("-x");
784 check = g_find_program_in_path ("nxterm");
786 check = g_find_program_in_path ("color-xterm");
788 check = g_find_program_in_path ("rxvt");
790 check = g_find_program_in_path ("xterm");
792 check = g_find_program_in_path ("dtterm");
795 check = g_strdup ("xterm");
796 g_warning ("couldn't find a terminal, falling back to xterm");
798 term_argv[0] = check;
799 term_argv[1] = g_strdup ("-e");
802 real_argc = term_argc + *argc;
803 real_argv = g_new (char *, real_argc + 1);
805 for (i = 0; i < term_argc; i++)
806 real_argv[i] = term_argv[i];
808 for (j = 0; j < *argc; j++, i++)
809 real_argv[i] = (char *)the_argv[j];
817 /* we use g_free here as we sucked all the inner strings
818 * out from it into real_argv */
823 #endif /* G_OS_WIN32 */
827 uri_list_segment_to_files (GList *start,
834 while (start != NULL && start != end)
836 file = g_file_new_for_uri ((char *)start->data);
837 res = g_list_prepend (res, file);
841 return g_list_reverse (res);
851 child_setup (gpointer user_data)
853 ChildSetupData *data = user_data;
856 g_setenv ("DISPLAY", data->display, TRUE);
859 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
863 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
865 GAppLaunchContext *launch_context,
868 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
869 gboolean completed = FALSE;
871 GList *launched_files;
876 g_return_val_if_fail (appinfo != NULL, FALSE);
883 if (!expand_application_parameters (info, &uris,
884 &argc, &argv, error))
887 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
889 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
890 _("Unable to find terminal required for application"));
899 launched_files = uri_list_segment_to_files (old_uris, uris);
901 data.display = g_app_launch_context_get_display (launch_context,
905 if (info->startup_notify)
906 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
909 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
910 g_list_free (launched_files);
913 if (!g_spawn_async (info->path,
923 g_app_launch_context_launch_failed (launch_context, data.sn_id);
926 g_free (data.display);
932 g_free (data.display);
937 while (uris != NULL);
948 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
950 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
953 ((strstr (info->exec, "%u") != NULL) ||
954 (strstr (info->exec, "%U") != NULL));
958 g_desktop_app_info_supports_files (GAppInfo *appinfo)
960 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
963 ((strstr (info->exec, "%f") != NULL) ||
964 (strstr (info->exec, "%F") != NULL));
968 g_desktop_app_info_launch (GAppInfo *appinfo,
970 GAppLaunchContext *launch_context,
980 uri = g_file_get_uri (files->data);
981 uris = g_list_prepend (uris, uri);
985 uris = g_list_reverse (uris);
987 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
989 g_list_foreach (uris, (GFunc)g_free, NULL);
995 G_LOCK_DEFINE_STATIC (g_desktop_env);
996 static gchar *g_desktop_env = NULL;
999 * g_desktop_app_info_set_desktop_env:
1000 * @desktop_env: a string specifying what desktop this is
1002 * Sets the name of the desktop that the application is running in.
1003 * This is used by g_app_info_should_show() to evaluate the
1004 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1005 * desktop entry fields.
1007 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1008 * Menu specification</ulink> recognizes the following:
1010 * <member>GNOME</member>
1011 * <member>KDE</member>
1012 * <member>ROX</member>
1013 * <member>XFCE</member>
1014 * <member>Old</member>
1017 * Should be called only once; subsequent calls are ignored.
1020 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1022 G_LOCK (g_desktop_env);
1024 g_desktop_env = g_strdup (desktop_env);
1025 G_UNLOCK (g_desktop_env);
1029 g_desktop_app_info_should_show (GAppInfo *appinfo)
1031 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1033 const gchar *desktop_env;
1036 if (info->nodisplay)
1039 G_LOCK (g_desktop_env);
1040 desktop_env = g_desktop_env;
1041 G_UNLOCK (g_desktop_env);
1043 if (info->only_show_in)
1045 if (desktop_env == NULL)
1049 for (i = 0; info->only_show_in[i] != NULL; i++)
1051 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1061 if (info->not_show_in && desktop_env)
1063 for (i = 0; info->not_show_in[i] != NULL; i++)
1065 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1079 ensure_dir (DirType type,
1082 char *path, *display_name;
1085 if (type == APP_DIR)
1086 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1088 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1091 if (g_mkdir_with_parents (path, 0700) == 0)
1095 display_name = g_filename_display_name (path);
1096 if (type == APP_DIR)
1097 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1098 _("Can't create user application configuration folder %s: %s"),
1099 display_name, g_strerror (errsv));
1101 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1102 _("Can't create user MIME configuration folder %s: %s"),
1103 display_name, g_strerror (errsv));
1105 g_free (display_name);
1112 update_mimeapps_list (const char *desktop_id,
1113 const char *content_type,
1114 gboolean add_as_default,
1115 gboolean add_non_default,
1119 char *dirname, *filename;
1121 gboolean load_succeeded, res;
1122 char **old_list, **list;
1123 GList *system_list, *l;
1124 gsize length, data_size;
1127 char **content_types;
1129 /* Don't add both at start and end */
1130 g_assert (!(add_as_default && add_non_default));
1132 dirname = ensure_dir (APP_DIR, error);
1136 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1139 key_file = g_key_file_new ();
1140 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1141 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1143 g_key_file_free (key_file);
1144 key_file = g_key_file_new ();
1149 content_types = g_new (char *, 2);
1150 content_types[0] = g_strdup (content_type);
1151 content_types[1] = NULL;
1155 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1158 for (k = 0; content_types && content_types[k]; k++)
1160 /* Add to the right place in the list */
1163 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1164 content_types[k], &length, NULL);
1166 list = g_new (char *, 1 + length + 1);
1170 list[i++] = g_strdup (desktop_id);
1173 for (j = 0; old_list[j] != NULL; j++)
1175 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1176 list[i++] = g_strdup (old_list[j]);
1177 else if (add_non_default)
1179 /* If adding as non-default, and it's already in,
1180 don't change order of desktop ids */
1181 add_non_default = FALSE;
1182 list[i++] = g_strdup (old_list[j]);
1187 if (add_non_default)
1189 /* We're adding as non-default, and it wasn't already in the list,
1190 so we add at the end. But to avoid listing the app before the
1191 current system default (thus changing the default) we have to
1192 add the current list of (not yet listed) apps before it. */
1194 list[i] = NULL; /* Terminate current list so we can use it */
1195 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1197 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1199 for (l = system_list; l != NULL; l = l->next)
1201 list[i++] = l->data; /* no strdup, taking ownership */
1202 if (g_strcmp0 (l->data, desktop_id) == 0)
1203 add_non_default = FALSE;
1205 g_list_free (system_list);
1207 if (add_non_default)
1208 list[i++] = g_strdup (desktop_id);
1213 g_strfreev (old_list);
1215 if (list[0] == NULL || desktop_id == NULL)
1216 g_key_file_remove_key (key_file,
1217 ADDED_ASSOCIATIONS_GROUP,
1221 g_key_file_set_string_list (key_file,
1222 ADDED_ASSOCIATIONS_GROUP,
1224 (const char * const *)list, i);
1231 /* reuse the list from above */
1235 g_strfreev (content_types);
1236 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1239 for (k = 0; content_types && content_types[k]; k++)
1241 /* Remove from removed associations group (unless remove) */
1244 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1245 content_types[k], &length, NULL);
1247 list = g_new (char *, 1 + length + 1);
1251 list[i++] = g_strdup (desktop_id);
1254 for (j = 0; old_list[j] != NULL; j++)
1256 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1257 list[i++] = g_strdup (old_list[j]);
1262 g_strfreev (old_list);
1264 if (list[0] == NULL || desktop_id == NULL)
1265 g_key_file_remove_key (key_file,
1266 REMOVED_ASSOCIATIONS_GROUP,
1270 g_key_file_set_string_list (key_file,
1271 REMOVED_ASSOCIATIONS_GROUP,
1273 (const char * const *)list, i);
1278 g_strfreev (content_types);
1280 data = g_key_file_to_data (key_file, &data_size, error);
1281 g_key_file_free (key_file);
1283 res = g_file_set_contents (filename, data, data_size, error);
1285 mime_info_cache_reload (NULL);
1294 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1295 const char *content_type,
1298 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1300 if (!g_desktop_app_info_ensure_saved (info, error))
1303 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1307 update_program_done (GPid pid,
1311 /* Did the application exit correctly */
1312 if (WIFEXITED (status) &&
1313 WEXITSTATUS (status) == 0)
1315 /* Here we could clean out any caches in use */
1320 run_update_command (char *command,
1329 GError *error = NULL;
1332 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1334 if (g_spawn_async ("/", argv,
1336 G_SPAWN_SEARCH_PATH |
1337 G_SPAWN_STDOUT_TO_DEV_NULL |
1338 G_SPAWN_STDERR_TO_DEV_NULL |
1339 G_SPAWN_DO_NOT_REAP_CHILD,
1340 NULL, NULL, /* No setup function */
1343 g_child_watch_add (pid, update_program_done, NULL);
1346 /* If we get an error at this point, it's quite likely the user doesn't
1347 * have an installed copy of either 'update-mime-database' or
1348 * 'update-desktop-database'. I don't think we want to popup an error
1349 * dialog at this point, so we just do a g_warning to give the user a
1350 * chance of debugging it.
1352 g_warning ("%s", error->message);
1359 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1360 const char *extension,
1363 char *filename, *basename, *mimetype;
1367 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1370 dirname = ensure_dir (MIMETYPE_DIR, error);
1374 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1375 filename = g_build_filename (dirname, basename, NULL);
1379 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1381 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1386 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1387 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1388 " <mime-type type=\"%s\">\n"
1389 " <comment>%s document</comment>\n"
1390 " <glob pattern=\"*.%s\"/>\n"
1392 "</mime-info>\n", mimetype, extension, extension);
1394 g_file_set_contents (filename, contents, -1, NULL);
1397 run_update_command ("update-mime-database", "mime");
1401 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1411 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1412 const char *content_type,
1415 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1417 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1420 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1424 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1430 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1431 const char *content_type,
1434 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1436 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1439 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1443 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1449 char *data, *desktop_id;
1454 if (info->filename != NULL)
1457 /* This is only used for object created with
1458 * g_app_info_create_from_commandline. All other
1459 * object should have a filename
1462 dirname = ensure_dir (APP_DIR, error);
1466 key_file = g_key_file_new ();
1468 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1469 "Encoding", "UTF-8");
1470 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1471 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1472 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1473 G_KEY_FILE_DESKTOP_KEY_TYPE,
1474 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1476 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1477 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1479 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1480 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1482 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1483 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1485 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1486 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1488 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1489 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1491 data = g_key_file_to_data (key_file, &data_size, NULL);
1492 g_key_file_free (key_file);
1494 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1495 filename = g_build_filename (dirname, desktop_id, NULL);
1496 g_free (desktop_id);
1499 fd = g_mkstemp (filename);
1504 display_name = g_filename_display_name (filename);
1505 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1506 _("Can't create user desktop file %s"), display_name);
1507 g_free (display_name);
1513 desktop_id = g_path_get_basename (filename);
1517 res = g_file_set_contents (filename, data, data_size, error);
1520 g_free (desktop_id);
1525 info->filename = filename;
1526 info->desktop_id = desktop_id;
1528 run_update_command ("update-desktop-database", "applications");
1534 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1536 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1540 if (strstr (info->filename, "/userapp-"))
1541 return g_access (info->filename, W_OK) == 0;
1548 g_desktop_app_info_delete (GAppInfo *appinfo)
1550 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1554 if (g_remove (info->filename) == 0)
1556 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1558 g_free (info->filename);
1559 info->filename = NULL;
1560 g_free (info->desktop_id);
1561 info->desktop_id = NULL;
1571 * g_app_info_create_from_commandline:
1572 * @commandline: the commandline to use
1573 * @application_name: the application name, or %NULL to use @commandline
1574 * @flags: flags that can specify details of the created #GAppInfo
1575 * @error: a #GError location to store the error occuring, %NULL to ignore.
1577 * Creates a new #GAppInfo from the given information.
1579 * Returns: new #GAppInfo for given command.
1582 g_app_info_create_from_commandline (const char *commandline,
1583 const char *application_name,
1584 GAppInfoCreateFlags flags,
1589 GDesktopAppInfo *info;
1591 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1593 info->filename = NULL;
1594 info->desktop_id = NULL;
1596 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1597 info->startup_notify = FALSE;
1598 info->hidden = FALSE;
1599 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1600 info->exec = g_strconcat (commandline, " %u", NULL);
1602 info->exec = g_strconcat (commandline, " %f", NULL);
1603 info->nodisplay = TRUE;
1604 info->binary = binary_from_exec (info->exec);
1606 if (application_name)
1607 info->name = g_strdup (application_name);
1610 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1611 split = g_strsplit (commandline, " ", 2);
1612 basename = g_path_get_basename (split[0]);
1614 info->name = basename;
1615 if (info->name == NULL)
1616 info->name = g_strdup ("custom");
1618 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1620 return G_APP_INFO (info);
1624 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1626 iface->dup = g_desktop_app_info_dup;
1627 iface->equal = g_desktop_app_info_equal;
1628 iface->get_id = g_desktop_app_info_get_id;
1629 iface->get_name = g_desktop_app_info_get_name;
1630 iface->get_description = g_desktop_app_info_get_description;
1631 iface->get_executable = g_desktop_app_info_get_executable;
1632 iface->get_icon = g_desktop_app_info_get_icon;
1633 iface->launch = g_desktop_app_info_launch;
1634 iface->supports_uris = g_desktop_app_info_supports_uris;
1635 iface->supports_files = g_desktop_app_info_supports_files;
1636 iface->launch_uris = g_desktop_app_info_launch_uris;
1637 iface->should_show = g_desktop_app_info_should_show;
1638 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1639 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1640 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1641 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1642 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1643 iface->can_delete = g_desktop_app_info_can_delete;
1644 iface->do_delete = g_desktop_app_info_delete;
1645 iface->get_commandline = g_desktop_app_info_get_commandline;
1649 app_info_in_list (GAppInfo *info,
1652 while (list != NULL)
1654 if (g_app_info_equal (info, list->data))
1663 * g_app_info_get_all_for_type:
1664 * @content_type: the content type to find a #GAppInfo for
1666 * Gets a list of all #GAppInfo s for a given content type.
1668 * Returns: #GList of #GAppInfo s for given @content_type
1669 * or %NULL on error.
1672 g_app_info_get_all_for_type (const char *content_type)
1674 GList *desktop_entries, *l;
1676 GDesktopAppInfo *info;
1678 g_return_val_if_fail (content_type != NULL, NULL);
1680 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1683 for (l = desktop_entries; l != NULL; l = l->next)
1685 char *desktop_entry = l->data;
1687 info = g_desktop_app_info_new (desktop_entry);
1690 if (app_info_in_list (G_APP_INFO (info), infos))
1691 g_object_unref (info);
1693 infos = g_list_prepend (infos, info);
1695 g_free (desktop_entry);
1698 g_list_free (desktop_entries);
1700 return g_list_reverse (infos);
1704 * g_app_info_reset_type_associations:
1705 * @content_type: a content type
1707 * Removes all changes to the type associations done by
1708 * g_app_info_set_as_default_for_type(),
1709 * g_app_info_set_as_default_for_extension(),
1710 * g_app_info_add_supports_type() of g_app_info_remove_supports_type().
1715 g_app_info_reset_type_associations (const char *content_type)
1717 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1721 * g_app_info_get_default_for_type:
1722 * @content_type: the content type to find a #GAppInfo for
1723 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1726 * Gets the #GAppInfo that correspond to a given content type.
1728 * Returns: #GAppInfo for given @content_type or %NULL on error.
1731 g_app_info_get_default_for_type (const char *content_type,
1732 gboolean must_support_uris)
1734 GList *desktop_entries, *l;
1737 g_return_val_if_fail (content_type != NULL, NULL);
1739 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1742 for (l = desktop_entries; l != NULL; l = l->next)
1744 char *desktop_entry = l->data;
1746 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1749 if (must_support_uris && !g_app_info_supports_uris (info))
1751 g_object_unref (info);
1759 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1760 g_list_free (desktop_entries);
1766 * g_app_info_get_default_for_uri_scheme:
1767 * @uri_scheme: a string containing a URI scheme.
1769 * Gets the default application for launching applications
1770 * using this URI scheme. A URI scheme is the initial part
1771 * of the URI, up to but not including the ':', e.g. "http",
1774 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1777 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1779 static gsize lookup = 0;
1781 if (g_once_init_enter (&lookup))
1783 gsize setup_value = 1;
1784 GDesktopAppInfoLookup *lookup_instance;
1785 const char *use_this;
1786 GIOExtensionPoint *ep;
1787 GIOExtension *extension;
1790 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1792 /* Ensure vfs in modules loaded */
1793 _g_io_modules_ensure_loaded ();
1795 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1797 lookup_instance = NULL;
1800 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1802 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1805 if (lookup_instance == NULL)
1807 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1809 extension = l->data;
1810 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1811 if (lookup_instance != NULL)
1816 if (lookup_instance != NULL)
1817 setup_value = (gsize)lookup_instance;
1819 g_once_init_leave (&lookup, setup_value);
1825 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1831 get_apps_from_dir (GHashTable *apps,
1832 const char *dirname,
1836 const char *basename;
1837 char *filename, *subprefix, *desktop_id;
1839 GDesktopAppInfo *appinfo;
1841 dir = g_dir_open (dirname, 0, NULL);
1844 while ((basename = g_dir_read_name (dir)) != NULL)
1846 filename = g_build_filename (dirname, basename, NULL);
1847 if (g_str_has_suffix (basename, ".desktop"))
1849 desktop_id = g_strconcat (prefix, basename, NULL);
1851 /* Use _extended so we catch NULLs too (hidden) */
1852 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1854 appinfo = g_desktop_app_info_new_from_filename (filename);
1856 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1858 g_object_unref (appinfo);
1863 if (appinfo || hidden)
1865 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1869 /* Reuse instead of strdup here */
1870 appinfo->desktop_id = desktop_id;
1875 g_free (desktop_id);
1879 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1881 subprefix = g_strconcat (prefix, basename, "-", NULL);
1882 get_apps_from_dir (apps, filename, subprefix);
1894 * g_app_info_get_all:
1896 * Gets a list of all of the applications currently registered
1899 * For desktop files, this includes applications that have
1900 * <literal>NoDisplay=true</literal> set or are excluded from
1901 * display by means of <literal>OnlyShowIn</literal> or
1902 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1903 * The returned list does not include applications which have
1904 * the <literal>Hidden</literal> key set.
1906 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1909 g_app_info_get_all (void)
1911 const char * const *dirs;
1913 GHashTableIter iter;
1918 dirs = get_applications_search_path ();
1920 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1924 for (i = 0; dirs[i] != NULL; i++)
1925 get_apps_from_dir (apps, dirs[i], "");
1929 g_hash_table_iter_init (&iter, apps);
1930 while (g_hash_table_iter_next (&iter, NULL, &value))
1933 infos = g_list_prepend (infos, value);
1936 g_hash_table_destroy (apps);
1938 return g_list_reverse (infos);
1941 /* Cacheing of mimeinfo.cache and defaults.list files */
1945 GHashTable *mime_info_cache_map;
1946 GHashTable *defaults_list_map;
1947 GHashTable *mimeapps_list_added_map;
1948 GHashTable *mimeapps_list_removed_map;
1949 time_t mime_info_cache_timestamp;
1950 time_t defaults_list_timestamp;
1951 time_t mimeapps_list_timestamp;
1955 GList *dirs; /* mimeinfo.cache and defaults.list */
1956 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1957 time_t last_stat_time;
1958 guint should_ping_mime_monitor : 1;
1961 static MimeInfoCache *mime_info_cache = NULL;
1962 G_LOCK_DEFINE_STATIC (mime_info_cache);
1964 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
1965 const char *mime_type,
1966 char **new_desktop_file_ids);
1968 static MimeInfoCache * mime_info_cache_new (void);
1971 destroy_info_cache_value (gpointer key,
1975 g_list_foreach (value, (GFunc)g_free, NULL);
1976 g_list_free (value);
1980 destroy_info_cache_map (GHashTable *info_cache_map)
1982 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
1983 g_hash_table_destroy (info_cache_map);
1987 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
1988 const char *cache_file,
1994 filename = g_build_filename (dir->path, cache_file, NULL);
1996 if (g_stat (filename, &buf) < 0)
2003 if (buf.st_mtime != *timestamp)
2009 /* Call with lock held */
2011 remove_all (gpointer key,
2020 mime_info_cache_blow_global_cache (void)
2022 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2027 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2031 gchar *filename, **mime_types;
2038 if (dir->mime_info_cache_map != NULL &&
2039 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2040 &dir->mime_info_cache_timestamp))
2043 if (dir->mime_info_cache_map != NULL)
2044 destroy_info_cache_map (dir->mime_info_cache_map);
2046 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2047 (GDestroyNotify) g_free,
2050 key_file = g_key_file_new ();
2052 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2054 if (g_stat (filename, &buf) < 0)
2057 if (dir->mime_info_cache_timestamp > 0)
2058 mime_info_cache->should_ping_mime_monitor = TRUE;
2060 dir->mime_info_cache_timestamp = buf.st_mtime;
2062 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2067 if (load_error != NULL)
2070 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2073 if (load_error != NULL)
2076 for (i = 0; mime_types[i] != NULL; i++)
2078 gchar **desktop_file_ids;
2079 char *unaliased_type;
2080 desktop_file_ids = g_key_file_get_string_list (key_file,
2086 if (desktop_file_ids == NULL)
2089 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2090 mime_info_cache_dir_add_desktop_entries (dir,
2093 g_free (unaliased_type);
2095 g_strfreev (desktop_file_ids);
2098 g_strfreev (mime_types);
2099 g_key_file_free (key_file);
2104 g_key_file_free (key_file);
2106 if (mime_types != NULL)
2107 g_strfreev (mime_types);
2110 g_error_free (load_error);
2114 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2118 gchar *filename, **mime_types;
2119 char *unaliased_type;
2120 char **desktop_file_ids;
2127 if (dir->defaults_list_map != NULL &&
2128 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2129 &dir->defaults_list_timestamp))
2132 if (dir->defaults_list_map != NULL)
2133 g_hash_table_destroy (dir->defaults_list_map);
2134 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2135 g_free, (GDestroyNotify)g_strfreev);
2138 key_file = g_key_file_new ();
2140 filename = g_build_filename (dir->path, "defaults.list", NULL);
2141 if (g_stat (filename, &buf) < 0)
2144 if (dir->defaults_list_timestamp > 0)
2145 mime_info_cache->should_ping_mime_monitor = TRUE;
2147 dir->defaults_list_timestamp = buf.st_mtime;
2149 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2153 if (load_error != NULL)
2156 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2158 if (mime_types != NULL)
2160 for (i = 0; mime_types[i] != NULL; i++)
2162 desktop_file_ids = g_key_file_get_string_list (key_file,
2163 DEFAULT_APPLICATIONS_GROUP,
2167 if (desktop_file_ids == NULL)
2170 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2171 g_hash_table_replace (dir->defaults_list_map,
2176 g_strfreev (mime_types);
2179 g_key_file_free (key_file);
2184 g_key_file_free (key_file);
2186 if (mime_types != NULL)
2187 g_strfreev (mime_types);
2190 g_error_free (load_error);
2194 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2198 gchar *filename, **mime_types;
2199 char *unaliased_type;
2200 char **desktop_file_ids;
2207 if (dir->mimeapps_list_added_map != NULL &&
2208 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2209 &dir->mimeapps_list_timestamp))
2212 if (dir->mimeapps_list_added_map != NULL)
2213 g_hash_table_destroy (dir->mimeapps_list_added_map);
2214 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2215 g_free, (GDestroyNotify)g_strfreev);
2217 if (dir->mimeapps_list_removed_map != NULL)
2218 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2219 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2220 g_free, (GDestroyNotify)g_strfreev);
2222 key_file = g_key_file_new ();
2224 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2225 if (g_stat (filename, &buf) < 0)
2228 if (dir->mimeapps_list_timestamp > 0)
2229 mime_info_cache->should_ping_mime_monitor = TRUE;
2231 dir->mimeapps_list_timestamp = buf.st_mtime;
2233 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2237 if (load_error != NULL)
2240 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2242 if (mime_types != NULL)
2244 for (i = 0; mime_types[i] != NULL; i++)
2246 desktop_file_ids = g_key_file_get_string_list (key_file,
2247 ADDED_ASSOCIATIONS_GROUP,
2251 if (desktop_file_ids == NULL)
2254 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2255 g_hash_table_replace (dir->mimeapps_list_added_map,
2260 g_strfreev (mime_types);
2263 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2265 if (mime_types != NULL)
2267 for (i = 0; mime_types[i] != NULL; i++)
2269 desktop_file_ids = g_key_file_get_string_list (key_file,
2270 REMOVED_ASSOCIATIONS_GROUP,
2274 if (desktop_file_ids == NULL)
2277 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2278 g_hash_table_replace (dir->mimeapps_list_removed_map,
2283 g_strfreev (mime_types);
2286 g_key_file_free (key_file);
2291 g_key_file_free (key_file);
2293 if (mime_types != NULL)
2294 g_strfreev (mime_types);
2297 g_error_free (load_error);
2300 static MimeInfoCacheDir *
2301 mime_info_cache_dir_new (const char *path)
2303 MimeInfoCacheDir *dir;
2305 dir = g_new0 (MimeInfoCacheDir, 1);
2306 dir->path = g_strdup (path);
2312 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2317 if (dir->mime_info_cache_map != NULL)
2319 destroy_info_cache_map (dir->mime_info_cache_map);
2320 dir->mime_info_cache_map = NULL;
2324 if (dir->defaults_list_map != NULL)
2326 g_hash_table_destroy (dir->defaults_list_map);
2327 dir->defaults_list_map = NULL;
2330 if (dir->mimeapps_list_added_map != NULL)
2332 g_hash_table_destroy (dir->mimeapps_list_added_map);
2333 dir->mimeapps_list_added_map = NULL;
2336 if (dir->mimeapps_list_removed_map != NULL)
2338 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2339 dir->mimeapps_list_removed_map = NULL;
2346 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2347 const char *mime_type,
2348 char **new_desktop_file_ids)
2350 GList *desktop_file_ids;
2353 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2356 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2358 if (!g_list_find (desktop_file_ids, new_desktop_file_ids[i]))
2359 desktop_file_ids = g_list_append (desktop_file_ids,
2360 g_strdup (new_desktop_file_ids[i]));
2363 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2367 mime_info_cache_init_dir_lists (void)
2369 const char * const *dirs;
2372 mime_info_cache = mime_info_cache_new ();
2374 dirs = get_applications_search_path ();
2376 for (i = 0; dirs[i] != NULL; i++)
2378 MimeInfoCacheDir *dir;
2380 dir = mime_info_cache_dir_new (dirs[i]);
2384 mime_info_cache_dir_init (dir);
2385 mime_info_cache_dir_init_defaults_list (dir);
2386 mime_info_cache_dir_init_mimeapps_list (dir);
2388 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2394 mime_info_cache_update_dir_lists (void)
2398 tmp = mime_info_cache->dirs;
2402 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2404 /* No need to do this if we had file monitors... */
2405 mime_info_cache_blow_global_cache ();
2406 mime_info_cache_dir_init (dir);
2407 mime_info_cache_dir_init_defaults_list (dir);
2408 mime_info_cache_dir_init_mimeapps_list (dir);
2415 mime_info_cache_init (void)
2417 G_LOCK (mime_info_cache);
2418 if (mime_info_cache == NULL)
2419 mime_info_cache_init_dir_lists ();
2425 if (now >= mime_info_cache->last_stat_time + 10)
2427 mime_info_cache_update_dir_lists ();
2428 mime_info_cache->last_stat_time = now;
2432 if (mime_info_cache->should_ping_mime_monitor)
2434 /* g_idle_add (emit_mime_changed, NULL); */
2435 mime_info_cache->should_ping_mime_monitor = FALSE;
2438 G_UNLOCK (mime_info_cache);
2441 static MimeInfoCache *
2442 mime_info_cache_new (void)
2444 MimeInfoCache *cache;
2446 cache = g_new0 (MimeInfoCache, 1);
2448 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2449 (GDestroyNotify) g_free,
2450 (GDestroyNotify) g_free);
2455 mime_info_cache_free (MimeInfoCache *cache)
2460 g_list_foreach (cache->dirs,
2461 (GFunc) mime_info_cache_dir_free,
2463 g_list_free (cache->dirs);
2464 g_hash_table_destroy (cache->global_defaults_cache);
2469 * mime_info_cache_reload:
2470 * @dir: directory path which needs reloading.
2472 * Reload the mime information for the @dir.
2475 mime_info_cache_reload (const char *dir)
2477 /* FIXME: just reload the dir that needs reloading,
2478 * don't blow the whole cache
2480 if (mime_info_cache != NULL)
2482 G_LOCK (mime_info_cache);
2483 mime_info_cache_free (mime_info_cache);
2484 mime_info_cache = NULL;
2485 G_UNLOCK (mime_info_cache);
2490 append_desktop_entry (GList *list,
2491 const char *desktop_entry,
2492 GList *removed_entries)
2494 /* Add if not already in list, and valid */
2495 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2496 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2497 list = g_list_prepend (list, g_strdup (desktop_entry));
2503 * get_all_desktop_entries_for_mime_type:
2504 * @mime_type: a mime type.
2505 * @except: NULL or a strv list
2507 * Returns all the desktop ids for @mime_type. The desktop files
2508 * are listed in an order so that default applications are listed before
2509 * non-default ones, and handlers for inherited mimetypes are listed
2510 * after the base ones.
2512 * Optionally doesn't list the desktop ids given in the @except
2514 * Return value: a #GList containing the desktop ids which claim
2515 * to handle @mime_type.
2518 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2519 const char **except)
2521 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2522 MimeInfoCacheDir *dir;
2525 char **default_entries;
2526 char **removed_associations;
2531 mime_info_cache_init ();
2533 /* collect all ancestors */
2534 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2535 array = g_ptr_array_new ();
2536 for (i = 0; mime_types[i]; i++)
2537 g_ptr_array_add (array, mime_types[i]);
2538 g_free (mime_types);
2539 for (i = 0; i < array->len; i++)
2541 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2542 for (j = 0; anc[j]; j++)
2544 for (k = 0; k < array->len; k++)
2546 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2549 if (k == array->len) /* not found */
2550 g_ptr_array_add (array, g_strdup (anc[j]));
2554 g_ptr_array_add (array, NULL);
2555 mime_types = (char **)g_ptr_array_free (array, FALSE);
2557 G_LOCK (mime_info_cache);
2559 removed_entries = NULL;
2560 desktop_entries = NULL;
2562 for (i = 0; except != NULL && except[i] != NULL; i++)
2563 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2565 for (i = 0; mime_types[i] != NULL; i++)
2567 mime_type = mime_types[i];
2569 /* Go through all apps listed as defaults */
2570 for (dir_list = mime_info_cache->dirs;
2572 dir_list = dir_list->next)
2574 dir = dir_list->data;
2576 /* First added associations from mimeapps.list */
2577 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2578 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2579 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2581 /* Then removed associations from mimeapps.list */
2582 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2583 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2584 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2586 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2587 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2588 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2589 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2592 /* Go through all entries that support the mimetype */
2593 for (dir_list = mime_info_cache->dirs;
2595 dir_list = dir_list->next)
2597 dir = dir_list->data;
2599 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2600 for (tmp = list; tmp != NULL; tmp = tmp->next)
2601 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2605 G_UNLOCK (mime_info_cache);
2607 g_strfreev (mime_types);
2609 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2610 g_list_free (removed_entries);
2612 desktop_entries = g_list_reverse (desktop_entries);
2614 return desktop_entries;
2617 /* GDesktopAppInfoLookup interface: */
2619 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2620 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2621 gpointer class_data);
2624 g_desktop_app_info_lookup_get_type (void)
2626 static volatile gsize g_define_type_id__volatile = 0;
2628 if (g_once_init_enter (&g_define_type_id__volatile))
2630 const GTypeInfo desktop_app_info_lookup_info =
2632 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2633 g_desktop_app_info_lookup_base_init, /* base_init */
2634 NULL, /* base_finalize */
2635 g_desktop_app_info_lookup_class_init,
2636 NULL, /* class_finalize */
2637 NULL, /* class_data */
2639 0, /* n_preallocs */
2642 GType g_define_type_id =
2643 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2644 &desktop_app_info_lookup_info, 0);
2646 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2648 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2651 return g_define_type_id__volatile;
2655 g_desktop_app_info_lookup_class_init (gpointer g_class,
2656 gpointer class_data)
2661 g_desktop_app_info_lookup_base_init (gpointer g_class)
2666 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2667 * @lookup: a #GDesktopAppInfoLookup
2668 * @uri_scheme: a string containing a URI scheme.
2670 * Gets the default application for launching applications
2671 * using this URI scheme for a particular GDesktopAppInfoLookup
2674 * The GDesktopAppInfoLookup interface and this function is used
2675 * to implement g_app_info_get_default_for_uri_scheme() backends
2676 * in a GIO module. There is no reason for applications to use it
2677 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2679 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2682 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2683 const char *uri_scheme)
2685 GDesktopAppInfoLookupIface *iface;
2687 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2689 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2691 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2694 #define __G_DESKTOP_APP_INFO_C__
2695 #include "gioaliasdef.c"