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>
22 * Ryan Lortie <desrt@desrt.ca>
33 #ifdef HAVE_CRT_EXTERNS_H
34 #include <crt_externs.h>
37 #include "gcontenttypeprivate.h"
38 #include "gdesktopappinfo.h"
40 #include "glib-unix.h"
44 #include "gthemedicon.h"
45 #include "gfileicon.h"
46 #include <glib/gstdio.h>
48 #include "giomodule-priv.h"
53 * SECTION:gdesktopappinfo
54 * @title: GDesktopAppInfo
55 * @short_description: Application information from desktop files
56 * @include: gio/gdesktopappinfo.h
58 * #GDesktopAppInfo is an implementation of #GAppInfo based on
61 * Note that <filename><gio/gdesktopappinfo.h></filename> belongs to
62 * the UNIX-specific GIO interfaces, thus you have to use the
63 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
66 #define DEFAULT_APPLICATIONS_GROUP "Default Applications"
67 #define ADDED_ASSOCIATIONS_GROUP "Added Associations"
68 #define REMOVED_ASSOCIATIONS_GROUP "Removed Associations"
69 #define MIME_CACHE_GROUP "MIME Cache"
70 #define GENERIC_NAME_KEY "GenericName"
71 #define FULL_NAME_KEY "X-GNOME-FullName"
72 #define KEYWORDS_KEY "Keywords"
73 #define STARTUP_WM_CLASS_KEY "StartupWMClass"
80 static void g_desktop_app_info_iface_init (GAppInfoIface
*iface
);
81 static GList
* get_all_desktop_entries_for_mime_type (const char *base_mime_type
,
83 gboolean include_fallback
,
84 char **explicit_default
);
85 static void mime_info_cache_reload (const char *dir
);
86 static gboolean
g_desktop_app_info_ensure_saved (GDesktopAppInfo
*info
,
92 * Information about an installed application from a desktop file.
94 struct _GDesktopAppInfo
96 GObject parent_instance
;
118 char *startup_wm_class
;
125 guint startup_notify
: 1;
130 UPDATE_MIME_NONE
= 1 << 0,
131 UPDATE_MIME_SET_DEFAULT
= 1 << 1,
132 UPDATE_MIME_SET_NON_DEFAULT
= 1 << 2,
133 UPDATE_MIME_REMOVE
= 1 << 3,
134 UPDATE_MIME_SET_LAST_USED
= 1 << 4,
137 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo
, g_desktop_app_info
, G_TYPE_OBJECT
,
138 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO
, g_desktop_app_info_iface_init
))
140 G_LOCK_DEFINE_STATIC (g_desktop_env
);
141 static gchar
*g_desktop_env
= NULL
;
143 /* DesktopFileDir implementation {{{1 */
150 static DesktopFileDir
*desktop_file_dirs
;
151 static guint n_desktop_file_dirs
;
153 /* DesktopFileDir "API" {{{2 */
156 * desktop_file_dir_create:
157 * @array: the #GArray to add a new item to
158 * @data_dir: an XDG_DATA_DIR
160 * Creates a #DesktopFileDir for the corresponding @data_dir, adding it
164 desktop_file_dir_create (GArray
*array
,
165 const gchar
*data_dir
)
167 DesktopFileDir dir
= { 0, };
169 dir
.path
= g_build_filename (data_dir
, "applications", NULL
);
171 g_array_append_val (array
, dir
);
174 /* Global setup API {{{2 */
177 desktop_file_dirs_refresh (void)
179 if (g_once_init_enter (&desktop_file_dirs
))
181 const char * const *data_dirs
;
185 tmp
= g_array_new (FALSE
, FALSE
, sizeof (DesktopFileDir
));
187 /* Highest priority: the user's ~/.local/share/applications */
188 desktop_file_dir_create (tmp
, g_get_user_data_dir ());
190 /* Following that, XDG_DATA_DIRS/applications, in order */
191 data_dirs
= g_get_system_data_dirs ();
192 for (i
= 0; data_dirs
[i
]; i
++)
193 desktop_file_dir_create (tmp
, data_dirs
[i
]);
195 n_desktop_file_dirs
= tmp
->len
;
197 g_once_init_leave (&desktop_file_dirs
, (DesktopFileDir
*) g_array_free (tmp
, FALSE
));
201 /* GDesktopAppInfo implementation {{{1 */
202 /* GObject implementation {{{2 */
204 g_desktop_app_info_finalize (GObject
*object
)
206 GDesktopAppInfo
*info
;
208 info
= G_DESKTOP_APP_INFO (object
);
210 g_free (info
->desktop_id
);
211 g_free (info
->filename
);
214 g_key_file_unref (info
->keyfile
);
217 g_free (info
->generic_name
);
218 g_free (info
->fullname
);
219 g_free (info
->comment
);
220 g_free (info
->icon_name
);
222 g_object_unref (info
->icon
);
223 g_strfreev (info
->keywords
);
224 g_strfreev (info
->only_show_in
);
225 g_strfreev (info
->not_show_in
);
226 g_free (info
->try_exec
);
228 g_free (info
->binary
);
230 g_free (info
->categories
);
231 g_free (info
->startup_wm_class
);
232 g_strfreev (info
->mime_types
);
233 g_free (info
->app_id
);
234 g_strfreev (info
->actions
);
236 G_OBJECT_CLASS (g_desktop_app_info_parent_class
)->finalize (object
);
240 g_desktop_app_info_set_property (GObject
*object
,
245 GDesktopAppInfo
*self
= G_DESKTOP_APP_INFO (object
);
250 self
->filename
= g_value_dup_string (value
);
254 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
260 g_desktop_app_info_get_property (GObject
*object
,
265 GDesktopAppInfo
*self
= G_DESKTOP_APP_INFO (object
);
270 g_value_set_string (value
, self
->filename
);
273 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
279 g_desktop_app_info_class_init (GDesktopAppInfoClass
*klass
)
281 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
283 gobject_class
->get_property
= g_desktop_app_info_get_property
;
284 gobject_class
->set_property
= g_desktop_app_info_set_property
;
285 gobject_class
->finalize
= g_desktop_app_info_finalize
;
288 * GDesktopAppInfo:filename:
290 * The origin filename of this #GDesktopAppInfo
292 g_object_class_install_property (gobject_class
,
294 g_param_spec_string ("filename", "Filename", "", NULL
,
295 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
299 g_desktop_app_info_init (GDesktopAppInfo
*local
)
303 /* Construction... {{{2 */
307 * @exec: an exec line
309 * Returns the first word in an exec line (ie: the binary name).
311 * If @exec is " progname --foo %F" then returns "progname".
314 binary_from_exec (const char *exec
)
316 const char *p
, *start
;
322 while (*p
!= ' ' && *p
!= 0)
325 return g_strndup (start
, p
- start
);
329 g_desktop_app_info_load_from_keyfile (GDesktopAppInfo
*info
,
336 gboolean bus_activatable
;
338 start_group
= g_key_file_get_start_group (key_file
);
339 if (start_group
== NULL
|| strcmp (start_group
, G_KEY_FILE_DESKTOP_GROUP
) != 0)
341 g_free (start_group
);
344 g_free (start_group
);
346 type
= g_key_file_get_string (key_file
,
347 G_KEY_FILE_DESKTOP_GROUP
,
348 G_KEY_FILE_DESKTOP_KEY_TYPE
,
350 if (type
== NULL
|| strcmp (type
, G_KEY_FILE_DESKTOP_TYPE_APPLICATION
) != 0)
357 try_exec
= g_key_file_get_string (key_file
,
358 G_KEY_FILE_DESKTOP_GROUP
,
359 G_KEY_FILE_DESKTOP_KEY_TRY_EXEC
,
361 if (try_exec
&& try_exec
[0] != '\0')
364 t
= g_find_program_in_path (try_exec
);
373 exec
= g_key_file_get_string (key_file
,
374 G_KEY_FILE_DESKTOP_GROUP
,
375 G_KEY_FILE_DESKTOP_KEY_EXEC
,
377 if (exec
&& exec
[0] != '\0')
381 if (!g_shell_parse_argv (exec
, &argc
, &argv
, NULL
))
390 t
= g_find_program_in_path (argv
[0]);
403 info
->name
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_NAME
, NULL
, NULL
);
404 info
->generic_name
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, GENERIC_NAME_KEY
, NULL
, NULL
);
405 info
->fullname
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, FULL_NAME_KEY
, NULL
, NULL
);
406 info
->keywords
= g_key_file_get_locale_string_list (key_file
, G_KEY_FILE_DESKTOP_GROUP
, KEYWORDS_KEY
, NULL
, NULL
, NULL
);
407 info
->comment
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_COMMENT
, NULL
, NULL
);
408 info
->nodisplay
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY
, NULL
) != FALSE
;
409 info
->icon_name
= g_key_file_get_locale_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_ICON
, NULL
, NULL
);
410 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
);
411 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
);
412 info
->try_exec
= try_exec
;
414 info
->path
= g_key_file_get_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_PATH
, NULL
);
415 info
->terminal
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_TERMINAL
, NULL
) != FALSE
;
416 info
->startup_notify
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY
, NULL
) != FALSE
;
417 info
->no_fuse
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, "X-GIO-NoFuse", NULL
) != FALSE
;
418 info
->hidden
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_HIDDEN
, NULL
) != FALSE
;
419 info
->categories
= g_key_file_get_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_CATEGORIES
, NULL
);
420 info
->startup_wm_class
= g_key_file_get_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
, STARTUP_WM_CLASS_KEY
, NULL
);
421 info
->mime_types
= g_key_file_get_string_list (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE
, NULL
, NULL
);
422 bus_activatable
= g_key_file_get_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE
, NULL
);
423 info
->actions
= g_key_file_get_string_list (key_file
, G_KEY_FILE_DESKTOP_GROUP
, G_KEY_FILE_DESKTOP_KEY_ACTIONS
, NULL
, NULL
);
425 /* Remove the special-case: no Actions= key just means 0 extra actions */
426 if (info
->actions
== NULL
)
427 info
->actions
= g_new0 (gchar
*, 0 + 1);
432 if (g_path_is_absolute (info
->icon_name
))
436 file
= g_file_new_for_path (info
->icon_name
);
437 info
->icon
= g_file_icon_new (file
);
438 g_object_unref (file
);
444 /* Work around a common mistake in desktop files */
445 if ((p
= strrchr (info
->icon_name
, '.')) != NULL
&&
446 (strcmp (p
, ".png") == 0 ||
447 strcmp (p
, ".xpm") == 0 ||
448 strcmp (p
, ".svg") == 0))
451 info
->icon
= g_themed_icon_new (info
->icon_name
);
456 info
->binary
= binary_from_exec (info
->exec
);
458 if (info
->path
&& info
->path
[0] == '\0')
464 /* Can only be DBusActivatable if we know the filename, which means
465 * that this won't work for the load-from-keyfile case.
467 if (bus_activatable
&& info
->filename
)
472 basename
= g_path_get_basename (info
->filename
);
473 last_dot
= strrchr (basename
, '.');
475 if (last_dot
&& g_str_equal (last_dot
, ".desktop"))
479 if (g_dbus_is_interface_name (basename
))
480 info
->app_id
= g_strdup (basename
);
486 info
->keyfile
= g_key_file_ref (key_file
);
492 g_desktop_app_info_load_file (GDesktopAppInfo
*self
)
495 gboolean retval
= FALSE
;
497 g_return_val_if_fail (self
->filename
!= NULL
, FALSE
);
499 self
->desktop_id
= g_path_get_basename (self
->filename
);
501 key_file
= g_key_file_new ();
503 if (g_key_file_load_from_file (key_file
, self
->filename
, G_KEY_FILE_NONE
, NULL
))
504 retval
= g_desktop_app_info_load_from_keyfile (self
, key_file
);
506 g_key_file_unref (key_file
);
511 * g_desktop_app_info_new_from_keyfile:
512 * @key_file: an opened #GKeyFile
514 * Creates a new #GDesktopAppInfo.
516 * Returns: a new #GDesktopAppInfo or %NULL on error.
521 g_desktop_app_info_new_from_keyfile (GKeyFile
*key_file
)
523 GDesktopAppInfo
*info
;
525 info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, NULL
);
526 info
->filename
= NULL
;
527 if (!g_desktop_app_info_load_from_keyfile (info
, key_file
))
529 g_object_unref (info
);
536 * g_desktop_app_info_new_from_filename:
537 * @filename: the path of a desktop file, in the GLib filename encoding
539 * Creates a new #GDesktopAppInfo.
541 * Returns: a new #GDesktopAppInfo or %NULL on error.
544 g_desktop_app_info_new_from_filename (const char *filename
)
546 GDesktopAppInfo
*info
= NULL
;
548 info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, "filename", filename
, NULL
);
549 if (!g_desktop_app_info_load_file (info
))
551 g_object_unref (info
);
558 * g_desktop_app_info_new:
559 * @desktop_id: the desktop file id
561 * Creates a new #GDesktopAppInfo based on a desktop file id.
563 * A desktop file id is the basename of the desktop file, including the
564 * .desktop extension. GIO is looking for a desktop file with this name
565 * in the <filename>applications</filename> subdirectories of the XDG data
566 * directories (i.e. the directories specified in the
567 * <envar>XDG_DATA_HOME</envar> and <envar>XDG_DATA_DIRS</envar> environment
568 * variables). GIO also supports the prefix-to-subdirectory mapping that is
569 * described in the <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Menu Spec</ulink>
570 * (i.e. a desktop id of kde-foo.desktop will match
571 * <filename>/usr/share/applications/kde/foo.desktop</filename>).
573 * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
576 g_desktop_app_info_new (const char *desktop_id
)
578 GDesktopAppInfo
*appinfo
;
582 desktop_file_dirs_refresh ();
584 basename
= g_strdup (desktop_id
);
586 for (i
= 0; i
< n_desktop_file_dirs
; i
++)
588 const gchar
*path
= desktop_file_dirs
[i
].path
;
592 filename
= g_build_filename (path
, desktop_id
, NULL
);
593 appinfo
= g_desktop_app_info_new_from_filename (filename
);
599 while ((p
= strchr (p
, '-')) != NULL
)
603 filename
= g_build_filename (path
, basename
, NULL
);
604 appinfo
= g_desktop_app_info_new_from_filename (filename
);
619 g_free (appinfo
->desktop_id
);
620 appinfo
->desktop_id
= g_strdup (desktop_id
);
622 if (g_desktop_app_info_get_is_hidden (appinfo
))
624 g_object_unref (appinfo
);
632 g_desktop_app_info_dup (GAppInfo
*appinfo
)
634 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
635 GDesktopAppInfo
*new_info
;
637 new_info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, NULL
);
639 new_info
->filename
= g_strdup (info
->filename
);
640 new_info
->desktop_id
= g_strdup (info
->desktop_id
);
643 new_info
->keyfile
= g_key_file_ref (info
->keyfile
);
645 new_info
->name
= g_strdup (info
->name
);
646 new_info
->generic_name
= g_strdup (info
->generic_name
);
647 new_info
->fullname
= g_strdup (info
->fullname
);
648 new_info
->keywords
= g_strdupv (info
->keywords
);
649 new_info
->comment
= g_strdup (info
->comment
);
650 new_info
->nodisplay
= info
->nodisplay
;
651 new_info
->icon_name
= g_strdup (info
->icon_name
);
653 new_info
->icon
= g_object_ref (info
->icon
);
654 new_info
->only_show_in
= g_strdupv (info
->only_show_in
);
655 new_info
->not_show_in
= g_strdupv (info
->not_show_in
);
656 new_info
->try_exec
= g_strdup (info
->try_exec
);
657 new_info
->exec
= g_strdup (info
->exec
);
658 new_info
->binary
= g_strdup (info
->binary
);
659 new_info
->path
= g_strdup (info
->path
);
660 new_info
->app_id
= g_strdup (info
->app_id
);
661 new_info
->hidden
= info
->hidden
;
662 new_info
->terminal
= info
->terminal
;
663 new_info
->startup_notify
= info
->startup_notify
;
665 return G_APP_INFO (new_info
);
668 /* GAppInfo interface implementation functions {{{2 */
671 g_desktop_app_info_equal (GAppInfo
*appinfo1
,
674 GDesktopAppInfo
*info1
= G_DESKTOP_APP_INFO (appinfo1
);
675 GDesktopAppInfo
*info2
= G_DESKTOP_APP_INFO (appinfo2
);
677 if (info1
->desktop_id
== NULL
||
678 info2
->desktop_id
== NULL
)
679 return info1
== info2
;
681 return strcmp (info1
->desktop_id
, info2
->desktop_id
) == 0;
685 g_desktop_app_info_get_id (GAppInfo
*appinfo
)
687 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
689 return info
->desktop_id
;
693 g_desktop_app_info_get_name (GAppInfo
*appinfo
)
695 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
697 if (info
->name
== NULL
)
703 g_desktop_app_info_get_display_name (GAppInfo
*appinfo
)
705 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
707 if (info
->fullname
== NULL
)
708 return g_desktop_app_info_get_name (appinfo
);
709 return info
->fullname
;
713 * g_desktop_app_info_get_is_hidden:
714 * @info: a #GDesktopAppInfo.
716 * A desktop file is hidden if the Hidden key in it is
719 * Returns: %TRUE if hidden, %FALSE otherwise.
722 g_desktop_app_info_get_is_hidden (GDesktopAppInfo
*info
)
728 * g_desktop_app_info_get_filename:
729 * @info: a #GDesktopAppInfo
731 * When @info was created from a known filename, return it. In some
732 * situations such as the #GDesktopAppInfo returned from
733 * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
735 * Returns: The full path to the file for @info, or %NULL if not known.
739 g_desktop_app_info_get_filename (GDesktopAppInfo
*info
)
741 return info
->filename
;
745 g_desktop_app_info_get_description (GAppInfo
*appinfo
)
747 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
749 return info
->comment
;
753 g_desktop_app_info_get_executable (GAppInfo
*appinfo
)
755 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
761 g_desktop_app_info_get_commandline (GAppInfo
*appinfo
)
763 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
769 g_desktop_app_info_get_icon (GAppInfo
*appinfo
)
771 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
777 * g_desktop_app_info_get_categories:
778 * @info: a #GDesktopAppInfo
780 * Gets the categories from the desktop file.
782 * Returns: The unparsed Categories key from the desktop file;
783 * i.e. no attempt is made to split it by ';' or validate it.
786 g_desktop_app_info_get_categories (GDesktopAppInfo
*info
)
788 return info
->categories
;
792 * g_desktop_app_info_get_keywords:
793 * @info: a #GDesktopAppInfo
795 * Gets the keywords from the desktop file.
797 * Returns: (transfer none): The value of the Keywords key
802 g_desktop_app_info_get_keywords (GDesktopAppInfo
*info
)
804 return (const char * const *)info
->keywords
;
808 * g_desktop_app_info_get_generic_name:
809 * @info: a #GDesktopAppInfo
811 * Gets the generic name from the destkop file.
813 * Returns: The value of the GenericName key
816 g_desktop_app_info_get_generic_name (GDesktopAppInfo
*info
)
818 return info
->generic_name
;
822 * g_desktop_app_info_get_nodisplay:
823 * @info: a #GDesktopAppInfo
825 * Gets the value of the NoDisplay key, which helps determine if the
826 * application info should be shown in menus. See
827 * #G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY and g_app_info_should_show().
829 * Returns: The value of the NoDisplay key
834 g_desktop_app_info_get_nodisplay (GDesktopAppInfo
*info
)
836 return info
->nodisplay
;
840 * g_desktop_app_info_get_show_in:
841 * @info: a #GDesktopAppInfo
842 * @desktop_env: a string specifying a desktop name
844 * Checks if the application info should be shown in menus that list available
845 * applications for a specific name of the desktop, based on the
846 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal> keys.
848 * If @desktop_env is %NULL, then the name of the desktop set with
849 * g_desktop_app_info_set_desktop_env() is used.
851 * Note that g_app_info_should_show() for @info will include this check (with
852 * %NULL for @desktop_env) as well as additional checks.
854 * Returns: %TRUE if the @info should be shown in @desktop_env according to the
855 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal> keys, %FALSE
861 g_desktop_app_info_get_show_in (GDesktopAppInfo
*info
,
862 const gchar
*desktop_env
)
867 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), FALSE
);
870 G_LOCK (g_desktop_env
);
871 desktop_env
= g_desktop_env
;
872 G_UNLOCK (g_desktop_env
);
875 if (info
->only_show_in
)
877 if (desktop_env
== NULL
)
881 for (i
= 0; info
->only_show_in
[i
] != NULL
; i
++)
883 if (strcmp (info
->only_show_in
[i
], desktop_env
) == 0)
893 if (info
->not_show_in
&& desktop_env
)
895 for (i
= 0; info
->not_show_in
[i
] != NULL
; i
++)
897 if (strcmp (info
->not_show_in
[i
], desktop_env
) == 0)
905 /* Launching... {{{2 */
908 expand_macro_single (char macro
, char *uri
)
915 file
= g_file_new_for_uri (uri
);
921 result
= g_shell_quote (uri
);
925 path
= g_file_get_path (file
);
927 result
= g_shell_quote (path
);
931 path
= g_file_get_path (file
);
934 name
= g_path_get_dirname (path
);
935 result
= g_shell_quote (name
);
941 path
= g_file_get_path (file
);
944 name
= g_path_get_basename (path
);
945 result
= g_shell_quote (name
);
951 g_object_unref (file
);
958 expand_macro (char macro
,
960 GDesktopAppInfo
*info
,
963 GList
*uris
= *uri_list
;
965 gboolean force_file_uri
;
966 char force_file_uri_macro
;
969 g_return_if_fail (exec
!= NULL
);
971 /* On %u and %U, pass POSIX file path pointing to the URI via
972 * the FUSE mount in ~/.gvfs. Note that if the FUSE daemon isn't
973 * running or the URI doesn't have a POSIX file path via FUSE
974 * we'll just pass the URI.
976 force_file_uri_macro
= macro
;
977 force_file_uri
= FALSE
;
983 force_file_uri_macro
= 'f';
984 force_file_uri
= TRUE
;
987 force_file_uri_macro
= 'F';
988 force_file_uri
= TRUE
;
1004 if (!force_file_uri
||
1005 /* Pass URI if it contains an anchor */
1006 strchr (uri
, '#') != NULL
)
1008 expanded
= expand_macro_single (macro
, uri
);
1012 expanded
= expand_macro_single (force_file_uri_macro
, uri
);
1013 if (expanded
== NULL
)
1014 expanded
= expand_macro_single (macro
, uri
);
1019 g_string_append (exec
, expanded
);
1035 if (!force_file_uri
||
1036 /* Pass URI if it contains an anchor */
1037 strchr (uri
, '#') != NULL
)
1039 expanded
= expand_macro_single (macro
, uri
);
1043 expanded
= expand_macro_single (force_file_uri_macro
, uri
);
1044 if (expanded
== NULL
)
1045 expanded
= expand_macro_single (macro
, uri
);
1050 g_string_append (exec
, expanded
);
1056 if (uris
!= NULL
&& expanded
)
1057 g_string_append_c (exec
, ' ');
1063 if (info
->icon_name
)
1065 g_string_append (exec
, "--icon ");
1066 expanded
= g_shell_quote (info
->icon_name
);
1067 g_string_append (exec
, expanded
);
1075 expanded
= g_shell_quote (info
->name
);
1076 g_string_append (exec
, expanded
);
1084 expanded
= g_shell_quote (info
->filename
);
1085 g_string_append (exec
, expanded
);
1090 case 'm': /* deprecated */
1094 g_string_append_c (exec
, '%');
1102 expand_application_parameters (GDesktopAppInfo
*info
,
1103 const gchar
*exec_line
,
1109 GList
*uri_list
= *uris
;
1110 const char *p
= exec_line
;
1111 GString
*expanded_exec
;
1114 if (exec_line
== NULL
)
1116 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1117 _("Desktop file didn't specify Exec field"));
1121 expanded_exec
= g_string_new (NULL
);
1125 if (p
[0] == '%' && p
[1] != '\0')
1127 expand_macro (p
[1], expanded_exec
, info
, uris
);
1131 g_string_append_c (expanded_exec
, *p
);
1136 /* No file substitutions */
1137 if (uri_list
== *uris
&& uri_list
!= NULL
)
1139 /* If there is no macro default to %f. This is also what KDE does */
1140 g_string_append_c (expanded_exec
, ' ');
1141 expand_macro ('f', expanded_exec
, info
, uris
);
1144 res
= g_shell_parse_argv (expanded_exec
->str
, argc
, argv
, error
);
1145 g_string_free (expanded_exec
, TRUE
);
1150 prepend_terminal_to_vector (int *argc
,
1157 char **term_argv
= NULL
;
1162 g_return_val_if_fail (argc
!= NULL
, FALSE
);
1163 g_return_val_if_fail (argv
!= NULL
, FALSE
);
1171 /* compute size if not given */
1174 for (i
= 0; the_argv
[i
] != NULL
; i
++)
1180 term_argv
= g_new0 (char *, 3);
1182 check
= g_find_program_in_path ("gnome-terminal");
1185 term_argv
[0] = check
;
1186 /* Note that gnome-terminal takes -x and
1187 * as -e in gnome-terminal is broken we use that. */
1188 term_argv
[1] = g_strdup ("-x");
1193 check
= g_find_program_in_path ("nxterm");
1195 check
= g_find_program_in_path ("color-xterm");
1197 check
= g_find_program_in_path ("rxvt");
1199 check
= g_find_program_in_path ("xterm");
1201 check
= g_find_program_in_path ("dtterm");
1204 check
= g_strdup ("xterm");
1205 g_warning ("couldn't find a terminal, falling back to xterm");
1207 term_argv
[0] = check
;
1208 term_argv
[1] = g_strdup ("-e");
1211 real_argc
= term_argc
+ *argc
;
1212 real_argv
= g_new (char *, real_argc
+ 1);
1214 for (i
= 0; i
< term_argc
; i
++)
1215 real_argv
[i
] = term_argv
[i
];
1217 for (j
= 0; j
< *argc
; j
++, i
++)
1218 real_argv
[i
] = (char *)the_argv
[j
];
1220 real_argv
[i
] = NULL
;
1226 /* we use g_free here as we sucked all the inner strings
1227 * out from it into real_argv */
1232 #endif /* G_OS_WIN32 */
1236 create_files_for_uris (GList
*uris
)
1243 for (iter
= uris
; iter
; iter
= iter
->next
)
1245 GFile
*file
= g_file_new_for_uri ((char *)iter
->data
);
1246 res
= g_list_prepend (res
, file
);
1249 return g_list_reverse (res
);
1254 GSpawnChildSetupFunc user_setup
;
1255 gpointer user_setup_data
;
1261 child_setup (gpointer user_data
)
1263 ChildSetupData
*data
= user_data
;
1265 if (data
->pid_envvar
)
1267 pid_t pid
= getpid ();
1271 /* Write the pid into the space already reserved for it in the
1272 * environment array. We can't use sprintf because it might
1273 * malloc, so we do it by hand. It's simplest to write the pid
1274 * out backwards first, then copy it over.
1276 for (i
= 0; pid
; i
++, pid
/= 10)
1277 buf
[i
] = (pid
% 10) + '0';
1278 for (i
--; i
>= 0; i
--)
1279 *(data
->pid_envvar
++) = buf
[i
];
1280 *data
->pid_envvar
= '\0';
1283 if (data
->user_setup
)
1284 data
->user_setup (data
->user_setup_data
);
1288 notify_desktop_launch (GDBusConnection
*session_bus
,
1289 GDesktopAppInfo
*info
,
1291 const char *display
,
1296 GVariantBuilder uri_variant
;
1297 GVariantBuilder extras_variant
;
1299 const char *desktop_file_id
;
1300 const char *gio_desktop_file
;
1302 if (session_bus
== NULL
)
1305 g_variant_builder_init (&uri_variant
, G_VARIANT_TYPE ("as"));
1306 for (iter
= uris
; iter
; iter
= iter
->next
)
1307 g_variant_builder_add (&uri_variant
, "s", iter
->data
);
1309 g_variant_builder_init (&extras_variant
, G_VARIANT_TYPE ("a{sv}"));
1310 if (sn_id
!= NULL
&& g_utf8_validate (sn_id
, -1, NULL
))
1311 g_variant_builder_add (&extras_variant
, "{sv}",
1315 gio_desktop_file
= g_getenv ("GIO_LAUNCHED_DESKTOP_FILE");
1316 if (gio_desktop_file
!= NULL
)
1317 g_variant_builder_add (&extras_variant
, "{sv}",
1318 "origin-desktop-file",
1319 g_variant_new_bytestring (gio_desktop_file
));
1320 if (g_get_prgname () != NULL
)
1321 g_variant_builder_add (&extras_variant
, "{sv}",
1323 g_variant_new_bytestring (g_get_prgname ()));
1324 g_variant_builder_add (&extras_variant
, "{sv}",
1327 (gint64
)getpid ()));
1330 desktop_file_id
= info
->filename
;
1331 else if (info
->desktop_id
)
1332 desktop_file_id
= info
->desktop_id
;
1334 desktop_file_id
= "";
1336 msg
= g_dbus_message_new_signal ("/org/gtk/gio/DesktopAppInfo",
1337 "org.gtk.gio.DesktopAppInfo",
1339 g_dbus_message_set_body (msg
, g_variant_new ("(@aysxasa{sv})",
1340 g_variant_new_bytestring (desktop_file_id
),
1341 display
? display
: "",
1345 g_dbus_connection_send_message (session_bus
,
1349 g_object_unref (msg
);
1352 #define _SPAWN_FLAGS_DEFAULT (G_SPAWN_SEARCH_PATH)
1355 g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo
*info
,
1356 GDBusConnection
*session_bus
,
1357 const gchar
*exec_line
,
1359 GAppLaunchContext
*launch_context
,
1360 GSpawnFlags spawn_flags
,
1361 GSpawnChildSetupFunc user_setup
,
1362 gpointer user_setup_data
,
1363 GDesktopAppLaunchCallback pid_callback
,
1364 gpointer pid_callback_data
,
1367 gboolean completed
= FALSE
;
1369 char **argv
, **envp
;
1371 ChildSetupData data
;
1373 g_return_val_if_fail (info
!= NULL
, FALSE
);
1378 envp
= g_app_launch_context_get_environment (launch_context
);
1380 envp
= g_get_environ ();
1385 GList
*launched_uris
;
1387 char *display
, *sn_id
;
1390 if (!expand_application_parameters (info
, exec_line
, &uris
, &argc
, &argv
, error
))
1393 /* Get the subset of URIs we're launching with this process */
1394 launched_uris
= NULL
;
1395 for (iter
= old_uris
; iter
!= NULL
&& iter
!= uris
; iter
= iter
->next
)
1396 launched_uris
= g_list_prepend (launched_uris
, iter
->data
);
1397 launched_uris
= g_list_reverse (launched_uris
);
1399 if (info
->terminal
&& !prepend_terminal_to_vector (&argc
, &argv
))
1401 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1402 _("Unable to find terminal required for application"));
1406 data
.user_setup
= user_setup
;
1407 data
.user_setup_data
= user_setup_data
;
1411 envp
= g_environ_setenv (envp
,
1412 "GIO_LAUNCHED_DESKTOP_FILE",
1415 envp
= g_environ_setenv (envp
,
1416 "GIO_LAUNCHED_DESKTOP_FILE_PID",
1417 "XXXXXXXXXXXXXXXXXXXX", /* filled in child_setup */
1419 data
.pid_envvar
= (char *)g_environ_getenv (envp
, "GIO_LAUNCHED_DESKTOP_FILE_PID");
1423 data
.pid_envvar
= NULL
;
1430 GList
*launched_files
= create_files_for_uris (launched_uris
);
1432 display
= g_app_launch_context_get_display (launch_context
,
1436 envp
= g_environ_setenv (envp
, "DISPLAY", display
, TRUE
);
1438 if (info
->startup_notify
)
1440 sn_id
= g_app_launch_context_get_startup_notify_id (launch_context
,
1443 envp
= g_environ_setenv (envp
, "DESKTOP_STARTUP_ID", sn_id
, TRUE
);
1446 g_list_free_full (launched_files
, g_object_unref
);
1449 if (!g_spawn_async (info
->path
,
1459 g_app_launch_context_launch_failed (launch_context
, sn_id
);
1463 g_list_free (launched_uris
);
1468 if (pid_callback
!= NULL
)
1469 pid_callback (info
, pid
, pid_callback_data
);
1471 if (launch_context
!= NULL
)
1473 GVariantBuilder builder
;
1474 GVariant
*platform_data
;
1476 g_variant_builder_init (&builder
, G_VARIANT_TYPE_ARRAY
);
1477 g_variant_builder_add (&builder
, "{sv}", "pid", g_variant_new_int32 (pid
));
1479 g_variant_builder_add (&builder
, "{sv}", "startup-notification-id", g_variant_new_string (sn_id
));
1480 platform_data
= g_variant_ref_sink (g_variant_builder_end (&builder
));
1481 g_signal_emit_by_name (launch_context
, "launched", info
, platform_data
);
1482 g_variant_unref (platform_data
);
1485 notify_desktop_launch (session_bus
,
1494 g_list_free (launched_uris
);
1499 while (uris
!= NULL
);
1511 object_path_from_appid (const gchar
*app_id
)
1516 n
= strlen (app_id
);
1517 path
= g_malloc (n
+ 2);
1521 for (i
= 0; i
< n
; i
++)
1522 if (app_id
[i
] != '.')
1523 path
[i
+ 1] = app_id
[i
];
1533 g_desktop_app_info_make_platform_data (GDesktopAppInfo
*info
,
1535 GAppLaunchContext
*launch_context
)
1537 GVariantBuilder builder
;
1539 g_variant_builder_init (&builder
, G_VARIANT_TYPE_VARDICT
);
1543 GList
*launched_files
= create_files_for_uris (uris
);
1545 if (info
->startup_notify
)
1549 sn_id
= g_app_launch_context_get_startup_notify_id (launch_context
, G_APP_INFO (info
), launched_files
);
1550 g_variant_builder_add (&builder
, "{sv}", "desktop-startup-id", g_variant_new_take_string (sn_id
));
1553 g_list_free_full (launched_files
, g_object_unref
);
1556 return g_variant_builder_end (&builder
);
1560 g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo
*info
,
1561 GDBusConnection
*session_bus
,
1563 GAppLaunchContext
*launch_context
)
1565 GVariantBuilder builder
;
1568 g_return_val_if_fail (info
!= NULL
, FALSE
);
1570 g_variant_builder_init (&builder
, G_VARIANT_TYPE_TUPLE
);
1576 g_variant_builder_open (&builder
, G_VARIANT_TYPE_STRING_ARRAY
);
1577 for (iter
= uris
; iter
; iter
= iter
->next
)
1578 g_variant_builder_add (&builder
, "s", iter
->data
);
1579 g_variant_builder_close (&builder
);
1582 g_variant_builder_add_value (&builder
, g_desktop_app_info_make_platform_data (info
, uris
, launch_context
));
1584 /* This is non-blocking API. Similar to launching via fork()/exec()
1585 * we don't wait around to see if the program crashed during startup.
1586 * This is what startup-notification's job is...
1588 object_path
= object_path_from_appid (info
->app_id
);
1589 g_dbus_connection_call (session_bus
, info
->app_id
, object_path
, "org.freedesktop.Application",
1590 uris
? "Open" : "Activate", g_variant_builder_end (&builder
),
1591 NULL
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
1592 g_free (object_path
);
1598 g_desktop_app_info_launch_uris_internal (GAppInfo
*appinfo
,
1600 GAppLaunchContext
*launch_context
,
1601 GSpawnFlags spawn_flags
,
1602 GSpawnChildSetupFunc user_setup
,
1603 gpointer user_setup_data
,
1604 GDesktopAppLaunchCallback pid_callback
,
1605 gpointer pid_callback_data
,
1608 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1609 GDBusConnection
*session_bus
;
1610 gboolean success
= TRUE
;
1612 session_bus
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
1614 if (session_bus
&& info
->app_id
)
1615 g_desktop_app_info_launch_uris_with_dbus (info
, session_bus
, uris
, launch_context
);
1617 success
= g_desktop_app_info_launch_uris_with_spawn (info
, session_bus
, info
->exec
, uris
, launch_context
,
1618 spawn_flags
, user_setup
, user_setup_data
,
1619 pid_callback
, pid_callback_data
, error
);
1621 if (session_bus
!= NULL
)
1623 /* This asynchronous flush holds a reference until it completes,
1624 * which ensures that the following unref won't immediately kill
1625 * the connection if we were the initial owner.
1627 g_dbus_connection_flush (session_bus
, NULL
, NULL
, NULL
);
1628 g_object_unref (session_bus
);
1635 g_desktop_app_info_launch_uris (GAppInfo
*appinfo
,
1637 GAppLaunchContext
*launch_context
,
1640 return g_desktop_app_info_launch_uris_internal (appinfo
, uris
,
1642 _SPAWN_FLAGS_DEFAULT
,
1643 NULL
, NULL
, NULL
, NULL
,
1648 g_desktop_app_info_supports_uris (GAppInfo
*appinfo
)
1650 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1652 return info
->exec
&&
1653 ((strstr (info
->exec
, "%u") != NULL
) ||
1654 (strstr (info
->exec
, "%U") != NULL
));
1658 g_desktop_app_info_supports_files (GAppInfo
*appinfo
)
1660 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1662 return info
->exec
&&
1663 ((strstr (info
->exec
, "%f") != NULL
) ||
1664 (strstr (info
->exec
, "%F") != NULL
));
1668 g_desktop_app_info_launch (GAppInfo
*appinfo
,
1670 GAppLaunchContext
*launch_context
,
1680 uri
= g_file_get_uri (files
->data
);
1681 uris
= g_list_prepend (uris
, uri
);
1682 files
= files
->next
;
1685 uris
= g_list_reverse (uris
);
1687 res
= g_desktop_app_info_launch_uris (appinfo
, uris
, launch_context
, error
);
1689 g_list_free_full (uris
, g_free
);
1695 * g_desktop_app_info_launch_uris_as_manager:
1696 * @appinfo: a #GDesktopAppInfo
1697 * @uris: (element-type utf8): List of URIs
1698 * @launch_context: a #GAppLaunchContext
1699 * @spawn_flags: #GSpawnFlags, used for each process
1700 * @user_setup: (scope call): a #GSpawnChildSetupFunc, used once for
1702 * @user_setup_data: (closure user_setup): User data for @user_setup
1703 * @pid_callback: (scope call): Callback for child processes
1704 * @pid_callback_data: (closure pid_callback): User data for @callback
1705 * @error: return location for a #GError, or %NULL
1707 * This function performs the equivalent of g_app_info_launch_uris(),
1708 * but is intended primarily for operating system components that
1709 * launch applications. Ordinary applications should use
1710 * g_app_info_launch_uris().
1712 * If the application is launched via traditional UNIX fork()/exec()
1713 * then @spawn_flags, @user_setup and @user_setup_data are used for the
1714 * call to g_spawn_async(). Additionally, @pid_callback (with
1715 * @pid_callback_data) will be called to inform about the PID of the
1718 * If application launching occurs via some other mechanism (eg: D-Bus
1719 * activation) then @spawn_flags, @user_setup, @user_setup_data,
1720 * @pid_callback and @pid_callback_data are ignored.
1722 * Returns: %TRUE on successful launch, %FALSE otherwise.
1725 g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo
*appinfo
,
1727 GAppLaunchContext
*launch_context
,
1728 GSpawnFlags spawn_flags
,
1729 GSpawnChildSetupFunc user_setup
,
1730 gpointer user_setup_data
,
1731 GDesktopAppLaunchCallback pid_callback
,
1732 gpointer pid_callback_data
,
1735 return g_desktop_app_info_launch_uris_internal ((GAppInfo
*)appinfo
,
1746 /* OnlyShowIn API support {{{2 */
1749 * g_desktop_app_info_set_desktop_env:
1750 * @desktop_env: a string specifying what desktop this is
1752 * Sets the name of the desktop that the application is running in.
1753 * This is used by g_app_info_should_show() and
1754 * g_desktop_app_info_get_show_in() to evaluate the
1755 * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1756 * desktop entry fields.
1758 * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop
1759 * Menu specification</ulink> recognizes the following:
1761 * <member>GNOME</member>
1762 * <member>KDE</member>
1763 * <member>ROX</member>
1764 * <member>XFCE</member>
1765 * <member>LXDE</member>
1766 * <member>Unity</member>
1767 * <member>Old</member>
1770 * Should be called only once; subsequent calls are ignored.
1773 g_desktop_app_info_set_desktop_env (const gchar
*desktop_env
)
1775 G_LOCK (g_desktop_env
);
1777 g_desktop_env
= g_strdup (desktop_env
);
1778 G_UNLOCK (g_desktop_env
);
1782 g_desktop_app_info_should_show (GAppInfo
*appinfo
)
1784 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
1786 if (info
->nodisplay
)
1789 return g_desktop_app_info_get_show_in (info
, NULL
);
1792 /* mime types/default apps support {{{2 */
1800 ensure_dir (DirType type
,
1803 char *path
, *display_name
;
1806 if (type
== APP_DIR
)
1807 path
= g_build_filename (g_get_user_data_dir (), "applications", NULL
);
1809 path
= g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL
);
1812 if (g_mkdir_with_parents (path
, 0700) == 0)
1816 display_name
= g_filename_display_name (path
);
1817 if (type
== APP_DIR
)
1818 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
1819 _("Can't create user application configuration folder %s: %s"),
1820 display_name
, g_strerror (errsv
));
1822 g_set_error (error
, G_IO_ERROR
, g_io_error_from_errno (errsv
),
1823 _("Can't create user MIME configuration folder %s: %s"),
1824 display_name
, g_strerror (errsv
));
1826 g_free (display_name
);
1833 update_mimeapps_list (const char *desktop_id
,
1834 const char *content_type
,
1835 UpdateMimeFlags flags
,
1838 char *dirname
, *filename
, *string
;
1840 gboolean load_succeeded
, res
;
1841 char **old_list
, **list
;
1842 gsize length
, data_size
;
1845 char **content_types
;
1847 /* Don't add both at start and end */
1848 g_assert (!((flags
& UPDATE_MIME_SET_DEFAULT
) &&
1849 (flags
& UPDATE_MIME_SET_NON_DEFAULT
)));
1851 dirname
= ensure_dir (APP_DIR
, error
);
1855 filename
= g_build_filename (dirname
, "mimeapps.list", NULL
);
1858 key_file
= g_key_file_new ();
1859 load_succeeded
= g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, NULL
);
1860 if (!load_succeeded
||
1861 (!g_key_file_has_group (key_file
, ADDED_ASSOCIATIONS_GROUP
) &&
1862 !g_key_file_has_group (key_file
, REMOVED_ASSOCIATIONS_GROUP
) &&
1863 !g_key_file_has_group (key_file
, DEFAULT_APPLICATIONS_GROUP
)))
1865 g_key_file_free (key_file
);
1866 key_file
= g_key_file_new ();
1871 content_types
= g_new (char *, 2);
1872 content_types
[0] = g_strdup (content_type
);
1873 content_types
[1] = NULL
;
1877 content_types
= g_key_file_get_keys (key_file
, DEFAULT_APPLICATIONS_GROUP
, NULL
, NULL
);
1880 for (k
= 0; content_types
&& content_types
[k
]; k
++)
1882 /* set as default, if requested so */
1883 string
= g_key_file_get_string (key_file
,
1884 DEFAULT_APPLICATIONS_GROUP
,
1888 if (g_strcmp0 (string
, desktop_id
) != 0 &&
1889 (flags
& UPDATE_MIME_SET_DEFAULT
))
1892 string
= g_strdup (desktop_id
);
1894 /* add in the non-default list too, if it's not already there */
1895 flags
|= UPDATE_MIME_SET_NON_DEFAULT
;
1898 if (string
== NULL
|| desktop_id
== NULL
)
1899 g_key_file_remove_key (key_file
,
1900 DEFAULT_APPLICATIONS_GROUP
,
1904 g_key_file_set_string (key_file
,
1905 DEFAULT_APPLICATIONS_GROUP
,
1914 /* reuse the list from above */
1918 g_strfreev (content_types
);
1919 content_types
= g_key_file_get_keys (key_file
, ADDED_ASSOCIATIONS_GROUP
, NULL
, NULL
);
1922 for (k
= 0; content_types
&& content_types
[k
]; k
++)
1924 /* Add to the right place in the list */
1927 old_list
= g_key_file_get_string_list (key_file
, ADDED_ASSOCIATIONS_GROUP
,
1928 content_types
[k
], &length
, NULL
);
1930 list
= g_new (char *, 1 + length
+ 1);
1934 /* if we're adding a last-used hint, just put the application in front of the list */
1935 if (flags
& UPDATE_MIME_SET_LAST_USED
)
1937 /* avoid adding this again as non-default later */
1938 if (flags
& UPDATE_MIME_SET_NON_DEFAULT
)
1939 flags
^= UPDATE_MIME_SET_NON_DEFAULT
;
1941 list
[i
++] = g_strdup (desktop_id
);
1946 for (j
= 0; old_list
[j
] != NULL
; j
++)
1948 if (g_strcmp0 (old_list
[j
], desktop_id
) != 0)
1950 /* rewrite other entries if they're different from the new one */
1951 list
[i
++] = g_strdup (old_list
[j
]);
1953 else if (flags
& UPDATE_MIME_SET_NON_DEFAULT
)
1955 /* we encountered an old entry which is equal to the one we're adding as non-default,
1956 * don't change its position in the list.
1958 flags
^= UPDATE_MIME_SET_NON_DEFAULT
;
1959 list
[i
++] = g_strdup (old_list
[j
]);
1964 /* add it at the end of the list */
1965 if (flags
& UPDATE_MIME_SET_NON_DEFAULT
)
1966 list
[i
++] = g_strdup (desktop_id
);
1970 g_strfreev (old_list
);
1972 if (list
[0] == NULL
|| desktop_id
== NULL
)
1973 g_key_file_remove_key (key_file
,
1974 ADDED_ASSOCIATIONS_GROUP
,
1978 g_key_file_set_string_list (key_file
,
1979 ADDED_ASSOCIATIONS_GROUP
,
1981 (const char * const *)list
, i
);
1988 /* reuse the list from above */
1992 g_strfreev (content_types
);
1993 content_types
= g_key_file_get_keys (key_file
, REMOVED_ASSOCIATIONS_GROUP
, NULL
, NULL
);
1996 for (k
= 0; content_types
&& content_types
[k
]; k
++)
1998 /* Remove from removed associations group (unless remove) */
2001 old_list
= g_key_file_get_string_list (key_file
, REMOVED_ASSOCIATIONS_GROUP
,
2002 content_types
[k
], &length
, NULL
);
2004 list
= g_new (char *, 1 + length
+ 1);
2007 if (flags
& UPDATE_MIME_REMOVE
)
2008 list
[i
++] = g_strdup (desktop_id
);
2011 for (j
= 0; old_list
[j
] != NULL
; j
++)
2013 if (g_strcmp0 (old_list
[j
], desktop_id
) != 0)
2014 list
[i
++] = g_strdup (old_list
[j
]);
2019 g_strfreev (old_list
);
2021 if (list
[0] == NULL
|| desktop_id
== NULL
)
2022 g_key_file_remove_key (key_file
,
2023 REMOVED_ASSOCIATIONS_GROUP
,
2027 g_key_file_set_string_list (key_file
,
2028 REMOVED_ASSOCIATIONS_GROUP
,
2030 (const char * const *)list
, i
);
2035 g_strfreev (content_types
);
2037 data
= g_key_file_to_data (key_file
, &data_size
, error
);
2038 g_key_file_free (key_file
);
2040 res
= g_file_set_contents (filename
, data
, data_size
, error
);
2042 mime_info_cache_reload (NULL
);
2051 g_desktop_app_info_set_as_last_used_for_type (GAppInfo
*appinfo
,
2052 const char *content_type
,
2055 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2057 if (!g_desktop_app_info_ensure_saved (info
, error
))
2060 if (!info
->desktop_id
)
2062 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
2063 _("Application information lacks an identifier"));
2067 /* both add support for the content type and set as last used */
2068 return update_mimeapps_list (info
->desktop_id
, content_type
,
2069 UPDATE_MIME_SET_NON_DEFAULT
|
2070 UPDATE_MIME_SET_LAST_USED
,
2075 g_desktop_app_info_set_as_default_for_type (GAppInfo
*appinfo
,
2076 const char *content_type
,
2079 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2081 if (!g_desktop_app_info_ensure_saved (info
, error
))
2084 if (!info
->desktop_id
)
2086 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
2087 _("Application information lacks an identifier"));
2091 return update_mimeapps_list (info
->desktop_id
, content_type
,
2092 UPDATE_MIME_SET_DEFAULT
,
2097 update_program_done (GPid pid
,
2101 /* Did the application exit correctly */
2102 if (g_spawn_check_exit_status (status
, NULL
))
2104 /* Here we could clean out any caches in use */
2109 run_update_command (char *command
,
2118 GError
*error
= NULL
;
2121 argv
[1] = g_build_filename (g_get_user_data_dir (), subdir
, NULL
);
2123 if (g_spawn_async ("/", argv
,
2125 G_SPAWN_SEARCH_PATH
|
2126 G_SPAWN_STDOUT_TO_DEV_NULL
|
2127 G_SPAWN_STDERR_TO_DEV_NULL
|
2128 G_SPAWN_DO_NOT_REAP_CHILD
,
2129 NULL
, NULL
, /* No setup function */
2132 g_child_watch_add (pid
, update_program_done
, NULL
);
2135 /* If we get an error at this point, it's quite likely the user doesn't
2136 * have an installed copy of either 'update-mime-database' or
2137 * 'update-desktop-database'. I don't think we want to popup an error
2138 * dialog at this point, so we just do a g_warning to give the user a
2139 * chance of debugging it.
2141 g_warning ("%s", error
->message
);
2148 g_desktop_app_info_set_as_default_for_extension (GAppInfo
*appinfo
,
2149 const char *extension
,
2152 char *filename
, *basename
, *mimetype
;
2156 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (appinfo
), error
))
2159 dirname
= ensure_dir (MIMETYPE_DIR
, error
);
2163 basename
= g_strdup_printf ("user-extension-%s.xml", extension
);
2164 filename
= g_build_filename (dirname
, basename
, NULL
);
2168 mimetype
= g_strdup_printf ("application/x-extension-%s", extension
);
2170 if (!g_file_test (filename
, G_FILE_TEST_EXISTS
))
2175 g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2176 "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
2177 " <mime-type type=\"%s\">\n"
2178 " <comment>%s document</comment>\n"
2179 " <glob pattern=\"*.%s\"/>\n"
2181 "</mime-info>\n", mimetype
, extension
, extension
);
2183 g_file_set_contents (filename
, contents
, -1, NULL
);
2186 run_update_command ("update-mime-database", "mime");
2190 res
= g_desktop_app_info_set_as_default_for_type (appinfo
,
2200 g_desktop_app_info_add_supports_type (GAppInfo
*appinfo
,
2201 const char *content_type
,
2204 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2206 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info
), error
))
2209 return update_mimeapps_list (info
->desktop_id
, content_type
,
2210 UPDATE_MIME_SET_NON_DEFAULT
,
2215 g_desktop_app_info_can_remove_supports_type (GAppInfo
*appinfo
)
2221 g_desktop_app_info_remove_supports_type (GAppInfo
*appinfo
,
2222 const char *content_type
,
2225 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2227 if (!g_desktop_app_info_ensure_saved (G_DESKTOP_APP_INFO (info
), error
))
2230 return update_mimeapps_list (info
->desktop_id
, content_type
,
2235 static const char **
2236 g_desktop_app_info_get_supported_types (GAppInfo
*appinfo
)
2238 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2240 return (const char**) info
->mime_types
;
2243 /* Saving and deleting {{{2 */
2246 g_desktop_app_info_ensure_saved (GDesktopAppInfo
*info
,
2252 char *data
, *desktop_id
;
2257 if (info
->filename
!= NULL
)
2260 /* This is only used for object created with
2261 * g_app_info_create_from_commandline. All other
2262 * object should have a filename
2265 dirname
= ensure_dir (APP_DIR
, error
);
2269 key_file
= g_key_file_new ();
2271 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2272 "Encoding", "UTF-8");
2273 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2274 G_KEY_FILE_DESKTOP_KEY_VERSION
, "1.0");
2275 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2276 G_KEY_FILE_DESKTOP_KEY_TYPE
,
2277 G_KEY_FILE_DESKTOP_TYPE_APPLICATION
);
2279 g_key_file_set_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2280 G_KEY_FILE_DESKTOP_KEY_TERMINAL
, TRUE
);
2281 if (info
->nodisplay
)
2282 g_key_file_set_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2283 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY
, TRUE
);
2285 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2286 G_KEY_FILE_DESKTOP_KEY_EXEC
, info
->exec
);
2288 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2289 G_KEY_FILE_DESKTOP_KEY_NAME
, info
->name
);
2291 if (info
->generic_name
!= NULL
)
2292 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2293 GENERIC_NAME_KEY
, info
->generic_name
);
2295 if (info
->fullname
!= NULL
)
2296 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2297 FULL_NAME_KEY
, info
->fullname
);
2299 g_key_file_set_string (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2300 G_KEY_FILE_DESKTOP_KEY_COMMENT
, info
->comment
);
2302 g_key_file_set_boolean (key_file
, G_KEY_FILE_DESKTOP_GROUP
,
2303 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY
, TRUE
);
2305 data
= g_key_file_to_data (key_file
, &data_size
, NULL
);
2306 g_key_file_free (key_file
);
2308 desktop_id
= g_strdup_printf ("userapp-%s-XXXXXX.desktop", info
->name
);
2309 filename
= g_build_filename (dirname
, desktop_id
, NULL
);
2310 g_free (desktop_id
);
2313 fd
= g_mkstemp (filename
);
2318 display_name
= g_filename_display_name (filename
);
2319 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
2320 _("Can't create user desktop file %s"), display_name
);
2321 g_free (display_name
);
2327 desktop_id
= g_path_get_basename (filename
);
2329 /* FIXME - actually handle error */
2330 (void) g_close (fd
, NULL
);
2332 res
= g_file_set_contents (filename
, data
, data_size
, error
);
2336 g_free (desktop_id
);
2341 info
->filename
= filename
;
2342 info
->desktop_id
= desktop_id
;
2344 run_update_command ("update-desktop-database", "applications");
2350 g_desktop_app_info_can_delete (GAppInfo
*appinfo
)
2352 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2356 if (strstr (info
->filename
, "/userapp-"))
2357 return g_access (info
->filename
, W_OK
) == 0;
2364 g_desktop_app_info_delete (GAppInfo
*appinfo
)
2366 GDesktopAppInfo
*info
= G_DESKTOP_APP_INFO (appinfo
);
2370 if (g_remove (info
->filename
) == 0)
2372 update_mimeapps_list (info
->desktop_id
, NULL
,
2376 g_free (info
->filename
);
2377 info
->filename
= NULL
;
2378 g_free (info
->desktop_id
);
2379 info
->desktop_id
= NULL
;
2388 /* Create for commandline {{{2 */
2390 * g_app_info_create_from_commandline:
2391 * @commandline: the commandline to use
2392 * @application_name: (allow-none): the application name, or %NULL to use @commandline
2393 * @flags: flags that can specify details of the created #GAppInfo
2394 * @error: a #GError location to store the error occurring, %NULL to ignore.
2396 * Creates a new #GAppInfo from the given information.
2398 * Note that for @commandline, the quoting rules of the Exec key of the
2399 * <ulink url="http://freedesktop.org/Standards/desktop-entry-spec">freedesktop.org Desktop
2400 * Entry Specification</ulink> are applied. For example, if the @commandline contains
2401 * percent-encoded URIs, the percent-character must be doubled in order to prevent it from
2402 * being swallowed by Exec key unquoting. See the specification for exact quoting rules.
2404 * Returns: (transfer full): new #GAppInfo for given command.
2407 g_app_info_create_from_commandline (const char *commandline
,
2408 const char *application_name
,
2409 GAppInfoCreateFlags flags
,
2414 GDesktopAppInfo
*info
;
2416 g_return_val_if_fail (commandline
, NULL
);
2418 info
= g_object_new (G_TYPE_DESKTOP_APP_INFO
, NULL
);
2420 info
->filename
= NULL
;
2421 info
->desktop_id
= NULL
;
2423 info
->terminal
= (flags
& G_APP_INFO_CREATE_NEEDS_TERMINAL
) != 0;
2424 info
->startup_notify
= (flags
& G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION
) != 0;
2425 info
->hidden
= FALSE
;
2426 if ((flags
& G_APP_INFO_CREATE_SUPPORTS_URIS
) != 0)
2427 info
->exec
= g_strconcat (commandline
, " %u", NULL
);
2429 info
->exec
= g_strconcat (commandline
, " %f", NULL
);
2430 info
->nodisplay
= TRUE
;
2431 info
->binary
= binary_from_exec (info
->exec
);
2433 if (application_name
)
2434 info
->name
= g_strdup (application_name
);
2437 /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
2438 split
= g_strsplit (commandline
, " ", 2);
2439 basename
= split
[0] ? g_path_get_basename (split
[0]) : NULL
;
2441 info
->name
= basename
;
2442 if (info
->name
== NULL
)
2443 info
->name
= g_strdup ("custom");
2445 info
->comment
= g_strdup_printf (_("Custom definition for %s"), info
->name
);
2447 return G_APP_INFO (info
);
2450 /* GAppInfo interface init */
2453 g_desktop_app_info_iface_init (GAppInfoIface
*iface
)
2455 iface
->dup
= g_desktop_app_info_dup
;
2456 iface
->equal
= g_desktop_app_info_equal
;
2457 iface
->get_id
= g_desktop_app_info_get_id
;
2458 iface
->get_name
= g_desktop_app_info_get_name
;
2459 iface
->get_description
= g_desktop_app_info_get_description
;
2460 iface
->get_executable
= g_desktop_app_info_get_executable
;
2461 iface
->get_icon
= g_desktop_app_info_get_icon
;
2462 iface
->launch
= g_desktop_app_info_launch
;
2463 iface
->supports_uris
= g_desktop_app_info_supports_uris
;
2464 iface
->supports_files
= g_desktop_app_info_supports_files
;
2465 iface
->launch_uris
= g_desktop_app_info_launch_uris
;
2466 iface
->should_show
= g_desktop_app_info_should_show
;
2467 iface
->set_as_default_for_type
= g_desktop_app_info_set_as_default_for_type
;
2468 iface
->set_as_default_for_extension
= g_desktop_app_info_set_as_default_for_extension
;
2469 iface
->add_supports_type
= g_desktop_app_info_add_supports_type
;
2470 iface
->can_remove_supports_type
= g_desktop_app_info_can_remove_supports_type
;
2471 iface
->remove_supports_type
= g_desktop_app_info_remove_supports_type
;
2472 iface
->can_delete
= g_desktop_app_info_can_delete
;
2473 iface
->do_delete
= g_desktop_app_info_delete
;
2474 iface
->get_commandline
= g_desktop_app_info_get_commandline
;
2475 iface
->get_display_name
= g_desktop_app_info_get_display_name
;
2476 iface
->set_as_last_used_for_type
= g_desktop_app_info_set_as_last_used_for_type
;
2477 iface
->get_supported_types
= g_desktop_app_info_get_supported_types
;
2480 /* Recommended applications {{{2 */
2483 app_info_in_list (GAppInfo
*info
,
2486 while (list
!= NULL
)
2488 if (g_app_info_equal (info
, list
->data
))
2496 * g_app_info_get_recommended_for_type:
2497 * @content_type: the content type to find a #GAppInfo for
2499 * Gets a list of recommended #GAppInfos for a given content type, i.e.
2500 * those applications which claim to support the given content type exactly,
2501 * and not by MIME type subclassing.
2502 * Note that the first application of the list is the last used one, i.e.
2503 * the last one for which g_app_info_set_as_last_used_for_type() has been
2506 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
2507 * for given @content_type or %NULL on error.
2512 g_app_info_get_recommended_for_type (const gchar
*content_type
)
2514 GList
*desktop_entries
, *l
;
2516 GDesktopAppInfo
*info
;
2518 g_return_val_if_fail (content_type
!= NULL
, NULL
);
2520 desktop_entries
= get_all_desktop_entries_for_mime_type (content_type
, NULL
, FALSE
, NULL
);
2523 for (l
= desktop_entries
; l
!= NULL
; l
= l
->next
)
2525 char *desktop_entry
= l
->data
;
2527 info
= g_desktop_app_info_new (desktop_entry
);
2530 if (app_info_in_list (G_APP_INFO (info
), infos
))
2531 g_object_unref (info
);
2533 infos
= g_list_prepend (infos
, info
);
2535 g_free (desktop_entry
);
2538 g_list_free (desktop_entries
);
2540 return g_list_reverse (infos
);
2544 * g_app_info_get_fallback_for_type:
2545 * @content_type: the content type to find a #GAppInfo for
2547 * Gets a list of fallback #GAppInfos for a given content type, i.e.
2548 * those applications which claim to support the given content type
2549 * by MIME type subclassing and not directly.
2551 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
2552 * for given @content_type or %NULL on error.
2557 g_app_info_get_fallback_for_type (const gchar
*content_type
)
2559 GList
*desktop_entries
, *l
;
2560 GList
*infos
, *recommended_infos
;
2561 GDesktopAppInfo
*info
;
2563 g_return_val_if_fail (content_type
!= NULL
, NULL
);
2565 desktop_entries
= get_all_desktop_entries_for_mime_type (content_type
, NULL
, TRUE
, NULL
);
2566 recommended_infos
= g_app_info_get_recommended_for_type (content_type
);
2569 for (l
= desktop_entries
; l
!= NULL
; l
= l
->next
)
2571 char *desktop_entry
= l
->data
;
2573 info
= g_desktop_app_info_new (desktop_entry
);
2576 if (app_info_in_list (G_APP_INFO (info
), infos
) ||
2577 app_info_in_list (G_APP_INFO (info
), recommended_infos
))
2578 g_object_unref (info
);
2580 infos
= g_list_prepend (infos
, info
);
2582 g_free (desktop_entry
);
2585 g_list_free (desktop_entries
);
2586 g_list_free_full (recommended_infos
, g_object_unref
);
2588 return g_list_reverse (infos
);
2592 * g_app_info_get_all_for_type:
2593 * @content_type: the content type to find a #GAppInfo for
2595 * Gets a list of all #GAppInfos for a given content type,
2596 * including the recommended and fallback #GAppInfos. See
2597 * g_app_info_get_recommended_for_type() and
2598 * g_app_info_get_fallback_for_type().
2600 * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos
2601 * for given @content_type or %NULL on error.
2604 g_app_info_get_all_for_type (const char *content_type
)
2606 GList
*desktop_entries
, *l
;
2608 char *user_default
= NULL
;
2609 GDesktopAppInfo
*info
;
2611 g_return_val_if_fail (content_type
!= NULL
, NULL
);
2613 desktop_entries
= get_all_desktop_entries_for_mime_type (content_type
, NULL
, TRUE
, &user_default
);
2616 /* put the user default in front of the list, for compatibility */
2617 if (user_default
!= NULL
)
2619 info
= g_desktop_app_info_new (user_default
);
2622 infos
= g_list_prepend (infos
, info
);
2625 g_free (user_default
);
2627 for (l
= desktop_entries
; l
!= NULL
; l
= l
->next
)
2629 char *desktop_entry
= l
->data
;
2631 info
= g_desktop_app_info_new (desktop_entry
);
2634 if (app_info_in_list (G_APP_INFO (info
), infos
))
2635 g_object_unref (info
);
2637 infos
= g_list_prepend (infos
, info
);
2639 g_free (desktop_entry
);
2642 g_list_free (desktop_entries
);
2644 return g_list_reverse (infos
);
2648 * g_app_info_reset_type_associations:
2649 * @content_type: a content type
2651 * Removes all changes to the type associations done by
2652 * g_app_info_set_as_default_for_type(),
2653 * g_app_info_set_as_default_for_extension(),
2654 * g_app_info_add_supports_type() or
2655 * g_app_info_remove_supports_type().
2660 g_app_info_reset_type_associations (const char *content_type
)
2662 update_mimeapps_list (NULL
, content_type
,
2668 * g_app_info_get_default_for_type:
2669 * @content_type: the content type to find a #GAppInfo for
2670 * @must_support_uris: if %TRUE, the #GAppInfo is expected to
2673 * Gets the default #GAppInfo for a given content type.
2675 * Returns: (transfer full): #GAppInfo for given @content_type or
2679 g_app_info_get_default_for_type (const char *content_type
,
2680 gboolean must_support_uris
)
2682 GList
*desktop_entries
, *l
;
2683 char *user_default
= NULL
;
2686 g_return_val_if_fail (content_type
!= NULL
, NULL
);
2688 desktop_entries
= get_all_desktop_entries_for_mime_type (content_type
, NULL
, TRUE
, &user_default
);
2692 if (user_default
!= NULL
)
2694 info
= (GAppInfo
*) g_desktop_app_info_new (user_default
);
2698 if (must_support_uris
&& !g_app_info_supports_uris (info
))
2700 g_object_unref (info
);
2706 g_free (user_default
);
2710 g_list_free_full (desktop_entries
, g_free
);
2714 /* pick the first from the other list that matches our URI
2717 for (l
= desktop_entries
; l
!= NULL
; l
= l
->next
)
2719 char *desktop_entry
= l
->data
;
2721 info
= (GAppInfo
*)g_desktop_app_info_new (desktop_entry
);
2724 if (must_support_uris
&& !g_app_info_supports_uris (info
))
2726 g_object_unref (info
);
2734 g_list_free_full (desktop_entries
, g_free
);
2740 * g_app_info_get_default_for_uri_scheme:
2741 * @uri_scheme: a string containing a URI scheme.
2743 * Gets the default application for handling URIs with
2744 * the given URI scheme. A URI scheme is the initial part
2745 * of the URI, up to but not including the ':', e.g. "http",
2748 * Returns: (transfer full): #GAppInfo for given @uri_scheme or %NULL on error.
2751 g_app_info_get_default_for_uri_scheme (const char *uri_scheme
)
2754 char *content_type
, *scheme_down
;
2756 scheme_down
= g_ascii_strdown (uri_scheme
, -1);
2757 content_type
= g_strdup_printf ("x-scheme-handler/%s", scheme_down
);
2758 g_free (scheme_down
);
2759 app_info
= g_app_info_get_default_for_type (content_type
, FALSE
);
2760 g_free (content_type
);
2766 get_apps_from_dir (GHashTable
*apps
,
2767 const char *dirname
,
2771 const char *basename
;
2772 char *filename
, *subprefix
, *desktop_id
;
2774 GDesktopAppInfo
*appinfo
;
2776 dir
= g_dir_open (dirname
, 0, NULL
);
2779 while ((basename
= g_dir_read_name (dir
)) != NULL
)
2781 filename
= g_build_filename (dirname
, basename
, NULL
);
2782 if (g_str_has_suffix (basename
, ".desktop"))
2784 desktop_id
= g_strconcat (prefix
, basename
, NULL
);
2786 /* Use _extended so we catch NULLs too (hidden) */
2787 if (!g_hash_table_lookup_extended (apps
, desktop_id
, NULL
, NULL
))
2789 appinfo
= g_desktop_app_info_new_from_filename (filename
);
2792 if (appinfo
&& g_desktop_app_info_get_is_hidden (appinfo
))
2794 g_object_unref (appinfo
);
2799 if (appinfo
|| hidden
)
2801 g_hash_table_insert (apps
, g_strdup (desktop_id
), appinfo
);
2805 /* Reuse instead of strdup here */
2806 appinfo
->desktop_id
= desktop_id
;
2811 g_free (desktop_id
);
2815 if (g_file_test (filename
, G_FILE_TEST_IS_DIR
))
2817 subprefix
= g_strconcat (prefix
, basename
, "-", NULL
);
2818 get_apps_from_dir (apps
, filename
, subprefix
);
2828 /* "Get all" API {{{2 */
2831 * g_app_info_get_all:
2833 * Gets a list of all of the applications currently registered
2836 * For desktop files, this includes applications that have
2837 * <literal>NoDisplay=true</literal> set or are excluded from
2838 * display by means of <literal>OnlyShowIn</literal> or
2839 * <literal>NotShowIn</literal>. See g_app_info_should_show().
2840 * The returned list does not include applications which have
2841 * the <literal>Hidden</literal> key set.
2843 * Returns: (element-type GAppInfo) (transfer full): a newly allocated #GList of references to #GAppInfo<!---->s.
2846 g_app_info_get_all (void)
2849 GHashTableIter iter
;
2854 desktop_file_dirs_refresh ();
2856 apps
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2860 for (i
= 0; i
< n_desktop_file_dirs
; i
++)
2861 get_apps_from_dir (apps
, desktop_file_dirs
[i
].path
, "");
2865 g_hash_table_iter_init (&iter
, apps
);
2866 while (g_hash_table_iter_next (&iter
, NULL
, &value
))
2869 infos
= g_list_prepend (infos
, value
);
2872 g_hash_table_destroy (apps
);
2874 return g_list_reverse (infos
);
2877 /* Caching of mimeinfo.cache and defaults.list files {{{2 */
2881 GHashTable
*mime_info_cache_map
;
2882 GHashTable
*defaults_list_map
;
2883 GHashTable
*mimeapps_list_added_map
;
2884 GHashTable
*mimeapps_list_removed_map
;
2885 GHashTable
*mimeapps_list_defaults_map
;
2886 time_t mime_info_cache_timestamp
;
2887 time_t defaults_list_timestamp
;
2888 time_t mimeapps_list_timestamp
;
2892 GList
*dirs
; /* mimeinfo.cache and defaults.list */
2893 time_t last_stat_time
;
2896 static MimeInfoCache
*mime_info_cache
= NULL
;
2897 G_LOCK_DEFINE_STATIC (mime_info_cache
);
2899 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir
*dir
,
2900 const char *mime_type
,
2901 char **new_desktop_file_ids
);
2903 static MimeInfoCache
* mime_info_cache_new (void);
2906 destroy_info_cache_value (gpointer key
,
2910 g_list_free_full (value
, g_free
);
2914 destroy_info_cache_map (GHashTable
*info_cache_map
)
2916 g_hash_table_foreach (info_cache_map
, (GHFunc
)destroy_info_cache_value
, NULL
);
2917 g_hash_table_destroy (info_cache_map
);
2921 mime_info_cache_dir_out_of_date (MimeInfoCacheDir
*dir
,
2922 const char *cache_file
,
2928 filename
= g_build_filename (dir
->path
, cache_file
, NULL
);
2930 if (g_stat (filename
, &buf
) < 0)
2937 if (buf
.st_mtime
!= *timestamp
)
2943 /* Call with lock held */
2945 mime_info_cache_dir_init (MimeInfoCacheDir
*dir
)
2949 gchar
*filename
, **mime_types
;
2956 if (dir
->mime_info_cache_map
!= NULL
&&
2957 !mime_info_cache_dir_out_of_date (dir
, "mimeinfo.cache",
2958 &dir
->mime_info_cache_timestamp
))
2961 if (dir
->mime_info_cache_map
!= NULL
)
2962 destroy_info_cache_map (dir
->mime_info_cache_map
);
2964 dir
->mime_info_cache_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
2965 (GDestroyNotify
) g_free
,
2968 key_file
= g_key_file_new ();
2970 filename
= g_build_filename (dir
->path
, "mimeinfo.cache", NULL
);
2972 if (g_stat (filename
, &buf
) < 0)
2975 dir
->mime_info_cache_timestamp
= buf
.st_mtime
;
2977 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, &load_error
);
2982 if (load_error
!= NULL
)
2985 mime_types
= g_key_file_get_keys (key_file
, MIME_CACHE_GROUP
,
2988 if (load_error
!= NULL
)
2991 for (i
= 0; mime_types
[i
] != NULL
; i
++)
2993 gchar
**desktop_file_ids
;
2994 char *unaliased_type
;
2995 desktop_file_ids
= g_key_file_get_string_list (key_file
,
3001 if (desktop_file_ids
== NULL
)
3004 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
3005 mime_info_cache_dir_add_desktop_entries (dir
,
3008 g_free (unaliased_type
);
3010 g_strfreev (desktop_file_ids
);
3013 g_strfreev (mime_types
);
3014 g_key_file_free (key_file
);
3019 g_key_file_free (key_file
);
3021 if (mime_types
!= NULL
)
3022 g_strfreev (mime_types
);
3025 g_error_free (load_error
);
3029 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir
*dir
)
3033 gchar
*filename
, **mime_types
;
3034 char *unaliased_type
;
3035 char **desktop_file_ids
;
3042 if (dir
->defaults_list_map
!= NULL
&&
3043 !mime_info_cache_dir_out_of_date (dir
, "defaults.list",
3044 &dir
->defaults_list_timestamp
))
3047 if (dir
->defaults_list_map
!= NULL
)
3048 g_hash_table_destroy (dir
->defaults_list_map
);
3049 dir
->defaults_list_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
3050 g_free
, (GDestroyNotify
)g_strfreev
);
3053 key_file
= g_key_file_new ();
3055 filename
= g_build_filename (dir
->path
, "defaults.list", NULL
);
3056 if (g_stat (filename
, &buf
) < 0)
3059 dir
->defaults_list_timestamp
= buf
.st_mtime
;
3061 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, &load_error
);
3065 if (load_error
!= NULL
)
3068 mime_types
= g_key_file_get_keys (key_file
, DEFAULT_APPLICATIONS_GROUP
,
3070 if (mime_types
!= NULL
)
3072 for (i
= 0; mime_types
[i
] != NULL
; i
++)
3074 desktop_file_ids
= g_key_file_get_string_list (key_file
,
3075 DEFAULT_APPLICATIONS_GROUP
,
3079 if (desktop_file_ids
== NULL
)
3082 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
3083 g_hash_table_replace (dir
->defaults_list_map
,
3088 g_strfreev (mime_types
);
3091 g_key_file_free (key_file
);
3096 g_key_file_free (key_file
);
3098 if (mime_types
!= NULL
)
3099 g_strfreev (mime_types
);
3102 g_error_free (load_error
);
3106 mime_info_cache_dir_init_mimeapps_list (MimeInfoCacheDir
*dir
)
3110 gchar
*filename
, **mime_types
;
3111 char *unaliased_type
;
3112 char **desktop_file_ids
;
3120 if (dir
->mimeapps_list_added_map
!= NULL
&&
3121 !mime_info_cache_dir_out_of_date (dir
, "mimeapps.list",
3122 &dir
->mimeapps_list_timestamp
))
3125 if (dir
->mimeapps_list_added_map
!= NULL
)
3126 g_hash_table_destroy (dir
->mimeapps_list_added_map
);
3127 dir
->mimeapps_list_added_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
3128 g_free
, (GDestroyNotify
)g_strfreev
);
3130 if (dir
->mimeapps_list_removed_map
!= NULL
)
3131 g_hash_table_destroy (dir
->mimeapps_list_removed_map
);
3132 dir
->mimeapps_list_removed_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
3133 g_free
, (GDestroyNotify
)g_strfreev
);
3135 if (dir
->mimeapps_list_defaults_map
!= NULL
)
3136 g_hash_table_destroy (dir
->mimeapps_list_defaults_map
);
3137 dir
->mimeapps_list_defaults_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
3140 key_file
= g_key_file_new ();
3142 filename
= g_build_filename (dir
->path
, "mimeapps.list", NULL
);
3143 if (g_stat (filename
, &buf
) < 0)
3146 dir
->mimeapps_list_timestamp
= buf
.st_mtime
;
3148 g_key_file_load_from_file (key_file
, filename
, G_KEY_FILE_NONE
, &load_error
);
3152 if (load_error
!= NULL
)
3155 mime_types
= g_key_file_get_keys (key_file
, ADDED_ASSOCIATIONS_GROUP
,
3157 if (mime_types
!= NULL
)
3159 for (i
= 0; mime_types
[i
] != NULL
; i
++)
3161 desktop_file_ids
= g_key_file_get_string_list (key_file
,
3162 ADDED_ASSOCIATIONS_GROUP
,
3166 if (desktop_file_ids
== NULL
)
3169 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
3170 g_hash_table_replace (dir
->mimeapps_list_added_map
,
3175 g_strfreev (mime_types
);
3178 mime_types
= g_key_file_get_keys (key_file
, REMOVED_ASSOCIATIONS_GROUP
,
3180 if (mime_types
!= NULL
)
3182 for (i
= 0; mime_types
[i
] != NULL
; i
++)
3184 desktop_file_ids
= g_key_file_get_string_list (key_file
,
3185 REMOVED_ASSOCIATIONS_GROUP
,
3189 if (desktop_file_ids
== NULL
)
3192 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
3193 g_hash_table_replace (dir
->mimeapps_list_removed_map
,
3198 g_strfreev (mime_types
);
3201 mime_types
= g_key_file_get_keys (key_file
, DEFAULT_APPLICATIONS_GROUP
,
3203 if (mime_types
!= NULL
)
3205 for (i
= 0; mime_types
[i
] != NULL
; i
++)
3207 desktop_id
= g_key_file_get_string (key_file
,
3208 DEFAULT_APPLICATIONS_GROUP
,
3211 if (desktop_id
== NULL
)
3214 unaliased_type
= _g_unix_content_type_unalias (mime_types
[i
]);
3215 g_hash_table_replace (dir
->mimeapps_list_defaults_map
,
3220 g_strfreev (mime_types
);
3223 g_key_file_free (key_file
);
3228 g_key_file_free (key_file
);
3230 if (mime_types
!= NULL
)
3231 g_strfreev (mime_types
);
3234 g_error_free (load_error
);
3237 static MimeInfoCacheDir
*
3238 mime_info_cache_dir_new (const char *path
)
3240 MimeInfoCacheDir
*dir
;
3242 dir
= g_new0 (MimeInfoCacheDir
, 1);
3243 dir
->path
= g_strdup (path
);
3249 mime_info_cache_dir_free (MimeInfoCacheDir
*dir
)
3254 if (dir
->mime_info_cache_map
!= NULL
)
3256 destroy_info_cache_map (dir
->mime_info_cache_map
);
3257 dir
->mime_info_cache_map
= NULL
;
3261 if (dir
->defaults_list_map
!= NULL
)
3263 g_hash_table_destroy (dir
->defaults_list_map
);
3264 dir
->defaults_list_map
= NULL
;
3267 if (dir
->mimeapps_list_added_map
!= NULL
)
3269 g_hash_table_destroy (dir
->mimeapps_list_added_map
);
3270 dir
->mimeapps_list_added_map
= NULL
;
3273 if (dir
->mimeapps_list_removed_map
!= NULL
)
3275 g_hash_table_destroy (dir
->mimeapps_list_removed_map
);
3276 dir
->mimeapps_list_removed_map
= NULL
;
3279 if (dir
->mimeapps_list_defaults_map
!= NULL
)
3281 g_hash_table_destroy (dir
->mimeapps_list_defaults_map
);
3282 dir
->mimeapps_list_defaults_map
= NULL
;
3289 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir
*dir
,
3290 const char *mime_type
,
3291 char **new_desktop_file_ids
)
3293 GList
*desktop_file_ids
;
3296 desktop_file_ids
= g_hash_table_lookup (dir
->mime_info_cache_map
,
3299 for (i
= 0; new_desktop_file_ids
[i
] != NULL
; i
++)
3301 if (!g_list_find_custom (desktop_file_ids
, new_desktop_file_ids
[i
], (GCompareFunc
) strcmp
))
3302 desktop_file_ids
= g_list_append (desktop_file_ids
,
3303 g_strdup (new_desktop_file_ids
[i
]));
3306 g_hash_table_insert (dir
->mime_info_cache_map
, g_strdup (mime_type
), desktop_file_ids
);
3310 mime_info_cache_init_dir_lists (void)
3314 mime_info_cache
= mime_info_cache_new ();
3316 desktop_file_dirs_refresh ();
3318 for (i
= 0; i
< n_desktop_file_dirs
; i
++)
3320 MimeInfoCacheDir
*dir
;
3322 dir
= mime_info_cache_dir_new (desktop_file_dirs
[i
].path
);
3326 mime_info_cache_dir_init (dir
);
3327 mime_info_cache_dir_init_defaults_list (dir
);
3328 mime_info_cache_dir_init_mimeapps_list (dir
);
3330 mime_info_cache
->dirs
= g_list_append (mime_info_cache
->dirs
, dir
);
3336 mime_info_cache_update_dir_lists (void)
3340 tmp
= mime_info_cache
->dirs
;
3344 MimeInfoCacheDir
*dir
= (MimeInfoCacheDir
*) tmp
->data
;
3346 /* No need to do this if we had file monitors... */
3347 mime_info_cache_dir_init (dir
);
3348 mime_info_cache_dir_init_defaults_list (dir
);
3349 mime_info_cache_dir_init_mimeapps_list (dir
);
3356 mime_info_cache_init (void)
3358 G_LOCK (mime_info_cache
);
3359 if (mime_info_cache
== NULL
)
3360 mime_info_cache_init_dir_lists ();
3366 if (now
>= mime_info_cache
->last_stat_time
+ 10)
3368 mime_info_cache_update_dir_lists ();
3369 mime_info_cache
->last_stat_time
= now
;
3373 G_UNLOCK (mime_info_cache
);
3376 static MimeInfoCache
*
3377 mime_info_cache_new (void)
3379 MimeInfoCache
*cache
;
3381 cache
= g_new0 (MimeInfoCache
, 1);
3387 mime_info_cache_free (MimeInfoCache
*cache
)
3392 g_list_free_full (cache
->dirs
, (GDestroyNotify
) mime_info_cache_dir_free
);
3397 * mime_info_cache_reload:
3398 * @dir: directory path which needs reloading.
3400 * Reload the mime information for the @dir.
3403 mime_info_cache_reload (const char *dir
)
3405 /* FIXME: just reload the dir that needs reloading,
3406 * don't blow the whole cache
3408 if (mime_info_cache
!= NULL
)
3410 G_LOCK (mime_info_cache
);
3411 mime_info_cache_free (mime_info_cache
);
3412 mime_info_cache
= NULL
;
3413 G_UNLOCK (mime_info_cache
);
3418 append_desktop_entry (GList
*list
,
3419 const char *desktop_entry
,
3420 GList
*removed_entries
)
3422 /* Add if not already in list, and valid */
3423 if (!g_list_find_custom (list
, desktop_entry
, (GCompareFunc
) strcmp
) &&
3424 !g_list_find_custom (removed_entries
, desktop_entry
, (GCompareFunc
) strcmp
))
3425 list
= g_list_prepend (list
, g_strdup (desktop_entry
));
3431 * get_all_desktop_entries_for_mime_type:
3432 * @mime_type: a mime type.
3433 * @except: NULL or a strv list
3435 * Returns all the desktop ids for @mime_type. The desktop files
3436 * are listed in an order so that default applications are listed before
3437 * non-default ones, and handlers for inherited mimetypes are listed
3438 * after the base ones.
3440 * Optionally doesn't list the desktop ids given in the @except
3442 * Return value: a #GList containing the desktop ids which claim
3443 * to handle @mime_type.
3446 get_all_desktop_entries_for_mime_type (const char *base_mime_type
,
3447 const char **except
,
3448 gboolean include_fallback
,
3449 char **explicit_default
)
3451 GList
*desktop_entries
, *removed_entries
, *list
, *dir_list
, *tmp
;
3452 MimeInfoCacheDir
*dir
;
3453 char *mime_type
, *default_entry
= NULL
;
3454 char *old_default_entry
= NULL
;
3457 char **default_entries
;
3458 char **removed_associations
;
3459 gboolean already_found_handler
;
3464 mime_info_cache_init ();
3466 if (include_fallback
)
3468 /* collect all ancestors */
3469 mime_types
= _g_unix_content_type_get_parents (base_mime_type
);
3470 array
= g_ptr_array_new ();
3471 for (i
= 0; mime_types
[i
]; i
++)
3472 g_ptr_array_add (array
, mime_types
[i
]);
3473 g_free (mime_types
);
3474 for (i
= 0; i
< array
->len
; i
++)
3476 anc
= _g_unix_content_type_get_parents (g_ptr_array_index (array
, i
));
3477 for (j
= 0; anc
[j
]; j
++)
3479 for (k
= 0; k
< array
->len
; k
++)
3481 if (strcmp (anc
[j
], g_ptr_array_index (array
, k
)) == 0)
3484 if (k
== array
->len
) /* not found */
3485 g_ptr_array_add (array
, g_strdup (anc
[j
]));
3489 g_ptr_array_add (array
, NULL
);
3490 mime_types
= (char **)g_ptr_array_free (array
, FALSE
);
3494 mime_types
= g_malloc0 (2 * sizeof (gchar
*));
3495 mime_types
[0] = g_strdup (base_mime_type
);
3496 mime_types
[1] = NULL
;
3499 G_LOCK (mime_info_cache
);
3501 removed_entries
= NULL
;
3502 desktop_entries
= NULL
;
3504 for (i
= 0; except
!= NULL
&& except
[i
] != NULL
; i
++)
3505 removed_entries
= g_list_prepend (removed_entries
, g_strdup (except
[i
]));
3507 for (i
= 0; mime_types
[i
] != NULL
; i
++)
3509 mime_type
= mime_types
[i
];
3511 /* This is true if we already found a handler for a more specific
3512 mimetype. If its set we ignore any defaults for the less specific
3514 already_found_handler
= (desktop_entries
!= NULL
);
3516 /* Go through all apps listed in user and system dirs */
3517 for (dir_list
= mime_info_cache
->dirs
;
3519 dir_list
= dir_list
->next
)
3521 dir
= dir_list
->data
;
3523 /* Pick the explicit default application if we got no result earlier
3524 * (ie, for more specific mime types)
3526 if (!already_found_handler
)
3528 entry
= g_hash_table_lookup (dir
->mimeapps_list_defaults_map
, mime_type
);
3532 /* Save the default entry if it's the first one we encounter */
3533 if (default_entry
== NULL
)
3534 default_entry
= g_strdup (entry
);
3538 /* Then added associations from mimeapps.list */
3539 default_entries
= g_hash_table_lookup (dir
->mimeapps_list_added_map
, mime_type
);
3540 for (j
= 0; default_entries
!= NULL
&& default_entries
[j
] != NULL
; j
++)
3541 desktop_entries
= append_desktop_entry (desktop_entries
, default_entries
[j
], removed_entries
);
3543 /* Then removed associations from mimeapps.list */
3544 removed_associations
= g_hash_table_lookup (dir
->mimeapps_list_removed_map
, mime_type
);
3545 for (j
= 0; removed_associations
!= NULL
&& removed_associations
[j
] != NULL
; j
++)
3546 removed_entries
= append_desktop_entry (removed_entries
, removed_associations
[j
], NULL
);
3548 /* Then system defaults (or old per-user config) (using removed associations from this dir or earlier) */
3549 default_entries
= g_hash_table_lookup (dir
->defaults_list_map
, mime_type
);
3550 for (j
= 0; default_entries
!= NULL
&& default_entries
[j
] != NULL
; j
++)
3552 if (default_entry
== NULL
&& old_default_entry
== NULL
&& !already_found_handler
)
3553 old_default_entry
= g_strdup (default_entries
[j
]);
3555 desktop_entries
= append_desktop_entry (desktop_entries
, default_entries
[j
], removed_entries
);
3559 /* Go through all entries that support the mimetype */
3560 for (dir_list
= mime_info_cache
->dirs
;
3562 dir_list
= dir_list
->next
)
3564 dir
= dir_list
->data
;
3566 list
= g_hash_table_lookup (dir
->mime_info_cache_map
, mime_type
);
3567 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
)
3568 desktop_entries
= append_desktop_entry (desktop_entries
, tmp
->data
, removed_entries
);
3572 G_UNLOCK (mime_info_cache
);
3574 g_strfreev (mime_types
);
3576 /* If we have no default from mimeapps.list, take it from
3577 * defaults.list intead.
3579 * If we do have a default from mimeapps.list, free any one that came
3580 * from defaults.list.
3582 if (default_entry
== NULL
)
3583 default_entry
= old_default_entry
;
3585 g_free (old_default_entry
);
3587 if (explicit_default
!= NULL
)
3588 *explicit_default
= default_entry
;
3590 g_free (default_entry
);
3592 g_list_free_full (removed_entries
, g_free
);
3594 desktop_entries
= g_list_reverse (desktop_entries
);
3596 return desktop_entries
;
3599 /* GDesktopAppInfoLookup interface {{{2 */
3601 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
3603 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface
;
3604 G_DEFINE_INTERFACE (GDesktopAppInfoLookup
, g_desktop_app_info_lookup
, G_TYPE_OBJECT
)
3607 g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface
*iface
)
3611 /* "Get for mime type" APIs {{{2 */
3614 * g_desktop_app_info_lookup_get_default_for_uri_scheme:
3615 * @lookup: a #GDesktopAppInfoLookup
3616 * @uri_scheme: a string containing a URI scheme.
3618 * Gets the default application for launching applications
3619 * using this URI scheme for a particular GDesktopAppInfoLookup
3622 * The GDesktopAppInfoLookup interface and this function is used
3623 * to implement g_app_info_get_default_for_uri_scheme() backends
3624 * in a GIO module. There is no reason for applications to use it
3625 * directly. Applications should use g_app_info_get_default_for_uri_scheme().
3627 * Returns: (transfer full): #GAppInfo for given @uri_scheme or %NULL on error.
3629 * Deprecated: The #GDesktopAppInfoLookup interface is deprecated and unused by gio.
3632 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup
*lookup
,
3633 const char *uri_scheme
)
3635 GDesktopAppInfoLookupIface
*iface
;
3637 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup
), NULL
);
3639 iface
= G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup
);
3641 return (* iface
->get_default_for_uri_scheme
) (lookup
, uri_scheme
);
3644 G_GNUC_END_IGNORE_DEPRECATIONS
3646 /* Misc getter APIs {{{2 */
3649 * g_desktop_app_info_get_startup_wm_class:
3650 * @info: a #GDesktopAppInfo that supports startup notify
3652 * Retrieves the StartupWMClass field from @info. This represents the
3653 * WM_CLASS property of the main window of the application, if launched
3656 * Returns: (transfer none): the startup WM class, or %NULL if none is set
3657 * in the desktop file.
3662 g_desktop_app_info_get_startup_wm_class (GDesktopAppInfo
*info
)
3664 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), NULL
);
3666 return info
->startup_wm_class
;
3670 * g_desktop_app_info_get_string:
3671 * @info: a #GDesktopAppInfo
3672 * @key: the key to look up
3674 * Looks up a string value in the keyfile backing @info.
3676 * The @key is looked up in the "Desktop Entry" group.
3678 * Returns: a newly allocated string, or %NULL if the key
3684 g_desktop_app_info_get_string (GDesktopAppInfo
*info
,
3687 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), NULL
);
3689 return g_key_file_get_string (info
->keyfile
,
3690 G_KEY_FILE_DESKTOP_GROUP
, key
, NULL
);
3694 * g_desktop_app_info_get_boolean:
3695 * @info: a #GDesktopAppInfo
3696 * @key: the key to look up
3698 * Looks up a boolean value in the keyfile backing @info.
3700 * The @key is looked up in the "Desktop Entry" group.
3702 * Returns: the boolean value, or %FALSE if the key
3708 g_desktop_app_info_get_boolean (GDesktopAppInfo
*info
,
3711 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), FALSE
);
3713 return g_key_file_get_boolean (info
->keyfile
,
3714 G_KEY_FILE_DESKTOP_GROUP
, key
, NULL
);
3718 * g_desktop_app_info_has_key:
3719 * @info: a #GDesktopAppInfo
3720 * @key: the key to look up
3722 * Returns whether @key exists in the "Desktop Entry" group
3723 * of the keyfile backing @info.
3725 * Returns: %TRUE if the @key exists
3730 g_desktop_app_info_has_key (GDesktopAppInfo
*info
,
3733 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), FALSE
);
3735 return g_key_file_has_key (info
->keyfile
,
3736 G_KEY_FILE_DESKTOP_GROUP
, key
, NULL
);
3739 /* Desktop actions support {{{2 */
3742 * g_desktop_app_info_list_actions:
3743 * @info: a #GDesktopAppInfo
3745 * Returns the list of "additional application actions" supported on the
3746 * desktop file, as per the desktop file specification.
3748 * As per the specification, this is the list of actions that are
3749 * explicitly listed in the "Actions" key of the [Desktop Entry] group.
3751 * Returns: (array zero-terminated=1) (element-type utf8) (transfer none): a list of strings, always non-%NULL
3755 const gchar
* const *
3756 g_desktop_app_info_list_actions (GDesktopAppInfo
*info
)
3758 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), NULL
);
3760 return (const gchar
**) info
->actions
;
3764 app_info_has_action (GDesktopAppInfo
*info
,
3765 const gchar
*action_name
)
3769 for (i
= 0; info
->actions
[i
]; i
++)
3770 if (g_str_equal (info
->actions
[i
], action_name
))
3777 * g_desktop_app_info_get_action_name:
3778 * @info: a #GDesktopAppInfo
3779 * @action_name: the name of the action as from
3780 * g_desktop_app_info_list_actions()
3782 * Gets the user-visible display name of the "additional application
3783 * action" specified by @action_name.
3785 * This corresponds to the "Name" key within the keyfile group for the
3788 * Returns: (transfer full): the locale-specific action name
3793 g_desktop_app_info_get_action_name (GDesktopAppInfo
*info
,
3794 const gchar
*action_name
)
3799 g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info
), NULL
);
3800 g_return_val_if_fail (action_name
!= NULL
, NULL
);
3801 g_return_val_if_fail (app_info_has_action (info
, action_name
), NULL
);
3803 group_name
= g_strdup_printf ("Desktop Action %s", action_name
);
3804 result
= g_key_file_get_locale_string (info
->keyfile
, group_name
, "Name", NULL
, NULL
);
3805 g_free (group_name
);
3807 /* The spec says that the Name field must be given.
3809 * If it's not, let's follow the behaviour of our get_name()
3810 * implementation above and never return %NULL.
3813 result
= g_strdup (_("Unnamed"));
3819 * g_desktop_app_info_launch_action:
3820 * @info: a #GDesktopAppInfo
3821 * @action_name: the name of the action as from
3822 * g_desktop_app_info_list_actions()
3823 * @launch_context: (allow-none): a #GAppLaunchContext
3825 * Activates the named application action.
3827 * You may only call this function on action names that were
3828 * returned from g_desktop_app_info_list_actions().
3830 * Note that if the main entry of the desktop file indicates that the
3831 * application supports startup notification, and @launch_context is
3832 * non-%NULL, then startup notification will be used when activating the
3833 * action (and as such, invocation of the action on the receiving side
3834 * must signal the end of startup notification when it is completed).
3835 * This is the expected behaviour of applications declaring additional
3836 * actions, as per the desktop file specification.
3838 * As with g_app_info_launch() there is no way to detect failures that
3839 * occur while using this function.
3844 g_desktop_app_info_launch_action (GDesktopAppInfo
*info
,
3845 const gchar
*action_name
,
3846 GAppLaunchContext
*launch_context
)
3848 GDBusConnection
*session_bus
;
3850 g_return_if_fail (G_IS_DESKTOP_APP_INFO (info
));
3851 g_return_if_fail (action_name
!= NULL
);
3852 g_return_if_fail (app_info_has_action (info
, action_name
));
3854 session_bus
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
3856 if (session_bus
&& info
->app_id
)
3860 object_path
= object_path_from_appid (info
->app_id
);
3861 g_dbus_connection_call (session_bus
, info
->app_id
, object_path
,
3862 "org.freedesktop.Application", "ActivateAction",
3863 g_variant_new ("(sav@a{sv})", action_name
, NULL
,
3864 g_desktop_app_info_make_platform_data (info
, NULL
, launch_context
)),
3865 NULL
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
3866 g_free (object_path
);
3873 group_name
= g_strdup_printf ("Desktop Action %s", action_name
);
3874 exec_line
= g_key_file_get_string (info
->keyfile
, group_name
, "Exec", NULL
);
3875 g_free (group_name
);
3878 g_desktop_app_info_launch_uris_with_spawn (info
, session_bus
, exec_line
, NULL
, launch_context
,
3879 _SPAWN_FLAGS_DEFAULT
, NULL
, NULL
, NULL
, NULL
, NULL
);
3882 if (session_bus
!= NULL
)
3884 g_dbus_connection_flush (session_bus
, NULL
, NULL
, NULL
);
3885 g_object_unref (session_bus
);
3890 /* vim:set foldmethod=marker: */