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 #undef G_DISABLE_DEPRECATED
37 #include "gcontenttypeprivate.h"
38 #include "gdesktopappinfo.h"
41 #include "gthemedicon.h"
42 #include "gfileicon.h"
43 #include <glib/gstdio.h>
45 #include "giomodule-priv.h"
50 * SECTION:gdesktopappinfo
51 * @short_description: Application information from desktop files
52 * @include: gio/gdesktopappinfo.h
54 * #GDesktopAppInfo is an implementation of #GAppInfo based on
57 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
58 * the UNIX-specific GIO interfaces, thus you have to use the
59 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
62 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
63 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
64 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
65 #define MIME_CACHE_GROUP "MIME Cache"
66 #define FULL_NAME_KEY "X-GNOME-FullName"
68 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
69 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
71 gboolean include_fallback);
72 static void mime_info_cache_reload (const char *dir);
73 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
79 * Information about an installed application from a desktop file.
81 struct _GDesktopAppInfo
83 GObject parent_instance;
89 /* FIXME: what about GenericName ? */
104 guint startup_notify : 1;
106 /* FIXME: what about StartupWMClass ? */
109 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
110 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
111 g_desktop_app_info_iface_init))
114 search_path_init (gpointer data)
117 const char * const *data_dirs;
118 const char *user_data_dir;
121 data_dirs = g_get_system_data_dirs ();
122 length = g_strv_length ((char **) data_dirs);
124 args = g_new (char *, length + 2);
127 user_data_dir = g_get_user_data_dir ();
128 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
129 for (i = 0; i < length; i++)
130 args[j++] = g_build_filename (data_dirs[i],
131 "applications", NULL);
137 static const char * const *
138 get_applications_search_path (void)
140 static GOnce once_init = G_ONCE_INIT;
141 return g_once (&once_init, search_path_init, NULL);
145 g_desktop_app_info_finalize (GObject *object)
147 GDesktopAppInfo *info;
149 info = G_DESKTOP_APP_INFO (object);
151 g_free (info->desktop_id);
152 g_free (info->filename);
154 g_free (info->fullname);
155 g_free (info->comment);
156 g_free (info->icon_name);
158 g_object_unref (info->icon);
159 g_strfreev (info->only_show_in);
160 g_strfreev (info->not_show_in);
161 g_free (info->try_exec);
163 g_free (info->binary);
166 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
170 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
172 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
174 gobject_class->finalize = g_desktop_app_info_finalize;
178 g_desktop_app_info_init (GDesktopAppInfo *local)
183 binary_from_exec (const char *exec)
185 const char *p, *start;
191 while (*p != ' ' && *p != 0)
194 return g_strndup (start, p - start);
199 * g_desktop_app_info_new_from_keyfile:
200 * @key_file: an opened #GKeyFile
202 * Creates a new #GDesktopAppInfo.
204 * Returns: a new #GDesktopAppInfo or %NULL on error.
209 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
211 GDesktopAppInfo *info;
216 start_group = g_key_file_get_start_group (key_file);
217 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
219 g_free (start_group);
222 g_free (start_group);
224 type = g_key_file_get_string (key_file,
225 G_KEY_FILE_DESKTOP_GROUP,
226 G_KEY_FILE_DESKTOP_KEY_TYPE,
228 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
235 try_exec = g_key_file_get_string (key_file,
236 G_KEY_FILE_DESKTOP_GROUP,
237 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
239 if (try_exec && try_exec[0] != '\0')
242 t = g_find_program_in_path (try_exec);
251 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
252 info->filename = NULL;
254 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
255 info->fullname = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, FULL_NAME_KEY, NULL, NULL);
256 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
257 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
258 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
259 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);
260 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);
261 info->try_exec = try_exec;
262 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
263 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
264 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
265 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
266 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
267 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
272 if (g_path_is_absolute (info->icon_name))
276 file = g_file_new_for_path (info->icon_name);
277 info->icon = g_file_icon_new (file);
278 g_object_unref (file);
284 /* Work around a common mistake in desktop files */
285 if ((p = strrchr (info->icon_name, '.')) != NULL &&
286 (strcmp (p, ".png") == 0 ||
287 strcmp (p, ".xpm") == 0 ||
288 strcmp (p, ".svg") == 0))
291 info->icon = g_themed_icon_new (info->icon_name);
296 info->binary = binary_from_exec (info->exec);
298 if (info->path && info->path[0] == '\0')
308 * g_desktop_app_info_new_from_filename:
309 * @filename: the path of a desktop file, in the GLib filename encoding
311 * Creates a new #GDesktopAppInfo.
313 * Returns: a new #GDesktopAppInfo or %NULL on error.
316 g_desktop_app_info_new_from_filename (const char *filename)
319 GDesktopAppInfo *info = NULL;
321 key_file = g_key_file_new ();
323 if (g_key_file_load_from_file (key_file,
328 info = g_desktop_app_info_new_from_keyfile (key_file);
330 info->filename = g_strdup (filename);
333 g_key_file_free (key_file);
339 * g_desktop_app_info_new:
340 * @desktop_id: the desktop file id
342 * Creates a new #GDesktopAppInfo based on a desktop file id.
344 * A desktop file id is the basename of the desktop file, including the
345 * .desktop extension. GIO is looking for a desktop file with this name
346 * in the <filename>applications</filename> subdirectories of the XDG data
347 * directories (i.e. the directories specified in the
348 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
349 * variables). GIO also supports the prefix-to-subdirectory mapping that is
350 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
351 * (i.e. a desktop id of kde-foo.desktop will match
352 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
354 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
357 g_desktop_app_info_new (const char *desktop_id)
359 GDesktopAppInfo *appinfo;
360 const char * const *dirs;
364 dirs = get_applications_search_path ();
366 basename = g_strdup (desktop_id);
368 for (i = 0; dirs[i] != NULL; i++)
373 filename = g_build_filename (dirs[i], desktop_id, NULL);
374 appinfo = g_desktop_app_info_new_from_filename (filename);
380 while ((p = strchr (p, '-')) != NULL)
384 filename = g_build_filename (dirs[i], basename, NULL);
385 appinfo = g_desktop_app_info_new_from_filename (filename);
400 appinfo->desktop_id = g_strdup (desktop_id);
402 if (g_desktop_app_info_get_is_hidden (appinfo))
404 g_object_unref (appinfo);
412 g_desktop_app_info_dup (GAppInfo *appinfo)
414 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
415 GDesktopAppInfo *new_info;
417 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
419 new_info->filename = g_strdup (info->filename);
420 new_info->desktop_id = g_strdup (info->desktop_id);
422 new_info->name = g_strdup (info->name);
423 new_info->fullname = g_strdup (info->fullname);
424 new_info->comment = g_strdup (info->comment);
425 new_info->nodisplay = info->nodisplay;
426 new_info->icon_name = g_strdup (info->icon_name);
428 new_info->icon = g_object_ref (info->icon);
429 new_info->only_show_in = g_strdupv (info->only_show_in);
430 new_info->not_show_in = g_strdupv (info->not_show_in);
431 new_info->try_exec = g_strdup (info->try_exec);
432 new_info->exec = g_strdup (info->exec);
433 new_info->binary = g_strdup (info->binary);
434 new_info->path = g_strdup (info->path);
435 new_info->hidden = info->hidden;
436 new_info->terminal = info->terminal;
437 new_info->startup_notify = info->startup_notify;
439 return G_APP_INFO (new_info);
443 g_desktop_app_info_equal (GAppInfo *appinfo1,
446 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
447 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
449 if (info1->desktop_id == NULL ||
450 info2->desktop_id == NULL)
451 return info1 == info2;
453 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
457 g_desktop_app_info_get_id (GAppInfo *appinfo)
459 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
461 return info->desktop_id;
465 g_desktop_app_info_get_name (GAppInfo *appinfo)
467 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
469 if (info->name == NULL)
475 g_desktop_app_info_get_display_name (GAppInfo *appinfo)
477 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
479 if (info->fullname == NULL)
480 return g_desktop_app_info_get_name (appinfo);
481 return info->fullname;
485 * g_desktop_app_info_get_is_hidden:
486 * @info: a #GDesktopAppInfo.
488 * A desktop file is hidden if the Hidden key in it is
491 * Returns: %TRUE if hidden, %FALSE otherwise.
494 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
500 * g_desktop_app_info_get_filename:
501 * @info: a #GDesktopAppInfo
503 * When @info was created from a known filename, return it. In some
504 * situations such as the #GDesktopAppInfo returned from
505 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
507 * Returns: The full path to the file for @info, or %NULL if not known.
511 g_desktop_app_info_get_filename (GDesktopAppInfo *info)
513 return info->filename;
517 g_desktop_app_info_get_description (GAppInfo *appinfo)
519 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
521 return info->comment;
525 g_desktop_app_info_get_executable (GAppInfo *appinfo)
527 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
533 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
535 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
541 g_desktop_app_info_get_icon (GAppInfo *appinfo)
543 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
549 expand_macro_single (char macro, char *uri)
555 file = g_file_new_for_uri (uri);
556 path = g_file_get_path (file);
557 g_object_unref (file);
563 result = g_shell_quote (uri);
568 result = g_shell_quote (path);
574 name = g_path_get_dirname (path);
575 result = g_shell_quote (name);
583 name = g_path_get_basename (path);
584 result = g_shell_quote (name);
596 expand_macro (char macro,
598 GDesktopAppInfo *info,
601 GList *uris = *uri_list;
603 gboolean force_file_uri;
604 char force_file_uri_macro;
607 g_return_if_fail (exec != NULL);
609 /* On %u and %U, pass POSIX file path pointing to the URI via
610 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
611 * running or the URI doesn't have a POSIX file path via FUSE
612 * we'll just pass the URI.
614 force_file_uri_macro = macro;
615 force_file_uri = FALSE;
621 force_file_uri_macro = 'f';
622 force_file_uri = TRUE;
625 force_file_uri_macro = 'F';
626 force_file_uri = TRUE;
642 if (!force_file_uri ||
643 /* Pass URI if it contains an anchor */
644 strchr (uri, '#') != NULL)
646 expanded = expand_macro_single (macro, uri);
650 expanded = expand_macro_single (force_file_uri_macro, uri);
651 if (expanded == NULL)
652 expanded = expand_macro_single (macro, uri);
657 g_string_append (exec, expanded);
673 if (!force_file_uri ||
674 /* Pass URI if it contains an anchor */
675 strchr (uri, '#') != NULL)
677 expanded = expand_macro_single (macro, uri);
681 expanded = expand_macro_single (force_file_uri_macro, uri);
682 if (expanded == NULL)
683 expanded = expand_macro_single (macro, uri);
688 g_string_append (exec, expanded);
694 if (uris != NULL && expanded)
695 g_string_append_c (exec, ' ');
703 g_string_append (exec, "--icon ");
704 expanded = g_shell_quote (info->icon_name);
705 g_string_append (exec, expanded);
713 expanded = g_shell_quote (info->name);
714 g_string_append (exec, expanded);
722 expanded = g_shell_quote (info->filename);
723 g_string_append (exec, expanded);
728 case 'm': /* deprecated */
732 g_string_append_c (exec, '%');
740 expand_application_parameters (GDesktopAppInfo *info,
746 GList *uri_list = *uris;
747 const char *p = info->exec;
748 GString *expanded_exec;
751 if (info->exec == NULL)
753 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
754 _("Desktop file didn't specify Exec field"));
758 expanded_exec = g_string_new (NULL);
762 if (p[0] == '%' && p[1] != '\0')
764 expand_macro (p[1], expanded_exec, info, uris);
768 g_string_append_c (expanded_exec, *p);
773 /* No file substitutions */
774 if (uri_list == *uris && uri_list != NULL)
776 /* If there is no macro default to %f. This is also what KDE does */
777 g_string_append_c (expanded_exec, ' ');
778 expand_macro ('f', expanded_exec, info, uris);
781 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
782 g_string_free (expanded_exec, TRUE);
787 prepend_terminal_to_vector (int *argc,
794 char **term_argv = NULL;
799 g_return_val_if_fail (argc != NULL, FALSE);
800 g_return_val_if_fail (argv != NULL, FALSE);
808 /* compute size if not given */
811 for (i = 0; the_argv[i] != NULL; i++)
817 term_argv = g_new0 (char *, 3);
819 check = g_find_program_in_path ("gnome-terminal");
822 term_argv[0] = check;
823 /* Note that gnome-terminal takes -x and
824 * as -e in gnome-terminal is broken we use that. */
825 term_argv[1] = g_strdup ("-x");
830 check = g_find_program_in_path ("nxterm");
832 check = g_find_program_in_path ("color-xterm");
834 check = g_find_program_in_path ("rxvt");
836 check = g_find_program_in_path ("xterm");
838 check = g_find_program_in_path ("dtterm");
841 check = g_strdup ("xterm");
842 g_warning ("couldn't find a terminal, falling back to xterm");
844 term_argv[0] = check;
845 term_argv[1] = g_strdup ("-e");
848 real_argc = term_argc + *argc;
849 real_argv = g_new (char *, real_argc + 1);
851 for (i = 0; i < term_argc; i++)
852 real_argv[i] = term_argv[i];
854 for (j = 0; j < *argc; j++, i++)
855 real_argv[i] = (char *)the_argv[j];
863 /* we use g_free here as we sucked all the inner strings
864 * out from it into real_argv */
869 #endif /* G_OS_WIN32 */
873 uri_list_segment_to_files (GList *start,
880 while (start != NULL && start != end)
882 file = g_file_new_for_uri ((char *)start->data);
883 res = g_list_prepend (res, file);
887 return g_list_reverse (res);
898 child_setup (gpointer user_data)
900 ChildSetupData *data = user_data;
903 g_setenv ("DISPLAY", data->display, TRUE);
906 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
908 if (data->desktop_file)
912 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
914 g_snprintf (pid, 20, "%ld", (long)getpid ());
915 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
920 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
922 GAppLaunchContext *launch_context,
925 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
926 gboolean completed = FALSE;
928 GList *launched_files;
933 g_return_val_if_fail (appinfo != NULL, FALSE);
940 if (!expand_application_parameters (info, &uris,
941 &argc, &argv, error))
944 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
946 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
947 _("Unable to find terminal required for application"));
953 data.desktop_file = info->filename;
957 launched_files = uri_list_segment_to_files (old_uris, uris);
959 data.display = g_app_launch_context_get_display (launch_context,
963 if (info->startup_notify)
964 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
967 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
968 g_list_free (launched_files);
971 if (!g_spawn_async (info->path,
981 g_app_launch_context_launch_failed (launch_context, data.sn_id);
984 g_free (data.display);
990 g_free (data.display);
995 while (uris != NULL);
1006 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
1008 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1010 return info->exec &&
1011 ((strstr (info->exec, "%u") != NULL) ||
1012 (strstr (info->exec, "%U") != NULL));
1016 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1018 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1020 return info->exec &&
1021 ((strstr (info->exec, "%f") != NULL) ||
1022 (strstr (info->exec, "%F") != NULL));
1026 g_desktop_app_info_launch (GAppInfo *appinfo,
1028 GAppLaunchContext *launch_context,
1038 uri = g_file_get_uri (files->data);
1039 uris = g_list_prepend (uris, uri);
1040 files = files->next;
1043 uris = g_list_reverse (uris);
1045 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1047 g_list_foreach (uris, (GFunc)g_free, NULL);
1053 G_LOCK_DEFINE_STATIC (g_desktop_env);
1054 static gchar *g_desktop_env = NULL;
1057 * g_desktop_app_info_set_desktop_env:
1058 * @desktop_env: a string specifying what desktop this is
1060 * Sets the name of the desktop that the application is running in.
1061 * This is used by g_app_info_should_show() to evaluate the
1062 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1063 * desktop entry fields.
1065 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1066 * Menu specification</ulink> recognizes the following:
1068 * <member>GNOME</member>
1069 * <member>KDE</member>
1070 * <member>ROX</member>
1071 * <member>XFCE</member>
1072 * <member>Old</member>
1075 * Should be called only once; subsequent calls are ignored.
1078 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1080 G_LOCK (g_desktop_env);
1082 g_desktop_env = g_strdup (desktop_env);
1083 G_UNLOCK (g_desktop_env);
1087 g_desktop_app_info_should_show (GAppInfo *appinfo)
1089 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1091 const gchar *desktop_env;
1094 if (info->nodisplay)
1097 G_LOCK (g_desktop_env);
1098 desktop_env = g_desktop_env;
1099 G_UNLOCK (g_desktop_env);
1101 if (info->only_show_in)
1103 if (desktop_env == NULL)
1107 for (i = 0; info->only_show_in[i] != NULL; i++)
1109 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1119 if (info->not_show_in && desktop_env)
1121 for (i = 0; info->not_show_in[i] != NULL; i++)
1123 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1137 ensure_dir (DirType type,
1140 char *path, *display_name;
1143 if (type == APP_DIR)
1144 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1146 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1149 if (g_mkdir_with_parents (path, 0700) == 0)
1153 display_name = g_filename_display_name (path);
1154 if (type == APP_DIR)
1155 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1156 _("Can't create user application configuration folder %s: %s"),
1157 display_name, g_strerror (errsv));
1159 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1160 _("Can't create user MIME configuration folder %s: %s"),
1161 display_name, g_strerror (errsv));
1163 g_free (display_name);
1170 update_mimeapps_list (const char *desktop_id,
1171 const char *content_type,
1172 gboolean add_as_default,
1173 gboolean add_non_default,
1177 char *dirname, *filename;
1179 gboolean load_succeeded, res;
1180 char **old_list, **list;
1181 GList *system_list, *l;
1182 gsize length, data_size;
1185 char **content_types;
1187 /* Don't add both at start and end */
1188 g_assert (!(add_as_default && add_non_default));
1190 dirname = ensure_dir (APP_DIR, error);
1194 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1197 key_file = g_key_file_new ();
1198 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1199 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1201 g_key_file_free (key_file);
1202 key_file = g_key_file_new ();
1207 content_types = g_new (char *, 2);
1208 content_types[0] = g_strdup (content_type);
1209 content_types[1] = NULL;
1213 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1216 for (k = 0; content_types && content_types[k]; k++)
1218 /* Add to the right place in the list */
1221 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1222 content_types[k], &length, NULL);
1224 list = g_new (char *, 1 + length + 1);
1228 list[i++] = g_strdup (desktop_id);
1231 for (j = 0; old_list[j] != NULL; j++)
1233 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1234 list[i++] = g_strdup (old_list[j]);
1235 else if (add_non_default)
1237 /* If adding as non-default, and it's already in,
1238 don't change order of desktop ids */
1239 add_non_default = FALSE;
1240 list[i++] = g_strdup (old_list[j]);
1245 if (add_non_default)
1247 /* We're adding as non-default, and it wasn't already in the list,
1248 so we add at the end. But to avoid listing the app before the
1249 current system default (thus changing the default) we have to
1250 add the current list of (not yet listed) apps before it. */
1252 list[i] = NULL; /* Terminate current list so we can use it */
1253 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list, FALSE);
1255 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1257 for (l = system_list; l != NULL; l = l->next)
1259 list[i++] = l->data; /* no strdup, taking ownership */
1260 if (g_strcmp0 (l->data, desktop_id) == 0)
1261 add_non_default = FALSE;
1263 g_list_free (system_list);
1265 if (add_non_default)
1266 list[i++] = g_strdup (desktop_id);
1271 g_strfreev (old_list);
1273 if (list[0] == NULL || desktop_id == NULL)
1274 g_key_file_remove_key (key_file,
1275 ADDED_ASSOCIATIONS_GROUP,
1279 g_key_file_set_string_list (key_file,
1280 ADDED_ASSOCIATIONS_GROUP,
1282 (const char * const *)list, i);
1289 /* reuse the list from above */
1293 g_strfreev (content_types);
1294 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1297 for (k = 0; content_types && content_types[k]; k++)
1299 /* Remove from removed associations group (unless remove) */
1302 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1303 content_types[k], &length, NULL);
1305 list = g_new (char *, 1 + length + 1);
1309 list[i++] = g_strdup (desktop_id);
1312 for (j = 0; old_list[j] != NULL; j++)
1314 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1315 list[i++] = g_strdup (old_list[j]);
1320 g_strfreev (old_list);
1322 if (list[0] == NULL || desktop_id == NULL)
1323 g_key_file_remove_key (key_file,
1324 REMOVED_ASSOCIATIONS_GROUP,
1328 g_key_file_set_string_list (key_file,
1329 REMOVED_ASSOCIATIONS_GROUP,
1331 (const char * const *)list, i);
1336 g_strfreev (content_types);
1338 data = g_key_file_to_data (key_file, &data_size, error);
1339 g_key_file_free (key_file);
1341 res = g_file_set_contents (filename, data, data_size, error);
1343 mime_info_cache_reload (NULL);
1352 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1353 const char *content_type,
1356 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1358 if (!g_desktop_app_info_ensure_saved (info, error))
1361 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1365 update_program_done (GPid pid,
1369 /* Did the application exit correctly */
1370 if (WIFEXITED (status) &&
1371 WEXITSTATUS (status) == 0)
1373 /* Here we could clean out any caches in use */
1378 run_update_command (char *command,
1387 GError *error = NULL;
1390 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1392 if (g_spawn_async ("/", argv,
1394 G_SPAWN_SEARCH_PATH |
1395 G_SPAWN_STDOUT_TO_DEV_NULL |
1396 G_SPAWN_STDERR_TO_DEV_NULL |
1397 G_SPAWN_DO_NOT_REAP_CHILD,
1398 NULL, NULL, /* No setup function */
1401 g_child_watch_add (pid, update_program_done, NULL);
1404 /* If we get an error at this point, it's quite likely the user doesn't
1405 * have an installed copy of either 'update-mime-database' or
1406 * 'update-desktop-database'. I don't think we want to popup an error
1407 * dialog at this point, so we just do a g_warning to give the user a
1408 * chance of debugging it.
1410 g_warning ("%s", error->message);
1417 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1418 const char *extension,
1421 char *filename, *basename, *mimetype;
1425 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1428 dirname = ensure_dir (MIMETYPE_DIR, error);
1432 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1433 filename = g_build_filename (dirname, basename, NULL);
1437 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1439 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1444 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1445 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1446 " <mime-type type=\"%s\">\n"
1447 " <comment>%s document</comment>\n"
1448 " <glob pattern=\"*.%s\"/>\n"
1450 "</mime-info>\n", mimetype, extension, extension);
1452 g_file_set_contents (filename, contents, -1, NULL);
1455 run_update_command ("update-mime-database", "mime");
1459 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1469 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1470 const char *content_type,
1473 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1475 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1478 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1482 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1488 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1489 const char *content_type,
1492 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1494 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1497 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1501 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1507 char *data, *desktop_id;
1512 if (info->filename != NULL)
1515 /* This is only used for object created with
1516 * g_app_info_create_from_commandline. All other
1517 * object should have a filename
1520 dirname = ensure_dir (APP_DIR, error);
1524 key_file = g_key_file_new ();
1526 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1527 "Encoding", "UTF-8");
1528 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1529 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1530 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1531 G_KEY_FILE_DESKTOP_KEY_TYPE,
1532 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1534 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1535 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1537 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1538 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1540 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1541 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1543 if (info->fullname != NULL)
1544 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1545 FULL_NAME_KEY, info->fullname);
1547 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1548 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1550 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1551 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1553 data = g_key_file_to_data (key_file, &data_size, NULL);
1554 g_key_file_free (key_file);
1556 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1557 filename = g_build_filename (dirname, desktop_id, NULL);
1558 g_free (desktop_id);
1561 fd = g_mkstemp (filename);
1566 display_name = g_filename_display_name (filename);
1567 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1568 _("Can't create user desktop file %s"), display_name);
1569 g_free (display_name);
1575 desktop_id = g_path_get_basename (filename);
1579 res = g_file_set_contents (filename, data, data_size, error);
1582 g_free (desktop_id);
1587 info->filename = filename;
1588 info->desktop_id = desktop_id;
1590 run_update_command ("update-desktop-database", "applications");
1596 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1598 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1602 if (strstr (info->filename, "/userapp-"))
1603 return g_access (info->filename, W_OK) == 0;
1610 g_desktop_app_info_delete (GAppInfo *appinfo)
1612 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1616 if (g_remove (info->filename) == 0)
1618 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1620 g_free (info->filename);
1621 info->filename = NULL;
1622 g_free (info->desktop_id);
1623 info->desktop_id = NULL;
1633 * g_app_info_create_from_commandline:
1634 * @commandline: the commandline to use
1635 * @application_name: (allow-none): the application name, or %NULL to use @commandline
1636 * @flags: flags that can specify details of the created #GAppInfo
1637 * @error: a #GError location to store the error occuring, %NULL to ignore.
1639 * Creates a new #GAppInfo from the given information.
1641 * Returns: (transfer full): new #GAppInfo for given command.
1644 g_app_info_create_from_commandline (const char *commandline,
1645 const char *application_name,
1646 GAppInfoCreateFlags flags,
1651 GDesktopAppInfo *info;
1653 g_return_val_if_fail (commandline, NULL);
1655 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1657 info->filename = NULL;
1658 info->desktop_id = NULL;
1660 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1661 info->startup_notify = flags & G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION;
1662 info->hidden = FALSE;
1663 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1664 info->exec = g_strconcat (commandline, " %u", NULL);
1666 info->exec = g_strconcat (commandline, " %f", NULL);
1667 info->nodisplay = TRUE;
1668 info->binary = binary_from_exec (info->exec);
1670 if (application_name)
1671 info->name = g_strdup (application_name);
1674 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1675 split = g_strsplit (commandline, " ", 2);
1676 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1678 info->name = basename;
1679 if (info->name == NULL)
1680 info->name = g_strdup ("custom");
1682 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1684 return G_APP_INFO (info);
1688 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1690 iface->dup = g_desktop_app_info_dup;
1691 iface->equal = g_desktop_app_info_equal;
1692 iface->get_id = g_desktop_app_info_get_id;
1693 iface->get_name = g_desktop_app_info_get_name;
1694 iface->get_description = g_desktop_app_info_get_description;
1695 iface->get_executable = g_desktop_app_info_get_executable;
1696 iface->get_icon = g_desktop_app_info_get_icon;
1697 iface->launch = g_desktop_app_info_launch;
1698 iface->supports_uris = g_desktop_app_info_supports_uris;
1699 iface->supports_files = g_desktop_app_info_supports_files;
1700 iface->launch_uris = g_desktop_app_info_launch_uris;
1701 iface->should_show = g_desktop_app_info_should_show;
1702 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1703 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1704 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1705 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1706 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1707 iface->can_delete = g_desktop_app_info_can_delete;
1708 iface->do_delete = g_desktop_app_info_delete;
1709 iface->get_commandline = g_desktop_app_info_get_commandline;
1710 iface->get_display_name = g_desktop_app_info_get_display_name;
1714 app_info_in_list (GAppInfo *info,
1717 while (list != NULL)
1719 if (g_app_info_equal (info, list->data))
1727 g_app_info_get_recommended_for_type (const gchar *content_type)
1729 GList *desktop_entries, *l;
1731 GDesktopAppInfo *info;
1733 g_return_val_if_fail (content_type != NULL, NULL);
1735 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, FALSE);
1738 for (l = desktop_entries; l != NULL; l = l->next)
1740 char *desktop_entry = l->data;
1742 info = g_desktop_app_info_new (desktop_entry);
1745 if (app_info_in_list (G_APP_INFO (info), infos))
1746 g_object_unref (info);
1748 infos = g_list_prepend (infos, info);
1750 g_free (desktop_entry);
1753 g_list_free (desktop_entries);
1755 return g_list_reverse (infos);
1759 g_app_info_get_fallback_for_type (const gchar *content_type)
1761 GList *desktop_entries, *l;
1762 GList *infos, *recommended_infos;
1763 GDesktopAppInfo *info;
1765 g_return_val_if_fail (content_type != NULL, NULL);
1767 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1768 recommended_infos = g_app_info_get_recommended_for_type (content_type);
1771 for (l = desktop_entries; l != NULL; l = l->next)
1773 char *desktop_entry = l->data;
1775 info = g_desktop_app_info_new (desktop_entry);
1778 if (app_info_in_list (G_APP_INFO (info), infos) ||
1779 app_info_in_list (G_APP_INFO (info), recommended_infos))
1780 g_object_unref (info);
1782 infos = g_list_prepend (infos, info);
1784 g_free (desktop_entry);
1787 g_list_free (desktop_entries);
1788 g_list_free_full (recommended_infos, g_object_unref);
1790 return g_list_reverse (infos);
1794 * g_app_info_get_all_for_type:
1795 * @content_type: the content type to find a #GAppInfo for
1797 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1799 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfo<!-- -->s for given @content_type
1800 * or %NULL on error.
1803 g_app_info_get_all_for_type (const char *content_type)
1805 GList *desktop_entries, *l;
1807 GDesktopAppInfo *info;
1809 g_return_val_if_fail (content_type != NULL, NULL);
1811 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1814 for (l = desktop_entries; l != NULL; l = l->next)
1816 char *desktop_entry = l->data;
1818 info = g_desktop_app_info_new (desktop_entry);
1821 if (app_info_in_list (G_APP_INFO (info), infos))
1822 g_object_unref (info);
1824 infos = g_list_prepend (infos, info);
1826 g_free (desktop_entry);
1829 g_list_free (desktop_entries);
1831 return g_list_reverse (infos);
1835 * g_app_info_reset_type_associations:
1836 * @content_type: a content type
1838 * Removes all changes to the type associations done by
1839 * g_app_info_set_as_default_for_type(),
1840 * g_app_info_set_as_default_for_extension(),
1841 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1846 g_app_info_reset_type_associations (const char *content_type)
1848 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1852 * g_app_info_get_default_for_type:
1853 * @content_type: the content type to find a #GAppInfo for
1854 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1857 * Gets the #GAppInfo that corresponds to a given content type.
1859 * Returns: #GAppInfo for given @content_type or %NULL on error.
1862 g_app_info_get_default_for_type (const char *content_type,
1863 gboolean must_support_uris)
1865 GList *desktop_entries, *l;
1868 g_return_val_if_fail (content_type != NULL, NULL);
1870 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1873 for (l = desktop_entries; l != NULL; l = l->next)
1875 char *desktop_entry = l->data;
1877 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1880 if (must_support_uris && !g_app_info_supports_uris (info))
1882 g_object_unref (info);
1890 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1891 g_list_free (desktop_entries);
1897 * g_app_info_get_default_for_uri_scheme:
1898 * @uri_scheme: a string containing a URI scheme.
1900 * Gets the default application for launching applications
1901 * using this URI scheme. A URI scheme is the initial part
1902 * of the URI, up to but not including the ':', e.g. "http",
1905 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1908 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1911 char *content_type, *scheme_down;
1913 scheme_down = g_ascii_strdown (uri_scheme, -1);
1914 content_type = g_strdup_printf ("x-scheme-handler/%s", scheme_down);
1915 g_free (scheme_down);
1916 app_info = g_app_info_get_default_for_type (content_type, FALSE);
1917 g_free (content_type);
1923 get_apps_from_dir (GHashTable *apps,
1924 const char *dirname,
1928 const char *basename;
1929 char *filename, *subprefix, *desktop_id;
1931 GDesktopAppInfo *appinfo;
1933 dir = g_dir_open (dirname, 0, NULL);
1936 while ((basename = g_dir_read_name (dir)) != NULL)
1938 filename = g_build_filename (dirname, basename, NULL);
1939 if (g_str_has_suffix (basename, ".desktop"))
1941 desktop_id = g_strconcat (prefix, basename, NULL);
1943 /* Use _extended so we catch NULLs too (hidden) */
1944 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1946 appinfo = g_desktop_app_info_new_from_filename (filename);
1949 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1951 g_object_unref (appinfo);
1956 if (appinfo || hidden)
1958 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1962 /* Reuse instead of strdup here */
1963 appinfo->desktop_id = desktop_id;
1968 g_free (desktop_id);
1972 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1974 subprefix = g_strconcat (prefix, basename, "-", NULL);
1975 get_apps_from_dir (apps, filename, subprefix);
1987 * g_app_info_get_all:
1989 * Gets a list of all of the applications currently registered
1992 * For desktop files, this includes applications that have
1993 * <literal>NoDisplay=true</literal> set or are excluded from
1994 * display by means of <literal>OnlyShowIn</literal> or
1995 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1996 * The returned list does not include applications which have
1997 * the <literal>Hidden</literal> key set.
1999 * Returns: (element-type GAppInfo) (transfer full): a newly allocated #GList of references to #GAppInfo<!---->s.
2002 g_app_info_get_all (void)
2004 const char * const *dirs;
2006 GHashTableIter iter;
2011 dirs = get_applications_search_path ();
2013 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
2017 for (i = 0; dirs[i] != NULL; i++)
2018 get_apps_from_dir (apps, dirs[i], "");
2022 g_hash_table_iter_init (&iter, apps);
2023 while (g_hash_table_iter_next (&iter, NULL, &value))
2026 infos = g_list_prepend (infos, value);
2029 g_hash_table_destroy (apps);
2031 return g_list_reverse (infos);
2034 /* Cacheing of mimeinfo.cache and defaults.list files */
2038 GHashTable *mime_info_cache_map;
2039 GHashTable *defaults_list_map;
2040 GHashTable *mimeapps_list_added_map;
2041 GHashTable *mimeapps_list_removed_map;
2042 time_t mime_info_cache_timestamp;
2043 time_t defaults_list_timestamp;
2044 time_t mimeapps_list_timestamp;
2048 GList *dirs; /* mimeinfo.cache and defaults.list */
2049 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2050 time_t last_stat_time;
2051 guint should_ping_mime_monitor : 1;
2054 static MimeInfoCache *mime_info_cache = NULL;
2055 G_LOCK_DEFINE_STATIC (mime_info_cache);
2057 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2058 const char *mime_type,
2059 char **new_desktop_file_ids);
2061 static MimeInfoCache * mime_info_cache_new (void);
2064 destroy_info_cache_value (gpointer key,
2068 g_list_foreach (value, (GFunc)g_free, NULL);
2069 g_list_free (value);
2073 destroy_info_cache_map (GHashTable *info_cache_map)
2075 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2076 g_hash_table_destroy (info_cache_map);
2080 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2081 const char *cache_file,
2087 filename = g_build_filename (dir->path, cache_file, NULL);
2089 if (g_stat (filename, &buf) < 0)
2096 if (buf.st_mtime != *timestamp)
2102 /* Call with lock held */
2104 remove_all (gpointer key,
2113 mime_info_cache_blow_global_cache (void)
2115 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2120 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2124 gchar *filename, **mime_types;
2131 if (dir->mime_info_cache_map != NULL &&
2132 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2133 &dir->mime_info_cache_timestamp))
2136 if (dir->mime_info_cache_map != NULL)
2137 destroy_info_cache_map (dir->mime_info_cache_map);
2139 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2140 (GDestroyNotify) g_free,
2143 key_file = g_key_file_new ();
2145 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2147 if (g_stat (filename, &buf) < 0)
2150 if (dir->mime_info_cache_timestamp > 0)
2151 mime_info_cache->should_ping_mime_monitor = TRUE;
2153 dir->mime_info_cache_timestamp = buf.st_mtime;
2155 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2160 if (load_error != NULL)
2163 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2166 if (load_error != NULL)
2169 for (i = 0; mime_types[i] != NULL; i++)
2171 gchar **desktop_file_ids;
2172 char *unaliased_type;
2173 desktop_file_ids = g_key_file_get_string_list (key_file,
2179 if (desktop_file_ids == NULL)
2182 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2183 mime_info_cache_dir_add_desktop_entries (dir,
2186 g_free (unaliased_type);
2188 g_strfreev (desktop_file_ids);
2191 g_strfreev (mime_types);
2192 g_key_file_free (key_file);
2197 g_key_file_free (key_file);
2199 if (mime_types != NULL)
2200 g_strfreev (mime_types);
2203 g_error_free (load_error);
2207 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2211 gchar *filename, **mime_types;
2212 char *unaliased_type;
2213 char **desktop_file_ids;
2220 if (dir->defaults_list_map != NULL &&
2221 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2222 &dir->defaults_list_timestamp))
2225 if (dir->defaults_list_map != NULL)
2226 g_hash_table_destroy (dir->defaults_list_map);
2227 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2228 g_free, (GDestroyNotify)g_strfreev);
2231 key_file = g_key_file_new ();
2233 filename = g_build_filename (dir->path, "defaults.list", NULL);
2234 if (g_stat (filename, &buf) < 0)
2237 if (dir->defaults_list_timestamp > 0)
2238 mime_info_cache->should_ping_mime_monitor = TRUE;
2240 dir->defaults_list_timestamp = buf.st_mtime;
2242 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2246 if (load_error != NULL)
2249 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2251 if (mime_types != NULL)
2253 for (i = 0; mime_types[i] != NULL; i++)
2255 desktop_file_ids = g_key_file_get_string_list (key_file,
2256 DEFAULT_APPLICATIONS_GROUP,
2260 if (desktop_file_ids == NULL)
2263 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2264 g_hash_table_replace (dir->defaults_list_map,
2269 g_strfreev (mime_types);
2272 g_key_file_free (key_file);
2277 g_key_file_free (key_file);
2279 if (mime_types != NULL)
2280 g_strfreev (mime_types);
2283 g_error_free (load_error);
2287 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2291 gchar *filename, **mime_types;
2292 char *unaliased_type;
2293 char **desktop_file_ids;
2300 if (dir->mimeapps_list_added_map != NULL &&
2301 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2302 &dir->mimeapps_list_timestamp))
2305 if (dir->mimeapps_list_added_map != NULL)
2306 g_hash_table_destroy (dir->mimeapps_list_added_map);
2307 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2308 g_free, (GDestroyNotify)g_strfreev);
2310 if (dir->mimeapps_list_removed_map != NULL)
2311 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2312 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2313 g_free, (GDestroyNotify)g_strfreev);
2315 key_file = g_key_file_new ();
2317 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2318 if (g_stat (filename, &buf) < 0)
2321 if (dir->mimeapps_list_timestamp > 0)
2322 mime_info_cache->should_ping_mime_monitor = TRUE;
2324 dir->mimeapps_list_timestamp = buf.st_mtime;
2326 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2330 if (load_error != NULL)
2333 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2335 if (mime_types != NULL)
2337 for (i = 0; mime_types[i] != NULL; i++)
2339 desktop_file_ids = g_key_file_get_string_list (key_file,
2340 ADDED_ASSOCIATIONS_GROUP,
2344 if (desktop_file_ids == NULL)
2347 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2348 g_hash_table_replace (dir->mimeapps_list_added_map,
2353 g_strfreev (mime_types);
2356 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2358 if (mime_types != NULL)
2360 for (i = 0; mime_types[i] != NULL; i++)
2362 desktop_file_ids = g_key_file_get_string_list (key_file,
2363 REMOVED_ASSOCIATIONS_GROUP,
2367 if (desktop_file_ids == NULL)
2370 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2371 g_hash_table_replace (dir->mimeapps_list_removed_map,
2376 g_strfreev (mime_types);
2379 g_key_file_free (key_file);
2384 g_key_file_free (key_file);
2386 if (mime_types != NULL)
2387 g_strfreev (mime_types);
2390 g_error_free (load_error);
2393 static MimeInfoCacheDir *
2394 mime_info_cache_dir_new (const char *path)
2396 MimeInfoCacheDir *dir;
2398 dir = g_new0 (MimeInfoCacheDir, 1);
2399 dir->path = g_strdup (path);
2405 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2410 if (dir->mime_info_cache_map != NULL)
2412 destroy_info_cache_map (dir->mime_info_cache_map);
2413 dir->mime_info_cache_map = NULL;
2417 if (dir->defaults_list_map != NULL)
2419 g_hash_table_destroy (dir->defaults_list_map);
2420 dir->defaults_list_map = NULL;
2423 if (dir->mimeapps_list_added_map != NULL)
2425 g_hash_table_destroy (dir->mimeapps_list_added_map);
2426 dir->mimeapps_list_added_map = NULL;
2429 if (dir->mimeapps_list_removed_map != NULL)
2431 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2432 dir->mimeapps_list_removed_map = NULL;
2439 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2440 const char *mime_type,
2441 char **new_desktop_file_ids)
2443 GList *desktop_file_ids;
2446 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2449 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2451 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2452 desktop_file_ids = g_list_append (desktop_file_ids,
2453 g_strdup (new_desktop_file_ids[i]));
2456 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2460 mime_info_cache_init_dir_lists (void)
2462 const char * const *dirs;
2465 mime_info_cache = mime_info_cache_new ();
2467 dirs = get_applications_search_path ();
2469 for (i = 0; dirs[i] != NULL; i++)
2471 MimeInfoCacheDir *dir;
2473 dir = mime_info_cache_dir_new (dirs[i]);
2477 mime_info_cache_dir_init (dir);
2478 mime_info_cache_dir_init_defaults_list (dir);
2479 mime_info_cache_dir_init_mimeapps_list (dir);
2481 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2487 mime_info_cache_update_dir_lists (void)
2491 tmp = mime_info_cache->dirs;
2495 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2497 /* No need to do this if we had file monitors... */
2498 mime_info_cache_blow_global_cache ();
2499 mime_info_cache_dir_init (dir);
2500 mime_info_cache_dir_init_defaults_list (dir);
2501 mime_info_cache_dir_init_mimeapps_list (dir);
2508 mime_info_cache_init (void)
2510 G_LOCK (mime_info_cache);
2511 if (mime_info_cache == NULL)
2512 mime_info_cache_init_dir_lists ();
2518 if (now >= mime_info_cache->last_stat_time + 10)
2520 mime_info_cache_update_dir_lists ();
2521 mime_info_cache->last_stat_time = now;
2525 if (mime_info_cache->should_ping_mime_monitor)
2527 /* g_idle_add (emit_mime_changed, NULL); */
2528 mime_info_cache->should_ping_mime_monitor = FALSE;
2531 G_UNLOCK (mime_info_cache);
2534 static MimeInfoCache *
2535 mime_info_cache_new (void)
2537 MimeInfoCache *cache;
2539 cache = g_new0 (MimeInfoCache, 1);
2541 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2542 (GDestroyNotify) g_free,
2543 (GDestroyNotify) g_free);
2548 mime_info_cache_free (MimeInfoCache *cache)
2553 g_list_foreach (cache->dirs,
2554 (GFunc) mime_info_cache_dir_free,
2556 g_list_free (cache->dirs);
2557 g_hash_table_destroy (cache->global_defaults_cache);
2562 * mime_info_cache_reload:
2563 * @dir: directory path which needs reloading.
2565 * Reload the mime information for the @dir.
2568 mime_info_cache_reload (const char *dir)
2570 /* FIXME: just reload the dir that needs reloading,
2571 * don't blow the whole cache
2573 if (mime_info_cache != NULL)
2575 G_LOCK (mime_info_cache);
2576 mime_info_cache_free (mime_info_cache);
2577 mime_info_cache = NULL;
2578 G_UNLOCK (mime_info_cache);
2583 append_desktop_entry (GList *list,
2584 const char *desktop_entry,
2585 GList *removed_entries)
2587 /* Add if not already in list, and valid */
2588 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2589 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2590 list = g_list_prepend (list, g_strdup (desktop_entry));
2596 * get_all_desktop_entries_for_mime_type:
2597 * @mime_type: a mime type.
2598 * @except: NULL or a strv list
2600 * Returns all the desktop ids for @mime_type. The desktop files
2601 * are listed in an order so that default applications are listed before
2602 * non-default ones, and handlers for inherited mimetypes are listed
2603 * after the base ones.
2605 * Optionally doesn't list the desktop ids given in the @except
2607 * Return value: a #GList containing the desktop ids which claim
2608 * to handle @mime_type.
2611 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2612 const char **except,
2613 gboolean include_fallback)
2615 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2616 MimeInfoCacheDir *dir;
2619 char **default_entries;
2620 char **removed_associations;
2625 mime_info_cache_init ();
2627 if (include_fallback)
2629 /* collect all ancestors */
2630 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2631 array = g_ptr_array_new ();
2632 for (i = 0; mime_types[i]; i++)
2633 g_ptr_array_add (array, mime_types[i]);
2634 g_free (mime_types);
2635 for (i = 0; i < array->len; i++)
2637 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2638 for (j = 0; anc[j]; j++)
2640 for (k = 0; k < array->len; k++)
2642 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2645 if (k == array->len) /* not found */
2646 g_ptr_array_add (array, g_strdup (anc[j]));
2650 g_ptr_array_add (array, NULL);
2651 mime_types = (char **)g_ptr_array_free (array, FALSE);
2655 mime_types = g_malloc0 (2 * sizeof (gchar *));
2656 mime_types[0] = g_strdup (base_mime_type);
2657 mime_types[1] = NULL;
2660 G_LOCK (mime_info_cache);
2662 removed_entries = NULL;
2663 desktop_entries = NULL;
2665 for (i = 0; except != NULL && except[i] != NULL; i++)
2666 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2668 for (i = 0; mime_types[i] != NULL; i++)
2670 mime_type = mime_types[i];
2672 /* Go through all apps listed as defaults */
2673 for (dir_list = mime_info_cache->dirs;
2675 dir_list = dir_list->next)
2677 dir = dir_list->data;
2679 /* First added associations from mimeapps.list */
2680 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2681 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2682 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2684 /* Then removed associations from mimeapps.list */
2685 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2686 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2687 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2689 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2690 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2691 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2692 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2695 /* Go through all entries that support the mimetype */
2696 for (dir_list = mime_info_cache->dirs;
2698 dir_list = dir_list->next)
2700 dir = dir_list->data;
2702 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2703 for (tmp = list; tmp != NULL; tmp = tmp->next)
2704 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2708 G_UNLOCK (mime_info_cache);
2710 g_strfreev (mime_types);
2712 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2713 g_list_free (removed_entries);
2715 desktop_entries = g_list_reverse (desktop_entries);
2717 return desktop_entries;
2720 /* GDesktopAppInfoLookup interface: */
2722 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2723 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2726 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2731 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2732 * @lookup: a #GDesktopAppInfoLookup
2733 * @uri_scheme: a string containing a URI scheme.
2735 * Gets the default application for launching applications
2736 * using this URI scheme for a particular GDesktopAppInfoLookup
2739 * The GDesktopAppInfoLookup interface and this function is used
2740 * to implement g_app_info_get_default_for_uri_scheme() backends
2741 * in a GIO module. There is no reason for applications to use it
2742 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2744 * Returns: (transfer full): #GAppInfo for given @uri_scheme or %NULL on error.
2746 * Deprecated: The #GDesktopAppInfoLookup interface is deprecated and unused by gio.
2749 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2750 const char *uri_scheme)
2752 GDesktopAppInfoLookupIface *iface;
2754 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2756 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2758 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);