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
58 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
59 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
60 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
61 #define MIME_CACHE_GROUP "MIME Cache"
63 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
64 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
66 static void mime_info_cache_reload (const char *dir);
67 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
73 * Information about an installed application from a desktop file.
75 struct _GDesktopAppInfo
77 GObject parent_instance;
83 /* FIXME: what about GenericName ? */
97 guint startup_notify : 1;
98 /* FIXME: what about StartupWMClass ? */
101 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
102 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
103 g_desktop_app_info_iface_init))
106 search_path_init (gpointer data)
109 const char * const *data_dirs;
110 const char *user_data_dir;
113 data_dirs = g_get_system_data_dirs ();
114 length = g_strv_length ((char **) data_dirs);
116 args = g_new (char *, length + 2);
119 user_data_dir = g_get_user_data_dir ();
120 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
121 for (i = 0; i < length; i++)
122 args[j++] = g_build_filename (data_dirs[i],
123 "applications", NULL);
129 static const char * const *
130 get_applications_search_path (void)
132 static GOnce once_init = G_ONCE_INIT;
133 return g_once (&once_init, search_path_init, NULL);
137 g_desktop_app_info_finalize (GObject *object)
139 GDesktopAppInfo *info;
141 info = G_DESKTOP_APP_INFO (object);
143 g_free (info->desktop_id);
144 g_free (info->filename);
146 g_free (info->comment);
147 g_free (info->icon_name);
149 g_object_unref (info->icon);
150 g_strfreev (info->only_show_in);
151 g_strfreev (info->not_show_in);
152 g_free (info->try_exec);
154 g_free (info->binary);
157 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
161 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
163 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
165 gobject_class->finalize = g_desktop_app_info_finalize;
169 g_desktop_app_info_init (GDesktopAppInfo *local)
174 binary_from_exec (const char *exec)
176 const char *p, *start;
182 while (*p != ' ' && *p != 0)
185 return g_strndup (start, p - start);
190 * g_desktop_app_info_new_from_keyfile:
191 * @key_file: an opened #GKeyFile
193 * Creates a new #GDesktopAppInfo.
195 * Returns: a new #GDesktopAppInfo or %NULL on error.
200 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
202 GDesktopAppInfo *info;
207 start_group = g_key_file_get_start_group (key_file);
208 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
210 g_free (start_group);
213 g_free (start_group);
215 type = g_key_file_get_string (key_file,
216 G_KEY_FILE_DESKTOP_GROUP,
217 G_KEY_FILE_DESKTOP_KEY_TYPE,
219 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
226 try_exec = g_key_file_get_string (key_file,
227 G_KEY_FILE_DESKTOP_GROUP,
228 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
230 if (try_exec && try_exec[0] != '\0')
233 t = g_find_program_in_path (try_exec);
242 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
243 info->filename = NULL;
245 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
246 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
247 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
248 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
249 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);
250 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);
251 info->try_exec = try_exec;
252 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
253 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
254 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
255 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
256 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
261 if (g_path_is_absolute (info->icon_name))
265 file = g_file_new_for_path (info->icon_name);
266 info->icon = g_file_icon_new (file);
267 g_object_unref (file);
270 info->icon = g_themed_icon_new (info->icon_name);
274 info->binary = binary_from_exec (info->exec);
276 if (info->path && info->path[0] == '\0')
286 * g_desktop_app_info_new_from_filename:
287 * @filename: the path of a desktop file, in the GLib filename encoding
289 * Creates a new #GDesktopAppInfo.
291 * Returns: a new #GDesktopAppInfo or %NULL on error.
294 g_desktop_app_info_new_from_filename (const char *filename)
297 GDesktopAppInfo *info = NULL;
299 key_file = g_key_file_new ();
301 if (g_key_file_load_from_file (key_file,
306 info = g_desktop_app_info_new_from_keyfile (key_file);
308 info->filename = g_strdup (filename);
311 g_key_file_free (key_file);
317 * g_desktop_app_info_new:
318 * @desktop_id: the desktop file id
320 * Creates a new #GDesktopAppInfo.
322 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
325 g_desktop_app_info_new (const char *desktop_id)
327 GDesktopAppInfo *appinfo;
328 const char * const *dirs;
332 dirs = get_applications_search_path ();
334 basename = g_strdup (desktop_id);
336 for (i = 0; dirs[i] != NULL; i++)
341 filename = g_build_filename (dirs[i], desktop_id, NULL);
342 appinfo = g_desktop_app_info_new_from_filename (filename);
348 while ((p = strchr (p, '-')) != NULL)
352 filename = g_build_filename (dirs[i], basename, NULL);
353 appinfo = g_desktop_app_info_new_from_filename (filename);
368 appinfo->desktop_id = g_strdup (desktop_id);
370 if (g_desktop_app_info_get_is_hidden (appinfo))
372 g_object_unref (appinfo);
380 g_desktop_app_info_dup (GAppInfo *appinfo)
382 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
383 GDesktopAppInfo *new_info;
385 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
387 new_info->filename = g_strdup (info->filename);
388 new_info->desktop_id = g_strdup (info->desktop_id);
390 new_info->name = g_strdup (info->name);
391 new_info->comment = g_strdup (info->comment);
392 new_info->nodisplay = info->nodisplay;
393 new_info->icon_name = g_strdup (info->icon_name);
394 new_info->icon = g_object_ref (info->icon);
395 new_info->only_show_in = g_strdupv (info->only_show_in);
396 new_info->not_show_in = g_strdupv (info->not_show_in);
397 new_info->try_exec = g_strdup (info->try_exec);
398 new_info->exec = g_strdup (info->exec);
399 new_info->binary = g_strdup (info->binary);
400 new_info->path = g_strdup (info->path);
401 new_info->hidden = info->hidden;
402 new_info->terminal = info->terminal;
403 new_info->startup_notify = info->startup_notify;
405 return G_APP_INFO (new_info);
409 g_desktop_app_info_equal (GAppInfo *appinfo1,
412 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
413 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
415 if (info1->desktop_id == NULL ||
416 info2->desktop_id == NULL)
417 return info1 == info2;
419 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
423 g_desktop_app_info_get_id (GAppInfo *appinfo)
425 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
427 return info->desktop_id;
431 g_desktop_app_info_get_name (GAppInfo *appinfo)
433 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
435 if (info->name == NULL)
441 * g_desktop_app_info_get_is_hidden:
442 * @info: a #GDesktopAppInfo.
444 * A desktop file is hidden if the Hidden key in it is
447 * Returns: %TRUE if hidden, %FALSE otherwise.
450 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
456 g_desktop_app_info_get_description (GAppInfo *appinfo)
458 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
460 return info->comment;
464 g_desktop_app_info_get_executable (GAppInfo *appinfo)
466 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
472 g_desktop_app_info_get_icon (GAppInfo *appinfo)
474 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
480 expand_macro_single (char macro, char *uri)
486 file = g_file_new_for_uri (uri);
487 path = g_file_get_path (file);
488 g_object_unref (file);
494 result = g_shell_quote (uri);
499 result = g_shell_quote (path);
505 name = g_path_get_dirname (path);
506 result = g_shell_quote (name);
514 name = g_path_get_basename (path);
515 result = g_shell_quote (name);
527 expand_macro (char macro,
529 GDesktopAppInfo *info,
532 GList *uris = *uri_list;
534 gboolean force_file_uri;
535 char force_file_uri_macro;
537 g_return_if_fail (exec != NULL);
539 /* On %u and %U, pass POSIX file path pointing to the URI via
540 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
541 * running or the URI doesn't have a POSIX file path via FUSE
542 * we'll just pass the URI.
547 force_file_uri_macro = 'f';
548 force_file_uri = TRUE;
551 force_file_uri_macro = 'F';
552 force_file_uri = TRUE;
555 force_file_uri_macro = macro;
556 force_file_uri = FALSE;
570 expanded = expand_macro_single (macro, uris->data);
574 expanded = expand_macro_single (force_file_uri_macro, uris->data);
575 if (expanded == NULL)
576 expanded = expand_macro_single (macro, uris->data);
581 g_string_append (exec, expanded);
597 expanded = expand_macro_single (macro, uris->data);
601 expanded = expand_macro_single (force_file_uri_macro, uris->data);
602 if (expanded == NULL)
603 expanded = expand_macro_single (macro, uris->data);
608 g_string_append (exec, expanded);
614 if (uris != NULL && expanded)
615 g_string_append_c (exec, ' ');
623 g_string_append (exec, "--icon ");
624 g_string_append (exec, info->icon_name);
630 g_string_append (exec, info->name);
635 g_string_append (exec, info->filename);
638 case 'm': /* deprecated */
642 g_string_append_c (exec, '%');
650 expand_application_parameters (GDesktopAppInfo *info,
656 GList *uri_list = *uris;
657 const char *p = info->exec;
658 GString *expanded_exec = g_string_new (NULL);
661 if (info->exec == NULL)
663 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
664 _("Desktop file didn't specify Exec field"));
670 if (p[0] == '%' && p[1] != '\0')
672 expand_macro (p[1], expanded_exec, info, uris);
676 g_string_append_c (expanded_exec, *p);
681 /* No file substitutions */
682 if (uri_list == *uris && uri_list != NULL)
684 /* If there is no macro default to %f. This is also what KDE does */
685 g_string_append_c (expanded_exec, ' ');
686 expand_macro ('f', expanded_exec, info, uris);
689 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
690 g_string_free (expanded_exec, TRUE);
695 prepend_terminal_to_vector (int *argc,
702 char **term_argv = NULL;
707 g_return_val_if_fail (argc != NULL, FALSE);
708 g_return_val_if_fail (argv != NULL, FALSE);
716 /* compute size if not given */
719 for (i = 0; the_argv[i] != NULL; i++)
725 term_argv = g_new0 (char *, 3);
727 check = g_find_program_in_path ("gnome-terminal");
730 term_argv[0] = check;
731 /* Note that gnome-terminal takes -x and
732 * as -e in gnome-terminal is broken we use that. */
733 term_argv[1] = g_strdup ("-x");
738 check = g_find_program_in_path ("nxterm");
740 check = g_find_program_in_path ("color-xterm");
742 check = g_find_program_in_path ("rxvt");
744 check = g_find_program_in_path ("xterm");
746 check = g_find_program_in_path ("dtterm");
749 check = g_strdup ("xterm");
750 g_warning ("couldn't find a terminal, falling back to xterm");
752 term_argv[0] = check;
753 term_argv[1] = g_strdup ("-e");
756 real_argc = term_argc + *argc;
757 real_argv = g_new (char *, real_argc + 1);
759 for (i = 0; i < term_argc; i++)
760 real_argv[i] = term_argv[i];
762 for (j = 0; j < *argc; j++, i++)
763 real_argv[i] = (char *)the_argv[j];
771 /* we use g_free here as we sucked all the inner strings
772 * out from it into real_argv */
777 #endif /* G_OS_WIN32 */
780 /* '=' is the new '\0'.
781 * DO NOT CALL unless at least one string ends with '='
784 is_env (const char *a,
789 if (*a == 0 || *b == 0)
802 /* free with g_strfreev */
804 replace_env_var (char **old_environ,
806 const char *new_value)
808 int length, new_length;
809 int index, new_index;
813 /* do two things at once:
814 * - discover the length of the environment ('length')
815 * - find the location (if any) of the env var ('index')
818 for (length = 0; old_environ[length]; length++)
820 /* if we already have it in our environment, replace */
821 if (is_env (old_environ[length], env_var))
826 /* no current env var, no desired env value.
829 if (new_value == NULL && index == -1)
832 /* in all cases now, we will be using a modified environment.
833 * determine its length and allocated it.
836 * new_index = location to insert, if any
837 * new_length = length of the new array
838 * new_environ = the pointer array for the new environment
841 if (new_value == NULL && index >= 0)
843 /* in this case, we will be removing an entry */
844 new_length = length - 1;
847 else if (new_value != NULL && index < 0)
849 /* in this case, we will be adding an entry to the end */
850 new_length = length + 1;
854 /* in this case, we will be replacing the existing entry */
860 new_environ = g_malloc (sizeof (char *) * (new_length + 1));
861 new_environ[new_length] = NULL;
863 /* now we do the copying.
864 * for each entry in the new environment, we decide what to do
868 for (new_i = 0; new_i < new_length; new_i++)
870 if (new_i == new_index)
872 /* insert our new item */
873 new_environ[new_i] = g_strconcat (env_var,
878 /* if we had an old entry, skip it now */
884 /* if this is the old DESKTOP_STARTUP_ID, skip it */
888 /* copy an old item */
889 new_environ[new_i] = g_strdup (old_environ[i]);
894 g_strfreev (old_environ);
900 uri_list_segment_to_files (GList *start,
907 while (start != NULL && start != end)
909 file = g_file_new_for_uri ((char *)start->data);
910 res = g_list_prepend (res, file);
914 return g_list_reverse (res);
917 #ifdef HAVE__NSGETENVIRON
918 #define environ (*_NSGetEnviron())
919 #elif !defined(G_OS_WIN32)
921 /* According to the Single Unix Specification, environ is not in
922 * * any system header, although unistd.h often declares it.
924 extern char **environ;
928 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
930 GAppLaunchContext *launch_context,
933 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
934 gboolean completed = FALSE;
936 GList *launched_files;
943 g_return_val_if_fail (appinfo != NULL, FALSE);
951 if (!expand_application_parameters (info, &uris,
952 &argc, &argv, error))
955 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
957 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
958 _("Unable to find terminal required for application"));
965 launched_files = uri_list_segment_to_files (old_uris, uris);
967 display = g_app_launch_context_get_display (launch_context,
972 if (info->startup_notify)
973 sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
977 if (display || sn_id)
981 envp = g_new0 (char *, 1);
983 envp = g_strdupv (environ);
987 envp = replace_env_var (envp,
992 envp = replace_env_var (envp,
993 "DESKTOP_STARTUP_ID",
999 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
1000 g_list_free (launched_files);
1003 if (!g_spawn_async (info->path, /* working directory */
1006 G_SPAWN_SEARCH_PATH /* flags */,
1007 NULL /* child_setup */,
1009 NULL /* child_pid */,
1014 g_app_launch_context_launch_failed (launch_context, sn_id);
1028 while (uris != NULL);
1040 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
1042 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1044 return info->exec &&
1045 ((strstr (info->exec, "%u") != NULL) ||
1046 (strstr (info->exec, "%U") != NULL));
1050 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1052 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1054 return info->exec &&
1055 ((strstr (info->exec, "%f") != NULL) ||
1056 (strstr (info->exec, "%F") != NULL));
1060 g_desktop_app_info_launch (GAppInfo *appinfo,
1062 GAppLaunchContext *launch_context,
1072 uri = g_file_get_uri (files->data);
1073 uris = g_list_prepend (uris, uri);
1074 files = files->next;
1077 uris = g_list_reverse (uris);
1079 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1081 g_list_foreach (uris, (GFunc)g_free, NULL);
1087 G_LOCK_DEFINE_STATIC (g_desktop_env);
1088 static gchar *g_desktop_env = NULL;
1091 * g_desktop_app_info_set_desktop_env:
1092 * @desktop_env: a string specifying what desktop this is
1094 * Sets the name of the desktop that the application is running in.
1095 * This is used by g_app_info_should_show() to evaluate the
1096 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1097 * desktop entry fields.
1099 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1100 * Menu specification</ulink> recognizes the following:
1102 * <member>GNOME</member>
1103 * <member>KDE</member>
1104 * <member>ROX</member>
1105 * <member>XFCE</member>
1106 * <member>Old</member>
1109 * Should be called only once; subsequent calls are ignored.
1112 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1114 G_LOCK (g_desktop_env);
1116 g_desktop_env = g_strdup (desktop_env);
1117 G_UNLOCK (g_desktop_env);
1121 g_desktop_app_info_should_show (GAppInfo *appinfo)
1123 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1125 const gchar *desktop_env;
1128 if (info->nodisplay)
1131 G_LOCK (g_desktop_env);
1132 desktop_env = g_desktop_env;
1133 G_UNLOCK (g_desktop_env);
1135 if (info->only_show_in)
1137 if (desktop_env == NULL)
1141 for (i = 0; info->only_show_in[i] != NULL; i++)
1143 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1153 if (info->not_show_in && desktop_env)
1155 for (i = 0; info->not_show_in[i] != NULL; i++)
1157 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1171 ensure_dir (DirType type,
1174 char *path, *display_name;
1177 if (type == APP_DIR)
1178 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1180 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1183 if (g_mkdir_with_parents (path, 0700) == 0)
1187 display_name = g_filename_display_name (path);
1188 if (type == APP_DIR)
1189 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1190 _("Can't create user application configuration folder %s: %s"),
1191 display_name, g_strerror (errsv));
1193 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1194 _("Can't create user MIME configuration folder %s: %s"),
1195 display_name, g_strerror (errsv));
1197 g_free (display_name);
1204 update_mimeapps_list (const char *desktop_id,
1205 const char *content_type,
1206 gboolean add_as_default,
1207 gboolean add_non_default,
1211 char *dirname, *filename;
1213 gboolean load_succeeded, res;
1214 char **old_list, **list;
1215 GList *system_list, *l;
1216 gsize length, data_size;
1219 char **content_types;
1221 /* Don't add both at start and end */
1222 g_assert (!(add_as_default && add_non_default));
1224 dirname = ensure_dir (APP_DIR, error);
1228 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1231 key_file = g_key_file_new ();
1232 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1233 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1235 g_key_file_free (key_file);
1236 key_file = g_key_file_new ();
1241 content_types = g_new (char *, 2);
1242 content_types[0] = g_strdup (content_type);
1243 content_types[1] = NULL;
1247 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1250 for (k = 0; content_types && content_types[k]; k++)
1252 /* Add to the right place in the list */
1255 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1256 content_types[k], &length, NULL);
1258 list = g_new (char *, 1 + length + 1);
1262 list[i++] = g_strdup (desktop_id);
1265 for (j = 0; old_list[j] != NULL; j++)
1267 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1268 list[i++] = g_strdup (old_list[j]);
1269 else if (add_non_default)
1271 /* If adding as non-default, and its already in,
1272 don't change order of desktop ids */
1273 add_non_default = FALSE;
1274 list[i++] = g_strdup (old_list[j]);
1279 if (add_non_default)
1281 /* We're adding as non-default, and it wasn't already in the list,
1282 so we add at the end. But to avoid listing the app before the
1283 current system default (thus changing the default) we have to
1284 add the current list of (not yet listed) apps before it. */
1286 list[i] = NULL; /* Terminate current list so we can use it */
1287 system_list = get_all_desktop_entries_for_mime_type (content_type, list);
1289 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1291 for (l = system_list; l != NULL; l = l->next)
1293 list[i++] = l->data; /* no strdup, taking ownership */
1294 if (g_strcmp0 (l->data, desktop_id) == 0)
1295 add_non_default = FALSE;
1297 g_list_free (system_list);
1299 if (add_non_default)
1300 list[i++] = g_strdup (desktop_id);
1305 g_strfreev (old_list);
1307 if (list[0] == NULL || desktop_id == NULL)
1308 g_key_file_remove_key (key_file,
1309 ADDED_ASSOCIATIONS_GROUP,
1313 g_key_file_set_string_list (key_file,
1314 ADDED_ASSOCIATIONS_GROUP,
1316 (const char * const *)list, i);
1323 /* reuse the list from above */
1327 g_strfreev (content_types);
1328 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1331 for (k = 0; content_types && content_types[k]; k++)
1333 /* Remove from removed associations group (unless remove) */
1336 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1337 content_types[k], &length, NULL);
1339 list = g_new (char *, 1 + length + 1);
1343 list[i++] = g_strdup (desktop_id);
1346 for (j = 0; old_list[j] != NULL; j++)
1348 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1349 list[i++] = g_strdup (old_list[j]);
1354 g_strfreev (old_list);
1356 if (list[0] == NULL || desktop_id == NULL)
1357 g_key_file_remove_key (key_file,
1358 REMOVED_ASSOCIATIONS_GROUP,
1362 g_key_file_set_string_list (key_file,
1363 REMOVED_ASSOCIATIONS_GROUP,
1365 (const char * const *)list, i);
1370 g_strfreev (content_types);
1372 data = g_key_file_to_data (key_file, &data_size, error);
1373 g_key_file_free (key_file);
1375 res = g_file_set_contents (filename, data, data_size, error);
1377 mime_info_cache_reload (NULL);
1386 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1387 const char *content_type,
1390 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1392 if (!g_desktop_app_info_ensure_saved (info, error))
1395 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1399 update_program_done (GPid pid,
1403 /* Did the application exit correctly */
1404 if (WIFEXITED (status) &&
1405 WEXITSTATUS (status) == 0)
1407 /* Here we could clean out any caches in use */
1412 run_update_command (char *command,
1421 GError *error = NULL;
1424 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1426 if (g_spawn_async ("/", argv,
1428 G_SPAWN_SEARCH_PATH |
1429 G_SPAWN_STDOUT_TO_DEV_NULL |
1430 G_SPAWN_STDERR_TO_DEV_NULL |
1431 G_SPAWN_DO_NOT_REAP_CHILD,
1432 NULL, NULL, /* No setup function */
1435 g_child_watch_add (pid, update_program_done, NULL);
1438 /* If we get an error at this point, it's quite likely the user doesn't
1439 * have an installed copy of either 'update-mime-database' or
1440 * 'update-desktop-database'. I don't think we want to popup an error
1441 * dialog at this point, so we just do a g_warning to give the user a
1442 * chance of debugging it.
1444 g_warning ("%s", error->message);
1451 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1452 const char *extension,
1455 char *filename, *basename, *mimetype;
1459 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1462 dirname = ensure_dir (MIMETYPE_DIR, error);
1466 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1467 filename = g_build_filename (dirname, basename, NULL);
1471 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1473 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1478 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1479 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1480 " <mime-type type=\"%s\">\n"
1481 " <comment>%s document</comment>\n"
1482 " <glob pattern=\"*.%s\"/>\n"
1484 "</mime-info>\n", mimetype, extension, extension);
1486 g_file_set_contents (filename, contents, -1, NULL);
1489 run_update_command ("update-mime-database", "mime");
1493 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1503 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1504 const char *content_type,
1507 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1509 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1512 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1516 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1522 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1523 const char *content_type,
1526 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1528 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1531 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1535 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1541 char *data, *desktop_id;
1546 if (info->filename != NULL)
1549 /* This is only used for object created with
1550 * g_app_info_create_from_commandline. All other
1551 * object should have a filename
1554 dirname = ensure_dir (APP_DIR, error);
1558 key_file = g_key_file_new ();
1560 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1561 "Encoding", "UTF-8");
1562 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1563 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1564 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1565 G_KEY_FILE_DESKTOP_KEY_TYPE,
1566 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1568 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1569 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1571 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1572 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1574 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1575 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1577 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1578 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1580 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1581 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1583 data = g_key_file_to_data (key_file, &data_size, NULL);
1584 g_key_file_free (key_file);
1586 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1587 filename = g_build_filename (dirname, desktop_id, NULL);
1588 g_free (desktop_id);
1591 fd = g_mkstemp (filename);
1596 display_name = g_filename_display_name (filename);
1597 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1598 _("Can't create user desktop file %s"), display_name);
1599 g_free (display_name);
1605 desktop_id = g_path_get_basename (filename);
1609 res = g_file_set_contents (filename, data, data_size, error);
1612 g_free (desktop_id);
1617 info->filename = filename;
1618 info->desktop_id = desktop_id;
1620 run_update_command ("update-desktop-database", "applications");
1626 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1628 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1632 if (strstr (info->filename, "/userapp-"))
1633 return g_access (info->filename, W_OK) == 0;
1640 g_desktop_app_info_delete (GAppInfo *appinfo)
1642 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1646 if (g_remove (info->filename) == 0)
1648 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1650 g_free (info->filename);
1651 info->filename = NULL;
1652 g_free (info->desktop_id);
1653 info->desktop_id = NULL;
1663 * g_app_info_create_from_commandline:
1664 * @commandline: the commandline to use
1665 * @application_name: the application name, or %NULL to use @commandline
1666 * @flags: flags that can specify details of the created #GAppInfo
1667 * @error: a #GError location to store the error occuring, %NULL to ignore.
1669 * Creates a new #GAppInfo from the given information.
1671 * Returns: new #GAppInfo for given command.
1674 g_app_info_create_from_commandline (const char *commandline,
1675 const char *application_name,
1676 GAppInfoCreateFlags flags,
1681 GDesktopAppInfo *info;
1683 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1685 info->filename = NULL;
1686 info->desktop_id = NULL;
1688 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1689 info->startup_notify = FALSE;
1690 info->hidden = FALSE;
1691 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1692 info->exec = g_strconcat (commandline, " %u", NULL);
1694 info->exec = g_strconcat (commandline, " %f", NULL);
1695 info->nodisplay = TRUE;
1696 info->binary = binary_from_exec (info->exec);
1698 if (application_name)
1699 info->name = g_strdup (application_name);
1702 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1703 split = g_strsplit (commandline, " ", 2);
1704 basename = g_path_get_basename (split[0]);
1706 info->name = basename;
1707 if (info->name == NULL)
1708 info->name = g_strdup ("custom");
1710 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1712 return G_APP_INFO (info);
1716 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1718 iface->dup = g_desktop_app_info_dup;
1719 iface->equal = g_desktop_app_info_equal;
1720 iface->get_id = g_desktop_app_info_get_id;
1721 iface->get_name = g_desktop_app_info_get_name;
1722 iface->get_description = g_desktop_app_info_get_description;
1723 iface->get_executable = g_desktop_app_info_get_executable;
1724 iface->get_icon = g_desktop_app_info_get_icon;
1725 iface->launch = g_desktop_app_info_launch;
1726 iface->supports_uris = g_desktop_app_info_supports_uris;
1727 iface->supports_files = g_desktop_app_info_supports_files;
1728 iface->launch_uris = g_desktop_app_info_launch_uris;
1729 iface->should_show = g_desktop_app_info_should_show;
1730 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1731 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1732 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1733 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1734 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1735 iface->can_delete = g_desktop_app_info_can_delete;
1736 iface->do_delete = g_desktop_app_info_delete;
1740 app_info_in_list (GAppInfo *info,
1743 while (list != NULL)
1745 if (g_app_info_equal (info, list->data))
1754 * g_app_info_get_all_for_type:
1755 * @content_type: the content type to find a #GAppInfo for
1757 * Gets a list of all #GAppInfo s for a given content type.
1759 * Returns: #GList of #GAppInfo s for given @content_type
1760 * or %NULL on error.
1763 g_app_info_get_all_for_type (const char *content_type)
1765 GList *desktop_entries, *l;
1767 GDesktopAppInfo *info;
1769 g_return_val_if_fail (content_type != NULL, NULL);
1771 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1774 for (l = desktop_entries; l != NULL; l = l->next)
1776 char *desktop_entry = l->data;
1778 info = g_desktop_app_info_new (desktop_entry);
1781 if (app_info_in_list (G_APP_INFO (info), infos))
1782 g_object_unref (info);
1784 infos = g_list_prepend (infos, info);
1786 g_free (desktop_entry);
1789 g_list_free (desktop_entries);
1791 return g_list_reverse (infos);
1795 * g_app_info_reset_type_associations:
1796 * @content_type: a content type
1798 * Removes all changes to the type associations done by
1799 * g_app_info_set_as_default_for_type(),
1800 * g_app_info_set_as_default_for_extension(),
1801 * g_app_info_add_supports_type() of g_app_info_remove_supports_type().
1806 g_app_info_reset_type_associations (const char *content_type)
1808 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1812 * g_app_info_get_default_for_type:
1813 * @content_type: the content type to find a #GAppInfo for
1814 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1817 * Gets the #GAppInfo that correspond to a given content type.
1819 * Returns: #GAppInfo for given @content_type or %NULL on error.
1822 g_app_info_get_default_for_type (const char *content_type,
1823 gboolean must_support_uris)
1825 GList *desktop_entries, *l;
1828 g_return_val_if_fail (content_type != NULL, NULL);
1830 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1833 for (l = desktop_entries; l != NULL; l = l->next)
1835 char *desktop_entry = l->data;
1837 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1840 if (must_support_uris && !g_app_info_supports_uris (info))
1842 g_object_unref (info);
1850 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1851 g_list_free (desktop_entries);
1857 * g_app_info_get_default_for_uri_scheme:
1858 * @uri_scheme: a string containing a URI scheme.
1860 * Gets the default application for launching applications
1861 * using this URI scheme. A URI scheme is the initial part
1862 * of the URI, up to but not including the ':', e.g. "http",
1865 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1868 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1870 static gsize lookup = 0;
1872 if (g_once_init_enter (&lookup))
1874 gsize setup_value = 1;
1875 GDesktopAppInfoLookup *lookup_instance;
1876 const char *use_this;
1877 GIOExtensionPoint *ep;
1878 GIOExtension *extension;
1881 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1883 /* Ensure vfs in modules loaded */
1884 _g_io_modules_ensure_loaded ();
1886 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1888 lookup_instance = NULL;
1891 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1893 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1896 if (lookup_instance == NULL)
1898 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1900 extension = l->data;
1901 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1902 if (lookup_instance != NULL)
1907 if (lookup_instance != NULL)
1908 setup_value = (gsize)lookup_instance;
1910 g_once_init_leave (&lookup, setup_value);
1916 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1922 get_apps_from_dir (GHashTable *apps,
1923 const char *dirname,
1927 const char *basename;
1928 char *filename, *subprefix, *desktop_id;
1930 GDesktopAppInfo *appinfo;
1932 dir = g_dir_open (dirname, 0, NULL);
1935 while ((basename = g_dir_read_name (dir)) != NULL)
1937 filename = g_build_filename (dirname, basename, NULL);
1938 if (g_str_has_suffix (basename, ".desktop"))
1940 desktop_id = g_strconcat (prefix, basename, NULL);
1942 /* Use _extended so we catch NULLs too (hidden) */
1943 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1945 appinfo = g_desktop_app_info_new_from_filename (filename);
1947 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1949 g_object_unref (appinfo);
1954 if (appinfo || hidden)
1956 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1960 /* Reuse instead of strdup here */
1961 appinfo->desktop_id = desktop_id;
1966 g_free (desktop_id);
1970 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1972 subprefix = g_strconcat (prefix, basename, "-", NULL);
1973 get_apps_from_dir (apps, filename, subprefix);
1985 * g_app_info_get_all:
1987 * Gets a list of all of the applications currently registered
1990 * For desktop files, this includes applications that have
1991 * <literal>NoDisplay=true</literal> set or are excluded from
1992 * display by means of <literal>OnlyShowIn</literal> or
1993 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1994 * The returned list does not include applications which have
1995 * the <literal>Hidden</literal> key set.
1997 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
2000 g_app_info_get_all (void)
2002 const char * const *dirs;
2004 GHashTableIter iter;
2009 dirs = get_applications_search_path ();
2011 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
2015 for (i = 0; dirs[i] != NULL; i++)
2016 get_apps_from_dir (apps, dirs[i], "");
2020 g_hash_table_iter_init (&iter, apps);
2021 while (g_hash_table_iter_next (&iter, NULL, &value))
2024 infos = g_list_prepend (infos, value);
2027 g_hash_table_destroy (apps);
2029 return g_list_reverse (infos);
2032 /* Cacheing of mimeinfo.cache and defaults.list files */
2036 GHashTable *mime_info_cache_map;
2037 GHashTable *defaults_list_map;
2038 GHashTable *mimeapps_list_added_map;
2039 GHashTable *mimeapps_list_removed_map;
2040 time_t mime_info_cache_timestamp;
2041 time_t defaults_list_timestamp;
2042 time_t mimeapps_list_timestamp;
2046 GList *dirs; /* mimeinfo.cache and defaults.list */
2047 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2048 time_t last_stat_time;
2049 guint should_ping_mime_monitor : 1;
2052 static MimeInfoCache *mime_info_cache = NULL;
2053 G_LOCK_DEFINE_STATIC (mime_info_cache);
2055 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2056 const char *mime_type,
2057 char **new_desktop_file_ids);
2059 static MimeInfoCache * mime_info_cache_new (void);
2062 destroy_info_cache_value (gpointer key,
2066 g_list_foreach (value, (GFunc)g_free, NULL);
2067 g_list_free (value);
2071 destroy_info_cache_map (GHashTable *info_cache_map)
2073 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2074 g_hash_table_destroy (info_cache_map);
2078 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2079 const char *cache_file,
2085 filename = g_build_filename (dir->path, cache_file, NULL);
2087 if (g_stat (filename, &buf) < 0)
2094 if (buf.st_mtime != *timestamp)
2100 /* Call with lock held */
2102 remove_all (gpointer key,
2111 mime_info_cache_blow_global_cache (void)
2113 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2118 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2122 gchar *filename, **mime_types;
2129 if (dir->mime_info_cache_map != NULL &&
2130 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2131 &dir->mime_info_cache_timestamp))
2134 if (dir->mime_info_cache_map != NULL)
2135 destroy_info_cache_map (dir->mime_info_cache_map);
2137 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2138 (GDestroyNotify) g_free,
2141 key_file = g_key_file_new ();
2143 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2145 if (g_stat (filename, &buf) < 0)
2148 if (dir->mime_info_cache_timestamp > 0)
2149 mime_info_cache->should_ping_mime_monitor = TRUE;
2151 dir->mime_info_cache_timestamp = buf.st_mtime;
2153 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2158 if (load_error != NULL)
2161 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2164 if (load_error != NULL)
2167 for (i = 0; mime_types[i] != NULL; i++)
2169 gchar **desktop_file_ids;
2170 char *unaliased_type;
2171 desktop_file_ids = g_key_file_get_string_list (key_file,
2177 if (desktop_file_ids == NULL)
2180 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2181 mime_info_cache_dir_add_desktop_entries (dir,
2184 g_free (unaliased_type);
2186 g_strfreev (desktop_file_ids);
2189 g_strfreev (mime_types);
2190 g_key_file_free (key_file);
2195 g_key_file_free (key_file);
2197 if (mime_types != NULL)
2198 g_strfreev (mime_types);
2201 g_error_free (load_error);
2205 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2209 gchar *filename, **mime_types;
2210 char *unaliased_type;
2211 char **desktop_file_ids;
2218 if (dir->defaults_list_map != NULL &&
2219 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2220 &dir->defaults_list_timestamp))
2223 if (dir->defaults_list_map != NULL)
2224 g_hash_table_destroy (dir->defaults_list_map);
2225 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2226 g_free, (GDestroyNotify)g_strfreev);
2229 key_file = g_key_file_new ();
2231 filename = g_build_filename (dir->path, "defaults.list", NULL);
2232 if (g_stat (filename, &buf) < 0)
2235 if (dir->defaults_list_timestamp > 0)
2236 mime_info_cache->should_ping_mime_monitor = TRUE;
2238 dir->defaults_list_timestamp = buf.st_mtime;
2240 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2244 if (load_error != NULL)
2247 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2249 if (mime_types != NULL)
2251 for (i = 0; mime_types[i] != NULL; i++)
2253 desktop_file_ids = g_key_file_get_string_list (key_file,
2254 DEFAULT_APPLICATIONS_GROUP,
2258 if (desktop_file_ids == NULL)
2261 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2262 g_hash_table_replace (dir->defaults_list_map,
2267 g_strfreev (mime_types);
2270 g_key_file_free (key_file);
2275 g_key_file_free (key_file);
2277 if (mime_types != NULL)
2278 g_strfreev (mime_types);
2281 g_error_free (load_error);
2285 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2289 gchar *filename, **mime_types;
2290 char *unaliased_type;
2291 char **desktop_file_ids;
2298 if (dir->mimeapps_list_added_map != NULL &&
2299 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2300 &dir->mimeapps_list_timestamp))
2303 if (dir->mimeapps_list_added_map != NULL)
2304 g_hash_table_destroy (dir->mimeapps_list_added_map);
2305 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2306 g_free, (GDestroyNotify)g_strfreev);
2308 if (dir->mimeapps_list_removed_map != NULL)
2309 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2310 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2311 g_free, (GDestroyNotify)g_strfreev);
2313 key_file = g_key_file_new ();
2315 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2316 if (g_stat (filename, &buf) < 0)
2319 if (dir->mimeapps_list_timestamp > 0)
2320 mime_info_cache->should_ping_mime_monitor = TRUE;
2322 dir->mimeapps_list_timestamp = buf.st_mtime;
2324 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2328 if (load_error != NULL)
2331 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2333 if (mime_types != NULL)
2335 for (i = 0; mime_types[i] != NULL; i++)
2337 desktop_file_ids = g_key_file_get_string_list (key_file,
2338 ADDED_ASSOCIATIONS_GROUP,
2342 if (desktop_file_ids == NULL)
2345 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2346 g_hash_table_replace (dir->mimeapps_list_added_map,
2351 g_strfreev (mime_types);
2354 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2356 if (mime_types != NULL)
2358 for (i = 0; mime_types[i] != NULL; i++)
2360 desktop_file_ids = g_key_file_get_string_list (key_file,
2361 REMOVED_ASSOCIATIONS_GROUP,
2365 if (desktop_file_ids == NULL)
2368 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2369 g_hash_table_replace (dir->mimeapps_list_removed_map,
2374 g_strfreev (mime_types);
2377 g_key_file_free (key_file);
2382 g_key_file_free (key_file);
2384 if (mime_types != NULL)
2385 g_strfreev (mime_types);
2388 g_error_free (load_error);
2391 static MimeInfoCacheDir *
2392 mime_info_cache_dir_new (const char *path)
2394 MimeInfoCacheDir *dir;
2396 dir = g_new0 (MimeInfoCacheDir, 1);
2397 dir->path = g_strdup (path);
2403 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2408 if (dir->mime_info_cache_map != NULL)
2410 destroy_info_cache_map (dir->mime_info_cache_map);
2411 dir->mime_info_cache_map = NULL;
2415 if (dir->defaults_list_map != NULL)
2417 g_hash_table_destroy (dir->defaults_list_map);
2418 dir->defaults_list_map = NULL;
2421 if (dir->mimeapps_list_added_map != NULL)
2423 g_hash_table_destroy (dir->mimeapps_list_added_map);
2424 dir->mimeapps_list_added_map = NULL;
2427 if (dir->mimeapps_list_removed_map != NULL)
2429 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2430 dir->mimeapps_list_removed_map = NULL;
2437 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2438 const char *mime_type,
2439 char **new_desktop_file_ids)
2441 GList *desktop_file_ids;
2444 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2447 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2449 if (!g_list_find (desktop_file_ids, new_desktop_file_ids[i]))
2450 desktop_file_ids = g_list_append (desktop_file_ids,
2451 g_strdup (new_desktop_file_ids[i]));
2454 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2458 mime_info_cache_init_dir_lists (void)
2460 const char * const *dirs;
2463 mime_info_cache = mime_info_cache_new ();
2465 dirs = get_applications_search_path ();
2467 for (i = 0; dirs[i] != NULL; i++)
2469 MimeInfoCacheDir *dir;
2471 dir = mime_info_cache_dir_new (dirs[i]);
2475 mime_info_cache_dir_init (dir);
2476 mime_info_cache_dir_init_defaults_list (dir);
2477 mime_info_cache_dir_init_mimeapps_list (dir);
2479 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2485 mime_info_cache_update_dir_lists (void)
2489 tmp = mime_info_cache->dirs;
2493 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2495 /* No need to do this if we had file monitors... */
2496 mime_info_cache_blow_global_cache ();
2497 mime_info_cache_dir_init (dir);
2498 mime_info_cache_dir_init_defaults_list (dir);
2499 mime_info_cache_dir_init_mimeapps_list (dir);
2506 mime_info_cache_init (void)
2508 G_LOCK (mime_info_cache);
2509 if (mime_info_cache == NULL)
2510 mime_info_cache_init_dir_lists ();
2516 if (now >= mime_info_cache->last_stat_time + 10)
2518 mime_info_cache_update_dir_lists ();
2519 mime_info_cache->last_stat_time = now;
2523 if (mime_info_cache->should_ping_mime_monitor)
2525 /* g_idle_add (emit_mime_changed, NULL); */
2526 mime_info_cache->should_ping_mime_monitor = FALSE;
2529 G_UNLOCK (mime_info_cache);
2532 static MimeInfoCache *
2533 mime_info_cache_new (void)
2535 MimeInfoCache *cache;
2537 cache = g_new0 (MimeInfoCache, 1);
2539 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2540 (GDestroyNotify) g_free,
2541 (GDestroyNotify) g_free);
2546 mime_info_cache_free (MimeInfoCache *cache)
2551 g_list_foreach (cache->dirs,
2552 (GFunc) mime_info_cache_dir_free,
2554 g_list_free (cache->dirs);
2555 g_hash_table_destroy (cache->global_defaults_cache);
2560 * mime_info_cache_reload:
2561 * @dir: directory path which needs reloading.
2563 * Reload the mime information for the @dir.
2566 mime_info_cache_reload (const char *dir)
2568 /* FIXME: just reload the dir that needs reloading,
2569 * don't blow the whole cache
2571 if (mime_info_cache != NULL)
2573 G_LOCK (mime_info_cache);
2574 mime_info_cache_free (mime_info_cache);
2575 mime_info_cache = NULL;
2576 G_UNLOCK (mime_info_cache);
2581 append_desktop_entry (GList *list,
2582 const char *desktop_entry,
2583 GList *removed_entries)
2585 /* Add if not already in list, and valid */
2586 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2587 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2588 list = g_list_prepend (list, g_strdup (desktop_entry));
2594 * get_all_desktop_entries_for_mime_type:
2595 * @mime_type: a mime type.
2596 * @except: NULL or a strv list
2598 * Returns all the desktop ids for @mime_type. The desktop files
2599 * are listed in an order so that default applications are listed before
2600 * non-default ones, and handlers for inherited mimetypes are listed
2601 * after the base ones.
2603 * Optionally doesn't list the desktop ids given in the @except
2605 * Return value: a #GList containing the desktop ids which claim
2606 * to handle @mime_type.
2609 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2610 const char **except)
2612 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2613 MimeInfoCacheDir *dir;
2616 char **default_entries;
2617 char **removed_associations;
2622 mime_info_cache_init ();
2624 /* collect all ancestors */
2625 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2626 array = g_ptr_array_new ();
2627 for (i = 0; mime_types[i]; i++)
2628 g_ptr_array_add (array, mime_types[i]);
2629 g_free (mime_types);
2630 for (i = 0; i < array->len; i++)
2632 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2633 for (j = 0; anc[j]; j++)
2635 for (k = 0; k < array->len; k++)
2637 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2640 if (k == array->len) /* not found */
2641 g_ptr_array_add (array, g_strdup (anc[j]));
2645 g_ptr_array_add (array, NULL);
2646 mime_types = (char **)g_ptr_array_free (array, FALSE);
2648 G_LOCK (mime_info_cache);
2650 removed_entries = NULL;
2651 desktop_entries = NULL;
2653 for (i = 0; except != NULL && except[i] != NULL; i++)
2654 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2656 for (i = 0; mime_types[i] != NULL; i++)
2658 mime_type = mime_types[i];
2660 /* Go through all apps listed as defaults */
2661 for (dir_list = mime_info_cache->dirs;
2663 dir_list = dir_list->next)
2665 dir = dir_list->data;
2667 /* First added associations from mimeapps.list */
2668 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2669 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2670 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2672 /* Then removed associations from mimeapps.list */
2673 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2674 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2675 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2677 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2678 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2679 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2680 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2683 /* Go through all entries that support the mimetype */
2684 for (dir_list = mime_info_cache->dirs;
2686 dir_list = dir_list->next)
2688 dir = dir_list->data;
2690 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2691 for (tmp = list; tmp != NULL; tmp = tmp->next)
2692 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2696 G_UNLOCK (mime_info_cache);
2698 g_strfreev (mime_types);
2700 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2701 g_list_free (removed_entries);
2703 desktop_entries = g_list_reverse (desktop_entries);
2705 return desktop_entries;
2708 /* GDesktopAppInfoLookup interface: */
2710 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2711 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2712 gpointer class_data);
2715 g_desktop_app_info_lookup_get_type (void)
2717 static volatile gsize g_define_type_id__volatile = 0;
2719 if (g_once_init_enter (&g_define_type_id__volatile))
2721 const GTypeInfo desktop_app_info_lookup_info =
2723 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2724 g_desktop_app_info_lookup_base_init, /* base_init */
2725 NULL, /* base_finalize */
2726 g_desktop_app_info_lookup_class_init,
2727 NULL, /* class_finalize */
2728 NULL, /* class_data */
2730 0, /* n_preallocs */
2733 GType g_define_type_id =
2734 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2735 &desktop_app_info_lookup_info, 0);
2737 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2739 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2742 return g_define_type_id__volatile;
2746 g_desktop_app_info_lookup_class_init (gpointer g_class,
2747 gpointer class_data)
2752 g_desktop_app_info_lookup_base_init (gpointer g_class)
2757 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2758 * @lookup: a #GDesktopAppInfoLookup
2759 * @uri_scheme: a string containing a URI scheme.
2761 * Gets the default application for launching applications
2762 * using this URI scheme for a particular GDesktopAppInfoLookup
2765 * The GDesktopAppInfoLookup interface and this function is used
2766 * to implement g_app_info_get_default_for_uri_scheme() backends
2767 * in a GIO module. There is no reason for applications to use it
2768 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2770 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2773 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2774 const char *uri_scheme)
2776 GDesktopAppInfoLookupIface *iface;
2778 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2780 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2782 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2785 #define __G_DESKTOP_APP_INFO_C__
2786 #include "gioaliasdef.c"