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() or 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 corresponds 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);
1857 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1859 g_object_unref (appinfo);
1864 if (appinfo || hidden)
1866 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1870 /* Reuse instead of strdup here */
1871 appinfo->desktop_id = desktop_id;
1876 g_free (desktop_id);
1880 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1882 subprefix = g_strconcat (prefix, basename, "-", NULL);
1883 get_apps_from_dir (apps, filename, subprefix);
1895 * g_app_info_get_all:
1897 * Gets a list of all of the applications currently registered
1900 * For desktop files, this includes applications that have
1901 * <literal>NoDisplay=true</literal> set or are excluded from
1902 * display by means of <literal>OnlyShowIn</literal> or
1903 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1904 * The returned list does not include applications which have
1905 * the <literal>Hidden</literal> key set.
1907 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1910 g_app_info_get_all (void)
1912 const char * const *dirs;
1914 GHashTableIter iter;
1919 dirs = get_applications_search_path ();
1921 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1925 for (i = 0; dirs[i] != NULL; i++)
1926 get_apps_from_dir (apps, dirs[i], "");
1930 g_hash_table_iter_init (&iter, apps);
1931 while (g_hash_table_iter_next (&iter, NULL, &value))
1934 infos = g_list_prepend (infos, value);
1937 g_hash_table_destroy (apps);
1939 return g_list_reverse (infos);
1942 /* Cacheing of mimeinfo.cache and defaults.list files */
1946 GHashTable *mime_info_cache_map;
1947 GHashTable *defaults_list_map;
1948 GHashTable *mimeapps_list_added_map;
1949 GHashTable *mimeapps_list_removed_map;
1950 time_t mime_info_cache_timestamp;
1951 time_t defaults_list_timestamp;
1952 time_t mimeapps_list_timestamp;
1956 GList *dirs; /* mimeinfo.cache and defaults.list */
1957 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1958 time_t last_stat_time;
1959 guint should_ping_mime_monitor : 1;
1962 static MimeInfoCache *mime_info_cache = NULL;
1963 G_LOCK_DEFINE_STATIC (mime_info_cache);
1965 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
1966 const char *mime_type,
1967 char **new_desktop_file_ids);
1969 static MimeInfoCache * mime_info_cache_new (void);
1972 destroy_info_cache_value (gpointer key,
1976 g_list_foreach (value, (GFunc)g_free, NULL);
1977 g_list_free (value);
1981 destroy_info_cache_map (GHashTable *info_cache_map)
1983 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
1984 g_hash_table_destroy (info_cache_map);
1988 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
1989 const char *cache_file,
1995 filename = g_build_filename (dir->path, cache_file, NULL);
1997 if (g_stat (filename, &buf) < 0)
2004 if (buf.st_mtime != *timestamp)
2010 /* Call with lock held */
2012 remove_all (gpointer key,
2021 mime_info_cache_blow_global_cache (void)
2023 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2028 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2032 gchar *filename, **mime_types;
2039 if (dir->mime_info_cache_map != NULL &&
2040 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2041 &dir->mime_info_cache_timestamp))
2044 if (dir->mime_info_cache_map != NULL)
2045 destroy_info_cache_map (dir->mime_info_cache_map);
2047 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2048 (GDestroyNotify) g_free,
2051 key_file = g_key_file_new ();
2053 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2055 if (g_stat (filename, &buf) < 0)
2058 if (dir->mime_info_cache_timestamp > 0)
2059 mime_info_cache->should_ping_mime_monitor = TRUE;
2061 dir->mime_info_cache_timestamp = buf.st_mtime;
2063 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2068 if (load_error != NULL)
2071 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2074 if (load_error != NULL)
2077 for (i = 0; mime_types[i] != NULL; i++)
2079 gchar **desktop_file_ids;
2080 char *unaliased_type;
2081 desktop_file_ids = g_key_file_get_string_list (key_file,
2087 if (desktop_file_ids == NULL)
2090 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2091 mime_info_cache_dir_add_desktop_entries (dir,
2094 g_free (unaliased_type);
2096 g_strfreev (desktop_file_ids);
2099 g_strfreev (mime_types);
2100 g_key_file_free (key_file);
2105 g_key_file_free (key_file);
2107 if (mime_types != NULL)
2108 g_strfreev (mime_types);
2111 g_error_free (load_error);
2115 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2119 gchar *filename, **mime_types;
2120 char *unaliased_type;
2121 char **desktop_file_ids;
2128 if (dir->defaults_list_map != NULL &&
2129 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2130 &dir->defaults_list_timestamp))
2133 if (dir->defaults_list_map != NULL)
2134 g_hash_table_destroy (dir->defaults_list_map);
2135 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2136 g_free, (GDestroyNotify)g_strfreev);
2139 key_file = g_key_file_new ();
2141 filename = g_build_filename (dir->path, "defaults.list", NULL);
2142 if (g_stat (filename, &buf) < 0)
2145 if (dir->defaults_list_timestamp > 0)
2146 mime_info_cache->should_ping_mime_monitor = TRUE;
2148 dir->defaults_list_timestamp = buf.st_mtime;
2150 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2154 if (load_error != NULL)
2157 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2159 if (mime_types != NULL)
2161 for (i = 0; mime_types[i] != NULL; i++)
2163 desktop_file_ids = g_key_file_get_string_list (key_file,
2164 DEFAULT_APPLICATIONS_GROUP,
2168 if (desktop_file_ids == NULL)
2171 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2172 g_hash_table_replace (dir->defaults_list_map,
2177 g_strfreev (mime_types);
2180 g_key_file_free (key_file);
2185 g_key_file_free (key_file);
2187 if (mime_types != NULL)
2188 g_strfreev (mime_types);
2191 g_error_free (load_error);
2195 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2199 gchar *filename, **mime_types;
2200 char *unaliased_type;
2201 char **desktop_file_ids;
2208 if (dir->mimeapps_list_added_map != NULL &&
2209 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2210 &dir->mimeapps_list_timestamp))
2213 if (dir->mimeapps_list_added_map != NULL)
2214 g_hash_table_destroy (dir->mimeapps_list_added_map);
2215 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2216 g_free, (GDestroyNotify)g_strfreev);
2218 if (dir->mimeapps_list_removed_map != NULL)
2219 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2220 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2221 g_free, (GDestroyNotify)g_strfreev);
2223 key_file = g_key_file_new ();
2225 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2226 if (g_stat (filename, &buf) < 0)
2229 if (dir->mimeapps_list_timestamp > 0)
2230 mime_info_cache->should_ping_mime_monitor = TRUE;
2232 dir->mimeapps_list_timestamp = buf.st_mtime;
2234 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2238 if (load_error != NULL)
2241 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2243 if (mime_types != NULL)
2245 for (i = 0; mime_types[i] != NULL; i++)
2247 desktop_file_ids = g_key_file_get_string_list (key_file,
2248 ADDED_ASSOCIATIONS_GROUP,
2252 if (desktop_file_ids == NULL)
2255 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2256 g_hash_table_replace (dir->mimeapps_list_added_map,
2261 g_strfreev (mime_types);
2264 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2266 if (mime_types != NULL)
2268 for (i = 0; mime_types[i] != NULL; i++)
2270 desktop_file_ids = g_key_file_get_string_list (key_file,
2271 REMOVED_ASSOCIATIONS_GROUP,
2275 if (desktop_file_ids == NULL)
2278 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2279 g_hash_table_replace (dir->mimeapps_list_removed_map,
2284 g_strfreev (mime_types);
2287 g_key_file_free (key_file);
2292 g_key_file_free (key_file);
2294 if (mime_types != NULL)
2295 g_strfreev (mime_types);
2298 g_error_free (load_error);
2301 static MimeInfoCacheDir *
2302 mime_info_cache_dir_new (const char *path)
2304 MimeInfoCacheDir *dir;
2306 dir = g_new0 (MimeInfoCacheDir, 1);
2307 dir->path = g_strdup (path);
2313 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2318 if (dir->mime_info_cache_map != NULL)
2320 destroy_info_cache_map (dir->mime_info_cache_map);
2321 dir->mime_info_cache_map = NULL;
2325 if (dir->defaults_list_map != NULL)
2327 g_hash_table_destroy (dir->defaults_list_map);
2328 dir->defaults_list_map = NULL;
2331 if (dir->mimeapps_list_added_map != NULL)
2333 g_hash_table_destroy (dir->mimeapps_list_added_map);
2334 dir->mimeapps_list_added_map = NULL;
2337 if (dir->mimeapps_list_removed_map != NULL)
2339 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2340 dir->mimeapps_list_removed_map = NULL;
2347 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2348 const char *mime_type,
2349 char **new_desktop_file_ids)
2351 GList *desktop_file_ids;
2354 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2357 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2359 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2360 desktop_file_ids = g_list_append (desktop_file_ids,
2361 g_strdup (new_desktop_file_ids[i]));
2364 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2368 mime_info_cache_init_dir_lists (void)
2370 const char * const *dirs;
2373 mime_info_cache = mime_info_cache_new ();
2375 dirs = get_applications_search_path ();
2377 for (i = 0; dirs[i] != NULL; i++)
2379 MimeInfoCacheDir *dir;
2381 dir = mime_info_cache_dir_new (dirs[i]);
2385 mime_info_cache_dir_init (dir);
2386 mime_info_cache_dir_init_defaults_list (dir);
2387 mime_info_cache_dir_init_mimeapps_list (dir);
2389 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2395 mime_info_cache_update_dir_lists (void)
2399 tmp = mime_info_cache->dirs;
2403 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2405 /* No need to do this if we had file monitors... */
2406 mime_info_cache_blow_global_cache ();
2407 mime_info_cache_dir_init (dir);
2408 mime_info_cache_dir_init_defaults_list (dir);
2409 mime_info_cache_dir_init_mimeapps_list (dir);
2416 mime_info_cache_init (void)
2418 G_LOCK (mime_info_cache);
2419 if (mime_info_cache == NULL)
2420 mime_info_cache_init_dir_lists ();
2426 if (now >= mime_info_cache->last_stat_time + 10)
2428 mime_info_cache_update_dir_lists ();
2429 mime_info_cache->last_stat_time = now;
2433 if (mime_info_cache->should_ping_mime_monitor)
2435 /* g_idle_add (emit_mime_changed, NULL); */
2436 mime_info_cache->should_ping_mime_monitor = FALSE;
2439 G_UNLOCK (mime_info_cache);
2442 static MimeInfoCache *
2443 mime_info_cache_new (void)
2445 MimeInfoCache *cache;
2447 cache = g_new0 (MimeInfoCache, 1);
2449 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2450 (GDestroyNotify) g_free,
2451 (GDestroyNotify) g_free);
2456 mime_info_cache_free (MimeInfoCache *cache)
2461 g_list_foreach (cache->dirs,
2462 (GFunc) mime_info_cache_dir_free,
2464 g_list_free (cache->dirs);
2465 g_hash_table_destroy (cache->global_defaults_cache);
2470 * mime_info_cache_reload:
2471 * @dir: directory path which needs reloading.
2473 * Reload the mime information for the @dir.
2476 mime_info_cache_reload (const char *dir)
2478 /* FIXME: just reload the dir that needs reloading,
2479 * don't blow the whole cache
2481 if (mime_info_cache != NULL)
2483 G_LOCK (mime_info_cache);
2484 mime_info_cache_free (mime_info_cache);
2485 mime_info_cache = NULL;
2486 G_UNLOCK (mime_info_cache);
2491 append_desktop_entry (GList *list,
2492 const char *desktop_entry,
2493 GList *removed_entries)
2495 /* Add if not already in list, and valid */
2496 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2497 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2498 list = g_list_prepend (list, g_strdup (desktop_entry));
2504 * get_all_desktop_entries_for_mime_type:
2505 * @mime_type: a mime type.
2506 * @except: NULL or a strv list
2508 * Returns all the desktop ids for @mime_type. The desktop files
2509 * are listed in an order so that default applications are listed before
2510 * non-default ones, and handlers for inherited mimetypes are listed
2511 * after the base ones.
2513 * Optionally doesn't list the desktop ids given in the @except
2515 * Return value: a #GList containing the desktop ids which claim
2516 * to handle @mime_type.
2519 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2520 const char **except)
2522 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2523 MimeInfoCacheDir *dir;
2526 char **default_entries;
2527 char **removed_associations;
2532 mime_info_cache_init ();
2534 /* collect all ancestors */
2535 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2536 array = g_ptr_array_new ();
2537 for (i = 0; mime_types[i]; i++)
2538 g_ptr_array_add (array, mime_types[i]);
2539 g_free (mime_types);
2540 for (i = 0; i < array->len; i++)
2542 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2543 for (j = 0; anc[j]; j++)
2545 for (k = 0; k < array->len; k++)
2547 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2550 if (k == array->len) /* not found */
2551 g_ptr_array_add (array, g_strdup (anc[j]));
2555 g_ptr_array_add (array, NULL);
2556 mime_types = (char **)g_ptr_array_free (array, FALSE);
2558 G_LOCK (mime_info_cache);
2560 removed_entries = NULL;
2561 desktop_entries = NULL;
2563 for (i = 0; except != NULL && except[i] != NULL; i++)
2564 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2566 for (i = 0; mime_types[i] != NULL; i++)
2568 mime_type = mime_types[i];
2570 /* Go through all apps listed as defaults */
2571 for (dir_list = mime_info_cache->dirs;
2573 dir_list = dir_list->next)
2575 dir = dir_list->data;
2577 /* First added associations from mimeapps.list */
2578 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2579 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2580 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2582 /* Then removed associations from mimeapps.list */
2583 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2584 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2585 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2587 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2588 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2589 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2590 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2593 /* Go through all entries that support the mimetype */
2594 for (dir_list = mime_info_cache->dirs;
2596 dir_list = dir_list->next)
2598 dir = dir_list->data;
2600 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2601 for (tmp = list; tmp != NULL; tmp = tmp->next)
2602 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2606 G_UNLOCK (mime_info_cache);
2608 g_strfreev (mime_types);
2610 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2611 g_list_free (removed_entries);
2613 desktop_entries = g_list_reverse (desktop_entries);
2615 return desktop_entries;
2618 /* GDesktopAppInfoLookup interface: */
2620 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2621 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2622 gpointer class_data);
2625 g_desktop_app_info_lookup_get_type (void)
2627 static volatile gsize g_define_type_id__volatile = 0;
2629 if (g_once_init_enter (&g_define_type_id__volatile))
2631 const GTypeInfo desktop_app_info_lookup_info =
2633 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2634 g_desktop_app_info_lookup_base_init, /* base_init */
2635 NULL, /* base_finalize */
2636 g_desktop_app_info_lookup_class_init,
2637 NULL, /* class_finalize */
2638 NULL, /* class_data */
2640 0, /* n_preallocs */
2643 GType g_define_type_id =
2644 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2645 &desktop_app_info_lookup_info, 0);
2647 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2649 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2652 return g_define_type_id__volatile;
2656 g_desktop_app_info_lookup_class_init (gpointer g_class,
2657 gpointer class_data)
2662 g_desktop_app_info_lookup_base_init (gpointer g_class)
2667 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2668 * @lookup: a #GDesktopAppInfoLookup
2669 * @uri_scheme: a string containing a URI scheme.
2671 * Gets the default application for launching applications
2672 * using this URI scheme for a particular GDesktopAppInfoLookup
2675 * The GDesktopAppInfoLookup interface and this function is used
2676 * to implement g_app_info_get_default_for_uri_scheme() backends
2677 * in a GIO module. There is no reason for applications to use it
2678 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2680 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2683 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2684 const char *uri_scheme)
2686 GDesktopAppInfoLookupIface *iface;
2688 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2690 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2692 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2695 #define __G_DESKTOP_APP_INFO_C__
2696 #include "gioaliasdef.c"