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"
48 * SECTION:gdesktopappinfo
49 * @short_description: Application information from desktop files
50 * @include: gio/gdesktopappinfo.h
52 * #GDesktopAppInfo is an implementation of #GAppInfo based on
55 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
56 * the UNIX-specific GIO interfaces, thus you have to use the
57 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
60 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
61 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
62 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
63 #define MIME_CACHE_GROUP "MIME Cache"
64 #define FULL_NAME_KEY "X-GNOME-FullName"
66 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
67 static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type,
69 static void mime_info_cache_reload (const char *dir);
70 static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
76 * Information about an installed application from a desktop file.
78 struct _GDesktopAppInfo
80 GObject parent_instance;
86 /* FIXME: what about GenericName ? */
101 guint startup_notify : 1;
103 /* FIXME: what about StartupWMClass ? */
106 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
107 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
108 g_desktop_app_info_iface_init))
111 search_path_init (gpointer data)
114 const char * const *data_dirs;
115 const char *user_data_dir;
118 data_dirs = g_get_system_data_dirs ();
119 length = g_strv_length ((char **) data_dirs);
121 args = g_new (char *, length + 2);
124 user_data_dir = g_get_user_data_dir ();
125 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
126 for (i = 0; i < length; i++)
127 args[j++] = g_build_filename (data_dirs[i],
128 "applications", NULL);
134 static const char * const *
135 get_applications_search_path (void)
137 static GOnce once_init = G_ONCE_INIT;
138 return g_once (&once_init, search_path_init, NULL);
142 g_desktop_app_info_finalize (GObject *object)
144 GDesktopAppInfo *info;
146 info = G_DESKTOP_APP_INFO (object);
148 g_free (info->desktop_id);
149 g_free (info->filename);
151 g_free (info->fullname);
152 g_free (info->comment);
153 g_free (info->icon_name);
155 g_object_unref (info->icon);
156 g_strfreev (info->only_show_in);
157 g_strfreev (info->not_show_in);
158 g_free (info->try_exec);
160 g_free (info->binary);
163 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
167 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
169 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
171 gobject_class->finalize = g_desktop_app_info_finalize;
175 g_desktop_app_info_init (GDesktopAppInfo *local)
180 binary_from_exec (const char *exec)
182 const char *p, *start;
188 while (*p != ' ' && *p != 0)
191 return g_strndup (start, p - start);
196 * g_desktop_app_info_new_from_keyfile:
197 * @key_file: an opened #GKeyFile
199 * Creates a new #GDesktopAppInfo.
201 * Returns: a new #GDesktopAppInfo or %NULL on error.
206 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
208 GDesktopAppInfo *info;
213 start_group = g_key_file_get_start_group (key_file);
214 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
216 g_free (start_group);
219 g_free (start_group);
221 type = g_key_file_get_string (key_file,
222 G_KEY_FILE_DESKTOP_GROUP,
223 G_KEY_FILE_DESKTOP_KEY_TYPE,
225 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
232 try_exec = g_key_file_get_string (key_file,
233 G_KEY_FILE_DESKTOP_GROUP,
234 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
236 if (try_exec && try_exec[0] != '\0')
239 t = g_find_program_in_path (try_exec);
248 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
249 info->filename = NULL;
251 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
252 info->fullname = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, FULL_NAME_KEY, NULL, NULL);
253 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
254 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
255 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
256 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);
257 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);
258 info->try_exec = try_exec;
259 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
260 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
261 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
262 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
263 info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
264 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
269 if (g_path_is_absolute (info->icon_name))
273 file = g_file_new_for_path (info->icon_name);
274 info->icon = g_file_icon_new (file);
275 g_object_unref (file);
281 /* Work around a common mistake in desktop files */
282 if ((p = strrchr (info->icon_name, '.')) != NULL &&
283 (strcmp (p, ".png") == 0 ||
284 strcmp (p, ".xpm") == 0 ||
285 strcmp (p, ".svg") == 0))
288 info->icon = g_themed_icon_new (info->icon_name);
293 info->binary = binary_from_exec (info->exec);
295 if (info->path && info->path[0] == '\0')
305 * g_desktop_app_info_new_from_filename:
306 * @filename: the path of a desktop file, in the GLib filename encoding
308 * Creates a new #GDesktopAppInfo.
310 * Returns: a new #GDesktopAppInfo or %NULL on error.
313 g_desktop_app_info_new_from_filename (const char *filename)
316 GDesktopAppInfo *info = NULL;
318 key_file = g_key_file_new ();
320 if (g_key_file_load_from_file (key_file,
325 info = g_desktop_app_info_new_from_keyfile (key_file);
327 info->filename = g_strdup (filename);
330 g_key_file_free (key_file);
336 * g_desktop_app_info_new:
337 * @desktop_id: the desktop file id
339 * Creates a new #GDesktopAppInfo based on a desktop file id.
341 * A desktop file id is the basename of the desktop file, including the
342 * .desktop extension. GIO is looking for a desktop file with this name
343 * in the <filename>applications</filename> subdirectories of the XDG data
344 * directories (i.e. the directories specified in the
345 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
346 * variables). GIO also supports the prefix-to-subdirectory mapping that is
347 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
348 * (i.e. a desktop id of kde-foo.desktop will match
349 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
351 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
354 g_desktop_app_info_new (const char *desktop_id)
356 GDesktopAppInfo *appinfo;
357 const char * const *dirs;
361 dirs = get_applications_search_path ();
363 basename = g_strdup (desktop_id);
365 for (i = 0; dirs[i] != NULL; i++)
370 filename = g_build_filename (dirs[i], desktop_id, NULL);
371 appinfo = g_desktop_app_info_new_from_filename (filename);
377 while ((p = strchr (p, '-')) != NULL)
381 filename = g_build_filename (dirs[i], basename, NULL);
382 appinfo = g_desktop_app_info_new_from_filename (filename);
397 appinfo->desktop_id = g_strdup (desktop_id);
399 if (g_desktop_app_info_get_is_hidden (appinfo))
401 g_object_unref (appinfo);
409 g_desktop_app_info_dup (GAppInfo *appinfo)
411 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
412 GDesktopAppInfo *new_info;
414 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
416 new_info->filename = g_strdup (info->filename);
417 new_info->desktop_id = g_strdup (info->desktop_id);
419 new_info->name = g_strdup (info->name);
420 new_info->fullname = g_strdup (info->fullname);
421 new_info->comment = g_strdup (info->comment);
422 new_info->nodisplay = info->nodisplay;
423 new_info->icon_name = g_strdup (info->icon_name);
425 new_info->icon = g_object_ref (info->icon);
426 new_info->only_show_in = g_strdupv (info->only_show_in);
427 new_info->not_show_in = g_strdupv (info->not_show_in);
428 new_info->try_exec = g_strdup (info->try_exec);
429 new_info->exec = g_strdup (info->exec);
430 new_info->binary = g_strdup (info->binary);
431 new_info->path = g_strdup (info->path);
432 new_info->hidden = info->hidden;
433 new_info->terminal = info->terminal;
434 new_info->startup_notify = info->startup_notify;
436 return G_APP_INFO (new_info);
440 g_desktop_app_info_equal (GAppInfo *appinfo1,
443 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
444 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
446 if (info1->desktop_id == NULL ||
447 info2->desktop_id == NULL)
448 return info1 == info2;
450 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
454 g_desktop_app_info_get_id (GAppInfo *appinfo)
456 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
458 return info->desktop_id;
462 g_desktop_app_info_get_name (GAppInfo *appinfo)
464 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
466 if (info->name == NULL)
472 g_desktop_app_info_get_display_name (GAppInfo *appinfo)
474 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
476 if (info->fullname == NULL)
477 return g_desktop_app_info_get_name (appinfo);
478 return info->fullname;
482 * g_desktop_app_info_get_is_hidden:
483 * @info: a #GDesktopAppInfo.
485 * A desktop file is hidden if the Hidden key in it is
488 * Returns: %TRUE if hidden, %FALSE otherwise.
491 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
497 * g_desktop_app_info_get_filename:
498 * @info: a #GDesktopAppInfo
500 * When @info was created from a known filename, return it. In some
501 * situations such as the #GDesktopAppInfo returned from
502 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
504 * Returns: The full path to the file for @info, or %NULL if not known.
508 g_desktop_app_info_get_filename (GDesktopAppInfo *info)
510 return info->filename;
514 g_desktop_app_info_get_description (GAppInfo *appinfo)
516 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
518 return info->comment;
522 g_desktop_app_info_get_executable (GAppInfo *appinfo)
524 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
530 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
532 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
538 g_desktop_app_info_get_icon (GAppInfo *appinfo)
540 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
546 expand_macro_single (char macro, char *uri)
552 file = g_file_new_for_uri (uri);
553 path = g_file_get_path (file);
554 g_object_unref (file);
560 result = g_shell_quote (uri);
565 result = g_shell_quote (path);
571 name = g_path_get_dirname (path);
572 result = g_shell_quote (name);
580 name = g_path_get_basename (path);
581 result = g_shell_quote (name);
593 expand_macro (char macro,
595 GDesktopAppInfo *info,
598 GList *uris = *uri_list;
600 gboolean force_file_uri;
601 char force_file_uri_macro;
604 g_return_if_fail (exec != NULL);
606 /* On %u and %U, pass POSIX file path pointing to the URI via
607 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
608 * running or the URI doesn't have a POSIX file path via FUSE
609 * we'll just pass the URI.
611 force_file_uri_macro = macro;
612 force_file_uri = FALSE;
618 force_file_uri_macro = 'f';
619 force_file_uri = TRUE;
622 force_file_uri_macro = 'F';
623 force_file_uri = TRUE;
639 if (!force_file_uri ||
640 /* Pass URI if it contains an anchor */
641 strchr (uri, '#') != NULL)
643 expanded = expand_macro_single (macro, uri);
647 expanded = expand_macro_single (force_file_uri_macro, uri);
648 if (expanded == NULL)
649 expanded = expand_macro_single (macro, uri);
654 g_string_append (exec, expanded);
670 if (!force_file_uri ||
671 /* Pass URI if it contains an anchor */
672 strchr (uri, '#') != NULL)
674 expanded = expand_macro_single (macro, uri);
678 expanded = expand_macro_single (force_file_uri_macro, uri);
679 if (expanded == NULL)
680 expanded = expand_macro_single (macro, uri);
685 g_string_append (exec, expanded);
691 if (uris != NULL && expanded)
692 g_string_append_c (exec, ' ');
700 g_string_append (exec, "--icon ");
701 expanded = g_shell_quote (info->icon_name);
702 g_string_append (exec, expanded);
710 expanded = g_shell_quote (info->name);
711 g_string_append (exec, expanded);
719 expanded = g_shell_quote (info->filename);
720 g_string_append (exec, expanded);
725 case 'm': /* deprecated */
729 g_string_append_c (exec, '%');
737 expand_application_parameters (GDesktopAppInfo *info,
743 GList *uri_list = *uris;
744 const char *p = info->exec;
745 GString *expanded_exec;
748 if (info->exec == NULL)
750 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
751 _("Desktop file didn't specify Exec field"));
755 expanded_exec = g_string_new (NULL);
759 if (p[0] == '%' && p[1] != '\0')
761 expand_macro (p[1], expanded_exec, info, uris);
765 g_string_append_c (expanded_exec, *p);
770 /* No file substitutions */
771 if (uri_list == *uris && uri_list != NULL)
773 /* If there is no macro default to %f. This is also what KDE does */
774 g_string_append_c (expanded_exec, ' ');
775 expand_macro ('f', expanded_exec, info, uris);
778 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
779 g_string_free (expanded_exec, TRUE);
784 prepend_terminal_to_vector (int *argc,
791 char **term_argv = NULL;
796 g_return_val_if_fail (argc != NULL, FALSE);
797 g_return_val_if_fail (argv != NULL, FALSE);
805 /* compute size if not given */
808 for (i = 0; the_argv[i] != NULL; i++)
814 term_argv = g_new0 (char *, 3);
816 check = g_find_program_in_path ("gnome-terminal");
819 term_argv[0] = check;
820 /* Note that gnome-terminal takes -x and
821 * as -e in gnome-terminal is broken we use that. */
822 term_argv[1] = g_strdup ("-x");
827 check = g_find_program_in_path ("nxterm");
829 check = g_find_program_in_path ("color-xterm");
831 check = g_find_program_in_path ("rxvt");
833 check = g_find_program_in_path ("xterm");
835 check = g_find_program_in_path ("dtterm");
838 check = g_strdup ("xterm");
839 g_warning ("couldn't find a terminal, falling back to xterm");
841 term_argv[0] = check;
842 term_argv[1] = g_strdup ("-e");
845 real_argc = term_argc + *argc;
846 real_argv = g_new (char *, real_argc + 1);
848 for (i = 0; i < term_argc; i++)
849 real_argv[i] = term_argv[i];
851 for (j = 0; j < *argc; j++, i++)
852 real_argv[i] = (char *)the_argv[j];
860 /* we use g_free here as we sucked all the inner strings
861 * out from it into real_argv */
866 #endif /* G_OS_WIN32 */
870 uri_list_segment_to_files (GList *start,
877 while (start != NULL && start != end)
879 file = g_file_new_for_uri ((char *)start->data);
880 res = g_list_prepend (res, file);
884 return g_list_reverse (res);
895 child_setup (gpointer user_data)
897 ChildSetupData *data = user_data;
900 g_setenv ("DISPLAY", data->display, TRUE);
903 g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
905 if (data->desktop_file)
909 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
911 g_snprintf (pid, 20, "%ld", (long)getpid ());
912 g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
917 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
919 GAppLaunchContext *launch_context,
922 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
923 gboolean completed = FALSE;
925 GList *launched_files;
930 g_return_val_if_fail (appinfo != NULL, FALSE);
937 if (!expand_application_parameters (info, &uris,
938 &argc, &argv, error))
941 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
943 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
944 _("Unable to find terminal required for application"));
950 data.desktop_file = info->filename;
954 launched_files = uri_list_segment_to_files (old_uris, uris);
956 data.display = g_app_launch_context_get_display (launch_context,
960 if (info->startup_notify)
961 data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
964 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
965 g_list_free (launched_files);
968 if (!g_spawn_async (info->path,
978 g_app_launch_context_launch_failed (launch_context, data.sn_id);
981 g_free (data.display);
987 g_free (data.display);
992 while (uris != NULL);
1003 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
1005 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1007 return info->exec &&
1008 ((strstr (info->exec, "%u") != NULL) ||
1009 (strstr (info->exec, "%U") != NULL));
1013 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1015 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1017 return info->exec &&
1018 ((strstr (info->exec, "%f") != NULL) ||
1019 (strstr (info->exec, "%F") != NULL));
1023 g_desktop_app_info_launch (GAppInfo *appinfo,
1025 GAppLaunchContext *launch_context,
1035 uri = g_file_get_uri (files->data);
1036 uris = g_list_prepend (uris, uri);
1037 files = files->next;
1040 uris = g_list_reverse (uris);
1042 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1044 g_list_foreach (uris, (GFunc)g_free, NULL);
1050 G_LOCK_DEFINE_STATIC (g_desktop_env);
1051 static gchar *g_desktop_env = NULL;
1054 * g_desktop_app_info_set_desktop_env:
1055 * @desktop_env: a string specifying what desktop this is
1057 * Sets the name of the desktop that the application is running in.
1058 * This is used by g_app_info_should_show() to evaluate the
1059 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1060 * desktop entry fields.
1062 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1063 * Menu specification</ulink> recognizes the following:
1065 * <member>GNOME</member>
1066 * <member>KDE</member>
1067 * <member>ROX</member>
1068 * <member>XFCE</member>
1069 * <member>Old</member>
1072 * Should be called only once; subsequent calls are ignored.
1075 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1077 G_LOCK (g_desktop_env);
1079 g_desktop_env = g_strdup (desktop_env);
1080 G_UNLOCK (g_desktop_env);
1084 g_desktop_app_info_should_show (GAppInfo *appinfo)
1086 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1088 const gchar *desktop_env;
1091 if (info->nodisplay)
1094 G_LOCK (g_desktop_env);
1095 desktop_env = g_desktop_env;
1096 G_UNLOCK (g_desktop_env);
1098 if (info->only_show_in)
1100 if (desktop_env == NULL)
1104 for (i = 0; info->only_show_in[i] != NULL; i++)
1106 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1116 if (info->not_show_in && desktop_env)
1118 for (i = 0; info->not_show_in[i] != NULL; i++)
1120 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1134 ensure_dir (DirType type,
1137 char *path, *display_name;
1140 if (type == APP_DIR)
1141 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1143 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1146 if (g_mkdir_with_parents (path, 0700) == 0)
1150 display_name = g_filename_display_name (path);
1151 if (type == APP_DIR)
1152 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1153 _("Can't create user application configuration folder %s: %s"),
1154 display_name, g_strerror (errsv));
1156 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1157 _("Can't create user MIME configuration folder %s: %s"),
1158 display_name, g_strerror (errsv));
1160 g_free (display_name);
1167 update_mimeapps_list (const char *desktop_id,
1168 const char *content_type,
1169 gboolean add_as_default,
1170 gboolean add_non_default,
1174 char *dirname, *filename;
1176 gboolean load_succeeded, res;
1177 char **old_list, **list;
1178 GList *system_list, *l;
1179 gsize length, data_size;
1182 char **content_types;
1184 /* Don't add both at start and end */
1185 g_assert (!(add_as_default && add_non_default));
1187 dirname = ensure_dir (APP_DIR, error);
1191 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1194 key_file = g_key_file_new ();
1195 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1196 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1198 g_key_file_free (key_file);
1199 key_file = g_key_file_new ();
1204 content_types = g_new (char *, 2);
1205 content_types[0] = g_strdup (content_type);
1206 content_types[1] = NULL;
1210 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1213 for (k = 0; content_types && content_types[k]; k++)
1215 /* Add to the right place in the list */
1218 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1219 content_types[k], &length, NULL);
1221 list = g_new (char *, 1 + length + 1);
1225 list[i++] = g_strdup (desktop_id);
1228 for (j = 0; old_list[j] != NULL; j++)
1230 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1231 list[i++] = g_strdup (old_list[j]);
1232 else if (add_non_default)
1234 /* If adding as non-default, and it's already in,
1235 don't change order of desktop ids */
1236 add_non_default = FALSE;
1237 list[i++] = g_strdup (old_list[j]);
1242 if (add_non_default)
1244 /* We're adding as non-default, and it wasn't already in the list,
1245 so we add at the end. But to avoid listing the app before the
1246 current system default (thus changing the default) we have to
1247 add the current list of (not yet listed) apps before it. */
1249 list[i] = NULL; /* Terminate current list so we can use it */
1250 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1252 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1254 for (l = system_list; l != NULL; l = l->next)
1256 list[i++] = l->data; /* no strdup, taking ownership */
1257 if (g_strcmp0 (l->data, desktop_id) == 0)
1258 add_non_default = FALSE;
1260 g_list_free (system_list);
1262 if (add_non_default)
1263 list[i++] = g_strdup (desktop_id);
1268 g_strfreev (old_list);
1270 if (list[0] == NULL || desktop_id == NULL)
1271 g_key_file_remove_key (key_file,
1272 ADDED_ASSOCIATIONS_GROUP,
1276 g_key_file_set_string_list (key_file,
1277 ADDED_ASSOCIATIONS_GROUP,
1279 (const char * const *)list, i);
1286 /* reuse the list from above */
1290 g_strfreev (content_types);
1291 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1294 for (k = 0; content_types && content_types[k]; k++)
1296 /* Remove from removed associations group (unless remove) */
1299 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1300 content_types[k], &length, NULL);
1302 list = g_new (char *, 1 + length + 1);
1306 list[i++] = g_strdup (desktop_id);
1309 for (j = 0; old_list[j] != NULL; j++)
1311 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1312 list[i++] = g_strdup (old_list[j]);
1317 g_strfreev (old_list);
1319 if (list[0] == NULL || desktop_id == NULL)
1320 g_key_file_remove_key (key_file,
1321 REMOVED_ASSOCIATIONS_GROUP,
1325 g_key_file_set_string_list (key_file,
1326 REMOVED_ASSOCIATIONS_GROUP,
1328 (const char * const *)list, i);
1333 g_strfreev (content_types);
1335 data = g_key_file_to_data (key_file, &data_size, error);
1336 g_key_file_free (key_file);
1338 res = g_file_set_contents (filename, data, data_size, error);
1340 mime_info_cache_reload (NULL);
1349 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1350 const char *content_type,
1353 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1355 if (!g_desktop_app_info_ensure_saved (info, error))
1358 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1362 update_program_done (GPid pid,
1366 /* Did the application exit correctly */
1367 if (WIFEXITED (status) &&
1368 WEXITSTATUS (status) == 0)
1370 /* Here we could clean out any caches in use */
1375 run_update_command (char *command,
1384 GError *error = NULL;
1387 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1389 if (g_spawn_async ("/", argv,
1391 G_SPAWN_SEARCH_PATH |
1392 G_SPAWN_STDOUT_TO_DEV_NULL |
1393 G_SPAWN_STDERR_TO_DEV_NULL |
1394 G_SPAWN_DO_NOT_REAP_CHILD,
1395 NULL, NULL, /* No setup function */
1398 g_child_watch_add (pid, update_program_done, NULL);
1401 /* If we get an error at this point, it's quite likely the user doesn't
1402 * have an installed copy of either 'update-mime-database' or
1403 * 'update-desktop-database'. I don't think we want to popup an error
1404 * dialog at this point, so we just do a g_warning to give the user a
1405 * chance of debugging it.
1407 g_warning ("%s", error->message);
1414 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1415 const char *extension,
1418 char *filename, *basename, *mimetype;
1422 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1425 dirname = ensure_dir (MIMETYPE_DIR, error);
1429 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1430 filename = g_build_filename (dirname, basename, NULL);
1434 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1436 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1441 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1442 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1443 " <mime-type type=\"%s\">\n"
1444 " <comment>%s document</comment>\n"
1445 " <glob pattern=\"*.%s\"/>\n"
1447 "</mime-info>\n", mimetype, extension, extension);
1449 g_file_set_contents (filename, contents, -1, NULL);
1452 run_update_command ("update-mime-database", "mime");
1456 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1466 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1467 const char *content_type,
1470 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1472 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1475 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1479 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1485 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1486 const char *content_type,
1489 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1491 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1494 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1498 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1504 char *data, *desktop_id;
1509 if (info->filename != NULL)
1512 /* This is only used for object created with
1513 * g_app_info_create_from_commandline. All other
1514 * object should have a filename
1517 dirname = ensure_dir (APP_DIR, error);
1521 key_file = g_key_file_new ();
1523 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1524 "Encoding", "UTF-8");
1525 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1526 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1527 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1528 G_KEY_FILE_DESKTOP_KEY_TYPE,
1529 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1531 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1532 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1534 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1535 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1537 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1538 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1540 if (info->fullname != NULL)
1541 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1542 FULL_NAME_KEY, info->fullname);
1544 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1545 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1547 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1548 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1550 data = g_key_file_to_data (key_file, &data_size, NULL);
1551 g_key_file_free (key_file);
1553 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1554 filename = g_build_filename (dirname, desktop_id, NULL);
1555 g_free (desktop_id);
1558 fd = g_mkstemp (filename);
1563 display_name = g_filename_display_name (filename);
1564 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1565 _("Can't create user desktop file %s"), display_name);
1566 g_free (display_name);
1572 desktop_id = g_path_get_basename (filename);
1576 res = g_file_set_contents (filename, data, data_size, error);
1579 g_free (desktop_id);
1584 info->filename = filename;
1585 info->desktop_id = desktop_id;
1587 run_update_command ("update-desktop-database", "applications");
1593 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1595 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1599 if (strstr (info->filename, "/userapp-"))
1600 return g_access (info->filename, W_OK) == 0;
1607 g_desktop_app_info_delete (GAppInfo *appinfo)
1609 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1613 if (g_remove (info->filename) == 0)
1615 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1617 g_free (info->filename);
1618 info->filename = NULL;
1619 g_free (info->desktop_id);
1620 info->desktop_id = NULL;
1630 * g_app_info_create_from_commandline:
1631 * @commandline: the commandline to use
1632 * @application_name: (allow-none): the application name, or %NULL to use @commandline
1633 * @flags: flags that can specify details of the created #GAppInfo
1634 * @error: a #GError location to store the error occuring, %NULL to ignore.
1636 * Creates a new #GAppInfo from the given information.
1638 * Returns: (transfer full): new #GAppInfo for given command.
1641 g_app_info_create_from_commandline (const char *commandline,
1642 const char *application_name,
1643 GAppInfoCreateFlags flags,
1648 GDesktopAppInfo *info;
1650 g_return_val_if_fail (commandline, NULL);
1652 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1654 info->filename = NULL;
1655 info->desktop_id = NULL;
1657 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1658 info->startup_notify = flags & G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION;
1659 info->hidden = FALSE;
1660 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1661 info->exec = g_strconcat (commandline, " %u", NULL);
1663 info->exec = g_strconcat (commandline, " %f", NULL);
1664 info->nodisplay = TRUE;
1665 info->binary = binary_from_exec (info->exec);
1667 if (application_name)
1668 info->name = g_strdup (application_name);
1671 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1672 split = g_strsplit (commandline, " ", 2);
1673 basename = split[0] ? g_path_get_basename (split[0]) : NULL;
1675 info->name = basename;
1676 if (info->name == NULL)
1677 info->name = g_strdup ("custom");
1679 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1681 return G_APP_INFO (info);
1685 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1687 iface->dup = g_desktop_app_info_dup;
1688 iface->equal = g_desktop_app_info_equal;
1689 iface->get_id = g_desktop_app_info_get_id;
1690 iface->get_name = g_desktop_app_info_get_name;
1691 iface->get_description = g_desktop_app_info_get_description;
1692 iface->get_executable = g_desktop_app_info_get_executable;
1693 iface->get_icon = g_desktop_app_info_get_icon;
1694 iface->launch = g_desktop_app_info_launch;
1695 iface->supports_uris = g_desktop_app_info_supports_uris;
1696 iface->supports_files = g_desktop_app_info_supports_files;
1697 iface->launch_uris = g_desktop_app_info_launch_uris;
1698 iface->should_show = g_desktop_app_info_should_show;
1699 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1700 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1701 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1702 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1703 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1704 iface->can_delete = g_desktop_app_info_can_delete;
1705 iface->do_delete = g_desktop_app_info_delete;
1706 iface->get_commandline = g_desktop_app_info_get_commandline;
1707 iface->get_display_name = g_desktop_app_info_get_display_name;
1711 app_info_in_list (GAppInfo *info,
1714 while (list != NULL)
1716 if (g_app_info_equal (info, list->data))
1725 * g_app_info_get_all_for_type:
1726 * @content_type: the content type to find a #GAppInfo for
1728 * Gets a list of all #GAppInfo<!-- -->s for a given content type.
1730 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfo<!-- -->s for given @content_type
1731 * or %NULL on error.
1734 g_app_info_get_all_for_type (const char *content_type)
1736 GList *desktop_entries, *l;
1738 GDesktopAppInfo *info;
1740 g_return_val_if_fail (content_type != NULL, NULL);
1742 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1745 for (l = desktop_entries; l != NULL; l = l->next)
1747 char *desktop_entry = l->data;
1749 info = g_desktop_app_info_new (desktop_entry);
1752 if (app_info_in_list (G_APP_INFO (info), infos))
1753 g_object_unref (info);
1755 infos = g_list_prepend (infos, info);
1757 g_free (desktop_entry);
1760 g_list_free (desktop_entries);
1762 return g_list_reverse (infos);
1766 * g_app_info_reset_type_associations:
1767 * @content_type: a content type
1769 * Removes all changes to the type associations done by
1770 * g_app_info_set_as_default_for_type(),
1771 * g_app_info_set_as_default_for_extension(),
1772 * g_app_info_add_supports_type() or g_app_info_remove_supports_type().
1777 g_app_info_reset_type_associations (const char *content_type)
1779 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1783 * g_app_info_get_default_for_type:
1784 * @content_type: the content type to find a #GAppInfo for
1785 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1788 * Gets the #GAppInfo that corresponds to a given content type.
1790 * Returns: #GAppInfo for given @content_type or %NULL on error.
1793 g_app_info_get_default_for_type (const char *content_type,
1794 gboolean must_support_uris)
1796 GList *desktop_entries, *l;
1799 g_return_val_if_fail (content_type != NULL, NULL);
1801 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1804 for (l = desktop_entries; l != NULL; l = l->next)
1806 char *desktop_entry = l->data;
1808 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1811 if (must_support_uris && !g_app_info_supports_uris (info))
1813 g_object_unref (info);
1821 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1822 g_list_free (desktop_entries);
1828 * g_app_info_get_default_for_uri_scheme:
1829 * @uri_scheme: a string containing a URI scheme.
1831 * Gets the default application for launching applications
1832 * using this URI scheme. A URI scheme is the initial part
1833 * of the URI, up to but not including the ':', e.g. "http",
1836 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1839 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1841 static gsize lookup = 0;
1843 if (g_once_init_enter (&lookup))
1845 gsize setup_value = 1;
1846 GDesktopAppInfoLookup *lookup_instance;
1847 const char *use_this;
1848 GIOExtensionPoint *ep;
1849 GIOExtension *extension;
1852 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1854 /* Ensure vfs in modules loaded */
1855 _g_io_modules_ensure_loaded ();
1857 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1859 lookup_instance = NULL;
1862 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1864 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1867 if (lookup_instance == NULL)
1869 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1871 extension = l->data;
1872 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1873 if (lookup_instance != NULL)
1878 if (lookup_instance != NULL)
1879 setup_value = (gsize)lookup_instance;
1881 g_once_init_leave (&lookup, setup_value);
1887 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1893 get_apps_from_dir (GHashTable *apps,
1894 const char *dirname,
1898 const char *basename;
1899 char *filename, *subprefix, *desktop_id;
1901 GDesktopAppInfo *appinfo;
1903 dir = g_dir_open (dirname, 0, NULL);
1906 while ((basename = g_dir_read_name (dir)) != NULL)
1908 filename = g_build_filename (dirname, basename, NULL);
1909 if (g_str_has_suffix (basename, ".desktop"))
1911 desktop_id = g_strconcat (prefix, basename, NULL);
1913 /* Use _extended so we catch NULLs too (hidden) */
1914 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1916 appinfo = g_desktop_app_info_new_from_filename (filename);
1919 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1921 g_object_unref (appinfo);
1926 if (appinfo || hidden)
1928 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1932 /* Reuse instead of strdup here */
1933 appinfo->desktop_id = desktop_id;
1938 g_free (desktop_id);
1942 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1944 subprefix = g_strconcat (prefix, basename, "-", NULL);
1945 get_apps_from_dir (apps, filename, subprefix);
1957 * g_app_info_get_all:
1959 * Gets a list of all of the applications currently registered
1962 * For desktop files, this includes applications that have
1963 * <literal>NoDisplay=true</literal> set or are excluded from
1964 * display by means of <literal>OnlyShowIn</literal> or
1965 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1966 * The returned list does not include applications which have
1967 * the <literal>Hidden</literal> key set.
1969 * Returns: (element-type GAppInfo) (transfer full): a newly allocated #GList of references to #GAppInfo<!---->s.
1972 g_app_info_get_all (void)
1974 const char * const *dirs;
1976 GHashTableIter iter;
1981 dirs = get_applications_search_path ();
1983 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1987 for (i = 0; dirs[i] != NULL; i++)
1988 get_apps_from_dir (apps, dirs[i], "");
1992 g_hash_table_iter_init (&iter, apps);
1993 while (g_hash_table_iter_next (&iter, NULL, &value))
1996 infos = g_list_prepend (infos, value);
1999 g_hash_table_destroy (apps);
2001 return g_list_reverse (infos);
2004 /* Cacheing of mimeinfo.cache and defaults.list files */
2008 GHashTable *mime_info_cache_map;
2009 GHashTable *defaults_list_map;
2010 GHashTable *mimeapps_list_added_map;
2011 GHashTable *mimeapps_list_removed_map;
2012 time_t mime_info_cache_timestamp;
2013 time_t defaults_list_timestamp;
2014 time_t mimeapps_list_timestamp;
2018 GList *dirs; /* mimeinfo.cache and defaults.list */
2019 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2020 time_t last_stat_time;
2021 guint should_ping_mime_monitor : 1;
2024 static MimeInfoCache *mime_info_cache = NULL;
2025 G_LOCK_DEFINE_STATIC (mime_info_cache);
2027 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2028 const char *mime_type,
2029 char **new_desktop_file_ids);
2031 static MimeInfoCache * mime_info_cache_new (void);
2034 destroy_info_cache_value (gpointer key,
2038 g_list_foreach (value, (GFunc)g_free, NULL);
2039 g_list_free (value);
2043 destroy_info_cache_map (GHashTable *info_cache_map)
2045 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2046 g_hash_table_destroy (info_cache_map);
2050 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2051 const char *cache_file,
2057 filename = g_build_filename (dir->path, cache_file, NULL);
2059 if (g_stat (filename, &buf) < 0)
2066 if (buf.st_mtime != *timestamp)
2072 /* Call with lock held */
2074 remove_all (gpointer key,
2083 mime_info_cache_blow_global_cache (void)
2085 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2090 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2094 gchar *filename, **mime_types;
2101 if (dir->mime_info_cache_map != NULL &&
2102 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2103 &dir->mime_info_cache_timestamp))
2106 if (dir->mime_info_cache_map != NULL)
2107 destroy_info_cache_map (dir->mime_info_cache_map);
2109 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2110 (GDestroyNotify) g_free,
2113 key_file = g_key_file_new ();
2115 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2117 if (g_stat (filename, &buf) < 0)
2120 if (dir->mime_info_cache_timestamp > 0)
2121 mime_info_cache->should_ping_mime_monitor = TRUE;
2123 dir->mime_info_cache_timestamp = buf.st_mtime;
2125 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2130 if (load_error != NULL)
2133 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2136 if (load_error != NULL)
2139 for (i = 0; mime_types[i] != NULL; i++)
2141 gchar **desktop_file_ids;
2142 char *unaliased_type;
2143 desktop_file_ids = g_key_file_get_string_list (key_file,
2149 if (desktop_file_ids == NULL)
2152 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2153 mime_info_cache_dir_add_desktop_entries (dir,
2156 g_free (unaliased_type);
2158 g_strfreev (desktop_file_ids);
2161 g_strfreev (mime_types);
2162 g_key_file_free (key_file);
2167 g_key_file_free (key_file);
2169 if (mime_types != NULL)
2170 g_strfreev (mime_types);
2173 g_error_free (load_error);
2177 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2181 gchar *filename, **mime_types;
2182 char *unaliased_type;
2183 char **desktop_file_ids;
2190 if (dir->defaults_list_map != NULL &&
2191 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2192 &dir->defaults_list_timestamp))
2195 if (dir->defaults_list_map != NULL)
2196 g_hash_table_destroy (dir->defaults_list_map);
2197 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2198 g_free, (GDestroyNotify)g_strfreev);
2201 key_file = g_key_file_new ();
2203 filename = g_build_filename (dir->path, "defaults.list", NULL);
2204 if (g_stat (filename, &buf) < 0)
2207 if (dir->defaults_list_timestamp > 0)
2208 mime_info_cache->should_ping_mime_monitor = TRUE;
2210 dir->defaults_list_timestamp = buf.st_mtime;
2212 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2216 if (load_error != NULL)
2219 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2221 if (mime_types != NULL)
2223 for (i = 0; mime_types[i] != NULL; i++)
2225 desktop_file_ids = g_key_file_get_string_list (key_file,
2226 DEFAULT_APPLICATIONS_GROUP,
2230 if (desktop_file_ids == NULL)
2233 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2234 g_hash_table_replace (dir->defaults_list_map,
2239 g_strfreev (mime_types);
2242 g_key_file_free (key_file);
2247 g_key_file_free (key_file);
2249 if (mime_types != NULL)
2250 g_strfreev (mime_types);
2253 g_error_free (load_error);
2257 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2261 gchar *filename, **mime_types;
2262 char *unaliased_type;
2263 char **desktop_file_ids;
2270 if (dir->mimeapps_list_added_map != NULL &&
2271 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2272 &dir->mimeapps_list_timestamp))
2275 if (dir->mimeapps_list_added_map != NULL)
2276 g_hash_table_destroy (dir->mimeapps_list_added_map);
2277 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2278 g_free, (GDestroyNotify)g_strfreev);
2280 if (dir->mimeapps_list_removed_map != NULL)
2281 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2282 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2283 g_free, (GDestroyNotify)g_strfreev);
2285 key_file = g_key_file_new ();
2287 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2288 if (g_stat (filename, &buf) < 0)
2291 if (dir->mimeapps_list_timestamp > 0)
2292 mime_info_cache->should_ping_mime_monitor = TRUE;
2294 dir->mimeapps_list_timestamp = buf.st_mtime;
2296 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2300 if (load_error != NULL)
2303 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2305 if (mime_types != NULL)
2307 for (i = 0; mime_types[i] != NULL; i++)
2309 desktop_file_ids = g_key_file_get_string_list (key_file,
2310 ADDED_ASSOCIATIONS_GROUP,
2314 if (desktop_file_ids == NULL)
2317 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2318 g_hash_table_replace (dir->mimeapps_list_added_map,
2323 g_strfreev (mime_types);
2326 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2328 if (mime_types != NULL)
2330 for (i = 0; mime_types[i] != NULL; i++)
2332 desktop_file_ids = g_key_file_get_string_list (key_file,
2333 REMOVED_ASSOCIATIONS_GROUP,
2337 if (desktop_file_ids == NULL)
2340 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2341 g_hash_table_replace (dir->mimeapps_list_removed_map,
2346 g_strfreev (mime_types);
2349 g_key_file_free (key_file);
2354 g_key_file_free (key_file);
2356 if (mime_types != NULL)
2357 g_strfreev (mime_types);
2360 g_error_free (load_error);
2363 static MimeInfoCacheDir *
2364 mime_info_cache_dir_new (const char *path)
2366 MimeInfoCacheDir *dir;
2368 dir = g_new0 (MimeInfoCacheDir, 1);
2369 dir->path = g_strdup (path);
2375 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2380 if (dir->mime_info_cache_map != NULL)
2382 destroy_info_cache_map (dir->mime_info_cache_map);
2383 dir->mime_info_cache_map = NULL;
2387 if (dir->defaults_list_map != NULL)
2389 g_hash_table_destroy (dir->defaults_list_map);
2390 dir->defaults_list_map = NULL;
2393 if (dir->mimeapps_list_added_map != NULL)
2395 g_hash_table_destroy (dir->mimeapps_list_added_map);
2396 dir->mimeapps_list_added_map = NULL;
2399 if (dir->mimeapps_list_removed_map != NULL)
2401 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2402 dir->mimeapps_list_removed_map = NULL;
2409 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2410 const char *mime_type,
2411 char **new_desktop_file_ids)
2413 GList *desktop_file_ids;
2416 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2419 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2421 if (!g_list_find_custom (desktop_file_ids, new_desktop_file_ids[i], (GCompareFunc) strcmp))
2422 desktop_file_ids = g_list_append (desktop_file_ids,
2423 g_strdup (new_desktop_file_ids[i]));
2426 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2430 mime_info_cache_init_dir_lists (void)
2432 const char * const *dirs;
2435 mime_info_cache = mime_info_cache_new ();
2437 dirs = get_applications_search_path ();
2439 for (i = 0; dirs[i] != NULL; i++)
2441 MimeInfoCacheDir *dir;
2443 dir = mime_info_cache_dir_new (dirs[i]);
2447 mime_info_cache_dir_init (dir);
2448 mime_info_cache_dir_init_defaults_list (dir);
2449 mime_info_cache_dir_init_mimeapps_list (dir);
2451 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2457 mime_info_cache_update_dir_lists (void)
2461 tmp = mime_info_cache->dirs;
2465 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2467 /* No need to do this if we had file monitors... */
2468 mime_info_cache_blow_global_cache ();
2469 mime_info_cache_dir_init (dir);
2470 mime_info_cache_dir_init_defaults_list (dir);
2471 mime_info_cache_dir_init_mimeapps_list (dir);
2478 mime_info_cache_init (void)
2480 G_LOCK (mime_info_cache);
2481 if (mime_info_cache == NULL)
2482 mime_info_cache_init_dir_lists ();
2488 if (now >= mime_info_cache->last_stat_time + 10)
2490 mime_info_cache_update_dir_lists ();
2491 mime_info_cache->last_stat_time = now;
2495 if (mime_info_cache->should_ping_mime_monitor)
2497 /* g_idle_add (emit_mime_changed, NULL); */
2498 mime_info_cache->should_ping_mime_monitor = FALSE;
2501 G_UNLOCK (mime_info_cache);
2504 static MimeInfoCache *
2505 mime_info_cache_new (void)
2507 MimeInfoCache *cache;
2509 cache = g_new0 (MimeInfoCache, 1);
2511 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2512 (GDestroyNotify) g_free,
2513 (GDestroyNotify) g_free);
2518 mime_info_cache_free (MimeInfoCache *cache)
2523 g_list_foreach (cache->dirs,
2524 (GFunc) mime_info_cache_dir_free,
2526 g_list_free (cache->dirs);
2527 g_hash_table_destroy (cache->global_defaults_cache);
2532 * mime_info_cache_reload:
2533 * @dir: directory path which needs reloading.
2535 * Reload the mime information for the @dir.
2538 mime_info_cache_reload (const char *dir)
2540 /* FIXME: just reload the dir that needs reloading,
2541 * don't blow the whole cache
2543 if (mime_info_cache != NULL)
2545 G_LOCK (mime_info_cache);
2546 mime_info_cache_free (mime_info_cache);
2547 mime_info_cache = NULL;
2548 G_UNLOCK (mime_info_cache);
2553 append_desktop_entry (GList *list,
2554 const char *desktop_entry,
2555 GList *removed_entries)
2557 /* Add if not already in list, and valid */
2558 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2559 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2560 list = g_list_prepend (list, g_strdup (desktop_entry));
2566 * get_all_desktop_entries_for_mime_type:
2567 * @mime_type: a mime type.
2568 * @except: NULL or a strv list
2570 * Returns all the desktop ids for @mime_type. The desktop files
2571 * are listed in an order so that default applications are listed before
2572 * non-default ones, and handlers for inherited mimetypes are listed
2573 * after the base ones.
2575 * Optionally doesn't list the desktop ids given in the @except
2577 * Return value: a #GList containing the desktop ids which claim
2578 * to handle @mime_type.
2581 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2582 const char **except)
2584 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2585 MimeInfoCacheDir *dir;
2588 char **default_entries;
2589 char **removed_associations;
2594 mime_info_cache_init ();
2596 /* collect all ancestors */
2597 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2598 array = g_ptr_array_new ();
2599 for (i = 0; mime_types[i]; i++)
2600 g_ptr_array_add (array, mime_types[i]);
2601 g_free (mime_types);
2602 for (i = 0; i < array->len; i++)
2604 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2605 for (j = 0; anc[j]; j++)
2607 for (k = 0; k < array->len; k++)
2609 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2612 if (k == array->len) /* not found */
2613 g_ptr_array_add (array, g_strdup (anc[j]));
2617 g_ptr_array_add (array, NULL);
2618 mime_types = (char **)g_ptr_array_free (array, FALSE);
2620 G_LOCK (mime_info_cache);
2622 removed_entries = NULL;
2623 desktop_entries = NULL;
2625 for (i = 0; except != NULL && except[i] != NULL; i++)
2626 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2628 for (i = 0; mime_types[i] != NULL; i++)
2630 mime_type = mime_types[i];
2632 /* Go through all apps listed as defaults */
2633 for (dir_list = mime_info_cache->dirs;
2635 dir_list = dir_list->next)
2637 dir = dir_list->data;
2639 /* First added associations from mimeapps.list */
2640 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2641 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2642 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2644 /* Then removed associations from mimeapps.list */
2645 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2646 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2647 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2649 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2650 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2651 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2652 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2655 /* Go through all entries that support the mimetype */
2656 for (dir_list = mime_info_cache->dirs;
2658 dir_list = dir_list->next)
2660 dir = dir_list->data;
2662 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2663 for (tmp = list; tmp != NULL; tmp = tmp->next)
2664 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2668 G_UNLOCK (mime_info_cache);
2670 g_strfreev (mime_types);
2672 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2673 g_list_free (removed_entries);
2675 desktop_entries = g_list_reverse (desktop_entries);
2677 return desktop_entries;
2680 /* GDesktopAppInfoLookup interface: */
2682 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
2683 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
2686 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
2691 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2692 * @lookup: a #GDesktopAppInfoLookup
2693 * @uri_scheme: a string containing a URI scheme.
2695 * Gets the default application for launching applications
2696 * using this URI scheme for a particular GDesktopAppInfoLookup
2699 * The GDesktopAppInfoLookup interface and this function is used
2700 * to implement g_app_info_get_default_for_uri_scheme() backends
2701 * in a GIO module. There is no reason for applications to use it
2702 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2704 * Returns: (transfer full): #GAppInfo for given @uri_scheme or %NULL on error.
2707 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2708 const char *uri_scheme)
2710 GDesktopAppInfoLookupIface *iface;
2712 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2714 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2716 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);