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"
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 ? */
100 guint startup_notify : 1;
101 /* FIXME: what about StartupWMClass ? */
104 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
105 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
106 g_desktop_app_info_iface_init))
109 search_path_init (gpointer data)
112 const char * const *data_dirs;
113 const char *user_data_dir;
116 data_dirs = g_get_system_data_dirs ();
117 length = g_strv_length ((char **) data_dirs);
119 args = g_new (char *, length + 2);
122 user_data_dir = g_get_user_data_dir ();
123 args[j++] = g_build_filename (user_data_dir, "applications", NULL);
124 for (i = 0; i < length; i++)
125 args[j++] = g_build_filename (data_dirs[i],
126 "applications", NULL);
132 static const char * const *
133 get_applications_search_path (void)
135 static GOnce once_init = G_ONCE_INIT;
136 return g_once (&once_init, search_path_init, NULL);
140 g_desktop_app_info_finalize (GObject *object)
142 GDesktopAppInfo *info;
144 info = G_DESKTOP_APP_INFO (object);
146 g_free (info->desktop_id);
147 g_free (info->filename);
149 g_free (info->comment);
150 g_free (info->icon_name);
152 g_object_unref (info->icon);
153 g_strfreev (info->only_show_in);
154 g_strfreev (info->not_show_in);
155 g_free (info->try_exec);
157 g_free (info->binary);
160 G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
164 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
166 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
168 gobject_class->finalize = g_desktop_app_info_finalize;
172 g_desktop_app_info_init (GDesktopAppInfo *local)
177 binary_from_exec (const char *exec)
179 const char *p, *start;
185 while (*p != ' ' && *p != 0)
188 return g_strndup (start, p - start);
193 * g_desktop_app_info_new_from_keyfile:
194 * @key_file: an opened #GKeyFile
196 * Creates a new #GDesktopAppInfo.
198 * Returns: a new #GDesktopAppInfo or %NULL on error.
203 g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
205 GDesktopAppInfo *info;
210 start_group = g_key_file_get_start_group (key_file);
211 if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
213 g_free (start_group);
216 g_free (start_group);
218 type = g_key_file_get_string (key_file,
219 G_KEY_FILE_DESKTOP_GROUP,
220 G_KEY_FILE_DESKTOP_KEY_TYPE,
222 if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
229 try_exec = g_key_file_get_string (key_file,
230 G_KEY_FILE_DESKTOP_GROUP,
231 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
233 if (try_exec && try_exec[0] != '\0')
236 t = g_find_program_in_path (try_exec);
245 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
246 info->filename = NULL;
248 info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
249 info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
250 info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
251 info->icon_name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
252 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);
253 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);
254 info->try_exec = try_exec;
255 info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
256 info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
257 info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
258 info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
259 info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
264 if (g_path_is_absolute (info->icon_name))
268 file = g_file_new_for_path (info->icon_name);
269 info->icon = g_file_icon_new (file);
270 g_object_unref (file);
276 /* Work around a common mistake in desktop files */
277 if ((p = strrchr (info->icon_name, '.')) != NULL &&
278 (strcmp (p, ".png") == 0 ||
279 strcmp (p, ".xpm") == 0 ||
280 strcmp (p, ".svg") == 0))
283 info->icon = g_themed_icon_new (info->icon_name);
288 info->binary = binary_from_exec (info->exec);
290 if (info->path && info->path[0] == '\0')
300 * g_desktop_app_info_new_from_filename:
301 * @filename: the path of a desktop file, in the GLib filename encoding
303 * Creates a new #GDesktopAppInfo.
305 * Returns: a new #GDesktopAppInfo or %NULL on error.
308 g_desktop_app_info_new_from_filename (const char *filename)
311 GDesktopAppInfo *info = NULL;
313 key_file = g_key_file_new ();
315 if (g_key_file_load_from_file (key_file,
320 info = g_desktop_app_info_new_from_keyfile (key_file);
322 info->filename = g_strdup (filename);
325 g_key_file_free (key_file);
331 * g_desktop_app_info_new:
332 * @desktop_id: the desktop file id
334 * Creates a new #GDesktopAppInfo based on a desktop file id.
336 * A desktop file id is the basename of the desktop file, including the
337 * .desktop extension. GIO is looking for a desktop file with this name
338 * in the <filename>applications</filename> subdirectories of the XDG data
339 * directories (i.e. the directories specified in the
340 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
341 * variables). GIO also supports the prefix-to-subdirectory mapping that is
342 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
343 * (i.e. a desktop id of kde-foo.desktop will match
344 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
346 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
349 g_desktop_app_info_new (const char *desktop_id)
351 GDesktopAppInfo *appinfo;
352 const char * const *dirs;
356 dirs = get_applications_search_path ();
358 basename = g_strdup (desktop_id);
360 for (i = 0; dirs[i] != NULL; i++)
365 filename = g_build_filename (dirs[i], desktop_id, NULL);
366 appinfo = g_desktop_app_info_new_from_filename (filename);
372 while ((p = strchr (p, '-')) != NULL)
376 filename = g_build_filename (dirs[i], basename, NULL);
377 appinfo = g_desktop_app_info_new_from_filename (filename);
392 appinfo->desktop_id = g_strdup (desktop_id);
394 if (g_desktop_app_info_get_is_hidden (appinfo))
396 g_object_unref (appinfo);
404 g_desktop_app_info_dup (GAppInfo *appinfo)
406 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
407 GDesktopAppInfo *new_info;
409 new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
411 new_info->filename = g_strdup (info->filename);
412 new_info->desktop_id = g_strdup (info->desktop_id);
414 new_info->name = g_strdup (info->name);
415 new_info->comment = g_strdup (info->comment);
416 new_info->nodisplay = info->nodisplay;
417 new_info->icon_name = g_strdup (info->icon_name);
418 new_info->icon = g_object_ref (info->icon);
419 new_info->only_show_in = g_strdupv (info->only_show_in);
420 new_info->not_show_in = g_strdupv (info->not_show_in);
421 new_info->try_exec = g_strdup (info->try_exec);
422 new_info->exec = g_strdup (info->exec);
423 new_info->binary = g_strdup (info->binary);
424 new_info->path = g_strdup (info->path);
425 new_info->hidden = info->hidden;
426 new_info->terminal = info->terminal;
427 new_info->startup_notify = info->startup_notify;
429 return G_APP_INFO (new_info);
433 g_desktop_app_info_equal (GAppInfo *appinfo1,
436 GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
437 GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
439 if (info1->desktop_id == NULL ||
440 info2->desktop_id == NULL)
441 return info1 == info2;
443 return strcmp (info1->desktop_id, info2->desktop_id) == 0;
447 g_desktop_app_info_get_id (GAppInfo *appinfo)
449 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
451 return info->desktop_id;
455 g_desktop_app_info_get_name (GAppInfo *appinfo)
457 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
459 if (info->name == NULL)
465 * g_desktop_app_info_get_is_hidden:
466 * @info: a #GDesktopAppInfo.
468 * A desktop file is hidden if the Hidden key in it is
471 * Returns: %TRUE if hidden, %FALSE otherwise.
474 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
480 g_desktop_app_info_get_description (GAppInfo *appinfo)
482 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
484 return info->comment;
488 g_desktop_app_info_get_executable (GAppInfo *appinfo)
490 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
496 g_desktop_app_info_get_commandline (GAppInfo *appinfo)
498 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
504 g_desktop_app_info_get_icon (GAppInfo *appinfo)
506 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
512 expand_macro_single (char macro, char *uri)
518 file = g_file_new_for_uri (uri);
519 path = g_file_get_path (file);
520 g_object_unref (file);
526 result = g_shell_quote (uri);
531 result = g_shell_quote (path);
537 name = g_path_get_dirname (path);
538 result = g_shell_quote (name);
546 name = g_path_get_basename (path);
547 result = g_shell_quote (name);
559 expand_macro (char macro,
561 GDesktopAppInfo *info,
564 GList *uris = *uri_list;
566 gboolean force_file_uri;
567 char force_file_uri_macro;
569 g_return_if_fail (exec != NULL);
571 /* On %u and %U, pass POSIX file path pointing to the URI via
572 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
573 * running or the URI doesn't have a POSIX file path via FUSE
574 * we'll just pass the URI.
579 force_file_uri_macro = 'f';
580 force_file_uri = TRUE;
583 force_file_uri_macro = 'F';
584 force_file_uri = TRUE;
587 force_file_uri_macro = macro;
588 force_file_uri = FALSE;
602 expanded = expand_macro_single (macro, uris->data);
606 expanded = expand_macro_single (force_file_uri_macro, uris->data);
607 if (expanded == NULL)
608 expanded = expand_macro_single (macro, uris->data);
613 g_string_append (exec, expanded);
629 expanded = expand_macro_single (macro, uris->data);
633 expanded = expand_macro_single (force_file_uri_macro, uris->data);
634 if (expanded == NULL)
635 expanded = expand_macro_single (macro, uris->data);
640 g_string_append (exec, expanded);
646 if (uris != NULL && expanded)
647 g_string_append_c (exec, ' ');
655 g_string_append (exec, "--icon ");
656 g_string_append (exec, info->icon_name);
662 g_string_append (exec, info->name);
667 g_string_append (exec, info->filename);
670 case 'm': /* deprecated */
674 g_string_append_c (exec, '%');
682 expand_application_parameters (GDesktopAppInfo *info,
688 GList *uri_list = *uris;
689 const char *p = info->exec;
690 GString *expanded_exec = g_string_new (NULL);
693 if (info->exec == NULL)
695 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
696 _("Desktop file didn't specify Exec field"));
702 if (p[0] == '%' && p[1] != '\0')
704 expand_macro (p[1], expanded_exec, info, uris);
708 g_string_append_c (expanded_exec, *p);
713 /* No file substitutions */
714 if (uri_list == *uris && uri_list != NULL)
716 /* If there is no macro default to %f. This is also what KDE does */
717 g_string_append_c (expanded_exec, ' ');
718 expand_macro ('f', expanded_exec, info, uris);
721 res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
722 g_string_free (expanded_exec, TRUE);
727 prepend_terminal_to_vector (int *argc,
734 char **term_argv = NULL;
739 g_return_val_if_fail (argc != NULL, FALSE);
740 g_return_val_if_fail (argv != NULL, FALSE);
748 /* compute size if not given */
751 for (i = 0; the_argv[i] != NULL; i++)
757 term_argv = g_new0 (char *, 3);
759 check = g_find_program_in_path ("gnome-terminal");
762 term_argv[0] = check;
763 /* Note that gnome-terminal takes -x and
764 * as -e in gnome-terminal is broken we use that. */
765 term_argv[1] = g_strdup ("-x");
770 check = g_find_program_in_path ("nxterm");
772 check = g_find_program_in_path ("color-xterm");
774 check = g_find_program_in_path ("rxvt");
776 check = g_find_program_in_path ("xterm");
778 check = g_find_program_in_path ("dtterm");
781 check = g_strdup ("xterm");
782 g_warning ("couldn't find a terminal, falling back to xterm");
784 term_argv[0] = check;
785 term_argv[1] = g_strdup ("-e");
788 real_argc = term_argc + *argc;
789 real_argv = g_new (char *, real_argc + 1);
791 for (i = 0; i < term_argc; i++)
792 real_argv[i] = term_argv[i];
794 for (j = 0; j < *argc; j++, i++)
795 real_argv[i] = (char *)the_argv[j];
803 /* we use g_free here as we sucked all the inner strings
804 * out from it into real_argv */
809 #endif /* G_OS_WIN32 */
812 /* '=' is the new '\0'.
813 * DO NOT CALL unless at least one string ends with '='
816 is_env (const char *a,
821 if (*a == 0 || *b == 0)
834 /* free with g_strfreev */
836 replace_env_var (char **old_environ,
838 const char *new_value)
840 int length, new_length;
841 int index, new_index;
845 /* do two things at once:
846 * - discover the length of the environment ('length')
847 * - find the location (if any) of the env var ('index')
850 for (length = 0; old_environ[length]; length++)
852 /* if we already have it in our environment, replace */
853 if (is_env (old_environ[length], env_var))
858 /* no current env var, no desired env value.
861 if (new_value == NULL && index == -1)
864 /* in all cases now, we will be using a modified environment.
865 * determine its length and allocated it.
868 * new_index = location to insert, if any
869 * new_length = length of the new array
870 * new_environ = the pointer array for the new environment
873 if (new_value == NULL && index >= 0)
875 /* in this case, we will be removing an entry */
876 new_length = length - 1;
879 else if (new_value != NULL && index < 0)
881 /* in this case, we will be adding an entry to the end */
882 new_length = length + 1;
886 /* in this case, we will be replacing the existing entry */
892 new_environ = g_malloc (sizeof (char *) * (new_length + 1));
893 new_environ[new_length] = NULL;
895 /* now we do the copying.
896 * for each entry in the new environment, we decide what to do
900 for (new_i = 0; new_i < new_length; new_i++)
902 if (new_i == new_index)
904 /* insert our new item */
905 new_environ[new_i] = g_strconcat (env_var,
910 /* if we had an old entry, skip it now */
916 /* if this is the old DESKTOP_STARTUP_ID, skip it */
920 /* copy an old item */
921 new_environ[new_i] = g_strdup (old_environ[i]);
926 g_strfreev (old_environ);
932 uri_list_segment_to_files (GList *start,
939 while (start != NULL && start != end)
941 file = g_file_new_for_uri ((char *)start->data);
942 res = g_list_prepend (res, file);
946 return g_list_reverse (res);
949 #ifdef HAVE__NSGETENVIRON
950 #define environ (*_NSGetEnviron())
951 #elif !defined(G_OS_WIN32)
953 /* According to the Single Unix Specification, environ is not in
954 * * any system header, although unistd.h often declares it.
956 extern char **environ;
960 g_desktop_app_info_launch_uris (GAppInfo *appinfo,
962 GAppLaunchContext *launch_context,
965 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
966 gboolean completed = FALSE;
968 GList *launched_files;
975 g_return_val_if_fail (appinfo != NULL, FALSE);
983 if (!expand_application_parameters (info, &uris,
984 &argc, &argv, error))
987 if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
989 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
990 _("Unable to find terminal required for application"));
997 launched_files = uri_list_segment_to_files (old_uris, uris);
999 display = g_app_launch_context_get_display (launch_context,
1004 if (info->startup_notify)
1005 sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
1009 if (display || sn_id)
1013 envp = g_new0 (char *, 1);
1015 envp = g_strdupv (environ);
1019 envp = replace_env_var (envp,
1024 envp = replace_env_var (envp,
1025 "DESKTOP_STARTUP_ID",
1031 g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
1032 g_list_free (launched_files);
1035 if (!g_spawn_async (info->path, /* working directory */
1038 G_SPAWN_SEARCH_PATH /* flags */,
1039 NULL /* child_setup */,
1041 NULL /* child_pid */,
1046 g_app_launch_context_launch_failed (launch_context, sn_id);
1060 while (uris != NULL);
1072 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
1074 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1076 return info->exec &&
1077 ((strstr (info->exec, "%u") != NULL) ||
1078 (strstr (info->exec, "%U") != NULL));
1082 g_desktop_app_info_supports_files (GAppInfo *appinfo)
1084 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1086 return info->exec &&
1087 ((strstr (info->exec, "%f") != NULL) ||
1088 (strstr (info->exec, "%F") != NULL));
1092 g_desktop_app_info_launch (GAppInfo *appinfo,
1094 GAppLaunchContext *launch_context,
1104 uri = g_file_get_uri (files->data);
1105 uris = g_list_prepend (uris, uri);
1106 files = files->next;
1109 uris = g_list_reverse (uris);
1111 res = g_desktop_app_info_launch_uris (appinfo, uris, launch_context, error);
1113 g_list_foreach (uris, (GFunc)g_free, NULL);
1119 G_LOCK_DEFINE_STATIC (g_desktop_env);
1120 static gchar *g_desktop_env = NULL;
1123 * g_desktop_app_info_set_desktop_env:
1124 * @desktop_env: a string specifying what desktop this is
1126 * Sets the name of the desktop that the application is running in.
1127 * This is used by g_app_info_should_show() to evaluate the
1128 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1129 * desktop entry fields.
1131 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1132 * Menu specification</ulink> recognizes the following:
1134 * <member>GNOME</member>
1135 * <member>KDE</member>
1136 * <member>ROX</member>
1137 * <member>XFCE</member>
1138 * <member>Old</member>
1141 * Should be called only once; subsequent calls are ignored.
1144 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1146 G_LOCK (g_desktop_env);
1148 g_desktop_env = g_strdup (desktop_env);
1149 G_UNLOCK (g_desktop_env);
1153 g_desktop_app_info_should_show (GAppInfo *appinfo)
1155 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1157 const gchar *desktop_env;
1160 if (info->nodisplay)
1163 G_LOCK (g_desktop_env);
1164 desktop_env = g_desktop_env;
1165 G_UNLOCK (g_desktop_env);
1167 if (info->only_show_in)
1169 if (desktop_env == NULL)
1173 for (i = 0; info->only_show_in[i] != NULL; i++)
1175 if (strcmp (info->only_show_in[i], desktop_env) == 0)
1185 if (info->not_show_in && desktop_env)
1187 for (i = 0; info->not_show_in[i] != NULL; i++)
1189 if (strcmp (info->not_show_in[i], desktop_env) == 0)
1203 ensure_dir (DirType type,
1206 char *path, *display_name;
1209 if (type == APP_DIR)
1210 path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1212 path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1215 if (g_mkdir_with_parents (path, 0700) == 0)
1219 display_name = g_filename_display_name (path);
1220 if (type == APP_DIR)
1221 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1222 _("Can't create user application configuration folder %s: %s"),
1223 display_name, g_strerror (errsv));
1225 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
1226 _("Can't create user MIME configuration folder %s: %s"),
1227 display_name, g_strerror (errsv));
1229 g_free (display_name);
1236 update_mimeapps_list (const char *desktop_id,
1237 const char *content_type,
1238 gboolean add_as_default,
1239 gboolean add_non_default,
1243 char *dirname, *filename;
1245 gboolean load_succeeded, res;
1246 char **old_list, **list;
1247 GList *system_list, *l;
1248 gsize length, data_size;
1251 char **content_types;
1253 /* Don't add both at start and end */
1254 g_assert (!(add_as_default && add_non_default));
1256 dirname = ensure_dir (APP_DIR, error);
1260 filename = g_build_filename (dirname, "mimeapps.list", NULL);
1263 key_file = g_key_file_new ();
1264 load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1265 if (!load_succeeded || !g_key_file_has_group (key_file, ADDED_ASSOCIATIONS_GROUP))
1267 g_key_file_free (key_file);
1268 key_file = g_key_file_new ();
1273 content_types = g_new (char *, 2);
1274 content_types[0] = g_strdup (content_type);
1275 content_types[1] = NULL;
1279 content_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP, NULL, NULL);
1282 for (k = 0; content_types && content_types[k]; k++)
1284 /* Add to the right place in the list */
1287 old_list = g_key_file_get_string_list (key_file, ADDED_ASSOCIATIONS_GROUP,
1288 content_types[k], &length, NULL);
1290 list = g_new (char *, 1 + length + 1);
1294 list[i++] = g_strdup (desktop_id);
1297 for (j = 0; old_list[j] != NULL; j++)
1299 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1300 list[i++] = g_strdup (old_list[j]);
1301 else if (add_non_default)
1303 /* If adding as non-default, and it's already in,
1304 don't change order of desktop ids */
1305 add_non_default = FALSE;
1306 list[i++] = g_strdup (old_list[j]);
1311 if (add_non_default)
1313 /* We're adding as non-default, and it wasn't already in the list,
1314 so we add at the end. But to avoid listing the app before the
1315 current system default (thus changing the default) we have to
1316 add the current list of (not yet listed) apps before it. */
1318 list[i] = NULL; /* Terminate current list so we can use it */
1319 system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list);
1321 list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1);
1323 for (l = system_list; l != NULL; l = l->next)
1325 list[i++] = l->data; /* no strdup, taking ownership */
1326 if (g_strcmp0 (l->data, desktop_id) == 0)
1327 add_non_default = FALSE;
1329 g_list_free (system_list);
1331 if (add_non_default)
1332 list[i++] = g_strdup (desktop_id);
1337 g_strfreev (old_list);
1339 if (list[0] == NULL || desktop_id == NULL)
1340 g_key_file_remove_key (key_file,
1341 ADDED_ASSOCIATIONS_GROUP,
1345 g_key_file_set_string_list (key_file,
1346 ADDED_ASSOCIATIONS_GROUP,
1348 (const char * const *)list, i);
1355 /* reuse the list from above */
1359 g_strfreev (content_types);
1360 content_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL);
1363 for (k = 0; content_types && content_types[k]; k++)
1365 /* Remove from removed associations group (unless remove) */
1368 old_list = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP,
1369 content_types[k], &length, NULL);
1371 list = g_new (char *, 1 + length + 1);
1375 list[i++] = g_strdup (desktop_id);
1378 for (j = 0; old_list[j] != NULL; j++)
1380 if (g_strcmp0 (old_list[j], desktop_id) != 0)
1381 list[i++] = g_strdup (old_list[j]);
1386 g_strfreev (old_list);
1388 if (list[0] == NULL || desktop_id == NULL)
1389 g_key_file_remove_key (key_file,
1390 REMOVED_ASSOCIATIONS_GROUP,
1394 g_key_file_set_string_list (key_file,
1395 REMOVED_ASSOCIATIONS_GROUP,
1397 (const char * const *)list, i);
1402 g_strfreev (content_types);
1404 data = g_key_file_to_data (key_file, &data_size, error);
1405 g_key_file_free (key_file);
1407 res = g_file_set_contents (filename, data, data_size, error);
1409 mime_info_cache_reload (NULL);
1418 g_desktop_app_info_set_as_default_for_type (GAppInfo *appinfo,
1419 const char *content_type,
1422 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1424 if (!g_desktop_app_info_ensure_saved (info, error))
1427 return update_mimeapps_list (info->desktop_id, content_type, TRUE, FALSE, FALSE, error);
1431 update_program_done (GPid pid,
1435 /* Did the application exit correctly */
1436 if (WIFEXITED (status) &&
1437 WEXITSTATUS (status) == 0)
1439 /* Here we could clean out any caches in use */
1444 run_update_command (char *command,
1453 GError *error = NULL;
1456 argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1458 if (g_spawn_async ("/", argv,
1460 G_SPAWN_SEARCH_PATH |
1461 G_SPAWN_STDOUT_TO_DEV_NULL |
1462 G_SPAWN_STDERR_TO_DEV_NULL |
1463 G_SPAWN_DO_NOT_REAP_CHILD,
1464 NULL, NULL, /* No setup function */
1467 g_child_watch_add (pid, update_program_done, NULL);
1470 /* If we get an error at this point, it's quite likely the user doesn't
1471 * have an installed copy of either 'update-mime-database' or
1472 * 'update-desktop-database'. I don't think we want to popup an error
1473 * dialog at this point, so we just do a g_warning to give the user a
1474 * chance of debugging it.
1476 g_warning ("%s", error->message);
1483 g_desktop_app_info_set_as_default_for_extension (GAppInfo *appinfo,
1484 const char *extension,
1487 char *filename, *basename, *mimetype;
1491 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo), error))
1494 dirname = ensure_dir (MIMETYPE_DIR, error);
1498 basename = g_strdup_printf ("user-extension-%s.xml", extension);
1499 filename = g_build_filename (dirname, basename, NULL);
1503 mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1505 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1510 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1511 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1512 " <mime-type type=\"%s\">\n"
1513 " <comment>%s document</comment>\n"
1514 " <glob pattern=\"*.%s\"/>\n"
1516 "</mime-info>\n", mimetype, extension, extension);
1518 g_file_set_contents (filename, contents, -1, NULL);
1521 run_update_command ("update-mime-database", "mime");
1525 res = g_desktop_app_info_set_as_default_for_type (appinfo,
1535 g_desktop_app_info_add_supports_type (GAppInfo *appinfo,
1536 const char *content_type,
1539 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1541 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1544 return update_mimeapps_list (info->desktop_id, content_type, FALSE, TRUE, FALSE, error);
1548 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1554 g_desktop_app_info_remove_supports_type (GAppInfo *appinfo,
1555 const char *content_type,
1558 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1560 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info), error))
1563 return update_mimeapps_list (info->desktop_id, content_type, FALSE, FALSE, TRUE, error);
1567 g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
1573 char *data, *desktop_id;
1578 if (info->filename != NULL)
1581 /* This is only used for object created with
1582 * g_app_info_create_from_commandline. All other
1583 * object should have a filename
1586 dirname = ensure_dir (APP_DIR, error);
1590 key_file = g_key_file_new ();
1592 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1593 "Encoding", "UTF-8");
1594 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1595 G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1596 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1597 G_KEY_FILE_DESKTOP_KEY_TYPE,
1598 G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1600 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1601 G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1603 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1604 G_KEY_FILE_DESKTOP_KEY_EXEC, info->exec);
1606 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1607 G_KEY_FILE_DESKTOP_KEY_NAME, info->name);
1609 g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1610 G_KEY_FILE_DESKTOP_KEY_COMMENT, info->comment);
1612 g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1613 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1615 data = g_key_file_to_data (key_file, &data_size, NULL);
1616 g_key_file_free (key_file);
1618 desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", info->name);
1619 filename = g_build_filename (dirname, desktop_id, NULL);
1620 g_free (desktop_id);
1623 fd = g_mkstemp (filename);
1628 display_name = g_filename_display_name (filename);
1629 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1630 _("Can't create user desktop file %s"), display_name);
1631 g_free (display_name);
1637 desktop_id = g_path_get_basename (filename);
1641 res = g_file_set_contents (filename, data, data_size, error);
1644 g_free (desktop_id);
1649 info->filename = filename;
1650 info->desktop_id = desktop_id;
1652 run_update_command ("update-desktop-database", "applications");
1658 g_desktop_app_info_can_delete (GAppInfo *appinfo)
1660 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1664 if (strstr (info->filename, "/userapp-"))
1665 return g_access (info->filename, W_OK) == 0;
1672 g_desktop_app_info_delete (GAppInfo *appinfo)
1674 GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1678 if (g_remove (info->filename) == 0)
1680 update_mimeapps_list (info->desktop_id, NULL, FALSE, FALSE, FALSE, NULL);
1682 g_free (info->filename);
1683 info->filename = NULL;
1684 g_free (info->desktop_id);
1685 info->desktop_id = NULL;
1695 * g_app_info_create_from_commandline:
1696 * @commandline: the commandline to use
1697 * @application_name: the application name, or %NULL to use @commandline
1698 * @flags: flags that can specify details of the created #GAppInfo
1699 * @error: a #GError location to store the error occuring, %NULL to ignore.
1701 * Creates a new #GAppInfo from the given information.
1703 * Returns: new #GAppInfo for given command.
1706 g_app_info_create_from_commandline (const char *commandline,
1707 const char *application_name,
1708 GAppInfoCreateFlags flags,
1713 GDesktopAppInfo *info;
1715 info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
1717 info->filename = NULL;
1718 info->desktop_id = NULL;
1720 info->terminal = flags & G_APP_INFO_CREATE_NEEDS_TERMINAL;
1721 info->startup_notify = FALSE;
1722 info->hidden = FALSE;
1723 if (flags & G_APP_INFO_CREATE_SUPPORTS_URIS)
1724 info->exec = g_strconcat (commandline, " %u", NULL);
1726 info->exec = g_strconcat (commandline, " %f", NULL);
1727 info->nodisplay = TRUE;
1728 info->binary = binary_from_exec (info->exec);
1730 if (application_name)
1731 info->name = g_strdup (application_name);
1734 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1735 split = g_strsplit (commandline, " ", 2);
1736 basename = g_path_get_basename (split[0]);
1738 info->name = basename;
1739 if (info->name == NULL)
1740 info->name = g_strdup ("custom");
1742 info->comment = g_strdup_printf (_("Custom definition for %s"), info->name);
1744 return G_APP_INFO (info);
1748 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1750 iface->dup = g_desktop_app_info_dup;
1751 iface->equal = g_desktop_app_info_equal;
1752 iface->get_id = g_desktop_app_info_get_id;
1753 iface->get_name = g_desktop_app_info_get_name;
1754 iface->get_description = g_desktop_app_info_get_description;
1755 iface->get_executable = g_desktop_app_info_get_executable;
1756 iface->get_icon = g_desktop_app_info_get_icon;
1757 iface->launch = g_desktop_app_info_launch;
1758 iface->supports_uris = g_desktop_app_info_supports_uris;
1759 iface->supports_files = g_desktop_app_info_supports_files;
1760 iface->launch_uris = g_desktop_app_info_launch_uris;
1761 iface->should_show = g_desktop_app_info_should_show;
1762 iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1763 iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1764 iface->add_supports_type = g_desktop_app_info_add_supports_type;
1765 iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1766 iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1767 iface->can_delete = g_desktop_app_info_can_delete;
1768 iface->do_delete = g_desktop_app_info_delete;
1769 iface->get_commandline = g_desktop_app_info_get_commandline;
1773 app_info_in_list (GAppInfo *info,
1776 while (list != NULL)
1778 if (g_app_info_equal (info, list->data))
1787 * g_app_info_get_all_for_type:
1788 * @content_type: the content type to find a #GAppInfo for
1790 * Gets a list of all #GAppInfo s for a given content type.
1792 * Returns: #GList of #GAppInfo s for given @content_type
1793 * or %NULL on error.
1796 g_app_info_get_all_for_type (const char *content_type)
1798 GList *desktop_entries, *l;
1800 GDesktopAppInfo *info;
1802 g_return_val_if_fail (content_type != NULL, NULL);
1804 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1807 for (l = desktop_entries; l != NULL; l = l->next)
1809 char *desktop_entry = l->data;
1811 info = g_desktop_app_info_new (desktop_entry);
1814 if (app_info_in_list (G_APP_INFO (info), infos))
1815 g_object_unref (info);
1817 infos = g_list_prepend (infos, info);
1819 g_free (desktop_entry);
1822 g_list_free (desktop_entries);
1824 return g_list_reverse (infos);
1828 * g_app_info_reset_type_associations:
1829 * @content_type: a content type
1831 * Removes all changes to the type associations done by
1832 * g_app_info_set_as_default_for_type(),
1833 * g_app_info_set_as_default_for_extension(),
1834 * g_app_info_add_supports_type() of g_app_info_remove_supports_type().
1839 g_app_info_reset_type_associations (const char *content_type)
1841 update_mimeapps_list (NULL, content_type, FALSE, FALSE, FALSE, NULL);
1845 * g_app_info_get_default_for_type:
1846 * @content_type: the content type to find a #GAppInfo for
1847 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1850 * Gets the #GAppInfo that correspond to a given content type.
1852 * Returns: #GAppInfo for given @content_type or %NULL on error.
1855 g_app_info_get_default_for_type (const char *content_type,
1856 gboolean must_support_uris)
1858 GList *desktop_entries, *l;
1861 g_return_val_if_fail (content_type != NULL, NULL);
1863 desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL);
1866 for (l = desktop_entries; l != NULL; l = l->next)
1868 char *desktop_entry = l->data;
1870 info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1873 if (must_support_uris && !g_app_info_supports_uris (info))
1875 g_object_unref (info);
1883 g_list_foreach (desktop_entries, (GFunc)g_free, NULL);
1884 g_list_free (desktop_entries);
1890 * g_app_info_get_default_for_uri_scheme:
1891 * @uri_scheme: a string containing a URI scheme.
1893 * Gets the default application for launching applications
1894 * using this URI scheme. A URI scheme is the initial part
1895 * of the URI, up to but not including the ':', e.g. "http",
1898 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1901 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1903 static gsize lookup = 0;
1905 if (g_once_init_enter (&lookup))
1907 gsize setup_value = 1;
1908 GDesktopAppInfoLookup *lookup_instance;
1909 const char *use_this;
1910 GIOExtensionPoint *ep;
1911 GIOExtension *extension;
1914 use_this = g_getenv ("GIO_USE_URI_ASSOCIATION");
1916 /* Ensure vfs in modules loaded */
1917 _g_io_modules_ensure_loaded ();
1919 ep = g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1921 lookup_instance = NULL;
1924 extension = g_io_extension_point_get_extension_by_name (ep, use_this);
1926 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1929 if (lookup_instance == NULL)
1931 for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1933 extension = l->data;
1934 lookup_instance = g_object_new (g_io_extension_get_type (extension), NULL);
1935 if (lookup_instance != NULL)
1940 if (lookup_instance != NULL)
1941 setup_value = (gsize)lookup_instance;
1943 g_once_init_leave (&lookup, setup_value);
1949 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup),
1955 get_apps_from_dir (GHashTable *apps,
1956 const char *dirname,
1960 const char *basename;
1961 char *filename, *subprefix, *desktop_id;
1963 GDesktopAppInfo *appinfo;
1965 dir = g_dir_open (dirname, 0, NULL);
1968 while ((basename = g_dir_read_name (dir)) != NULL)
1970 filename = g_build_filename (dirname, basename, NULL);
1971 if (g_str_has_suffix (basename, ".desktop"))
1973 desktop_id = g_strconcat (prefix, basename, NULL);
1975 /* Use _extended so we catch NULLs too (hidden) */
1976 if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1978 appinfo = g_desktop_app_info_new_from_filename (filename);
1980 if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1982 g_object_unref (appinfo);
1987 if (appinfo || hidden)
1989 g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1993 /* Reuse instead of strdup here */
1994 appinfo->desktop_id = desktop_id;
1999 g_free (desktop_id);
2003 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
2005 subprefix = g_strconcat (prefix, basename, "-", NULL);
2006 get_apps_from_dir (apps, filename, subprefix);
2018 * g_app_info_get_all:
2020 * Gets a list of all of the applications currently registered
2023 * For desktop files, this includes applications that have
2024 * <literal>NoDisplay=true</literal> set or are excluded from
2025 * display by means of <literal>OnlyShowIn</literal> or
2026 * <literal>NotShowIn</literal>. See g_app_info_should_show().
2027 * The returned list does not include applications which have
2028 * the <literal>Hidden</literal> key set.
2030 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
2033 g_app_info_get_all (void)
2035 const char * const *dirs;
2037 GHashTableIter iter;
2042 dirs = get_applications_search_path ();
2044 apps = g_hash_table_new_full (g_str_hash, g_str_equal,
2048 for (i = 0; dirs[i] != NULL; i++)
2049 get_apps_from_dir (apps, dirs[i], "");
2053 g_hash_table_iter_init (&iter, apps);
2054 while (g_hash_table_iter_next (&iter, NULL, &value))
2057 infos = g_list_prepend (infos, value);
2060 g_hash_table_destroy (apps);
2062 return g_list_reverse (infos);
2065 /* Cacheing of mimeinfo.cache and defaults.list files */
2069 GHashTable *mime_info_cache_map;
2070 GHashTable *defaults_list_map;
2071 GHashTable *mimeapps_list_added_map;
2072 GHashTable *mimeapps_list_removed_map;
2073 time_t mime_info_cache_timestamp;
2074 time_t defaults_list_timestamp;
2075 time_t mimeapps_list_timestamp;
2079 GList *dirs; /* mimeinfo.cache and defaults.list */
2080 GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
2081 time_t last_stat_time;
2082 guint should_ping_mime_monitor : 1;
2085 static MimeInfoCache *mime_info_cache = NULL;
2086 G_LOCK_DEFINE_STATIC (mime_info_cache);
2088 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2089 const char *mime_type,
2090 char **new_desktop_file_ids);
2092 static MimeInfoCache * mime_info_cache_new (void);
2095 destroy_info_cache_value (gpointer key,
2099 g_list_foreach (value, (GFunc)g_free, NULL);
2100 g_list_free (value);
2104 destroy_info_cache_map (GHashTable *info_cache_map)
2106 g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
2107 g_hash_table_destroy (info_cache_map);
2111 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
2112 const char *cache_file,
2118 filename = g_build_filename (dir->path, cache_file, NULL);
2120 if (g_stat (filename, &buf) < 0)
2127 if (buf.st_mtime != *timestamp)
2133 /* Call with lock held */
2135 remove_all (gpointer key,
2144 mime_info_cache_blow_global_cache (void)
2146 g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
2151 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
2155 gchar *filename, **mime_types;
2162 if (dir->mime_info_cache_map != NULL &&
2163 !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
2164 &dir->mime_info_cache_timestamp))
2167 if (dir->mime_info_cache_map != NULL)
2168 destroy_info_cache_map (dir->mime_info_cache_map);
2170 dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2171 (GDestroyNotify) g_free,
2174 key_file = g_key_file_new ();
2176 filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
2178 if (g_stat (filename, &buf) < 0)
2181 if (dir->mime_info_cache_timestamp > 0)
2182 mime_info_cache->should_ping_mime_monitor = TRUE;
2184 dir->mime_info_cache_timestamp = buf.st_mtime;
2186 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2191 if (load_error != NULL)
2194 mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
2197 if (load_error != NULL)
2200 for (i = 0; mime_types[i] != NULL; i++)
2202 gchar **desktop_file_ids;
2203 char *unaliased_type;
2204 desktop_file_ids = g_key_file_get_string_list (key_file,
2210 if (desktop_file_ids == NULL)
2213 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2214 mime_info_cache_dir_add_desktop_entries (dir,
2217 g_free (unaliased_type);
2219 g_strfreev (desktop_file_ids);
2222 g_strfreev (mime_types);
2223 g_key_file_free (key_file);
2228 g_key_file_free (key_file);
2230 if (mime_types != NULL)
2231 g_strfreev (mime_types);
2234 g_error_free (load_error);
2238 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
2242 gchar *filename, **mime_types;
2243 char *unaliased_type;
2244 char **desktop_file_ids;
2251 if (dir->defaults_list_map != NULL &&
2252 !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2253 &dir->defaults_list_timestamp))
2256 if (dir->defaults_list_map != NULL)
2257 g_hash_table_destroy (dir->defaults_list_map);
2258 dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2259 g_free, (GDestroyNotify)g_strfreev);
2262 key_file = g_key_file_new ();
2264 filename = g_build_filename (dir->path, "defaults.list", NULL);
2265 if (g_stat (filename, &buf) < 0)
2268 if (dir->defaults_list_timestamp > 0)
2269 mime_info_cache->should_ping_mime_monitor = TRUE;
2271 dir->defaults_list_timestamp = buf.st_mtime;
2273 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2277 if (load_error != NULL)
2280 mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2282 if (mime_types != NULL)
2284 for (i = 0; mime_types[i] != NULL; i++)
2286 desktop_file_ids = g_key_file_get_string_list (key_file,
2287 DEFAULT_APPLICATIONS_GROUP,
2291 if (desktop_file_ids == NULL)
2294 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2295 g_hash_table_replace (dir->defaults_list_map,
2300 g_strfreev (mime_types);
2303 g_key_file_free (key_file);
2308 g_key_file_free (key_file);
2310 if (mime_types != NULL)
2311 g_strfreev (mime_types);
2314 g_error_free (load_error);
2318 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir *dir)
2322 gchar *filename, **mime_types;
2323 char *unaliased_type;
2324 char **desktop_file_ids;
2331 if (dir->mimeapps_list_added_map != NULL &&
2332 !mime_info_cache_dir_out_of_date (dir, "mimeapps.list",
2333 &dir->mimeapps_list_timestamp))
2336 if (dir->mimeapps_list_added_map != NULL)
2337 g_hash_table_destroy (dir->mimeapps_list_added_map);
2338 dir->mimeapps_list_added_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2339 g_free, (GDestroyNotify)g_strfreev);
2341 if (dir->mimeapps_list_removed_map != NULL)
2342 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2343 dir->mimeapps_list_removed_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2344 g_free, (GDestroyNotify)g_strfreev);
2346 key_file = g_key_file_new ();
2348 filename = g_build_filename (dir->path, "mimeapps.list", NULL);
2349 if (g_stat (filename, &buf) < 0)
2352 if (dir->mimeapps_list_timestamp > 0)
2353 mime_info_cache->should_ping_mime_monitor = TRUE;
2355 dir->mimeapps_list_timestamp = buf.st_mtime;
2357 g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2361 if (load_error != NULL)
2364 mime_types = g_key_file_get_keys (key_file, ADDED_ASSOCIATIONS_GROUP,
2366 if (mime_types != NULL)
2368 for (i = 0; mime_types[i] != NULL; i++)
2370 desktop_file_ids = g_key_file_get_string_list (key_file,
2371 ADDED_ASSOCIATIONS_GROUP,
2375 if (desktop_file_ids == NULL)
2378 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2379 g_hash_table_replace (dir->mimeapps_list_added_map,
2384 g_strfreev (mime_types);
2387 mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP,
2389 if (mime_types != NULL)
2391 for (i = 0; mime_types[i] != NULL; i++)
2393 desktop_file_ids = g_key_file_get_string_list (key_file,
2394 REMOVED_ASSOCIATIONS_GROUP,
2398 if (desktop_file_ids == NULL)
2401 unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2402 g_hash_table_replace (dir->mimeapps_list_removed_map,
2407 g_strfreev (mime_types);
2410 g_key_file_free (key_file);
2415 g_key_file_free (key_file);
2417 if (mime_types != NULL)
2418 g_strfreev (mime_types);
2421 g_error_free (load_error);
2424 static MimeInfoCacheDir *
2425 mime_info_cache_dir_new (const char *path)
2427 MimeInfoCacheDir *dir;
2429 dir = g_new0 (MimeInfoCacheDir, 1);
2430 dir->path = g_strdup (path);
2436 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2441 if (dir->mime_info_cache_map != NULL)
2443 destroy_info_cache_map (dir->mime_info_cache_map);
2444 dir->mime_info_cache_map = NULL;
2448 if (dir->defaults_list_map != NULL)
2450 g_hash_table_destroy (dir->defaults_list_map);
2451 dir->defaults_list_map = NULL;
2454 if (dir->mimeapps_list_added_map != NULL)
2456 g_hash_table_destroy (dir->mimeapps_list_added_map);
2457 dir->mimeapps_list_added_map = NULL;
2460 if (dir->mimeapps_list_removed_map != NULL)
2462 g_hash_table_destroy (dir->mimeapps_list_removed_map);
2463 dir->mimeapps_list_removed_map = NULL;
2470 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir *dir,
2471 const char *mime_type,
2472 char **new_desktop_file_ids)
2474 GList *desktop_file_ids;
2477 desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2480 for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2482 if (!g_list_find (desktop_file_ids, new_desktop_file_ids[i]))
2483 desktop_file_ids = g_list_append (desktop_file_ids,
2484 g_strdup (new_desktop_file_ids[i]));
2487 g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2491 mime_info_cache_init_dir_lists (void)
2493 const char * const *dirs;
2496 mime_info_cache = mime_info_cache_new ();
2498 dirs = get_applications_search_path ();
2500 for (i = 0; dirs[i] != NULL; i++)
2502 MimeInfoCacheDir *dir;
2504 dir = mime_info_cache_dir_new (dirs[i]);
2508 mime_info_cache_dir_init (dir);
2509 mime_info_cache_dir_init_defaults_list (dir);
2510 mime_info_cache_dir_init_mimeapps_list (dir);
2512 mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2518 mime_info_cache_update_dir_lists (void)
2522 tmp = mime_info_cache->dirs;
2526 MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2528 /* No need to do this if we had file monitors... */
2529 mime_info_cache_blow_global_cache ();
2530 mime_info_cache_dir_init (dir);
2531 mime_info_cache_dir_init_defaults_list (dir);
2532 mime_info_cache_dir_init_mimeapps_list (dir);
2539 mime_info_cache_init (void)
2541 G_LOCK (mime_info_cache);
2542 if (mime_info_cache == NULL)
2543 mime_info_cache_init_dir_lists ();
2549 if (now >= mime_info_cache->last_stat_time + 10)
2551 mime_info_cache_update_dir_lists ();
2552 mime_info_cache->last_stat_time = now;
2556 if (mime_info_cache->should_ping_mime_monitor)
2558 /* g_idle_add (emit_mime_changed, NULL); */
2559 mime_info_cache->should_ping_mime_monitor = FALSE;
2562 G_UNLOCK (mime_info_cache);
2565 static MimeInfoCache *
2566 mime_info_cache_new (void)
2568 MimeInfoCache *cache;
2570 cache = g_new0 (MimeInfoCache, 1);
2572 cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2573 (GDestroyNotify) g_free,
2574 (GDestroyNotify) g_free);
2579 mime_info_cache_free (MimeInfoCache *cache)
2584 g_list_foreach (cache->dirs,
2585 (GFunc) mime_info_cache_dir_free,
2587 g_list_free (cache->dirs);
2588 g_hash_table_destroy (cache->global_defaults_cache);
2593 * mime_info_cache_reload:
2594 * @dir: directory path which needs reloading.
2596 * Reload the mime information for the @dir.
2599 mime_info_cache_reload (const char *dir)
2601 /* FIXME: just reload the dir that needs reloading,
2602 * don't blow the whole cache
2604 if (mime_info_cache != NULL)
2606 G_LOCK (mime_info_cache);
2607 mime_info_cache_free (mime_info_cache);
2608 mime_info_cache = NULL;
2609 G_UNLOCK (mime_info_cache);
2614 append_desktop_entry (GList *list,
2615 const char *desktop_entry,
2616 GList *removed_entries)
2618 /* Add if not already in list, and valid */
2619 if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp) &&
2620 !g_list_find_custom (removed_entries, desktop_entry, (GCompareFunc) strcmp))
2621 list = g_list_prepend (list, g_strdup (desktop_entry));
2627 * get_all_desktop_entries_for_mime_type:
2628 * @mime_type: a mime type.
2629 * @except: NULL or a strv list
2631 * Returns all the desktop ids for @mime_type. The desktop files
2632 * are listed in an order so that default applications are listed before
2633 * non-default ones, and handlers for inherited mimetypes are listed
2634 * after the base ones.
2636 * Optionally doesn't list the desktop ids given in the @except
2638 * Return value: a #GList containing the desktop ids which claim
2639 * to handle @mime_type.
2642 get_all_desktop_entries_for_mime_type (const char *base_mime_type,
2643 const char **except)
2645 GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp;
2646 MimeInfoCacheDir *dir;
2649 char **default_entries;
2650 char **removed_associations;
2655 mime_info_cache_init ();
2657 /* collect all ancestors */
2658 mime_types = _g_unix_content_type_get_parents (base_mime_type);
2659 array = g_ptr_array_new ();
2660 for (i = 0; mime_types[i]; i++)
2661 g_ptr_array_add (array, mime_types[i]);
2662 g_free (mime_types);
2663 for (i = 0; i < array->len; i++)
2665 anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i));
2666 for (j = 0; anc[j]; j++)
2668 for (k = 0; k < array->len; k++)
2670 if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0)
2673 if (k == array->len) /* not found */
2674 g_ptr_array_add (array, g_strdup (anc[j]));
2678 g_ptr_array_add (array, NULL);
2679 mime_types = (char **)g_ptr_array_free (array, FALSE);
2681 G_LOCK (mime_info_cache);
2683 removed_entries = NULL;
2684 desktop_entries = NULL;
2686 for (i = 0; except != NULL && except[i] != NULL; i++)
2687 removed_entries = g_list_prepend (removed_entries, g_strdup (except[i]));
2689 for (i = 0; mime_types[i] != NULL; i++)
2691 mime_type = mime_types[i];
2693 /* Go through all apps listed as defaults */
2694 for (dir_list = mime_info_cache->dirs;
2696 dir_list = dir_list->next)
2698 dir = dir_list->data;
2700 /* First added associations from mimeapps.list */
2701 default_entries = g_hash_table_lookup (dir->mimeapps_list_added_map, mime_type);
2702 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2703 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2705 /* Then removed associations from mimeapps.list */
2706 removed_associations = g_hash_table_lookup (dir->mimeapps_list_removed_map, mime_type);
2707 for (j = 0; removed_associations != NULL && removed_associations[j] != NULL; j++)
2708 removed_entries = append_desktop_entry (removed_entries, removed_associations[j], NULL);
2710 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2711 default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2712 for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2713 desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
2716 /* Go through all entries that support the mimetype */
2717 for (dir_list = mime_info_cache->dirs;
2719 dir_list = dir_list->next)
2721 dir = dir_list->data;
2723 list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2724 for (tmp = list; tmp != NULL; tmp = tmp->next)
2725 desktop_entries = append_desktop_entry (desktop_entries, tmp->data, removed_entries);
2729 G_UNLOCK (mime_info_cache);
2731 g_strfreev (mime_types);
2733 g_list_foreach (removed_entries, (GFunc)g_free, NULL);
2734 g_list_free (removed_entries);
2736 desktop_entries = g_list_reverse (desktop_entries);
2738 return desktop_entries;
2741 /* GDesktopAppInfoLookup interface: */
2743 static void g_desktop_app_info_lookup_base_init (gpointer g_class);
2744 static void g_desktop_app_info_lookup_class_init (gpointer g_class,
2745 gpointer class_data);
2748 g_desktop_app_info_lookup_get_type (void)
2750 static volatile gsize g_define_type_id__volatile = 0;
2752 if (g_once_init_enter (&g_define_type_id__volatile))
2754 const GTypeInfo desktop_app_info_lookup_info =
2756 sizeof (GDesktopAppInfoLookupIface), /* class_size */
2757 g_desktop_app_info_lookup_base_init, /* base_init */
2758 NULL, /* base_finalize */
2759 g_desktop_app_info_lookup_class_init,
2760 NULL, /* class_finalize */
2761 NULL, /* class_data */
2763 0, /* n_preallocs */
2766 GType g_define_type_id =
2767 g_type_register_static (G_TYPE_INTERFACE, I_("GDesktopAppInfoLookup"),
2768 &desktop_app_info_lookup_info, 0);
2770 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
2772 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
2775 return g_define_type_id__volatile;
2779 g_desktop_app_info_lookup_class_init (gpointer g_class,
2780 gpointer class_data)
2785 g_desktop_app_info_lookup_base_init (gpointer g_class)
2790 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2791 * @lookup: a #GDesktopAppInfoLookup
2792 * @uri_scheme: a string containing a URI scheme.
2794 * Gets the default application for launching applications
2795 * using this URI scheme for a particular GDesktopAppInfoLookup
2798 * The GDesktopAppInfoLookup interface and this function is used
2799 * to implement g_app_info_get_default_for_uri_scheme() backends
2800 * in a GIO module. There is no reason for applications to use it
2801 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2803 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2806 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
2807 const char *uri_scheme)
2809 GDesktopAppInfoLookupIface *iface;
2811 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
2813 iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
2815 return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
2818 #define __G_DESKTOP_APP_INFO_C__
2819 #include "gioaliasdef.c"