1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright © 2007 Ryan Lortie
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Author: Alexander Larsson <alexl@redhat.com>
31 #ifdef HAVE_CRT_EXTERNS_H
32 #include <crt_externs.h>
35 #include "gcontenttypeprivate.h"
36 #include "gdesktopappinfo.h"
39 #include "gthemedicon.h"
40 #include "gfileicon.h"
41 #include <glib/gstdio.h>
43 #include "giomodule-priv.h"
48 * SECTION:gdesktopappinfo
49 * @short_description: Application information from desktop files
50 * @include: gio/gdesktopappinfo.h
52 * #GDesktopAppInfo is an implementation of #GAppInfo based on
55 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
56 * the UNIX-specific GIO interfaces, thus you have to use the
57 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
60 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
61 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
62 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
63 #define MIME_CACHE_GROUP "MIME Cache"
64 #define FULL_NAME_KEY "X-GNOME-FullName"
66 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
67 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
69 static void mime_info_cache_reload (const char *dir);
70 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
76 * Information about an installed application from a desktop file.
78 struct _GDesktopAppInfo
80 GObject parent_instance;
86 /* FIXME: what about GenericName ? */
101 guint startup_notify : 1;
103 /* FIXME: what about StartupWMClass ? */
106 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
107 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
108 g_desktop_app_info_iface_init))
111 search_path_init (gpointer data)
114 const char * const *data_dirs;
115 const char *user_data_dir;
118 data_dirs = g_get_system_data_dirs ();
119 length = g_strv_length ((char **) data_dirs);
121 args = g_new (char *, length + 2);
124 user_data_dir = g_get_user_data_dir ();
125 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
126 for (i = 0; i < length; i++)
127 args[j++] = g_build_filename (data_dirs[i],
128 "applications", NULL);
134 static const char * const *
135 get_applications_search_path (void)
137 static GOnce once_init = G_ONCE_INIT;
138 return g_once (&once_init, search_path_init, NULL);
142 g_desktop_app_info_finalize (GObject *object)
144 GDesktopAppInfo *info;
146 info = G_DESKTOP_APP_INFO (object);
148 g_free (info->desktop_id);
149 g_free (info->filename);
151 g_free (info->fullname);
152 g_free (info->comment);
153 g_free (info->icon_name);
155 g_object_unref (info->icon);
156 g_strfreev (info->only_show_in);
157 g_strfreev (info->not_show_in);
158 g_free (info->try_exec);
160 g_free (info->binary);
163 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
167 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
169 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
171 gobject_class->finalize = g_desktop_app_info_finalize;
175 g_desktop_app_info_init (GDesktopAppInfo *local)
180 binary_from_exec (const char *exec)
182 const char *p, *start;
188 while (*p != ' ' && *p != 0)
191 return g_strndup (start, p - start);
196 * g_desktop_app_info_new_from_keyfile:
197 * @key_file: an opened #GKeyFile
199 * Creates a new #GDesktopAppInfo.
201 * Returns: a new #GDesktopAppInfo or %NULL on error.
206 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
208 GDesktopAppInfo *info;
213 start_group = g_key_file_get_start_group (key_file);
214 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
216 g_free (start_group);
219 g_free (start_group);
221 type = g_key_file_get_string (key_file,
222 G_KEY_FILE_DESKTOP_GROUP,
223 G_KEY_FILE_DESKTOP_KEY_TYPE,
225 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
232 try_exec = g_key_file_get_string (key_file,
233 G_KEY_FILE_DESKTOP_GROUP,
234 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
236 if (try_exec && try_exec[0] != '\0')
239 t = g_find_program_in_path (try_exec);
248 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
249 info->filename = NULL;
251 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
252 info->fullname = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, FULL_NAME_KEY, NULL, NULL);
253 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
254 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
255 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
256 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);
257 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);
258 info->try_exec = try_exec;
259 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
260 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
261 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
262 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
263 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
264 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
269 if (g_path_is_absolute (info->icon_name))
273 file = g_file_new_for_path (info->icon_name);
274 info->icon = g_file_icon_new (file);
275 g_object_unref (file);
281 /* Work around a common mistake in desktop files */
282 if ((p = strrchr (info->icon_name, '.')) != NULL &&
283 (strcmp (p, ".png") == 0 ||
284 strcmp (p, ".xpm") == 0 ||
285 strcmp (p, ".svg") == 0))
288 info->icon = g_themed_icon_new (info->icon_name);
293 info->binary = binary_from_exec (info->exec);
295 if (info->path && info->path[0] == '\0')
305 * g_desktop_app_info_new_from_filename:
306 * @filename: the path of a desktop file, in the GLib filename encoding
308 * Creates a new #GDesktopAppInfo.
310 * Returns: a new #GDesktopAppInfo or %NULL on error.
313 g_desktop_app_info_new_from_filename (const char *filename)
316 GDesktopAppInfo *info = NULL;
318 key_file = g_key_file_new ();
320 if (g_key_file_load_from_file (key_file,
325 info = g_desktop_app_info_new_from_keyfile (key_file);
327 info->filename = g_strdup (filename);
330 g_key_file_free (key_file);
336 * g_desktop_app_info_new:
337 * @desktop_id: the desktop file id
339 * Creates a new #GDesktopAppInfo based on a desktop file id.
341 * A desktop file id is the basename of the desktop file, including the
342 * .desktop extension. GIO is looking for a desktop file with this name
343 * in the <filename>applications</filename> subdirectories of the XDG data
344 * directories (i.e. the directories specified in the
345 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
346 * variables). GIO also supports the prefix-to-subdirectory mapping that is
347 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
348 * (i.e. a desktop id of kde-foo.desktop will match
349 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
351 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
354 g_desktop_app_info_new (const char *desktop_id)
356 GDesktopAppInfo *appinfo;
357 const char * const *dirs;
361 dirs = get_applications_search_path ();
363 basename = g_strdup (desktop_id);
365 for (i = 0; dirs[i] != NULL; i++)
370 filename = g_build_filename (dirs[i], desktop_id, NULL);
371 appinfo = g_desktop_app_info_new_from_filename (filename);
377 while ((p = strchr (p, '-')) != NULL)
381 filename = g_build_filename (dirs[i], basename, NULL);
382 appinfo = g_desktop_app_info_new_from_filename (filename);
397 appinfo->desktop_id = g_strdup (desktop_id);
399 if (g_desktop_app_info_get_is_hidden (appinfo))
401 g_object_unref (appinfo);
409 g_desktop_app_info_dup (GAppInfo *appinfo)
411 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
412 GDesktopAppInfo *new_info;
414 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
416 new_info->filename = g_strdup (info->filename);
417 new_info->desktop_id = g_strdup (info->desktop_id);
419 new_info->name = g_strdup (info->name);
420 new_info->fullname = g_strdup (info->fullname);
421 new_info->comment = g_strdup (info->comment);
422 new_info->nodisplay = info->nodisplay;
423 new_info->icon_name = g_strdup (info->icon_name);
425 new_info->icon = g_object_ref (info->icon);
426 new_info->only_show_in = g_strdupv (info->only_show_in);
427 new_info->not_show_in = g_strdupv (info->not_show_in);
428 new_info->try_exec = g_strdup (info->try_exec);
429 new_info->exec = g_strdup (info->exec);
430 new_info->binary = g_strdup (info->binary);
431 new_info->path = g_strdup (info->path);
432 new_info->hidden = info->hidden;
433 new_info->terminal = info->terminal;
434 new_info->startup_notify = info->startup_notify;
436 return G_APP_INFO (new_info);
440 g_desktop_app_info_equal (GAppInfo *appinfo1,
443 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
444 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
446 if (info1->desktop_id == NULL ||
447 info2->desktop_id == NULL)
448 return info1 == info2;
450 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
454 g_desktop_app_info_get_id (GAppInfo *appinfo)
456 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
458 return info->desktop_id;
462 g_desktop_app_info_get_name (GAppInfo *appinfo)
464 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
466 if (info->name == NULL)
472 g_desktop_app_info_get_display_name (GAppInfo *appinfo)
474 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
476 if (info->fullname == NULL)
477 return g_desktop_app_info_get_name (appinfo);
478 return info->fullname;
482 * g_desktop_app_info_get_is_hidden:
483 * @info: a #GDesktopAppInfo.
485 * A desktop file is hidden if the Hidden key in it is
488 * Returns: %TRUE if hidden, %FALSE otherwise.
491 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
497 * g_desktop_app_info_get_filename:
498 * @info: a #GDesktopAppInfo
500 * When @info was created from a known filename, return it. In some
501 * situations such as the #GDesktopAppInfo returned from
502 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
504 * Returns: The full path to the file for @info, or %NULL if not known.
508 g_desktop_app_info_get_filename (GDesktopAppInfo *info)
510 return info->filename;
514 g_desktop_app_info_get_description (GAppInfo *appinfo)
516 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
518 return info->comment;
522 g_desktop_app_info_get_executable (GAppInfo *appinfo)
524 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
530 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
532 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
538 g_desktop_app_info_get_icon (GAppInfo *appinfo)
540 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
546 expand_macro_single (char macro, char *uri)
552 file = g_file_new_for_uri (uri);
553 path = g_file_get_path (file);
554 g_object_unref (file);
560 result = g_shell_quote (uri);
565 result = g_shell_quote (path);
571 name = g_path_get_dirname (path);
572 result = g_shell_quote (name);
580 name = g_path_get_basename (path);
581 result = g_shell_quote (name);
593 expand_macro (char macro,
595 GDesktopAppInfo *info,
598 GList *uris = *uri_list;
600 gboolean force_file_uri;
601 char force_file_uri_macro;
604 g_return_if_fail (exec != NULL);
606 /* On %u and %U, pass POSIX file path pointing to the URI via
607 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
608 * running or the URI doesn't have a POSIX file path via FUSE
609 * we'll just pass the URI.
611 force_file_uri_macro = macro;
612 force_file_uri = FALSE;
618 force_file_uri_macro = 'f';
619 force_file_uri = TRUE;
622 force_file_uri_macro = 'F';
623 force_file_uri = TRUE;
639 if (!force_file_uri ||
640 /* Pass URI if it contains an anchor */
641 strchr (uri, '#') != NULL)
643 expanded = expand_macro_single (macro, uri);
647 expanded = expand_macro_single (force_file_uri_macro, uri);
648 if (expanded == NULL)
649 expanded = expand_macro_single (macro, uri);
654 g_string_append (exec, expanded);
670 if (!force_file_uri ||
671 /* Pass URI if it contains an anchor */
672 strchr (uri, '#') != NULL)
674 expanded = expand_macro_single (macro, uri);
678 expanded = expand_macro_single (force_file_uri_macro, uri);
679 if (expanded == NULL)
680 expanded = expand_macro_single (macro, uri);
685 g_string_append (exec, expanded);
691 if (uris != NULL && expanded)
692 g_string_append_c (exec, ' ');
700 g_string_append (exec, "--icon ");
701 g_string_append (exec, info->icon_name);
707 g_string_append (exec, info->name);
712 g_string_append (exec, info->filename);
715 case 'm': /* deprecated */
719 g_string_append_c (exec, '%');
727 expand_application_parameters (GDesktopAppInfo *info,
733 GList *uri_list = *uris;
734 const char *p = info->exec;
735 GString *expanded_exec;
738 if (info->exec == NULL)
740 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
741 _("Desktop file didn't specify Exec field"));
745 expanded_exec = g_string_new (NULL);
749 if (p[0] == '%' && p[1] != '\0')
751 expand_macro (p[1], expanded_exec, info, uris);
755 g_string_append_c (expanded_exec, *p);
760 /* No file substitutions */
761 if (uri_list == *uris && uri_list != NULL)
763 /* If there is no macro default to %f. This is also what KDE does */
764 g_string_append_c (expanded_exec, ' ');
765 expand_macro ('f', expanded_exec, info, uris);
768 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
769 g_string_free (expanded_exec, TRUE);
774 prepend_terminal_to_vector (int *argc,
781 char **term_argv = NULL;
786 g_return_val_if_fail (argc != NULL, FALSE);
787 g_return_val_if_fail (argv != NULL, FALSE);
795 /* compute size if not given */
798 for (i = 0; the_argv[i] != NULL; i++)
804 term_argv = g_new0 (char *, 3);
806 check = g_find_program_in_path ("gnome-terminal");
809 term_argv[0] = check;
810 /* Note that gnome-terminal takes -x and
811 * as -e in gnome-terminal is broken we use that. */
812 term_argv[1] = g_strdup ("-x");
817 check = g_find_program_in_path ("nxterm");
819 check = g_find_program_in_path ("color-xterm");
821 check = g_find_program_in_path ("rxvt");
823 check = g_find_program_in_path ("xterm");
825 check = g_find_program_in_path ("dtterm");
828 check = g_strdup ("xterm");
829 g_warning ("couldn't find a terminal, falling back to xterm");
831 term_argv[0] = check;
832 term_argv[1] = g_strdup ("-e");
835 real_argc = term_argc + *argc;
836 real_argv = g_new (char *, real_argc + 1);
838 for (i = 0; i < term_argc; i++)
839 real_argv[i] = term_argv[i];
841 for (j = 0; j < *argc; j++, i++)
842 real_argv[i] = (char *)the_argv[j];
850 /* we use g_free here as we sucked all the inner strings
851 * out from it into real_argv */
856 #endif /* G_OS_WIN32 */
860 uri_list_segment_to_files (GList *start,
867 while (start != NULL && start != end)
869 file = g_file_new_for_uri ((char *)start->data);
870 res = g_list_prepend (res, file);
874 return g_list_reverse (res);
885 child_setup (gpointer user_data)
887 ChildSetupData *data = user_data;
890 g_setenv ("DISPLAY", data->display, TRUE);
893 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
895 if (data->desktop_file)
899 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
901 g_snprintf (pid, 20, "%d", getpid ());
902 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
907 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
909 GAppLaunchContext *launch_context,
912 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
913 gboolean completed = FALSE;
915 GList *launched_files;
920 g_return_val_if_fail (appinfo != NULL, FALSE);
927 if (!expand_application_parameters (info, &uris,
928 &argc, &argv, error))
931 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
933 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
934 _("Unable to find terminal required for application"));
940 data.desktop_file = info->filename;
944 launched_files = uri_list_segment_to_files (old_uris, uris);
946 data.display = g_app_launch_context_get_display (launch_context,
950 if (info->startup_notify)
951 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
954 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
955 g_list_free (launched_files);
958 if (!g_spawn_async (info->path,
968 g_app_launch_context_launch_failed (launch_context, data.sn_id);
971 g_free (data.display);
977 g_free (data.display);
982 while (uris != NULL);
993 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
995 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
998 ((strstr (info->exec, "%u") != NULL) ||
999 (strstr (info->exec, "%U") != NULL));
1003 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1005 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1007 return info->exec &&
1008 ((strstr (info->exec, "%f") != NULL) ||
1009 (strstr (info->exec, "%F") != NULL));
1013 g_desktop_app_info_launch (GAppInfo *appinfo,
1015 GAppLaunchContext *launch_context,
1025 uri = g_file_get_uri (files->data);
1026 uris = g_list_prepend (uris, uri);
1027 files = files->next;
1030 uris = g_list_reverse (uris);
1032 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1034 g_list_foreach (uris, (GFunc)g_free, NULL);
1040 G_LOCK_DEFINE_STATIC (g_desktop_env);
1041 static gchar *g_desktop_env = NULL;
1044 * g_desktop_app_info_set_desktop_env:
1045 * @desktop_env: a string specifying what desktop this is
1047 * Sets the name of the desktop that the application is running in.
1048 * This is used by g_app_info_should_show() to evaluate the
1049 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1050 * desktop entry fields.
1052 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1053 * Menu specification</ulink> recognizes the following:
1055 * <member>GNOME</member>
1056 * <member>KDE</member>
1057 * <member>ROX</member>
1058 * <member>XFCE</member>
1059 * <member>Old</member>
1062 * Should be called only once; subsequent calls are ignored.
1065 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1067 G_LOCK (g_desktop_env);
1069 g_desktop_env = g_strdup (desktop_env);
1070 G_UNLOCK (g_desktop_env);
1074 g_desktop_app_info_should_show (GAppInfo *appinfo)
1076 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1078 const gchar *desktop_env;
1081 if (info->nodisplay)
1084 G_LOCK (g_desktop_env);
1085 desktop_env = g_desktop_env;
1086 G_UNLOCK (g_desktop_env);
1088 if (info->only_show_in)
1090 if (desktop_env == NULL)
1094 for (i = 0; info->only_show_in[i] != NULL; i++)
1096 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1106 if (info->not_show_in && desktop_env)
1108 for (i = 0; info->not_show_in[i] != NULL; i++)
1110 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1124 ensure_dir (DirType type,
1127 char *path, *display_name;
1130 if (type == APP_DIR)
1131 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1133 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1136 if (g_mkdir_with_parents (path, 0700) == 0)
1140 display_name = g_filename_display_name (path);
1141 if (type == APP_DIR)
1142 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1143 _("Can't create user application configuration folder %s: %s"),
1144 display_name, g_strerror (errsv));
1146 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1147 _("Can't create user MIME configuration folder %s: %s"),
1148 display_name, g_strerror (errsv));
1150 g_free (display_name);
1157 update_mimeapps_list (const char *desktop_id,
1158 const char *content_type,
1159 gboolean add_as_default,
1160 gboolean add_non_default,
1164 char *dirname, *filename;
1166 gboolean load_succeeded, res;
1167 char **old_list, **list;
1168 GList *system_list, *l;
1169 gsize length, data_size;
1172 char **content_types;
1174 /* Don't add both at start and end */
1175 g_assert (!(add_as_default && add_non_default));
1177 dirname = ensure_dir (APP_DIR, error);
1181 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1184 key_file = g_key_file_new ();
1185 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1186 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1188 g_key_file_free (key_file);
1189 key_file = g_key_file_new ();
1194 content_types = g_new (char *, 2);
1195 content_types[0] = g_strdup (content_type);
1196 content_types[1] = NULL;
1200 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1203 for (k = 0; content_types && content_types[k]; k++)
1205 /* Add to the right place in the list */
1208 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1209 content_types[k], &length, NULL);
1211 list = g_new (char *, 1 + length + 1);
1215 list[i++] = g_strdup (desktop_id);
1218 for (j = 0; old_list[j] != NULL; j++)
1220 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1221 list[i++] = g_strdup (old_list[j]);
1222 else if (add_non_default)
1224 /* If adding as non-default, and it's already in,
1225 don't change order of desktop ids */
1226 add_non_default = FALSE;
1227 list[i++] = g_strdup (old_list[j]);
1232 if (add_non_default)
1234 /* We're adding as non-default, and it wasn't already in the list,
1235 so we add at the end. But to avoid listing the app before the
1236 current system default (thus changing the default) we have to
1237 add the current list of (not yet listed) apps before it. */
1239 list[i] = NULL; /* Terminate current list so we can use it */
1240 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1242 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1244 for (l = system_list; l != NULL; l = l->next)
1246 list[i++] = l->data; /* no strdup, taking ownership */
1247 if (g_strcmp0 (l->data, desktop_id) == 0)
1248 add_non_default = FALSE;
1250 g_list_free (system_list);
1252 if (add_non_default)
1253 list[i++] = g_strdup (desktop_id);
1258 g_strfreev (old_list);
1260 if (list[0] == NULL || desktop_id == NULL)
1261 g_key_file_remove_key (key_file,
1262 ADDED_ASSOCIATIONS_GROUP,
1266 g_key_file_set_string_list (key_file,
1267 ADDED_ASSOCIATIONS_GROUP,
1269 (const char * const *)list, i);
1276 /* reuse the list from above */
1280 g_strfreev (content_types);
1281 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1284 for (k = 0; content_types && content_types[k]; k++)
1286 /* Remove from removed associations group (unless remove) */
1289 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1290 content_types[k], &length, NULL);
1292 list = g_new (char *, 1 + length + 1);
1296 list[i++] = g_strdup (desktop_id);
1299 for (j = 0; old_list[j] != NULL; j++)
1301 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1302 list[i++] = g_strdup (old_list[j]);
1307 g_strfreev (old_list);
1309 if (list[0] == NULL || desktop_id == NULL)
1310 g_key_file_remove_key (key_file,
1311 REMOVED_ASSOCIATIONS_GROUP,
1315 g_key_file_set_string_list (key_file,
1316 REMOVED_ASSOCIATIONS_GROUP,
1318 (const char * const *)list, i);
1323 g_strfreev (content_types);
1325 data = g_key_file_to_data (key_file, &data_size, error);
1326 g_key_file_free (key_file);
1328 res = g_file_set_contents (filename, data, data_size, error);
1330 mime_info_cache_reload (NULL);
1339 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1340 const char *content_type,
1343 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1345 if (!g_desktop_app_info_ensure_saved (info, error))
1348 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1352 update_program_done (GPid pid,
1356 /* Did the application exit correctly */
1357 if (WIFEXITED (status) &&
1358 WEXITSTATUS (status) == 0)
1360 /* Here we could clean out any caches in use */
1365 run_update_command (char *command,
1374 GError *error = NULL;
1377 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1379 if (g_spawn_async ("/", argv,
1381 G_SPAWN_SEARCH_PATH |
1382 G_SPAWN_STDOUT_TO_DEV_NULL |
1383 G_SPAWN_STDERR_TO_DEV_NULL |
1384 G_SPAWN_DO_NOT_REAP_CHILD,
1385 NULL, NULL, /* No setup function */
1388 g_child_watch_add (pid, update_program_done, NULL);
1391 /* If we get an error at this point, it's quite likely the user doesn't
1392 * have an installed copy of either 'update-mime-database' or
1393 * 'update-desktop-database'. I don't think we want to popup an error
1394 * dialog at this point, so we just do a g_warning to give the user a
1395 * chance of debugging it.
1397 g_warning ("%s", error->message);
1404 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1405 const char *extension,
1408 char *filename, *basename, *mimetype;
1412 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1415 dirname = ensure_dir (MIMETYPE_DIR, error);
1419 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1420 filename = g_build_filename (dirname, basename, NULL);
1424 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1426 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1431 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1432 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1433 " <mime-type type=\"%s\">\n"
1434 " <comment>%s document</comment>\n"
1435 " <glob pattern=\"*.%s\"/>\n"
1437 "</mime-info>\n", mimetype, extension, extension);
1439 g_file_set_contents (filename, contents, -1, NULL);
1442 run_update_command ("update-mime-database", "mime");
1446 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1456 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1457 const char *content_type,
1460 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1462 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1465 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1469 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1475 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1476 const char *content_type,
1479 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1481 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1484 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1488 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1494 char *data, *desktop_id;
1499 if (info->filename != NULL)
1502 /* This is only used for object created with
1503 * g_app_info_create_from_commandline. All other
1504 * object should have a filename
1507 dirname = ensure_dir (APP_DIR, error);
1511 key_file = g_key_file_new ();
1513 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1514 "Encoding", "UTF-8");
1515 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1516 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1517 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1518 G_KEY_FILE_DESKTOP_KEY_TYPE,
1519 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1521 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1522 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1524 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1525 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1527 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1528 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1530 if (info->fullname != NULL)
1531 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1532 FULL_NAME_KEY, info->fullname);
1534 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1535 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1537 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1538 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1540 data = g_key_file_to_data (key_file, &data_size, NULL);
1541 g_key_file_free (key_file);
1543 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1544 filename = g_build_filename (dirname, desktop_id, NULL);
1545 g_free (desktop_id);
1548 fd = g_mkstemp (filename);
1553 display_name = g_filename_display_name (filename);
1554 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1555 _("Can't create user desktop file %s"), display_name);
1556 g_free (display_name);
1562 desktop_id = g_path_get_basename (filename);
1566 res = g_file_set_contents (filename, data, data_size, error);
1569 g_free (desktop_id);
1574 info->filename = filename;
1575 info->desktop_id = desktop_id;
1577 run_update_command ("update-desktop-database", "applications");
1583 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1585 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1589 if (strstr (info->filename, "/userapp-"))
1590 return g_access (info->filename, W_OK) == 0;
1597 g_desktop_app_info_delete (GAppInfo *appinfo)
1599 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1603 if (g_remove (info->filename) == 0)
1605 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1607 g_free (info->filename);
1608 info->filename = NULL;
1609 g_free (info->desktop_id);
1610 info->desktop_id = NULL;
1620 * g_app_info_create_from_commandline:
1621 * @commandline: the commandline to use
1622 * @application_name: (allow-none): the application name, or %NULL to use @commandline
1623 * @flags: flags that can specify details of the created #GAppInfo
1624 * @error: a #GError location to store the error occuring, %NULL to ignore.
1626 * Creates a new #GAppInfo from the given information.
1628 * Returns: new #GAppInfo for given command.
1631 g_app_info_create_from_commandline (const char *commandline,
1632 const char *application_name,
1633 GAppInfoCreateFlags flags,
1638 GDesktopAppInfo *info;
1640 g_return_val_if_fail (commandline, NULL);
1642 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1644 info->filename = NULL;
1645 info->desktop_id = NULL;
1647 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1648 info->startup_notify = FALSE;
1649 info->hidden = FALSE;
1650 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1651 info->exec = g_strconcat (commandline, " %u", NULL);
1653 info->exec = g_strconcat (commandline, " %f", NULL);
1654 info->nodisplay = TRUE;
1655 info->binary = binary_from_exec (info->exec);
1657 if (application_name)
1658 info->name = g_strdup (application_name);
1661 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1662 split = g_strsplit (commandline, " ", 2);
1663 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1665 info->name = basename;
1666 if (info->name == NULL)
1667 info->name = g_strdup ("custom");
1669 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1671 return G_APP_INFO (info);
1675 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1677 iface->dup = g_desktop_app_info_dup;
1678 iface->equal = g_desktop_app_info_equal;
1679 iface->get_id = g_desktop_app_info_get_id;
1680 iface->get_name = g_desktop_app_info_get_name;
1681 iface->get_description = g_desktop_app_info_get_description;
1682 iface->get_executable = g_desktop_app_info_get_executable;
1683 iface->get_icon = g_desktop_app_info_get_icon;
1684 iface->launch = g_desktop_app_info_launch;
1685 iface->supports_uris = g_desktop_app_info_supports_uris;
1686 iface->supports_files = g_desktop_app_info_supports_files;
1687 iface->launch_uris = g_desktop_app_info_launch_uris;
1688 iface->should_show = g_desktop_app_info_should_show;
1689 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1690 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1691 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1692 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1693 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1694 iface->can_delete = g_desktop_app_info_can_delete;
1695 iface->do_delete = g_desktop_app_info_delete;
1696 iface->get_commandline = g_desktop_app_info_get_commandline;
1697 iface->get_display_name = g_desktop_app_info_get_display_name;
1701 app_info_in_list (GAppInfo *info,
1704 while (list != NULL)
1706 if (g_app_info_equal (info, list->data))
1715 * g_app_info_get_all_for_type:
1716 * @content_type: the content type to find a #GAppInfo for
1718 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1720 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfo<!-- -->s for given @content_type
1721 * or %NULL on error.
1724 g_app_info_get_all_for_type (const char *content_type)
1726 GList *desktop_entries, *l;
1728 GDesktopAppInfo *info;
1730 g_return_val_if_fail (content_type != NULL, NULL);
1732 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1735 for (l = desktop_entries; l != NULL; l = l->next)
1737 char *desktop_entry = l->data;
1739 info = g_desktop_app_info_new (desktop_entry);
1742 if (app_info_in_list (G_APP_INFO (info), infos))
1743 g_object_unref (info);
1745 infos = g_list_prepend (infos, info);
1747 g_free (desktop_entry);
1750 g_list_free (desktop_entries);
1752 return g_list_reverse (infos);
1756 * g_app_info_reset_type_associations:
1757 * @content_type: a content type
1759 * Removes all changes to the type associations done by
1760 * g_app_info_set_as_default_for_type(),
1761 * g_app_info_set_as_default_for_extension(),
1762 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1767 g_app_info_reset_type_associations (const char *content_type)
1769 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1773 * g_app_info_get_default_for_type:
1774 * @content_type: the content type to find a #GAppInfo for
1775 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1778 * Gets the #GAppInfo that corresponds to a given content type.
1780 * Returns: #GAppInfo for given @content_type or %NULL on error.
1783 g_app_info_get_default_for_type (const char *content_type,
1784 gboolean must_support_uris)
1786 GList *desktop_entries, *l;
1789 g_return_val_if_fail (content_type != NULL, NULL);
1791 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1794 for (l = desktop_entries; l != NULL; l = l->next)
1796 char *desktop_entry = l->data;
1798 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1801 if (must_support_uris && !g_app_info_supports_uris (info))
1803 g_object_unref (info);
1811 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1812 g_list_free (desktop_entries);
1818 * g_app_info_get_default_for_uri_scheme:
1819 * @uri_scheme: a string containing a URI scheme.
1821 * Gets the default application for launching applications
1822 * using this URI scheme. A URI scheme is the initial part
1823 * of the URI, up to but not including the ':', e.g. "http",
1826 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1829 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1831 static gsize lookup = 0;
1833 if (g_once_init_enter (&lookup))
1835 gsize setup_value = 1;
1836 GDesktopAppInfoLookup *lookup_instance;
1837 const char *use_this;
1838 GIOExtensionPoint *ep;
1839 GIOExtension *extension;
1842 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1844 /* Ensure vfs in modules loaded */
1845 _g_io_modules_ensure_loaded ();
1847 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1849 lookup_instance = NULL;
1852 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1854 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1857 if (lookup_instance == NULL)
1859 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1861 extension = l->data;
1862 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1863 if (lookup_instance != NULL)
1868 if (lookup_instance != NULL)
1869 setup_value = (gsize)lookup_instance;
1871 g_once_init_leave (&lookup, setup_value);
1877 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1883 get_apps_from_dir (GHashTable *apps,
1884 const char *dirname,
1888 const char *basename;
1889 char *filename, *subprefix, *desktop_id;
1891 GDesktopAppInfo *appinfo;
1893 dir = g_dir_open (dirname, 0, NULL);
1896 while ((basename = g_dir_read_name (dir)) != NULL)
1898 filename = g_build_filename (dirname, basename, NULL);
1899 if (g_str_has_suffix (basename, ".desktop"))
1901 desktop_id = g_strconcat (prefix, basename, NULL);
1903 /* Use _extended so we catch NULLs too (hidden) */
1904 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1906 appinfo = g_desktop_app_info_new_from_filename (filename);
1909 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1911 g_object_unref (appinfo);
1916 if (appinfo || hidden)
1918 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1922 /* Reuse instead of strdup here */
1923 appinfo->desktop_id = desktop_id;
1928 g_free (desktop_id);
1932 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1934 subprefix = g_strconcat (prefix, basename, "-", NULL);
1935 get_apps_from_dir (apps, filename, subprefix);
1947 * g_app_info_get_all:
1949 * Gets a list of all of the applications currently registered
1952 * For desktop files, this includes applications that have
1953 * <literal>NoDisplay=true</literal> set or are excluded from
1954 * display by means of <literal>OnlyShowIn</literal> or
1955 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1956 * The returned list does not include applications which have
1957 * the <literal>Hidden</literal> key set.
1959 * Returns: (element-type GAppInfo) (transfer full): a newly allocated #GList of references to #GAppInfo<!---->s.
1962 g_app_info_get_all (void)
1964 const char * const *dirs;
1966 GHashTableIter iter;
1971 dirs = get_applications_search_path ();
1973 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1977 for (i = 0; dirs[i] != NULL; i++)
1978 get_apps_from_dir (apps, dirs[i], "");
1982 g_hash_table_iter_init (&iter, apps);
1983 while (g_hash_table_iter_next (&iter, NULL, &value))
1986 infos = g_list_prepend (infos, value);
1989 g_hash_table_destroy (apps);
1991 return g_list_reverse (infos);
1994 /* Cacheing of mimeinfo.cache and defaults.list files */
1998 GHashTable *mime_info_cache_map;
1999 GHashTable *defaults_list_map;
2000 GHashTable *mimeapps_list_added_map;
2001 GHashTable *mimeapps_list_removed_map;
2002 time_t mime_info_cache_timestamp;
2003 time_t defaults_list_timestamp;
2004 time_t mimeapps_list_timestamp;
2008 GList *dirs; /* mimeinfo.cache and defaults.list */
2009 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2010 time_t last_stat_time;
2011 guint should_ping_mime_monitor : 1;
2014 static MimeInfoCache *mime_info_cache = NULL;
2015 G_LOCK_DEFINE_STATIC (mime_info_cache);
2017 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2018 const char *mime_type,
2019 char **new_desktop_file_ids);
2021 static MimeInfoCache * mime_info_cache_new (void);
2024 destroy_info_cache_value (gpointer key,
2028 g_list_foreach (value, (GFunc)g_free, NULL);
2029 g_list_free (value);
2033 destroy_info_cache_map (GHashTable *info_cache_map)
2035 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2036 g_hash_table_destroy (info_cache_map);
2040 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2041 const char *cache_file,
2047 filename = g_build_filename (dir->path, cache_file, NULL);
2049 if (g_stat (filename, &buf) < 0)
2056 if (buf.st_mtime != *timestamp)
2062 /* Call with lock held */
2064 remove_all (gpointer key,
2073 mime_info_cache_blow_global_cache (void)
2075 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2080 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2084 gchar *filename, **mime_types;
2091 if (dir->mime_info_cache_map != NULL &&
2092 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2093 &dir->mime_info_cache_timestamp))
2096 if (dir->mime_info_cache_map != NULL)
2097 destroy_info_cache_map (dir->mime_info_cache_map);
2099 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2100 (GDestroyNotify) g_free,
2103 key_file = g_key_file_new ();
2105 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2107 if (g_stat (filename, &buf) < 0)
2110 if (dir->mime_info_cache_timestamp > 0)
2111 mime_info_cache->should_ping_mime_monitor = TRUE;
2113 dir->mime_info_cache_timestamp = buf.st_mtime;
2115 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2120 if (load_error != NULL)
2123 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2126 if (load_error != NULL)
2129 for (i = 0; mime_types[i] != NULL; i++)
2131 gchar **desktop_file_ids;
2132 char *unaliased_type;
2133 desktop_file_ids = g_key_file_get_string_list (key_file,
2139 if (desktop_file_ids == NULL)
2142 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2143 mime_info_cache_dir_add_desktop_entries (dir,
2146 g_free (unaliased_type);
2148 g_strfreev (desktop_file_ids);
2151 g_strfreev (mime_types);
2152 g_key_file_free (key_file);
2157 g_key_file_free (key_file);
2159 if (mime_types != NULL)
2160 g_strfreev (mime_types);
2163 g_error_free (load_error);
2167 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2171 gchar *filename, **mime_types;
2172 char *unaliased_type;
2173 char **desktop_file_ids;
2180 if (dir->defaults_list_map != NULL &&
2181 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2182 &dir->defaults_list_timestamp))
2185 if (dir->defaults_list_map != NULL)
2186 g_hash_table_destroy (dir->defaults_list_map);
2187 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2188 g_free, (GDestroyNotify)g_strfreev);
2191 key_file = g_key_file_new ();
2193 filename = g_build_filename (dir->path, "defaults.list", NULL);
2194 if (g_stat (filename, &buf) < 0)
2197 if (dir->defaults_list_timestamp > 0)
2198 mime_info_cache->should_ping_mime_monitor = TRUE;
2200 dir->defaults_list_timestamp = buf.st_mtime;
2202 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2206 if (load_error != NULL)
2209 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2211 if (mime_types != NULL)
2213 for (i = 0; mime_types[i] != NULL; i++)
2215 desktop_file_ids = g_key_file_get_string_list (key_file,
2216 DEFAULT_APPLICATIONS_GROUP,
2220 if (desktop_file_ids == NULL)
2223 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2224 g_hash_table_replace (dir->defaults_list_map,
2229 g_strfreev (mime_types);
2232 g_key_file_free (key_file);
2237 g_key_file_free (key_file);
2239 if (mime_types != NULL)
2240 g_strfreev (mime_types);
2243 g_error_free (load_error);
2247 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2251 gchar *filename, **mime_types;
2252 char *unaliased_type;
2253 char **desktop_file_ids;
2260 if (dir->mimeapps_list_added_map != NULL &&
2261 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2262 &dir->mimeapps_list_timestamp))
2265 if (dir->mimeapps_list_added_map != NULL)
2266 g_hash_table_destroy (dir->mimeapps_list_added_map);
2267 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2268 g_free, (GDestroyNotify)g_strfreev);
2270 if (dir->mimeapps_list_removed_map != NULL)
2271 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2272 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2273 g_free, (GDestroyNotify)g_strfreev);
2275 key_file = g_key_file_new ();
2277 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2278 if (g_stat (filename, &buf) < 0)
2281 if (dir->mimeapps_list_timestamp > 0)
2282 mime_info_cache->should_ping_mime_monitor = TRUE;
2284 dir->mimeapps_list_timestamp = buf.st_mtime;
2286 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2290 if (load_error != NULL)
2293 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2295 if (mime_types != NULL)
2297 for (i = 0; mime_types[i] != NULL; i++)
2299 desktop_file_ids = g_key_file_get_string_list (key_file,
2300 ADDED_ASSOCIATIONS_GROUP,
2304 if (desktop_file_ids == NULL)
2307 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2308 g_hash_table_replace (dir->mimeapps_list_added_map,
2313 g_strfreev (mime_types);
2316 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2318 if (mime_types != NULL)
2320 for (i = 0; mime_types[i] != NULL; i++)
2322 desktop_file_ids = g_key_file_get_string_list (key_file,
2323 REMOVED_ASSOCIATIONS_GROUP,
2327 if (desktop_file_ids == NULL)
2330 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2331 g_hash_table_replace (dir->mimeapps_list_removed_map,
2336 g_strfreev (mime_types);
2339 g_key_file_free (key_file);
2344 g_key_file_free (key_file);
2346 if (mime_types != NULL)
2347 g_strfreev (mime_types);
2350 g_error_free (load_error);
2353 static MimeInfoCacheDir *
2354 mime_info_cache_dir_new (const char *path)
2356 MimeInfoCacheDir *dir;
2358 dir = g_new0 (MimeInfoCacheDir, 1);
2359 dir->path = g_strdup (path);
2365 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2370 if (dir->mime_info_cache_map != NULL)
2372 destroy_info_cache_map (dir->mime_info_cache_map);
2373 dir->mime_info_cache_map = NULL;
2377 if (dir->defaults_list_map != NULL)
2379 g_hash_table_destroy (dir->defaults_list_map);
2380 dir->defaults_list_map = NULL;
2383 if (dir->mimeapps_list_added_map != NULL)
2385 g_hash_table_destroy (dir->mimeapps_list_added_map);
2386 dir->mimeapps_list_added_map = NULL;
2389 if (dir->mimeapps_list_removed_map != NULL)
2391 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2392 dir->mimeapps_list_removed_map = NULL;
2399 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2400 const char *mime_type,
2401 char **new_desktop_file_ids)
2403 GList *desktop_file_ids;
2406 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2409 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2411 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2412 desktop_file_ids = g_list_append (desktop_file_ids,
2413 g_strdup (new_desktop_file_ids[i]));
2416 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2420 mime_info_cache_init_dir_lists (void)
2422 const char * const *dirs;
2425 mime_info_cache = mime_info_cache_new ();
2427 dirs = get_applications_search_path ();
2429 for (i = 0; dirs[i] != NULL; i++)
2431 MimeInfoCacheDir *dir;
2433 dir = mime_info_cache_dir_new (dirs[i]);
2437 mime_info_cache_dir_init (dir);
2438 mime_info_cache_dir_init_defaults_list (dir);
2439 mime_info_cache_dir_init_mimeapps_list (dir);
2441 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2447 mime_info_cache_update_dir_lists (void)
2451 tmp = mime_info_cache->dirs;
2455 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2457 /* No need to do this if we had file monitors... */
2458 mime_info_cache_blow_global_cache ();
2459 mime_info_cache_dir_init (dir);
2460 mime_info_cache_dir_init_defaults_list (dir);
2461 mime_info_cache_dir_init_mimeapps_list (dir);
2468 mime_info_cache_init (void)
2470 G_LOCK (mime_info_cache);
2471 if (mime_info_cache == NULL)
2472 mime_info_cache_init_dir_lists ();
2478 if (now >= mime_info_cache->last_stat_time + 10)
2480 mime_info_cache_update_dir_lists ();
2481 mime_info_cache->last_stat_time = now;
2485 if (mime_info_cache->should_ping_mime_monitor)
2487 /* g_idle_add (emit_mime_changed, NULL); */
2488 mime_info_cache->should_ping_mime_monitor = FALSE;
2491 G_UNLOCK (mime_info_cache);
2494 static MimeInfoCache *
2495 mime_info_cache_new (void)
2497 MimeInfoCache *cache;
2499 cache = g_new0 (MimeInfoCache, 1);
2501 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2502 (GDestroyNotify) g_free,
2503 (GDestroyNotify) g_free);
2508 mime_info_cache_free (MimeInfoCache *cache)
2513 g_list_foreach (cache->dirs,
2514 (GFunc) mime_info_cache_dir_free,
2516 g_list_free (cache->dirs);
2517 g_hash_table_destroy (cache->global_defaults_cache);
2522 * mime_info_cache_reload:
2523 * @dir: directory path which needs reloading.
2525 * Reload the mime information for the @dir.
2528 mime_info_cache_reload (const char *dir)
2530 /* FIXME: just reload the dir that needs reloading,
2531 * don't blow the whole cache
2533 if (mime_info_cache != NULL)
2535 G_LOCK (mime_info_cache);
2536 mime_info_cache_free (mime_info_cache);
2537 mime_info_cache = NULL;
2538 G_UNLOCK (mime_info_cache);
2543 append_desktop_entry (GList *list,
2544 const char *desktop_entry,
2545 GList *removed_entries)
2547 /* Add if not already in list, and valid */
2548 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2549 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2550 list = g_list_prepend (list, g_strdup (desktop_entry));
2556 * get_all_desktop_entries_for_mime_type:
2557 * @mime_type: a mime type.
2558 * @except: NULL or a strv list
2560 * Returns all the desktop ids for @mime_type. The desktop files
2561 * are listed in an order so that default applications are listed before
2562 * non-default ones, and handlers for inherited mimetypes are listed
2563 * after the base ones.
2565 * Optionally doesn't list the desktop ids given in the @except
2567 * Return value: a #GList containing the desktop ids which claim
2568 * to handle @mime_type.
2571 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2572 const char **except)
2574 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2575 MimeInfoCacheDir *dir;
2578 char **default_entries;
2579 char **removed_associations;
2584 mime_info_cache_init ();
2586 /* collect all ancestors */
2587 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2588 array = g_ptr_array_new ();
2589 for (i = 0; mime_types[i]; i++)
2590 g_ptr_array_add (array, mime_types[i]);
2591 g_free (mime_types);
2592 for (i = 0; i < array->len; i++)
2594 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2595 for (j = 0; anc[j]; j++)
2597 for (k = 0; k < array->len; k++)
2599 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2602 if (k == array->len) /* not found */
2603 g_ptr_array_add (array, g_strdup (anc[j]));
2607 g_ptr_array_add (array, NULL);
2608 mime_types = (char **)g_ptr_array_free (array, FALSE);
2610 G_LOCK (mime_info_cache);
2612 removed_entries = NULL;
2613 desktop_entries = NULL;
2615 for (i = 0; except != NULL && except[i] != NULL; i++)
2616 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2618 for (i = 0; mime_types[i] != NULL; i++)
2620 mime_type = mime_types[i];
2622 /* Go through all apps listed as defaults */
2623 for (dir_list = mime_info_cache->dirs;
2625 dir_list = dir_list->next)
2627 dir = dir_list->data;
2629 /* First added associations from mimeapps.list */
2630 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2631 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2632 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2634 /* Then removed associations from mimeapps.list */
2635 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2636 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2637 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2639 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2640 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2641 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2642 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2645 /* Go through all entries that support the mimetype */
2646 for (dir_list = mime_info_cache->dirs;
2648 dir_list = dir_list->next)
2650 dir = dir_list->data;
2652 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2653 for (tmp = list; tmp != NULL; tmp = tmp->next)
2654 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2658 G_UNLOCK (mime_info_cache);
2660 g_strfreev (mime_types);
2662 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2663 g_list_free (removed_entries);
2665 desktop_entries = g_list_reverse (desktop_entries);
2667 return desktop_entries;
2670 /* GDesktopAppInfoLookup interface: */
2672 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2673 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2676 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2681 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2682 * @lookup: a #GDesktopAppInfoLookup
2683 * @uri_scheme: a string containing a URI scheme.
2685 * Gets the default application for launching applications
2686 * using this URI scheme for a particular GDesktopAppInfoLookup
2689 * The GDesktopAppInfoLookup interface and this function is used
2690 * to implement g_app_info_get_default_for_uri_scheme() backends
2691 * in a GIO module. There is no reason for applications to use it
2692 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2694 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2697 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2698 const char *uri_scheme)
2700 GDesktopAppInfoLookupIface *iface;
2702 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2704 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2706 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);