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"
65 #define FULL_NAME_KEY "X-GNOME-FullName"
67 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
68 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
70 static void mime_info_cache_reload (const char *dir);
71 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
77 * Information about an installed application from a desktop file.
79 struct _GDesktopAppInfo
81 GObject parent_instance;
87 /* FIXME: what about GenericName ? */
102 guint startup_notify : 1;
104 /* FIXME: what about StartupWMClass ? */
107 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
108 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
109 g_desktop_app_info_iface_init))
112 search_path_init (gpointer data)
115 const char * const *data_dirs;
116 const char *user_data_dir;
119 data_dirs = g_get_system_data_dirs ();
120 length = g_strv_length ((char **) data_dirs);
122 args = g_new (char *, length + 2);
125 user_data_dir = g_get_user_data_dir ();
126 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
127 for (i = 0; i < length; i++)
128 args[j++] = g_build_filename (data_dirs[i],
129 "applications", NULL);
135 static const char * const *
136 get_applications_search_path (void)
138 static GOnce once_init = G_ONCE_INIT;
139 return g_once (&once_init, search_path_init, NULL);
143 g_desktop_app_info_finalize (GObject *object)
145 GDesktopAppInfo *info;
147 info = G_DESKTOP_APP_INFO (object);
149 g_free (info->desktop_id);
150 g_free (info->filename);
152 g_free (info->fullname);
153 g_free (info->comment);
154 g_free (info->icon_name);
156 g_object_unref (info->icon);
157 g_strfreev (info->only_show_in);
158 g_strfreev (info->not_show_in);
159 g_free (info->try_exec);
161 g_free (info->binary);
164 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
168 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
170 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
172 gobject_class->finalize = g_desktop_app_info_finalize;
176 g_desktop_app_info_init (GDesktopAppInfo *local)
181 binary_from_exec (const char *exec)
183 const char *p, *start;
189 while (*p != ' ' && *p != 0)
192 return g_strndup (start, p - start);
197 * g_desktop_app_info_new_from_keyfile:
198 * @key_file: an opened #GKeyFile
200 * Creates a new #GDesktopAppInfo.
202 * Returns: a new #GDesktopAppInfo or %NULL on error.
207 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
209 GDesktopAppInfo *info;
214 start_group = g_key_file_get_start_group (key_file);
215 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
217 g_free (start_group);
220 g_free (start_group);
222 type = g_key_file_get_string (key_file,
223 G_KEY_FILE_DESKTOP_GROUP,
224 G_KEY_FILE_DESKTOP_KEY_TYPE,
226 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
233 try_exec = g_key_file_get_string (key_file,
234 G_KEY_FILE_DESKTOP_GROUP,
235 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
237 if (try_exec && try_exec[0] != '\0')
240 t = g_find_program_in_path (try_exec);
249 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
250 info->filename = NULL;
252 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
253 info->fullname = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, FULL_NAME_KEY, NULL, NULL);
254 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
255 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
256 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
257 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);
258 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);
259 info->try_exec = try_exec;
260 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
261 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
262 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
263 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
264 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
265 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
270 if (g_path_is_absolute (info->icon_name))
274 file = g_file_new_for_path (info->icon_name);
275 info->icon = g_file_icon_new (file);
276 g_object_unref (file);
282 /* Work around a common mistake in desktop files */
283 if ((p = strrchr (info->icon_name, '.')) != NULL &&
284 (strcmp (p, ".png") == 0 ||
285 strcmp (p, ".xpm") == 0 ||
286 strcmp (p, ".svg") == 0))
289 info->icon = g_themed_icon_new (info->icon_name);
294 info->binary = binary_from_exec (info->exec);
296 if (info->path && info->path[0] == '\0')
306 * g_desktop_app_info_new_from_filename:
307 * @filename: the path of a desktop file, in the GLib filename encoding
309 * Creates a new #GDesktopAppInfo.
311 * Returns: a new #GDesktopAppInfo or %NULL on error.
314 g_desktop_app_info_new_from_filename (const char *filename)
317 GDesktopAppInfo *info = NULL;
319 key_file = g_key_file_new ();
321 if (g_key_file_load_from_file (key_file,
326 info = g_desktop_app_info_new_from_keyfile (key_file);
328 info->filename = g_strdup (filename);
331 g_key_file_free (key_file);
337 * g_desktop_app_info_new:
338 * @desktop_id: the desktop file id
340 * Creates a new #GDesktopAppInfo based on a desktop file id.
342 * A desktop file id is the basename of the desktop file, including the
343 * .desktop extension. GIO is looking for a desktop file with this name
344 * in the <filename>applications</filename> subdirectories of the XDG data
345 * directories (i.e. the directories specified in the
346 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
347 * variables). GIO also supports the prefix-to-subdirectory mapping that is
348 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
349 * (i.e. a desktop id of kde-foo.desktop will match
350 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
352 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
355 g_desktop_app_info_new (const char *desktop_id)
357 GDesktopAppInfo *appinfo;
358 const char * const *dirs;
362 dirs = get_applications_search_path ();
364 basename = g_strdup (desktop_id);
366 for (i = 0; dirs[i] != NULL; i++)
371 filename = g_build_filename (dirs[i], desktop_id, NULL);
372 appinfo = g_desktop_app_info_new_from_filename (filename);
378 while ((p = strchr (p, '-')) != NULL)
382 filename = g_build_filename (dirs[i], basename, NULL);
383 appinfo = g_desktop_app_info_new_from_filename (filename);
398 appinfo->desktop_id = g_strdup (desktop_id);
400 if (g_desktop_app_info_get_is_hidden (appinfo))
402 g_object_unref (appinfo);
410 g_desktop_app_info_dup (GAppInfo *appinfo)
412 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
413 GDesktopAppInfo *new_info;
415 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
417 new_info->filename = g_strdup (info->filename);
418 new_info->desktop_id = g_strdup (info->desktop_id);
420 new_info->name = g_strdup (info->name);
421 new_info->fullname = g_strdup (info->fullname);
422 new_info->comment = g_strdup (info->comment);
423 new_info->nodisplay = info->nodisplay;
424 new_info->icon_name = g_strdup (info->icon_name);
426 new_info->icon = g_object_ref (info->icon);
427 new_info->only_show_in = g_strdupv (info->only_show_in);
428 new_info->not_show_in = g_strdupv (info->not_show_in);
429 new_info->try_exec = g_strdup (info->try_exec);
430 new_info->exec = g_strdup (info->exec);
431 new_info->binary = g_strdup (info->binary);
432 new_info->path = g_strdup (info->path);
433 new_info->hidden = info->hidden;
434 new_info->terminal = info->terminal;
435 new_info->startup_notify = info->startup_notify;
437 return G_APP_INFO (new_info);
441 g_desktop_app_info_equal (GAppInfo *appinfo1,
444 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
445 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
447 if (info1->desktop_id == NULL ||
448 info2->desktop_id == NULL)
449 return info1 == info2;
451 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
455 g_desktop_app_info_get_id (GAppInfo *appinfo)
457 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
459 return info->desktop_id;
463 g_desktop_app_info_get_name (GAppInfo *appinfo)
465 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
467 if (info->name == NULL)
473 g_desktop_app_info_get_display_name (GAppInfo *appinfo)
475 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
477 if (info->fullname == NULL)
478 return g_desktop_app_info_get_name (appinfo);
479 return info->fullname;
483 * g_desktop_app_info_get_is_hidden:
484 * @info: a #GDesktopAppInfo.
486 * A desktop file is hidden if the Hidden key in it is
489 * Returns: %TRUE if hidden, %FALSE otherwise.
492 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
498 g_desktop_app_info_get_description (GAppInfo *appinfo)
500 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
502 return info->comment;
506 g_desktop_app_info_get_executable (GAppInfo *appinfo)
508 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
514 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
516 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
522 g_desktop_app_info_get_icon (GAppInfo *appinfo)
524 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
530 expand_macro_single (char macro, char *uri)
536 file = g_file_new_for_uri (uri);
537 path = g_file_get_path (file);
538 g_object_unref (file);
544 result = g_shell_quote (uri);
549 result = g_shell_quote (path);
555 name = g_path_get_dirname (path);
556 result = g_shell_quote (name);
564 name = g_path_get_basename (path);
565 result = g_shell_quote (name);
577 expand_macro (char macro,
579 GDesktopAppInfo *info,
582 GList *uris = *uri_list;
584 gboolean force_file_uri;
585 char force_file_uri_macro;
588 g_return_if_fail (exec != NULL);
590 /* On %u and %U, pass POSIX file path pointing to the URI via
591 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
592 * running or the URI doesn't have a POSIX file path via FUSE
593 * we'll just pass the URI.
595 force_file_uri_macro = macro;
596 force_file_uri = FALSE;
602 force_file_uri_macro = 'f';
603 force_file_uri = TRUE;
606 force_file_uri_macro = 'F';
607 force_file_uri = TRUE;
623 if (!force_file_uri ||
624 /* Pass URI if it contains an anchor */
625 strchr (uri, '#') != NULL)
627 expanded = expand_macro_single (macro, uri);
631 expanded = expand_macro_single (force_file_uri_macro, uri);
632 if (expanded == NULL)
633 expanded = expand_macro_single (macro, uri);
638 g_string_append (exec, expanded);
654 if (!force_file_uri ||
655 /* Pass URI if it contains an anchor */
656 strchr (uri, '#') != NULL)
658 expanded = expand_macro_single (macro, uri);
662 expanded = expand_macro_single (force_file_uri_macro, uri);
663 if (expanded == NULL)
664 expanded = expand_macro_single (macro, uri);
669 g_string_append (exec, expanded);
675 if (uris != NULL && expanded)
676 g_string_append_c (exec, ' ');
684 g_string_append (exec, "--icon ");
685 g_string_append (exec, info->icon_name);
691 g_string_append (exec, info->name);
696 g_string_append (exec, info->filename);
699 case 'm': /* deprecated */
703 g_string_append_c (exec, '%');
711 expand_application_parameters (GDesktopAppInfo *info,
717 GList *uri_list = *uris;
718 const char *p = info->exec;
719 GString *expanded_exec = g_string_new (NULL);
722 if (info->exec == NULL)
724 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
725 _("Desktop file didn't specify Exec field"));
731 if (p[0] == '%' && p[1] != '\0')
733 expand_macro (p[1], expanded_exec, info, uris);
737 g_string_append_c (expanded_exec, *p);
742 /* No file substitutions */
743 if (uri_list == *uris && uri_list != NULL)
745 /* If there is no macro default to %f. This is also what KDE does */
746 g_string_append_c (expanded_exec, ' ');
747 expand_macro ('f', expanded_exec, info, uris);
750 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
751 g_string_free (expanded_exec, TRUE);
756 prepend_terminal_to_vector (int *argc,
763 char **term_argv = NULL;
768 g_return_val_if_fail (argc != NULL, FALSE);
769 g_return_val_if_fail (argv != NULL, FALSE);
777 /* compute size if not given */
780 for (i = 0; the_argv[i] != NULL; i++)
786 term_argv = g_new0 (char *, 3);
788 check = g_find_program_in_path ("gnome-terminal");
791 term_argv[0] = check;
792 /* Note that gnome-terminal takes -x and
793 * as -e in gnome-terminal is broken we use that. */
794 term_argv[1] = g_strdup ("-x");
799 check = g_find_program_in_path ("nxterm");
801 check = g_find_program_in_path ("color-xterm");
803 check = g_find_program_in_path ("rxvt");
805 check = g_find_program_in_path ("xterm");
807 check = g_find_program_in_path ("dtterm");
810 check = g_strdup ("xterm");
811 g_warning ("couldn't find a terminal, falling back to xterm");
813 term_argv[0] = check;
814 term_argv[1] = g_strdup ("-e");
817 real_argc = term_argc + *argc;
818 real_argv = g_new (char *, real_argc + 1);
820 for (i = 0; i < term_argc; i++)
821 real_argv[i] = term_argv[i];
823 for (j = 0; j < *argc; j++, i++)
824 real_argv[i] = (char *)the_argv[j];
832 /* we use g_free here as we sucked all the inner strings
833 * out from it into real_argv */
838 #endif /* G_OS_WIN32 */
842 uri_list_segment_to_files (GList *start,
849 while (start != NULL && start != end)
851 file = g_file_new_for_uri ((char *)start->data);
852 res = g_list_prepend (res, file);
856 return g_list_reverse (res);
866 child_setup (gpointer user_data)
868 ChildSetupData *data = user_data;
871 g_setenv ("DISPLAY", data->display, TRUE);
874 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
878 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
880 GAppLaunchContext *launch_context,
883 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
884 gboolean completed = FALSE;
886 GList *launched_files;
891 g_return_val_if_fail (appinfo != NULL, FALSE);
898 if (!expand_application_parameters (info, &uris,
899 &argc, &argv, error))
902 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
904 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
905 _("Unable to find terminal required for application"));
914 launched_files = uri_list_segment_to_files (old_uris, uris);
916 data.display = g_app_launch_context_get_display (launch_context,
920 if (info->startup_notify)
921 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
924 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
925 g_list_free (launched_files);
928 if (!g_spawn_async (info->path,
938 g_app_launch_context_launch_failed (launch_context, data.sn_id);
941 g_free (data.display);
947 g_free (data.display);
952 while (uris != NULL);
963 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
965 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
968 ((strstr (info->exec, "%u") != NULL) ||
969 (strstr (info->exec, "%U") != NULL));
973 g_desktop_app_info_supports_files (GAppInfo *appinfo)
975 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
978 ((strstr (info->exec, "%f") != NULL) ||
979 (strstr (info->exec, "%F") != NULL));
983 g_desktop_app_info_launch (GAppInfo *appinfo,
985 GAppLaunchContext *launch_context,
995 uri = g_file_get_uri (files->data);
996 uris = g_list_prepend (uris, uri);
1000 uris = g_list_reverse (uris);
1002 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1004 g_list_foreach (uris, (GFunc)g_free, NULL);
1010 G_LOCK_DEFINE_STATIC (g_desktop_env);
1011 static gchar *g_desktop_env = NULL;
1014 * g_desktop_app_info_set_desktop_env:
1015 * @desktop_env: a string specifying what desktop this is
1017 * Sets the name of the desktop that the application is running in.
1018 * This is used by g_app_info_should_show() to evaluate the
1019 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1020 * desktop entry fields.
1022 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1023 * Menu specification</ulink> recognizes the following:
1025 * <member>GNOME</member>
1026 * <member>KDE</member>
1027 * <member>ROX</member>
1028 * <member>XFCE</member>
1029 * <member>Old</member>
1032 * Should be called only once; subsequent calls are ignored.
1035 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1037 G_LOCK (g_desktop_env);
1039 g_desktop_env = g_strdup (desktop_env);
1040 G_UNLOCK (g_desktop_env);
1044 g_desktop_app_info_should_show (GAppInfo *appinfo)
1046 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1048 const gchar *desktop_env;
1051 if (info->nodisplay)
1054 G_LOCK (g_desktop_env);
1055 desktop_env = g_desktop_env;
1056 G_UNLOCK (g_desktop_env);
1058 if (info->only_show_in)
1060 if (desktop_env == NULL)
1064 for (i = 0; info->only_show_in[i] != NULL; i++)
1066 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1076 if (info->not_show_in && desktop_env)
1078 for (i = 0; info->not_show_in[i] != NULL; i++)
1080 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1094 ensure_dir (DirType type,
1097 char *path, *display_name;
1100 if (type == APP_DIR)
1101 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1103 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1106 if (g_mkdir_with_parents (path, 0700) == 0)
1110 display_name = g_filename_display_name (path);
1111 if (type == APP_DIR)
1112 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1113 _("Can't create user application configuration folder %s: %s"),
1114 display_name, g_strerror (errsv));
1116 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1117 _("Can't create user MIME configuration folder %s: %s"),
1118 display_name, g_strerror (errsv));
1120 g_free (display_name);
1127 update_mimeapps_list (const char *desktop_id,
1128 const char *content_type,
1129 gboolean add_as_default,
1130 gboolean add_non_default,
1134 char *dirname, *filename;
1136 gboolean load_succeeded, res;
1137 char **old_list, **list;
1138 GList *system_list, *l;
1139 gsize length, data_size;
1142 char **content_types;
1144 /* Don't add both at start and end */
1145 g_assert (!(add_as_default && add_non_default));
1147 dirname = ensure_dir (APP_DIR, error);
1151 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1154 key_file = g_key_file_new ();
1155 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1156 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1158 g_key_file_free (key_file);
1159 key_file = g_key_file_new ();
1164 content_types = g_new (char *, 2);
1165 content_types[0] = g_strdup (content_type);
1166 content_types[1] = NULL;
1170 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1173 for (k = 0; content_types && content_types[k]; k++)
1175 /* Add to the right place in the list */
1178 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1179 content_types[k], &length, NULL);
1181 list = g_new (char *, 1 + length + 1);
1185 list[i++] = g_strdup (desktop_id);
1188 for (j = 0; old_list[j] != NULL; j++)
1190 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1191 list[i++] = g_strdup (old_list[j]);
1192 else if (add_non_default)
1194 /* If adding as non-default, and it's already in,
1195 don't change order of desktop ids */
1196 add_non_default = FALSE;
1197 list[i++] = g_strdup (old_list[j]);
1202 if (add_non_default)
1204 /* We're adding as non-default, and it wasn't already in the list,
1205 so we add at the end. But to avoid listing the app before the
1206 current system default (thus changing the default) we have to
1207 add the current list of (not yet listed) apps before it. */
1209 list[i] = NULL; /* Terminate current list so we can use it */
1210 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1212 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1214 for (l = system_list; l != NULL; l = l->next)
1216 list[i++] = l->data; /* no strdup, taking ownership */
1217 if (g_strcmp0 (l->data, desktop_id) == 0)
1218 add_non_default = FALSE;
1220 g_list_free (system_list);
1222 if (add_non_default)
1223 list[i++] = g_strdup (desktop_id);
1228 g_strfreev (old_list);
1230 if (list[0] == NULL || desktop_id == NULL)
1231 g_key_file_remove_key (key_file,
1232 ADDED_ASSOCIATIONS_GROUP,
1236 g_key_file_set_string_list (key_file,
1237 ADDED_ASSOCIATIONS_GROUP,
1239 (const char * const *)list, i);
1246 /* reuse the list from above */
1250 g_strfreev (content_types);
1251 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1254 for (k = 0; content_types && content_types[k]; k++)
1256 /* Remove from removed associations group (unless remove) */
1259 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1260 content_types[k], &length, NULL);
1262 list = g_new (char *, 1 + length + 1);
1266 list[i++] = g_strdup (desktop_id);
1269 for (j = 0; old_list[j] != NULL; j++)
1271 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1272 list[i++] = g_strdup (old_list[j]);
1277 g_strfreev (old_list);
1279 if (list[0] == NULL || desktop_id == NULL)
1280 g_key_file_remove_key (key_file,
1281 REMOVED_ASSOCIATIONS_GROUP,
1285 g_key_file_set_string_list (key_file,
1286 REMOVED_ASSOCIATIONS_GROUP,
1288 (const char * const *)list, i);
1293 g_strfreev (content_types);
1295 data = g_key_file_to_data (key_file, &data_size, error);
1296 g_key_file_free (key_file);
1298 res = g_file_set_contents (filename, data, data_size, error);
1300 mime_info_cache_reload (NULL);
1309 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1310 const char *content_type,
1313 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1315 if (!g_desktop_app_info_ensure_saved (info, error))
1318 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1322 update_program_done (GPid pid,
1326 /* Did the application exit correctly */
1327 if (WIFEXITED (status) &&
1328 WEXITSTATUS (status) == 0)
1330 /* Here we could clean out any caches in use */
1335 run_update_command (char *command,
1344 GError *error = NULL;
1347 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1349 if (g_spawn_async ("/", argv,
1351 G_SPAWN_SEARCH_PATH |
1352 G_SPAWN_STDOUT_TO_DEV_NULL |
1353 G_SPAWN_STDERR_TO_DEV_NULL |
1354 G_SPAWN_DO_NOT_REAP_CHILD,
1355 NULL, NULL, /* No setup function */
1358 g_child_watch_add (pid, update_program_done, NULL);
1361 /* If we get an error at this point, it's quite likely the user doesn't
1362 * have an installed copy of either 'update-mime-database' or
1363 * 'update-desktop-database'. I don't think we want to popup an error
1364 * dialog at this point, so we just do a g_warning to give the user a
1365 * chance of debugging it.
1367 g_warning ("%s", error->message);
1374 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1375 const char *extension,
1378 char *filename, *basename, *mimetype;
1382 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1385 dirname = ensure_dir (MIMETYPE_DIR, error);
1389 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1390 filename = g_build_filename (dirname, basename, NULL);
1394 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1396 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1401 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1402 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1403 " <mime-type type=\"%s\">\n"
1404 " <comment>%s document</comment>\n"
1405 " <glob pattern=\"*.%s\"/>\n"
1407 "</mime-info>\n", mimetype, extension, extension);
1409 g_file_set_contents (filename, contents, -1, NULL);
1412 run_update_command ("update-mime-database", "mime");
1416 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1426 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1427 const char *content_type,
1430 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1432 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1435 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1439 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1445 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1446 const char *content_type,
1449 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1451 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1454 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1458 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1464 char *data, *desktop_id;
1469 if (info->filename != NULL)
1472 /* This is only used for object created with
1473 * g_app_info_create_from_commandline. All other
1474 * object should have a filename
1477 dirname = ensure_dir (APP_DIR, error);
1481 key_file = g_key_file_new ();
1483 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1484 "Encoding", "UTF-8");
1485 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1486 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1487 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1488 G_KEY_FILE_DESKTOP_KEY_TYPE,
1489 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1491 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1492 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1494 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1495 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1497 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1498 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1500 if (info->fullname != NULL)
1501 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1502 FULL_NAME_KEY, info->fullname);
1504 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1505 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1507 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1508 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1510 data = g_key_file_to_data (key_file, &data_size, NULL);
1511 g_key_file_free (key_file);
1513 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1514 filename = g_build_filename (dirname, desktop_id, NULL);
1515 g_free (desktop_id);
1518 fd = g_mkstemp (filename);
1523 display_name = g_filename_display_name (filename);
1524 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1525 _("Can't create user desktop file %s"), display_name);
1526 g_free (display_name);
1532 desktop_id = g_path_get_basename (filename);
1536 res = g_file_set_contents (filename, data, data_size, error);
1539 g_free (desktop_id);
1544 info->filename = filename;
1545 info->desktop_id = desktop_id;
1547 run_update_command ("update-desktop-database", "applications");
1553 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1555 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1559 if (strstr (info->filename, "/userapp-"))
1560 return g_access (info->filename, W_OK) == 0;
1567 g_desktop_app_info_delete (GAppInfo *appinfo)
1569 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1573 if (g_remove (info->filename) == 0)
1575 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1577 g_free (info->filename);
1578 info->filename = NULL;
1579 g_free (info->desktop_id);
1580 info->desktop_id = NULL;
1590 * g_app_info_create_from_commandline:
1591 * @commandline: the commandline to use
1592 * @application_name: the application name, or %NULL to use @commandline
1593 * @flags: flags that can specify details of the created #GAppInfo
1594 * @error: a #GError location to store the error occuring, %NULL to ignore.
1596 * Creates a new #GAppInfo from the given information.
1598 * Returns: new #GAppInfo for given command.
1601 g_app_info_create_from_commandline (const char *commandline,
1602 const char *application_name,
1603 GAppInfoCreateFlags flags,
1608 GDesktopAppInfo *info;
1610 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1612 info->filename = NULL;
1613 info->desktop_id = NULL;
1615 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1616 info->startup_notify = FALSE;
1617 info->hidden = FALSE;
1618 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1619 info->exec = g_strconcat (commandline, " %u", NULL);
1621 info->exec = g_strconcat (commandline, " %f", NULL);
1622 info->nodisplay = TRUE;
1623 info->binary = binary_from_exec (info->exec);
1625 if (application_name)
1626 info->name = g_strdup (application_name);
1629 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1630 split = g_strsplit (commandline, " ", 2);
1631 basename = g_path_get_basename (split[0]);
1633 info->name = basename;
1634 if (info->name == NULL)
1635 info->name = g_strdup ("custom");
1637 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1639 return G_APP_INFO (info);
1643 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1645 iface->dup = g_desktop_app_info_dup;
1646 iface->equal = g_desktop_app_info_equal;
1647 iface->get_id = g_desktop_app_info_get_id;
1648 iface->get_name = g_desktop_app_info_get_name;
1649 iface->get_description = g_desktop_app_info_get_description;
1650 iface->get_executable = g_desktop_app_info_get_executable;
1651 iface->get_icon = g_desktop_app_info_get_icon;
1652 iface->launch = g_desktop_app_info_launch;
1653 iface->supports_uris = g_desktop_app_info_supports_uris;
1654 iface->supports_files = g_desktop_app_info_supports_files;
1655 iface->launch_uris = g_desktop_app_info_launch_uris;
1656 iface->should_show = g_desktop_app_info_should_show;
1657 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1658 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1659 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1660 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1661 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1662 iface->can_delete = g_desktop_app_info_can_delete;
1663 iface->do_delete = g_desktop_app_info_delete;
1664 iface->get_commandline = g_desktop_app_info_get_commandline;
1665 iface->get_display_name = g_desktop_app_info_get_display_name;
1669 app_info_in_list (GAppInfo *info,
1672 while (list != NULL)
1674 if (g_app_info_equal (info, list->data))
1683 * g_app_info_get_all_for_type:
1684 * @content_type: the content type to find a #GAppInfo for
1686 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1688 * Returns: #GList of #GAppInfo<!-- -->s for given @content_type
1689 * or %NULL on error.
1692 g_app_info_get_all_for_type (const char *content_type)
1694 GList *desktop_entries, *l;
1696 GDesktopAppInfo *info;
1698 g_return_val_if_fail (content_type != NULL, NULL);
1700 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1703 for (l = desktop_entries; l != NULL; l = l->next)
1705 char *desktop_entry = l->data;
1707 info = g_desktop_app_info_new (desktop_entry);
1710 if (app_info_in_list (G_APP_INFO (info), infos))
1711 g_object_unref (info);
1713 infos = g_list_prepend (infos, info);
1715 g_free (desktop_entry);
1718 g_list_free (desktop_entries);
1720 return g_list_reverse (infos);
1724 * g_app_info_reset_type_associations:
1725 * @content_type: a content type
1727 * Removes all changes to the type associations done by
1728 * g_app_info_set_as_default_for_type(),
1729 * g_app_info_set_as_default_for_extension(),
1730 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1735 g_app_info_reset_type_associations (const char *content_type)
1737 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1741 * g_app_info_get_default_for_type:
1742 * @content_type: the content type to find a #GAppInfo for
1743 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1746 * Gets the #GAppInfo that corresponds to a given content type.
1748 * Returns: #GAppInfo for given @content_type or %NULL on error.
1751 g_app_info_get_default_for_type (const char *content_type,
1752 gboolean must_support_uris)
1754 GList *desktop_entries, *l;
1757 g_return_val_if_fail (content_type != NULL, NULL);
1759 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1762 for (l = desktop_entries; l != NULL; l = l->next)
1764 char *desktop_entry = l->data;
1766 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1769 if (must_support_uris && !g_app_info_supports_uris (info))
1771 g_object_unref (info);
1779 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1780 g_list_free (desktop_entries);
1786 * g_app_info_get_default_for_uri_scheme:
1787 * @uri_scheme: a string containing a URI scheme.
1789 * Gets the default application for launching applications
1790 * using this URI scheme. A URI scheme is the initial part
1791 * of the URI, up to but not including the ':', e.g. "http",
1794 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1797 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1799 static gsize lookup = 0;
1801 if (g_once_init_enter (&lookup))
1803 gsize setup_value = 1;
1804 GDesktopAppInfoLookup *lookup_instance;
1805 const char *use_this;
1806 GIOExtensionPoint *ep;
1807 GIOExtension *extension;
1810 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1812 /* Ensure vfs in modules loaded */
1813 _g_io_modules_ensure_loaded ();
1815 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1817 lookup_instance = NULL;
1820 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1822 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1825 if (lookup_instance == NULL)
1827 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1829 extension = l->data;
1830 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1831 if (lookup_instance != NULL)
1836 if (lookup_instance != NULL)
1837 setup_value = (gsize)lookup_instance;
1839 g_once_init_leave (&lookup, setup_value);
1845 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1851 get_apps_from_dir (GHashTable *apps,
1852 const char *dirname,
1856 const char *basename;
1857 char *filename, *subprefix, *desktop_id;
1859 GDesktopAppInfo *appinfo;
1861 dir = g_dir_open (dirname, 0, NULL);
1864 while ((basename = g_dir_read_name (dir)) != NULL)
1866 filename = g_build_filename (dirname, basename, NULL);
1867 if (g_str_has_suffix (basename, ".desktop"))
1869 desktop_id = g_strconcat (prefix, basename, NULL);
1871 /* Use _extended so we catch NULLs too (hidden) */
1872 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1874 appinfo = g_desktop_app_info_new_from_filename (filename);
1877 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1879 g_object_unref (appinfo);
1884 if (appinfo || hidden)
1886 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1890 /* Reuse instead of strdup here */
1891 appinfo->desktop_id = desktop_id;
1896 g_free (desktop_id);
1900 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1902 subprefix = g_strconcat (prefix, basename, "-", NULL);
1903 get_apps_from_dir (apps, filename, subprefix);
1915 * g_app_info_get_all:
1917 * Gets a list of all of the applications currently registered
1920 * For desktop files, this includes applications that have
1921 * <literal>NoDisplay=true</literal> set or are excluded from
1922 * display by means of <literal>OnlyShowIn</literal> or
1923 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1924 * The returned list does not include applications which have
1925 * the <literal>Hidden</literal> key set.
1927 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1930 g_app_info_get_all (void)
1932 const char * const *dirs;
1934 GHashTableIter iter;
1939 dirs = get_applications_search_path ();
1941 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1945 for (i = 0; dirs[i] != NULL; i++)
1946 get_apps_from_dir (apps, dirs[i], "");
1950 g_hash_table_iter_init (&iter, apps);
1951 while (g_hash_table_iter_next (&iter, NULL, &value))
1954 infos = g_list_prepend (infos, value);
1957 g_hash_table_destroy (apps);
1959 return g_list_reverse (infos);
1962 /* Cacheing of mimeinfo.cache and defaults.list files */
1966 GHashTable *mime_info_cache_map;
1967 GHashTable *defaults_list_map;
1968 GHashTable *mimeapps_list_added_map;
1969 GHashTable *mimeapps_list_removed_map;
1970 time_t mime_info_cache_timestamp;
1971 time_t defaults_list_timestamp;
1972 time_t mimeapps_list_timestamp;
1976 GList *dirs; /* mimeinfo.cache and defaults.list */
1977 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1978 time_t last_stat_time;
1979 guint should_ping_mime_monitor : 1;
1982 static MimeInfoCache *mime_info_cache = NULL;
1983 G_LOCK_DEFINE_STATIC (mime_info_cache);
1985 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
1986 const char *mime_type,
1987 char **new_desktop_file_ids);
1989 static MimeInfoCache * mime_info_cache_new (void);
1992 destroy_info_cache_value (gpointer key,
1996 g_list_foreach (value, (GFunc)g_free, NULL);
1997 g_list_free (value);
2001 destroy_info_cache_map (GHashTable *info_cache_map)
2003 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2004 g_hash_table_destroy (info_cache_map);
2008 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2009 const char *cache_file,
2015 filename = g_build_filename (dir->path, cache_file, NULL);
2017 if (g_stat (filename, &buf) < 0)
2024 if (buf.st_mtime != *timestamp)
2030 /* Call with lock held */
2032 remove_all (gpointer key,
2041 mime_info_cache_blow_global_cache (void)
2043 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2048 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2052 gchar *filename, **mime_types;
2059 if (dir->mime_info_cache_map != NULL &&
2060 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2061 &dir->mime_info_cache_timestamp))
2064 if (dir->mime_info_cache_map != NULL)
2065 destroy_info_cache_map (dir->mime_info_cache_map);
2067 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2068 (GDestroyNotify) g_free,
2071 key_file = g_key_file_new ();
2073 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2075 if (g_stat (filename, &buf) < 0)
2078 if (dir->mime_info_cache_timestamp > 0)
2079 mime_info_cache->should_ping_mime_monitor = TRUE;
2081 dir->mime_info_cache_timestamp = buf.st_mtime;
2083 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2088 if (load_error != NULL)
2091 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2094 if (load_error != NULL)
2097 for (i = 0; mime_types[i] != NULL; i++)
2099 gchar **desktop_file_ids;
2100 char *unaliased_type;
2101 desktop_file_ids = g_key_file_get_string_list (key_file,
2107 if (desktop_file_ids == NULL)
2110 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2111 mime_info_cache_dir_add_desktop_entries (dir,
2114 g_free (unaliased_type);
2116 g_strfreev (desktop_file_ids);
2119 g_strfreev (mime_types);
2120 g_key_file_free (key_file);
2125 g_key_file_free (key_file);
2127 if (mime_types != NULL)
2128 g_strfreev (mime_types);
2131 g_error_free (load_error);
2135 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2139 gchar *filename, **mime_types;
2140 char *unaliased_type;
2141 char **desktop_file_ids;
2148 if (dir->defaults_list_map != NULL &&
2149 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2150 &dir->defaults_list_timestamp))
2153 if (dir->defaults_list_map != NULL)
2154 g_hash_table_destroy (dir->defaults_list_map);
2155 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2156 g_free, (GDestroyNotify)g_strfreev);
2159 key_file = g_key_file_new ();
2161 filename = g_build_filename (dir->path, "defaults.list", NULL);
2162 if (g_stat (filename, &buf) < 0)
2165 if (dir->defaults_list_timestamp > 0)
2166 mime_info_cache->should_ping_mime_monitor = TRUE;
2168 dir->defaults_list_timestamp = buf.st_mtime;
2170 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2174 if (load_error != NULL)
2177 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2179 if (mime_types != NULL)
2181 for (i = 0; mime_types[i] != NULL; i++)
2183 desktop_file_ids = g_key_file_get_string_list (key_file,
2184 DEFAULT_APPLICATIONS_GROUP,
2188 if (desktop_file_ids == NULL)
2191 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2192 g_hash_table_replace (dir->defaults_list_map,
2197 g_strfreev (mime_types);
2200 g_key_file_free (key_file);
2205 g_key_file_free (key_file);
2207 if (mime_types != NULL)
2208 g_strfreev (mime_types);
2211 g_error_free (load_error);
2215 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2219 gchar *filename, **mime_types;
2220 char *unaliased_type;
2221 char **desktop_file_ids;
2228 if (dir->mimeapps_list_added_map != NULL &&
2229 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2230 &dir->mimeapps_list_timestamp))
2233 if (dir->mimeapps_list_added_map != NULL)
2234 g_hash_table_destroy (dir->mimeapps_list_added_map);
2235 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2236 g_free, (GDestroyNotify)g_strfreev);
2238 if (dir->mimeapps_list_removed_map != NULL)
2239 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2240 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2241 g_free, (GDestroyNotify)g_strfreev);
2243 key_file = g_key_file_new ();
2245 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2246 if (g_stat (filename, &buf) < 0)
2249 if (dir->mimeapps_list_timestamp > 0)
2250 mime_info_cache->should_ping_mime_monitor = TRUE;
2252 dir->mimeapps_list_timestamp = buf.st_mtime;
2254 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2258 if (load_error != NULL)
2261 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2263 if (mime_types != NULL)
2265 for (i = 0; mime_types[i] != NULL; i++)
2267 desktop_file_ids = g_key_file_get_string_list (key_file,
2268 ADDED_ASSOCIATIONS_GROUP,
2272 if (desktop_file_ids == NULL)
2275 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2276 g_hash_table_replace (dir->mimeapps_list_added_map,
2281 g_strfreev (mime_types);
2284 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2286 if (mime_types != NULL)
2288 for (i = 0; mime_types[i] != NULL; i++)
2290 desktop_file_ids = g_key_file_get_string_list (key_file,
2291 REMOVED_ASSOCIATIONS_GROUP,
2295 if (desktop_file_ids == NULL)
2298 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2299 g_hash_table_replace (dir->mimeapps_list_removed_map,
2304 g_strfreev (mime_types);
2307 g_key_file_free (key_file);
2312 g_key_file_free (key_file);
2314 if (mime_types != NULL)
2315 g_strfreev (mime_types);
2318 g_error_free (load_error);
2321 static MimeInfoCacheDir *
2322 mime_info_cache_dir_new (const char *path)
2324 MimeInfoCacheDir *dir;
2326 dir = g_new0 (MimeInfoCacheDir, 1);
2327 dir->path = g_strdup (path);
2333 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2338 if (dir->mime_info_cache_map != NULL)
2340 destroy_info_cache_map (dir->mime_info_cache_map);
2341 dir->mime_info_cache_map = NULL;
2345 if (dir->defaults_list_map != NULL)
2347 g_hash_table_destroy (dir->defaults_list_map);
2348 dir->defaults_list_map = NULL;
2351 if (dir->mimeapps_list_added_map != NULL)
2353 g_hash_table_destroy (dir->mimeapps_list_added_map);
2354 dir->mimeapps_list_added_map = NULL;
2357 if (dir->mimeapps_list_removed_map != NULL)
2359 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2360 dir->mimeapps_list_removed_map = NULL;
2367 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2368 const char *mime_type,
2369 char **new_desktop_file_ids)
2371 GList *desktop_file_ids;
2374 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2377 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2379 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2380 desktop_file_ids = g_list_append (desktop_file_ids,
2381 g_strdup (new_desktop_file_ids[i]));
2384 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2388 mime_info_cache_init_dir_lists (void)
2390 const char * const *dirs;
2393 mime_info_cache = mime_info_cache_new ();
2395 dirs = get_applications_search_path ();
2397 for (i = 0; dirs[i] != NULL; i++)
2399 MimeInfoCacheDir *dir;
2401 dir = mime_info_cache_dir_new (dirs[i]);
2405 mime_info_cache_dir_init (dir);
2406 mime_info_cache_dir_init_defaults_list (dir);
2407 mime_info_cache_dir_init_mimeapps_list (dir);
2409 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2415 mime_info_cache_update_dir_lists (void)
2419 tmp = mime_info_cache->dirs;
2423 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2425 /* No need to do this if we had file monitors... */
2426 mime_info_cache_blow_global_cache ();
2427 mime_info_cache_dir_init (dir);
2428 mime_info_cache_dir_init_defaults_list (dir);
2429 mime_info_cache_dir_init_mimeapps_list (dir);
2436 mime_info_cache_init (void)
2438 G_LOCK (mime_info_cache);
2439 if (mime_info_cache == NULL)
2440 mime_info_cache_init_dir_lists ();
2446 if (now >= mime_info_cache->last_stat_time + 10)
2448 mime_info_cache_update_dir_lists ();
2449 mime_info_cache->last_stat_time = now;
2453 if (mime_info_cache->should_ping_mime_monitor)
2455 /* g_idle_add (emit_mime_changed, NULL); */
2456 mime_info_cache->should_ping_mime_monitor = FALSE;
2459 G_UNLOCK (mime_info_cache);
2462 static MimeInfoCache *
2463 mime_info_cache_new (void)
2465 MimeInfoCache *cache;
2467 cache = g_new0 (MimeInfoCache, 1);
2469 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2470 (GDestroyNotify) g_free,
2471 (GDestroyNotify) g_free);
2476 mime_info_cache_free (MimeInfoCache *cache)
2481 g_list_foreach (cache->dirs,
2482 (GFunc) mime_info_cache_dir_free,
2484 g_list_free (cache->dirs);
2485 g_hash_table_destroy (cache->global_defaults_cache);
2490 * mime_info_cache_reload:
2491 * @dir: directory path which needs reloading.
2493 * Reload the mime information for the @dir.
2496 mime_info_cache_reload (const char *dir)
2498 /* FIXME: just reload the dir that needs reloading,
2499 * don't blow the whole cache
2501 if (mime_info_cache != NULL)
2503 G_LOCK (mime_info_cache);
2504 mime_info_cache_free (mime_info_cache);
2505 mime_info_cache = NULL;
2506 G_UNLOCK (mime_info_cache);
2511 append_desktop_entry (GList *list,
2512 const char *desktop_entry,
2513 GList *removed_entries)
2515 /* Add if not already in list, and valid */
2516 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2517 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2518 list = g_list_prepend (list, g_strdup (desktop_entry));
2524 * get_all_desktop_entries_for_mime_type:
2525 * @mime_type: a mime type.
2526 * @except: NULL or a strv list
2528 * Returns all the desktop ids for @mime_type. The desktop files
2529 * are listed in an order so that default applications are listed before
2530 * non-default ones, and handlers for inherited mimetypes are listed
2531 * after the base ones.
2533 * Optionally doesn't list the desktop ids given in the @except
2535 * Return value: a #GList containing the desktop ids which claim
2536 * to handle @mime_type.
2539 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2540 const char **except)
2542 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2543 MimeInfoCacheDir *dir;
2546 char **default_entries;
2547 char **removed_associations;
2552 mime_info_cache_init ();
2554 /* collect all ancestors */
2555 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2556 array = g_ptr_array_new ();
2557 for (i = 0; mime_types[i]; i++)
2558 g_ptr_array_add (array, mime_types[i]);
2559 g_free (mime_types);
2560 for (i = 0; i < array->len; i++)
2562 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2563 for (j = 0; anc[j]; j++)
2565 for (k = 0; k < array->len; k++)
2567 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2570 if (k == array->len) /* not found */
2571 g_ptr_array_add (array, g_strdup (anc[j]));
2575 g_ptr_array_add (array, NULL);
2576 mime_types = (char **)g_ptr_array_free (array, FALSE);
2578 G_LOCK (mime_info_cache);
2580 removed_entries = NULL;
2581 desktop_entries = NULL;
2583 for (i = 0; except != NULL && except[i] != NULL; i++)
2584 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2586 for (i = 0; mime_types[i] != NULL; i++)
2588 mime_type = mime_types[i];
2590 /* Go through all apps listed as defaults */
2591 for (dir_list = mime_info_cache->dirs;
2593 dir_list = dir_list->next)
2595 dir = dir_list->data;
2597 /* First added associations from mimeapps.list */
2598 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2599 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2600 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2602 /* Then removed associations from mimeapps.list */
2603 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2604 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2605 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2607 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2608 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2609 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2610 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2613 /* Go through all entries that support the mimetype */
2614 for (dir_list = mime_info_cache->dirs;
2616 dir_list = dir_list->next)
2618 dir = dir_list->data;
2620 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2621 for (tmp = list; tmp != NULL; tmp = tmp->next)
2622 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2626 G_UNLOCK (mime_info_cache);
2628 g_strfreev (mime_types);
2630 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2631 g_list_free (removed_entries);
2633 desktop_entries = g_list_reverse (desktop_entries);
2635 return desktop_entries;
2638 /* GDesktopAppInfoLookup interface: */
2640 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2641 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2642 gpointer class_data);
2645 g_desktop_app_info_lookup_get_type (void)
2647 static volatile gsize g_define_type_id__volatile = 0;
2649 if (g_once_init_enter (&g_define_type_id__volatile))
2651 const GTypeInfo desktop_app_info_lookup_info =
2653 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2654 g_desktop_app_info_lookup_base_init, /* base_init */
2655 NULL, /* base_finalize */
2656 g_desktop_app_info_lookup_class_init,
2657 NULL, /* class_finalize */
2658 NULL, /* class_data */
2660 0, /* n_preallocs */
2663 GType g_define_type_id =
2664 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2665 &desktop_app_info_lookup_info, 0);
2667 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2669 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2672 return g_define_type_id__volatile;
2676 g_desktop_app_info_lookup_class_init (gpointer g_class,
2677 gpointer class_data)
2682 g_desktop_app_info_lookup_base_init (gpointer g_class)
2687 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2688 * @lookup: a #GDesktopAppInfoLookup
2689 * @uri_scheme: a string containing a URI scheme.
2691 * Gets the default application for launching applications
2692 * using this URI scheme for a particular GDesktopAppInfoLookup
2695 * The GDesktopAppInfoLookup interface and this function is used
2696 * to implement g_app_info_get_default_for_uri_scheme() backends
2697 * in a GIO module. There is no reason for applications to use it
2698 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2700 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2703 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2704 const char *uri_scheme)
2706 GDesktopAppInfoLookupIface *iface;
2708 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2710 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2712 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2715 #define __G_DESKTOP_APP_INFO_C__
2716 #include "gioaliasdef.c"