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_filename:
499 * @info: a #GDesktopAppInfo
501 * When @info was created from a known filename, return it. In some
502 * situations such as the #GDesktopAppInfo returned from
503 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
505 * Returns: The full path to the file for @info, or %NULL if not known.
509 g_desktop_app_info_get_filename (GDesktopAppInfo *info)
511 return info->filename;
515 g_desktop_app_info_get_description (GAppInfo *appinfo)
517 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
519 return info->comment;
523 g_desktop_app_info_get_executable (GAppInfo *appinfo)
525 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
531 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
533 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
539 g_desktop_app_info_get_icon (GAppInfo *appinfo)
541 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
547 expand_macro_single (char macro, char *uri)
553 file = g_file_new_for_uri (uri);
554 path = g_file_get_path (file);
555 g_object_unref (file);
561 result = g_shell_quote (uri);
566 result = g_shell_quote (path);
572 name = g_path_get_dirname (path);
573 result = g_shell_quote (name);
581 name = g_path_get_basename (path);
582 result = g_shell_quote (name);
594 expand_macro (char macro,
596 GDesktopAppInfo *info,
599 GList *uris = *uri_list;
601 gboolean force_file_uri;
602 char force_file_uri_macro;
605 g_return_if_fail (exec != NULL);
607 /* On %u and %U, pass POSIX file path pointing to the URI via
608 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
609 * running or the URI doesn't have a POSIX file path via FUSE
610 * we'll just pass the URI.
612 force_file_uri_macro = macro;
613 force_file_uri = FALSE;
619 force_file_uri_macro = 'f';
620 force_file_uri = TRUE;
623 force_file_uri_macro = 'F';
624 force_file_uri = TRUE;
640 if (!force_file_uri ||
641 /* Pass URI if it contains an anchor */
642 strchr (uri, '#') != NULL)
644 expanded = expand_macro_single (macro, uri);
648 expanded = expand_macro_single (force_file_uri_macro, uri);
649 if (expanded == NULL)
650 expanded = expand_macro_single (macro, uri);
655 g_string_append (exec, expanded);
671 if (!force_file_uri ||
672 /* Pass URI if it contains an anchor */
673 strchr (uri, '#') != NULL)
675 expanded = expand_macro_single (macro, uri);
679 expanded = expand_macro_single (force_file_uri_macro, uri);
680 if (expanded == NULL)
681 expanded = expand_macro_single (macro, uri);
686 g_string_append (exec, expanded);
692 if (uris != NULL && expanded)
693 g_string_append_c (exec, ' ');
701 g_string_append (exec, "--icon ");
702 g_string_append (exec, info->icon_name);
708 g_string_append (exec, info->name);
713 g_string_append (exec, info->filename);
716 case 'm': /* deprecated */
720 g_string_append_c (exec, '%');
728 expand_application_parameters (GDesktopAppInfo *info,
734 GList *uri_list = *uris;
735 const char *p = info->exec;
736 GString *expanded_exec;
739 if (info->exec == NULL)
741 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
742 _("Desktop file didn't specify Exec field"));
746 expanded_exec = g_string_new (NULL);
750 if (p[0] == '%' && p[1] != '\0')
752 expand_macro (p[1], expanded_exec, info, uris);
756 g_string_append_c (expanded_exec, *p);
761 /* No file substitutions */
762 if (uri_list == *uris && uri_list != NULL)
764 /* If there is no macro default to %f. This is also what KDE does */
765 g_string_append_c (expanded_exec, ' ');
766 expand_macro ('f', expanded_exec, info, uris);
769 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
770 g_string_free (expanded_exec, TRUE);
775 prepend_terminal_to_vector (int *argc,
782 char **term_argv = NULL;
787 g_return_val_if_fail (argc != NULL, FALSE);
788 g_return_val_if_fail (argv != NULL, FALSE);
796 /* compute size if not given */
799 for (i = 0; the_argv[i] != NULL; i++)
805 term_argv = g_new0 (char *, 3);
807 check = g_find_program_in_path ("gnome-terminal");
810 term_argv[0] = check;
811 /* Note that gnome-terminal takes -x and
812 * as -e in gnome-terminal is broken we use that. */
813 term_argv[1] = g_strdup ("-x");
818 check = g_find_program_in_path ("nxterm");
820 check = g_find_program_in_path ("color-xterm");
822 check = g_find_program_in_path ("rxvt");
824 check = g_find_program_in_path ("xterm");
826 check = g_find_program_in_path ("dtterm");
829 check = g_strdup ("xterm");
830 g_warning ("couldn't find a terminal, falling back to xterm");
832 term_argv[0] = check;
833 term_argv[1] = g_strdup ("-e");
836 real_argc = term_argc + *argc;
837 real_argv = g_new (char *, real_argc + 1);
839 for (i = 0; i < term_argc; i++)
840 real_argv[i] = term_argv[i];
842 for (j = 0; j < *argc; j++, i++)
843 real_argv[i] = (char *)the_argv[j];
851 /* we use g_free here as we sucked all the inner strings
852 * out from it into real_argv */
857 #endif /* G_OS_WIN32 */
861 uri_list_segment_to_files (GList *start,
868 while (start != NULL && start != end)
870 file = g_file_new_for_uri ((char *)start->data);
871 res = g_list_prepend (res, file);
875 return g_list_reverse (res);
885 child_setup (gpointer user_data)
887 ChildSetupData *data = user_data;
890 g_setenv ("DISPLAY", data->display, TRUE);
893 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
897 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
899 GAppLaunchContext *launch_context,
902 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
903 gboolean completed = FALSE;
905 GList *launched_files;
910 g_return_val_if_fail (appinfo != NULL, FALSE);
917 if (!expand_application_parameters (info, &uris,
918 &argc, &argv, error))
921 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
923 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
924 _("Unable to find terminal required for application"));
933 launched_files = uri_list_segment_to_files (old_uris, uris);
935 data.display = g_app_launch_context_get_display (launch_context,
939 if (info->startup_notify)
940 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
943 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
944 g_list_free (launched_files);
947 if (!g_spawn_async (info->path,
957 g_app_launch_context_launch_failed (launch_context, data.sn_id);
960 g_free (data.display);
966 g_free (data.display);
971 while (uris != NULL);
982 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
984 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
987 ((strstr (info->exec, "%u") != NULL) ||
988 (strstr (info->exec, "%U") != NULL));
992 g_desktop_app_info_supports_files (GAppInfo *appinfo)
994 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
997 ((strstr (info->exec, "%f") != NULL) ||
998 (strstr (info->exec, "%F") != NULL));
1002 g_desktop_app_info_launch (GAppInfo *appinfo,
1004 GAppLaunchContext *launch_context,
1014 uri = g_file_get_uri (files->data);
1015 uris = g_list_prepend (uris, uri);
1016 files = files->next;
1019 uris = g_list_reverse (uris);
1021 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1023 g_list_foreach (uris, (GFunc)g_free, NULL);
1029 G_LOCK_DEFINE_STATIC (g_desktop_env);
1030 static gchar *g_desktop_env = NULL;
1033 * g_desktop_app_info_set_desktop_env:
1034 * @desktop_env: a string specifying what desktop this is
1036 * Sets the name of the desktop that the application is running in.
1037 * This is used by g_app_info_should_show() to evaluate the
1038 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1039 * desktop entry fields.
1041 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1042 * Menu specification</ulink> recognizes the following:
1044 * <member>GNOME</member>
1045 * <member>KDE</member>
1046 * <member>ROX</member>
1047 * <member>XFCE</member>
1048 * <member>Old</member>
1051 * Should be called only once; subsequent calls are ignored.
1054 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1056 G_LOCK (g_desktop_env);
1058 g_desktop_env = g_strdup (desktop_env);
1059 G_UNLOCK (g_desktop_env);
1063 g_desktop_app_info_should_show (GAppInfo *appinfo)
1065 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1067 const gchar *desktop_env;
1070 if (info->nodisplay)
1073 G_LOCK (g_desktop_env);
1074 desktop_env = g_desktop_env;
1075 G_UNLOCK (g_desktop_env);
1077 if (info->only_show_in)
1079 if (desktop_env == NULL)
1083 for (i = 0; info->only_show_in[i] != NULL; i++)
1085 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1095 if (info->not_show_in && desktop_env)
1097 for (i = 0; info->not_show_in[i] != NULL; i++)
1099 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1113 ensure_dir (DirType type,
1116 char *path, *display_name;
1119 if (type == APP_DIR)
1120 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1122 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1125 if (g_mkdir_with_parents (path, 0700) == 0)
1129 display_name = g_filename_display_name (path);
1130 if (type == APP_DIR)
1131 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1132 _("Can't create user application configuration folder %s: %s"),
1133 display_name, g_strerror (errsv));
1135 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1136 _("Can't create user MIME configuration folder %s: %s"),
1137 display_name, g_strerror (errsv));
1139 g_free (display_name);
1146 update_mimeapps_list (const char *desktop_id,
1147 const char *content_type,
1148 gboolean add_as_default,
1149 gboolean add_non_default,
1153 char *dirname, *filename;
1155 gboolean load_succeeded, res;
1156 char **old_list, **list;
1157 GList *system_list, *l;
1158 gsize length, data_size;
1161 char **content_types;
1163 /* Don't add both at start and end */
1164 g_assert (!(add_as_default && add_non_default));
1166 dirname = ensure_dir (APP_DIR, error);
1170 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1173 key_file = g_key_file_new ();
1174 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1175 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1177 g_key_file_free (key_file);
1178 key_file = g_key_file_new ();
1183 content_types = g_new (char *, 2);
1184 content_types[0] = g_strdup (content_type);
1185 content_types[1] = NULL;
1189 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1192 for (k = 0; content_types && content_types[k]; k++)
1194 /* Add to the right place in the list */
1197 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1198 content_types[k], &length, NULL);
1200 list = g_new (char *, 1 + length + 1);
1204 list[i++] = g_strdup (desktop_id);
1207 for (j = 0; old_list[j] != NULL; j++)
1209 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1210 list[i++] = g_strdup (old_list[j]);
1211 else if (add_non_default)
1213 /* If adding as non-default, and it's already in,
1214 don't change order of desktop ids */
1215 add_non_default = FALSE;
1216 list[i++] = g_strdup (old_list[j]);
1221 if (add_non_default)
1223 /* We're adding as non-default, and it wasn't already in the list,
1224 so we add at the end. But to avoid listing the app before the
1225 current system default (thus changing the default) we have to
1226 add the current list of (not yet listed) apps before it. */
1228 list[i] = NULL; /* Terminate current list so we can use it */
1229 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1231 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1233 for (l = system_list; l != NULL; l = l->next)
1235 list[i++] = l->data; /* no strdup, taking ownership */
1236 if (g_strcmp0 (l->data, desktop_id) == 0)
1237 add_non_default = FALSE;
1239 g_list_free (system_list);
1241 if (add_non_default)
1242 list[i++] = g_strdup (desktop_id);
1247 g_strfreev (old_list);
1249 if (list[0] == NULL || desktop_id == NULL)
1250 g_key_file_remove_key (key_file,
1251 ADDED_ASSOCIATIONS_GROUP,
1255 g_key_file_set_string_list (key_file,
1256 ADDED_ASSOCIATIONS_GROUP,
1258 (const char * const *)list, i);
1265 /* reuse the list from above */
1269 g_strfreev (content_types);
1270 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1273 for (k = 0; content_types && content_types[k]; k++)
1275 /* Remove from removed associations group (unless remove) */
1278 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1279 content_types[k], &length, NULL);
1281 list = g_new (char *, 1 + length + 1);
1285 list[i++] = g_strdup (desktop_id);
1288 for (j = 0; old_list[j] != NULL; j++)
1290 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1291 list[i++] = g_strdup (old_list[j]);
1296 g_strfreev (old_list);
1298 if (list[0] == NULL || desktop_id == NULL)
1299 g_key_file_remove_key (key_file,
1300 REMOVED_ASSOCIATIONS_GROUP,
1304 g_key_file_set_string_list (key_file,
1305 REMOVED_ASSOCIATIONS_GROUP,
1307 (const char * const *)list, i);
1312 g_strfreev (content_types);
1314 data = g_key_file_to_data (key_file, &data_size, error);
1315 g_key_file_free (key_file);
1317 res = g_file_set_contents (filename, data, data_size, error);
1319 mime_info_cache_reload (NULL);
1328 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1329 const char *content_type,
1332 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1334 if (!g_desktop_app_info_ensure_saved (info, error))
1337 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1341 update_program_done (GPid pid,
1345 /* Did the application exit correctly */
1346 if (WIFEXITED (status) &&
1347 WEXITSTATUS (status) == 0)
1349 /* Here we could clean out any caches in use */
1354 run_update_command (char *command,
1363 GError *error = NULL;
1366 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1368 if (g_spawn_async ("/", argv,
1370 G_SPAWN_SEARCH_PATH |
1371 G_SPAWN_STDOUT_TO_DEV_NULL |
1372 G_SPAWN_STDERR_TO_DEV_NULL |
1373 G_SPAWN_DO_NOT_REAP_CHILD,
1374 NULL, NULL, /* No setup function */
1377 g_child_watch_add (pid, update_program_done, NULL);
1380 /* If we get an error at this point, it's quite likely the user doesn't
1381 * have an installed copy of either 'update-mime-database' or
1382 * 'update-desktop-database'. I don't think we want to popup an error
1383 * dialog at this point, so we just do a g_warning to give the user a
1384 * chance of debugging it.
1386 g_warning ("%s", error->message);
1393 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1394 const char *extension,
1397 char *filename, *basename, *mimetype;
1401 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1404 dirname = ensure_dir (MIMETYPE_DIR, error);
1408 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1409 filename = g_build_filename (dirname, basename, NULL);
1413 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1415 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1420 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1421 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1422 " <mime-type type=\"%s\">\n"
1423 " <comment>%s document</comment>\n"
1424 " <glob pattern=\"*.%s\"/>\n"
1426 "</mime-info>\n", mimetype, extension, extension);
1428 g_file_set_contents (filename, contents, -1, NULL);
1431 run_update_command ("update-mime-database", "mime");
1435 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1445 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1446 const char *content_type,
1449 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1451 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1454 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1458 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1464 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1465 const char *content_type,
1468 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1470 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1473 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1477 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1483 char *data, *desktop_id;
1488 if (info->filename != NULL)
1491 /* This is only used for object created with
1492 * g_app_info_create_from_commandline. All other
1493 * object should have a filename
1496 dirname = ensure_dir (APP_DIR, error);
1500 key_file = g_key_file_new ();
1502 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1503 "Encoding", "UTF-8");
1504 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1505 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1506 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1507 G_KEY_FILE_DESKTOP_KEY_TYPE,
1508 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1510 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1511 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1513 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1514 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1516 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1517 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1519 if (info->fullname != NULL)
1520 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1521 FULL_NAME_KEY, info->fullname);
1523 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1524 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1526 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1527 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1529 data = g_key_file_to_data (key_file, &data_size, NULL);
1530 g_key_file_free (key_file);
1532 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1533 filename = g_build_filename (dirname, desktop_id, NULL);
1534 g_free (desktop_id);
1537 fd = g_mkstemp (filename);
1542 display_name = g_filename_display_name (filename);
1543 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1544 _("Can't create user desktop file %s"), display_name);
1545 g_free (display_name);
1551 desktop_id = g_path_get_basename (filename);
1555 res = g_file_set_contents (filename, data, data_size, error);
1558 g_free (desktop_id);
1563 info->filename = filename;
1564 info->desktop_id = desktop_id;
1566 run_update_command ("update-desktop-database", "applications");
1572 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1574 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1578 if (strstr (info->filename, "/userapp-"))
1579 return g_access (info->filename, W_OK) == 0;
1586 g_desktop_app_info_delete (GAppInfo *appinfo)
1588 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1592 if (g_remove (info->filename) == 0)
1594 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1596 g_free (info->filename);
1597 info->filename = NULL;
1598 g_free (info->desktop_id);
1599 info->desktop_id = NULL;
1609 * g_app_info_create_from_commandline:
1610 * @commandline: the commandline to use
1611 * @application_name: the application name, or %NULL to use @commandline
1612 * @flags: flags that can specify details of the created #GAppInfo
1613 * @error: a #GError location to store the error occuring, %NULL to ignore.
1615 * Creates a new #GAppInfo from the given information.
1617 * Returns: new #GAppInfo for given command.
1620 g_app_info_create_from_commandline (const char *commandline,
1621 const char *application_name,
1622 GAppInfoCreateFlags flags,
1627 GDesktopAppInfo *info;
1629 g_return_val_if_fail (commandline, NULL);
1631 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1633 info->filename = NULL;
1634 info->desktop_id = NULL;
1636 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1637 info->startup_notify = FALSE;
1638 info->hidden = FALSE;
1639 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1640 info->exec = g_strconcat (commandline, " %u", NULL);
1642 info->exec = g_strconcat (commandline, " %f", NULL);
1643 info->nodisplay = TRUE;
1644 info->binary = binary_from_exec (info->exec);
1646 if (application_name)
1647 info->name = g_strdup (application_name);
1650 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1651 split = g_strsplit (commandline, " ", 2);
1652 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1654 info->name = basename;
1655 if (info->name == NULL)
1656 info->name = g_strdup ("custom");
1658 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1660 return G_APP_INFO (info);
1664 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1666 iface->dup = g_desktop_app_info_dup;
1667 iface->equal = g_desktop_app_info_equal;
1668 iface->get_id = g_desktop_app_info_get_id;
1669 iface->get_name = g_desktop_app_info_get_name;
1670 iface->get_description = g_desktop_app_info_get_description;
1671 iface->get_executable = g_desktop_app_info_get_executable;
1672 iface->get_icon = g_desktop_app_info_get_icon;
1673 iface->launch = g_desktop_app_info_launch;
1674 iface->supports_uris = g_desktop_app_info_supports_uris;
1675 iface->supports_files = g_desktop_app_info_supports_files;
1676 iface->launch_uris = g_desktop_app_info_launch_uris;
1677 iface->should_show = g_desktop_app_info_should_show;
1678 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1679 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1680 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1681 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1682 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1683 iface->can_delete = g_desktop_app_info_can_delete;
1684 iface->do_delete = g_desktop_app_info_delete;
1685 iface->get_commandline = g_desktop_app_info_get_commandline;
1686 iface->get_display_name = g_desktop_app_info_get_display_name;
1690 app_info_in_list (GAppInfo *info,
1693 while (list != NULL)
1695 if (g_app_info_equal (info, list->data))
1704 * g_app_info_get_all_for_type:
1705 * @content_type: the content type to find a #GAppInfo for
1707 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1709 * Returns: #GList of #GAppInfo<!-- -->s for given @content_type
1710 * or %NULL on error.
1713 g_app_info_get_all_for_type (const char *content_type)
1715 GList *desktop_entries, *l;
1717 GDesktopAppInfo *info;
1719 g_return_val_if_fail (content_type != NULL, NULL);
1721 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1724 for (l = desktop_entries; l != NULL; l = l->next)
1726 char *desktop_entry = l->data;
1728 info = g_desktop_app_info_new (desktop_entry);
1731 if (app_info_in_list (G_APP_INFO (info), infos))
1732 g_object_unref (info);
1734 infos = g_list_prepend (infos, info);
1736 g_free (desktop_entry);
1739 g_list_free (desktop_entries);
1741 return g_list_reverse (infos);
1745 * g_app_info_reset_type_associations:
1746 * @content_type: a content type
1748 * Removes all changes to the type associations done by
1749 * g_app_info_set_as_default_for_type(),
1750 * g_app_info_set_as_default_for_extension(),
1751 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1756 g_app_info_reset_type_associations (const char *content_type)
1758 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1762 * g_app_info_get_default_for_type:
1763 * @content_type: the content type to find a #GAppInfo for
1764 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1767 * Gets the #GAppInfo that corresponds to a given content type.
1769 * Returns: #GAppInfo for given @content_type or %NULL on error.
1772 g_app_info_get_default_for_type (const char *content_type,
1773 gboolean must_support_uris)
1775 GList *desktop_entries, *l;
1778 g_return_val_if_fail (content_type != NULL, NULL);
1780 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1783 for (l = desktop_entries; l != NULL; l = l->next)
1785 char *desktop_entry = l->data;
1787 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1790 if (must_support_uris && !g_app_info_supports_uris (info))
1792 g_object_unref (info);
1800 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1801 g_list_free (desktop_entries);
1807 * g_app_info_get_default_for_uri_scheme:
1808 * @uri_scheme: a string containing a URI scheme.
1810 * Gets the default application for launching applications
1811 * using this URI scheme. A URI scheme is the initial part
1812 * of the URI, up to but not including the ':', e.g. "http",
1815 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1818 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1820 static gsize lookup = 0;
1822 if (g_once_init_enter (&lookup))
1824 gsize setup_value = 1;
1825 GDesktopAppInfoLookup *lookup_instance;
1826 const char *use_this;
1827 GIOExtensionPoint *ep;
1828 GIOExtension *extension;
1831 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1833 /* Ensure vfs in modules loaded */
1834 _g_io_modules_ensure_loaded ();
1836 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1838 lookup_instance = NULL;
1841 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1843 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1846 if (lookup_instance == NULL)
1848 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1850 extension = l->data;
1851 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1852 if (lookup_instance != NULL)
1857 if (lookup_instance != NULL)
1858 setup_value = (gsize)lookup_instance;
1860 g_once_init_leave (&lookup, setup_value);
1866 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1872 get_apps_from_dir (GHashTable *apps,
1873 const char *dirname,
1877 const char *basename;
1878 char *filename, *subprefix, *desktop_id;
1880 GDesktopAppInfo *appinfo;
1882 dir = g_dir_open (dirname, 0, NULL);
1885 while ((basename = g_dir_read_name (dir)) != NULL)
1887 filename = g_build_filename (dirname, basename, NULL);
1888 if (g_str_has_suffix (basename, ".desktop"))
1890 desktop_id = g_strconcat (prefix, basename, NULL);
1892 /* Use _extended so we catch NULLs too (hidden) */
1893 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1895 appinfo = g_desktop_app_info_new_from_filename (filename);
1898 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1900 g_object_unref (appinfo);
1905 if (appinfo || hidden)
1907 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1911 /* Reuse instead of strdup here */
1912 appinfo->desktop_id = desktop_id;
1917 g_free (desktop_id);
1921 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1923 subprefix = g_strconcat (prefix, basename, "-", NULL);
1924 get_apps_from_dir (apps, filename, subprefix);
1936 * g_app_info_get_all:
1938 * Gets a list of all of the applications currently registered
1941 * For desktop files, this includes applications that have
1942 * <literal>NoDisplay=true</literal> set or are excluded from
1943 * display by means of <literal>OnlyShowIn</literal> or
1944 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1945 * The returned list does not include applications which have
1946 * the <literal>Hidden</literal> key set.
1948 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1951 g_app_info_get_all (void)
1953 const char * const *dirs;
1955 GHashTableIter iter;
1960 dirs = get_applications_search_path ();
1962 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1966 for (i = 0; dirs[i] != NULL; i++)
1967 get_apps_from_dir (apps, dirs[i], "");
1971 g_hash_table_iter_init (&iter, apps);
1972 while (g_hash_table_iter_next (&iter, NULL, &value))
1975 infos = g_list_prepend (infos, value);
1978 g_hash_table_destroy (apps);
1980 return g_list_reverse (infos);
1983 /* Cacheing of mimeinfo.cache and defaults.list files */
1987 GHashTable *mime_info_cache_map;
1988 GHashTable *defaults_list_map;
1989 GHashTable *mimeapps_list_added_map;
1990 GHashTable *mimeapps_list_removed_map;
1991 time_t mime_info_cache_timestamp;
1992 time_t defaults_list_timestamp;
1993 time_t mimeapps_list_timestamp;
1997 GList *dirs; /* mimeinfo.cache and defaults.list */
1998 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1999 time_t last_stat_time;
2000 guint should_ping_mime_monitor : 1;
2003 static MimeInfoCache *mime_info_cache = NULL;
2004 G_LOCK_DEFINE_STATIC (mime_info_cache);
2006 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2007 const char *mime_type,
2008 char **new_desktop_file_ids);
2010 static MimeInfoCache * mime_info_cache_new (void);
2013 destroy_info_cache_value (gpointer key,
2017 g_list_foreach (value, (GFunc)g_free, NULL);
2018 g_list_free (value);
2022 destroy_info_cache_map (GHashTable *info_cache_map)
2024 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2025 g_hash_table_destroy (info_cache_map);
2029 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2030 const char *cache_file,
2036 filename = g_build_filename (dir->path, cache_file, NULL);
2038 if (g_stat (filename, &buf) < 0)
2045 if (buf.st_mtime != *timestamp)
2051 /* Call with lock held */
2053 remove_all (gpointer key,
2062 mime_info_cache_blow_global_cache (void)
2064 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2069 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2073 gchar *filename, **mime_types;
2080 if (dir->mime_info_cache_map != NULL &&
2081 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2082 &dir->mime_info_cache_timestamp))
2085 if (dir->mime_info_cache_map != NULL)
2086 destroy_info_cache_map (dir->mime_info_cache_map);
2088 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2089 (GDestroyNotify) g_free,
2092 key_file = g_key_file_new ();
2094 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2096 if (g_stat (filename, &buf) < 0)
2099 if (dir->mime_info_cache_timestamp > 0)
2100 mime_info_cache->should_ping_mime_monitor = TRUE;
2102 dir->mime_info_cache_timestamp = buf.st_mtime;
2104 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2109 if (load_error != NULL)
2112 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2115 if (load_error != NULL)
2118 for (i = 0; mime_types[i] != NULL; i++)
2120 gchar **desktop_file_ids;
2121 char *unaliased_type;
2122 desktop_file_ids = g_key_file_get_string_list (key_file,
2128 if (desktop_file_ids == NULL)
2131 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2132 mime_info_cache_dir_add_desktop_entries (dir,
2135 g_free (unaliased_type);
2137 g_strfreev (desktop_file_ids);
2140 g_strfreev (mime_types);
2141 g_key_file_free (key_file);
2146 g_key_file_free (key_file);
2148 if (mime_types != NULL)
2149 g_strfreev (mime_types);
2152 g_error_free (load_error);
2156 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2160 gchar *filename, **mime_types;
2161 char *unaliased_type;
2162 char **desktop_file_ids;
2169 if (dir->defaults_list_map != NULL &&
2170 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2171 &dir->defaults_list_timestamp))
2174 if (dir->defaults_list_map != NULL)
2175 g_hash_table_destroy (dir->defaults_list_map);
2176 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2177 g_free, (GDestroyNotify)g_strfreev);
2180 key_file = g_key_file_new ();
2182 filename = g_build_filename (dir->path, "defaults.list", NULL);
2183 if (g_stat (filename, &buf) < 0)
2186 if (dir->defaults_list_timestamp > 0)
2187 mime_info_cache->should_ping_mime_monitor = TRUE;
2189 dir->defaults_list_timestamp = buf.st_mtime;
2191 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2195 if (load_error != NULL)
2198 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2200 if (mime_types != NULL)
2202 for (i = 0; mime_types[i] != NULL; i++)
2204 desktop_file_ids = g_key_file_get_string_list (key_file,
2205 DEFAULT_APPLICATIONS_GROUP,
2209 if (desktop_file_ids == NULL)
2212 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2213 g_hash_table_replace (dir->defaults_list_map,
2218 g_strfreev (mime_types);
2221 g_key_file_free (key_file);
2226 g_key_file_free (key_file);
2228 if (mime_types != NULL)
2229 g_strfreev (mime_types);
2232 g_error_free (load_error);
2236 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2240 gchar *filename, **mime_types;
2241 char *unaliased_type;
2242 char **desktop_file_ids;
2249 if (dir->mimeapps_list_added_map != NULL &&
2250 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2251 &dir->mimeapps_list_timestamp))
2254 if (dir->mimeapps_list_added_map != NULL)
2255 g_hash_table_destroy (dir->mimeapps_list_added_map);
2256 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2257 g_free, (GDestroyNotify)g_strfreev);
2259 if (dir->mimeapps_list_removed_map != NULL)
2260 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2261 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2262 g_free, (GDestroyNotify)g_strfreev);
2264 key_file = g_key_file_new ();
2266 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2267 if (g_stat (filename, &buf) < 0)
2270 if (dir->mimeapps_list_timestamp > 0)
2271 mime_info_cache->should_ping_mime_monitor = TRUE;
2273 dir->mimeapps_list_timestamp = buf.st_mtime;
2275 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2279 if (load_error != NULL)
2282 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2284 if (mime_types != NULL)
2286 for (i = 0; mime_types[i] != NULL; i++)
2288 desktop_file_ids = g_key_file_get_string_list (key_file,
2289 ADDED_ASSOCIATIONS_GROUP,
2293 if (desktop_file_ids == NULL)
2296 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2297 g_hash_table_replace (dir->mimeapps_list_added_map,
2302 g_strfreev (mime_types);
2305 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2307 if (mime_types != NULL)
2309 for (i = 0; mime_types[i] != NULL; i++)
2311 desktop_file_ids = g_key_file_get_string_list (key_file,
2312 REMOVED_ASSOCIATIONS_GROUP,
2316 if (desktop_file_ids == NULL)
2319 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2320 g_hash_table_replace (dir->mimeapps_list_removed_map,
2325 g_strfreev (mime_types);
2328 g_key_file_free (key_file);
2333 g_key_file_free (key_file);
2335 if (mime_types != NULL)
2336 g_strfreev (mime_types);
2339 g_error_free (load_error);
2342 static MimeInfoCacheDir *
2343 mime_info_cache_dir_new (const char *path)
2345 MimeInfoCacheDir *dir;
2347 dir = g_new0 (MimeInfoCacheDir, 1);
2348 dir->path = g_strdup (path);
2354 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2359 if (dir->mime_info_cache_map != NULL)
2361 destroy_info_cache_map (dir->mime_info_cache_map);
2362 dir->mime_info_cache_map = NULL;
2366 if (dir->defaults_list_map != NULL)
2368 g_hash_table_destroy (dir->defaults_list_map);
2369 dir->defaults_list_map = NULL;
2372 if (dir->mimeapps_list_added_map != NULL)
2374 g_hash_table_destroy (dir->mimeapps_list_added_map);
2375 dir->mimeapps_list_added_map = NULL;
2378 if (dir->mimeapps_list_removed_map != NULL)
2380 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2381 dir->mimeapps_list_removed_map = NULL;
2388 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2389 const char *mime_type,
2390 char **new_desktop_file_ids)
2392 GList *desktop_file_ids;
2395 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2398 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2400 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2401 desktop_file_ids = g_list_append (desktop_file_ids,
2402 g_strdup (new_desktop_file_ids[i]));
2405 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2409 mime_info_cache_init_dir_lists (void)
2411 const char * const *dirs;
2414 mime_info_cache = mime_info_cache_new ();
2416 dirs = get_applications_search_path ();
2418 for (i = 0; dirs[i] != NULL; i++)
2420 MimeInfoCacheDir *dir;
2422 dir = mime_info_cache_dir_new (dirs[i]);
2426 mime_info_cache_dir_init (dir);
2427 mime_info_cache_dir_init_defaults_list (dir);
2428 mime_info_cache_dir_init_mimeapps_list (dir);
2430 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2436 mime_info_cache_update_dir_lists (void)
2440 tmp = mime_info_cache->dirs;
2444 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2446 /* No need to do this if we had file monitors... */
2447 mime_info_cache_blow_global_cache ();
2448 mime_info_cache_dir_init (dir);
2449 mime_info_cache_dir_init_defaults_list (dir);
2450 mime_info_cache_dir_init_mimeapps_list (dir);
2457 mime_info_cache_init (void)
2459 G_LOCK (mime_info_cache);
2460 if (mime_info_cache == NULL)
2461 mime_info_cache_init_dir_lists ();
2467 if (now >= mime_info_cache->last_stat_time + 10)
2469 mime_info_cache_update_dir_lists ();
2470 mime_info_cache->last_stat_time = now;
2474 if (mime_info_cache->should_ping_mime_monitor)
2476 /* g_idle_add (emit_mime_changed, NULL); */
2477 mime_info_cache->should_ping_mime_monitor = FALSE;
2480 G_UNLOCK (mime_info_cache);
2483 static MimeInfoCache *
2484 mime_info_cache_new (void)
2486 MimeInfoCache *cache;
2488 cache = g_new0 (MimeInfoCache, 1);
2490 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2491 (GDestroyNotify) g_free,
2492 (GDestroyNotify) g_free);
2497 mime_info_cache_free (MimeInfoCache *cache)
2502 g_list_foreach (cache->dirs,
2503 (GFunc) mime_info_cache_dir_free,
2505 g_list_free (cache->dirs);
2506 g_hash_table_destroy (cache->global_defaults_cache);
2511 * mime_info_cache_reload:
2512 * @dir: directory path which needs reloading.
2514 * Reload the mime information for the @dir.
2517 mime_info_cache_reload (const char *dir)
2519 /* FIXME: just reload the dir that needs reloading,
2520 * don't blow the whole cache
2522 if (mime_info_cache != NULL)
2524 G_LOCK (mime_info_cache);
2525 mime_info_cache_free (mime_info_cache);
2526 mime_info_cache = NULL;
2527 G_UNLOCK (mime_info_cache);
2532 append_desktop_entry (GList *list,
2533 const char *desktop_entry,
2534 GList *removed_entries)
2536 /* Add if not already in list, and valid */
2537 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2538 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2539 list = g_list_prepend (list, g_strdup (desktop_entry));
2545 * get_all_desktop_entries_for_mime_type:
2546 * @mime_type: a mime type.
2547 * @except: NULL or a strv list
2549 * Returns all the desktop ids for @mime_type. The desktop files
2550 * are listed in an order so that default applications are listed before
2551 * non-default ones, and handlers for inherited mimetypes are listed
2552 * after the base ones.
2554 * Optionally doesn't list the desktop ids given in the @except
2556 * Return value: a #GList containing the desktop ids which claim
2557 * to handle @mime_type.
2560 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2561 const char **except)
2563 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2564 MimeInfoCacheDir *dir;
2567 char **default_entries;
2568 char **removed_associations;
2573 mime_info_cache_init ();
2575 /* collect all ancestors */
2576 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2577 array = g_ptr_array_new ();
2578 for (i = 0; mime_types[i]; i++)
2579 g_ptr_array_add (array, mime_types[i]);
2580 g_free (mime_types);
2581 for (i = 0; i < array->len; i++)
2583 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2584 for (j = 0; anc[j]; j++)
2586 for (k = 0; k < array->len; k++)
2588 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2591 if (k == array->len) /* not found */
2592 g_ptr_array_add (array, g_strdup (anc[j]));
2596 g_ptr_array_add (array, NULL);
2597 mime_types = (char **)g_ptr_array_free (array, FALSE);
2599 G_LOCK (mime_info_cache);
2601 removed_entries = NULL;
2602 desktop_entries = NULL;
2604 for (i = 0; except != NULL && except[i] != NULL; i++)
2605 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2607 for (i = 0; mime_types[i] != NULL; i++)
2609 mime_type = mime_types[i];
2611 /* Go through all apps listed as defaults */
2612 for (dir_list = mime_info_cache->dirs;
2614 dir_list = dir_list->next)
2616 dir = dir_list->data;
2618 /* First added associations from mimeapps.list */
2619 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2620 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2621 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2623 /* Then removed associations from mimeapps.list */
2624 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2625 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2626 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2628 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2629 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2630 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2631 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2634 /* Go through all entries that support the mimetype */
2635 for (dir_list = mime_info_cache->dirs;
2637 dir_list = dir_list->next)
2639 dir = dir_list->data;
2641 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2642 for (tmp = list; tmp != NULL; tmp = tmp->next)
2643 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2647 G_UNLOCK (mime_info_cache);
2649 g_strfreev (mime_types);
2651 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2652 g_list_free (removed_entries);
2654 desktop_entries = g_list_reverse (desktop_entries);
2656 return desktop_entries;
2659 /* GDesktopAppInfoLookup interface: */
2661 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2662 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2665 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2670 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2671 * @lookup: a #GDesktopAppInfoLookup
2672 * @uri_scheme: a string containing a URI scheme.
2674 * Gets the default application for launching applications
2675 * using this URI scheme for a particular GDesktopAppInfoLookup
2678 * The GDesktopAppInfoLookup interface and this function is used
2679 * to implement g_app_info_get_default_for_uri_scheme() backends
2680 * in a GIO module. There is no reason for applications to use it
2681 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2683 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2686 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2687 const char *uri_scheme)
2689 GDesktopAppInfoLookupIface *iface;
2691 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2693 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2695 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2698 #define __G_DESKTOP_APP_INFO_C__
2699 #include "gioaliasdef.c"