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
58 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
59 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
60 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
61 #define MIME_CACHE_GROUP "MIME Cache"
63 static void g_desktop_app_info_iface_init (GAppInfoIface
*iface
);
64 static GList
* get_all_desktop_entries_for_mime_type (const char *base_mime_type
,
66 static void mime_info_cache_reload (const char *dir
);
67 static gboolean
g_desktop_app_info_ensure_saved (GDesktopAppInfo
*info
,
73 * Information about an installed application from a desktop file.
75 struct _GDesktopAppInfo
77 GObject parent_instance
;
83 /* FIXME: what about GenericName ? */
97 guint startup_notify
: 1;
98 /* FIXME: what about StartupWMClass ? */
101 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo
, g_desktop_app_info
, G_TYPE_OBJECT
,
102 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO
,
103 g_desktop_app_info_iface_init
))
106 search_path_init (gpointer data
)
109 const char * const *data_dirs
;
110 const char *user_data_dir
;
113 data_dirs
= g_get_system_data_dirs ();
114 length
= g_strv_length ((char **) data_dirs
);
116 args
= g_new (char *, length
+ 2);
119 user_data_dir
= g_get_user_data_dir ();
120 args
[j
++] = g_build_filename (user_data_dir
, "applications", NULL
);
121 for (i
= 0; i
< length
; i
++)
122 args
[j
++] = g_build_filename (data_dirs
[i
],
123 "applications", NULL
);
129 static const char * const *
130 get_applications_search_path (void)
132 static GOnce once_init
= G_ONCE_INIT
;
133 return g_once (&once_init
, search_path_init
, NULL
);
137 g_desktop_app_info_finalize (GObject
*object
)
139 GDesktopAppInfo
*info
;
141 info
= G_DESKTOP_APP_INFO (object
);
143 g_free (info
->desktop_id
);
144 g_free (info
->filename
);
146 g_free (info
->comment
);
147 g_free (info
->icon_name
);
149 g_object_unref (info
->icon
);
150 g_strfreev (info
->only_show_in
);
151 g_strfreev (info
->not_show_in
);
152 g_free (info
->try_exec
);
154 g_free (info
->binary
);
157 G_OBJECT_CLASS (g_desktop_app_info_parent_class
)->finalize (object
);
161 g_desktop_app_info_class_init (GDesktopAppInfoClass
*klass
)
163 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
165 gobject_class
->finalize
= g_desktop_app_info_finalize
;
169 g_desktop_app_info_init (GDesktopAppInfo
*local
)
174 binary_from_exec (const char *exec
)
176 const char *p
, *start
;
182 while (*p
!= ' ' && *p
!= 0)
185 return g_strndup (start
, p
- start
);
190 * g_desktop_app_info_new_from_keyfile:
191 * @key_file: an opened #GKeyFile
193 * Creates a new #GDesktopAppInfo.
195 * Returns: a new #GDesktopAppInfo or %NULL on error.
200 g_desktop_app_info_new_from_keyfile (GKeyFile
*key_file
)
202 GDesktopAppInfo
*info
;
207 start_group
= g_key_file_get_start_group (key_file
);
208 if (start_group
== NULL
|| strcmp (start_group
, G_KEY_FILE_DESKTOP_GROUP
) != 0)
210 g_free (start_group
);
213 g_free (start_group
);
215 type
= g_key_file_get_string (key_file
,
216 G_KEY_FILE_DESKTOP_GROUP
,
217 G_KEY_FILE_DESKTOP_KEY_TYPE
,
219 if (type
== NULL
|| strcmp (type
, G_KEY_FILE_DESKTOP_TYPE_APPLICATION
) != 0)
226 try_exec
= g_key_file_get_string (key_file
,
227 G_KEY_FILE_DESKTOP_GROUP
,
228 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC
,
230 if (try_exec
&& try_exec
[0] != '\0')
233 t
= g_find_program_in_path (try_exec
);
242 info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, NULL
);
243 info
->filename
= NULL
;
245 info
->name
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_NAME
, NULL
, NULL
);
246 info
->comment
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_COMMENT
, NULL
, NULL
);
247 info
->nodisplay
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY
, NULL
) != FALSE
;
248 info
->icon_name
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_ICON
, NULL
, NULL
);
249 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
);
250 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
);
251 info
->try_exec
= try_exec
;
252 info
->exec
= g_key_file_get_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_EXEC
, NULL
);
253 info
->path
= g_key_file_get_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_PATH
, NULL
);
254 info
->terminal
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_TERMINAL
, NULL
) != FALSE
;
255 info
->startup_notify
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY
, NULL
) != FALSE
;
256 info
->hidden
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_HIDDEN
, NULL
) != FALSE
;
261 if (g_path_is_absolute (info
->icon_name
))
265 file
= g_file_new_for_path (info
->icon_name
);
266 info
->icon
= g_file_icon_new (file
);
267 g_object_unref (file
);
270 info
->icon
= g_themed_icon_new (info
->icon_name
);
274 info
->binary
= binary_from_exec (info
->exec
);
276 if (info
->path
&& info
->path
[0] == '\0')
286 * g_desktop_app_info_new_from_filename:
287 * @filename: the path of a desktop file, in the GLib filename encoding
289 * Creates a new #GDesktopAppInfo.
291 * Returns: a new #GDesktopAppInfo or %NULL on error.
294 g_desktop_app_info_new_from_filename (const char *filename
)
297 GDesktopAppInfo
*info
= NULL
;
299 key_file
= g_key_file_new ();
301 if (g_key_file_load_from_file (key_file
,
306 info
= g_desktop_app_info_new_from_keyfile (key_file
);
308 info
->filename
= g_strdup (filename
);
311 g_key_file_free (key_file
);
317 * g_desktop_app_info_new:
318 * @desktop_id: the desktop file id
320 * Creates a new #GDesktopAppInfo.
322 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
325 g_desktop_app_info_new (const char *desktop_id
)
327 GDesktopAppInfo
*appinfo
;
328 const char * const *dirs
;
332 dirs
= get_applications_search_path ();
334 basename
= g_strdup (desktop_id
);
336 for (i
= 0; dirs
[i
] != NULL
; i
++)
341 filename
= g_build_filename (dirs
[i
], desktop_id
, NULL
);
342 appinfo
= g_desktop_app_info_new_from_filename (filename
);
348 while ((p
= strchr (p
, '-')) != NULL
)
352 filename
= g_build_filename (dirs
[i
], basename
, NULL
);
353 appinfo
= g_desktop_app_info_new_from_filename (filename
);
368 appinfo
->desktop_id
= g_strdup (desktop_id
);
370 if (g_desktop_app_info_get_is_hidden (appinfo
))
372 g_object_unref (appinfo
);
380 g_desktop_app_info_dup (GAppInfo
*appinfo
)
382 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
383 GDesktopAppInfo
*new_info
;
385 new_info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, NULL
);
387 new_info
->filename
= g_strdup (info
->filename
);
388 new_info
->desktop_id
= g_strdup (info
->desktop_id
);
390 new_info
->name
= g_strdup (info
->name
);
391 new_info
->comment
= g_strdup (info
->comment
);
392 new_info
->nodisplay
= info
->nodisplay
;
393 new_info
->icon_name
= g_strdup (info
->icon_name
);
394 new_info
->icon
= g_object_ref (info
->icon
);
395 new_info
->only_show_in
= g_strdupv (info
->only_show_in
);
396 new_info
->not_show_in
= g_strdupv (info
->not_show_in
);
397 new_info
->try_exec
= g_strdup (info
->try_exec
);
398 new_info
->exec
= g_strdup (info
->exec
);
399 new_info
->binary
= g_strdup (info
->binary
);
400 new_info
->path
= g_strdup (info
->path
);
401 new_info
->hidden
= info
->hidden
;
402 new_info
->terminal
= info
->terminal
;
403 new_info
->startup_notify
= info
->startup_notify
;
405 return G_APP_INFO (new_info
);
409 g_desktop_app_info_equal (GAppInfo
*appinfo1
,
412 GDesktopAppInfo
*info1
= G_DESKTOP_APP_INFO (appinfo1
);
413 GDesktopAppInfo
*info2
= G_DESKTOP_APP_INFO (appinfo2
);
415 if (info1
->desktop_id
== NULL
||
416 info2
->desktop_id
== NULL
)
417 return info1
== info2
;
419 return strcmp (info1
->desktop_id
, info2
->desktop_id
) == 0;
423 g_desktop_app_info_get_id (GAppInfo
*appinfo
)
425 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
427 return info
->desktop_id
;
431 g_desktop_app_info_get_name (GAppInfo
*appinfo
)
433 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
435 if (info
->name
== NULL
)
441 * g_desktop_app_info_get_is_hidden:
442 * @info: a #GDesktopAppInfo.
444 * A desktop file is hidden if the Hidden key in it is
447 * Returns: %TRUE if hidden, %FALSE otherwise.
450 g_desktop_app_info_get_is_hidden (GDesktopAppInfo
*info
)
456 g_desktop_app_info_get_description (GAppInfo
*appinfo
)
458 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
460 return info
->comment
;
464 g_desktop_app_info_get_executable (GAppInfo
*appinfo
)
466 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
472 g_desktop_app_info_get_icon (GAppInfo
*appinfo
)
474 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
480 expand_macro_single (char macro
, char *uri
)
486 file
= g_file_new_for_uri (uri
);
487 path
= g_file_get_path (file
);
488 g_object_unref (file
);
494 result
= g_shell_quote (uri
);
499 result
= g_shell_quote (path
);
505 name
= g_path_get_dirname (path
);
506 result
= g_shell_quote (name
);
514 name
= g_path_get_basename (path
);
515 result
= g_shell_quote (name
);
527 expand_macro (char macro
,
529 GDesktopAppInfo
*info
,
532 GList
*uris
= *uri_list
;
534 gboolean force_file_uri
;
535 char force_file_uri_macro
;
537 g_return_if_fail (exec
!= NULL
);
539 /* On %u and %U, pass POSIX file path pointing to the URI via
540 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
541 * running or the URI doesn't have a POSIX file path via FUSE
542 * we'll just pass the URI.
547 force_file_uri_macro
= 'f';
548 force_file_uri
= TRUE
;
551 force_file_uri_macro
= 'F';
552 force_file_uri
= TRUE
;
555 force_file_uri_macro
= macro
;
556 force_file_uri
= FALSE
;
570 expanded
= expand_macro_single (macro
, uris
->data
);
574 expanded
= expand_macro_single (force_file_uri_macro
, uris
->data
);
575 if (expanded
== NULL
)
576 expanded
= expand_macro_single (macro
, uris
->data
);
581 g_string_append (exec
, expanded
);
597 expanded
= expand_macro_single (macro
, uris
->data
);
601 expanded
= expand_macro_single (force_file_uri_macro
, uris
->data
);
602 if (expanded
== NULL
)
603 expanded
= expand_macro_single (macro
, uris
->data
);
608 g_string_append (exec
, expanded
);
614 if (uris
!= NULL
&& expanded
)
615 g_string_append_c (exec
, ' ');
623 g_string_append (exec
, "--icon ");
624 g_string_append (exec
, info
->icon_name
);
630 g_string_append (exec
, info
->name
);
635 g_string_append (exec
, info
->filename
);
638 case 'm': /* deprecated */
642 g_string_append_c (exec
, '%');
650 expand_application_parameters (GDesktopAppInfo
*info
,
656 GList
*uri_list
= *uris
;
657 const char *p
= info
->exec
;
658 GString
*expanded_exec
= g_string_new (NULL
);
661 if (info
->exec
== NULL
)
663 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
664 _("Desktop file didn't specify Exec field"));
670 if (p
[0] == '%' && p
[1] != '\0')
672 expand_macro (p
[1], expanded_exec
, info
, uris
);
676 g_string_append_c (expanded_exec
, *p
);
681 /* No file substitutions */
682 if (uri_list
== *uris
&& uri_list
!= NULL
)
684 /* If there is no macro default to %f. This is also what KDE does */
685 g_string_append_c (expanded_exec
, ' ');
686 expand_macro ('f', expanded_exec
, info
, uris
);
689 res
= g_shell_parse_argv (expanded_exec
->str
, argc
, argv
, error
);
690 g_string_free (expanded_exec
, TRUE
);
695 prepend_terminal_to_vector (int *argc
,
702 char **term_argv
= NULL
;
707 g_return_val_if_fail (argc
!= NULL
, FALSE
);
708 g_return_val_if_fail (argv
!= NULL
, FALSE
);
716 /* compute size if not given */
719 for (i
= 0; the_argv
[i
] != NULL
; i
++)
725 term_argv
= g_new0 (char *, 3);
727 check
= g_find_program_in_path ("gnome-terminal");
730 term_argv
[0] = check
;
731 /* Note that gnome-terminal takes -x and
732 * as -e in gnome-terminal is broken we use that. */
733 term_argv
[1] = g_strdup ("-x");
738 check
= g_find_program_in_path ("nxterm");
740 check
= g_find_program_in_path ("color-xterm");
742 check
= g_find_program_in_path ("rxvt");
744 check
= g_find_program_in_path ("xterm");
746 check
= g_find_program_in_path ("dtterm");
749 check
= g_strdup ("xterm");
750 g_warning ("couldn't find a terminal, falling back to xterm");
752 term_argv
[0] = check
;
753 term_argv
[1] = g_strdup ("-e");
756 real_argc
= term_argc
+ *argc
;
757 real_argv
= g_new (char *, real_argc
+ 1);
759 for (i
= 0; i
< term_argc
; i
++)
760 real_argv
[i
] = term_argv
[i
];
762 for (j
= 0; j
< *argc
; j
++, i
++)
763 real_argv
[i
] = (char *)the_argv
[j
];
771 /* we use g_free here as we sucked all the inner strings
772 * out from it into real_argv */
777 #endif /* G_OS_WIN32 */
780 /* '=' is the new '\0'.
781 * DO NOT CALL unless at least one string ends with '='
784 is_env (const char *a
,
789 if (*a
== 0 || *b
== 0)
802 /* free with g_strfreev */
804 replace_env_var (char **old_environ
,
806 const char *new_value
)
808 int length
, new_length
;
809 int index
, new_index
;
813 /* do two things at once:
814 * - discover the length of the environment ('length')
815 * - find the location (if any) of the env var ('index')
818 for (length
= 0; old_environ
[length
]; length
++)
820 /* if we already have it in our environment, replace */
821 if (is_env (old_environ
[length
], env_var
))
826 /* no current env var, no desired env value.
829 if (new_value
== NULL
&& index
== -1)
832 /* in all cases now, we will be using a modified environment.
833 * determine its length and allocated it.
836 * new_index = location to insert, if any
837 * new_length = length of the new array
838 * new_environ = the pointer array for the new environment
841 if (new_value
== NULL
&& index
>= 0)
843 /* in this case, we will be removing an entry */
844 new_length
= length
- 1;
847 else if (new_value
!= NULL
&& index
< 0)
849 /* in this case, we will be adding an entry to the end */
850 new_length
= length
+ 1;
854 /* in this case, we will be replacing the existing entry */
860 new_environ
= g_malloc (sizeof (char *) * (new_length
+ 1));
861 new_environ
[new_length
] = NULL
;
863 /* now we do the copying.
864 * for each entry in the new environment, we decide what to do
868 for (new_i
= 0; new_i
< new_length
; new_i
++)
870 if (new_i
== new_index
)
872 /* insert our new item */
873 new_environ
[new_i
] = g_strconcat (env_var
,
878 /* if we had an old entry, skip it now */
884 /* if this is the old DESKTOP_STARTUP_ID, skip it */
888 /* copy an old item */
889 new_environ
[new_i
] = g_strdup (old_environ
[i
]);
894 g_strfreev (old_environ
);
900 uri_list_segment_to_files (GList
*start
,
907 while (start
!= NULL
&& start
!= end
)
909 file
= g_file_new_for_uri ((char *)start
->data
);
910 res
= g_list_prepend (res
, file
);
914 return g_list_reverse (res
);
917 #ifdef HAVE__NSGETENVIRON
918 #define environ (*_NSGetEnviron())
919 #elif !defined(G_OS_WIN32)
921 /* According to the Single Unix Specification, environ is not in
922 * * any system header, although unistd.h often declares it.
924 extern char **environ
;
928 g_desktop_app_info_launch_uris (GAppInfo
*appinfo
,
930 GAppLaunchContext
*launch_context
,
933 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
934 gboolean completed
= FALSE
;
936 GList
*launched_files
;
943 g_return_val_if_fail (appinfo
!= NULL
, FALSE
);
951 if (!expand_application_parameters (info
, &uris
,
952 &argc
, &argv
, error
))
955 if (info
->terminal
&& !prepend_terminal_to_vector (&argc
, &argv
))
957 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
958 _("Unable to find terminal required for application"));
965 launched_files
= uri_list_segment_to_files (old_uris
, uris
);
967 display
= g_app_launch_context_get_display (launch_context
,
972 if (info
->startup_notify
)
973 sn_id
= g_app_launch_context_get_startup_notify_id (launch_context
,
977 if (display
|| sn_id
)
981 envp
= g_new0 (char *, 1);
983 envp
= g_strdupv (environ
);
987 envp
= replace_env_var (envp
,
992 envp
= replace_env_var (envp
,
993 "DESKTOP_STARTUP_ID",
999 g_list_foreach (launched_files
, (GFunc
)g_object_unref
, NULL
);
1000 g_list_free (launched_files
);
1003 if (!g_spawn_async (info
->path
, /* working directory */
1006 G_SPAWN_SEARCH_PATH
/* flags */,
1007 NULL
/* child_setup */,
1009 NULL
/* child_pid */,
1014 g_app_launch_context_launch_failed (launch_context
, sn_id
);
1028 while (uris
!= NULL
);
1040 g_desktop_app_info_supports_uris (GAppInfo
*appinfo
)
1042 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1044 return info
->exec
&&
1045 ((strstr (info
->exec
, "%u") != NULL
) ||
1046 (strstr (info
->exec
, "%U") != NULL
));
1050 g_desktop_app_info_supports_files (GAppInfo
*appinfo
)
1052 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1054 return info
->exec
&&
1055 ((strstr (info
->exec
, "%f") != NULL
) ||
1056 (strstr (info
->exec
, "%F") != NULL
));
1060 g_desktop_app_info_launch (GAppInfo
*appinfo
,
1062 GAppLaunchContext
*launch_context
,
1072 uri
= g_file_get_uri (files
->data
);
1073 uris
= g_list_prepend (uris
, uri
);
1074 files
= files
->next
;
1077 uris
= g_list_reverse (uris
);
1079 res
= g_desktop_app_info_launch_uris (appinfo
, uris
, launch_context
, error
);
1081 g_list_foreach (uris
, (GFunc
)g_free
, NULL
);
1087 G_LOCK_DEFINE_STATIC (g_desktop_env
);
1088 static gchar
*g_desktop_env
= NULL
;
1091 * g_desktop_app_info_set_desktop_env:
1092 * @desktop_env: a string specifying what desktop this is
1094 * Sets the name of the desktop that the application is running in.
1095 * This is used by g_app_info_should_show() to evaluate the
1096 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1097 * desktop entry fields.
1099 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1100 * Menu specification</ulink> recognizes the following:
1102 * <member>GNOME</member>
1103 * <member>KDE</member>
1104 * <member>ROX</member>
1105 * <member>XFCE</member>
1106 * <member>Old</member>
1109 * Should be called only once; subsequent calls are ignored.
1112 g_desktop_app_info_set_desktop_env (const gchar
*desktop_env
)
1114 G_LOCK (g_desktop_env
);
1116 g_desktop_env
= g_strdup (desktop_env
);
1117 G_UNLOCK (g_desktop_env
);
1121 g_desktop_app_info_should_show (GAppInfo
*appinfo
)
1123 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1125 const gchar
*desktop_env
;
1128 if (info
->nodisplay
)
1131 G_LOCK (g_desktop_env
);
1132 desktop_env
= g_desktop_env
;
1133 G_UNLOCK (g_desktop_env
);
1135 if (info
->only_show_in
)
1137 if (desktop_env
== NULL
)
1141 for (i
= 0; info
->only_show_in
[i
] != NULL
; i
++)
1143 if (strcmp (info
->only_show_in
[i
], desktop_env
) == 0)
1153 if (info
->not_show_in
&& desktop_env
)
1155 for (i
= 0; info
->not_show_in
[i
] != NULL
; i
++)
1157 if (strcmp (info
->not_show_in
[i
], desktop_env
) == 0)
1171 ensure_dir (DirType type
,
1174 char *path
, *display_name
;
1177 if (type
== APP_DIR
)
1178 path
= g_build_filename (g_get_user_data_dir (), "applications", NULL
);
1180 path
= g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL
);
1183 if (g_mkdir_with_parents (path
, 0700) == 0)
1187 display_name
= g_filename_display_name (path
);
1188 if (type
== APP_DIR
)
1189 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
1190 _("Can't create user application configuration folder %s: %s"),
1191 display_name
, g_strerror (errsv
));
1193 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
1194 _("Can't create user MIME configuration folder %s: %s"),
1195 display_name
, g_strerror (errsv
));
1197 g_free (display_name
);
1204 update_mimeapps_list (const char *desktop_id
,
1205 const char *content_type
,
1206 gboolean add_as_default
,
1207 gboolean add_non_default
,
1211 char *dirname
, *filename
;
1213 gboolean load_succeeded
, res
;
1214 char **old_list
, **list
;
1215 GList
*system_list
, *l
;
1216 gsize length
, data_size
;
1219 char **content_types
;
1221 /* Don't add both at start and end */
1222 g_assert (!(add_as_default
&& add_non_default
));
1224 dirname
= ensure_dir (APP_DIR
, error
);
1228 filename
= g_build_filename (dirname
, "mimeapps.list", NULL
);
1231 key_file
= g_key_file_new ();
1232 load_succeeded
= g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, NULL
);
1233 if (!load_succeeded
|| !g_key_file_has_group (key_file
, ADDED_ASSOCIATIONS_GROUP
))
1235 g_key_file_free (key_file
);
1236 key_file
= g_key_file_new ();
1241 content_types
= g_new (char *, 2);
1242 content_types
[0] = g_strdup (content_type
);
1243 content_types
[1] = NULL
;
1247 content_types
= g_key_file_get_keys (key_file
, ADDED_ASSOCIATIONS_GROUP
, NULL
, NULL
);
1250 for (k
= 0; content_types
&& content_types
[k
]; k
++)
1252 /* Add to the right place in the list */
1255 old_list
= g_key_file_get_string_list (key_file
, ADDED_ASSOCIATIONS_GROUP
,
1256 content_types
[k
], &length
, NULL
);
1258 list
= g_new (char *, 1 + length
+ 1);
1262 list
[i
++] = g_strdup (desktop_id
);
1265 for (j
= 0; old_list
[j
] != NULL
; j
++)
1267 if (g_strcmp0 (old_list
[j
], desktop_id
) != 0)
1268 list
[i
++] = g_strdup (old_list
[j
]);
1269 else if (add_non_default
)
1271 /* If adding as non-default, and its already in,
1272 don't change order of desktop ids */
1273 add_non_default
= FALSE
;
1274 list
[i
++] = g_strdup (old_list
[j
]);
1279 if (add_non_default
)
1281 /* We're adding as non-default, and it wasn't already in the list,
1282 so we add at the end. But to avoid listing the app before the
1283 current system default (thus changing the default) we have to
1284 add the current list of (not yet listed) apps before it. */
1286 list
[i
] = NULL
; /* Terminate current list so we can use it */
1287 system_list
= get_all_desktop_entries_for_mime_type (content_type
, list
);
1289 list
= g_renew (char *, list
, 1 + length
+ g_list_length (system_list
) + 1);
1291 for (l
= system_list
; l
!= NULL
; l
= l
->next
)
1293 list
[i
++] = l
->data
; /* no strdup, taking ownership */
1294 if (g_strcmp0 (l
->data
, desktop_id
) == 0)
1295 add_non_default
= FALSE
;
1297 g_list_free (system_list
);
1299 if (add_non_default
)
1300 list
[i
++] = g_strdup (desktop_id
);
1305 g_strfreev (old_list
);
1307 if (list
[0] == NULL
|| desktop_id
== NULL
)
1308 g_key_file_remove_key (key_file
,
1309 ADDED_ASSOCIATIONS_GROUP
,
1313 g_key_file_set_string_list (key_file
,
1314 ADDED_ASSOCIATIONS_GROUP
,
1316 (const char * const *)list
, i
);
1323 /* reuse the list from above */
1327 g_strfreev (content_types
);
1328 content_types
= g_key_file_get_keys (key_file
, REMOVED_ASSOCIATIONS_GROUP
, NULL
, NULL
);
1331 for (k
= 0; content_types
&& content_types
[k
]; k
++)
1333 /* Remove from removed associations group (unless remove) */
1336 old_list
= g_key_file_get_string_list (key_file
, REMOVED_ASSOCIATIONS_GROUP
,
1337 content_types
[k
], &length
, NULL
);
1339 list
= g_new (char *, 1 + length
+ 1);
1343 list
[i
++] = g_strdup (desktop_id
);
1346 for (j
= 0; old_list
[j
] != NULL
; j
++)
1348 if (g_strcmp0 (old_list
[j
], desktop_id
) != 0)
1349 list
[i
++] = g_strdup (old_list
[j
]);
1354 g_strfreev (old_list
);
1356 if (list
[0] == NULL
|| desktop_id
== NULL
)
1357 g_key_file_remove_key (key_file
,
1358 REMOVED_ASSOCIATIONS_GROUP
,
1362 g_key_file_set_string_list (key_file
,
1363 REMOVED_ASSOCIATIONS_GROUP
,
1365 (const char * const *)list
, i
);
1370 g_strfreev (content_types
);
1372 data
= g_key_file_to_data (key_file
, &data_size
, error
);
1373 g_key_file_free (key_file
);
1375 res
= g_file_set_contents (filename
, data
, data_size
, error
);
1377 mime_info_cache_reload (NULL
);
1386 g_desktop_app_info_set_as_default_for_type (GAppInfo
*appinfo
,
1387 const char *content_type
,
1390 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1392 if (!g_desktop_app_info_ensure_saved (info
, error
))
1395 return update_mimeapps_list (info
->desktop_id
, content_type
, TRUE
, FALSE
, FALSE
, error
);
1399 update_program_done (GPid pid
,
1403 /* Did the application exit correctly */
1404 if (WIFEXITED (status
) &&
1405 WEXITSTATUS (status
) == 0)
1407 /* Here we could clean out any caches in use */
1412 run_update_command (char *command
,
1421 GError
*error
= NULL
;
1424 argv
[1] = g_build_filename (g_get_user_data_dir (), subdir
, NULL
);
1426 if (g_spawn_async ("/", argv
,
1428 G_SPAWN_SEARCH_PATH
|
1429 G_SPAWN_STDOUT_TO_DEV_NULL
|
1430 G_SPAWN_STDERR_TO_DEV_NULL
|
1431 G_SPAWN_DO_NOT_REAP_CHILD
,
1432 NULL
, NULL
, /* No setup function */
1435 g_child_watch_add (pid
, update_program_done
, NULL
);
1438 /* If we get an error at this point, it's quite likely the user doesn't
1439 * have an installed copy of either 'update-mime-database' or
1440 * 'update-desktop-database'. I don't think we want to popup an error
1441 * dialog at this point, so we just do a g_warning to give the user a
1442 * chance of debugging it.
1444 g_warning ("%s", error
->message
);
1451 g_desktop_app_info_set_as_default_for_extension (GAppInfo
*appinfo
,
1452 const char *extension
,
1455 char *filename
, *basename
, *mimetype
;
1459 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo
), error
))
1462 dirname
= ensure_dir (MIMETYPE_DIR
, error
);
1466 basename
= g_strdup_printf ("user-extension-%s.xml", extension
);
1467 filename
= g_build_filename (dirname
, basename
, NULL
);
1471 mimetype
= g_strdup_printf ("application/x-extension-%s", extension
);
1473 if (!g_file_test (filename
, G_FILE_TEST_EXISTS
))
1478 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1479 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1480 " <mime-type type=\"%s\">\n"
1481 " <comment>%s document</comment>\n"
1482 " <glob pattern=\"*.%s\"/>\n"
1484 "</mime-info>\n", mimetype
, extension
, extension
);
1486 g_file_set_contents (filename
, contents
, -1, NULL
);
1489 run_update_command ("update-mime-database", "mime");
1493 res
= g_desktop_app_info_set_as_default_for_type (appinfo
,
1503 g_desktop_app_info_add_supports_type (GAppInfo
*appinfo
,
1504 const char *content_type
,
1507 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1509 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info
), error
))
1512 return update_mimeapps_list (info
->desktop_id
, content_type
, FALSE
, TRUE
, FALSE
, error
);
1516 g_desktop_app_info_can_remove_supports_type (GAppInfo
*appinfo
)
1522 g_desktop_app_info_remove_supports_type (GAppInfo
*appinfo
,
1523 const char *content_type
,
1526 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1528 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info
), error
))
1531 return update_mimeapps_list (info
->desktop_id
, content_type
, FALSE
, FALSE
, TRUE
, error
);
1535 g_desktop_app_info_ensure_saved (GDesktopAppInfo
*info
,
1541 char *data
, *desktop_id
;
1546 if (info
->filename
!= NULL
)
1549 /* This is only used for object created with
1550 * g_app_info_create_from_commandline. All other
1551 * object should have a filename
1554 dirname
= ensure_dir (APP_DIR
, error
);
1558 key_file
= g_key_file_new ();
1560 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1561 "Encoding", "UTF-8");
1562 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1563 G_KEY_FILE_DESKTOP_KEY_VERSION
, "1.0");
1564 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1565 G_KEY_FILE_DESKTOP_KEY_TYPE
,
1566 G_KEY_FILE_DESKTOP_TYPE_APPLICATION
);
1568 g_key_file_set_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1569 G_KEY_FILE_DESKTOP_KEY_TERMINAL
, TRUE
);
1571 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1572 G_KEY_FILE_DESKTOP_KEY_EXEC
, info
->exec
);
1574 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1575 G_KEY_FILE_DESKTOP_KEY_NAME
, info
->name
);
1577 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1578 G_KEY_FILE_DESKTOP_KEY_COMMENT
, info
->comment
);
1580 g_key_file_set_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
1581 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY
, TRUE
);
1583 data
= g_key_file_to_data (key_file
, &data_size
, NULL
);
1584 g_key_file_free (key_file
);
1586 desktop_id
= g_strdup_printf ("userapp-%s-XXXXXX.desktop", info
->name
);
1587 filename
= g_build_filename (dirname
, desktop_id
, NULL
);
1588 g_free (desktop_id
);
1591 fd
= g_mkstemp (filename
);
1596 display_name
= g_filename_display_name (filename
);
1597 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1598 _("Can't create user desktop file %s"), display_name
);
1599 g_free (display_name
);
1605 desktop_id
= g_path_get_basename (filename
);
1609 res
= g_file_set_contents (filename
, data
, data_size
, error
);
1612 g_free (desktop_id
);
1617 info
->filename
= filename
;
1618 info
->desktop_id
= desktop_id
;
1620 run_update_command ("update-desktop-database", "applications");
1626 g_desktop_app_info_can_delete (GAppInfo
*appinfo
)
1628 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1631 return g_access (info
->filename
, W_OK
) == 0;
1637 g_desktop_app_info_delete (GAppInfo
*appinfo
)
1639 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1643 if (g_remove (info
->filename
) == 0)
1645 update_mimeapps_list (info
->desktop_id
, NULL
, FALSE
, FALSE
, FALSE
, NULL
);
1647 g_free (info
->filename
);
1648 info
->filename
= NULL
;
1649 g_free (info
->desktop_id
);
1650 info
->desktop_id
= NULL
;
1660 * g_app_info_create_from_commandline:
1661 * @commandline: the commandline to use
1662 * @application_name: the application name, or %NULL to use @commandline
1663 * @flags: flags that can specify details of the created #GAppInfo
1664 * @error: a #GError location to store the error occuring, %NULL to ignore.
1666 * Creates a new #GAppInfo from the given information.
1668 * Returns: new #GAppInfo for given command.
1671 g_app_info_create_from_commandline (const char *commandline
,
1672 const char *application_name
,
1673 GAppInfoCreateFlags flags
,
1678 GDesktopAppInfo
*info
;
1680 info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, NULL
);
1682 info
->filename
= NULL
;
1683 info
->desktop_id
= NULL
;
1685 info
->terminal
= flags
& G_APP_INFO_CREATE_NEEDS_TERMINAL
;
1686 info
->startup_notify
= FALSE
;
1687 info
->hidden
= FALSE
;
1688 if (flags
& G_APP_INFO_CREATE_SUPPORTS_URIS
)
1689 info
->exec
= g_strconcat (commandline
, " %u", NULL
);
1691 info
->exec
= g_strconcat (commandline
, " %f", NULL
);
1692 info
->nodisplay
= TRUE
;
1693 info
->binary
= binary_from_exec (info
->exec
);
1695 if (application_name
)
1696 info
->name
= g_strdup (application_name
);
1699 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1700 split
= g_strsplit (commandline
, " ", 2);
1701 basename
= g_path_get_basename (split
[0]);
1703 info
->name
= basename
;
1704 if (info
->name
== NULL
)
1705 info
->name
= g_strdup ("custom");
1707 info
->comment
= g_strdup_printf (_("Custom definition for %s"), info
->name
);
1709 return G_APP_INFO (info
);
1713 g_desktop_app_info_iface_init (GAppInfoIface
*iface
)
1715 iface
->dup
= g_desktop_app_info_dup
;
1716 iface
->equal
= g_desktop_app_info_equal
;
1717 iface
->get_id
= g_desktop_app_info_get_id
;
1718 iface
->get_name
= g_desktop_app_info_get_name
;
1719 iface
->get_description
= g_desktop_app_info_get_description
;
1720 iface
->get_executable
= g_desktop_app_info_get_executable
;
1721 iface
->get_icon
= g_desktop_app_info_get_icon
;
1722 iface
->launch
= g_desktop_app_info_launch
;
1723 iface
->supports_uris
= g_desktop_app_info_supports_uris
;
1724 iface
->supports_files
= g_desktop_app_info_supports_files
;
1725 iface
->launch_uris
= g_desktop_app_info_launch_uris
;
1726 iface
->should_show
= g_desktop_app_info_should_show
;
1727 iface
->set_as_default_for_type
= g_desktop_app_info_set_as_default_for_type
;
1728 iface
->set_as_default_for_extension
= g_desktop_app_info_set_as_default_for_extension
;
1729 iface
->add_supports_type
= g_desktop_app_info_add_supports_type
;
1730 iface
->can_remove_supports_type
= g_desktop_app_info_can_remove_supports_type
;
1731 iface
->remove_supports_type
= g_desktop_app_info_remove_supports_type
;
1732 iface
->can_delete
= g_desktop_app_info_can_delete
;
1733 iface
->do_delete
= g_desktop_app_info_delete
;
1737 app_info_in_list (GAppInfo
*info
,
1740 while (list
!= NULL
)
1742 if (g_app_info_equal (info
, list
->data
))
1751 * g_app_info_get_all_for_type:
1752 * @content_type: the content type to find a #GAppInfo for
1754 * Gets a list of all #GAppInfo s for a given content type.
1756 * Returns: #GList of #GAppInfo s for given @content_type
1757 * or %NULL on error.
1760 g_app_info_get_all_for_type (const char *content_type
)
1762 GList
*desktop_entries
, *l
;
1764 GDesktopAppInfo
*info
;
1766 g_return_val_if_fail (content_type
!= NULL
, NULL
);
1768 desktop_entries
= get_all_desktop_entries_for_mime_type (content_type
, NULL
);
1771 for (l
= desktop_entries
; l
!= NULL
; l
= l
->next
)
1773 char *desktop_entry
= l
->data
;
1775 info
= g_desktop_app_info_new (desktop_entry
);
1778 if (app_info_in_list (G_APP_INFO (info
), infos
))
1779 g_object_unref (info
);
1781 infos
= g_list_prepend (infos
, info
);
1783 g_free (desktop_entry
);
1786 g_list_free (desktop_entries
);
1788 return g_list_reverse (infos
);
1792 * g_app_info_reset_type_associations:
1793 * @content_type: a content type
1795 * Removes all changes to the type associations done by
1796 * g_app_info_set_as_default_for_type(),
1797 * g_app_info_set_as_default_for_extension(),
1798 * g_app_info_add_supports_type() of g_app_info_remove_supports_type().
1803 g_app_info_reset_type_associations (const char *content_type
)
1805 update_mimeapps_list (NULL
, content_type
, FALSE
, FALSE
, FALSE
, NULL
);
1809 * g_app_info_get_default_for_type:
1810 * @content_type: the content type to find a #GAppInfo for
1811 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1814 * Gets the #GAppInfo that correspond to a given content type.
1816 * Returns: #GAppInfo for given @content_type or %NULL on error.
1819 g_app_info_get_default_for_type (const char *content_type
,
1820 gboolean must_support_uris
)
1822 GList
*desktop_entries
, *l
;
1825 g_return_val_if_fail (content_type
!= NULL
, NULL
);
1827 desktop_entries
= get_all_desktop_entries_for_mime_type (content_type
, NULL
);
1830 for (l
= desktop_entries
; l
!= NULL
; l
= l
->next
)
1832 char *desktop_entry
= l
->data
;
1834 info
= (GAppInfo
*)g_desktop_app_info_new (desktop_entry
);
1837 if (must_support_uris
&& !g_app_info_supports_uris (info
))
1839 g_object_unref (info
);
1847 g_list_foreach (desktop_entries
, (GFunc
)g_free
, NULL
);
1848 g_list_free (desktop_entries
);
1854 * g_app_info_get_default_for_uri_scheme:
1855 * @uri_scheme: a string containing a URI scheme.
1857 * Gets the default application for launching applications
1858 * using this URI scheme. A URI scheme is the initial part
1859 * of the URI, up to but not including the ':', e.g. "http",
1862 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
1865 g_app_info_get_default_for_uri_scheme (const char *uri_scheme
)
1867 static gsize lookup
= 0;
1869 if (g_once_init_enter (&lookup
))
1871 gsize setup_value
= 1;
1872 GDesktopAppInfoLookup
*lookup_instance
;
1873 const char *use_this
;
1874 GIOExtensionPoint
*ep
;
1875 GIOExtension
*extension
;
1878 use_this
= g_getenv ("GIO_USE_URI_ASSOCIATION");
1880 /* Ensure vfs in modules loaded */
1881 _g_io_modules_ensure_loaded ();
1883 ep
= g_io_extension_point_lookup (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME
);
1885 lookup_instance
= NULL
;
1888 extension
= g_io_extension_point_get_extension_by_name (ep
, use_this
);
1890 lookup_instance
= g_object_new (g_io_extension_get_type (extension
), NULL
);
1893 if (lookup_instance
== NULL
)
1895 for (l
= g_io_extension_point_get_extensions (ep
); l
!= NULL
; l
= l
->next
)
1897 extension
= l
->data
;
1898 lookup_instance
= g_object_new (g_io_extension_get_type (extension
), NULL
);
1899 if (lookup_instance
!= NULL
)
1904 if (lookup_instance
!= NULL
)
1905 setup_value
= (gsize
)lookup_instance
;
1907 g_once_init_leave (&lookup
, setup_value
);
1913 return g_desktop_app_info_lookup_get_default_for_uri_scheme (G_DESKTOP_APP_INFO_LOOKUP (lookup
),
1919 get_apps_from_dir (GHashTable
*apps
,
1920 const char *dirname
,
1924 const char *basename
;
1925 char *filename
, *subprefix
, *desktop_id
;
1927 GDesktopAppInfo
*appinfo
;
1929 dir
= g_dir_open (dirname
, 0, NULL
);
1932 while ((basename
= g_dir_read_name (dir
)) != NULL
)
1934 filename
= g_build_filename (dirname
, basename
, NULL
);
1935 if (g_str_has_suffix (basename
, ".desktop"))
1937 desktop_id
= g_strconcat (prefix
, basename
, NULL
);
1939 /* Use _extended so we catch NULLs too (hidden) */
1940 if (!g_hash_table_lookup_extended (apps
, desktop_id
, NULL
, NULL
))
1942 appinfo
= g_desktop_app_info_new_from_filename (filename
);
1944 if (appinfo
&& g_desktop_app_info_get_is_hidden (appinfo
))
1946 g_object_unref (appinfo
);
1951 if (appinfo
|| hidden
)
1953 g_hash_table_insert (apps
, g_strdup (desktop_id
), appinfo
);
1957 /* Reuse instead of strdup here */
1958 appinfo
->desktop_id
= desktop_id
;
1963 g_free (desktop_id
);
1967 if (g_file_test (filename
, G_FILE_TEST_IS_DIR
))
1969 subprefix
= g_strconcat (prefix
, basename
, "-", NULL
);
1970 get_apps_from_dir (apps
, filename
, subprefix
);
1982 * g_app_info_get_all:
1984 * Gets a list of all of the applications currently registered
1987 * For desktop files, this includes applications that have
1988 * <literal>NoDisplay=true</literal> set or are excluded from
1989 * display by means of <literal>OnlyShowIn</literal> or
1990 * <literal>NotShowIn</literal>. See g_app_info_should_show().
1991 * The returned list does not include applications which have
1992 * the <literal>Hidden</literal> key set.
1994 * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1997 g_app_info_get_all (void)
1999 const char * const *dirs
;
2001 GHashTableIter iter
;
2006 dirs
= get_applications_search_path ();
2008 apps
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2012 for (i
= 0; dirs
[i
] != NULL
; i
++)
2013 get_apps_from_dir (apps
, dirs
[i
], "");
2017 g_hash_table_iter_init (&iter
, apps
);
2018 while (g_hash_table_iter_next (&iter
, NULL
, &value
))
2021 infos
= g_list_prepend (infos
, value
);
2024 g_hash_table_destroy (apps
);
2026 return g_list_reverse (infos
);
2029 /* Cacheing of mimeinfo.cache and defaults.list files */
2033 GHashTable
*mime_info_cache_map
;
2034 GHashTable
*defaults_list_map
;
2035 GHashTable
*mimeapps_list_added_map
;
2036 GHashTable
*mimeapps_list_removed_map
;
2037 time_t mime_info_cache_timestamp
;
2038 time_t defaults_list_timestamp
;
2039 time_t mimeapps_list_timestamp
;
2043 GList
*dirs
; /* mimeinfo.cache and defaults.list */
2044 GHashTable
*global_defaults_cache
; /* global results of defaults.list lookup and validation */
2045 time_t last_stat_time
;
2046 guint should_ping_mime_monitor
: 1;
2049 static MimeInfoCache
*mime_info_cache
= NULL
;
2050 G_LOCK_DEFINE_STATIC (mime_info_cache
);
2052 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir
*dir
,
2053 const char *mime_type
,
2054 char **new_desktop_file_ids
);
2056 static MimeInfoCache
* mime_info_cache_new (void);
2059 destroy_info_cache_value (gpointer key
,
2063 g_list_foreach (value
, (GFunc
)g_free
, NULL
);
2064 g_list_free (value
);
2068 destroy_info_cache_map (GHashTable
*info_cache_map
)
2070 g_hash_table_foreach (info_cache_map
, (GHFunc
)destroy_info_cache_value
, NULL
);
2071 g_hash_table_destroy (info_cache_map
);
2075 mime_info_cache_dir_out_of_date (MimeInfoCacheDir
*dir
,
2076 const char *cache_file
,
2082 filename
= g_build_filename (dir
->path
, cache_file
, NULL
);
2084 if (g_stat (filename
, &buf
) < 0)
2091 if (buf
.st_mtime
!= *timestamp
)
2097 /* Call with lock held */
2099 remove_all (gpointer key
,
2108 mime_info_cache_blow_global_cache (void)
2110 g_hash_table_foreach_remove (mime_info_cache
->global_defaults_cache
,
2115 mime_info_cache_dir_init (MimeInfoCacheDir
*dir
)
2119 gchar
*filename
, **mime_types
;
2126 if (dir
->mime_info_cache_map
!= NULL
&&
2127 !mime_info_cache_dir_out_of_date (dir
, "mimeinfo.cache",
2128 &dir
->mime_info_cache_timestamp
))
2131 if (dir
->mime_info_cache_map
!= NULL
)
2132 destroy_info_cache_map (dir
->mime_info_cache_map
);
2134 dir
->mime_info_cache_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2135 (GDestroyNotify
) g_free
,
2138 key_file
= g_key_file_new ();
2140 filename
= g_build_filename (dir
->path
, "mimeinfo.cache", NULL
);
2142 if (g_stat (filename
, &buf
) < 0)
2145 if (dir
->mime_info_cache_timestamp
> 0)
2146 mime_info_cache
->should_ping_mime_monitor
= TRUE
;
2148 dir
->mime_info_cache_timestamp
= buf
.st_mtime
;
2150 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, &load_error
);
2155 if (load_error
!= NULL
)
2158 mime_types
= g_key_file_get_keys (key_file
, MIME_CACHE_GROUP
,
2161 if (load_error
!= NULL
)
2164 for (i
= 0; mime_types
[i
] != NULL
; i
++)
2166 gchar
**desktop_file_ids
;
2167 char *unaliased_type
;
2168 desktop_file_ids
= g_key_file_get_string_list (key_file
,
2174 if (desktop_file_ids
== NULL
)
2177 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
2178 mime_info_cache_dir_add_desktop_entries (dir
,
2181 g_free (unaliased_type
);
2183 g_strfreev (desktop_file_ids
);
2186 g_strfreev (mime_types
);
2187 g_key_file_free (key_file
);
2192 g_key_file_free (key_file
);
2194 if (mime_types
!= NULL
)
2195 g_strfreev (mime_types
);
2198 g_error_free (load_error
);
2202 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir
*dir
)
2206 gchar
*filename
, **mime_types
;
2207 char *unaliased_type
;
2208 char **desktop_file_ids
;
2215 if (dir
->defaults_list_map
!= NULL
&&
2216 !mime_info_cache_dir_out_of_date (dir
, "defaults.list",
2217 &dir
->defaults_list_timestamp
))
2220 if (dir
->defaults_list_map
!= NULL
)
2221 g_hash_table_destroy (dir
->defaults_list_map
);
2222 dir
->defaults_list_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2223 g_free
, (GDestroyNotify
)g_strfreev
);
2226 key_file
= g_key_file_new ();
2228 filename
= g_build_filename (dir
->path
, "defaults.list", NULL
);
2229 if (g_stat (filename
, &buf
) < 0)
2232 if (dir
->defaults_list_timestamp
> 0)
2233 mime_info_cache
->should_ping_mime_monitor
= TRUE
;
2235 dir
->defaults_list_timestamp
= buf
.st_mtime
;
2237 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, &load_error
);
2241 if (load_error
!= NULL
)
2244 mime_types
= g_key_file_get_keys (key_file
, DEFAULT_APPLICATIONS_GROUP
,
2246 if (mime_types
!= NULL
)
2248 for (i
= 0; mime_types
[i
] != NULL
; i
++)
2250 desktop_file_ids
= g_key_file_get_string_list (key_file
,
2251 DEFAULT_APPLICATIONS_GROUP
,
2255 if (desktop_file_ids
== NULL
)
2258 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
2259 g_hash_table_replace (dir
->defaults_list_map
,
2264 g_strfreev (mime_types
);
2267 g_key_file_free (key_file
);
2272 g_key_file_free (key_file
);
2274 if (mime_types
!= NULL
)
2275 g_strfreev (mime_types
);
2278 g_error_free (load_error
);
2282 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir
*dir
)
2286 gchar
*filename
, **mime_types
;
2287 char *unaliased_type
;
2288 char **desktop_file_ids
;
2295 if (dir
->mimeapps_list_added_map
!= NULL
&&
2296 !mime_info_cache_dir_out_of_date (dir
, "mimeapps.list",
2297 &dir
->mimeapps_list_timestamp
))
2300 if (dir
->mimeapps_list_added_map
!= NULL
)
2301 g_hash_table_destroy (dir
->mimeapps_list_added_map
);
2302 dir
->mimeapps_list_added_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2303 g_free
, (GDestroyNotify
)g_strfreev
);
2305 if (dir
->mimeapps_list_removed_map
!= NULL
)
2306 g_hash_table_destroy (dir
->mimeapps_list_removed_map
);
2307 dir
->mimeapps_list_removed_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2308 g_free
, (GDestroyNotify
)g_strfreev
);
2310 key_file
= g_key_file_new ();
2312 filename
= g_build_filename (dir
->path
, "mimeapps.list", NULL
);
2313 if (g_stat (filename
, &buf
) < 0)
2316 if (dir
->mimeapps_list_timestamp
> 0)
2317 mime_info_cache
->should_ping_mime_monitor
= TRUE
;
2319 dir
->mimeapps_list_timestamp
= buf
.st_mtime
;
2321 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, &load_error
);
2325 if (load_error
!= NULL
)
2328 mime_types
= g_key_file_get_keys (key_file
, ADDED_ASSOCIATIONS_GROUP
,
2330 if (mime_types
!= NULL
)
2332 for (i
= 0; mime_types
[i
] != NULL
; i
++)
2334 desktop_file_ids
= g_key_file_get_string_list (key_file
,
2335 ADDED_ASSOCIATIONS_GROUP
,
2339 if (desktop_file_ids
== NULL
)
2342 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
2343 g_hash_table_replace (dir
->mimeapps_list_added_map
,
2348 g_strfreev (mime_types
);
2351 mime_types
= g_key_file_get_keys (key_file
, REMOVED_ASSOCIATIONS_GROUP
,
2353 if (mime_types
!= NULL
)
2355 for (i
= 0; mime_types
[i
] != NULL
; i
++)
2357 desktop_file_ids
= g_key_file_get_string_list (key_file
,
2358 REMOVED_ASSOCIATIONS_GROUP
,
2362 if (desktop_file_ids
== NULL
)
2365 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
2366 g_hash_table_replace (dir
->mimeapps_list_removed_map
,
2371 g_strfreev (mime_types
);
2374 g_key_file_free (key_file
);
2379 g_key_file_free (key_file
);
2381 if (mime_types
!= NULL
)
2382 g_strfreev (mime_types
);
2385 g_error_free (load_error
);
2388 static MimeInfoCacheDir
*
2389 mime_info_cache_dir_new (const char *path
)
2391 MimeInfoCacheDir
*dir
;
2393 dir
= g_new0 (MimeInfoCacheDir
, 1);
2394 dir
->path
= g_strdup (path
);
2400 mime_info_cache_dir_free (MimeInfoCacheDir
*dir
)
2405 if (dir
->mime_info_cache_map
!= NULL
)
2407 destroy_info_cache_map (dir
->mime_info_cache_map
);
2408 dir
->mime_info_cache_map
= NULL
;
2412 if (dir
->defaults_list_map
!= NULL
)
2414 g_hash_table_destroy (dir
->defaults_list_map
);
2415 dir
->defaults_list_map
= NULL
;
2418 if (dir
->mimeapps_list_added_map
!= NULL
)
2420 g_hash_table_destroy (dir
->mimeapps_list_added_map
);
2421 dir
->mimeapps_list_added_map
= NULL
;
2424 if (dir
->mimeapps_list_removed_map
!= NULL
)
2426 g_hash_table_destroy (dir
->mimeapps_list_removed_map
);
2427 dir
->mimeapps_list_removed_map
= NULL
;
2434 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir
*dir
,
2435 const char *mime_type
,
2436 char **new_desktop_file_ids
)
2438 GList
*desktop_file_ids
;
2441 desktop_file_ids
= g_hash_table_lookup (dir
->mime_info_cache_map
,
2444 for (i
= 0; new_desktop_file_ids
[i
] != NULL
; i
++)
2446 if (!g_list_find (desktop_file_ids
, new_desktop_file_ids
[i
]))
2447 desktop_file_ids
= g_list_append (desktop_file_ids
,
2448 g_strdup (new_desktop_file_ids
[i
]));
2451 g_hash_table_insert (dir
->mime_info_cache_map
, g_strdup (mime_type
), desktop_file_ids
);
2455 mime_info_cache_init_dir_lists (void)
2457 const char * const *dirs
;
2460 mime_info_cache
= mime_info_cache_new ();
2462 dirs
= get_applications_search_path ();
2464 for (i
= 0; dirs
[i
] != NULL
; i
++)
2466 MimeInfoCacheDir
*dir
;
2468 dir
= mime_info_cache_dir_new (dirs
[i
]);
2472 mime_info_cache_dir_init (dir
);
2473 mime_info_cache_dir_init_defaults_list (dir
);
2474 mime_info_cache_dir_init_mimeapps_list (dir
);
2476 mime_info_cache
->dirs
= g_list_append (mime_info_cache
->dirs
, dir
);
2482 mime_info_cache_update_dir_lists (void)
2486 tmp
= mime_info_cache
->dirs
;
2490 MimeInfoCacheDir
*dir
= (MimeInfoCacheDir
*) tmp
->data
;
2492 /* No need to do this if we had file monitors... */
2493 mime_info_cache_blow_global_cache ();
2494 mime_info_cache_dir_init (dir
);
2495 mime_info_cache_dir_init_defaults_list (dir
);
2496 mime_info_cache_dir_init_mimeapps_list (dir
);
2503 mime_info_cache_init (void)
2505 G_LOCK (mime_info_cache
);
2506 if (mime_info_cache
== NULL
)
2507 mime_info_cache_init_dir_lists ();
2513 if (now
>= mime_info_cache
->last_stat_time
+ 10)
2515 mime_info_cache_update_dir_lists ();
2516 mime_info_cache
->last_stat_time
= now
;
2520 if (mime_info_cache
->should_ping_mime_monitor
)
2522 /* g_idle_add (emit_mime_changed, NULL); */
2523 mime_info_cache
->should_ping_mime_monitor
= FALSE
;
2526 G_UNLOCK (mime_info_cache
);
2529 static MimeInfoCache
*
2530 mime_info_cache_new (void)
2532 MimeInfoCache
*cache
;
2534 cache
= g_new0 (MimeInfoCache
, 1);
2536 cache
->global_defaults_cache
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2537 (GDestroyNotify
) g_free
,
2538 (GDestroyNotify
) g_free
);
2543 mime_info_cache_free (MimeInfoCache
*cache
)
2548 g_list_foreach (cache
->dirs
,
2549 (GFunc
) mime_info_cache_dir_free
,
2551 g_list_free (cache
->dirs
);
2552 g_hash_table_destroy (cache
->global_defaults_cache
);
2557 * mime_info_cache_reload:
2558 * @dir: directory path which needs reloading.
2560 * Reload the mime information for the @dir.
2563 mime_info_cache_reload (const char *dir
)
2565 /* FIXME: just reload the dir that needs reloading,
2566 * don't blow the whole cache
2568 if (mime_info_cache
!= NULL
)
2570 G_LOCK (mime_info_cache
);
2571 mime_info_cache_free (mime_info_cache
);
2572 mime_info_cache
= NULL
;
2573 G_UNLOCK (mime_info_cache
);
2578 append_desktop_entry (GList
*list
,
2579 const char *desktop_entry
,
2580 GList
*removed_entries
)
2582 /* Add if not already in list, and valid */
2583 if (!g_list_find_custom (list
, desktop_entry
, (GCompareFunc
) strcmp
) &&
2584 !g_list_find_custom (removed_entries
, desktop_entry
, (GCompareFunc
) strcmp
))
2585 list
= g_list_prepend (list
, g_strdup (desktop_entry
));
2591 * get_all_desktop_entries_for_mime_type:
2592 * @mime_type: a mime type.
2593 * @except: NULL or a strv list
2595 * Returns all the desktop ids for @mime_type. The desktop files
2596 * are listed in an order so that default applications are listed before
2597 * non-default ones, and handlers for inherited mimetypes are listed
2598 * after the base ones.
2600 * Optionally doesn't list the desktop ids given in the @except
2602 * Return value: a #GList containing the desktop ids which claim
2603 * to handle @mime_type.
2606 get_all_desktop_entries_for_mime_type (const char *base_mime_type
,
2607 const char **except
)
2609 GList
*desktop_entries
, *removed_entries
, *list
, *dir_list
, *tmp
;
2610 MimeInfoCacheDir
*dir
;
2613 char **default_entries
;
2614 char **removed_associations
;
2619 mime_info_cache_init ();
2621 /* collect all ancestors */
2622 mime_types
= _g_unix_content_type_get_parents (base_mime_type
);
2623 array
= g_ptr_array_new ();
2624 for (i
= 0; mime_types
[i
]; i
++)
2625 g_ptr_array_add (array
, mime_types
[i
]);
2626 g_free (mime_types
);
2627 for (i
= 0; i
< array
->len
; i
++)
2629 anc
= _g_unix_content_type_get_parents (g_ptr_array_index (array
, i
));
2630 for (j
= 0; anc
[j
]; j
++)
2632 for (k
= 0; k
< array
->len
; k
++)
2634 if (strcmp (anc
[j
], g_ptr_array_index (array
, k
)) == 0)
2637 if (k
== array
->len
) /* not found */
2638 g_ptr_array_add (array
, g_strdup (anc
[j
]));
2642 g_ptr_array_add (array
, NULL
);
2643 mime_types
= (char **)g_ptr_array_free (array
, FALSE
);
2645 G_LOCK (mime_info_cache
);
2647 removed_entries
= NULL
;
2648 desktop_entries
= NULL
;
2650 for (i
= 0; except
!= NULL
&& except
[i
] != NULL
; i
++)
2651 removed_entries
= g_list_prepend (removed_entries
, g_strdup (except
[i
]));
2653 for (i
= 0; mime_types
[i
] != NULL
; i
++)
2655 mime_type
= mime_types
[i
];
2657 /* Go through all apps listed as defaults */
2658 for (dir_list
= mime_info_cache
->dirs
;
2660 dir_list
= dir_list
->next
)
2662 dir
= dir_list
->data
;
2664 /* First added associations from mimeapps.list */
2665 default_entries
= g_hash_table_lookup (dir
->mimeapps_list_added_map
, mime_type
);
2666 for (j
= 0; default_entries
!= NULL
&& default_entries
[j
] != NULL
; j
++)
2667 desktop_entries
= append_desktop_entry (desktop_entries
, default_entries
[j
], removed_entries
);
2669 /* Then removed associations from mimeapps.list */
2670 removed_associations
= g_hash_table_lookup (dir
->mimeapps_list_removed_map
, mime_type
);
2671 for (j
= 0; removed_associations
!= NULL
&& removed_associations
[j
] != NULL
; j
++)
2672 removed_entries
= append_desktop_entry (removed_entries
, removed_associations
[j
], NULL
);
2674 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
2675 default_entries
= g_hash_table_lookup (dir
->defaults_list_map
, mime_type
);
2676 for (j
= 0; default_entries
!= NULL
&& default_entries
[j
] != NULL
; j
++)
2677 desktop_entries
= append_desktop_entry (desktop_entries
, default_entries
[j
], removed_entries
);
2680 /* Go through all entries that support the mimetype */
2681 for (dir_list
= mime_info_cache
->dirs
;
2683 dir_list
= dir_list
->next
)
2685 dir
= dir_list
->data
;
2687 list
= g_hash_table_lookup (dir
->mime_info_cache_map
, mime_type
);
2688 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
)
2689 desktop_entries
= append_desktop_entry (desktop_entries
, tmp
->data
, removed_entries
);
2693 G_UNLOCK (mime_info_cache
);
2695 g_strfreev (mime_types
);
2697 g_list_foreach (removed_entries
, (GFunc
)g_free
, NULL
);
2698 g_list_free (removed_entries
);
2700 desktop_entries
= g_list_reverse (desktop_entries
);
2702 return desktop_entries
;
2705 /* GDesktopAppInfoLookup interface: */
2707 static void g_desktop_app_info_lookup_base_init (gpointer g_class
);
2708 static void g_desktop_app_info_lookup_class_init (gpointer g_class
,
2709 gpointer class_data
);
2712 g_desktop_app_info_lookup_get_type (void)
2714 static volatile gsize g_define_type_id__volatile
= 0;
2716 if (g_once_init_enter (&g_define_type_id__volatile
))
2718 const GTypeInfo desktop_app_info_lookup_info
=
2720 sizeof (GDesktopAppInfoLookupIface
), /* class_size */
2721 g_desktop_app_info_lookup_base_init
, /* base_init */
2722 NULL
, /* base_finalize */
2723 g_desktop_app_info_lookup_class_init
,
2724 NULL
, /* class_finalize */
2725 NULL
, /* class_data */
2727 0, /* n_preallocs */
2730 GType g_define_type_id
=
2731 g_type_register_static (G_TYPE_INTERFACE
, I_("GDesktopAppInfoLookup"),
2732 &desktop_app_info_lookup_info
, 0);
2734 g_type_interface_add_prerequisite (g_define_type_id
, G_TYPE_OBJECT
);
2736 g_once_init_leave (&g_define_type_id__volatile
, g_define_type_id
);
2739 return g_define_type_id__volatile
;
2743 g_desktop_app_info_lookup_class_init (gpointer g_class
,
2744 gpointer class_data
)
2749 g_desktop_app_info_lookup_base_init (gpointer g_class
)
2754 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
2755 * @lookup: a #GDesktopAppInfoLookup
2756 * @uri_scheme: a string containing a URI scheme.
2758 * Gets the default application for launching applications
2759 * using this URI scheme for a particular GDesktopAppInfoLookup
2762 * The GDesktopAppInfoLookup interface and this function is used
2763 * to implement g_app_info_get_default_for_uri_scheme() backends
2764 * in a GIO module. There is no reason for applications to use it
2765 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
2767 * Returns: #GAppInfo for given @uri_scheme or %NULL on error.
2770 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup
*lookup
,
2771 const char *uri_scheme
)
2773 GDesktopAppInfoLookupIface
*iface
;
2775 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup
), NULL
);
2777 iface
= G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup
);
2779 return (* iface
->get_default_for_uri_scheme
) (lookup
, uri_scheme
);
2782 #define __G_DESKTOP_APP_INFO_C__
2783 #include "gioaliasdef.c"