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_filename:
499 * @info: a #GDesktopAppInfo
501 * When @info was created from a known filename, return it. In some
502 * situations such as the #GDesktopAppInfo returned from
503 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
505 * Returns: The full path to the file for @info, or %NULL if not known.
509 g_desktop_app_info_get_filename (GDesktopAppInfo *info)
511 return info->filename;
515 g_desktop_app_info_get_description (GAppInfo *appinfo)
517 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
519 return info->comment;
523 g_desktop_app_info_get_executable (GAppInfo *appinfo)
525 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
531 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
533 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
539 g_desktop_app_info_get_icon (GAppInfo *appinfo)
541 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
547 expand_macro_single (char macro, char *uri)
553 file = g_file_new_for_uri (uri);
554 path = g_file_get_path (file);
555 g_object_unref (file);
561 result = g_shell_quote (uri);
566 result = g_shell_quote (path);
572 name = g_path_get_dirname (path);
573 result = g_shell_quote (name);
581 name = g_path_get_basename (path);
582 result = g_shell_quote (name);
594 expand_macro (char macro,
596 GDesktopAppInfo *info,
599 GList *uris = *uri_list;
601 gboolean force_file_uri;
602 char force_file_uri_macro;
605 g_return_if_fail (exec != NULL);
607 /* On %u and %U, pass POSIX file path pointing to the URI via
608 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
609 * running or the URI doesn't have a POSIX file path via FUSE
610 * we'll just pass the URI.
612 force_file_uri_macro = macro;
613 force_file_uri = FALSE;
619 force_file_uri_macro = 'f';
620 force_file_uri = TRUE;
623 force_file_uri_macro = 'F';
624 force_file_uri = TRUE;
640 if (!force_file_uri ||
641 /* Pass URI if it contains an anchor */
642 strchr (uri, '#') != NULL)
644 expanded = expand_macro_single (macro, uri);
648 expanded = expand_macro_single (force_file_uri_macro, uri);
649 if (expanded == NULL)
650 expanded = expand_macro_single (macro, uri);
655 g_string_append (exec, expanded);
671 if (!force_file_uri ||
672 /* Pass URI if it contains an anchor */
673 strchr (uri, '#') != NULL)
675 expanded = expand_macro_single (macro, uri);
679 expanded = expand_macro_single (force_file_uri_macro, uri);
680 if (expanded == NULL)
681 expanded = expand_macro_single (macro, uri);
686 g_string_append (exec, expanded);
692 if (uris != NULL && expanded)
693 g_string_append_c (exec, ' ');
701 g_string_append (exec, "--icon ");
702 g_string_append (exec, info->icon_name);
708 g_string_append (exec, info->name);
713 g_string_append (exec, info->filename);
716 case 'm': /* deprecated */
720 g_string_append_c (exec, '%');
728 expand_application_parameters (GDesktopAppInfo *info,
734 GList *uri_list = *uris;
735 const char *p = info->exec;
736 GString *expanded_exec;
739 if (info->exec == NULL)
741 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
742 _("Desktop file didn't specify Exec field"));
746 expanded_exec = g_string_new (NULL);
750 if (p[0] == '%' && p[1] != '\0')
752 expand_macro (p[1], expanded_exec, info, uris);
756 g_string_append_c (expanded_exec, *p);
761 /* No file substitutions */
762 if (uri_list == *uris && uri_list != NULL)
764 /* If there is no macro default to %f. This is also what KDE does */
765 g_string_append_c (expanded_exec, ' ');
766 expand_macro ('f', expanded_exec, info, uris);
769 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
770 g_string_free (expanded_exec, TRUE);
775 prepend_terminal_to_vector (int *argc,
782 char **term_argv = NULL;
787 g_return_val_if_fail (argc != NULL, FALSE);
788 g_return_val_if_fail (argv != NULL, FALSE);
796 /* compute size if not given */
799 for (i = 0; the_argv[i] != NULL; i++)
805 term_argv = g_new0 (char *, 3);
807 check = g_find_program_in_path ("gnome-terminal");
810 term_argv[0] = check;
811 /* Note that gnome-terminal takes -x and
812 * as -e in gnome-terminal is broken we use that. */
813 term_argv[1] = g_strdup ("-x");
818 check = g_find_program_in_path ("nxterm");
820 check = g_find_program_in_path ("color-xterm");
822 check = g_find_program_in_path ("rxvt");
824 check = g_find_program_in_path ("xterm");
826 check = g_find_program_in_path ("dtterm");
829 check = g_strdup ("xterm");
830 g_warning ("couldn't find a terminal, falling back to xterm");
832 term_argv[0] = check;
833 term_argv[1] = g_strdup ("-e");
836 real_argc = term_argc + *argc;
837 real_argv = g_new (char *, real_argc + 1);
839 for (i = 0; i < term_argc; i++)
840 real_argv[i] = term_argv[i];
842 for (j = 0; j < *argc; j++, i++)
843 real_argv[i] = (char *)the_argv[j];
851 /* we use g_free here as we sucked all the inner strings
852 * out from it into real_argv */
857 #endif /* G_OS_WIN32 */
861 uri_list_segment_to_files (GList *start,
868 while (start != NULL && start != end)
870 file = g_file_new_for_uri ((char *)start->data);
871 res = g_list_prepend (res, file);
875 return g_list_reverse (res);
886 child_setup (gpointer user_data)
888 ChildSetupData *data = user_data;
891 g_setenv ("DISPLAY", data->display, TRUE);
894 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
896 if (data->desktop_file)
900 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
902 g_snprintf (pid, 20, "%d", getpid ());
903 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
908 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
910 GAppLaunchContext *launch_context,
913 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
914 gboolean completed = FALSE;
916 GList *launched_files;
921 g_return_val_if_fail (appinfo != NULL, FALSE);
928 if (!expand_application_parameters (info, &uris,
929 &argc, &argv, error))
932 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
934 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
935 _("Unable to find terminal required for application"));
941 data.desktop_file = info->filename;
945 launched_files = uri_list_segment_to_files (old_uris, uris);
947 data.display = g_app_launch_context_get_display (launch_context,
951 if (info->startup_notify)
952 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
955 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
956 g_list_free (launched_files);
959 if (!g_spawn_async (info->path,
969 g_app_launch_context_launch_failed (launch_context, data.sn_id);
972 g_free (data.display);
978 g_free (data.display);
983 while (uris != NULL);
994 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
996 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
999 ((strstr (info->exec, "%u") != NULL) ||
1000 (strstr (info->exec, "%U") != NULL));
1004 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1006 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1008 return info->exec &&
1009 ((strstr (info->exec, "%f") != NULL) ||
1010 (strstr (info->exec, "%F") != NULL));
1014 g_desktop_app_info_launch (GAppInfo *appinfo,
1016 GAppLaunchContext *launch_context,
1026 uri = g_file_get_uri (files->data);
1027 uris = g_list_prepend (uris, uri);
1028 files = files->next;
1031 uris = g_list_reverse (uris);
1033 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1035 g_list_foreach (uris, (GFunc)g_free, NULL);
1041 G_LOCK_DEFINE_STATIC (g_desktop_env);
1042 static gchar *g_desktop_env = NULL;
1045 * g_desktop_app_info_set_desktop_env:
1046 * @desktop_env: a string specifying what desktop this is
1048 * Sets the name of the desktop that the application is running in.
1049 * This is used by g_app_info_should_show() to evaluate the
1050 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1051 * desktop entry fields.
1053 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1054 * Menu specification</ulink> recognizes the following:
1056 * <member>GNOME</member>
1057 * <member>KDE</member>
1058 * <member>ROX</member>
1059 * <member>XFCE</member>
1060 * <member>Old</member>
1063 * Should be called only once; subsequent calls are ignored.
1066 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1068 G_LOCK (g_desktop_env);
1070 g_desktop_env = g_strdup (desktop_env);
1071 G_UNLOCK (g_desktop_env);
1075 g_desktop_app_info_should_show (GAppInfo *appinfo)
1077 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1079 const gchar *desktop_env;
1082 if (info->nodisplay)
1085 G_LOCK (g_desktop_env);
1086 desktop_env = g_desktop_env;
1087 G_UNLOCK (g_desktop_env);
1089 if (info->only_show_in)
1091 if (desktop_env == NULL)
1095 for (i = 0; info->only_show_in[i] != NULL; i++)
1097 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1107 if (info->not_show_in && desktop_env)
1109 for (i = 0; info->not_show_in[i] != NULL; i++)
1111 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1125 ensure_dir (DirType type,
1128 char *path, *display_name;
1131 if (type == APP_DIR)
1132 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1134 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1137 if (g_mkdir_with_parents (path, 0700) == 0)
1141 display_name = g_filename_display_name (path);
1142 if (type == APP_DIR)
1143 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1144 _("Can't create user application configuration folder %s: %s"),
1145 display_name, g_strerror (errsv));
1147 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1148 _("Can't create user MIME configuration folder %s: %s"),
1149 display_name, g_strerror (errsv));
1151 g_free (display_name);
1158 update_mimeapps_list (const char *desktop_id,
1159 const char *content_type,
1160 gboolean add_as_default,
1161 gboolean add_non_default,
1165 char *dirname, *filename;
1167 gboolean load_succeeded, res;
1168 char **old_list, **list;
1169 GList *system_list, *l;
1170 gsize length, data_size;
1173 char **content_types;
1175 /* Don't add both at start and end */
1176 g_assert (!(add_as_default && add_non_default));
1178 dirname = ensure_dir (APP_DIR, error);
1182 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1185 key_file = g_key_file_new ();
1186 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1187 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1189 g_key_file_free (key_file);
1190 key_file = g_key_file_new ();
1195 content_types = g_new (char *, 2);
1196 content_types[0] = g_strdup (content_type);
1197 content_types[1] = NULL;
1201 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1204 for (k = 0; content_types && content_types[k]; k++)
1206 /* Add to the right place in the list */
1209 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1210 content_types[k], &length, NULL);
1212 list = g_new (char *, 1 + length + 1);
1216 list[i++] = g_strdup (desktop_id);
1219 for (j = 0; old_list[j] != NULL; j++)
1221 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1222 list[i++] = g_strdup (old_list[j]);
1223 else if (add_non_default)
1225 /* If adding as non-default, and it's already in,
1226 don't change order of desktop ids */
1227 add_non_default = FALSE;
1228 list[i++] = g_strdup (old_list[j]);
1233 if (add_non_default)
1235 /* We're adding as non-default, and it wasn't already in the list,
1236 so we add at the end. But to avoid listing the app before the
1237 current system default (thus changing the default) we have to
1238 add the current list of (not yet listed) apps before it. */
1240 list[i] = NULL; /* Terminate current list so we can use it */
1241 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1243 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1245 for (l = system_list; l != NULL; l = l->next)
1247 list[i++] = l->data; /* no strdup, taking ownership */
1248 if (g_strcmp0 (l->data, desktop_id) == 0)
1249 add_non_default = FALSE;
1251 g_list_free (system_list);
1253 if (add_non_default)
1254 list[i++] = g_strdup (desktop_id);
1259 g_strfreev (old_list);
1261 if (list[0] == NULL || desktop_id == NULL)
1262 g_key_file_remove_key (key_file,
1263 ADDED_ASSOCIATIONS_GROUP,
1267 g_key_file_set_string_list (key_file,
1268 ADDED_ASSOCIATIONS_GROUP,
1270 (const char * const *)list, i);
1277 /* reuse the list from above */
1281 g_strfreev (content_types);
1282 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1285 for (k = 0; content_types && content_types[k]; k++)
1287 /* Remove from removed associations group (unless remove) */
1290 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1291 content_types[k], &length, NULL);
1293 list = g_new (char *, 1 + length + 1);
1297 list[i++] = g_strdup (desktop_id);
1300 for (j = 0; old_list[j] != NULL; j++)
1302 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1303 list[i++] = g_strdup (old_list[j]);
1308 g_strfreev (old_list);
1310 if (list[0] == NULL || desktop_id == NULL)
1311 g_key_file_remove_key (key_file,
1312 REMOVED_ASSOCIATIONS_GROUP,
1316 g_key_file_set_string_list (key_file,
1317 REMOVED_ASSOCIATIONS_GROUP,
1319 (const char * const *)list, i);
1324 g_strfreev (content_types);
1326 data = g_key_file_to_data (key_file, &data_size, error);
1327 g_key_file_free (key_file);
1329 res = g_file_set_contents (filename, data, data_size, error);
1331 mime_info_cache_reload (NULL);
1340 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1341 const char *content_type,
1344 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1346 if (!g_desktop_app_info_ensure_saved (info, error))
1349 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1353 update_program_done (GPid pid,
1357 /* Did the application exit correctly */
1358 if (WIFEXITED (status) &&
1359 WEXITSTATUS (status) == 0)
1361 /* Here we could clean out any caches in use */
1366 run_update_command (char *command,
1375 GError *error = NULL;
1378 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1380 if (g_spawn_async ("/", argv,
1382 G_SPAWN_SEARCH_PATH |
1383 G_SPAWN_STDOUT_TO_DEV_NULL |
1384 G_SPAWN_STDERR_TO_DEV_NULL |
1385 G_SPAWN_DO_NOT_REAP_CHILD,
1386 NULL, NULL, /* No setup function */
1389 g_child_watch_add (pid, update_program_done, NULL);
1392 /* If we get an error at this point, it's quite likely the user doesn't
1393 * have an installed copy of either 'update-mime-database' or
1394 * 'update-desktop-database'. I don't think we want to popup an error
1395 * dialog at this point, so we just do a g_warning to give the user a
1396 * chance of debugging it.
1398 g_warning ("%s", error->message);
1405 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1406 const char *extension,
1409 char *filename, *basename, *mimetype;
1413 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1416 dirname = ensure_dir (MIMETYPE_DIR, error);
1420 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1421 filename = g_build_filename (dirname, basename, NULL);
1425 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1427 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1432 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1433 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1434 " <mime-type type=\"%s\">\n"
1435 " <comment>%s document</comment>\n"
1436 " <glob pattern=\"*.%s\"/>\n"
1438 "</mime-info>\n", mimetype, extension, extension);
1440 g_file_set_contents (filename, contents, -1, NULL);
1443 run_update_command ("update-mime-database", "mime");
1447 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1457 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1458 const char *content_type,
1461 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1463 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1466 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1470 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1476 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1477 const char *content_type,
1480 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1482 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1485 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1489 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1495 char *data, *desktop_id;
1500 if (info->filename != NULL)
1503 /* This is only used for object created with
1504 * g_app_info_create_from_commandline. All other
1505 * object should have a filename
1508 dirname = ensure_dir (APP_DIR, error);
1512 key_file = g_key_file_new ();
1514 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1515 "Encoding", "UTF-8");
1516 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1517 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1518 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1519 G_KEY_FILE_DESKTOP_KEY_TYPE,
1520 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1522 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1523 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1525 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1526 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1528 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1529 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1531 if (info->fullname != NULL)
1532 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1533 FULL_NAME_KEY, info->fullname);
1535 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1536 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1538 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1539 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1541 data = g_key_file_to_data (key_file, &data_size, NULL);
1542 g_key_file_free (key_file);
1544 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1545 filename = g_build_filename (dirname, desktop_id, NULL);
1546 g_free (desktop_id);
1549 fd = g_mkstemp (filename);
1554 display_name = g_filename_display_name (filename);
1555 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1556 _("Can't create user desktop file %s"), display_name);
1557 g_free (display_name);
1563 desktop_id = g_path_get_basename (filename);
1567 res = g_file_set_contents (filename, data, data_size, error);
1570 g_free (desktop_id);
1575 info->filename = filename;
1576 info->desktop_id = desktop_id;
1578 run_update_command ("update-desktop-database", "applications");
1584 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1586 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1590 if (strstr (info->filename, "/userapp-"))
1591 return g_access (info->filename, W_OK) == 0;
1598 g_desktop_app_info_delete (GAppInfo *appinfo)
1600 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1604 if (g_remove (info->filename) == 0)
1606 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1608 g_free (info->filename);
1609 info->filename = NULL;
1610 g_free (info->desktop_id);
1611 info->desktop_id = NULL;
1621 * g_app_info_create_from_commandline:
1622 * @commandline: the commandline to use
1623 * @application_name: the application name, or %NULL to use @commandline
1624 * @flags: flags that can specify details of the created #GAppInfo
1625 * @error: a #GError location to store the error occuring, %NULL to ignore.
1627 * Creates a new #GAppInfo from the given information.
1629 * Returns: new #GAppInfo for given command.
1632 g_app_info_create_from_commandline (const char *commandline,
1633 const char *application_name,
1634 GAppInfoCreateFlags flags,
1639 GDesktopAppInfo *info;
1641 g_return_val_if_fail (commandline, NULL);
1643 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1645 info->filename = NULL;
1646 info->desktop_id = NULL;
1648 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1649 info->startup_notify = FALSE;
1650 info->hidden = FALSE;
1651 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1652 info->exec = g_strconcat (commandline, " %u", NULL);
1654 info->exec = g_strconcat (commandline, " %f", NULL);
1655 info->nodisplay = TRUE;
1656 info->binary = binary_from_exec (info->exec);
1658 if (application_name)
1659 info->name = g_strdup (application_name);
1662 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1663 split = g_strsplit (commandline, " ", 2);
1664 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1666 info->name = basename;
1667 if (info->name == NULL)
1668 info->name = g_strdup ("custom");
1670 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1672 return G_APP_INFO (info);
1676 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1678 iface->dup = g_desktop_app_info_dup;
1679 iface->equal = g_desktop_app_info_equal;
1680 iface->get_id = g_desktop_app_info_get_id;
1681 iface->get_name = g_desktop_app_info_get_name;
1682 iface->get_description = g_desktop_app_info_get_description;
1683 iface->get_executable = g_desktop_app_info_get_executable;
1684 iface->get_icon = g_desktop_app_info_get_icon;
1685 iface->launch = g_desktop_app_info_launch;
1686 iface->supports_uris = g_desktop_app_info_supports_uris;
1687 iface->supports_files = g_desktop_app_info_supports_files;
1688 iface->launch_uris = g_desktop_app_info_launch_uris;
1689 iface->should_show = g_desktop_app_info_should_show;
1690 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1691 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1692 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1693 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1694 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1695 iface->can_delete = g_desktop_app_info_can_delete;
1696 iface->do_delete = g_desktop_app_info_delete;
1697 iface->get_commandline = g_desktop_app_info_get_commandline;
1698 iface->get_display_name = g_desktop_app_info_get_display_name;
1702 app_info_in_list (GAppInfo *info,
1705 while (list != NULL)
1707 if (g_app_info_equal (info, list->data))
1716 * g_app_info_get_all_for_type:
1717 * @content_type: the content type to find a #GAppInfo for
1719 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1721 * Returns: #GList of #GAppInfo<!-- -->s for given @content_type
1722 * or %NULL on error.
1725 g_app_info_get_all_for_type (const char *content_type)
1727 GList *desktop_entries, *l;
1729 GDesktopAppInfo *info;
1731 g_return_val_if_fail (content_type != NULL, NULL);
1733 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1736 for (l = desktop_entries; l != NULL; l = l->next)
1738 char *desktop_entry = l->data;
1740 info = g_desktop_app_info_new (desktop_entry);
1743 if (app_info_in_list (G_APP_INFO (info), infos))
1744 g_object_unref (info);
1746 infos = g_list_prepend (infos, info);
1748 g_free (desktop_entry);
1751 g_list_free (desktop_entries);
1753 return g_list_reverse (infos);
1757 * g_app_info_reset_type_associations:
1758 * @content_type: a content type
1760 * Removes all changes to the type associations done by
1761 * g_app_info_set_as_default_for_type(),
1762 * g_app_info_set_as_default_for_extension(),
1763 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1768 g_app_info_reset_type_associations (const char *content_type)
1770 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1774 * g_app_info_get_default_for_type:
1775 * @content_type: the content type to find a #GAppInfo for
1776 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1779 * Gets the #GAppInfo that corresponds to a given content type.
1781 * Returns: #GAppInfo for given @content_type or %NULL on error.
1784 g_app_info_get_default_for_type (const char *content_type,
1785 gboolean must_support_uris)
1787 GList *desktop_entries, *l;
1790 g_return_val_if_fail (content_type != NULL, NULL);
1792 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1795 for (l = desktop_entries; l != NULL; l = l->next)
1797 char *desktop_entry = l->data;
1799 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1802 if (must_support_uris && !g_app_info_supports_uris (info))
1804 g_object_unref (info);
1812 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1813 g_list_free (desktop_entries);
1819 * g_app_info_get_default_for_uri_scheme:
1820 * @uri_scheme: a string containing a URI scheme.
1822 * Gets the default application for launching applications
1823 * using this URI scheme. A URI scheme is the initial part
1824 * of the URI, up to but not including the ':', e.g. "http",
1827 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1830 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1832 static gsize lookup = 0;
1834 if (g_once_init_enter (&lookup))
1836 gsize setup_value = 1;
1837 GDesktopAppInfoLookup *lookup_instance;
1838 const char *use_this;
1839 GIOExtensionPoint *ep;
1840 GIOExtension *extension;
1843 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1845 /* Ensure vfs in modules loaded */
1846 _g_io_modules_ensure_loaded ();
1848 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1850 lookup_instance = NULL;
1853 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1855 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1858 if (lookup_instance == NULL)
1860 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1862 extension = l->data;
1863 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1864 if (lookup_instance != NULL)
1869 if (lookup_instance != NULL)
1870 setup_value = (gsize)lookup_instance;
1872 g_once_init_leave (&lookup, setup_value);
1878 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1884 get_apps_from_dir (GHashTable *apps,
1885 const char *dirname,
1889 const char *basename;
1890 char *filename, *subprefix, *desktop_id;
1892 GDesktopAppInfo *appinfo;
1894 dir = g_dir_open (dirname, 0, NULL);
1897 while ((basename = g_dir_read_name (dir)) != NULL)
1899 filename = g_build_filename (dirname, basename, NULL);
1900 if (g_str_has_suffix (basename, ".desktop"))
1902 desktop_id = g_strconcat (prefix, basename, NULL);
1904 /* Use _extended so we catch NULLs too (hidden) */
1905 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1907 appinfo = g_desktop_app_info_new_from_filename (filename);
1910 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1912 g_object_unref (appinfo);
1917 if (appinfo || hidden)
1919 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1923 /* Reuse instead of strdup here */
1924 appinfo->desktop_id = desktop_id;
1929 g_free (desktop_id);
1933 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1935 subprefix = g_strconcat (prefix, basename, "-", NULL);
1936 get_apps_from_dir (apps, filename, subprefix);
1948 * g_app_info_get_all:
1950 * Gets a list of all of the applications currently registered
1953 * For desktop files, this includes applications that have
1954 * <literal>NoDisplay=true</literal> set or are excluded from
1955 * display by means of <literal>OnlyShowIn</literal> or
1956 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1957 * The returned list does not include applications which have
1958 * the <literal>Hidden</literal> key set.
1960 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1963 g_app_info_get_all (void)
1965 const char * const *dirs;
1967 GHashTableIter iter;
1972 dirs = get_applications_search_path ();
1974 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1978 for (i = 0; dirs[i] != NULL; i++)
1979 get_apps_from_dir (apps, dirs[i], "");
1983 g_hash_table_iter_init (&iter, apps);
1984 while (g_hash_table_iter_next (&iter, NULL, &value))
1987 infos = g_list_prepend (infos, value);
1990 g_hash_table_destroy (apps);
1992 return g_list_reverse (infos);
1995 /* Cacheing of mimeinfo.cache and defaults.list files */
1999 GHashTable *mime_info_cache_map;
2000 GHashTable *defaults_list_map;
2001 GHashTable *mimeapps_list_added_map;
2002 GHashTable *mimeapps_list_removed_map;
2003 time_t mime_info_cache_timestamp;
2004 time_t defaults_list_timestamp;
2005 time_t mimeapps_list_timestamp;
2009 GList *dirs; /* mimeinfo.cache and defaults.list */
2010 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2011 time_t last_stat_time;
2012 guint should_ping_mime_monitor : 1;
2015 static MimeInfoCache *mime_info_cache = NULL;
2016 G_LOCK_DEFINE_STATIC (mime_info_cache);
2018 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2019 const char *mime_type,
2020 char **new_desktop_file_ids);
2022 static MimeInfoCache * mime_info_cache_new (void);
2025 destroy_info_cache_value (gpointer key,
2029 g_list_foreach (value, (GFunc)g_free, NULL);
2030 g_list_free (value);
2034 destroy_info_cache_map (GHashTable *info_cache_map)
2036 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2037 g_hash_table_destroy (info_cache_map);
2041 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2042 const char *cache_file,
2048 filename = g_build_filename (dir->path, cache_file, NULL);
2050 if (g_stat (filename, &buf) < 0)
2057 if (buf.st_mtime != *timestamp)
2063 /* Call with lock held */
2065 remove_all (gpointer key,
2074 mime_info_cache_blow_global_cache (void)
2076 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2081 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2085 gchar *filename, **mime_types;
2092 if (dir->mime_info_cache_map != NULL &&
2093 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2094 &dir->mime_info_cache_timestamp))
2097 if (dir->mime_info_cache_map != NULL)
2098 destroy_info_cache_map (dir->mime_info_cache_map);
2100 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2101 (GDestroyNotify) g_free,
2104 key_file = g_key_file_new ();
2106 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2108 if (g_stat (filename, &buf) < 0)
2111 if (dir->mime_info_cache_timestamp > 0)
2112 mime_info_cache->should_ping_mime_monitor = TRUE;
2114 dir->mime_info_cache_timestamp = buf.st_mtime;
2116 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2121 if (load_error != NULL)
2124 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2127 if (load_error != NULL)
2130 for (i = 0; mime_types[i] != NULL; i++)
2132 gchar **desktop_file_ids;
2133 char *unaliased_type;
2134 desktop_file_ids = g_key_file_get_string_list (key_file,
2140 if (desktop_file_ids == NULL)
2143 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2144 mime_info_cache_dir_add_desktop_entries (dir,
2147 g_free (unaliased_type);
2149 g_strfreev (desktop_file_ids);
2152 g_strfreev (mime_types);
2153 g_key_file_free (key_file);
2158 g_key_file_free (key_file);
2160 if (mime_types != NULL)
2161 g_strfreev (mime_types);
2164 g_error_free (load_error);
2168 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2172 gchar *filename, **mime_types;
2173 char *unaliased_type;
2174 char **desktop_file_ids;
2181 if (dir->defaults_list_map != NULL &&
2182 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2183 &dir->defaults_list_timestamp))
2186 if (dir->defaults_list_map != NULL)
2187 g_hash_table_destroy (dir->defaults_list_map);
2188 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2189 g_free, (GDestroyNotify)g_strfreev);
2192 key_file = g_key_file_new ();
2194 filename = g_build_filename (dir->path, "defaults.list", NULL);
2195 if (g_stat (filename, &buf) < 0)
2198 if (dir->defaults_list_timestamp > 0)
2199 mime_info_cache->should_ping_mime_monitor = TRUE;
2201 dir->defaults_list_timestamp = buf.st_mtime;
2203 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2207 if (load_error != NULL)
2210 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2212 if (mime_types != NULL)
2214 for (i = 0; mime_types[i] != NULL; i++)
2216 desktop_file_ids = g_key_file_get_string_list (key_file,
2217 DEFAULT_APPLICATIONS_GROUP,
2221 if (desktop_file_ids == NULL)
2224 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2225 g_hash_table_replace (dir->defaults_list_map,
2230 g_strfreev (mime_types);
2233 g_key_file_free (key_file);
2238 g_key_file_free (key_file);
2240 if (mime_types != NULL)
2241 g_strfreev (mime_types);
2244 g_error_free (load_error);
2248 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2252 gchar *filename, **mime_types;
2253 char *unaliased_type;
2254 char **desktop_file_ids;
2261 if (dir->mimeapps_list_added_map != NULL &&
2262 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2263 &dir->mimeapps_list_timestamp))
2266 if (dir->mimeapps_list_added_map != NULL)
2267 g_hash_table_destroy (dir->mimeapps_list_added_map);
2268 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2269 g_free, (GDestroyNotify)g_strfreev);
2271 if (dir->mimeapps_list_removed_map != NULL)
2272 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2273 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2274 g_free, (GDestroyNotify)g_strfreev);
2276 key_file = g_key_file_new ();
2278 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2279 if (g_stat (filename, &buf) < 0)
2282 if (dir->mimeapps_list_timestamp > 0)
2283 mime_info_cache->should_ping_mime_monitor = TRUE;
2285 dir->mimeapps_list_timestamp = buf.st_mtime;
2287 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2291 if (load_error != NULL)
2294 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2296 if (mime_types != NULL)
2298 for (i = 0; mime_types[i] != NULL; i++)
2300 desktop_file_ids = g_key_file_get_string_list (key_file,
2301 ADDED_ASSOCIATIONS_GROUP,
2305 if (desktop_file_ids == NULL)
2308 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2309 g_hash_table_replace (dir->mimeapps_list_added_map,
2314 g_strfreev (mime_types);
2317 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2319 if (mime_types != NULL)
2321 for (i = 0; mime_types[i] != NULL; i++)
2323 desktop_file_ids = g_key_file_get_string_list (key_file,
2324 REMOVED_ASSOCIATIONS_GROUP,
2328 if (desktop_file_ids == NULL)
2331 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2332 g_hash_table_replace (dir->mimeapps_list_removed_map,
2337 g_strfreev (mime_types);
2340 g_key_file_free (key_file);
2345 g_key_file_free (key_file);
2347 if (mime_types != NULL)
2348 g_strfreev (mime_types);
2351 g_error_free (load_error);
2354 static MimeInfoCacheDir *
2355 mime_info_cache_dir_new (const char *path)
2357 MimeInfoCacheDir *dir;
2359 dir = g_new0 (MimeInfoCacheDir, 1);
2360 dir->path = g_strdup (path);
2366 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2371 if (dir->mime_info_cache_map != NULL)
2373 destroy_info_cache_map (dir->mime_info_cache_map);
2374 dir->mime_info_cache_map = NULL;
2378 if (dir->defaults_list_map != NULL)
2380 g_hash_table_destroy (dir->defaults_list_map);
2381 dir->defaults_list_map = NULL;
2384 if (dir->mimeapps_list_added_map != NULL)
2386 g_hash_table_destroy (dir->mimeapps_list_added_map);
2387 dir->mimeapps_list_added_map = NULL;
2390 if (dir->mimeapps_list_removed_map != NULL)
2392 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2393 dir->mimeapps_list_removed_map = NULL;
2400 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2401 const char *mime_type,
2402 char **new_desktop_file_ids)
2404 GList *desktop_file_ids;
2407 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2410 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2412 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2413 desktop_file_ids = g_list_append (desktop_file_ids,
2414 g_strdup (new_desktop_file_ids[i]));
2417 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2421 mime_info_cache_init_dir_lists (void)
2423 const char * const *dirs;
2426 mime_info_cache = mime_info_cache_new ();
2428 dirs = get_applications_search_path ();
2430 for (i = 0; dirs[i] != NULL; i++)
2432 MimeInfoCacheDir *dir;
2434 dir = mime_info_cache_dir_new (dirs[i]);
2438 mime_info_cache_dir_init (dir);
2439 mime_info_cache_dir_init_defaults_list (dir);
2440 mime_info_cache_dir_init_mimeapps_list (dir);
2442 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2448 mime_info_cache_update_dir_lists (void)
2452 tmp = mime_info_cache->dirs;
2456 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2458 /* No need to do this if we had file monitors... */
2459 mime_info_cache_blow_global_cache ();
2460 mime_info_cache_dir_init (dir);
2461 mime_info_cache_dir_init_defaults_list (dir);
2462 mime_info_cache_dir_init_mimeapps_list (dir);
2469 mime_info_cache_init (void)
2471 G_LOCK (mime_info_cache);
2472 if (mime_info_cache == NULL)
2473 mime_info_cache_init_dir_lists ();
2479 if (now >= mime_info_cache->last_stat_time + 10)
2481 mime_info_cache_update_dir_lists ();
2482 mime_info_cache->last_stat_time = now;
2486 if (mime_info_cache->should_ping_mime_monitor)
2488 /* g_idle_add (emit_mime_changed, NULL); */
2489 mime_info_cache->should_ping_mime_monitor = FALSE;
2492 G_UNLOCK (mime_info_cache);
2495 static MimeInfoCache *
2496 mime_info_cache_new (void)
2498 MimeInfoCache *cache;
2500 cache = g_new0 (MimeInfoCache, 1);
2502 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2503 (GDestroyNotify) g_free,
2504 (GDestroyNotify) g_free);
2509 mime_info_cache_free (MimeInfoCache *cache)
2514 g_list_foreach (cache->dirs,
2515 (GFunc) mime_info_cache_dir_free,
2517 g_list_free (cache->dirs);
2518 g_hash_table_destroy (cache->global_defaults_cache);
2523 * mime_info_cache_reload:
2524 * @dir: directory path which needs reloading.
2526 * Reload the mime information for the @dir.
2529 mime_info_cache_reload (const char *dir)
2531 /* FIXME: just reload the dir that needs reloading,
2532 * don't blow the whole cache
2534 if (mime_info_cache != NULL)
2536 G_LOCK (mime_info_cache);
2537 mime_info_cache_free (mime_info_cache);
2538 mime_info_cache = NULL;
2539 G_UNLOCK (mime_info_cache);
2544 append_desktop_entry (GList *list,
2545 const char *desktop_entry,
2546 GList *removed_entries)
2548 /* Add if not already in list, and valid */
2549 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2550 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2551 list = g_list_prepend (list, g_strdup (desktop_entry));
2557 * get_all_desktop_entries_for_mime_type:
2558 * @mime_type: a mime type.
2559 * @except: NULL or a strv list
2561 * Returns all the desktop ids for @mime_type. The desktop files
2562 * are listed in an order so that default applications are listed before
2563 * non-default ones, and handlers for inherited mimetypes are listed
2564 * after the base ones.
2566 * Optionally doesn't list the desktop ids given in the @except
2568 * Return value: a #GList containing the desktop ids which claim
2569 * to handle @mime_type.
2572 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2573 const char **except)
2575 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2576 MimeInfoCacheDir *dir;
2579 char **default_entries;
2580 char **removed_associations;
2585 mime_info_cache_init ();
2587 /* collect all ancestors */
2588 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2589 array = g_ptr_array_new ();
2590 for (i = 0; mime_types[i]; i++)
2591 g_ptr_array_add (array, mime_types[i]);
2592 g_free (mime_types);
2593 for (i = 0; i < array->len; i++)
2595 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2596 for (j = 0; anc[j]; j++)
2598 for (k = 0; k < array->len; k++)
2600 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2603 if (k == array->len) /* not found */
2604 g_ptr_array_add (array, g_strdup (anc[j]));
2608 g_ptr_array_add (array, NULL);
2609 mime_types = (char **)g_ptr_array_free (array, FALSE);
2611 G_LOCK (mime_info_cache);
2613 removed_entries = NULL;
2614 desktop_entries = NULL;
2616 for (i = 0; except != NULL && except[i] != NULL; i++)
2617 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2619 for (i = 0; mime_types[i] != NULL; i++)
2621 mime_type = mime_types[i];
2623 /* Go through all apps listed as defaults */
2624 for (dir_list = mime_info_cache->dirs;
2626 dir_list = dir_list->next)
2628 dir = dir_list->data;
2630 /* First added associations from mimeapps.list */
2631 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2632 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2633 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2635 /* Then removed associations from mimeapps.list */
2636 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2637 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2638 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2640 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2641 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2642 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2643 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2646 /* Go through all entries that support the mimetype */
2647 for (dir_list = mime_info_cache->dirs;
2649 dir_list = dir_list->next)
2651 dir = dir_list->data;
2653 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2654 for (tmp = list; tmp != NULL; tmp = tmp->next)
2655 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2659 G_UNLOCK (mime_info_cache);
2661 g_strfreev (mime_types);
2663 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2664 g_list_free (removed_entries);
2666 desktop_entries = g_list_reverse (desktop_entries);
2668 return desktop_entries;
2671 /* GDesktopAppInfoLookup interface: */
2673 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2674 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2677 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2682 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2683 * @lookup: a #GDesktopAppInfoLookup
2684 * @uri_scheme: a string containing a URI scheme.
2686 * Gets the default application for launching applications
2687 * using this URI scheme for a particular GDesktopAppInfoLookup
2690 * The GDesktopAppInfoLookup interface and this function is used
2691 * to implement g_app_info_get_default_for_uri_scheme() backends
2692 * in a GIO module. There is no reason for applications to use it
2693 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2695 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2698 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2699 const char *uri_scheme)
2701 GDesktopAppInfoLookupIface *iface;
2703 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2705 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2707 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2710 #define __G_DESKTOP_APP_INFO_C__
2711 #include "gioaliasdef.c"