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 g_return_val_if_fail (commandline, NULL);
1612 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1614 info->filename = NULL;
1615 info->desktop_id = NULL;
1617 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1618 info->startup_notify = FALSE;
1619 info->hidden = FALSE;
1620 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1621 info->exec = g_strconcat (commandline, " %u", NULL);
1623 info->exec = g_strconcat (commandline, " %f", NULL);
1624 info->nodisplay = TRUE;
1625 info->binary = binary_from_exec (info->exec);
1627 if (application_name)
1628 info->name = g_strdup (application_name);
1631 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1632 split = g_strsplit (commandline, " ", 2);
1633 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1635 info->name = basename;
1636 if (info->name == NULL)
1637 info->name = g_strdup ("custom");
1639 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1641 return G_APP_INFO (info);
1645 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1647 iface->dup = g_desktop_app_info_dup;
1648 iface->equal = g_desktop_app_info_equal;
1649 iface->get_id = g_desktop_app_info_get_id;
1650 iface->get_name = g_desktop_app_info_get_name;
1651 iface->get_description = g_desktop_app_info_get_description;
1652 iface->get_executable = g_desktop_app_info_get_executable;
1653 iface->get_icon = g_desktop_app_info_get_icon;
1654 iface->launch = g_desktop_app_info_launch;
1655 iface->supports_uris = g_desktop_app_info_supports_uris;
1656 iface->supports_files = g_desktop_app_info_supports_files;
1657 iface->launch_uris = g_desktop_app_info_launch_uris;
1658 iface->should_show = g_desktop_app_info_should_show;
1659 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1660 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1661 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1662 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1663 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1664 iface->can_delete = g_desktop_app_info_can_delete;
1665 iface->do_delete = g_desktop_app_info_delete;
1666 iface->get_commandline = g_desktop_app_info_get_commandline;
1667 iface->get_display_name = g_desktop_app_info_get_display_name;
1671 app_info_in_list (GAppInfo *info,
1674 while (list != NULL)
1676 if (g_app_info_equal (info, list->data))
1685 * g_app_info_get_all_for_type:
1686 * @content_type: the content type to find a #GAppInfo for
1688 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1690 * Returns: #GList of #GAppInfo<!-- -->s for given @content_type
1691 * or %NULL on error.
1694 g_app_info_get_all_for_type (const char *content_type)
1696 GList *desktop_entries, *l;
1698 GDesktopAppInfo *info;
1700 g_return_val_if_fail (content_type != NULL, NULL);
1702 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1705 for (l = desktop_entries; l != NULL; l = l->next)
1707 char *desktop_entry = l->data;
1709 info = g_desktop_app_info_new (desktop_entry);
1712 if (app_info_in_list (G_APP_INFO (info), infos))
1713 g_object_unref (info);
1715 infos = g_list_prepend (infos, info);
1717 g_free (desktop_entry);
1720 g_list_free (desktop_entries);
1722 return g_list_reverse (infos);
1726 * g_app_info_reset_type_associations:
1727 * @content_type: a content type
1729 * Removes all changes to the type associations done by
1730 * g_app_info_set_as_default_for_type(),
1731 * g_app_info_set_as_default_for_extension(),
1732 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1737 g_app_info_reset_type_associations (const char *content_type)
1739 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1743 * g_app_info_get_default_for_type:
1744 * @content_type: the content type to find a #GAppInfo for
1745 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1748 * Gets the #GAppInfo that corresponds to a given content type.
1750 * Returns: #GAppInfo for given @content_type or %NULL on error.
1753 g_app_info_get_default_for_type (const char *content_type,
1754 gboolean must_support_uris)
1756 GList *desktop_entries, *l;
1759 g_return_val_if_fail (content_type != NULL, NULL);
1761 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1764 for (l = desktop_entries; l != NULL; l = l->next)
1766 char *desktop_entry = l->data;
1768 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1771 if (must_support_uris && !g_app_info_supports_uris (info))
1773 g_object_unref (info);
1781 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1782 g_list_free (desktop_entries);
1788 * g_app_info_get_default_for_uri_scheme:
1789 * @uri_scheme: a string containing a URI scheme.
1791 * Gets the default application for launching applications
1792 * using this URI scheme. A URI scheme is the initial part
1793 * of the URI, up to but not including the ':', e.g. "http",
1796 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1799 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1801 static gsize lookup = 0;
1803 if (g_once_init_enter (&lookup))
1805 gsize setup_value = 1;
1806 GDesktopAppInfoLookup *lookup_instance;
1807 const char *use_this;
1808 GIOExtensionPoint *ep;
1809 GIOExtension *extension;
1812 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1814 /* Ensure vfs in modules loaded */
1815 _g_io_modules_ensure_loaded ();
1817 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1819 lookup_instance = NULL;
1822 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1824 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1827 if (lookup_instance == NULL)
1829 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1831 extension = l->data;
1832 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1833 if (lookup_instance != NULL)
1838 if (lookup_instance != NULL)
1839 setup_value = (gsize)lookup_instance;
1841 g_once_init_leave (&lookup, setup_value);
1847 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1853 get_apps_from_dir (GHashTable *apps,
1854 const char *dirname,
1858 const char *basename;
1859 char *filename, *subprefix, *desktop_id;
1861 GDesktopAppInfo *appinfo;
1863 dir = g_dir_open (dirname, 0, NULL);
1866 while ((basename = g_dir_read_name (dir)) != NULL)
1868 filename = g_build_filename (dirname, basename, NULL);
1869 if (g_str_has_suffix (basename, ".desktop"))
1871 desktop_id = g_strconcat (prefix, basename, NULL);
1873 /* Use _extended so we catch NULLs too (hidden) */
1874 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1876 appinfo = g_desktop_app_info_new_from_filename (filename);
1879 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1881 g_object_unref (appinfo);
1886 if (appinfo || hidden)
1888 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1892 /* Reuse instead of strdup here */
1893 appinfo->desktop_id = desktop_id;
1898 g_free (desktop_id);
1902 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1904 subprefix = g_strconcat (prefix, basename, "-", NULL);
1905 get_apps_from_dir (apps, filename, subprefix);
1917 * g_app_info_get_all:
1919 * Gets a list of all of the applications currently registered
1922 * For desktop files, this includes applications that have
1923 * <literal>NoDisplay=true</literal> set or are excluded from
1924 * display by means of <literal>OnlyShowIn</literal> or
1925 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1926 * The returned list does not include applications which have
1927 * the <literal>Hidden</literal> key set.
1929 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1932 g_app_info_get_all (void)
1934 const char * const *dirs;
1936 GHashTableIter iter;
1941 dirs = get_applications_search_path ();
1943 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1947 for (i = 0; dirs[i] != NULL; i++)
1948 get_apps_from_dir (apps, dirs[i], "");
1952 g_hash_table_iter_init (&iter, apps);
1953 while (g_hash_table_iter_next (&iter, NULL, &value))
1956 infos = g_list_prepend (infos, value);
1959 g_hash_table_destroy (apps);
1961 return g_list_reverse (infos);
1964 /* Cacheing of mimeinfo.cache and defaults.list files */
1968 GHashTable *mime_info_cache_map;
1969 GHashTable *defaults_list_map;
1970 GHashTable *mimeapps_list_added_map;
1971 GHashTable *mimeapps_list_removed_map;
1972 time_t mime_info_cache_timestamp;
1973 time_t defaults_list_timestamp;
1974 time_t mimeapps_list_timestamp;
1978 GList *dirs; /* mimeinfo.cache and defaults.list */
1979 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1980 time_t last_stat_time;
1981 guint should_ping_mime_monitor : 1;
1984 static MimeInfoCache *mime_info_cache = NULL;
1985 G_LOCK_DEFINE_STATIC (mime_info_cache);
1987 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
1988 const char *mime_type,
1989 char **new_desktop_file_ids);
1991 static MimeInfoCache * mime_info_cache_new (void);
1994 destroy_info_cache_value (gpointer key,
1998 g_list_foreach (value, (GFunc)g_free, NULL);
1999 g_list_free (value);
2003 destroy_info_cache_map (GHashTable *info_cache_map)
2005 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2006 g_hash_table_destroy (info_cache_map);
2010 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2011 const char *cache_file,
2017 filename = g_build_filename (dir->path, cache_file, NULL);
2019 if (g_stat (filename, &buf) < 0)
2026 if (buf.st_mtime != *timestamp)
2032 /* Call with lock held */
2034 remove_all (gpointer key,
2043 mime_info_cache_blow_global_cache (void)
2045 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2050 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2054 gchar *filename, **mime_types;
2061 if (dir->mime_info_cache_map != NULL &&
2062 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2063 &dir->mime_info_cache_timestamp))
2066 if (dir->mime_info_cache_map != NULL)
2067 destroy_info_cache_map (dir->mime_info_cache_map);
2069 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2070 (GDestroyNotify) g_free,
2073 key_file = g_key_file_new ();
2075 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2077 if (g_stat (filename, &buf) < 0)
2080 if (dir->mime_info_cache_timestamp > 0)
2081 mime_info_cache->should_ping_mime_monitor = TRUE;
2083 dir->mime_info_cache_timestamp = buf.st_mtime;
2085 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2090 if (load_error != NULL)
2093 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2096 if (load_error != NULL)
2099 for (i = 0; mime_types[i] != NULL; i++)
2101 gchar **desktop_file_ids;
2102 char *unaliased_type;
2103 desktop_file_ids = g_key_file_get_string_list (key_file,
2109 if (desktop_file_ids == NULL)
2112 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2113 mime_info_cache_dir_add_desktop_entries (dir,
2116 g_free (unaliased_type);
2118 g_strfreev (desktop_file_ids);
2121 g_strfreev (mime_types);
2122 g_key_file_free (key_file);
2127 g_key_file_free (key_file);
2129 if (mime_types != NULL)
2130 g_strfreev (mime_types);
2133 g_error_free (load_error);
2137 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2141 gchar *filename, **mime_types;
2142 char *unaliased_type;
2143 char **desktop_file_ids;
2150 if (dir->defaults_list_map != NULL &&
2151 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2152 &dir->defaults_list_timestamp))
2155 if (dir->defaults_list_map != NULL)
2156 g_hash_table_destroy (dir->defaults_list_map);
2157 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2158 g_free, (GDestroyNotify)g_strfreev);
2161 key_file = g_key_file_new ();
2163 filename = g_build_filename (dir->path, "defaults.list", NULL);
2164 if (g_stat (filename, &buf) < 0)
2167 if (dir->defaults_list_timestamp > 0)
2168 mime_info_cache->should_ping_mime_monitor = TRUE;
2170 dir->defaults_list_timestamp = buf.st_mtime;
2172 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2176 if (load_error != NULL)
2179 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2181 if (mime_types != NULL)
2183 for (i = 0; mime_types[i] != NULL; i++)
2185 desktop_file_ids = g_key_file_get_string_list (key_file,
2186 DEFAULT_APPLICATIONS_GROUP,
2190 if (desktop_file_ids == NULL)
2193 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2194 g_hash_table_replace (dir->defaults_list_map,
2199 g_strfreev (mime_types);
2202 g_key_file_free (key_file);
2207 g_key_file_free (key_file);
2209 if (mime_types != NULL)
2210 g_strfreev (mime_types);
2213 g_error_free (load_error);
2217 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2221 gchar *filename, **mime_types;
2222 char *unaliased_type;
2223 char **desktop_file_ids;
2230 if (dir->mimeapps_list_added_map != NULL &&
2231 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2232 &dir->mimeapps_list_timestamp))
2235 if (dir->mimeapps_list_added_map != NULL)
2236 g_hash_table_destroy (dir->mimeapps_list_added_map);
2237 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2238 g_free, (GDestroyNotify)g_strfreev);
2240 if (dir->mimeapps_list_removed_map != NULL)
2241 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2242 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2243 g_free, (GDestroyNotify)g_strfreev);
2245 key_file = g_key_file_new ();
2247 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2248 if (g_stat (filename, &buf) < 0)
2251 if (dir->mimeapps_list_timestamp > 0)
2252 mime_info_cache->should_ping_mime_monitor = TRUE;
2254 dir->mimeapps_list_timestamp = buf.st_mtime;
2256 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2260 if (load_error != NULL)
2263 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2265 if (mime_types != NULL)
2267 for (i = 0; mime_types[i] != NULL; i++)
2269 desktop_file_ids = g_key_file_get_string_list (key_file,
2270 ADDED_ASSOCIATIONS_GROUP,
2274 if (desktop_file_ids == NULL)
2277 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2278 g_hash_table_replace (dir->mimeapps_list_added_map,
2283 g_strfreev (mime_types);
2286 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2288 if (mime_types != NULL)
2290 for (i = 0; mime_types[i] != NULL; i++)
2292 desktop_file_ids = g_key_file_get_string_list (key_file,
2293 REMOVED_ASSOCIATIONS_GROUP,
2297 if (desktop_file_ids == NULL)
2300 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2301 g_hash_table_replace (dir->mimeapps_list_removed_map,
2306 g_strfreev (mime_types);
2309 g_key_file_free (key_file);
2314 g_key_file_free (key_file);
2316 if (mime_types != NULL)
2317 g_strfreev (mime_types);
2320 g_error_free (load_error);
2323 static MimeInfoCacheDir *
2324 mime_info_cache_dir_new (const char *path)
2326 MimeInfoCacheDir *dir;
2328 dir = g_new0 (MimeInfoCacheDir, 1);
2329 dir->path = g_strdup (path);
2335 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2340 if (dir->mime_info_cache_map != NULL)
2342 destroy_info_cache_map (dir->mime_info_cache_map);
2343 dir->mime_info_cache_map = NULL;
2347 if (dir->defaults_list_map != NULL)
2349 g_hash_table_destroy (dir->defaults_list_map);
2350 dir->defaults_list_map = NULL;
2353 if (dir->mimeapps_list_added_map != NULL)
2355 g_hash_table_destroy (dir->mimeapps_list_added_map);
2356 dir->mimeapps_list_added_map = NULL;
2359 if (dir->mimeapps_list_removed_map != NULL)
2361 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2362 dir->mimeapps_list_removed_map = NULL;
2369 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2370 const char *mime_type,
2371 char **new_desktop_file_ids)
2373 GList *desktop_file_ids;
2376 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2379 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2381 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2382 desktop_file_ids = g_list_append (desktop_file_ids,
2383 g_strdup (new_desktop_file_ids[i]));
2386 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2390 mime_info_cache_init_dir_lists (void)
2392 const char * const *dirs;
2395 mime_info_cache = mime_info_cache_new ();
2397 dirs = get_applications_search_path ();
2399 for (i = 0; dirs[i] != NULL; i++)
2401 MimeInfoCacheDir *dir;
2403 dir = mime_info_cache_dir_new (dirs[i]);
2407 mime_info_cache_dir_init (dir);
2408 mime_info_cache_dir_init_defaults_list (dir);
2409 mime_info_cache_dir_init_mimeapps_list (dir);
2411 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2417 mime_info_cache_update_dir_lists (void)
2421 tmp = mime_info_cache->dirs;
2425 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2427 /* No need to do this if we had file monitors... */
2428 mime_info_cache_blow_global_cache ();
2429 mime_info_cache_dir_init (dir);
2430 mime_info_cache_dir_init_defaults_list (dir);
2431 mime_info_cache_dir_init_mimeapps_list (dir);
2438 mime_info_cache_init (void)
2440 G_LOCK (mime_info_cache);
2441 if (mime_info_cache == NULL)
2442 mime_info_cache_init_dir_lists ();
2448 if (now >= mime_info_cache->last_stat_time + 10)
2450 mime_info_cache_update_dir_lists ();
2451 mime_info_cache->last_stat_time = now;
2455 if (mime_info_cache->should_ping_mime_monitor)
2457 /* g_idle_add (emit_mime_changed, NULL); */
2458 mime_info_cache->should_ping_mime_monitor = FALSE;
2461 G_UNLOCK (mime_info_cache);
2464 static MimeInfoCache *
2465 mime_info_cache_new (void)
2467 MimeInfoCache *cache;
2469 cache = g_new0 (MimeInfoCache, 1);
2471 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2472 (GDestroyNotify) g_free,
2473 (GDestroyNotify) g_free);
2478 mime_info_cache_free (MimeInfoCache *cache)
2483 g_list_foreach (cache->dirs,
2484 (GFunc) mime_info_cache_dir_free,
2486 g_list_free (cache->dirs);
2487 g_hash_table_destroy (cache->global_defaults_cache);
2492 * mime_info_cache_reload:
2493 * @dir: directory path which needs reloading.
2495 * Reload the mime information for the @dir.
2498 mime_info_cache_reload (const char *dir)
2500 /* FIXME: just reload the dir that needs reloading,
2501 * don't blow the whole cache
2503 if (mime_info_cache != NULL)
2505 G_LOCK (mime_info_cache);
2506 mime_info_cache_free (mime_info_cache);
2507 mime_info_cache = NULL;
2508 G_UNLOCK (mime_info_cache);
2513 append_desktop_entry (GList *list,
2514 const char *desktop_entry,
2515 GList *removed_entries)
2517 /* Add if not already in list, and valid */
2518 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2519 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2520 list = g_list_prepend (list, g_strdup (desktop_entry));
2526 * get_all_desktop_entries_for_mime_type:
2527 * @mime_type: a mime type.
2528 * @except: NULL or a strv list
2530 * Returns all the desktop ids for @mime_type. The desktop files
2531 * are listed in an order so that default applications are listed before
2532 * non-default ones, and handlers for inherited mimetypes are listed
2533 * after the base ones.
2535 * Optionally doesn't list the desktop ids given in the @except
2537 * Return value: a #GList containing the desktop ids which claim
2538 * to handle @mime_type.
2541 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2542 const char **except)
2544 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2545 MimeInfoCacheDir *dir;
2548 char **default_entries;
2549 char **removed_associations;
2554 mime_info_cache_init ();
2556 /* collect all ancestors */
2557 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2558 array = g_ptr_array_new ();
2559 for (i = 0; mime_types[i]; i++)
2560 g_ptr_array_add (array, mime_types[i]);
2561 g_free (mime_types);
2562 for (i = 0; i < array->len; i++)
2564 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2565 for (j = 0; anc[j]; j++)
2567 for (k = 0; k < array->len; k++)
2569 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2572 if (k == array->len) /* not found */
2573 g_ptr_array_add (array, g_strdup (anc[j]));
2577 g_ptr_array_add (array, NULL);
2578 mime_types = (char **)g_ptr_array_free (array, FALSE);
2580 G_LOCK (mime_info_cache);
2582 removed_entries = NULL;
2583 desktop_entries = NULL;
2585 for (i = 0; except != NULL && except[i] != NULL; i++)
2586 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2588 for (i = 0; mime_types[i] != NULL; i++)
2590 mime_type = mime_types[i];
2592 /* Go through all apps listed as defaults */
2593 for (dir_list = mime_info_cache->dirs;
2595 dir_list = dir_list->next)
2597 dir = dir_list->data;
2599 /* First added associations from mimeapps.list */
2600 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2601 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2602 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2604 /* Then removed associations from mimeapps.list */
2605 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2606 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2607 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2609 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2610 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2611 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2612 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2615 /* Go through all entries that support the mimetype */
2616 for (dir_list = mime_info_cache->dirs;
2618 dir_list = dir_list->next)
2620 dir = dir_list->data;
2622 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2623 for (tmp = list; tmp != NULL; tmp = tmp->next)
2624 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2628 G_UNLOCK (mime_info_cache);
2630 g_strfreev (mime_types);
2632 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2633 g_list_free (removed_entries);
2635 desktop_entries = g_list_reverse (desktop_entries);
2637 return desktop_entries;
2640 /* GDesktopAppInfoLookup interface: */
2642 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2643 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2644 gpointer class_data);
2647 g_desktop_app_info_lookup_get_type (void)
2649 static volatile gsize g_define_type_id__volatile = 0;
2651 if (g_once_init_enter (&g_define_type_id__volatile))
2653 const GTypeInfo desktop_app_info_lookup_info =
2655 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2656 g_desktop_app_info_lookup_base_init, /* base_init */
2657 NULL, /* base_finalize */
2658 g_desktop_app_info_lookup_class_init,
2659 NULL, /* class_finalize */
2660 NULL, /* class_data */
2662 0, /* n_preallocs */
2665 GType g_define_type_id =
2666 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2667 &desktop_app_info_lookup_info, 0);
2669 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2671 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2674 return g_define_type_id__volatile;
2678 g_desktop_app_info_lookup_class_init (gpointer g_class,
2679 gpointer class_data)
2684 g_desktop_app_info_lookup_base_init (gpointer g_class)
2689 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2690 * @lookup: a #GDesktopAppInfoLookup
2691 * @uri_scheme: a string containing a URI scheme.
2693 * Gets the default application for launching applications
2694 * using this URI scheme for a particular GDesktopAppInfoLookup
2697 * The GDesktopAppInfoLookup interface and this function is used
2698 * to implement g_app_info_get_default_for_uri_scheme() backends
2699 * in a GIO module. There is no reason for applications to use it
2700 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2702 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2705 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2706 const char *uri_scheme)
2708 GDesktopAppInfoLookupIface *iface;
2710 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2712 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2714 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2717 #define __G_DESKTOP_APP_INFO_C__
2718 #include "gioaliasdef.c"