1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright © 2007 Ryan Lortie
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Author: Alexander Larsson <alexl@redhat.com>
31 #ifdef HAVE_CRT_EXTERNS_H
32 #include <crt_externs.h>
35 #include "gcontenttypeprivate.h"
36 #include "gdesktopappinfo.h"
39 #include "gthemedicon.h"
40 #include "gfileicon.h"
41 #include <glib/gstdio.h>
43 #include "giomodule-priv.h"
49 * SECTION:gdesktopappinfo
50 * @short_description: Application information from desktop files
51 * @include: gio/gdesktopappinfo.h
53 * #GDesktopAppInfo is an implementation of #GAppInfo based on
56 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
57 * the UNIX-specific GIO interfaces, thus you have to use the
58 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
61 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
62 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
63 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
64 #define MIME_CACHE_GROUP "MIME Cache"
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 ? */
100 guint startup_notify : 1;
102 /* FIXME: what about StartupWMClass ? */
105 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
106 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
107 g_desktop_app_info_iface_init))
110 search_path_init (gpointer data)
113 const char * const *data_dirs;
114 const char *user_data_dir;
117 data_dirs = g_get_system_data_dirs ();
118 length = g_strv_length ((char **) data_dirs);
120 args = g_new (char *, length + 2);
123 user_data_dir = g_get_user_data_dir ();
124 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
125 for (i = 0; i < length; i++)
126 args[j++] = g_build_filename (data_dirs[i],
127 "applications", NULL);
133 static const char * const *
134 get_applications_search_path (void)
136 static GOnce once_init = G_ONCE_INIT;
137 return g_once (&once_init, search_path_init, NULL);
141 g_desktop_app_info_finalize (GObject *object)
143 GDesktopAppInfo *info;
145 info = G_DESKTOP_APP_INFO (object);
147 g_free (info->desktop_id);
148 g_free (info->filename);
150 g_free (info->comment);
151 g_free (info->icon_name);
153 g_object_unref (info->icon);
154 g_strfreev (info->only_show_in);
155 g_strfreev (info->not_show_in);
156 g_free (info->try_exec);
158 g_free (info->binary);
161 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
165 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
167 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
169 gobject_class->finalize = g_desktop_app_info_finalize;
173 g_desktop_app_info_init (GDesktopAppInfo *local)
178 binary_from_exec (const char *exec)
180 const char *p, *start;
186 while (*p != ' ' && *p != 0)
189 return g_strndup (start, p - start);
194 * g_desktop_app_info_new_from_keyfile:
195 * @key_file: an opened #GKeyFile
197 * Creates a new #GDesktopAppInfo.
199 * Returns: a new #GDesktopAppInfo or %NULL on error.
204 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
206 GDesktopAppInfo *info;
211 start_group = g_key_file_get_start_group (key_file);
212 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
214 g_free (start_group);
217 g_free (start_group);
219 type = g_key_file_get_string (key_file,
220 G_KEY_FILE_DESKTOP_GROUP,
221 G_KEY_FILE_DESKTOP_KEY_TYPE,
223 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
230 try_exec = g_key_file_get_string (key_file,
231 G_KEY_FILE_DESKTOP_GROUP,
232 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
234 if (try_exec && try_exec[0] != '\0')
237 t = g_find_program_in_path (try_exec);
246 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
247 info->filename = NULL;
249 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
250 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
251 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
252 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
253 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);
254 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);
255 info->try_exec = try_exec;
256 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
257 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
258 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
259 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
260 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
261 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
266 if (g_path_is_absolute (info->icon_name))
270 file = g_file_new_for_path (info->icon_name);
271 info->icon = g_file_icon_new (file);
272 g_object_unref (file);
278 /* Work around a common mistake in desktop files */
279 if ((p = strrchr (info->icon_name, '.')) != NULL &&
280 (strcmp (p, ".png") == 0 ||
281 strcmp (p, ".xpm") == 0 ||
282 strcmp (p, ".svg") == 0))
285 info->icon = g_themed_icon_new (info->icon_name);
290 info->binary = binary_from_exec (info->exec);
292 if (info->path && info->path[0] == '\0')
302 * g_desktop_app_info_new_from_filename:
303 * @filename: the path of a desktop file, in the GLib filename encoding
305 * Creates a new #GDesktopAppInfo.
307 * Returns: a new #GDesktopAppInfo or %NULL on error.
310 g_desktop_app_info_new_from_filename (const char *filename)
313 GDesktopAppInfo *info = NULL;
315 key_file = g_key_file_new ();
317 if (g_key_file_load_from_file (key_file,
322 info = g_desktop_app_info_new_from_keyfile (key_file);
324 info->filename = g_strdup (filename);
327 g_key_file_free (key_file);
333 * g_desktop_app_info_new:
334 * @desktop_id: the desktop file id
336 * Creates a new #GDesktopAppInfo based on a desktop file id.
338 * A desktop file id is the basename of the desktop file, including the
339 * .desktop extension. GIO is looking for a desktop file with this name
340 * in the <filename>applications</filename> subdirectories of the XDG data
341 * directories (i.e. the directories specified in the
342 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
343 * variables). GIO also supports the prefix-to-subdirectory mapping that is
344 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
345 * (i.e. a desktop id of kde-foo.desktop will match
346 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
348 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
351 g_desktop_app_info_new (const char *desktop_id)
353 GDesktopAppInfo *appinfo;
354 const char * const *dirs;
358 dirs = get_applications_search_path ();
360 basename = g_strdup (desktop_id);
362 for (i = 0; dirs[i] != NULL; i++)
367 filename = g_build_filename (dirs[i], desktop_id, NULL);
368 appinfo = g_desktop_app_info_new_from_filename (filename);
374 while ((p = strchr (p, '-')) != NULL)
378 filename = g_build_filename (dirs[i], basename, NULL);
379 appinfo = g_desktop_app_info_new_from_filename (filename);
394 appinfo->desktop_id = g_strdup (desktop_id);
396 if (g_desktop_app_info_get_is_hidden (appinfo))
398 g_object_unref (appinfo);
406 g_desktop_app_info_dup (GAppInfo *appinfo)
408 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
409 GDesktopAppInfo *new_info;
411 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
413 new_info->filename = g_strdup (info->filename);
414 new_info->desktop_id = g_strdup (info->desktop_id);
416 new_info->name = g_strdup (info->name);
417 new_info->comment = g_strdup (info->comment);
418 new_info->nodisplay = info->nodisplay;
419 new_info->icon_name = g_strdup (info->icon_name);
420 new_info->icon = g_object_ref (info->icon);
421 new_info->only_show_in = g_strdupv (info->only_show_in);
422 new_info->not_show_in = g_strdupv (info->not_show_in);
423 new_info->try_exec = g_strdup (info->try_exec);
424 new_info->exec = g_strdup (info->exec);
425 new_info->binary = g_strdup (info->binary);
426 new_info->path = g_strdup (info->path);
427 new_info->hidden = info->hidden;
428 new_info->terminal = info->terminal;
429 new_info->startup_notify = info->startup_notify;
431 return G_APP_INFO (new_info);
435 g_desktop_app_info_equal (GAppInfo *appinfo1,
438 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
439 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
441 if (info1->desktop_id == NULL ||
442 info2->desktop_id == NULL)
443 return info1 == info2;
445 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
449 g_desktop_app_info_get_id (GAppInfo *appinfo)
451 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
453 return info->desktop_id;
457 g_desktop_app_info_get_name (GAppInfo *appinfo)
459 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
461 if (info->name == NULL)
467 * g_desktop_app_info_get_is_hidden:
468 * @info: a #GDesktopAppInfo.
470 * A desktop file is hidden if the Hidden key in it is
473 * Returns: %TRUE if hidden, %FALSE otherwise.
476 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
482 g_desktop_app_info_get_description (GAppInfo *appinfo)
484 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
486 return info->comment;
490 g_desktop_app_info_get_executable (GAppInfo *appinfo)
492 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
498 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
500 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
506 g_desktop_app_info_get_icon (GAppInfo *appinfo)
508 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
514 expand_macro_single (char macro, char *uri)
520 file = g_file_new_for_uri (uri);
521 path = g_file_get_path (file);
522 g_object_unref (file);
528 result = g_shell_quote (uri);
533 result = g_shell_quote (path);
539 name = g_path_get_dirname (path);
540 result = g_shell_quote (name);
548 name = g_path_get_basename (path);
549 result = g_shell_quote (name);
561 expand_macro (char macro,
563 GDesktopAppInfo *info,
566 GList *uris = *uri_list;
568 gboolean force_file_uri;
569 char force_file_uri_macro;
571 g_return_if_fail (exec != NULL);
573 /* On %u and %U, pass POSIX file path pointing to the URI via
574 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
575 * running or the URI doesn't have a POSIX file path via FUSE
576 * we'll just pass the URI.
578 force_file_uri_macro = macro;
579 force_file_uri = FALSE;
585 force_file_uri_macro = 'f';
586 force_file_uri = TRUE;
589 force_file_uri_macro = 'F';
590 force_file_uri = TRUE;
607 expanded = expand_macro_single (macro, uris->data);
611 expanded = expand_macro_single (force_file_uri_macro, uris->data);
612 if (expanded == NULL)
613 expanded = expand_macro_single (macro, uris->data);
618 g_string_append (exec, expanded);
634 expanded = expand_macro_single (macro, uris->data);
638 expanded = expand_macro_single (force_file_uri_macro, uris->data);
639 if (expanded == NULL)
640 expanded = expand_macro_single (macro, uris->data);
645 g_string_append (exec, expanded);
651 if (uris != NULL && expanded)
652 g_string_append_c (exec, ' ');
660 g_string_append (exec, "--icon ");
661 g_string_append (exec, info->icon_name);
667 g_string_append (exec, info->name);
672 g_string_append (exec, info->filename);
675 case 'm': /* deprecated */
679 g_string_append_c (exec, '%');
687 expand_application_parameters (GDesktopAppInfo *info,
693 GList *uri_list = *uris;
694 const char *p = info->exec;
695 GString *expanded_exec = g_string_new (NULL);
698 if (info->exec == NULL)
700 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
701 _("Desktop file didn't specify Exec field"));
707 if (p[0] == '%' && p[1] != '\0')
709 expand_macro (p[1], expanded_exec, info, uris);
713 g_string_append_c (expanded_exec, *p);
718 /* No file substitutions */
719 if (uri_list == *uris && uri_list != NULL)
721 /* If there is no macro default to %f. This is also what KDE does */
722 g_string_append_c (expanded_exec, ' ');
723 expand_macro ('f', expanded_exec, info, uris);
726 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
727 g_string_free (expanded_exec, TRUE);
732 prepend_terminal_to_vector (int *argc,
739 char **term_argv = NULL;
744 g_return_val_if_fail (argc != NULL, FALSE);
745 g_return_val_if_fail (argv != NULL, FALSE);
753 /* compute size if not given */
756 for (i = 0; the_argv[i] != NULL; i++)
762 term_argv = g_new0 (char *, 3);
764 check = g_find_program_in_path ("gnome-terminal");
767 term_argv[0] = check;
768 /* Note that gnome-terminal takes -x and
769 * as -e in gnome-terminal is broken we use that. */
770 term_argv[1] = g_strdup ("-x");
775 check = g_find_program_in_path ("nxterm");
777 check = g_find_program_in_path ("color-xterm");
779 check = g_find_program_in_path ("rxvt");
781 check = g_find_program_in_path ("xterm");
783 check = g_find_program_in_path ("dtterm");
786 check = g_strdup ("xterm");
787 g_warning ("couldn't find a terminal, falling back to xterm");
789 term_argv[0] = check;
790 term_argv[1] = g_strdup ("-e");
793 real_argc = term_argc + *argc;
794 real_argv = g_new (char *, real_argc + 1);
796 for (i = 0; i < term_argc; i++)
797 real_argv[i] = term_argv[i];
799 for (j = 0; j < *argc; j++, i++)
800 real_argv[i] = (char *)the_argv[j];
808 /* we use g_free here as we sucked all the inner strings
809 * out from it into real_argv */
814 #endif /* G_OS_WIN32 */
817 /* '=' is the new '\0'.
818 * DO NOT CALL unless at least one string ends with '='
821 is_env (const char *a,
826 if (*a == 0 || *b == 0)
839 /* free with g_strfreev */
841 replace_env_var (char **old_environ,
843 const char *new_value)
845 int length, new_length;
846 int index, new_index;
850 /* do two things at once:
851 * - discover the length of the environment ('length')
852 * - find the location (if any) of the env var ('index')
855 for (length = 0; old_environ[length]; length++)
857 /* if we already have it in our environment, replace */
858 if (is_env (old_environ[length], env_var))
863 /* no current env var, no desired env value.
866 if (new_value == NULL && index == -1)
869 /* in all cases now, we will be using a modified environment.
870 * determine its length and allocated it.
873 * new_index = location to insert, if any
874 * new_length = length of the new array
875 * new_environ = the pointer array for the new environment
878 if (new_value == NULL && index >= 0)
880 /* in this case, we will be removing an entry */
881 new_length = length - 1;
884 else if (new_value != NULL && index < 0)
886 /* in this case, we will be adding an entry to the end */
887 new_length = length + 1;
891 /* in this case, we will be replacing the existing entry */
897 new_environ = g_malloc (sizeof (char *) * (new_length + 1));
898 new_environ[new_length] = NULL;
900 /* now we do the copying.
901 * for each entry in the new environment, we decide what to do
905 for (new_i = 0; new_i < new_length; new_i++)
907 if (new_i == new_index)
909 /* insert our new item */
910 new_environ[new_i] = g_strconcat (env_var,
915 /* if we had an old entry, skip it now */
921 /* if this is the old DESKTOP_STARTUP_ID, skip it */
925 /* copy an old item */
926 new_environ[new_i] = g_strdup (old_environ[i]);
931 g_strfreev (old_environ);
937 uri_list_segment_to_files (GList *start,
944 while (start != NULL && start != end)
946 file = g_file_new_for_uri ((char *)start->data);
947 res = g_list_prepend (res, file);
951 return g_list_reverse (res);
954 #ifdef HAVE__NSGETENVIRON
955 #define environ (*_NSGetEnviron())
956 #elif !defined(G_OS_WIN32)
958 /* According to the Single Unix Specification, environ is not in
959 * * any system header, although unistd.h often declares it.
961 extern char **environ;
965 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
967 GAppLaunchContext *launch_context,
970 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
971 gboolean completed = FALSE;
973 GList *launched_files;
980 g_return_val_if_fail (appinfo != NULL, FALSE);
988 if (!expand_application_parameters (info, &uris,
989 &argc, &argv, error))
992 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
994 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
995 _("Unable to find terminal required for application"));
1002 launched_files = uri_list_segment_to_files (old_uris, uris);
1004 display = g_app_launch_context_get_display (launch_context,
1009 if (info->startup_notify)
1010 sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
1014 if (display || sn_id)
1018 envp = g_new0 (char *, 1);
1020 envp = g_strdupv (environ);
1024 envp = replace_env_var (envp,
1029 envp = replace_env_var (envp,
1030 "DESKTOP_STARTUP_ID",
1036 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
1037 g_list_free (launched_files);
1040 if (!g_spawn_async (info->path, /* working directory */
1043 G_SPAWN_SEARCH_PATH /* flags */,
1044 NULL /* child_setup */,
1046 NULL /* child_pid */,
1051 g_app_launch_context_launch_failed (launch_context, sn_id);
1065 while (uris != NULL);
1077 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
1079 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1081 return info->exec &&
1082 ((strstr (info->exec, "%u") != NULL) ||
1083 (strstr (info->exec, "%U") != NULL));
1087 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1089 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1091 return info->exec &&
1092 ((strstr (info->exec, "%f") != NULL) ||
1093 (strstr (info->exec, "%F") != NULL));
1097 g_desktop_app_info_launch (GAppInfo *appinfo,
1099 GAppLaunchContext *launch_context,
1109 uri = g_file_get_uri (files->data);
1110 uris = g_list_prepend (uris, uri);
1111 files = files->next;
1114 uris = g_list_reverse (uris);
1116 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1118 g_list_foreach (uris, (GFunc)g_free, NULL);
1124 G_LOCK_DEFINE_STATIC (g_desktop_env);
1125 static gchar *g_desktop_env = NULL;
1128 * g_desktop_app_info_set_desktop_env:
1129 * @desktop_env: a string specifying what desktop this is
1131 * Sets the name of the desktop that the application is running in.
1132 * This is used by g_app_info_should_show() to evaluate the
1133 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1134 * desktop entry fields.
1136 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1137 * Menu specification</ulink> recognizes the following:
1139 * <member>GNOME</member>
1140 * <member>KDE</member>
1141 * <member>ROX</member>
1142 * <member>XFCE</member>
1143 * <member>Old</member>
1146 * Should be called only once; subsequent calls are ignored.
1149 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1151 G_LOCK (g_desktop_env);
1153 g_desktop_env = g_strdup (desktop_env);
1154 G_UNLOCK (g_desktop_env);
1158 g_desktop_app_info_should_show (GAppInfo *appinfo)
1160 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1162 const gchar *desktop_env;
1165 if (info->nodisplay)
1168 G_LOCK (g_desktop_env);
1169 desktop_env = g_desktop_env;
1170 G_UNLOCK (g_desktop_env);
1172 if (info->only_show_in)
1174 if (desktop_env == NULL)
1178 for (i = 0; info->only_show_in[i] != NULL; i++)
1180 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1190 if (info->not_show_in && desktop_env)
1192 for (i = 0; info->not_show_in[i] != NULL; i++)
1194 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1208 ensure_dir (DirType type,
1211 char *path, *display_name;
1214 if (type == APP_DIR)
1215 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1217 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1220 if (g_mkdir_with_parents (path, 0700) == 0)
1224 display_name = g_filename_display_name (path);
1225 if (type == APP_DIR)
1226 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1227 _("Can't create user application configuration folder %s: %s"),
1228 display_name, g_strerror (errsv));
1230 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1231 _("Can't create user MIME configuration folder %s: %s"),
1232 display_name, g_strerror (errsv));
1234 g_free (display_name);
1241 update_mimeapps_list (const char *desktop_id,
1242 const char *content_type,
1243 gboolean add_as_default,
1244 gboolean add_non_default,
1248 char *dirname, *filename;
1250 gboolean load_succeeded, res;
1251 char **old_list, **list;
1252 GList *system_list, *l;
1253 gsize length, data_size;
1256 char **content_types;
1258 /* Don't add both at start and end */
1259 g_assert (!(add_as_default && add_non_default));
1261 dirname = ensure_dir (APP_DIR, error);
1265 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1268 key_file = g_key_file_new ();
1269 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1270 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1272 g_key_file_free (key_file);
1273 key_file = g_key_file_new ();
1278 content_types = g_new (char *, 2);
1279 content_types[0] = g_strdup (content_type);
1280 content_types[1] = NULL;
1284 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1287 for (k = 0; content_types && content_types[k]; k++)
1289 /* Add to the right place in the list */
1292 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1293 content_types[k], &length, NULL);
1295 list = g_new (char *, 1 + length + 1);
1299 list[i++] = g_strdup (desktop_id);
1302 for (j = 0; old_list[j] != NULL; j++)
1304 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1305 list[i++] = g_strdup (old_list[j]);
1306 else if (add_non_default)
1308 /* If adding as non-default, and it's already in,
1309 don't change order of desktop ids */
1310 add_non_default = FALSE;
1311 list[i++] = g_strdup (old_list[j]);
1316 if (add_non_default)
1318 /* We're adding as non-default, and it wasn't already in the list,
1319 so we add at the end. But to avoid listing the app before the
1320 current system default (thus changing the default) we have to
1321 add the current list of (not yet listed) apps before it. */
1323 list[i] = NULL; /* Terminate current list so we can use it */
1324 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1326 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1328 for (l = system_list; l != NULL; l = l->next)
1330 list[i++] = l->data; /* no strdup, taking ownership */
1331 if (g_strcmp0 (l->data, desktop_id) == 0)
1332 add_non_default = FALSE;
1334 g_list_free (system_list);
1336 if (add_non_default)
1337 list[i++] = g_strdup (desktop_id);
1342 g_strfreev (old_list);
1344 if (list[0] == NULL || desktop_id == NULL)
1345 g_key_file_remove_key (key_file,
1346 ADDED_ASSOCIATIONS_GROUP,
1350 g_key_file_set_string_list (key_file,
1351 ADDED_ASSOCIATIONS_GROUP,
1353 (const char * const *)list, i);
1360 /* reuse the list from above */
1364 g_strfreev (content_types);
1365 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1368 for (k = 0; content_types && content_types[k]; k++)
1370 /* Remove from removed associations group (unless remove) */
1373 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1374 content_types[k], &length, NULL);
1376 list = g_new (char *, 1 + length + 1);
1380 list[i++] = g_strdup (desktop_id);
1383 for (j = 0; old_list[j] != NULL; j++)
1385 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1386 list[i++] = g_strdup (old_list[j]);
1391 g_strfreev (old_list);
1393 if (list[0] == NULL || desktop_id == NULL)
1394 g_key_file_remove_key (key_file,
1395 REMOVED_ASSOCIATIONS_GROUP,
1399 g_key_file_set_string_list (key_file,
1400 REMOVED_ASSOCIATIONS_GROUP,
1402 (const char * const *)list, i);
1407 g_strfreev (content_types);
1409 data = g_key_file_to_data (key_file, &data_size, error);
1410 g_key_file_free (key_file);
1412 res = g_file_set_contents (filename, data, data_size, error);
1414 mime_info_cache_reload (NULL);
1423 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1424 const char *content_type,
1427 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1429 if (!g_desktop_app_info_ensure_saved (info, error))
1432 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1436 update_program_done (GPid pid,
1440 /* Did the application exit correctly */
1441 if (WIFEXITED (status) &&
1442 WEXITSTATUS (status) == 0)
1444 /* Here we could clean out any caches in use */
1449 run_update_command (char *command,
1458 GError *error = NULL;
1461 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1463 if (g_spawn_async ("/", argv,
1465 G_SPAWN_SEARCH_PATH |
1466 G_SPAWN_STDOUT_TO_DEV_NULL |
1467 G_SPAWN_STDERR_TO_DEV_NULL |
1468 G_SPAWN_DO_NOT_REAP_CHILD,
1469 NULL, NULL, /* No setup function */
1472 g_child_watch_add (pid, update_program_done, NULL);
1475 /* If we get an error at this point, it's quite likely the user doesn't
1476 * have an installed copy of either 'update-mime-database' or
1477 * 'update-desktop-database'. I don't think we want to popup an error
1478 * dialog at this point, so we just do a g_warning to give the user a
1479 * chance of debugging it.
1481 g_warning ("%s", error->message);
1488 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1489 const char *extension,
1492 char *filename, *basename, *mimetype;
1496 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1499 dirname = ensure_dir (MIMETYPE_DIR, error);
1503 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1504 filename = g_build_filename (dirname, basename, NULL);
1508 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1510 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1515 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1516 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1517 " <mime-type type=\"%s\">\n"
1518 " <comment>%s document</comment>\n"
1519 " <glob pattern=\"*.%s\"/>\n"
1521 "</mime-info>\n", mimetype, extension, extension);
1523 g_file_set_contents (filename, contents, -1, NULL);
1526 run_update_command ("update-mime-database", "mime");
1530 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1540 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1541 const char *content_type,
1544 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1546 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1549 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1553 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1559 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1560 const char *content_type,
1563 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1565 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1568 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1572 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1578 char *data, *desktop_id;
1583 if (info->filename != NULL)
1586 /* This is only used for object created with
1587 * g_app_info_create_from_commandline. All other
1588 * object should have a filename
1591 dirname = ensure_dir (APP_DIR, error);
1595 key_file = g_key_file_new ();
1597 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1598 "Encoding", "UTF-8");
1599 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1600 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1601 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1602 G_KEY_FILE_DESKTOP_KEY_TYPE,
1603 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1605 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1606 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1608 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1609 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1611 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1612 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1614 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1615 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1617 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1618 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1620 data = g_key_file_to_data (key_file, &data_size, NULL);
1621 g_key_file_free (key_file);
1623 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1624 filename = g_build_filename (dirname, desktop_id, NULL);
1625 g_free (desktop_id);
1628 fd = g_mkstemp (filename);
1633 display_name = g_filename_display_name (filename);
1634 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1635 _("Can't create user desktop file %s"), display_name);
1636 g_free (display_name);
1642 desktop_id = g_path_get_basename (filename);
1646 res = g_file_set_contents (filename, data, data_size, error);
1649 g_free (desktop_id);
1654 info->filename = filename;
1655 info->desktop_id = desktop_id;
1657 run_update_command ("update-desktop-database", "applications");
1663 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1665 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1669 if (strstr (info->filename, "/userapp-"))
1670 return g_access (info->filename, W_OK) == 0;
1677 g_desktop_app_info_delete (GAppInfo *appinfo)
1679 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1683 if (g_remove (info->filename) == 0)
1685 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1687 g_free (info->filename);
1688 info->filename = NULL;
1689 g_free (info->desktop_id);
1690 info->desktop_id = NULL;
1700 * g_app_info_create_from_commandline:
1701 * @commandline: the commandline to use
1702 * @application_name: the application name, or %NULL to use @commandline
1703 * @flags: flags that can specify details of the created #GAppInfo
1704 * @error: a #GError location to store the error occuring, %NULL to ignore.
1706 * Creates a new #GAppInfo from the given information.
1708 * Returns: new #GAppInfo for given command.
1711 g_app_info_create_from_commandline (const char *commandline,
1712 const char *application_name,
1713 GAppInfoCreateFlags flags,
1718 GDesktopAppInfo *info;
1720 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1722 info->filename = NULL;
1723 info->desktop_id = NULL;
1725 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1726 info->startup_notify = FALSE;
1727 info->hidden = FALSE;
1728 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1729 info->exec = g_strconcat (commandline, " %u", NULL);
1731 info->exec = g_strconcat (commandline, " %f", NULL);
1732 info->nodisplay = TRUE;
1733 info->binary = binary_from_exec (info->exec);
1735 if (application_name)
1736 info->name = g_strdup (application_name);
1739 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1740 split = g_strsplit (commandline, " ", 2);
1741 basename = g_path_get_basename (split[0]);
1743 info->name = basename;
1744 if (info->name == NULL)
1745 info->name = g_strdup ("custom");
1747 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1749 return G_APP_INFO (info);
1753 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1755 iface->dup = g_desktop_app_info_dup;
1756 iface->equal = g_desktop_app_info_equal;
1757 iface->get_id = g_desktop_app_info_get_id;
1758 iface->get_name = g_desktop_app_info_get_name;
1759 iface->get_description = g_desktop_app_info_get_description;
1760 iface->get_executable = g_desktop_app_info_get_executable;
1761 iface->get_icon = g_desktop_app_info_get_icon;
1762 iface->launch = g_desktop_app_info_launch;
1763 iface->supports_uris = g_desktop_app_info_supports_uris;
1764 iface->supports_files = g_desktop_app_info_supports_files;
1765 iface->launch_uris = g_desktop_app_info_launch_uris;
1766 iface->should_show = g_desktop_app_info_should_show;
1767 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1768 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1769 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1770 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1771 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1772 iface->can_delete = g_desktop_app_info_can_delete;
1773 iface->do_delete = g_desktop_app_info_delete;
1774 iface->get_commandline = g_desktop_app_info_get_commandline;
1778 app_info_in_list (GAppInfo *info,
1781 while (list != NULL)
1783 if (g_app_info_equal (info, list->data))
1792 * g_app_info_get_all_for_type:
1793 * @content_type: the content type to find a #GAppInfo for
1795 * Gets a list of all #GAppInfo s for a given content type.
1797 * Returns: #GList of #GAppInfo s for given @content_type
1798 * or %NULL on error.
1801 g_app_info_get_all_for_type (const char *content_type)
1803 GList *desktop_entries, *l;
1805 GDesktopAppInfo *info;
1807 g_return_val_if_fail (content_type != NULL, NULL);
1809 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1812 for (l = desktop_entries; l != NULL; l = l->next)
1814 char *desktop_entry = l->data;
1816 info = g_desktop_app_info_new (desktop_entry);
1819 if (app_info_in_list (G_APP_INFO (info), infos))
1820 g_object_unref (info);
1822 infos = g_list_prepend (infos, info);
1824 g_free (desktop_entry);
1827 g_list_free (desktop_entries);
1829 return g_list_reverse (infos);
1833 * g_app_info_reset_type_associations:
1834 * @content_type: a content type
1836 * Removes all changes to the type associations done by
1837 * g_app_info_set_as_default_for_type(),
1838 * g_app_info_set_as_default_for_extension(),
1839 * g_app_info_add_supports_type() of g_app_info_remove_supports_type().
1844 g_app_info_reset_type_associations (const char *content_type)
1846 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1850 * g_app_info_get_default_for_type:
1851 * @content_type: the content type to find a #GAppInfo for
1852 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1855 * Gets the #GAppInfo that correspond to a given content type.
1857 * Returns: #GAppInfo for given @content_type or %NULL on error.
1860 g_app_info_get_default_for_type (const char *content_type,
1861 gboolean must_support_uris)
1863 GList *desktop_entries, *l;
1866 g_return_val_if_fail (content_type != NULL, NULL);
1868 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1871 for (l = desktop_entries; l != NULL; l = l->next)
1873 char *desktop_entry = l->data;
1875 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1878 if (must_support_uris && !g_app_info_supports_uris (info))
1880 g_object_unref (info);
1888 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1889 g_list_free (desktop_entries);
1895 * g_app_info_get_default_for_uri_scheme:
1896 * @uri_scheme: a string containing a URI scheme.
1898 * Gets the default application for launching applications
1899 * using this URI scheme. A URI scheme is the initial part
1900 * of the URI, up to but not including the ':', e.g. "http",
1903 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1906 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1908 static gsize lookup = 0;
1910 if (g_once_init_enter (&lookup))
1912 gsize setup_value = 1;
1913 GDesktopAppInfoLookup *lookup_instance;
1914 const char *use_this;
1915 GIOExtensionPoint *ep;
1916 GIOExtension *extension;
1919 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1921 /* Ensure vfs in modules loaded */
1922 _g_io_modules_ensure_loaded ();
1924 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1926 lookup_instance = NULL;
1929 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1931 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1934 if (lookup_instance == NULL)
1936 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1938 extension = l->data;
1939 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1940 if (lookup_instance != NULL)
1945 if (lookup_instance != NULL)
1946 setup_value = (gsize)lookup_instance;
1948 g_once_init_leave (&lookup, setup_value);
1954 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1960 get_apps_from_dir (GHashTable *apps,
1961 const char *dirname,
1965 const char *basename;
1966 char *filename, *subprefix, *desktop_id;
1968 GDesktopAppInfo *appinfo;
1970 dir = g_dir_open (dirname, 0, NULL);
1973 while ((basename = g_dir_read_name (dir)) != NULL)
1975 filename = g_build_filename (dirname, basename, NULL);
1976 if (g_str_has_suffix (basename, ".desktop"))
1978 desktop_id = g_strconcat (prefix, basename, NULL);
1980 /* Use _extended so we catch NULLs too (hidden) */
1981 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1983 appinfo = g_desktop_app_info_new_from_filename (filename);
1985 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1987 g_object_unref (appinfo);
1992 if (appinfo || hidden)
1994 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1998 /* Reuse instead of strdup here */
1999 appinfo->desktop_id = desktop_id;
2004 g_free (desktop_id);
2008 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
2010 subprefix = g_strconcat (prefix, basename, "-", NULL);
2011 get_apps_from_dir (apps, filename, subprefix);
2023 * g_app_info_get_all:
2025 * Gets a list of all of the applications currently registered
2028 * For desktop files, this includes applications that have
2029 * <literal>NoDisplay=true</literal> set or are excluded from
2030 * display by means of <literal>OnlyShowIn</literal> or
2031 * <literal>NotShowIn</literal>. See g_app_info_should_show().
2032 * The returned list does not include applications which have
2033 * the <literal>Hidden</literal> key set.
2035 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
2038 g_app_info_get_all (void)
2040 const char * const *dirs;
2042 GHashTableIter iter;
2047 dirs = get_applications_search_path ();
2049 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
2053 for (i = 0; dirs[i] != NULL; i++)
2054 get_apps_from_dir (apps, dirs[i], "");
2058 g_hash_table_iter_init (&iter, apps);
2059 while (g_hash_table_iter_next (&iter, NULL, &value))
2062 infos = g_list_prepend (infos, value);
2065 g_hash_table_destroy (apps);
2067 return g_list_reverse (infos);
2070 /* Cacheing of mimeinfo.cache and defaults.list files */
2074 GHashTable *mime_info_cache_map;
2075 GHashTable *defaults_list_map;
2076 GHashTable *mimeapps_list_added_map;
2077 GHashTable *mimeapps_list_removed_map;
2078 time_t mime_info_cache_timestamp;
2079 time_t defaults_list_timestamp;
2080 time_t mimeapps_list_timestamp;
2084 GList *dirs; /* mimeinfo.cache and defaults.list */
2085 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2086 time_t last_stat_time;
2087 guint should_ping_mime_monitor : 1;
2090 static MimeInfoCache *mime_info_cache = NULL;
2091 G_LOCK_DEFINE_STATIC (mime_info_cache);
2093 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2094 const char *mime_type,
2095 char **new_desktop_file_ids);
2097 static MimeInfoCache * mime_info_cache_new (void);
2100 destroy_info_cache_value (gpointer key,
2104 g_list_foreach (value, (GFunc)g_free, NULL);
2105 g_list_free (value);
2109 destroy_info_cache_map (GHashTable *info_cache_map)
2111 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2112 g_hash_table_destroy (info_cache_map);
2116 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2117 const char *cache_file,
2123 filename = g_build_filename (dir->path, cache_file, NULL);
2125 if (g_stat (filename, &buf) < 0)
2132 if (buf.st_mtime != *timestamp)
2138 /* Call with lock held */
2140 remove_all (gpointer key,
2149 mime_info_cache_blow_global_cache (void)
2151 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2156 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2160 gchar *filename, **mime_types;
2167 if (dir->mime_info_cache_map != NULL &&
2168 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2169 &dir->mime_info_cache_timestamp))
2172 if (dir->mime_info_cache_map != NULL)
2173 destroy_info_cache_map (dir->mime_info_cache_map);
2175 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2176 (GDestroyNotify) g_free,
2179 key_file = g_key_file_new ();
2181 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2183 if (g_stat (filename, &buf) < 0)
2186 if (dir->mime_info_cache_timestamp > 0)
2187 mime_info_cache->should_ping_mime_monitor = TRUE;
2189 dir->mime_info_cache_timestamp = buf.st_mtime;
2191 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2196 if (load_error != NULL)
2199 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2202 if (load_error != NULL)
2205 for (i = 0; mime_types[i] != NULL; i++)
2207 gchar **desktop_file_ids;
2208 char *unaliased_type;
2209 desktop_file_ids = g_key_file_get_string_list (key_file,
2215 if (desktop_file_ids == NULL)
2218 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2219 mime_info_cache_dir_add_desktop_entries (dir,
2222 g_free (unaliased_type);
2224 g_strfreev (desktop_file_ids);
2227 g_strfreev (mime_types);
2228 g_key_file_free (key_file);
2233 g_key_file_free (key_file);
2235 if (mime_types != NULL)
2236 g_strfreev (mime_types);
2239 g_error_free (load_error);
2243 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2247 gchar *filename, **mime_types;
2248 char *unaliased_type;
2249 char **desktop_file_ids;
2256 if (dir->defaults_list_map != NULL &&
2257 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2258 &dir->defaults_list_timestamp))
2261 if (dir->defaults_list_map != NULL)
2262 g_hash_table_destroy (dir->defaults_list_map);
2263 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2264 g_free, (GDestroyNotify)g_strfreev);
2267 key_file = g_key_file_new ();
2269 filename = g_build_filename (dir->path, "defaults.list", NULL);
2270 if (g_stat (filename, &buf) < 0)
2273 if (dir->defaults_list_timestamp > 0)
2274 mime_info_cache->should_ping_mime_monitor = TRUE;
2276 dir->defaults_list_timestamp = buf.st_mtime;
2278 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2282 if (load_error != NULL)
2285 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2287 if (mime_types != NULL)
2289 for (i = 0; mime_types[i] != NULL; i++)
2291 desktop_file_ids = g_key_file_get_string_list (key_file,
2292 DEFAULT_APPLICATIONS_GROUP,
2296 if (desktop_file_ids == NULL)
2299 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2300 g_hash_table_replace (dir->defaults_list_map,
2305 g_strfreev (mime_types);
2308 g_key_file_free (key_file);
2313 g_key_file_free (key_file);
2315 if (mime_types != NULL)
2316 g_strfreev (mime_types);
2319 g_error_free (load_error);
2323 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2327 gchar *filename, **mime_types;
2328 char *unaliased_type;
2329 char **desktop_file_ids;
2336 if (dir->mimeapps_list_added_map != NULL &&
2337 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2338 &dir->mimeapps_list_timestamp))
2341 if (dir->mimeapps_list_added_map != NULL)
2342 g_hash_table_destroy (dir->mimeapps_list_added_map);
2343 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2344 g_free, (GDestroyNotify)g_strfreev);
2346 if (dir->mimeapps_list_removed_map != NULL)
2347 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2348 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2349 g_free, (GDestroyNotify)g_strfreev);
2351 key_file = g_key_file_new ();
2353 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2354 if (g_stat (filename, &buf) < 0)
2357 if (dir->mimeapps_list_timestamp > 0)
2358 mime_info_cache->should_ping_mime_monitor = TRUE;
2360 dir->mimeapps_list_timestamp = buf.st_mtime;
2362 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2366 if (load_error != NULL)
2369 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2371 if (mime_types != NULL)
2373 for (i = 0; mime_types[i] != NULL; i++)
2375 desktop_file_ids = g_key_file_get_string_list (key_file,
2376 ADDED_ASSOCIATIONS_GROUP,
2380 if (desktop_file_ids == NULL)
2383 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2384 g_hash_table_replace (dir->mimeapps_list_added_map,
2389 g_strfreev (mime_types);
2392 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2394 if (mime_types != NULL)
2396 for (i = 0; mime_types[i] != NULL; i++)
2398 desktop_file_ids = g_key_file_get_string_list (key_file,
2399 REMOVED_ASSOCIATIONS_GROUP,
2403 if (desktop_file_ids == NULL)
2406 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2407 g_hash_table_replace (dir->mimeapps_list_removed_map,
2412 g_strfreev (mime_types);
2415 g_key_file_free (key_file);
2420 g_key_file_free (key_file);
2422 if (mime_types != NULL)
2423 g_strfreev (mime_types);
2426 g_error_free (load_error);
2429 static MimeInfoCacheDir *
2430 mime_info_cache_dir_new (const char *path)
2432 MimeInfoCacheDir *dir;
2434 dir = g_new0 (MimeInfoCacheDir, 1);
2435 dir->path = g_strdup (path);
2441 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2446 if (dir->mime_info_cache_map != NULL)
2448 destroy_info_cache_map (dir->mime_info_cache_map);
2449 dir->mime_info_cache_map = NULL;
2453 if (dir->defaults_list_map != NULL)
2455 g_hash_table_destroy (dir->defaults_list_map);
2456 dir->defaults_list_map = NULL;
2459 if (dir->mimeapps_list_added_map != NULL)
2461 g_hash_table_destroy (dir->mimeapps_list_added_map);
2462 dir->mimeapps_list_added_map = NULL;
2465 if (dir->mimeapps_list_removed_map != NULL)
2467 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2468 dir->mimeapps_list_removed_map = NULL;
2475 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2476 const char *mime_type,
2477 char **new_desktop_file_ids)
2479 GList *desktop_file_ids;
2482 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2485 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2487 if (!g_list_find (desktop_file_ids, new_desktop_file_ids[i]))
2488 desktop_file_ids = g_list_append (desktop_file_ids,
2489 g_strdup (new_desktop_file_ids[i]));
2492 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2496 mime_info_cache_init_dir_lists (void)
2498 const char * const *dirs;
2501 mime_info_cache = mime_info_cache_new ();
2503 dirs = get_applications_search_path ();
2505 for (i = 0; dirs[i] != NULL; i++)
2507 MimeInfoCacheDir *dir;
2509 dir = mime_info_cache_dir_new (dirs[i]);
2513 mime_info_cache_dir_init (dir);
2514 mime_info_cache_dir_init_defaults_list (dir);
2515 mime_info_cache_dir_init_mimeapps_list (dir);
2517 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2523 mime_info_cache_update_dir_lists (void)
2527 tmp = mime_info_cache->dirs;
2531 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2533 /* No need to do this if we had file monitors... */
2534 mime_info_cache_blow_global_cache ();
2535 mime_info_cache_dir_init (dir);
2536 mime_info_cache_dir_init_defaults_list (dir);
2537 mime_info_cache_dir_init_mimeapps_list (dir);
2544 mime_info_cache_init (void)
2546 G_LOCK (mime_info_cache);
2547 if (mime_info_cache == NULL)
2548 mime_info_cache_init_dir_lists ();
2554 if (now >= mime_info_cache->last_stat_time + 10)
2556 mime_info_cache_update_dir_lists ();
2557 mime_info_cache->last_stat_time = now;
2561 if (mime_info_cache->should_ping_mime_monitor)
2563 /* g_idle_add (emit_mime_changed, NULL); */
2564 mime_info_cache->should_ping_mime_monitor = FALSE;
2567 G_UNLOCK (mime_info_cache);
2570 static MimeInfoCache *
2571 mime_info_cache_new (void)
2573 MimeInfoCache *cache;
2575 cache = g_new0 (MimeInfoCache, 1);
2577 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2578 (GDestroyNotify) g_free,
2579 (GDestroyNotify) g_free);
2584 mime_info_cache_free (MimeInfoCache *cache)
2589 g_list_foreach (cache->dirs,
2590 (GFunc) mime_info_cache_dir_free,
2592 g_list_free (cache->dirs);
2593 g_hash_table_destroy (cache->global_defaults_cache);
2598 * mime_info_cache_reload:
2599 * @dir: directory path which needs reloading.
2601 * Reload the mime information for the @dir.
2604 mime_info_cache_reload (const char *dir)
2606 /* FIXME: just reload the dir that needs reloading,
2607 * don't blow the whole cache
2609 if (mime_info_cache != NULL)
2611 G_LOCK (mime_info_cache);
2612 mime_info_cache_free (mime_info_cache);
2613 mime_info_cache = NULL;
2614 G_UNLOCK (mime_info_cache);
2619 append_desktop_entry (GList *list,
2620 const char *desktop_entry,
2621 GList *removed_entries)
2623 /* Add if not already in list, and valid */
2624 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2625 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2626 list = g_list_prepend (list, g_strdup (desktop_entry));
2632 * get_all_desktop_entries_for_mime_type:
2633 * @mime_type: a mime type.
2634 * @except: NULL or a strv list
2636 * Returns all the desktop ids for @mime_type. The desktop files
2637 * are listed in an order so that default applications are listed before
2638 * non-default ones, and handlers for inherited mimetypes are listed
2639 * after the base ones.
2641 * Optionally doesn't list the desktop ids given in the @except
2643 * Return value: a #GList containing the desktop ids which claim
2644 * to handle @mime_type.
2647 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2648 const char **except)
2650 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2651 MimeInfoCacheDir *dir;
2654 char **default_entries;
2655 char **removed_associations;
2660 mime_info_cache_init ();
2662 /* collect all ancestors */
2663 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2664 array = g_ptr_array_new ();
2665 for (i = 0; mime_types[i]; i++)
2666 g_ptr_array_add (array, mime_types[i]);
2667 g_free (mime_types);
2668 for (i = 0; i < array->len; i++)
2670 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2671 for (j = 0; anc[j]; j++)
2673 for (k = 0; k < array->len; k++)
2675 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2678 if (k == array->len) /* not found */
2679 g_ptr_array_add (array, g_strdup (anc[j]));
2683 g_ptr_array_add (array, NULL);
2684 mime_types = (char **)g_ptr_array_free (array, FALSE);
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 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2749 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2750 gpointer class_data);
2753 g_desktop_app_info_lookup_get_type (void)
2755 static volatile gsize g_define_type_id__volatile = 0;
2757 if (g_once_init_enter (&g_define_type_id__volatile))
2759 const GTypeInfo desktop_app_info_lookup_info =
2761 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2762 g_desktop_app_info_lookup_base_init, /* base_init */
2763 NULL, /* base_finalize */
2764 g_desktop_app_info_lookup_class_init,
2765 NULL, /* class_finalize */
2766 NULL, /* class_data */
2768 0, /* n_preallocs */
2771 GType g_define_type_id =
2772 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2773 &desktop_app_info_lookup_info, 0);
2775 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2777 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2780 return g_define_type_id__volatile;
2784 g_desktop_app_info_lookup_class_init (gpointer g_class,
2785 gpointer class_data)
2790 g_desktop_app_info_lookup_base_init (gpointer g_class)
2795 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2796 * @lookup: a #GDesktopAppInfoLookup
2797 * @uri_scheme: a string containing a URI scheme.
2799 * Gets the default application for launching applications
2800 * using this URI scheme for a particular GDesktopAppInfoLookup
2803 * The GDesktopAppInfoLookup interface and this function is used
2804 * to implement g_app_info_get_default_for_uri_scheme() backends
2805 * in a GIO module. There is no reason for applications to use it
2806 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2808 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2811 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2812 const char *uri_scheme)
2814 GDesktopAppInfoLookupIface *iface;
2816 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2818 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2820 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2823 #define __G_DESKTOP_APP_INFO_C__
2824 #include "gioaliasdef.c"