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 #undef G_DISABLE_DEPRECATED
37 #include "gcontenttypeprivate.h"
38 #include "gdesktopappinfo.h"
41 #include "gthemedicon.h"
42 #include "gfileicon.h"
43 #include <glib/gstdio.h>
45 #include "giomodule-priv.h"
50 * SECTION:gdesktopappinfo
51 * @title: GDesktopAppInfo
52 * @short_description: Application information from desktop files
53 * @include: gio/gdesktopappinfo.h
55 * #GDesktopAppInfo is an implementation of #GAppInfo based on
58 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
59 * the UNIX-specific GIO interfaces, thus you have to use the
60 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
63 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
64 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
65 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
66 #define MIME_CACHE_GROUP "MIME Cache"
67 #define FULL_NAME_KEY "X-GNOME-FullName"
69 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
70 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
72 gboolean include_fallback);
73 static void mime_info_cache_reload (const char *dir);
74 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
80 * Information about an installed application from a desktop file.
82 struct _GDesktopAppInfo
84 GObject parent_instance;
90 /* FIXME: what about GenericName ? */
105 guint startup_notify : 1;
107 /* FIXME: what about StartupWMClass ? */
110 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
111 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
112 g_desktop_app_info_iface_init))
115 search_path_init (gpointer data)
118 const char * const *data_dirs;
119 const char *user_data_dir;
122 data_dirs = g_get_system_data_dirs ();
123 length = g_strv_length ((char **) data_dirs);
125 args = g_new (char *, length + 2);
128 user_data_dir = g_get_user_data_dir ();
129 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
130 for (i = 0; i < length; i++)
131 args[j++] = g_build_filename (data_dirs[i],
132 "applications", NULL);
138 static const char * const *
139 get_applications_search_path (void)
141 static GOnce once_init = G_ONCE_INIT;
142 return g_once (&once_init, search_path_init, NULL);
146 g_desktop_app_info_finalize (GObject *object)
148 GDesktopAppInfo *info;
150 info = G_DESKTOP_APP_INFO (object);
152 g_free (info->desktop_id);
153 g_free (info->filename);
155 g_free (info->fullname);
156 g_free (info->comment);
157 g_free (info->icon_name);
159 g_object_unref (info->icon);
160 g_strfreev (info->only_show_in);
161 g_strfreev (info->not_show_in);
162 g_free (info->try_exec);
164 g_free (info->binary);
167 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
171 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
173 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
175 gobject_class->finalize = g_desktop_app_info_finalize;
179 g_desktop_app_info_init (GDesktopAppInfo *local)
184 binary_from_exec (const char *exec)
186 const char *p, *start;
192 while (*p != ' ' && *p != 0)
195 return g_strndup (start, p - start);
200 * g_desktop_app_info_new_from_keyfile:
201 * @key_file: an opened #GKeyFile
203 * Creates a new #GDesktopAppInfo.
205 * Returns: a new #GDesktopAppInfo or %NULL on error.
210 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
212 GDesktopAppInfo *info;
217 start_group = g_key_file_get_start_group (key_file);
218 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
220 g_free (start_group);
223 g_free (start_group);
225 type = g_key_file_get_string (key_file,
226 G_KEY_FILE_DESKTOP_GROUP,
227 G_KEY_FILE_DESKTOP_KEY_TYPE,
229 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
236 try_exec = g_key_file_get_string (key_file,
237 G_KEY_FILE_DESKTOP_GROUP,
238 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
240 if (try_exec && try_exec[0] != '\0')
243 t = g_find_program_in_path (try_exec);
252 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
253 info->filename = NULL;
255 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
256 info->fullname = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, FULL_NAME_KEY, NULL, NULL);
257 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
258 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
259 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
260 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);
261 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);
262 info->try_exec = try_exec;
263 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
264 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
265 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
266 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
267 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
268 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
273 if (g_path_is_absolute (info->icon_name))
277 file = g_file_new_for_path (info->icon_name);
278 info->icon = g_file_icon_new (file);
279 g_object_unref (file);
285 /* Work around a common mistake in desktop files */
286 if ((p = strrchr (info->icon_name, '.')) != NULL &&
287 (strcmp (p, ".png") == 0 ||
288 strcmp (p, ".xpm") == 0 ||
289 strcmp (p, ".svg") == 0))
292 info->icon = g_themed_icon_new (info->icon_name);
297 info->binary = binary_from_exec (info->exec);
299 if (info->path && info->path[0] == '\0')
309 * g_desktop_app_info_new_from_filename:
310 * @filename: the path of a desktop file, in the GLib filename encoding
312 * Creates a new #GDesktopAppInfo.
314 * Returns: a new #GDesktopAppInfo or %NULL on error.
317 g_desktop_app_info_new_from_filename (const char *filename)
320 GDesktopAppInfo *info = NULL;
322 key_file = g_key_file_new ();
324 if (g_key_file_load_from_file (key_file,
329 info = g_desktop_app_info_new_from_keyfile (key_file);
331 info->filename = g_strdup (filename);
334 g_key_file_free (key_file);
340 * g_desktop_app_info_new:
341 * @desktop_id: the desktop file id
343 * Creates a new #GDesktopAppInfo based on a desktop file id.
345 * A desktop file id is the basename of the desktop file, including the
346 * .desktop extension. GIO is looking for a desktop file with this name
347 * in the <filename>applications</filename> subdirectories of the XDG data
348 * directories (i.e. the directories specified in the
349 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
350 * variables). GIO also supports the prefix-to-subdirectory mapping that is
351 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
352 * (i.e. a desktop id of kde-foo.desktop will match
353 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
355 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
358 g_desktop_app_info_new (const char *desktop_id)
360 GDesktopAppInfo *appinfo;
361 const char * const *dirs;
365 dirs = get_applications_search_path ();
367 basename = g_strdup (desktop_id);
369 for (i = 0; dirs[i] != NULL; i++)
374 filename = g_build_filename (dirs[i], desktop_id, NULL);
375 appinfo = g_desktop_app_info_new_from_filename (filename);
381 while ((p = strchr (p, '-')) != NULL)
385 filename = g_build_filename (dirs[i], basename, NULL);
386 appinfo = g_desktop_app_info_new_from_filename (filename);
401 appinfo->desktop_id = g_strdup (desktop_id);
403 if (g_desktop_app_info_get_is_hidden (appinfo))
405 g_object_unref (appinfo);
413 g_desktop_app_info_dup (GAppInfo *appinfo)
415 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
416 GDesktopAppInfo *new_info;
418 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
420 new_info->filename = g_strdup (info->filename);
421 new_info->desktop_id = g_strdup (info->desktop_id);
423 new_info->name = g_strdup (info->name);
424 new_info->fullname = g_strdup (info->fullname);
425 new_info->comment = g_strdup (info->comment);
426 new_info->nodisplay = info->nodisplay;
427 new_info->icon_name = g_strdup (info->icon_name);
429 new_info->icon = g_object_ref (info->icon);
430 new_info->only_show_in = g_strdupv (info->only_show_in);
431 new_info->not_show_in = g_strdupv (info->not_show_in);
432 new_info->try_exec = g_strdup (info->try_exec);
433 new_info->exec = g_strdup (info->exec);
434 new_info->binary = g_strdup (info->binary);
435 new_info->path = g_strdup (info->path);
436 new_info->hidden = info->hidden;
437 new_info->terminal = info->terminal;
438 new_info->startup_notify = info->startup_notify;
440 return G_APP_INFO (new_info);
444 g_desktop_app_info_equal (GAppInfo *appinfo1,
447 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
448 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
450 if (info1->desktop_id == NULL ||
451 info2->desktop_id == NULL)
452 return info1 == info2;
454 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
458 g_desktop_app_info_get_id (GAppInfo *appinfo)
460 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
462 return info->desktop_id;
466 g_desktop_app_info_get_name (GAppInfo *appinfo)
468 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
470 if (info->name == NULL)
476 g_desktop_app_info_get_display_name (GAppInfo *appinfo)
478 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
480 if (info->fullname == NULL)
481 return g_desktop_app_info_get_name (appinfo);
482 return info->fullname;
486 * g_desktop_app_info_get_is_hidden:
487 * @info: a #GDesktopAppInfo.
489 * A desktop file is hidden if the Hidden key in it is
492 * Returns: %TRUE if hidden, %FALSE otherwise.
495 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
501 * g_desktop_app_info_get_filename:
502 * @info: a #GDesktopAppInfo
504 * When @info was created from a known filename, return it. In some
505 * situations such as the #GDesktopAppInfo returned from
506 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
508 * Returns: The full path to the file for @info, or %NULL if not known.
512 g_desktop_app_info_get_filename (GDesktopAppInfo *info)
514 return info->filename;
518 g_desktop_app_info_get_description (GAppInfo *appinfo)
520 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
522 return info->comment;
526 g_desktop_app_info_get_executable (GAppInfo *appinfo)
528 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
534 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
536 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
542 g_desktop_app_info_get_icon (GAppInfo *appinfo)
544 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
550 expand_macro_single (char macro, char *uri)
556 file = g_file_new_for_uri (uri);
557 path = g_file_get_path (file);
558 g_object_unref (file);
564 result = g_shell_quote (uri);
569 result = g_shell_quote (path);
575 name = g_path_get_dirname (path);
576 result = g_shell_quote (name);
584 name = g_path_get_basename (path);
585 result = g_shell_quote (name);
597 expand_macro (char macro,
599 GDesktopAppInfo *info,
602 GList *uris = *uri_list;
604 gboolean force_file_uri;
605 char force_file_uri_macro;
608 g_return_if_fail (exec != NULL);
610 /* On %u and %U, pass POSIX file path pointing to the URI via
611 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
612 * running or the URI doesn't have a POSIX file path via FUSE
613 * we'll just pass the URI.
615 force_file_uri_macro = macro;
616 force_file_uri = FALSE;
622 force_file_uri_macro = 'f';
623 force_file_uri = TRUE;
626 force_file_uri_macro = 'F';
627 force_file_uri = TRUE;
643 if (!force_file_uri ||
644 /* Pass URI if it contains an anchor */
645 strchr (uri, '#') != NULL)
647 expanded = expand_macro_single (macro, uri);
651 expanded = expand_macro_single (force_file_uri_macro, uri);
652 if (expanded == NULL)
653 expanded = expand_macro_single (macro, uri);
658 g_string_append (exec, expanded);
674 if (!force_file_uri ||
675 /* Pass URI if it contains an anchor */
676 strchr (uri, '#') != NULL)
678 expanded = expand_macro_single (macro, uri);
682 expanded = expand_macro_single (force_file_uri_macro, uri);
683 if (expanded == NULL)
684 expanded = expand_macro_single (macro, uri);
689 g_string_append (exec, expanded);
695 if (uris != NULL && expanded)
696 g_string_append_c (exec, ' ');
704 g_string_append (exec, "--icon ");
705 expanded = g_shell_quote (info->icon_name);
706 g_string_append (exec, expanded);
714 expanded = g_shell_quote (info->name);
715 g_string_append (exec, expanded);
723 expanded = g_shell_quote (info->filename);
724 g_string_append (exec, expanded);
729 case 'm': /* deprecated */
733 g_string_append_c (exec, '%');
741 expand_application_parameters (GDesktopAppInfo *info,
747 GList *uri_list = *uris;
748 const char *p = info->exec;
749 GString *expanded_exec;
752 if (info->exec == NULL)
754 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
755 _("Desktop file didn't specify Exec field"));
759 expanded_exec = g_string_new (NULL);
763 if (p[0] == '%' && p[1] != '\0')
765 expand_macro (p[1], expanded_exec, info, uris);
769 g_string_append_c (expanded_exec, *p);
774 /* No file substitutions */
775 if (uri_list == *uris && uri_list != NULL)
777 /* If there is no macro default to %f. This is also what KDE does */
778 g_string_append_c (expanded_exec, ' ');
779 expand_macro ('f', expanded_exec, info, uris);
782 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
783 g_string_free (expanded_exec, TRUE);
788 prepend_terminal_to_vector (int *argc,
795 char **term_argv = NULL;
800 g_return_val_if_fail (argc != NULL, FALSE);
801 g_return_val_if_fail (argv != NULL, FALSE);
809 /* compute size if not given */
812 for (i = 0; the_argv[i] != NULL; i++)
818 term_argv = g_new0 (char *, 3);
820 check = g_find_program_in_path ("gnome-terminal");
823 term_argv[0] = check;
824 /* Note that gnome-terminal takes -x and
825 * as -e in gnome-terminal is broken we use that. */
826 term_argv[1] = g_strdup ("-x");
831 check = g_find_program_in_path ("nxterm");
833 check = g_find_program_in_path ("color-xterm");
835 check = g_find_program_in_path ("rxvt");
837 check = g_find_program_in_path ("xterm");
839 check = g_find_program_in_path ("dtterm");
842 check = g_strdup ("xterm");
843 g_warning ("couldn't find a terminal, falling back to xterm");
845 term_argv[0] = check;
846 term_argv[1] = g_strdup ("-e");
849 real_argc = term_argc + *argc;
850 real_argv = g_new (char *, real_argc + 1);
852 for (i = 0; i < term_argc; i++)
853 real_argv[i] = term_argv[i];
855 for (j = 0; j < *argc; j++, i++)
856 real_argv[i] = (char *)the_argv[j];
864 /* we use g_free here as we sucked all the inner strings
865 * out from it into real_argv */
870 #endif /* G_OS_WIN32 */
874 uri_list_segment_to_files (GList *start,
881 while (start != NULL && start != end)
883 file = g_file_new_for_uri ((char *)start->data);
884 res = g_list_prepend (res, file);
888 return g_list_reverse (res);
899 child_setup (gpointer user_data)
901 ChildSetupData *data = user_data;
904 g_setenv ("DISPLAY", data->display, TRUE);
907 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
909 if (data->desktop_file)
913 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
915 g_snprintf (pid, 20, "%ld", (long)getpid ());
916 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
921 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
923 GAppLaunchContext *launch_context,
926 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
927 gboolean completed = FALSE;
929 GList *launched_files;
934 g_return_val_if_fail (appinfo != NULL, FALSE);
941 if (!expand_application_parameters (info, &uris,
942 &argc, &argv, error))
945 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
947 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
948 _("Unable to find terminal required for application"));
954 data.desktop_file = info->filename;
958 launched_files = uri_list_segment_to_files (old_uris, uris);
960 data.display = g_app_launch_context_get_display (launch_context,
964 if (info->startup_notify)
965 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
968 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
969 g_list_free (launched_files);
972 if (!g_spawn_async (info->path,
982 g_app_launch_context_launch_failed (launch_context, data.sn_id);
985 g_free (data.display);
991 g_free (data.display);
996 while (uris != NULL);
1007 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
1009 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1011 return info->exec &&
1012 ((strstr (info->exec, "%u") != NULL) ||
1013 (strstr (info->exec, "%U") != NULL));
1017 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1019 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1021 return info->exec &&
1022 ((strstr (info->exec, "%f") != NULL) ||
1023 (strstr (info->exec, "%F") != NULL));
1027 g_desktop_app_info_launch (GAppInfo *appinfo,
1029 GAppLaunchContext *launch_context,
1039 uri = g_file_get_uri (files->data);
1040 uris = g_list_prepend (uris, uri);
1041 files = files->next;
1044 uris = g_list_reverse (uris);
1046 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1048 g_list_foreach (uris, (GFunc)g_free, NULL);
1054 G_LOCK_DEFINE_STATIC (g_desktop_env);
1055 static gchar *g_desktop_env = NULL;
1058 * g_desktop_app_info_set_desktop_env:
1059 * @desktop_env: a string specifying what desktop this is
1061 * Sets the name of the desktop that the application is running in.
1062 * This is used by g_app_info_should_show() to evaluate the
1063 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1064 * desktop entry fields.
1066 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1067 * Menu specification</ulink> recognizes the following:
1069 * <member>GNOME</member>
1070 * <member>KDE</member>
1071 * <member>ROX</member>
1072 * <member>XFCE</member>
1073 * <member>Old</member>
1076 * Should be called only once; subsequent calls are ignored.
1079 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1081 G_LOCK (g_desktop_env);
1083 g_desktop_env = g_strdup (desktop_env);
1084 G_UNLOCK (g_desktop_env);
1088 g_desktop_app_info_should_show (GAppInfo *appinfo)
1090 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1092 const gchar *desktop_env;
1095 if (info->nodisplay)
1098 G_LOCK (g_desktop_env);
1099 desktop_env = g_desktop_env;
1100 G_UNLOCK (g_desktop_env);
1102 if (info->only_show_in)
1104 if (desktop_env == NULL)
1108 for (i = 0; info->only_show_in[i] != NULL; i++)
1110 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1120 if (info->not_show_in && desktop_env)
1122 for (i = 0; info->not_show_in[i] != NULL; i++)
1124 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1138 ensure_dir (DirType type,
1141 char *path, *display_name;
1144 if (type == APP_DIR)
1145 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1147 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1150 if (g_mkdir_with_parents (path, 0700) == 0)
1154 display_name = g_filename_display_name (path);
1155 if (type == APP_DIR)
1156 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1157 _("Can't create user application configuration folder %s: %s"),
1158 display_name, g_strerror (errsv));
1160 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1161 _("Can't create user MIME configuration folder %s: %s"),
1162 display_name, g_strerror (errsv));
1164 g_free (display_name);
1171 update_mimeapps_list (const char *desktop_id,
1172 const char *content_type,
1173 gboolean add_as_default,
1174 gboolean add_non_default,
1178 char *dirname, *filename;
1180 gboolean load_succeeded, res;
1181 char **old_list, **list;
1182 GList *system_list, *l;
1183 gsize length, data_size;
1186 char **content_types;
1188 /* Don't add both at start and end */
1189 g_assert (!(add_as_default && add_non_default));
1191 dirname = ensure_dir (APP_DIR, error);
1195 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1198 key_file = g_key_file_new ();
1199 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1200 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1202 g_key_file_free (key_file);
1203 key_file = g_key_file_new ();
1208 content_types = g_new (char *, 2);
1209 content_types[0] = g_strdup (content_type);
1210 content_types[1] = NULL;
1214 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1217 for (k = 0; content_types && content_types[k]; k++)
1219 /* Add to the right place in the list */
1222 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1223 content_types[k], &length, NULL);
1225 list = g_new (char *, 1 + length + 1);
1229 list[i++] = g_strdup (desktop_id);
1232 for (j = 0; old_list[j] != NULL; j++)
1234 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1235 list[i++] = g_strdup (old_list[j]);
1236 else if (add_non_default)
1238 /* If adding as non-default, and it's already in,
1239 don't change order of desktop ids */
1240 add_non_default = FALSE;
1241 list[i++] = g_strdup (old_list[j]);
1246 if (add_non_default)
1248 /* We're adding as non-default, and it wasn't already in the list,
1249 so we add at the end. But to avoid listing the app before the
1250 current system default (thus changing the default) we have to
1251 add the current list of (not yet listed) apps before it. */
1253 list[i] = NULL; /* Terminate current list so we can use it */
1254 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list, FALSE);
1256 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1258 for (l = system_list; l != NULL; l = l->next)
1260 list[i++] = l->data; /* no strdup, taking ownership */
1261 if (g_strcmp0 (l->data, desktop_id) == 0)
1262 add_non_default = FALSE;
1264 g_list_free (system_list);
1266 if (add_non_default)
1267 list[i++] = g_strdup (desktop_id);
1272 g_strfreev (old_list);
1274 if (list[0] == NULL || desktop_id == NULL)
1275 g_key_file_remove_key (key_file,
1276 ADDED_ASSOCIATIONS_GROUP,
1280 g_key_file_set_string_list (key_file,
1281 ADDED_ASSOCIATIONS_GROUP,
1283 (const char * const *)list, i);
1290 /* reuse the list from above */
1294 g_strfreev (content_types);
1295 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1298 for (k = 0; content_types && content_types[k]; k++)
1300 /* Remove from removed associations group (unless remove) */
1303 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1304 content_types[k], &length, NULL);
1306 list = g_new (char *, 1 + length + 1);
1310 list[i++] = g_strdup (desktop_id);
1313 for (j = 0; old_list[j] != NULL; j++)
1315 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1316 list[i++] = g_strdup (old_list[j]);
1321 g_strfreev (old_list);
1323 if (list[0] == NULL || desktop_id == NULL)
1324 g_key_file_remove_key (key_file,
1325 REMOVED_ASSOCIATIONS_GROUP,
1329 g_key_file_set_string_list (key_file,
1330 REMOVED_ASSOCIATIONS_GROUP,
1332 (const char * const *)list, i);
1337 g_strfreev (content_types);
1339 data = g_key_file_to_data (key_file, &data_size, error);
1340 g_key_file_free (key_file);
1342 res = g_file_set_contents (filename, data, data_size, error);
1344 mime_info_cache_reload (NULL);
1353 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1354 const char *content_type,
1357 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1359 if (!g_desktop_app_info_ensure_saved (info, error))
1362 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1366 update_program_done (GPid pid,
1370 /* Did the application exit correctly */
1371 if (WIFEXITED (status) &&
1372 WEXITSTATUS (status) == 0)
1374 /* Here we could clean out any caches in use */
1379 run_update_command (char *command,
1388 GError *error = NULL;
1391 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1393 if (g_spawn_async ("/", argv,
1395 G_SPAWN_SEARCH_PATH |
1396 G_SPAWN_STDOUT_TO_DEV_NULL |
1397 G_SPAWN_STDERR_TO_DEV_NULL |
1398 G_SPAWN_DO_NOT_REAP_CHILD,
1399 NULL, NULL, /* No setup function */
1402 g_child_watch_add (pid, update_program_done, NULL);
1405 /* If we get an error at this point, it's quite likely the user doesn't
1406 * have an installed copy of either 'update-mime-database' or
1407 * 'update-desktop-database'. I don't think we want to popup an error
1408 * dialog at this point, so we just do a g_warning to give the user a
1409 * chance of debugging it.
1411 g_warning ("%s", error->message);
1418 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1419 const char *extension,
1422 char *filename, *basename, *mimetype;
1426 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1429 dirname = ensure_dir (MIMETYPE_DIR, error);
1433 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1434 filename = g_build_filename (dirname, basename, NULL);
1438 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1440 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1445 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1446 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1447 " <mime-type type=\"%s\">\n"
1448 " <comment>%s document</comment>\n"
1449 " <glob pattern=\"*.%s\"/>\n"
1451 "</mime-info>\n", mimetype, extension, extension);
1453 g_file_set_contents (filename, contents, -1, NULL);
1456 run_update_command ("update-mime-database", "mime");
1460 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1470 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1471 const char *content_type,
1474 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1476 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1479 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1483 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1489 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1490 const char *content_type,
1493 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1495 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1498 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1502 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1508 char *data, *desktop_id;
1513 if (info->filename != NULL)
1516 /* This is only used for object created with
1517 * g_app_info_create_from_commandline. All other
1518 * object should have a filename
1521 dirname = ensure_dir (APP_DIR, error);
1525 key_file = g_key_file_new ();
1527 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1528 "Encoding", "UTF-8");
1529 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1530 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1531 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1532 G_KEY_FILE_DESKTOP_KEY_TYPE,
1533 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1535 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1536 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1538 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1539 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1541 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1542 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1544 if (info->fullname != NULL)
1545 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1546 FULL_NAME_KEY, info->fullname);
1548 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1549 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1551 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1552 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1554 data = g_key_file_to_data (key_file, &data_size, NULL);
1555 g_key_file_free (key_file);
1557 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1558 filename = g_build_filename (dirname, desktop_id, NULL);
1559 g_free (desktop_id);
1562 fd = g_mkstemp (filename);
1567 display_name = g_filename_display_name (filename);
1568 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1569 _("Can't create user desktop file %s"), display_name);
1570 g_free (display_name);
1576 desktop_id = g_path_get_basename (filename);
1580 res = g_file_set_contents (filename, data, data_size, error);
1583 g_free (desktop_id);
1588 info->filename = filename;
1589 info->desktop_id = desktop_id;
1591 run_update_command ("update-desktop-database", "applications");
1597 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1599 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1603 if (strstr (info->filename, "/userapp-"))
1604 return g_access (info->filename, W_OK) == 0;
1611 g_desktop_app_info_delete (GAppInfo *appinfo)
1613 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1617 if (g_remove (info->filename) == 0)
1619 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1621 g_free (info->filename);
1622 info->filename = NULL;
1623 g_free (info->desktop_id);
1624 info->desktop_id = NULL;
1634 * g_app_info_create_from_commandline:
1635 * @commandline: the commandline to use
1636 * @application_name: (allow-none): the application name, or %NULL to use @commandline
1637 * @flags: flags that can specify details of the created #GAppInfo
1638 * @error: a #GError location to store the error occuring, %NULL to ignore.
1640 * Creates a new #GAppInfo from the given information.
1642 * Returns: (transfer full): new #GAppInfo for given command.
1645 g_app_info_create_from_commandline (const char *commandline,
1646 const char *application_name,
1647 GAppInfoCreateFlags flags,
1652 GDesktopAppInfo *info;
1654 g_return_val_if_fail (commandline, NULL);
1656 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1658 info->filename = NULL;
1659 info->desktop_id = NULL;
1661 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1662 info->startup_notify = flags & G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION;
1663 info->hidden = FALSE;
1664 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1665 info->exec = g_strconcat (commandline, " %u", NULL);
1667 info->exec = g_strconcat (commandline, " %f", NULL);
1668 info->nodisplay = TRUE;
1669 info->binary = binary_from_exec (info->exec);
1671 if (application_name)
1672 info->name = g_strdup (application_name);
1675 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1676 split = g_strsplit (commandline, " ", 2);
1677 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1679 info->name = basename;
1680 if (info->name == NULL)
1681 info->name = g_strdup ("custom");
1683 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1685 return G_APP_INFO (info);
1689 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1691 iface->dup = g_desktop_app_info_dup;
1692 iface->equal = g_desktop_app_info_equal;
1693 iface->get_id = g_desktop_app_info_get_id;
1694 iface->get_name = g_desktop_app_info_get_name;
1695 iface->get_description = g_desktop_app_info_get_description;
1696 iface->get_executable = g_desktop_app_info_get_executable;
1697 iface->get_icon = g_desktop_app_info_get_icon;
1698 iface->launch = g_desktop_app_info_launch;
1699 iface->supports_uris = g_desktop_app_info_supports_uris;
1700 iface->supports_files = g_desktop_app_info_supports_files;
1701 iface->launch_uris = g_desktop_app_info_launch_uris;
1702 iface->should_show = g_desktop_app_info_should_show;
1703 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1704 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1705 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1706 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1707 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1708 iface->can_delete = g_desktop_app_info_can_delete;
1709 iface->do_delete = g_desktop_app_info_delete;
1710 iface->get_commandline = g_desktop_app_info_get_commandline;
1711 iface->get_display_name = g_desktop_app_info_get_display_name;
1715 app_info_in_list (GAppInfo *info,
1718 while (list != NULL)
1720 if (g_app_info_equal (info, list->data))
1728 * g_app_info_get_recommended_for_type:
1729 * @content_type: the content type to find a #GAppInfo for
1731 * Gets a list of recommended #GAppInfos for a given content type, i.e.
1732 * those applications which claim to support the given content type exactly,
1733 * and not by MIME type subclassing.
1735 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
1736 * for given @content_type or %NULL on error.
1741 g_app_info_get_recommended_for_type (const gchar *content_type)
1743 GList *desktop_entries, *l;
1745 GDesktopAppInfo *info;
1747 g_return_val_if_fail (content_type != NULL, NULL);
1749 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, FALSE);
1752 for (l = desktop_entries; l != NULL; l = l->next)
1754 char *desktop_entry = l->data;
1756 info = g_desktop_app_info_new (desktop_entry);
1759 if (app_info_in_list (G_APP_INFO (info), infos))
1760 g_object_unref (info);
1762 infos = g_list_prepend (infos, info);
1764 g_free (desktop_entry);
1767 g_list_free (desktop_entries);
1769 return g_list_reverse (infos);
1773 * g_app_info_get_fallback_for_type:
1774 * @content_type: the content type to find a #GAppInfo for
1776 * Gets a list of fallback #GAppInfos for a given content type, i.e.
1777 * those applications which claim to support the given content type
1778 * by MIME type subclassing and not directly.
1780 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
1781 * for given @content_type or %NULL on error.
1786 g_app_info_get_fallback_for_type (const gchar *content_type)
1788 GList *desktop_entries, *l;
1789 GList *infos, *recommended_infos;
1790 GDesktopAppInfo *info;
1792 g_return_val_if_fail (content_type != NULL, NULL);
1794 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1795 recommended_infos = g_app_info_get_recommended_for_type (content_type);
1798 for (l = desktop_entries; l != NULL; l = l->next)
1800 char *desktop_entry = l->data;
1802 info = g_desktop_app_info_new (desktop_entry);
1805 if (app_info_in_list (G_APP_INFO (info), infos) ||
1806 app_info_in_list (G_APP_INFO (info), recommended_infos))
1807 g_object_unref (info);
1809 infos = g_list_prepend (infos, info);
1811 g_free (desktop_entry);
1814 g_list_free (desktop_entries);
1815 g_list_free_full (recommended_infos, g_object_unref);
1817 return g_list_reverse (infos);
1821 * g_app_info_get_all_for_type:
1822 * @content_type: the content type to find a #GAppInfo for
1824 * Gets a list of all #GAppInfos for a given content type.
1826 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
1827 * for given @content_type or %NULL on error.
1830 g_app_info_get_all_for_type (const char *content_type)
1832 GList *desktop_entries, *l;
1834 GDesktopAppInfo *info;
1836 g_return_val_if_fail (content_type != NULL, NULL);
1838 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1841 for (l = desktop_entries; l != NULL; l = l->next)
1843 char *desktop_entry = l->data;
1845 info = g_desktop_app_info_new (desktop_entry);
1848 if (app_info_in_list (G_APP_INFO (info), infos))
1849 g_object_unref (info);
1851 infos = g_list_prepend (infos, info);
1853 g_free (desktop_entry);
1856 g_list_free (desktop_entries);
1858 return g_list_reverse (infos);
1862 * g_app_info_reset_type_associations:
1863 * @content_type: a content type
1865 * Removes all changes to the type associations done by
1866 * g_app_info_set_as_default_for_type(),
1867 * g_app_info_set_as_default_for_extension(),
1868 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1873 g_app_info_reset_type_associations (const char *content_type)
1875 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1879 * g_app_info_get_default_for_type:
1880 * @content_type: the content type to find a #GAppInfo for
1881 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1884 * Gets the #GAppInfo that corresponds to a given content type.
1886 * Returns: #GAppInfo for given @content_type or %NULL on error.
1889 g_app_info_get_default_for_type (const char *content_type,
1890 gboolean must_support_uris)
1892 GList *desktop_entries, *l;
1895 g_return_val_if_fail (content_type != NULL, NULL);
1897 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE);
1900 for (l = desktop_entries; l != NULL; l = l->next)
1902 char *desktop_entry = l->data;
1904 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1907 if (must_support_uris && !g_app_info_supports_uris (info))
1909 g_object_unref (info);
1917 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1918 g_list_free (desktop_entries);
1924 * g_app_info_get_default_for_uri_scheme:
1925 * @uri_scheme: a string containing a URI scheme.
1927 * Gets the default application for launching applications
1928 * using this URI scheme. A URI scheme is the initial part
1929 * of the URI, up to but not including the ':', e.g. "http",
1932 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1935 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1938 char *content_type, *scheme_down;
1940 scheme_down = g_ascii_strdown (uri_scheme, -1);
1941 content_type = g_strdup_printf ("x-scheme-handler/%s", scheme_down);
1942 g_free (scheme_down);
1943 app_info = g_app_info_get_default_for_type (content_type, FALSE);
1944 g_free (content_type);
1950 get_apps_from_dir (GHashTable *apps,
1951 const char *dirname,
1955 const char *basename;
1956 char *filename, *subprefix, *desktop_id;
1958 GDesktopAppInfo *appinfo;
1960 dir = g_dir_open (dirname, 0, NULL);
1963 while ((basename = g_dir_read_name (dir)) != NULL)
1965 filename = g_build_filename (dirname, basename, NULL);
1966 if (g_str_has_suffix (basename, ".desktop"))
1968 desktop_id = g_strconcat (prefix, basename, NULL);
1970 /* Use _extended so we catch NULLs too (hidden) */
1971 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1973 appinfo = g_desktop_app_info_new_from_filename (filename);
1976 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1978 g_object_unref (appinfo);
1983 if (appinfo || hidden)
1985 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1989 /* Reuse instead of strdup here */
1990 appinfo->desktop_id = desktop_id;
1995 g_free (desktop_id);
1999 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
2001 subprefix = g_strconcat (prefix, basename, "-", NULL);
2002 get_apps_from_dir (apps, filename, subprefix);
2014 * g_app_info_get_all:
2016 * Gets a list of all of the applications currently registered
2019 * For desktop files, this includes applications that have
2020 * <literal>NoDisplay=true</literal> set or are excluded from
2021 * display by means of <literal>OnlyShowIn</literal> or
2022 * <literal>NotShowIn</literal>. See g_app_info_should_show().
2023 * The returned list does not include applications which have
2024 * the <literal>Hidden</literal> key set.
2026 * Returns: (element-type GAppInfo) (transfer full): a newly allocated #GList of references to #GAppInfo<!---->s.
2029 g_app_info_get_all (void)
2031 const char * const *dirs;
2033 GHashTableIter iter;
2038 dirs = get_applications_search_path ();
2040 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
2044 for (i = 0; dirs[i] != NULL; i++)
2045 get_apps_from_dir (apps, dirs[i], "");
2049 g_hash_table_iter_init (&iter, apps);
2050 while (g_hash_table_iter_next (&iter, NULL, &value))
2053 infos = g_list_prepend (infos, value);
2056 g_hash_table_destroy (apps);
2058 return g_list_reverse (infos);
2061 /* Cacheing of mimeinfo.cache and defaults.list files */
2065 GHashTable *mime_info_cache_map;
2066 GHashTable *defaults_list_map;
2067 GHashTable *mimeapps_list_added_map;
2068 GHashTable *mimeapps_list_removed_map;
2069 time_t mime_info_cache_timestamp;
2070 time_t defaults_list_timestamp;
2071 time_t mimeapps_list_timestamp;
2075 GList *dirs; /* mimeinfo.cache and defaults.list */
2076 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2077 time_t last_stat_time;
2078 guint should_ping_mime_monitor : 1;
2081 static MimeInfoCache *mime_info_cache = NULL;
2082 G_LOCK_DEFINE_STATIC (mime_info_cache);
2084 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2085 const char *mime_type,
2086 char **new_desktop_file_ids);
2088 static MimeInfoCache * mime_info_cache_new (void);
2091 destroy_info_cache_value (gpointer key,
2095 g_list_foreach (value, (GFunc)g_free, NULL);
2096 g_list_free (value);
2100 destroy_info_cache_map (GHashTable *info_cache_map)
2102 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2103 g_hash_table_destroy (info_cache_map);
2107 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2108 const char *cache_file,
2114 filename = g_build_filename (dir->path, cache_file, NULL);
2116 if (g_stat (filename, &buf) < 0)
2123 if (buf.st_mtime != *timestamp)
2129 /* Call with lock held */
2131 remove_all (gpointer key,
2140 mime_info_cache_blow_global_cache (void)
2142 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2147 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2151 gchar *filename, **mime_types;
2158 if (dir->mime_info_cache_map != NULL &&
2159 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2160 &dir->mime_info_cache_timestamp))
2163 if (dir->mime_info_cache_map != NULL)
2164 destroy_info_cache_map (dir->mime_info_cache_map);
2166 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2167 (GDestroyNotify) g_free,
2170 key_file = g_key_file_new ();
2172 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2174 if (g_stat (filename, &buf) < 0)
2177 if (dir->mime_info_cache_timestamp > 0)
2178 mime_info_cache->should_ping_mime_monitor = TRUE;
2180 dir->mime_info_cache_timestamp = buf.st_mtime;
2182 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2187 if (load_error != NULL)
2190 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2193 if (load_error != NULL)
2196 for (i = 0; mime_types[i] != NULL; i++)
2198 gchar **desktop_file_ids;
2199 char *unaliased_type;
2200 desktop_file_ids = g_key_file_get_string_list (key_file,
2206 if (desktop_file_ids == NULL)
2209 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2210 mime_info_cache_dir_add_desktop_entries (dir,
2213 g_free (unaliased_type);
2215 g_strfreev (desktop_file_ids);
2218 g_strfreev (mime_types);
2219 g_key_file_free (key_file);
2224 g_key_file_free (key_file);
2226 if (mime_types != NULL)
2227 g_strfreev (mime_types);
2230 g_error_free (load_error);
2234 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2238 gchar *filename, **mime_types;
2239 char *unaliased_type;
2240 char **desktop_file_ids;
2247 if (dir->defaults_list_map != NULL &&
2248 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2249 &dir->defaults_list_timestamp))
2252 if (dir->defaults_list_map != NULL)
2253 g_hash_table_destroy (dir->defaults_list_map);
2254 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2255 g_free, (GDestroyNotify)g_strfreev);
2258 key_file = g_key_file_new ();
2260 filename = g_build_filename (dir->path, "defaults.list", NULL);
2261 if (g_stat (filename, &buf) < 0)
2264 if (dir->defaults_list_timestamp > 0)
2265 mime_info_cache->should_ping_mime_monitor = TRUE;
2267 dir->defaults_list_timestamp = buf.st_mtime;
2269 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2273 if (load_error != NULL)
2276 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2278 if (mime_types != NULL)
2280 for (i = 0; mime_types[i] != NULL; i++)
2282 desktop_file_ids = g_key_file_get_string_list (key_file,
2283 DEFAULT_APPLICATIONS_GROUP,
2287 if (desktop_file_ids == NULL)
2290 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2291 g_hash_table_replace (dir->defaults_list_map,
2296 g_strfreev (mime_types);
2299 g_key_file_free (key_file);
2304 g_key_file_free (key_file);
2306 if (mime_types != NULL)
2307 g_strfreev (mime_types);
2310 g_error_free (load_error);
2314 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2318 gchar *filename, **mime_types;
2319 char *unaliased_type;
2320 char **desktop_file_ids;
2327 if (dir->mimeapps_list_added_map != NULL &&
2328 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2329 &dir->mimeapps_list_timestamp))
2332 if (dir->mimeapps_list_added_map != NULL)
2333 g_hash_table_destroy (dir->mimeapps_list_added_map);
2334 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2335 g_free, (GDestroyNotify)g_strfreev);
2337 if (dir->mimeapps_list_removed_map != NULL)
2338 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2339 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2340 g_free, (GDestroyNotify)g_strfreev);
2342 key_file = g_key_file_new ();
2344 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2345 if (g_stat (filename, &buf) < 0)
2348 if (dir->mimeapps_list_timestamp > 0)
2349 mime_info_cache->should_ping_mime_monitor = TRUE;
2351 dir->mimeapps_list_timestamp = buf.st_mtime;
2353 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2357 if (load_error != NULL)
2360 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2362 if (mime_types != NULL)
2364 for (i = 0; mime_types[i] != NULL; i++)
2366 desktop_file_ids = g_key_file_get_string_list (key_file,
2367 ADDED_ASSOCIATIONS_GROUP,
2371 if (desktop_file_ids == NULL)
2374 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2375 g_hash_table_replace (dir->mimeapps_list_added_map,
2380 g_strfreev (mime_types);
2383 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2385 if (mime_types != NULL)
2387 for (i = 0; mime_types[i] != NULL; i++)
2389 desktop_file_ids = g_key_file_get_string_list (key_file,
2390 REMOVED_ASSOCIATIONS_GROUP,
2394 if (desktop_file_ids == NULL)
2397 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2398 g_hash_table_replace (dir->mimeapps_list_removed_map,
2403 g_strfreev (mime_types);
2406 g_key_file_free (key_file);
2411 g_key_file_free (key_file);
2413 if (mime_types != NULL)
2414 g_strfreev (mime_types);
2417 g_error_free (load_error);
2420 static MimeInfoCacheDir *
2421 mime_info_cache_dir_new (const char *path)
2423 MimeInfoCacheDir *dir;
2425 dir = g_new0 (MimeInfoCacheDir, 1);
2426 dir->path = g_strdup (path);
2432 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2437 if (dir->mime_info_cache_map != NULL)
2439 destroy_info_cache_map (dir->mime_info_cache_map);
2440 dir->mime_info_cache_map = NULL;
2444 if (dir->defaults_list_map != NULL)
2446 g_hash_table_destroy (dir->defaults_list_map);
2447 dir->defaults_list_map = NULL;
2450 if (dir->mimeapps_list_added_map != NULL)
2452 g_hash_table_destroy (dir->mimeapps_list_added_map);
2453 dir->mimeapps_list_added_map = NULL;
2456 if (dir->mimeapps_list_removed_map != NULL)
2458 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2459 dir->mimeapps_list_removed_map = NULL;
2466 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2467 const char *mime_type,
2468 char **new_desktop_file_ids)
2470 GList *desktop_file_ids;
2473 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2476 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2478 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2479 desktop_file_ids = g_list_append (desktop_file_ids,
2480 g_strdup (new_desktop_file_ids[i]));
2483 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2487 mime_info_cache_init_dir_lists (void)
2489 const char * const *dirs;
2492 mime_info_cache = mime_info_cache_new ();
2494 dirs = get_applications_search_path ();
2496 for (i = 0; dirs[i] != NULL; i++)
2498 MimeInfoCacheDir *dir;
2500 dir = mime_info_cache_dir_new (dirs[i]);
2504 mime_info_cache_dir_init (dir);
2505 mime_info_cache_dir_init_defaults_list (dir);
2506 mime_info_cache_dir_init_mimeapps_list (dir);
2508 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2514 mime_info_cache_update_dir_lists (void)
2518 tmp = mime_info_cache->dirs;
2522 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2524 /* No need to do this if we had file monitors... */
2525 mime_info_cache_blow_global_cache ();
2526 mime_info_cache_dir_init (dir);
2527 mime_info_cache_dir_init_defaults_list (dir);
2528 mime_info_cache_dir_init_mimeapps_list (dir);
2535 mime_info_cache_init (void)
2537 G_LOCK (mime_info_cache);
2538 if (mime_info_cache == NULL)
2539 mime_info_cache_init_dir_lists ();
2545 if (now >= mime_info_cache->last_stat_time + 10)
2547 mime_info_cache_update_dir_lists ();
2548 mime_info_cache->last_stat_time = now;
2552 if (mime_info_cache->should_ping_mime_monitor)
2554 /* g_idle_add (emit_mime_changed, NULL); */
2555 mime_info_cache->should_ping_mime_monitor = FALSE;
2558 G_UNLOCK (mime_info_cache);
2561 static MimeInfoCache *
2562 mime_info_cache_new (void)
2564 MimeInfoCache *cache;
2566 cache = g_new0 (MimeInfoCache, 1);
2568 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2569 (GDestroyNotify) g_free,
2570 (GDestroyNotify) g_free);
2575 mime_info_cache_free (MimeInfoCache *cache)
2580 g_list_foreach (cache->dirs,
2581 (GFunc) mime_info_cache_dir_free,
2583 g_list_free (cache->dirs);
2584 g_hash_table_destroy (cache->global_defaults_cache);
2589 * mime_info_cache_reload:
2590 * @dir: directory path which needs reloading.
2592 * Reload the mime information for the @dir.
2595 mime_info_cache_reload (const char *dir)
2597 /* FIXME: just reload the dir that needs reloading,
2598 * don't blow the whole cache
2600 if (mime_info_cache != NULL)
2602 G_LOCK (mime_info_cache);
2603 mime_info_cache_free (mime_info_cache);
2604 mime_info_cache = NULL;
2605 G_UNLOCK (mime_info_cache);
2610 append_desktop_entry (GList *list,
2611 const char *desktop_entry,
2612 GList *removed_entries)
2614 /* Add if not already in list, and valid */
2615 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2616 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2617 list = g_list_prepend (list, g_strdup (desktop_entry));
2623 * get_all_desktop_entries_for_mime_type:
2624 * @mime_type: a mime type.
2625 * @except: NULL or a strv list
2627 * Returns all the desktop ids for @mime_type. The desktop files
2628 * are listed in an order so that default applications are listed before
2629 * non-default ones, and handlers for inherited mimetypes are listed
2630 * after the base ones.
2632 * Optionally doesn't list the desktop ids given in the @except
2634 * Return value: a #GList containing the desktop ids which claim
2635 * to handle @mime_type.
2638 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2639 const char **except,
2640 gboolean include_fallback)
2642 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2643 MimeInfoCacheDir *dir;
2646 char **default_entries;
2647 char **removed_associations;
2652 mime_info_cache_init ();
2654 if (include_fallback)
2656 /* collect all ancestors */
2657 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2658 array = g_ptr_array_new ();
2659 for (i = 0; mime_types[i]; i++)
2660 g_ptr_array_add (array, mime_types[i]);
2661 g_free (mime_types);
2662 for (i = 0; i < array->len; i++)
2664 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2665 for (j = 0; anc[j]; j++)
2667 for (k = 0; k < array->len; k++)
2669 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2672 if (k == array->len) /* not found */
2673 g_ptr_array_add (array, g_strdup (anc[j]));
2677 g_ptr_array_add (array, NULL);
2678 mime_types = (char **)g_ptr_array_free (array, FALSE);
2682 mime_types = g_malloc0 (2 * sizeof (gchar *));
2683 mime_types[0] = g_strdup (base_mime_type);
2684 mime_types[1] = NULL;
2687 G_LOCK (mime_info_cache);
2689 removed_entries = NULL;
2690 desktop_entries = NULL;
2692 for (i = 0; except != NULL && except[i] != NULL; i++)
2693 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2695 for (i = 0; mime_types[i] != NULL; i++)
2697 mime_type = mime_types[i];
2699 /* Go through all apps listed as defaults */
2700 for (dir_list = mime_info_cache->dirs;
2702 dir_list = dir_list->next)
2704 dir = dir_list->data;
2706 /* First added associations from mimeapps.list */
2707 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2708 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2709 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2711 /* Then removed associations from mimeapps.list */
2712 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2713 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2714 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2716 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2717 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2718 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2719 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2722 /* Go through all entries that support the mimetype */
2723 for (dir_list = mime_info_cache->dirs;
2725 dir_list = dir_list->next)
2727 dir = dir_list->data;
2729 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2730 for (tmp = list; tmp != NULL; tmp = tmp->next)
2731 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2735 G_UNLOCK (mime_info_cache);
2737 g_strfreev (mime_types);
2739 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2740 g_list_free (removed_entries);
2742 desktop_entries = g_list_reverse (desktop_entries);
2744 return desktop_entries;
2747 /* GDesktopAppInfoLookup interface: */
2749 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2750 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2753 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2758 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2759 * @lookup: a #GDesktopAppInfoLookup
2760 * @uri_scheme: a string containing a URI scheme.
2762 * Gets the default application for launching applications
2763 * using this URI scheme for a particular GDesktopAppInfoLookup
2766 * The GDesktopAppInfoLookup interface and this function is used
2767 * to implement g_app_info_get_default_for_uri_scheme() backends
2768 * in a GIO module. There is no reason for applications to use it
2769 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2771 * Returns: (transfer full): #GAppInfo for given @uri_scheme or %NULL on error.
2773 * Deprecated: The #GDesktopAppInfoLookup interface is deprecated and unused by gio.
2776 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2777 const char *uri_scheme)
2779 GDesktopAppInfoLookupIface *iface;
2781 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2783 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2785 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);