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:
1728 * @content_type: the content type to find a #GAppInfo for
1730 * Gets a list of recommended #GAppInfos for a given content type, i.e.
1731 * those applications which claim to support the given content type exactly,
1732 * and not by MIME type subclassing.
1734 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
1735 * for given @content_type or %NULL on error.
1740 g_app_info_get_recommended_for_type (const gchar *content_type)
1742 GList *desktop_entries, *l;
1744 GDesktopAppInfo *info;
1746 g_return_val_if_fail (content_type != NULL, NULL);
1748 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, FALSE);
1751 for (l = desktop_entries; l != NULL; l = l->next)
1753 char *desktop_entry = l->data;
1755 info = g_desktop_app_info_new (desktop_entry);
1758 if (app_info_in_list (G_APP_INFO (info), infos))
1759 g_object_unref (info);
1761 infos = g_list_prepend (infos, info);
1763 g_free (desktop_entry);
1766 g_list_free (desktop_entries);
1768 return g_list_reverse (infos);
1772 * g_app_info_get_fallback_for_type:
1773 * @content_type: the content type to find a #GAppInfo for
1775 * Gets a list of fallback #GAppInfos for a given content type, i.e.
1776 * those applications which claim to support the given content type
1777 * by MIME type subclassing and not directly.
1779 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
1780 * for given @content_type or %NULL on error.
1785 g_app_info_get_fallback_for_type (const gchar *content_type)
1787 GList *desktop_entries, *l;
1788 GList *infos, *recommended_infos;
1789 GDesktopAppInfo *info;
1791 g_return_val_if_fail (content_type != NULL, NULL);
1793 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1794 recommended_infos = g_app_info_get_recommended_for_type (content_type);
1797 for (l = desktop_entries; l != NULL; l = l->next)
1799 char *desktop_entry = l->data;
1801 info = g_desktop_app_info_new (desktop_entry);
1804 if (app_info_in_list (G_APP_INFO (info), infos) ||
1805 app_info_in_list (G_APP_INFO (info), recommended_infos))
1806 g_object_unref (info);
1808 infos = g_list_prepend (infos, info);
1810 g_free (desktop_entry);
1813 g_list_free (desktop_entries);
1814 g_list_free_full (recommended_infos, g_object_unref);
1816 return g_list_reverse (infos);
1820 * g_app_info_get_all_for_type:
1821 * @content_type: the content type to find a #GAppInfo for
1823 * Gets a list of all #GAppInfos for a given content type.
1825 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
1826 * for given @content_type or %NULL on error.
1829 g_app_info_get_all_for_type (const char *content_type)
1831 GList *desktop_entries, *l;
1833 GDesktopAppInfo *info;
1835 g_return_val_if_fail (content_type != NULL, NULL);
1837 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1840 for (l = desktop_entries; l != NULL; l = l->next)
1842 char *desktop_entry = l->data;
1844 info = g_desktop_app_info_new (desktop_entry);
1847 if (app_info_in_list (G_APP_INFO (info), infos))
1848 g_object_unref (info);
1850 infos = g_list_prepend (infos, info);
1852 g_free (desktop_entry);
1855 g_list_free (desktop_entries);
1857 return g_list_reverse (infos);
1861 * g_app_info_reset_type_associations:
1862 * @content_type: a content type
1864 * Removes all changes to the type associations done by
1865 * g_app_info_set_as_default_for_type(),
1866 * g_app_info_set_as_default_for_extension(),
1867 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1872 g_app_info_reset_type_associations (const char *content_type)
1874 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1878 * g_app_info_get_default_for_type:
1879 * @content_type: the content type to find a #GAppInfo for
1880 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1883 * Gets the #GAppInfo that corresponds to a given content type.
1885 * Returns: #GAppInfo for given @content_type or %NULL on error.
1888 g_app_info_get_default_for_type (const char *content_type,
1889 gboolean must_support_uris)
1891 GList *desktop_entries, *l;
1894 g_return_val_if_fail (content_type != NULL, NULL);
1896 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1899 for (l = desktop_entries; l != NULL; l = l->next)
1901 char *desktop_entry = l->data;
1903 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1906 if (must_support_uris && !g_app_info_supports_uris (info))
1908 g_object_unref (info);
1916 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1917 g_list_free (desktop_entries);
1923 * g_app_info_get_default_for_uri_scheme:
1924 * @uri_scheme: a string containing a URI scheme.
1926 * Gets the default application for launching applications
1927 * using this URI scheme. A URI scheme is the initial part
1928 * of the URI, up to but not including the ':', e.g. "http",
1931 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1934 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1937 char *content_type, *scheme_down;
1939 scheme_down = g_ascii_strdown (uri_scheme, -1);
1940 content_type = g_strdup_printf ("x-scheme-handler/%s", scheme_down);
1941 g_free (scheme_down);
1942 app_info = g_app_info_get_default_for_type (content_type, FALSE);
1943 g_free (content_type);
1949 get_apps_from_dir (GHashTable *apps,
1950 const char *dirname,
1954 const char *basename;
1955 char *filename, *subprefix, *desktop_id;
1957 GDesktopAppInfo *appinfo;
1959 dir = g_dir_open (dirname, 0, NULL);
1962 while ((basename = g_dir_read_name (dir)) != NULL)
1964 filename = g_build_filename (dirname, basename, NULL);
1965 if (g_str_has_suffix (basename, ".desktop"))
1967 desktop_id = g_strconcat (prefix, basename, NULL);
1969 /* Use _extended so we catch NULLs too (hidden) */
1970 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1972 appinfo = g_desktop_app_info_new_from_filename (filename);
1975 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1977 g_object_unref (appinfo);
1982 if (appinfo || hidden)
1984 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1988 /* Reuse instead of strdup here */
1989 appinfo->desktop_id = desktop_id;
1994 g_free (desktop_id);
1998 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
2000 subprefix = g_strconcat (prefix, basename, "-", NULL);
2001 get_apps_from_dir (apps, filename, subprefix);
2013 * g_app_info_get_all:
2015 * Gets a list of all of the applications currently registered
2018 * For desktop files, this includes applications that have
2019 * <literal>NoDisplay=true</literal> set or are excluded from
2020 * display by means of <literal>OnlyShowIn</literal> or
2021 * <literal>NotShowIn</literal>. See g_app_info_should_show().
2022 * The returned list does not include applications which have
2023 * the <literal>Hidden</literal> key set.
2025 * Returns: (element-type GAppInfo) (transfer full): a newly allocated #GList of references to #GAppInfo<!---->s.
2028 g_app_info_get_all (void)
2030 const char * const *dirs;
2032 GHashTableIter iter;
2037 dirs = get_applications_search_path ();
2039 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
2043 for (i = 0; dirs[i] != NULL; i++)
2044 get_apps_from_dir (apps, dirs[i], "");
2048 g_hash_table_iter_init (&iter, apps);
2049 while (g_hash_table_iter_next (&iter, NULL, &value))
2052 infos = g_list_prepend (infos, value);
2055 g_hash_table_destroy (apps);
2057 return g_list_reverse (infos);
2060 /* Cacheing of mimeinfo.cache and defaults.list files */
2064 GHashTable *mime_info_cache_map;
2065 GHashTable *defaults_list_map;
2066 GHashTable *mimeapps_list_added_map;
2067 GHashTable *mimeapps_list_removed_map;
2068 time_t mime_info_cache_timestamp;
2069 time_t defaults_list_timestamp;
2070 time_t mimeapps_list_timestamp;
2074 GList *dirs; /* mimeinfo.cache and defaults.list */
2075 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2076 time_t last_stat_time;
2077 guint should_ping_mime_monitor : 1;
2080 static MimeInfoCache *mime_info_cache = NULL;
2081 G_LOCK_DEFINE_STATIC (mime_info_cache);
2083 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2084 const char *mime_type,
2085 char **new_desktop_file_ids);
2087 static MimeInfoCache * mime_info_cache_new (void);
2090 destroy_info_cache_value (gpointer key,
2094 g_list_foreach (value, (GFunc)g_free, NULL);
2095 g_list_free (value);
2099 destroy_info_cache_map (GHashTable *info_cache_map)
2101 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2102 g_hash_table_destroy (info_cache_map);
2106 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2107 const char *cache_file,
2113 filename = g_build_filename (dir->path, cache_file, NULL);
2115 if (g_stat (filename, &buf) < 0)
2122 if (buf.st_mtime != *timestamp)
2128 /* Call with lock held */
2130 remove_all (gpointer key,
2139 mime_info_cache_blow_global_cache (void)
2141 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2146 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2150 gchar *filename, **mime_types;
2157 if (dir->mime_info_cache_map != NULL &&
2158 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2159 &dir->mime_info_cache_timestamp))
2162 if (dir->mime_info_cache_map != NULL)
2163 destroy_info_cache_map (dir->mime_info_cache_map);
2165 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2166 (GDestroyNotify) g_free,
2169 key_file = g_key_file_new ();
2171 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2173 if (g_stat (filename, &buf) < 0)
2176 if (dir->mime_info_cache_timestamp > 0)
2177 mime_info_cache->should_ping_mime_monitor = TRUE;
2179 dir->mime_info_cache_timestamp = buf.st_mtime;
2181 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2186 if (load_error != NULL)
2189 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2192 if (load_error != NULL)
2195 for (i = 0; mime_types[i] != NULL; i++)
2197 gchar **desktop_file_ids;
2198 char *unaliased_type;
2199 desktop_file_ids = g_key_file_get_string_list (key_file,
2205 if (desktop_file_ids == NULL)
2208 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2209 mime_info_cache_dir_add_desktop_entries (dir,
2212 g_free (unaliased_type);
2214 g_strfreev (desktop_file_ids);
2217 g_strfreev (mime_types);
2218 g_key_file_free (key_file);
2223 g_key_file_free (key_file);
2225 if (mime_types != NULL)
2226 g_strfreev (mime_types);
2229 g_error_free (load_error);
2233 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2237 gchar *filename, **mime_types;
2238 char *unaliased_type;
2239 char **desktop_file_ids;
2246 if (dir->defaults_list_map != NULL &&
2247 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2248 &dir->defaults_list_timestamp))
2251 if (dir->defaults_list_map != NULL)
2252 g_hash_table_destroy (dir->defaults_list_map);
2253 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2254 g_free, (GDestroyNotify)g_strfreev);
2257 key_file = g_key_file_new ();
2259 filename = g_build_filename (dir->path, "defaults.list", NULL);
2260 if (g_stat (filename, &buf) < 0)
2263 if (dir->defaults_list_timestamp > 0)
2264 mime_info_cache->should_ping_mime_monitor = TRUE;
2266 dir->defaults_list_timestamp = buf.st_mtime;
2268 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2272 if (load_error != NULL)
2275 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2277 if (mime_types != NULL)
2279 for (i = 0; mime_types[i] != NULL; i++)
2281 desktop_file_ids = g_key_file_get_string_list (key_file,
2282 DEFAULT_APPLICATIONS_GROUP,
2286 if (desktop_file_ids == NULL)
2289 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2290 g_hash_table_replace (dir->defaults_list_map,
2295 g_strfreev (mime_types);
2298 g_key_file_free (key_file);
2303 g_key_file_free (key_file);
2305 if (mime_types != NULL)
2306 g_strfreev (mime_types);
2309 g_error_free (load_error);
2313 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2317 gchar *filename, **mime_types;
2318 char *unaliased_type;
2319 char **desktop_file_ids;
2326 if (dir->mimeapps_list_added_map != NULL &&
2327 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2328 &dir->mimeapps_list_timestamp))
2331 if (dir->mimeapps_list_added_map != NULL)
2332 g_hash_table_destroy (dir->mimeapps_list_added_map);
2333 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2334 g_free, (GDestroyNotify)g_strfreev);
2336 if (dir->mimeapps_list_removed_map != NULL)
2337 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2338 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2339 g_free, (GDestroyNotify)g_strfreev);
2341 key_file = g_key_file_new ();
2343 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2344 if (g_stat (filename, &buf) < 0)
2347 if (dir->mimeapps_list_timestamp > 0)
2348 mime_info_cache->should_ping_mime_monitor = TRUE;
2350 dir->mimeapps_list_timestamp = buf.st_mtime;
2352 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2356 if (load_error != NULL)
2359 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2361 if (mime_types != NULL)
2363 for (i = 0; mime_types[i] != NULL; i++)
2365 desktop_file_ids = g_key_file_get_string_list (key_file,
2366 ADDED_ASSOCIATIONS_GROUP,
2370 if (desktop_file_ids == NULL)
2373 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2374 g_hash_table_replace (dir->mimeapps_list_added_map,
2379 g_strfreev (mime_types);
2382 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2384 if (mime_types != NULL)
2386 for (i = 0; mime_types[i] != NULL; i++)
2388 desktop_file_ids = g_key_file_get_string_list (key_file,
2389 REMOVED_ASSOCIATIONS_GROUP,
2393 if (desktop_file_ids == NULL)
2396 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2397 g_hash_table_replace (dir->mimeapps_list_removed_map,
2402 g_strfreev (mime_types);
2405 g_key_file_free (key_file);
2410 g_key_file_free (key_file);
2412 if (mime_types != NULL)
2413 g_strfreev (mime_types);
2416 g_error_free (load_error);
2419 static MimeInfoCacheDir *
2420 mime_info_cache_dir_new (const char *path)
2422 MimeInfoCacheDir *dir;
2424 dir = g_new0 (MimeInfoCacheDir, 1);
2425 dir->path = g_strdup (path);
2431 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2436 if (dir->mime_info_cache_map != NULL)
2438 destroy_info_cache_map (dir->mime_info_cache_map);
2439 dir->mime_info_cache_map = NULL;
2443 if (dir->defaults_list_map != NULL)
2445 g_hash_table_destroy (dir->defaults_list_map);
2446 dir->defaults_list_map = NULL;
2449 if (dir->mimeapps_list_added_map != NULL)
2451 g_hash_table_destroy (dir->mimeapps_list_added_map);
2452 dir->mimeapps_list_added_map = NULL;
2455 if (dir->mimeapps_list_removed_map != NULL)
2457 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2458 dir->mimeapps_list_removed_map = NULL;
2465 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2466 const char *mime_type,
2467 char **new_desktop_file_ids)
2469 GList *desktop_file_ids;
2472 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2475 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2477 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2478 desktop_file_ids = g_list_append (desktop_file_ids,
2479 g_strdup (new_desktop_file_ids[i]));
2482 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2486 mime_info_cache_init_dir_lists (void)
2488 const char * const *dirs;
2491 mime_info_cache = mime_info_cache_new ();
2493 dirs = get_applications_search_path ();
2495 for (i = 0; dirs[i] != NULL; i++)
2497 MimeInfoCacheDir *dir;
2499 dir = mime_info_cache_dir_new (dirs[i]);
2503 mime_info_cache_dir_init (dir);
2504 mime_info_cache_dir_init_defaults_list (dir);
2505 mime_info_cache_dir_init_mimeapps_list (dir);
2507 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2513 mime_info_cache_update_dir_lists (void)
2517 tmp = mime_info_cache->dirs;
2521 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2523 /* No need to do this if we had file monitors... */
2524 mime_info_cache_blow_global_cache ();
2525 mime_info_cache_dir_init (dir);
2526 mime_info_cache_dir_init_defaults_list (dir);
2527 mime_info_cache_dir_init_mimeapps_list (dir);
2534 mime_info_cache_init (void)
2536 G_LOCK (mime_info_cache);
2537 if (mime_info_cache == NULL)
2538 mime_info_cache_init_dir_lists ();
2544 if (now >= mime_info_cache->last_stat_time + 10)
2546 mime_info_cache_update_dir_lists ();
2547 mime_info_cache->last_stat_time = now;
2551 if (mime_info_cache->should_ping_mime_monitor)
2553 /* g_idle_add (emit_mime_changed, NULL); */
2554 mime_info_cache->should_ping_mime_monitor = FALSE;
2557 G_UNLOCK (mime_info_cache);
2560 static MimeInfoCache *
2561 mime_info_cache_new (void)
2563 MimeInfoCache *cache;
2565 cache = g_new0 (MimeInfoCache, 1);
2567 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2568 (GDestroyNotify) g_free,
2569 (GDestroyNotify) g_free);
2574 mime_info_cache_free (MimeInfoCache *cache)
2579 g_list_foreach (cache->dirs,
2580 (GFunc) mime_info_cache_dir_free,
2582 g_list_free (cache->dirs);
2583 g_hash_table_destroy (cache->global_defaults_cache);
2588 * mime_info_cache_reload:
2589 * @dir: directory path which needs reloading.
2591 * Reload the mime information for the @dir.
2594 mime_info_cache_reload (const char *dir)
2596 /* FIXME: just reload the dir that needs reloading,
2597 * don't blow the whole cache
2599 if (mime_info_cache != NULL)
2601 G_LOCK (mime_info_cache);
2602 mime_info_cache_free (mime_info_cache);
2603 mime_info_cache = NULL;
2604 G_UNLOCK (mime_info_cache);
2609 append_desktop_entry (GList *list,
2610 const char *desktop_entry,
2611 GList *removed_entries)
2613 /* Add if not already in list, and valid */
2614 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2615 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2616 list = g_list_prepend (list, g_strdup (desktop_entry));
2622 * get_all_desktop_entries_for_mime_type:
2623 * @mime_type: a mime type.
2624 * @except: NULL or a strv list
2626 * Returns all the desktop ids for @mime_type. The desktop files
2627 * are listed in an order so that default applications are listed before
2628 * non-default ones, and handlers for inherited mimetypes are listed
2629 * after the base ones.
2631 * Optionally doesn't list the desktop ids given in the @except
2633 * Return value: a #GList containing the desktop ids which claim
2634 * to handle @mime_type.
2637 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2638 const char **except,
2639 gboolean include_fallback)
2641 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2642 MimeInfoCacheDir *dir;
2645 char **default_entries;
2646 char **removed_associations;
2651 mime_info_cache_init ();
2653 if (include_fallback)
2655 /* collect all ancestors */
2656 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2657 array = g_ptr_array_new ();
2658 for (i = 0; mime_types[i]; i++)
2659 g_ptr_array_add (array, mime_types[i]);
2660 g_free (mime_types);
2661 for (i = 0; i < array->len; i++)
2663 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2664 for (j = 0; anc[j]; j++)
2666 for (k = 0; k < array->len; k++)
2668 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2671 if (k == array->len) /* not found */
2672 g_ptr_array_add (array, g_strdup (anc[j]));
2676 g_ptr_array_add (array, NULL);
2677 mime_types = (char **)g_ptr_array_free (array, FALSE);
2681 mime_types = g_malloc0 (2 * sizeof (gchar *));
2682 mime_types[0] = g_strdup (base_mime_type);
2683 mime_types[1] = NULL;
2686 G_LOCK (mime_info_cache);
2688 removed_entries = NULL;
2689 desktop_entries = NULL;
2691 for (i = 0; except != NULL && except[i] != NULL; i++)
2692 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2694 for (i = 0; mime_types[i] != NULL; i++)
2696 mime_type = mime_types[i];
2698 /* Go through all apps listed as defaults */
2699 for (dir_list = mime_info_cache->dirs;
2701 dir_list = dir_list->next)
2703 dir = dir_list->data;
2705 /* First added associations from mimeapps.list */
2706 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2707 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2708 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2710 /* Then removed associations from mimeapps.list */
2711 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2712 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2713 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2715 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2716 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2717 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2718 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2721 /* Go through all entries that support the mimetype */
2722 for (dir_list = mime_info_cache->dirs;
2724 dir_list = dir_list->next)
2726 dir = dir_list->data;
2728 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2729 for (tmp = list; tmp != NULL; tmp = tmp->next)
2730 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2734 G_UNLOCK (mime_info_cache);
2736 g_strfreev (mime_types);
2738 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2739 g_list_free (removed_entries);
2741 desktop_entries = g_list_reverse (desktop_entries);
2743 return desktop_entries;
2746 /* GDesktopAppInfoLookup interface: */
2748 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2749 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2752 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2757 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2758 * @lookup: a #GDesktopAppInfoLookup
2759 * @uri_scheme: a string containing a URI scheme.
2761 * Gets the default application for launching applications
2762 * using this URI scheme for a particular GDesktopAppInfoLookup
2765 * The GDesktopAppInfoLookup interface and this function is used
2766 * to implement g_app_info_get_default_for_uri_scheme() backends
2767 * in a GIO module. There is no reason for applications to use it
2768 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2770 * Returns: (transfer full): #GAppInfo for given @uri_scheme or %NULL on error.
2772 * Deprecated: The #GDesktopAppInfoLookup interface is deprecated and unused by gio.
2775 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2776 const char *uri_scheme)
2778 GDesktopAppInfoLookupIface *iface;
2780 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2782 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2784 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);