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);
421 new_info->icon = g_object_ref (info->icon);
422 new_info->only_show_in = g_strdupv (info->only_show_in);
423 new_info->not_show_in = g_strdupv (info->not_show_in);
424 new_info->try_exec = g_strdup (info->try_exec);
425 new_info->exec = g_strdup (info->exec);
426 new_info->binary = g_strdup (info->binary);
427 new_info->path = g_strdup (info->path);
428 new_info->hidden = info->hidden;
429 new_info->terminal = info->terminal;
430 new_info->startup_notify = info->startup_notify;
432 return G_APP_INFO (new_info);
436 g_desktop_app_info_equal (GAppInfo *appinfo1,
439 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
440 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
442 if (info1->desktop_id == NULL ||
443 info2->desktop_id == NULL)
444 return info1 == info2;
446 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
450 g_desktop_app_info_get_id (GAppInfo *appinfo)
452 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
454 return info->desktop_id;
458 g_desktop_app_info_get_name (GAppInfo *appinfo)
460 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
462 if (info->name == NULL)
468 * g_desktop_app_info_get_is_hidden:
469 * @info: a #GDesktopAppInfo.
471 * A desktop file is hidden if the Hidden key in it is
474 * Returns: %TRUE if hidden, %FALSE otherwise.
477 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
483 g_desktop_app_info_get_description (GAppInfo *appinfo)
485 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
487 return info->comment;
491 g_desktop_app_info_get_executable (GAppInfo *appinfo)
493 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
499 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
501 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
507 g_desktop_app_info_get_icon (GAppInfo *appinfo)
509 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
515 expand_macro_single (char macro, char *uri)
521 file = g_file_new_for_uri (uri);
522 path = g_file_get_path (file);
523 g_object_unref (file);
529 result = g_shell_quote (uri);
534 result = g_shell_quote (path);
540 name = g_path_get_dirname (path);
541 result = g_shell_quote (name);
549 name = g_path_get_basename (path);
550 result = g_shell_quote (name);
562 expand_macro (char macro,
564 GDesktopAppInfo *info,
567 GList *uris = *uri_list;
569 gboolean force_file_uri;
570 char force_file_uri_macro;
573 g_return_if_fail (exec != NULL);
575 /* On %u and %U, pass POSIX file path pointing to the URI via
576 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
577 * running or the URI doesn't have a POSIX file path via FUSE
578 * we'll just pass the URI.
580 force_file_uri_macro = macro;
581 force_file_uri = FALSE;
587 force_file_uri_macro = 'f';
588 force_file_uri = TRUE;
591 force_file_uri_macro = 'F';
592 force_file_uri = TRUE;
608 if (!force_file_uri ||
609 /* Pass URI if it contains an anchor */
610 strchr (uri, '#') != NULL)
612 expanded = expand_macro_single (macro, uri);
616 expanded = expand_macro_single (force_file_uri_macro, uri);
617 if (expanded == NULL)
618 expanded = expand_macro_single (macro, uri);
623 g_string_append (exec, expanded);
639 if (!force_file_uri ||
640 /* Pass URI if it contains an anchor */
641 strchr (uri, '#') != NULL)
643 expanded = expand_macro_single (macro, uri);
647 expanded = expand_macro_single (force_file_uri_macro, uri);
648 if (expanded == NULL)
649 expanded = expand_macro_single (macro, uri);
654 g_string_append (exec, expanded);
660 if (uris != NULL && expanded)
661 g_string_append_c (exec, ' ');
669 g_string_append (exec, "--icon ");
670 g_string_append (exec, info->icon_name);
676 g_string_append (exec, info->name);
681 g_string_append (exec, info->filename);
684 case 'm': /* deprecated */
688 g_string_append_c (exec, '%');
696 expand_application_parameters (GDesktopAppInfo *info,
702 GList *uri_list = *uris;
703 const char *p = info->exec;
704 GString *expanded_exec = g_string_new (NULL);
707 if (info->exec == NULL)
709 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
710 _("Desktop file didn't specify Exec field"));
716 if (p[0] == '%' && p[1] != '\0')
718 expand_macro (p[1], expanded_exec, info, uris);
722 g_string_append_c (expanded_exec, *p);
727 /* No file substitutions */
728 if (uri_list == *uris && uri_list != NULL)
730 /* If there is no macro default to %f. This is also what KDE does */
731 g_string_append_c (expanded_exec, ' ');
732 expand_macro ('f', expanded_exec, info, uris);
735 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
736 g_string_free (expanded_exec, TRUE);
741 prepend_terminal_to_vector (int *argc,
748 char **term_argv = NULL;
753 g_return_val_if_fail (argc != NULL, FALSE);
754 g_return_val_if_fail (argv != NULL, FALSE);
762 /* compute size if not given */
765 for (i = 0; the_argv[i] != NULL; i++)
771 term_argv = g_new0 (char *, 3);
773 check = g_find_program_in_path ("gnome-terminal");
776 term_argv[0] = check;
777 /* Note that gnome-terminal takes -x and
778 * as -e in gnome-terminal is broken we use that. */
779 term_argv[1] = g_strdup ("-x");
784 check = g_find_program_in_path ("nxterm");
786 check = g_find_program_in_path ("color-xterm");
788 check = g_find_program_in_path ("rxvt");
790 check = g_find_program_in_path ("xterm");
792 check = g_find_program_in_path ("dtterm");
795 check = g_strdup ("xterm");
796 g_warning ("couldn't find a terminal, falling back to xterm");
798 term_argv[0] = check;
799 term_argv[1] = g_strdup ("-e");
802 real_argc = term_argc + *argc;
803 real_argv = g_new (char *, real_argc + 1);
805 for (i = 0; i < term_argc; i++)
806 real_argv[i] = term_argv[i];
808 for (j = 0; j < *argc; j++, i++)
809 real_argv[i] = (char *)the_argv[j];
817 /* we use g_free here as we sucked all the inner strings
818 * out from it into real_argv */
823 #endif /* G_OS_WIN32 */
827 uri_list_segment_to_files (GList *start,
834 while (start != NULL && start != end)
836 file = g_file_new_for_uri ((char *)start->data);
837 res = g_list_prepend (res, file);
841 return g_list_reverse (res);
851 child_setup (gpointer user_data)
853 ChildSetupData *data = user_data;
856 g_setenv ("DISPLAY", data->display, TRUE);
858 g_unsetenv ("DISPLAY");
861 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
863 g_unsetenv ("DESKTOP_STARTUP_ID");
867 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
869 GAppLaunchContext *launch_context,
872 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
873 gboolean completed = FALSE;
875 GList *launched_files;
880 g_return_val_if_fail (appinfo != NULL, FALSE);
887 if (!expand_application_parameters (info, &uris,
888 &argc, &argv, error))
891 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
893 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
894 _("Unable to find terminal required for application"));
903 launched_files = uri_list_segment_to_files (old_uris, uris);
905 data.display = g_app_launch_context_get_display (launch_context,
909 if (info->startup_notify)
910 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
913 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
914 g_list_free (launched_files);
917 if (!g_spawn_async (info->path,
927 g_app_launch_context_launch_failed (launch_context, data.sn_id);
930 g_free (data.display);
936 g_free (data.display);
941 while (uris != NULL);
952 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
954 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
957 ((strstr (info->exec, "%u") != NULL) ||
958 (strstr (info->exec, "%U") != NULL));
962 g_desktop_app_info_supports_files (GAppInfo *appinfo)
964 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
967 ((strstr (info->exec, "%f") != NULL) ||
968 (strstr (info->exec, "%F") != NULL));
972 g_desktop_app_info_launch (GAppInfo *appinfo,
974 GAppLaunchContext *launch_context,
984 uri = g_file_get_uri (files->data);
985 uris = g_list_prepend (uris, uri);
989 uris = g_list_reverse (uris);
991 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
993 g_list_foreach (uris, (GFunc)g_free, NULL);
999 G_LOCK_DEFINE_STATIC (g_desktop_env);
1000 static gchar *g_desktop_env = NULL;
1003 * g_desktop_app_info_set_desktop_env:
1004 * @desktop_env: a string specifying what desktop this is
1006 * Sets the name of the desktop that the application is running in.
1007 * This is used by g_app_info_should_show() to evaluate the
1008 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1009 * desktop entry fields.
1011 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1012 * Menu specification</ulink> recognizes the following:
1014 * <member>GNOME</member>
1015 * <member>KDE</member>
1016 * <member>ROX</member>
1017 * <member>XFCE</member>
1018 * <member>Old</member>
1021 * Should be called only once; subsequent calls are ignored.
1024 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1026 G_LOCK (g_desktop_env);
1028 g_desktop_env = g_strdup (desktop_env);
1029 G_UNLOCK (g_desktop_env);
1033 g_desktop_app_info_should_show (GAppInfo *appinfo)
1035 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1037 const gchar *desktop_env;
1040 if (info->nodisplay)
1043 G_LOCK (g_desktop_env);
1044 desktop_env = g_desktop_env;
1045 G_UNLOCK (g_desktop_env);
1047 if (info->only_show_in)
1049 if (desktop_env == NULL)
1053 for (i = 0; info->only_show_in[i] != NULL; i++)
1055 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1065 if (info->not_show_in && desktop_env)
1067 for (i = 0; info->not_show_in[i] != NULL; i++)
1069 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1083 ensure_dir (DirType type,
1086 char *path, *display_name;
1089 if (type == APP_DIR)
1090 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1092 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1095 if (g_mkdir_with_parents (path, 0700) == 0)
1099 display_name = g_filename_display_name (path);
1100 if (type == APP_DIR)
1101 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1102 _("Can't create user application configuration folder %s: %s"),
1103 display_name, g_strerror (errsv));
1105 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1106 _("Can't create user MIME configuration folder %s: %s"),
1107 display_name, g_strerror (errsv));
1109 g_free (display_name);
1116 update_mimeapps_list (const char *desktop_id,
1117 const char *content_type,
1118 gboolean add_as_default,
1119 gboolean add_non_default,
1123 char *dirname, *filename;
1125 gboolean load_succeeded, res;
1126 char **old_list, **list;
1127 GList *system_list, *l;
1128 gsize length, data_size;
1131 char **content_types;
1133 /* Don't add both at start and end */
1134 g_assert (!(add_as_default && add_non_default));
1136 dirname = ensure_dir (APP_DIR, error);
1140 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1143 key_file = g_key_file_new ();
1144 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1145 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1147 g_key_file_free (key_file);
1148 key_file = g_key_file_new ();
1153 content_types = g_new (char *, 2);
1154 content_types[0] = g_strdup (content_type);
1155 content_types[1] = NULL;
1159 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1162 for (k = 0; content_types && content_types[k]; k++)
1164 /* Add to the right place in the list */
1167 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1168 content_types[k], &length, NULL);
1170 list = g_new (char *, 1 + length + 1);
1174 list[i++] = g_strdup (desktop_id);
1177 for (j = 0; old_list[j] != NULL; j++)
1179 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1180 list[i++] = g_strdup (old_list[j]);
1181 else if (add_non_default)
1183 /* If adding as non-default, and it's already in,
1184 don't change order of desktop ids */
1185 add_non_default = FALSE;
1186 list[i++] = g_strdup (old_list[j]);
1191 if (add_non_default)
1193 /* We're adding as non-default, and it wasn't already in the list,
1194 so we add at the end. But to avoid listing the app before the
1195 current system default (thus changing the default) we have to
1196 add the current list of (not yet listed) apps before it. */
1198 list[i] = NULL; /* Terminate current list so we can use it */
1199 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1201 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1203 for (l = system_list; l != NULL; l = l->next)
1205 list[i++] = l->data; /* no strdup, taking ownership */
1206 if (g_strcmp0 (l->data, desktop_id) == 0)
1207 add_non_default = FALSE;
1209 g_list_free (system_list);
1211 if (add_non_default)
1212 list[i++] = g_strdup (desktop_id);
1217 g_strfreev (old_list);
1219 if (list[0] == NULL || desktop_id == NULL)
1220 g_key_file_remove_key (key_file,
1221 ADDED_ASSOCIATIONS_GROUP,
1225 g_key_file_set_string_list (key_file,
1226 ADDED_ASSOCIATIONS_GROUP,
1228 (const char * const *)list, i);
1235 /* reuse the list from above */
1239 g_strfreev (content_types);
1240 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1243 for (k = 0; content_types && content_types[k]; k++)
1245 /* Remove from removed associations group (unless remove) */
1248 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1249 content_types[k], &length, NULL);
1251 list = g_new (char *, 1 + length + 1);
1255 list[i++] = g_strdup (desktop_id);
1258 for (j = 0; old_list[j] != NULL; j++)
1260 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1261 list[i++] = g_strdup (old_list[j]);
1266 g_strfreev (old_list);
1268 if (list[0] == NULL || desktop_id == NULL)
1269 g_key_file_remove_key (key_file,
1270 REMOVED_ASSOCIATIONS_GROUP,
1274 g_key_file_set_string_list (key_file,
1275 REMOVED_ASSOCIATIONS_GROUP,
1277 (const char * const *)list, i);
1282 g_strfreev (content_types);
1284 data = g_key_file_to_data (key_file, &data_size, error);
1285 g_key_file_free (key_file);
1287 res = g_file_set_contents (filename, data, data_size, error);
1289 mime_info_cache_reload (NULL);
1298 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1299 const char *content_type,
1302 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1304 if (!g_desktop_app_info_ensure_saved (info, error))
1307 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1311 update_program_done (GPid pid,
1315 /* Did the application exit correctly */
1316 if (WIFEXITED (status) &&
1317 WEXITSTATUS (status) == 0)
1319 /* Here we could clean out any caches in use */
1324 run_update_command (char *command,
1333 GError *error = NULL;
1336 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1338 if (g_spawn_async ("/", argv,
1340 G_SPAWN_SEARCH_PATH |
1341 G_SPAWN_STDOUT_TO_DEV_NULL |
1342 G_SPAWN_STDERR_TO_DEV_NULL |
1343 G_SPAWN_DO_NOT_REAP_CHILD,
1344 NULL, NULL, /* No setup function */
1347 g_child_watch_add (pid, update_program_done, NULL);
1350 /* If we get an error at this point, it's quite likely the user doesn't
1351 * have an installed copy of either 'update-mime-database' or
1352 * 'update-desktop-database'. I don't think we want to popup an error
1353 * dialog at this point, so we just do a g_warning to give the user a
1354 * chance of debugging it.
1356 g_warning ("%s", error->message);
1363 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1364 const char *extension,
1367 char *filename, *basename, *mimetype;
1371 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1374 dirname = ensure_dir (MIMETYPE_DIR, error);
1378 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1379 filename = g_build_filename (dirname, basename, NULL);
1383 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1385 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1390 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1391 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1392 " <mime-type type=\"%s\">\n"
1393 " <comment>%s document</comment>\n"
1394 " <glob pattern=\"*.%s\"/>\n"
1396 "</mime-info>\n", mimetype, extension, extension);
1398 g_file_set_contents (filename, contents, -1, NULL);
1401 run_update_command ("update-mime-database", "mime");
1405 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1415 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1416 const char *content_type,
1419 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1421 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1424 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1428 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1434 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1435 const char *content_type,
1438 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1440 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1443 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1447 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1453 char *data, *desktop_id;
1458 if (info->filename != NULL)
1461 /* This is only used for object created with
1462 * g_app_info_create_from_commandline. All other
1463 * object should have a filename
1466 dirname = ensure_dir (APP_DIR, error);
1470 key_file = g_key_file_new ();
1472 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1473 "Encoding", "UTF-8");
1474 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1475 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1476 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1477 G_KEY_FILE_DESKTOP_KEY_TYPE,
1478 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1480 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1481 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1483 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1484 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1486 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1487 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1489 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1490 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1492 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1493 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1495 data = g_key_file_to_data (key_file, &data_size, NULL);
1496 g_key_file_free (key_file);
1498 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1499 filename = g_build_filename (dirname, desktop_id, NULL);
1500 g_free (desktop_id);
1503 fd = g_mkstemp (filename);
1508 display_name = g_filename_display_name (filename);
1509 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1510 _("Can't create user desktop file %s"), display_name);
1511 g_free (display_name);
1517 desktop_id = g_path_get_basename (filename);
1521 res = g_file_set_contents (filename, data, data_size, error);
1524 g_free (desktop_id);
1529 info->filename = filename;
1530 info->desktop_id = desktop_id;
1532 run_update_command ("update-desktop-database", "applications");
1538 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1540 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1544 if (strstr (info->filename, "/userapp-"))
1545 return g_access (info->filename, W_OK) == 0;
1552 g_desktop_app_info_delete (GAppInfo *appinfo)
1554 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1558 if (g_remove (info->filename) == 0)
1560 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1562 g_free (info->filename);
1563 info->filename = NULL;
1564 g_free (info->desktop_id);
1565 info->desktop_id = NULL;
1575 * g_app_info_create_from_commandline:
1576 * @commandline: the commandline to use
1577 * @application_name: the application name, or %NULL to use @commandline
1578 * @flags: flags that can specify details of the created #GAppInfo
1579 * @error: a #GError location to store the error occuring, %NULL to ignore.
1581 * Creates a new #GAppInfo from the given information.
1583 * Returns: new #GAppInfo for given command.
1586 g_app_info_create_from_commandline (const char *commandline,
1587 const char *application_name,
1588 GAppInfoCreateFlags flags,
1593 GDesktopAppInfo *info;
1595 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1597 info->filename = NULL;
1598 info->desktop_id = NULL;
1600 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1601 info->startup_notify = FALSE;
1602 info->hidden = FALSE;
1603 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1604 info->exec = g_strconcat (commandline, " %u", NULL);
1606 info->exec = g_strconcat (commandline, " %f", NULL);
1607 info->nodisplay = TRUE;
1608 info->binary = binary_from_exec (info->exec);
1610 if (application_name)
1611 info->name = g_strdup (application_name);
1614 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1615 split = g_strsplit (commandline, " ", 2);
1616 basename = g_path_get_basename (split[0]);
1618 info->name = basename;
1619 if (info->name == NULL)
1620 info->name = g_strdup ("custom");
1622 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1624 return G_APP_INFO (info);
1628 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1630 iface->dup = g_desktop_app_info_dup;
1631 iface->equal = g_desktop_app_info_equal;
1632 iface->get_id = g_desktop_app_info_get_id;
1633 iface->get_name = g_desktop_app_info_get_name;
1634 iface->get_description = g_desktop_app_info_get_description;
1635 iface->get_executable = g_desktop_app_info_get_executable;
1636 iface->get_icon = g_desktop_app_info_get_icon;
1637 iface->launch = g_desktop_app_info_launch;
1638 iface->supports_uris = g_desktop_app_info_supports_uris;
1639 iface->supports_files = g_desktop_app_info_supports_files;
1640 iface->launch_uris = g_desktop_app_info_launch_uris;
1641 iface->should_show = g_desktop_app_info_should_show;
1642 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1643 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1644 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1645 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1646 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1647 iface->can_delete = g_desktop_app_info_can_delete;
1648 iface->do_delete = g_desktop_app_info_delete;
1649 iface->get_commandline = g_desktop_app_info_get_commandline;
1653 app_info_in_list (GAppInfo *info,
1656 while (list != NULL)
1658 if (g_app_info_equal (info, list->data))
1667 * g_app_info_get_all_for_type:
1668 * @content_type: the content type to find a #GAppInfo for
1670 * Gets a list of all #GAppInfo s for a given content type.
1672 * Returns: #GList of #GAppInfo s for given @content_type
1673 * or %NULL on error.
1676 g_app_info_get_all_for_type (const char *content_type)
1678 GList *desktop_entries, *l;
1680 GDesktopAppInfo *info;
1682 g_return_val_if_fail (content_type != NULL, NULL);
1684 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1687 for (l = desktop_entries; l != NULL; l = l->next)
1689 char *desktop_entry = l->data;
1691 info = g_desktop_app_info_new (desktop_entry);
1694 if (app_info_in_list (G_APP_INFO (info), infos))
1695 g_object_unref (info);
1697 infos = g_list_prepend (infos, info);
1699 g_free (desktop_entry);
1702 g_list_free (desktop_entries);
1704 return g_list_reverse (infos);
1708 * g_app_info_reset_type_associations:
1709 * @content_type: a content type
1711 * Removes all changes to the type associations done by
1712 * g_app_info_set_as_default_for_type(),
1713 * g_app_info_set_as_default_for_extension(),
1714 * g_app_info_add_supports_type() of g_app_info_remove_supports_type().
1719 g_app_info_reset_type_associations (const char *content_type)
1721 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1725 * g_app_info_get_default_for_type:
1726 * @content_type: the content type to find a #GAppInfo for
1727 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1730 * Gets the #GAppInfo that correspond to a given content type.
1732 * Returns: #GAppInfo for given @content_type or %NULL on error.
1735 g_app_info_get_default_for_type (const char *content_type,
1736 gboolean must_support_uris)
1738 GList *desktop_entries, *l;
1741 g_return_val_if_fail (content_type != NULL, NULL);
1743 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1746 for (l = desktop_entries; l != NULL; l = l->next)
1748 char *desktop_entry = l->data;
1750 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1753 if (must_support_uris && !g_app_info_supports_uris (info))
1755 g_object_unref (info);
1763 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1764 g_list_free (desktop_entries);
1770 * g_app_info_get_default_for_uri_scheme:
1771 * @uri_scheme: a string containing a URI scheme.
1773 * Gets the default application for launching applications
1774 * using this URI scheme. A URI scheme is the initial part
1775 * of the URI, up to but not including the ':', e.g. "http",
1778 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1781 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1783 static gsize lookup = 0;
1785 if (g_once_init_enter (&lookup))
1787 gsize setup_value = 1;
1788 GDesktopAppInfoLookup *lookup_instance;
1789 const char *use_this;
1790 GIOExtensionPoint *ep;
1791 GIOExtension *extension;
1794 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1796 /* Ensure vfs in modules loaded */
1797 _g_io_modules_ensure_loaded ();
1799 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1801 lookup_instance = NULL;
1804 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1806 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1809 if (lookup_instance == NULL)
1811 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1813 extension = l->data;
1814 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1815 if (lookup_instance != NULL)
1820 if (lookup_instance != NULL)
1821 setup_value = (gsize)lookup_instance;
1823 g_once_init_leave (&lookup, setup_value);
1829 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1835 get_apps_from_dir (GHashTable *apps,
1836 const char *dirname,
1840 const char *basename;
1841 char *filename, *subprefix, *desktop_id;
1843 GDesktopAppInfo *appinfo;
1845 dir = g_dir_open (dirname, 0, NULL);
1848 while ((basename = g_dir_read_name (dir)) != NULL)
1850 filename = g_build_filename (dirname, basename, NULL);
1851 if (g_str_has_suffix (basename, ".desktop"))
1853 desktop_id = g_strconcat (prefix, basename, NULL);
1855 /* Use _extended so we catch NULLs too (hidden) */
1856 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1858 appinfo = g_desktop_app_info_new_from_filename (filename);
1860 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1862 g_object_unref (appinfo);
1867 if (appinfo || hidden)
1869 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1873 /* Reuse instead of strdup here */
1874 appinfo->desktop_id = desktop_id;
1879 g_free (desktop_id);
1883 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1885 subprefix = g_strconcat (prefix, basename, "-", NULL);
1886 get_apps_from_dir (apps, filename, subprefix);
1898 * g_app_info_get_all:
1900 * Gets a list of all of the applications currently registered
1903 * For desktop files, this includes applications that have
1904 * <literal>NoDisplay=true</literal> set or are excluded from
1905 * display by means of <literal>OnlyShowIn</literal> or
1906 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1907 * The returned list does not include applications which have
1908 * the <literal>Hidden</literal> key set.
1910 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1913 g_app_info_get_all (void)
1915 const char * const *dirs;
1917 GHashTableIter iter;
1922 dirs = get_applications_search_path ();
1924 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1928 for (i = 0; dirs[i] != NULL; i++)
1929 get_apps_from_dir (apps, dirs[i], "");
1933 g_hash_table_iter_init (&iter, apps);
1934 while (g_hash_table_iter_next (&iter, NULL, &value))
1937 infos = g_list_prepend (infos, value);
1940 g_hash_table_destroy (apps);
1942 return g_list_reverse (infos);
1945 /* Cacheing of mimeinfo.cache and defaults.list files */
1949 GHashTable *mime_info_cache_map;
1950 GHashTable *defaults_list_map;
1951 GHashTable *mimeapps_list_added_map;
1952 GHashTable *mimeapps_list_removed_map;
1953 time_t mime_info_cache_timestamp;
1954 time_t defaults_list_timestamp;
1955 time_t mimeapps_list_timestamp;
1959 GList *dirs; /* mimeinfo.cache and defaults.list */
1960 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1961 time_t last_stat_time;
1962 guint should_ping_mime_monitor : 1;
1965 static MimeInfoCache *mime_info_cache = NULL;
1966 G_LOCK_DEFINE_STATIC (mime_info_cache);
1968 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
1969 const char *mime_type,
1970 char **new_desktop_file_ids);
1972 static MimeInfoCache * mime_info_cache_new (void);
1975 destroy_info_cache_value (gpointer key,
1979 g_list_foreach (value, (GFunc)g_free, NULL);
1980 g_list_free (value);
1984 destroy_info_cache_map (GHashTable *info_cache_map)
1986 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
1987 g_hash_table_destroy (info_cache_map);
1991 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
1992 const char *cache_file,
1998 filename = g_build_filename (dir->path, cache_file, NULL);
2000 if (g_stat (filename, &buf) < 0)
2007 if (buf.st_mtime != *timestamp)
2013 /* Call with lock held */
2015 remove_all (gpointer key,
2024 mime_info_cache_blow_global_cache (void)
2026 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2031 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2035 gchar *filename, **mime_types;
2042 if (dir->mime_info_cache_map != NULL &&
2043 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2044 &dir->mime_info_cache_timestamp))
2047 if (dir->mime_info_cache_map != NULL)
2048 destroy_info_cache_map (dir->mime_info_cache_map);
2050 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2051 (GDestroyNotify) g_free,
2054 key_file = g_key_file_new ();
2056 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2058 if (g_stat (filename, &buf) < 0)
2061 if (dir->mime_info_cache_timestamp > 0)
2062 mime_info_cache->should_ping_mime_monitor = TRUE;
2064 dir->mime_info_cache_timestamp = buf.st_mtime;
2066 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2071 if (load_error != NULL)
2074 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2077 if (load_error != NULL)
2080 for (i = 0; mime_types[i] != NULL; i++)
2082 gchar **desktop_file_ids;
2083 char *unaliased_type;
2084 desktop_file_ids = g_key_file_get_string_list (key_file,
2090 if (desktop_file_ids == NULL)
2093 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2094 mime_info_cache_dir_add_desktop_entries (dir,
2097 g_free (unaliased_type);
2099 g_strfreev (desktop_file_ids);
2102 g_strfreev (mime_types);
2103 g_key_file_free (key_file);
2108 g_key_file_free (key_file);
2110 if (mime_types != NULL)
2111 g_strfreev (mime_types);
2114 g_error_free (load_error);
2118 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2122 gchar *filename, **mime_types;
2123 char *unaliased_type;
2124 char **desktop_file_ids;
2131 if (dir->defaults_list_map != NULL &&
2132 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2133 &dir->defaults_list_timestamp))
2136 if (dir->defaults_list_map != NULL)
2137 g_hash_table_destroy (dir->defaults_list_map);
2138 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2139 g_free, (GDestroyNotify)g_strfreev);
2142 key_file = g_key_file_new ();
2144 filename = g_build_filename (dir->path, "defaults.list", NULL);
2145 if (g_stat (filename, &buf) < 0)
2148 if (dir->defaults_list_timestamp > 0)
2149 mime_info_cache->should_ping_mime_monitor = TRUE;
2151 dir->defaults_list_timestamp = buf.st_mtime;
2153 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2157 if (load_error != NULL)
2160 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2162 if (mime_types != NULL)
2164 for (i = 0; mime_types[i] != NULL; i++)
2166 desktop_file_ids = g_key_file_get_string_list (key_file,
2167 DEFAULT_APPLICATIONS_GROUP,
2171 if (desktop_file_ids == NULL)
2174 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2175 g_hash_table_replace (dir->defaults_list_map,
2180 g_strfreev (mime_types);
2183 g_key_file_free (key_file);
2188 g_key_file_free (key_file);
2190 if (mime_types != NULL)
2191 g_strfreev (mime_types);
2194 g_error_free (load_error);
2198 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2202 gchar *filename, **mime_types;
2203 char *unaliased_type;
2204 char **desktop_file_ids;
2211 if (dir->mimeapps_list_added_map != NULL &&
2212 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2213 &dir->mimeapps_list_timestamp))
2216 if (dir->mimeapps_list_added_map != NULL)
2217 g_hash_table_destroy (dir->mimeapps_list_added_map);
2218 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2219 g_free, (GDestroyNotify)g_strfreev);
2221 if (dir->mimeapps_list_removed_map != NULL)
2222 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2223 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2224 g_free, (GDestroyNotify)g_strfreev);
2226 key_file = g_key_file_new ();
2228 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2229 if (g_stat (filename, &buf) < 0)
2232 if (dir->mimeapps_list_timestamp > 0)
2233 mime_info_cache->should_ping_mime_monitor = TRUE;
2235 dir->mimeapps_list_timestamp = buf.st_mtime;
2237 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2241 if (load_error != NULL)
2244 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2246 if (mime_types != NULL)
2248 for (i = 0; mime_types[i] != NULL; i++)
2250 desktop_file_ids = g_key_file_get_string_list (key_file,
2251 ADDED_ASSOCIATIONS_GROUP,
2255 if (desktop_file_ids == NULL)
2258 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2259 g_hash_table_replace (dir->mimeapps_list_added_map,
2264 g_strfreev (mime_types);
2267 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2269 if (mime_types != NULL)
2271 for (i = 0; mime_types[i] != NULL; i++)
2273 desktop_file_ids = g_key_file_get_string_list (key_file,
2274 REMOVED_ASSOCIATIONS_GROUP,
2278 if (desktop_file_ids == NULL)
2281 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2282 g_hash_table_replace (dir->mimeapps_list_removed_map,
2287 g_strfreev (mime_types);
2290 g_key_file_free (key_file);
2295 g_key_file_free (key_file);
2297 if (mime_types != NULL)
2298 g_strfreev (mime_types);
2301 g_error_free (load_error);
2304 static MimeInfoCacheDir *
2305 mime_info_cache_dir_new (const char *path)
2307 MimeInfoCacheDir *dir;
2309 dir = g_new0 (MimeInfoCacheDir, 1);
2310 dir->path = g_strdup (path);
2316 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2321 if (dir->mime_info_cache_map != NULL)
2323 destroy_info_cache_map (dir->mime_info_cache_map);
2324 dir->mime_info_cache_map = NULL;
2328 if (dir->defaults_list_map != NULL)
2330 g_hash_table_destroy (dir->defaults_list_map);
2331 dir->defaults_list_map = NULL;
2334 if (dir->mimeapps_list_added_map != NULL)
2336 g_hash_table_destroy (dir->mimeapps_list_added_map);
2337 dir->mimeapps_list_added_map = NULL;
2340 if (dir->mimeapps_list_removed_map != NULL)
2342 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2343 dir->mimeapps_list_removed_map = NULL;
2350 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2351 const char *mime_type,
2352 char **new_desktop_file_ids)
2354 GList *desktop_file_ids;
2357 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2360 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2362 if (!g_list_find (desktop_file_ids, new_desktop_file_ids[i]))
2363 desktop_file_ids = g_list_append (desktop_file_ids,
2364 g_strdup (new_desktop_file_ids[i]));
2367 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2371 mime_info_cache_init_dir_lists (void)
2373 const char * const *dirs;
2376 mime_info_cache = mime_info_cache_new ();
2378 dirs = get_applications_search_path ();
2380 for (i = 0; dirs[i] != NULL; i++)
2382 MimeInfoCacheDir *dir;
2384 dir = mime_info_cache_dir_new (dirs[i]);
2388 mime_info_cache_dir_init (dir);
2389 mime_info_cache_dir_init_defaults_list (dir);
2390 mime_info_cache_dir_init_mimeapps_list (dir);
2392 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2398 mime_info_cache_update_dir_lists (void)
2402 tmp = mime_info_cache->dirs;
2406 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2408 /* No need to do this if we had file monitors... */
2409 mime_info_cache_blow_global_cache ();
2410 mime_info_cache_dir_init (dir);
2411 mime_info_cache_dir_init_defaults_list (dir);
2412 mime_info_cache_dir_init_mimeapps_list (dir);
2419 mime_info_cache_init (void)
2421 G_LOCK (mime_info_cache);
2422 if (mime_info_cache == NULL)
2423 mime_info_cache_init_dir_lists ();
2429 if (now >= mime_info_cache->last_stat_time + 10)
2431 mime_info_cache_update_dir_lists ();
2432 mime_info_cache->last_stat_time = now;
2436 if (mime_info_cache->should_ping_mime_monitor)
2438 /* g_idle_add (emit_mime_changed, NULL); */
2439 mime_info_cache->should_ping_mime_monitor = FALSE;
2442 G_UNLOCK (mime_info_cache);
2445 static MimeInfoCache *
2446 mime_info_cache_new (void)
2448 MimeInfoCache *cache;
2450 cache = g_new0 (MimeInfoCache, 1);
2452 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2453 (GDestroyNotify) g_free,
2454 (GDestroyNotify) g_free);
2459 mime_info_cache_free (MimeInfoCache *cache)
2464 g_list_foreach (cache->dirs,
2465 (GFunc) mime_info_cache_dir_free,
2467 g_list_free (cache->dirs);
2468 g_hash_table_destroy (cache->global_defaults_cache);
2473 * mime_info_cache_reload:
2474 * @dir: directory path which needs reloading.
2476 * Reload the mime information for the @dir.
2479 mime_info_cache_reload (const char *dir)
2481 /* FIXME: just reload the dir that needs reloading,
2482 * don't blow the whole cache
2484 if (mime_info_cache != NULL)
2486 G_LOCK (mime_info_cache);
2487 mime_info_cache_free (mime_info_cache);
2488 mime_info_cache = NULL;
2489 G_UNLOCK (mime_info_cache);
2494 append_desktop_entry (GList *list,
2495 const char *desktop_entry,
2496 GList *removed_entries)
2498 /* Add if not already in list, and valid */
2499 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2500 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2501 list = g_list_prepend (list, g_strdup (desktop_entry));
2507 * get_all_desktop_entries_for_mime_type:
2508 * @mime_type: a mime type.
2509 * @except: NULL or a strv list
2511 * Returns all the desktop ids for @mime_type. The desktop files
2512 * are listed in an order so that default applications are listed before
2513 * non-default ones, and handlers for inherited mimetypes are listed
2514 * after the base ones.
2516 * Optionally doesn't list the desktop ids given in the @except
2518 * Return value: a #GList containing the desktop ids which claim
2519 * to handle @mime_type.
2522 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2523 const char **except)
2525 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2526 MimeInfoCacheDir *dir;
2529 char **default_entries;
2530 char **removed_associations;
2535 mime_info_cache_init ();
2537 /* collect all ancestors */
2538 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2539 array = g_ptr_array_new ();
2540 for (i = 0; mime_types[i]; i++)
2541 g_ptr_array_add (array, mime_types[i]);
2542 g_free (mime_types);
2543 for (i = 0; i < array->len; i++)
2545 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2546 for (j = 0; anc[j]; j++)
2548 for (k = 0; k < array->len; k++)
2550 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2553 if (k == array->len) /* not found */
2554 g_ptr_array_add (array, g_strdup (anc[j]));
2558 g_ptr_array_add (array, NULL);
2559 mime_types = (char **)g_ptr_array_free (array, FALSE);
2561 G_LOCK (mime_info_cache);
2563 removed_entries = NULL;
2564 desktop_entries = NULL;
2566 for (i = 0; except != NULL && except[i] != NULL; i++)
2567 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2569 for (i = 0; mime_types[i] != NULL; i++)
2571 mime_type = mime_types[i];
2573 /* Go through all apps listed as defaults */
2574 for (dir_list = mime_info_cache->dirs;
2576 dir_list = dir_list->next)
2578 dir = dir_list->data;
2580 /* First added associations from mimeapps.list */
2581 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2582 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2583 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2585 /* Then removed associations from mimeapps.list */
2586 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2587 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2588 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2590 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2591 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2592 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2593 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2596 /* Go through all entries that support the mimetype */
2597 for (dir_list = mime_info_cache->dirs;
2599 dir_list = dir_list->next)
2601 dir = dir_list->data;
2603 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2604 for (tmp = list; tmp != NULL; tmp = tmp->next)
2605 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2609 G_UNLOCK (mime_info_cache);
2611 g_strfreev (mime_types);
2613 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2614 g_list_free (removed_entries);
2616 desktop_entries = g_list_reverse (desktop_entries);
2618 return desktop_entries;
2621 /* GDesktopAppInfoLookup interface: */
2623 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2624 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2625 gpointer class_data);
2628 g_desktop_app_info_lookup_get_type (void)
2630 static volatile gsize g_define_type_id__volatile = 0;
2632 if (g_once_init_enter (&g_define_type_id__volatile))
2634 const GTypeInfo desktop_app_info_lookup_info =
2636 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2637 g_desktop_app_info_lookup_base_init, /* base_init */
2638 NULL, /* base_finalize */
2639 g_desktop_app_info_lookup_class_init,
2640 NULL, /* class_finalize */
2641 NULL, /* class_data */
2643 0, /* n_preallocs */
2646 GType g_define_type_id =
2647 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2648 &desktop_app_info_lookup_info, 0);
2650 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2652 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2655 return g_define_type_id__volatile;
2659 g_desktop_app_info_lookup_class_init (gpointer g_class,
2660 gpointer class_data)
2665 g_desktop_app_info_lookup_base_init (gpointer g_class)
2670 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2671 * @lookup: a #GDesktopAppInfoLookup
2672 * @uri_scheme: a string containing a URI scheme.
2674 * Gets the default application for launching applications
2675 * using this URI scheme for a particular GDesktopAppInfoLookup
2678 * The GDesktopAppInfoLookup interface and this function is used
2679 * to implement g_app_info_get_default_for_uri_scheme() backends
2680 * in a GIO module. There is no reason for applications to use it
2681 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2683 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2686 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2687 const char *uri_scheme)
2689 GDesktopAppInfoLookupIface *iface;
2691 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2693 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2695 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2698 #define __G_DESKTOP_APP_INFO_C__
2699 #include "gioaliasdef.c"