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"
65 #define FULL_NAME_KEY "X-GNOME-FullName"
67 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
68 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
70 static void mime_info_cache_reload (const char *dir);
71 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
77 * Information about an installed application from a desktop file.
79 struct _GDesktopAppInfo
81 GObject parent_instance;
87 /* FIXME: what about GenericName ? */
102 guint startup_notify : 1;
104 /* FIXME: what about StartupWMClass ? */
107 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
108 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
109 g_desktop_app_info_iface_init))
112 search_path_init (gpointer data)
115 const char * const *data_dirs;
116 const char *user_data_dir;
119 data_dirs = g_get_system_data_dirs ();
120 length = g_strv_length ((char **) data_dirs);
122 args = g_new (char *, length + 2);
125 user_data_dir = g_get_user_data_dir ();
126 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
127 for (i = 0; i < length; i++)
128 args[j++] = g_build_filename (data_dirs[i],
129 "applications", NULL);
135 static const char * const *
136 get_applications_search_path (void)
138 static GOnce once_init = G_ONCE_INIT;
139 return g_once (&once_init, search_path_init, NULL);
143 g_desktop_app_info_finalize (GObject *object)
145 GDesktopAppInfo *info;
147 info = G_DESKTOP_APP_INFO (object);
149 g_free (info->desktop_id);
150 g_free (info->filename);
152 g_free (info->fullname);
153 g_free (info->comment);
154 g_free (info->icon_name);
156 g_object_unref (info->icon);
157 g_strfreev (info->only_show_in);
158 g_strfreev (info->not_show_in);
159 g_free (info->try_exec);
161 g_free (info->binary);
164 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
168 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
170 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
172 gobject_class->finalize = g_desktop_app_info_finalize;
176 g_desktop_app_info_init (GDesktopAppInfo *local)
181 binary_from_exec (const char *exec)
183 const char *p, *start;
189 while (*p != ' ' && *p != 0)
192 return g_strndup (start, p - start);
197 * g_desktop_app_info_new_from_keyfile:
198 * @key_file: an opened #GKeyFile
200 * Creates a new #GDesktopAppInfo.
202 * Returns: a new #GDesktopAppInfo or %NULL on error.
207 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
209 GDesktopAppInfo *info;
214 start_group = g_key_file_get_start_group (key_file);
215 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
217 g_free (start_group);
220 g_free (start_group);
222 type = g_key_file_get_string (key_file,
223 G_KEY_FILE_DESKTOP_GROUP,
224 G_KEY_FILE_DESKTOP_KEY_TYPE,
226 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
233 try_exec = g_key_file_get_string (key_file,
234 G_KEY_FILE_DESKTOP_GROUP,
235 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
237 if (try_exec && try_exec[0] != '\0')
240 t = g_find_program_in_path (try_exec);
249 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
250 info->filename = NULL;
252 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
253 info->fullname = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, FULL_NAME_KEY, NULL, NULL);
254 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
255 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
256 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
257 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);
258 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);
259 info->try_exec = try_exec;
260 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
261 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
262 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
263 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
264 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
265 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
270 if (g_path_is_absolute (info->icon_name))
274 file = g_file_new_for_path (info->icon_name);
275 info->icon = g_file_icon_new (file);
276 g_object_unref (file);
282 /* Work around a common mistake in desktop files */
283 if ((p = strrchr (info->icon_name, '.')) != NULL &&
284 (strcmp (p, ".png") == 0 ||
285 strcmp (p, ".xpm") == 0 ||
286 strcmp (p, ".svg") == 0))
289 info->icon = g_themed_icon_new (info->icon_name);
294 info->binary = binary_from_exec (info->exec);
296 if (info->path && info->path[0] == '\0')
306 * g_desktop_app_info_new_from_filename:
307 * @filename: the path of a desktop file, in the GLib filename encoding
309 * Creates a new #GDesktopAppInfo.
311 * Returns: a new #GDesktopAppInfo or %NULL on error.
314 g_desktop_app_info_new_from_filename (const char *filename)
317 GDesktopAppInfo *info = NULL;
319 key_file = g_key_file_new ();
321 if (g_key_file_load_from_file (key_file,
326 info = g_desktop_app_info_new_from_keyfile (key_file);
328 info->filename = g_strdup (filename);
331 g_key_file_free (key_file);
337 * g_desktop_app_info_new:
338 * @desktop_id: the desktop file id
340 * Creates a new #GDesktopAppInfo based on a desktop file id.
342 * A desktop file id is the basename of the desktop file, including the
343 * .desktop extension. GIO is looking for a desktop file with this name
344 * in the <filename>applications</filename> subdirectories of the XDG data
345 * directories (i.e. the directories specified in the
346 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
347 * variables). GIO also supports the prefix-to-subdirectory mapping that is
348 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
349 * (i.e. a desktop id of kde-foo.desktop will match
350 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
352 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
355 g_desktop_app_info_new (const char *desktop_id)
357 GDesktopAppInfo *appinfo;
358 const char * const *dirs;
362 dirs = get_applications_search_path ();
364 basename = g_strdup (desktop_id);
366 for (i = 0; dirs[i] != NULL; i++)
371 filename = g_build_filename (dirs[i], desktop_id, NULL);
372 appinfo = g_desktop_app_info_new_from_filename (filename);
378 while ((p = strchr (p, '-')) != NULL)
382 filename = g_build_filename (dirs[i], basename, NULL);
383 appinfo = g_desktop_app_info_new_from_filename (filename);
398 appinfo->desktop_id = g_strdup (desktop_id);
400 if (g_desktop_app_info_get_is_hidden (appinfo))
402 g_object_unref (appinfo);
410 g_desktop_app_info_dup (GAppInfo *appinfo)
412 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
413 GDesktopAppInfo *new_info;
415 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
417 new_info->filename = g_strdup (info->filename);
418 new_info->desktop_id = g_strdup (info->desktop_id);
420 new_info->name = g_strdup (info->name);
421 new_info->fullname = g_strdup (info->fullname);
422 new_info->comment = g_strdup (info->comment);
423 new_info->nodisplay = info->nodisplay;
424 new_info->icon_name = g_strdup (info->icon_name);
426 new_info->icon = g_object_ref (info->icon);
427 new_info->only_show_in = g_strdupv (info->only_show_in);
428 new_info->not_show_in = g_strdupv (info->not_show_in);
429 new_info->try_exec = g_strdup (info->try_exec);
430 new_info->exec = g_strdup (info->exec);
431 new_info->binary = g_strdup (info->binary);
432 new_info->path = g_strdup (info->path);
433 new_info->hidden = info->hidden;
434 new_info->terminal = info->terminal;
435 new_info->startup_notify = info->startup_notify;
437 return G_APP_INFO (new_info);
441 g_desktop_app_info_equal (GAppInfo *appinfo1,
444 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
445 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
447 if (info1->desktop_id == NULL ||
448 info2->desktop_id == NULL)
449 return info1 == info2;
451 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
455 g_desktop_app_info_get_id (GAppInfo *appinfo)
457 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
459 return info->desktop_id;
463 g_desktop_app_info_get_name (GAppInfo *appinfo)
465 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
467 if (info->name == NULL)
473 g_desktop_app_info_get_display_name (GAppInfo *appinfo)
475 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
477 if (info->fullname == NULL)
478 return g_desktop_app_info_get_name (appinfo);
479 return info->fullname;
483 * g_desktop_app_info_get_is_hidden:
484 * @info: a #GDesktopAppInfo.
486 * A desktop file is hidden if the Hidden key in it is
489 * Returns: %TRUE if hidden, %FALSE otherwise.
492 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
498 g_desktop_app_info_get_description (GAppInfo *appinfo)
500 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
502 return info->comment;
506 g_desktop_app_info_get_executable (GAppInfo *appinfo)
508 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
514 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
516 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
522 g_desktop_app_info_get_icon (GAppInfo *appinfo)
524 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
530 expand_macro_single (char macro, char *uri)
536 file = g_file_new_for_uri (uri);
537 path = g_file_get_path (file);
538 g_object_unref (file);
544 result = g_shell_quote (uri);
549 result = g_shell_quote (path);
555 name = g_path_get_dirname (path);
556 result = g_shell_quote (name);
564 name = g_path_get_basename (path);
565 result = g_shell_quote (name);
577 expand_macro (char macro,
579 GDesktopAppInfo *info,
582 GList *uris = *uri_list;
584 gboolean force_file_uri;
585 char force_file_uri_macro;
588 g_return_if_fail (exec != NULL);
590 /* On %u and %U, pass POSIX file path pointing to the URI via
591 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
592 * running or the URI doesn't have a POSIX file path via FUSE
593 * we'll just pass the URI.
595 force_file_uri_macro = macro;
596 force_file_uri = FALSE;
602 force_file_uri_macro = 'f';
603 force_file_uri = TRUE;
606 force_file_uri_macro = 'F';
607 force_file_uri = TRUE;
623 if (!force_file_uri ||
624 /* Pass URI if it contains an anchor */
625 strchr (uri, '#') != NULL)
627 expanded = expand_macro_single (macro, uri);
631 expanded = expand_macro_single (force_file_uri_macro, uri);
632 if (expanded == NULL)
633 expanded = expand_macro_single (macro, uri);
638 g_string_append (exec, expanded);
654 if (!force_file_uri ||
655 /* Pass URI if it contains an anchor */
656 strchr (uri, '#') != NULL)
658 expanded = expand_macro_single (macro, uri);
662 expanded = expand_macro_single (force_file_uri_macro, uri);
663 if (expanded == NULL)
664 expanded = expand_macro_single (macro, uri);
669 g_string_append (exec, expanded);
675 if (uris != NULL && expanded)
676 g_string_append_c (exec, ' ');
684 g_string_append (exec, "--icon ");
685 g_string_append (exec, info->icon_name);
691 g_string_append (exec, info->name);
696 g_string_append (exec, info->filename);
699 case 'm': /* deprecated */
703 g_string_append_c (exec, '%');
711 expand_application_parameters (GDesktopAppInfo *info,
717 GList *uri_list = *uris;
718 const char *p = info->exec;
719 GString *expanded_exec;
722 if (info->exec == NULL)
724 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
725 _("Desktop file didn't specify Exec field"));
729 expanded_exec = g_string_new (NULL);
733 if (p[0] == '%' && p[1] != '\0')
735 expand_macro (p[1], expanded_exec, info, uris);
739 g_string_append_c (expanded_exec, *p);
744 /* No file substitutions */
745 if (uri_list == *uris && uri_list != NULL)
747 /* If there is no macro default to %f. This is also what KDE does */
748 g_string_append_c (expanded_exec, ' ');
749 expand_macro ('f', expanded_exec, info, uris);
752 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
753 g_string_free (expanded_exec, TRUE);
758 prepend_terminal_to_vector (int *argc,
765 char **term_argv = NULL;
770 g_return_val_if_fail (argc != NULL, FALSE);
771 g_return_val_if_fail (argv != NULL, FALSE);
779 /* compute size if not given */
782 for (i = 0; the_argv[i] != NULL; i++)
788 term_argv = g_new0 (char *, 3);
790 check = g_find_program_in_path ("gnome-terminal");
793 term_argv[0] = check;
794 /* Note that gnome-terminal takes -x and
795 * as -e in gnome-terminal is broken we use that. */
796 term_argv[1] = g_strdup ("-x");
801 check = g_find_program_in_path ("nxterm");
803 check = g_find_program_in_path ("color-xterm");
805 check = g_find_program_in_path ("rxvt");
807 check = g_find_program_in_path ("xterm");
809 check = g_find_program_in_path ("dtterm");
812 check = g_strdup ("xterm");
813 g_warning ("couldn't find a terminal, falling back to xterm");
815 term_argv[0] = check;
816 term_argv[1] = g_strdup ("-e");
819 real_argc = term_argc + *argc;
820 real_argv = g_new (char *, real_argc + 1);
822 for (i = 0; i < term_argc; i++)
823 real_argv[i] = term_argv[i];
825 for (j = 0; j < *argc; j++, i++)
826 real_argv[i] = (char *)the_argv[j];
834 /* we use g_free here as we sucked all the inner strings
835 * out from it into real_argv */
840 #endif /* G_OS_WIN32 */
844 uri_list_segment_to_files (GList *start,
851 while (start != NULL && start != end)
853 file = g_file_new_for_uri ((char *)start->data);
854 res = g_list_prepend (res, file);
858 return g_list_reverse (res);
868 child_setup (gpointer user_data)
870 ChildSetupData *data = user_data;
873 g_setenv ("DISPLAY", data->display, TRUE);
876 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
880 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
882 GAppLaunchContext *launch_context,
885 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
886 gboolean completed = FALSE;
888 GList *launched_files;
893 g_return_val_if_fail (appinfo != NULL, FALSE);
900 if (!expand_application_parameters (info, &uris,
901 &argc, &argv, error))
904 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
906 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
907 _("Unable to find terminal required for application"));
916 launched_files = uri_list_segment_to_files (old_uris, uris);
918 data.display = g_app_launch_context_get_display (launch_context,
922 if (info->startup_notify)
923 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
926 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
927 g_list_free (launched_files);
930 if (!g_spawn_async (info->path,
940 g_app_launch_context_launch_failed (launch_context, data.sn_id);
943 g_free (data.display);
949 g_free (data.display);
954 while (uris != NULL);
965 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
967 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
970 ((strstr (info->exec, "%u") != NULL) ||
971 (strstr (info->exec, "%U") != NULL));
975 g_desktop_app_info_supports_files (GAppInfo *appinfo)
977 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
980 ((strstr (info->exec, "%f") != NULL) ||
981 (strstr (info->exec, "%F") != NULL));
985 g_desktop_app_info_launch (GAppInfo *appinfo,
987 GAppLaunchContext *launch_context,
997 uri = g_file_get_uri (files->data);
998 uris = g_list_prepend (uris, uri);
1002 uris = g_list_reverse (uris);
1004 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1006 g_list_foreach (uris, (GFunc)g_free, NULL);
1012 G_LOCK_DEFINE_STATIC (g_desktop_env);
1013 static gchar *g_desktop_env = NULL;
1016 * g_desktop_app_info_set_desktop_env:
1017 * @desktop_env: a string specifying what desktop this is
1019 * Sets the name of the desktop that the application is running in.
1020 * This is used by g_app_info_should_show() to evaluate the
1021 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1022 * desktop entry fields.
1024 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1025 * Menu specification</ulink> recognizes the following:
1027 * <member>GNOME</member>
1028 * <member>KDE</member>
1029 * <member>ROX</member>
1030 * <member>XFCE</member>
1031 * <member>Old</member>
1034 * Should be called only once; subsequent calls are ignored.
1037 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1039 G_LOCK (g_desktop_env);
1041 g_desktop_env = g_strdup (desktop_env);
1042 G_UNLOCK (g_desktop_env);
1046 g_desktop_app_info_should_show (GAppInfo *appinfo)
1048 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1050 const gchar *desktop_env;
1053 if (info->nodisplay)
1056 G_LOCK (g_desktop_env);
1057 desktop_env = g_desktop_env;
1058 G_UNLOCK (g_desktop_env);
1060 if (info->only_show_in)
1062 if (desktop_env == NULL)
1066 for (i = 0; info->only_show_in[i] != NULL; i++)
1068 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1078 if (info->not_show_in && desktop_env)
1080 for (i = 0; info->not_show_in[i] != NULL; i++)
1082 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1096 ensure_dir (DirType type,
1099 char *path, *display_name;
1102 if (type == APP_DIR)
1103 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1105 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1108 if (g_mkdir_with_parents (path, 0700) == 0)
1112 display_name = g_filename_display_name (path);
1113 if (type == APP_DIR)
1114 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1115 _("Can't create user application configuration folder %s: %s"),
1116 display_name, g_strerror (errsv));
1118 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1119 _("Can't create user MIME configuration folder %s: %s"),
1120 display_name, g_strerror (errsv));
1122 g_free (display_name);
1129 update_mimeapps_list (const char *desktop_id,
1130 const char *content_type,
1131 gboolean add_as_default,
1132 gboolean add_non_default,
1136 char *dirname, *filename;
1138 gboolean load_succeeded, res;
1139 char **old_list, **list;
1140 GList *system_list, *l;
1141 gsize length, data_size;
1144 char **content_types;
1146 /* Don't add both at start and end */
1147 g_assert (!(add_as_default && add_non_default));
1149 dirname = ensure_dir (APP_DIR, error);
1153 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1156 key_file = g_key_file_new ();
1157 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1158 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1160 g_key_file_free (key_file);
1161 key_file = g_key_file_new ();
1166 content_types = g_new (char *, 2);
1167 content_types[0] = g_strdup (content_type);
1168 content_types[1] = NULL;
1172 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1175 for (k = 0; content_types && content_types[k]; k++)
1177 /* Add to the right place in the list */
1180 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1181 content_types[k], &length, NULL);
1183 list = g_new (char *, 1 + length + 1);
1187 list[i++] = g_strdup (desktop_id);
1190 for (j = 0; old_list[j] != NULL; j++)
1192 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1193 list[i++] = g_strdup (old_list[j]);
1194 else if (add_non_default)
1196 /* If adding as non-default, and it's already in,
1197 don't change order of desktop ids */
1198 add_non_default = FALSE;
1199 list[i++] = g_strdup (old_list[j]);
1204 if (add_non_default)
1206 /* We're adding as non-default, and it wasn't already in the list,
1207 so we add at the end. But to avoid listing the app before the
1208 current system default (thus changing the default) we have to
1209 add the current list of (not yet listed) apps before it. */
1211 list[i] = NULL; /* Terminate current list so we can use it */
1212 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1214 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1216 for (l = system_list; l != NULL; l = l->next)
1218 list[i++] = l->data; /* no strdup, taking ownership */
1219 if (g_strcmp0 (l->data, desktop_id) == 0)
1220 add_non_default = FALSE;
1222 g_list_free (system_list);
1224 if (add_non_default)
1225 list[i++] = g_strdup (desktop_id);
1230 g_strfreev (old_list);
1232 if (list[0] == NULL || desktop_id == NULL)
1233 g_key_file_remove_key (key_file,
1234 ADDED_ASSOCIATIONS_GROUP,
1238 g_key_file_set_string_list (key_file,
1239 ADDED_ASSOCIATIONS_GROUP,
1241 (const char * const *)list, i);
1248 /* reuse the list from above */
1252 g_strfreev (content_types);
1253 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1256 for (k = 0; content_types && content_types[k]; k++)
1258 /* Remove from removed associations group (unless remove) */
1261 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1262 content_types[k], &length, NULL);
1264 list = g_new (char *, 1 + length + 1);
1268 list[i++] = g_strdup (desktop_id);
1271 for (j = 0; old_list[j] != NULL; j++)
1273 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1274 list[i++] = g_strdup (old_list[j]);
1279 g_strfreev (old_list);
1281 if (list[0] == NULL || desktop_id == NULL)
1282 g_key_file_remove_key (key_file,
1283 REMOVED_ASSOCIATIONS_GROUP,
1287 g_key_file_set_string_list (key_file,
1288 REMOVED_ASSOCIATIONS_GROUP,
1290 (const char * const *)list, i);
1295 g_strfreev (content_types);
1297 data = g_key_file_to_data (key_file, &data_size, error);
1298 g_key_file_free (key_file);
1300 res = g_file_set_contents (filename, data, data_size, error);
1302 mime_info_cache_reload (NULL);
1311 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1312 const char *content_type,
1315 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1317 if (!g_desktop_app_info_ensure_saved (info, error))
1320 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1324 update_program_done (GPid pid,
1328 /* Did the application exit correctly */
1329 if (WIFEXITED (status) &&
1330 WEXITSTATUS (status) == 0)
1332 /* Here we could clean out any caches in use */
1337 run_update_command (char *command,
1346 GError *error = NULL;
1349 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1351 if (g_spawn_async ("/", argv,
1353 G_SPAWN_SEARCH_PATH |
1354 G_SPAWN_STDOUT_TO_DEV_NULL |
1355 G_SPAWN_STDERR_TO_DEV_NULL |
1356 G_SPAWN_DO_NOT_REAP_CHILD,
1357 NULL, NULL, /* No setup function */
1360 g_child_watch_add (pid, update_program_done, NULL);
1363 /* If we get an error at this point, it's quite likely the user doesn't
1364 * have an installed copy of either 'update-mime-database' or
1365 * 'update-desktop-database'. I don't think we want to popup an error
1366 * dialog at this point, so we just do a g_warning to give the user a
1367 * chance of debugging it.
1369 g_warning ("%s", error->message);
1376 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1377 const char *extension,
1380 char *filename, *basename, *mimetype;
1384 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1387 dirname = ensure_dir (MIMETYPE_DIR, error);
1391 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1392 filename = g_build_filename (dirname, basename, NULL);
1396 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1398 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1403 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1404 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1405 " <mime-type type=\"%s\">\n"
1406 " <comment>%s document</comment>\n"
1407 " <glob pattern=\"*.%s\"/>\n"
1409 "</mime-info>\n", mimetype, extension, extension);
1411 g_file_set_contents (filename, contents, -1, NULL);
1414 run_update_command ("update-mime-database", "mime");
1418 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1428 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1429 const char *content_type,
1432 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1434 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1437 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1441 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1447 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1448 const char *content_type,
1451 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1453 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1456 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1460 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1466 char *data, *desktop_id;
1471 if (info->filename != NULL)
1474 /* This is only used for object created with
1475 * g_app_info_create_from_commandline. All other
1476 * object should have a filename
1479 dirname = ensure_dir (APP_DIR, error);
1483 key_file = g_key_file_new ();
1485 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1486 "Encoding", "UTF-8");
1487 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1488 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1489 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1490 G_KEY_FILE_DESKTOP_KEY_TYPE,
1491 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1493 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1494 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1496 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1497 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1499 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1500 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1502 if (info->fullname != NULL)
1503 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1504 FULL_NAME_KEY, info->fullname);
1506 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1507 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1509 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1510 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1512 data = g_key_file_to_data (key_file, &data_size, NULL);
1513 g_key_file_free (key_file);
1515 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1516 filename = g_build_filename (dirname, desktop_id, NULL);
1517 g_free (desktop_id);
1520 fd = g_mkstemp (filename);
1525 display_name = g_filename_display_name (filename);
1526 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1527 _("Can't create user desktop file %s"), display_name);
1528 g_free (display_name);
1534 desktop_id = g_path_get_basename (filename);
1538 res = g_file_set_contents (filename, data, data_size, error);
1541 g_free (desktop_id);
1546 info->filename = filename;
1547 info->desktop_id = desktop_id;
1549 run_update_command ("update-desktop-database", "applications");
1555 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1557 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1561 if (strstr (info->filename, "/userapp-"))
1562 return g_access (info->filename, W_OK) == 0;
1569 g_desktop_app_info_delete (GAppInfo *appinfo)
1571 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1575 if (g_remove (info->filename) == 0)
1577 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1579 g_free (info->filename);
1580 info->filename = NULL;
1581 g_free (info->desktop_id);
1582 info->desktop_id = NULL;
1592 * g_app_info_create_from_commandline:
1593 * @commandline: the commandline to use
1594 * @application_name: the application name, or %NULL to use @commandline
1595 * @flags: flags that can specify details of the created #GAppInfo
1596 * @error: a #GError location to store the error occuring, %NULL to ignore.
1598 * Creates a new #GAppInfo from the given information.
1600 * Returns: new #GAppInfo for given command.
1603 g_app_info_create_from_commandline (const char *commandline,
1604 const char *application_name,
1605 GAppInfoCreateFlags flags,
1610 GDesktopAppInfo *info;
1612 g_return_val_if_fail (commandline, NULL);
1614 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1616 info->filename = NULL;
1617 info->desktop_id = NULL;
1619 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1620 info->startup_notify = FALSE;
1621 info->hidden = FALSE;
1622 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1623 info->exec = g_strconcat (commandline, " %u", NULL);
1625 info->exec = g_strconcat (commandline, " %f", NULL);
1626 info->nodisplay = TRUE;
1627 info->binary = binary_from_exec (info->exec);
1629 if (application_name)
1630 info->name = g_strdup (application_name);
1633 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1634 split = g_strsplit (commandline, " ", 2);
1635 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1637 info->name = basename;
1638 if (info->name == NULL)
1639 info->name = g_strdup ("custom");
1641 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1643 return G_APP_INFO (info);
1647 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1649 iface->dup = g_desktop_app_info_dup;
1650 iface->equal = g_desktop_app_info_equal;
1651 iface->get_id = g_desktop_app_info_get_id;
1652 iface->get_name = g_desktop_app_info_get_name;
1653 iface->get_description = g_desktop_app_info_get_description;
1654 iface->get_executable = g_desktop_app_info_get_executable;
1655 iface->get_icon = g_desktop_app_info_get_icon;
1656 iface->launch = g_desktop_app_info_launch;
1657 iface->supports_uris = g_desktop_app_info_supports_uris;
1658 iface->supports_files = g_desktop_app_info_supports_files;
1659 iface->launch_uris = g_desktop_app_info_launch_uris;
1660 iface->should_show = g_desktop_app_info_should_show;
1661 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1662 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1663 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1664 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1665 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1666 iface->can_delete = g_desktop_app_info_can_delete;
1667 iface->do_delete = g_desktop_app_info_delete;
1668 iface->get_commandline = g_desktop_app_info_get_commandline;
1669 iface->get_display_name = g_desktop_app_info_get_display_name;
1673 app_info_in_list (GAppInfo *info,
1676 while (list != NULL)
1678 if (g_app_info_equal (info, list->data))
1687 * g_app_info_get_all_for_type:
1688 * @content_type: the content type to find a #GAppInfo for
1690 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1692 * Returns: #GList of #GAppInfo<!-- -->s for given @content_type
1693 * or %NULL on error.
1696 g_app_info_get_all_for_type (const char *content_type)
1698 GList *desktop_entries, *l;
1700 GDesktopAppInfo *info;
1702 g_return_val_if_fail (content_type != NULL, NULL);
1704 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1707 for (l = desktop_entries; l != NULL; l = l->next)
1709 char *desktop_entry = l->data;
1711 info = g_desktop_app_info_new (desktop_entry);
1714 if (app_info_in_list (G_APP_INFO (info), infos))
1715 g_object_unref (info);
1717 infos = g_list_prepend (infos, info);
1719 g_free (desktop_entry);
1722 g_list_free (desktop_entries);
1724 return g_list_reverse (infos);
1728 * g_app_info_reset_type_associations:
1729 * @content_type: a content type
1731 * Removes all changes to the type associations done by
1732 * g_app_info_set_as_default_for_type(),
1733 * g_app_info_set_as_default_for_extension(),
1734 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1739 g_app_info_reset_type_associations (const char *content_type)
1741 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1745 * g_app_info_get_default_for_type:
1746 * @content_type: the content type to find a #GAppInfo for
1747 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1750 * Gets the #GAppInfo that corresponds to a given content type.
1752 * Returns: #GAppInfo for given @content_type or %NULL on error.
1755 g_app_info_get_default_for_type (const char *content_type,
1756 gboolean must_support_uris)
1758 GList *desktop_entries, *l;
1761 g_return_val_if_fail (content_type != NULL, NULL);
1763 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1766 for (l = desktop_entries; l != NULL; l = l->next)
1768 char *desktop_entry = l->data;
1770 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1773 if (must_support_uris && !g_app_info_supports_uris (info))
1775 g_object_unref (info);
1783 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1784 g_list_free (desktop_entries);
1790 * g_app_info_get_default_for_uri_scheme:
1791 * @uri_scheme: a string containing a URI scheme.
1793 * Gets the default application for launching applications
1794 * using this URI scheme. A URI scheme is the initial part
1795 * of the URI, up to but not including the ':', e.g. "http",
1798 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1801 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1803 static gsize lookup = 0;
1805 if (g_once_init_enter (&lookup))
1807 gsize setup_value = 1;
1808 GDesktopAppInfoLookup *lookup_instance;
1809 const char *use_this;
1810 GIOExtensionPoint *ep;
1811 GIOExtension *extension;
1814 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1816 /* Ensure vfs in modules loaded */
1817 _g_io_modules_ensure_loaded ();
1819 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1821 lookup_instance = NULL;
1824 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1826 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1829 if (lookup_instance == NULL)
1831 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1833 extension = l->data;
1834 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1835 if (lookup_instance != NULL)
1840 if (lookup_instance != NULL)
1841 setup_value = (gsize)lookup_instance;
1843 g_once_init_leave (&lookup, setup_value);
1849 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1855 get_apps_from_dir (GHashTable *apps,
1856 const char *dirname,
1860 const char *basename;
1861 char *filename, *subprefix, *desktop_id;
1863 GDesktopAppInfo *appinfo;
1865 dir = g_dir_open (dirname, 0, NULL);
1868 while ((basename = g_dir_read_name (dir)) != NULL)
1870 filename = g_build_filename (dirname, basename, NULL);
1871 if (g_str_has_suffix (basename, ".desktop"))
1873 desktop_id = g_strconcat (prefix, basename, NULL);
1875 /* Use _extended so we catch NULLs too (hidden) */
1876 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1878 appinfo = g_desktop_app_info_new_from_filename (filename);
1881 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1883 g_object_unref (appinfo);
1888 if (appinfo || hidden)
1890 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1894 /* Reuse instead of strdup here */
1895 appinfo->desktop_id = desktop_id;
1900 g_free (desktop_id);
1904 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1906 subprefix = g_strconcat (prefix, basename, "-", NULL);
1907 get_apps_from_dir (apps, filename, subprefix);
1919 * g_app_info_get_all:
1921 * Gets a list of all of the applications currently registered
1924 * For desktop files, this includes applications that have
1925 * <literal>NoDisplay=true</literal> set or are excluded from
1926 * display by means of <literal>OnlyShowIn</literal> or
1927 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1928 * The returned list does not include applications which have
1929 * the <literal>Hidden</literal> key set.
1931 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1934 g_app_info_get_all (void)
1936 const char * const *dirs;
1938 GHashTableIter iter;
1943 dirs = get_applications_search_path ();
1945 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1949 for (i = 0; dirs[i] != NULL; i++)
1950 get_apps_from_dir (apps, dirs[i], "");
1954 g_hash_table_iter_init (&iter, apps);
1955 while (g_hash_table_iter_next (&iter, NULL, &value))
1958 infos = g_list_prepend (infos, value);
1961 g_hash_table_destroy (apps);
1963 return g_list_reverse (infos);
1966 /* Cacheing of mimeinfo.cache and defaults.list files */
1970 GHashTable *mime_info_cache_map;
1971 GHashTable *defaults_list_map;
1972 GHashTable *mimeapps_list_added_map;
1973 GHashTable *mimeapps_list_removed_map;
1974 time_t mime_info_cache_timestamp;
1975 time_t defaults_list_timestamp;
1976 time_t mimeapps_list_timestamp;
1980 GList *dirs; /* mimeinfo.cache and defaults.list */
1981 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1982 time_t last_stat_time;
1983 guint should_ping_mime_monitor : 1;
1986 static MimeInfoCache *mime_info_cache = NULL;
1987 G_LOCK_DEFINE_STATIC (mime_info_cache);
1989 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
1990 const char *mime_type,
1991 char **new_desktop_file_ids);
1993 static MimeInfoCache * mime_info_cache_new (void);
1996 destroy_info_cache_value (gpointer key,
2000 g_list_foreach (value, (GFunc)g_free, NULL);
2001 g_list_free (value);
2005 destroy_info_cache_map (GHashTable *info_cache_map)
2007 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2008 g_hash_table_destroy (info_cache_map);
2012 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2013 const char *cache_file,
2019 filename = g_build_filename (dir->path, cache_file, NULL);
2021 if (g_stat (filename, &buf) < 0)
2028 if (buf.st_mtime != *timestamp)
2034 /* Call with lock held */
2036 remove_all (gpointer key,
2045 mime_info_cache_blow_global_cache (void)
2047 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2052 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2056 gchar *filename, **mime_types;
2063 if (dir->mime_info_cache_map != NULL &&
2064 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2065 &dir->mime_info_cache_timestamp))
2068 if (dir->mime_info_cache_map != NULL)
2069 destroy_info_cache_map (dir->mime_info_cache_map);
2071 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2072 (GDestroyNotify) g_free,
2075 key_file = g_key_file_new ();
2077 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2079 if (g_stat (filename, &buf) < 0)
2082 if (dir->mime_info_cache_timestamp > 0)
2083 mime_info_cache->should_ping_mime_monitor = TRUE;
2085 dir->mime_info_cache_timestamp = buf.st_mtime;
2087 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2092 if (load_error != NULL)
2095 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2098 if (load_error != NULL)
2101 for (i = 0; mime_types[i] != NULL; i++)
2103 gchar **desktop_file_ids;
2104 char *unaliased_type;
2105 desktop_file_ids = g_key_file_get_string_list (key_file,
2111 if (desktop_file_ids == NULL)
2114 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2115 mime_info_cache_dir_add_desktop_entries (dir,
2118 g_free (unaliased_type);
2120 g_strfreev (desktop_file_ids);
2123 g_strfreev (mime_types);
2124 g_key_file_free (key_file);
2129 g_key_file_free (key_file);
2131 if (mime_types != NULL)
2132 g_strfreev (mime_types);
2135 g_error_free (load_error);
2139 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2143 gchar *filename, **mime_types;
2144 char *unaliased_type;
2145 char **desktop_file_ids;
2152 if (dir->defaults_list_map != NULL &&
2153 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2154 &dir->defaults_list_timestamp))
2157 if (dir->defaults_list_map != NULL)
2158 g_hash_table_destroy (dir->defaults_list_map);
2159 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2160 g_free, (GDestroyNotify)g_strfreev);
2163 key_file = g_key_file_new ();
2165 filename = g_build_filename (dir->path, "defaults.list", NULL);
2166 if (g_stat (filename, &buf) < 0)
2169 if (dir->defaults_list_timestamp > 0)
2170 mime_info_cache->should_ping_mime_monitor = TRUE;
2172 dir->defaults_list_timestamp = buf.st_mtime;
2174 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2178 if (load_error != NULL)
2181 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2183 if (mime_types != NULL)
2185 for (i = 0; mime_types[i] != NULL; i++)
2187 desktop_file_ids = g_key_file_get_string_list (key_file,
2188 DEFAULT_APPLICATIONS_GROUP,
2192 if (desktop_file_ids == NULL)
2195 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2196 g_hash_table_replace (dir->defaults_list_map,
2201 g_strfreev (mime_types);
2204 g_key_file_free (key_file);
2209 g_key_file_free (key_file);
2211 if (mime_types != NULL)
2212 g_strfreev (mime_types);
2215 g_error_free (load_error);
2219 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2223 gchar *filename, **mime_types;
2224 char *unaliased_type;
2225 char **desktop_file_ids;
2232 if (dir->mimeapps_list_added_map != NULL &&
2233 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2234 &dir->mimeapps_list_timestamp))
2237 if (dir->mimeapps_list_added_map != NULL)
2238 g_hash_table_destroy (dir->mimeapps_list_added_map);
2239 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2240 g_free, (GDestroyNotify)g_strfreev);
2242 if (dir->mimeapps_list_removed_map != NULL)
2243 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2244 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2245 g_free, (GDestroyNotify)g_strfreev);
2247 key_file = g_key_file_new ();
2249 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2250 if (g_stat (filename, &buf) < 0)
2253 if (dir->mimeapps_list_timestamp > 0)
2254 mime_info_cache->should_ping_mime_monitor = TRUE;
2256 dir->mimeapps_list_timestamp = buf.st_mtime;
2258 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2262 if (load_error != NULL)
2265 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2267 if (mime_types != NULL)
2269 for (i = 0; mime_types[i] != NULL; i++)
2271 desktop_file_ids = g_key_file_get_string_list (key_file,
2272 ADDED_ASSOCIATIONS_GROUP,
2276 if (desktop_file_ids == NULL)
2279 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2280 g_hash_table_replace (dir->mimeapps_list_added_map,
2285 g_strfreev (mime_types);
2288 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2290 if (mime_types != NULL)
2292 for (i = 0; mime_types[i] != NULL; i++)
2294 desktop_file_ids = g_key_file_get_string_list (key_file,
2295 REMOVED_ASSOCIATIONS_GROUP,
2299 if (desktop_file_ids == NULL)
2302 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2303 g_hash_table_replace (dir->mimeapps_list_removed_map,
2308 g_strfreev (mime_types);
2311 g_key_file_free (key_file);
2316 g_key_file_free (key_file);
2318 if (mime_types != NULL)
2319 g_strfreev (mime_types);
2322 g_error_free (load_error);
2325 static MimeInfoCacheDir *
2326 mime_info_cache_dir_new (const char *path)
2328 MimeInfoCacheDir *dir;
2330 dir = g_new0 (MimeInfoCacheDir, 1);
2331 dir->path = g_strdup (path);
2337 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2342 if (dir->mime_info_cache_map != NULL)
2344 destroy_info_cache_map (dir->mime_info_cache_map);
2345 dir->mime_info_cache_map = NULL;
2349 if (dir->defaults_list_map != NULL)
2351 g_hash_table_destroy (dir->defaults_list_map);
2352 dir->defaults_list_map = NULL;
2355 if (dir->mimeapps_list_added_map != NULL)
2357 g_hash_table_destroy (dir->mimeapps_list_added_map);
2358 dir->mimeapps_list_added_map = NULL;
2361 if (dir->mimeapps_list_removed_map != NULL)
2363 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2364 dir->mimeapps_list_removed_map = NULL;
2371 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2372 const char *mime_type,
2373 char **new_desktop_file_ids)
2375 GList *desktop_file_ids;
2378 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2381 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2383 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2384 desktop_file_ids = g_list_append (desktop_file_ids,
2385 g_strdup (new_desktop_file_ids[i]));
2388 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2392 mime_info_cache_init_dir_lists (void)
2394 const char * const *dirs;
2397 mime_info_cache = mime_info_cache_new ();
2399 dirs = get_applications_search_path ();
2401 for (i = 0; dirs[i] != NULL; i++)
2403 MimeInfoCacheDir *dir;
2405 dir = mime_info_cache_dir_new (dirs[i]);
2409 mime_info_cache_dir_init (dir);
2410 mime_info_cache_dir_init_defaults_list (dir);
2411 mime_info_cache_dir_init_mimeapps_list (dir);
2413 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2419 mime_info_cache_update_dir_lists (void)
2423 tmp = mime_info_cache->dirs;
2427 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2429 /* No need to do this if we had file monitors... */
2430 mime_info_cache_blow_global_cache ();
2431 mime_info_cache_dir_init (dir);
2432 mime_info_cache_dir_init_defaults_list (dir);
2433 mime_info_cache_dir_init_mimeapps_list (dir);
2440 mime_info_cache_init (void)
2442 G_LOCK (mime_info_cache);
2443 if (mime_info_cache == NULL)
2444 mime_info_cache_init_dir_lists ();
2450 if (now >= mime_info_cache->last_stat_time + 10)
2452 mime_info_cache_update_dir_lists ();
2453 mime_info_cache->last_stat_time = now;
2457 if (mime_info_cache->should_ping_mime_monitor)
2459 /* g_idle_add (emit_mime_changed, NULL); */
2460 mime_info_cache->should_ping_mime_monitor = FALSE;
2463 G_UNLOCK (mime_info_cache);
2466 static MimeInfoCache *
2467 mime_info_cache_new (void)
2469 MimeInfoCache *cache;
2471 cache = g_new0 (MimeInfoCache, 1);
2473 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2474 (GDestroyNotify) g_free,
2475 (GDestroyNotify) g_free);
2480 mime_info_cache_free (MimeInfoCache *cache)
2485 g_list_foreach (cache->dirs,
2486 (GFunc) mime_info_cache_dir_free,
2488 g_list_free (cache->dirs);
2489 g_hash_table_destroy (cache->global_defaults_cache);
2494 * mime_info_cache_reload:
2495 * @dir: directory path which needs reloading.
2497 * Reload the mime information for the @dir.
2500 mime_info_cache_reload (const char *dir)
2502 /* FIXME: just reload the dir that needs reloading,
2503 * don't blow the whole cache
2505 if (mime_info_cache != NULL)
2507 G_LOCK (mime_info_cache);
2508 mime_info_cache_free (mime_info_cache);
2509 mime_info_cache = NULL;
2510 G_UNLOCK (mime_info_cache);
2515 append_desktop_entry (GList *list,
2516 const char *desktop_entry,
2517 GList *removed_entries)
2519 /* Add if not already in list, and valid */
2520 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2521 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2522 list = g_list_prepend (list, g_strdup (desktop_entry));
2528 * get_all_desktop_entries_for_mime_type:
2529 * @mime_type: a mime type.
2530 * @except: NULL or a strv list
2532 * Returns all the desktop ids for @mime_type. The desktop files
2533 * are listed in an order so that default applications are listed before
2534 * non-default ones, and handlers for inherited mimetypes are listed
2535 * after the base ones.
2537 * Optionally doesn't list the desktop ids given in the @except
2539 * Return value: a #GList containing the desktop ids which claim
2540 * to handle @mime_type.
2543 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2544 const char **except)
2546 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2547 MimeInfoCacheDir *dir;
2550 char **default_entries;
2551 char **removed_associations;
2556 mime_info_cache_init ();
2558 /* collect all ancestors */
2559 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2560 array = g_ptr_array_new ();
2561 for (i = 0; mime_types[i]; i++)
2562 g_ptr_array_add (array, mime_types[i]);
2563 g_free (mime_types);
2564 for (i = 0; i < array->len; i++)
2566 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2567 for (j = 0; anc[j]; j++)
2569 for (k = 0; k < array->len; k++)
2571 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2574 if (k == array->len) /* not found */
2575 g_ptr_array_add (array, g_strdup (anc[j]));
2579 g_ptr_array_add (array, NULL);
2580 mime_types = (char **)g_ptr_array_free (array, FALSE);
2582 G_LOCK (mime_info_cache);
2584 removed_entries = NULL;
2585 desktop_entries = NULL;
2587 for (i = 0; except != NULL && except[i] != NULL; i++)
2588 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2590 for (i = 0; mime_types[i] != NULL; i++)
2592 mime_type = mime_types[i];
2594 /* Go through all apps listed as defaults */
2595 for (dir_list = mime_info_cache->dirs;
2597 dir_list = dir_list->next)
2599 dir = dir_list->data;
2601 /* First added associations from mimeapps.list */
2602 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2603 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2604 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2606 /* Then removed associations from mimeapps.list */
2607 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2608 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2609 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2611 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2612 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2613 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2614 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2617 /* Go through all entries that support the mimetype */
2618 for (dir_list = mime_info_cache->dirs;
2620 dir_list = dir_list->next)
2622 dir = dir_list->data;
2624 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2625 for (tmp = list; tmp != NULL; tmp = tmp->next)
2626 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2630 G_UNLOCK (mime_info_cache);
2632 g_strfreev (mime_types);
2634 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2635 g_list_free (removed_entries);
2637 desktop_entries = g_list_reverse (desktop_entries);
2639 return desktop_entries;
2642 /* GDesktopAppInfoLookup interface: */
2644 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2645 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2648 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2653 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2654 * @lookup: a #GDesktopAppInfoLookup
2655 * @uri_scheme: a string containing a URI scheme.
2657 * Gets the default application for launching applications
2658 * using this URI scheme for a particular GDesktopAppInfoLookup
2661 * The GDesktopAppInfoLookup interface and this function is used
2662 * to implement g_app_info_get_default_for_uri_scheme() backends
2663 * in a GIO module. There is no reason for applications to use it
2664 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2666 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2669 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2670 const char *uri_scheme)
2672 GDesktopAppInfoLookupIface *iface;
2674 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2676 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2678 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2681 #define __G_DESKTOP_APP_INFO_C__
2682 #include "gioaliasdef.c"