diff --git a/gio/gappinfo.c b/gio/gappinfo.c
index dd2f75695..c54fc677b 100644
--- a/gio/gappinfo.c
+++ b/gio/gappinfo.c
@@ -116,6 +116,38 @@ g_app_info_default_init (GAppInfoInterface *iface)
{
}
+/**
+ * g_app_info_create_from_commandline:
+ * @commandline: (type filename): the command line to use
+ * @application_name: (nullable): the application name, or `NULL` to use @commandline
+ * @flags: flags that can specify details of the created [iface@Gio.AppInfo]
+ * @error: a [type@GLib.Error] location to store the error occurring,
+ * `NULL` to ignore.
+ *
+ * Creates a new [iface@Gio.AppInfo] from the given information.
+ *
+ * Note that for @commandline, the quoting rules of the `Exec` key of the
+ * [freedesktop.org Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec)
+ * are applied. For example, if the @commandline contains
+ * percent-encoded URIs, the percent-character must be doubled in order to prevent it from
+ * being swallowed by `Exec` key unquoting. See
+ * [the specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s07.html)
+ * for exact quoting rules.
+ *
+ * Returns: (transfer full): new [iface@Gio.AppInfo] for given command.
+ **/
+GAppInfo *
+g_app_info_create_from_commandline (const char *commandline,
+ const char *application_name,
+ GAppInfoCreateFlags flags,
+ GError **error)
+{
+ g_return_val_if_fail (commandline, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ return g_app_info_create_from_commandline_impl (commandline, application_name,
+ flags, error);
+}
/**
* g_app_info_dup:
@@ -374,6 +406,156 @@ g_app_info_set_as_last_used_for_type (GAppInfo *appinfo,
return FALSE;
}
+/**
+ * g_app_info_get_all:
+ *
+ * Gets a list of all of the applications currently registered
+ * on this system.
+ *
+ * For desktop files, this includes applications that have
+ * [`NoDisplay=true`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-nodisplay)
+ * set or are excluded from display by means of
+ * [`OnlyShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-onlyshowin)
+ * or [`NotShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-notshowin).
+ * See [method@Gio.AppInfo.should_show].
+ *
+ * The returned list does not include applications which have the
+ * [`Hidden` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-hidden)
+ * set.
+ *
+ * Returns: (element-type GAppInfo) (transfer full): a newly allocated
+ * list of references to [iface@Gio.AppInfo]s.
+ **/
+GList *
+g_app_info_get_all (void)
+{
+ return g_app_info_get_all_impl ();
+}
+
+/**
+ * g_app_info_get_recommended_for_type:
+ * @content_type: the content type to find a [iface@Gio.AppInfo] for
+ *
+ * Gets a list of recommended [iface@Gio.AppInfo]s for a given content type,
+ * i.e. those applications which claim to support the given content type
+ * exactly, and not by MIME type subclassing.
+ *
+ * Note that the first application of the list is the last used one, i.e.
+ * the last one for which [method@Gio.AppInfo.set_as_last_used_for_type] has
+ * been called.
+ *
+ * Returns: (element-type GAppInfo) (transfer full): list of
+ * [iface@Gio.AppInfo]s for given @content_type or `NULL` on error.
+ *
+ * Since: 2.28
+ **/
+GList *
+g_app_info_get_recommended_for_type (const gchar *content_type)
+{
+ g_return_val_if_fail (content_type != NULL, NULL);
+
+ return g_app_info_get_recommended_for_type_impl (content_type);
+}
+
+/**
+ * g_app_info_get_fallback_for_type:
+ * @content_type: the content type to find a [iface@Gio.AppInfo] for
+ *
+ * Gets a list of fallback [iface@Gio.AppInfo]s for a given content type, i.e.
+ * those applications which claim to support the given content type by MIME
+ * type subclassing and not directly.
+ *
+ * Returns: (element-type GAppInfo) (transfer full): list of [iface@Gio.AppInfo]s
+ * for given @content_type or `NULL` on error.
+ *
+ * Since: 2.28
+ **/
+GList *
+g_app_info_get_fallback_for_type (const gchar *content_type)
+{
+ g_return_val_if_fail (content_type != NULL, NULL);
+
+ return g_app_info_get_fallback_for_type_impl (content_type);
+}
+
+/**
+ * g_app_info_get_all_for_type:
+ * @content_type: the content type to find a [iface@Gio.AppInfo] for
+ *
+ * Gets a list of all [iface@Gio.AppInfo]s for a given content type,
+ * including the recommended and fallback [iface@Gio.AppInfo]s. See
+ * [func@Gio.AppInfo.get_recommended_for_type] and
+ * [func@Gio.AppInfo.get_fallback_for_type].
+ *
+ * Returns: (element-type GAppInfo) (transfer full): list of
+ * [iface@Gio.AppInfo]s for given @content_type.
+ **/
+GList *
+g_app_info_get_all_for_type (const char *content_type)
+{
+ g_return_val_if_fail (content_type != NULL, NULL);
+
+ return g_app_info_get_all_for_type_impl (content_type);
+}
+
+/**
+ * g_app_info_reset_type_associations:
+ * @content_type: a content type
+ *
+ * Removes all changes to the type associations done by
+ * [method@Gio.AppInfo.set_as_default_for_type],
+ * [method@Gio.AppInfo.set_as_default_for_extension],
+ * [method@Gio.AppInfo.add_supports_type] or
+ * [method@Gio.AppInfo.remove_supports_type].
+ *
+ * Since: 2.20
+ */
+void
+g_app_info_reset_type_associations (const char *content_type)
+{
+ g_app_info_reset_type_associations_impl (content_type);
+}
+
+/**
+ * g_app_info_get_default_for_type:
+ * @content_type: the content type to find a [iface@Gio.AppInfo] for
+ * @must_support_uris: if `TRUE`, the [iface@Gio.AppInfo] is expected to
+ * support URIs
+ *
+ * Gets the default [iface@Gio.AppInfo] for a given content type.
+ *
+ * Returns: (transfer full) (nullable): [iface@Gio.AppInfo] for given
+ * @content_type or `NULL` on error.
+ */
+GAppInfo *
+g_app_info_get_default_for_type (const char *content_type,
+ gboolean must_support_uris)
+{
+ g_return_val_if_fail (content_type != NULL, NULL);
+
+ return g_app_info_get_default_for_type_impl (content_type, must_support_uris);
+}
+
+/**
+ * g_app_info_get_default_for_uri_scheme:
+ * @uri_scheme: a string containing a URI scheme.
+ *
+ * Gets the default application for handling URIs with the given URI scheme.
+ *
+ * A URI scheme is the initial part of the URI, up to but not including the `:`.
+ * For example, `http`, `ftp` or `sip`.
+ *
+ * Returns: (transfer full) (nullable): [iface@Gio.AppInfo] for given
+ * @uri_scheme or `NULL` on error.
+ */
+GAppInfo *
+g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
+{
+ g_return_val_if_fail (uri_scheme != NULL && *uri_scheme != '\0', NULL);
+
+ return g_app_info_get_default_for_uri_scheme_impl (uri_scheme);
+}
+
/**
* g_app_info_set_as_default_for_extension:
* @appinfo: the app info
diff --git a/gio/gappinfoprivate.h b/gio/gappinfoprivate.h
index dbf46c22a..df6a2d3bf 100644
--- a/gio/gappinfoprivate.h
+++ b/gio/gappinfoprivate.h
@@ -25,4 +25,17 @@
void g_app_info_monitor_fire (void);
+GAppInfo *g_app_info_create_from_commandline_impl (const char *commandline,
+ const char *application_name,
+ GAppInfoCreateFlags flags,
+ GError **error);
+GList *g_app_info_get_recommended_for_type_impl (const gchar *content_type);
+GList *g_app_info_get_fallback_for_type_impl (const gchar *content_type);
+GList *g_app_info_get_all_for_type_impl (const char *content_type);
+void g_app_info_reset_type_associations_impl (const char *content_type);
+GAppInfo *g_app_info_get_default_for_type_impl (const char *content_type,
+ gboolean must_support_uris);
+GAppInfo *g_app_info_get_default_for_uri_scheme_impl (const char *uri_scheme);
+GList *g_app_info_get_all_impl (void);
+
#endif /* __G_APP_INFO_PRIVATE_H__ */
diff --git a/gio/gcontenttype-fdo.c b/gio/gcontenttype-fdo.c
new file mode 100644
index 000000000..230cea182
--- /dev/null
+++ b/gio/gcontenttype-fdo.c
@@ -0,0 +1,1356 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see .
+ *
+ * Author: Alexander Larsson
+ */
+
+#include "config.h"
+#include
+#include
+#include
+#include
+#include "gcontenttypeprivate.h"
+#include "gthemedicon.h"
+#include "gicon.h"
+#include "gfile.h"
+#include "gfileenumerator.h"
+#include "gfileinfo.h"
+#include "glibintl.h"
+#include "glib-private.h"
+
+#include
+
+#define XDG_PREFIX _gio_xdg
+#include "xdgmime/xdgmime.h"
+
+static void tree_magic_schedule_reload (void);
+
+/* We lock this mutex whenever we modify global state in this module.
+ * Taking and releasing this lock should always be associated with a pair of
+ * g_begin_ignore_leaks()/g_end_ignore_leaks() calls, as any call into xdgmime
+ * could trigger xdg_mime_init(), which makes a number of one-time allocations
+ * which GLib can never free as it doesn’t know when is suitable to call
+ * xdg_mime_shutdown(). */
+G_LOCK_DEFINE_STATIC (gio_xdgmime);
+
+gsize
+_g_unix_content_type_get_sniff_len (void)
+{
+ gsize size;
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ size = xdg_mime_get_max_buffer_extents ();
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ return size;
+}
+
+gchar *
+_g_unix_content_type_unalias (const gchar *type)
+{
+ gchar *res;
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ res = g_strdup (xdg_mime_unalias_mime_type (type));
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ return res;
+}
+
+gchar **
+_g_unix_content_type_get_parents (const gchar *type)
+{
+ const gchar *umime;
+ gchar **parents;
+ GPtrArray *array;
+ int i;
+
+ array = g_ptr_array_new ();
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+
+ umime = xdg_mime_unalias_mime_type (type);
+
+ g_ptr_array_add (array, g_strdup (umime));
+
+ parents = xdg_mime_list_mime_parents (umime);
+ for (i = 0; parents && parents[i] != NULL; i++)
+ g_ptr_array_add (array, g_strdup (parents[i]));
+
+ free (parents);
+
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ g_ptr_array_add (array, NULL);
+
+ return (gchar **)g_ptr_array_free (array, FALSE);
+}
+
+G_LOCK_DEFINE_STATIC (global_mime_dirs);
+static gchar **global_mime_dirs = NULL;
+
+static void
+_g_content_type_set_mime_dirs_locked (const char * const *dirs)
+{
+ g_clear_pointer (&global_mime_dirs, g_strfreev);
+
+ if (dirs != NULL)
+ {
+ global_mime_dirs = g_strdupv ((gchar **) dirs);
+ }
+ else
+ {
+ GPtrArray *mime_dirs = g_ptr_array_new_with_free_func (g_free);
+ const gchar * const *system_dirs = g_get_system_data_dirs ();
+
+ g_ptr_array_add (mime_dirs, g_build_filename (g_get_user_data_dir (), "mime", NULL));
+ for (; *system_dirs != NULL; system_dirs++)
+ g_ptr_array_add (mime_dirs, g_build_filename (*system_dirs, "mime", NULL));
+ g_ptr_array_add (mime_dirs, NULL); /* NULL terminator */
+
+ global_mime_dirs = (gchar **) g_ptr_array_free (mime_dirs, FALSE);
+ }
+
+ xdg_mime_set_dirs ((const gchar * const *) global_mime_dirs);
+ tree_magic_schedule_reload ();
+}
+
+/*< private >*/
+void
+g_content_type_set_mime_dirs_impl (const gchar * const *dirs)
+{
+ G_LOCK (global_mime_dirs);
+ _g_content_type_set_mime_dirs_locked (dirs);
+ G_UNLOCK (global_mime_dirs);
+}
+
+/*< private >*/
+const gchar * const *
+g_content_type_get_mime_dirs_impl (void)
+{
+ const gchar * const *mime_dirs;
+
+ G_LOCK (global_mime_dirs);
+
+ if (global_mime_dirs == NULL)
+ _g_content_type_set_mime_dirs_locked (NULL);
+
+ mime_dirs = (const gchar * const *) global_mime_dirs;
+
+ G_UNLOCK (global_mime_dirs);
+
+ g_assert (mime_dirs != NULL);
+ return mime_dirs;
+}
+
+gboolean
+g_content_type_equals_impl (const gchar *type1,
+ const gchar *type2)
+{
+ gboolean res;
+
+ g_return_val_if_fail (type1 != NULL, FALSE);
+ g_return_val_if_fail (type2 != NULL, FALSE);
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ res = xdg_mime_mime_type_equal (type1, type2);
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ return res;
+}
+
+gboolean
+g_content_type_is_a_impl (const gchar *type,
+ const gchar *supertype)
+{
+ gboolean res;
+
+ g_return_val_if_fail (type != NULL, FALSE);
+ g_return_val_if_fail (supertype != NULL, FALSE);
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ res = xdg_mime_mime_type_subclass (type, supertype);
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ return res;
+}
+
+gboolean
+g_content_type_is_mime_type_impl (const gchar *type,
+ const gchar *mime_type)
+{
+ return g_content_type_is_a (type, mime_type);
+}
+
+gboolean
+g_content_type_is_unknown_impl (const gchar *type)
+{
+ g_return_val_if_fail (type != NULL, FALSE);
+
+ return strcmp (XDG_MIME_TYPE_UNKNOWN, type) == 0;
+}
+
+
+typedef enum {
+ MIME_TAG_TYPE_OTHER,
+ MIME_TAG_TYPE_COMMENT
+} MimeTagType;
+
+typedef struct {
+ int current_type;
+ int current_lang_level;
+ int comment_lang_level;
+ char *comment;
+} MimeParser;
+
+
+static int
+language_level (const char *lang)
+{
+ const char * const *lang_list;
+ int i;
+
+ /* The returned list is sorted from most desirable to least
+ desirable and always contains the default locale "C". */
+ lang_list = g_get_language_names ();
+
+ for (i = 0; lang_list[i]; i++)
+ if (strcmp (lang_list[i], lang) == 0)
+ return 1000-i;
+
+ return 0;
+}
+
+static void
+mime_info_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ int i;
+ const char *lang;
+ MimeParser *parser = user_data;
+
+ if (strcmp (element_name, "comment") == 0)
+ {
+ lang = "C";
+ for (i = 0; attribute_names[i]; i++)
+ if (strcmp (attribute_names[i], "xml:lang") == 0)
+ {
+ lang = attribute_values[i];
+ break;
+ }
+
+ parser->current_lang_level = language_level (lang);
+ parser->current_type = MIME_TAG_TYPE_COMMENT;
+ }
+ else
+ parser->current_type = MIME_TAG_TYPE_OTHER;
+}
+
+static void
+mime_info_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ MimeParser *parser = user_data;
+
+ parser->current_type = MIME_TAG_TYPE_OTHER;
+}
+
+static void
+mime_info_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ MimeParser *parser = user_data;
+
+ if (parser->current_type == MIME_TAG_TYPE_COMMENT &&
+ parser->current_lang_level > parser->comment_lang_level)
+ {
+ g_free (parser->comment);
+ parser->comment = g_strndup (text, text_len);
+ parser->comment_lang_level = parser->current_lang_level;
+ }
+}
+
+static char *
+load_comment_for_mime_helper (const char *dir,
+ const char *basename)
+{
+ GMarkupParseContext *context;
+ char *filename, *data;
+ gsize len;
+ gboolean res;
+ MimeParser parse_data = {0};
+ GMarkupParser parser = {
+ mime_info_start_element,
+ mime_info_end_element,
+ mime_info_text,
+ NULL,
+ NULL
+ };
+
+ filename = g_build_filename (dir, basename, NULL);
+
+ res = g_file_get_contents (filename, &data, &len, NULL);
+ g_free (filename);
+ if (!res)
+ return NULL;
+
+ context = g_markup_parse_context_new (&parser, G_MARKUP_DEFAULT_FLAGS, &parse_data, NULL);
+ res = g_markup_parse_context_parse (context, data, len, NULL);
+ g_free (data);
+ g_markup_parse_context_free (context);
+
+ if (!res)
+ return NULL;
+
+ return parse_data.comment;
+}
+
+
+static char *
+load_comment_for_mime (const char *mimetype)
+{
+ const char * const *dirs;
+ char *basename;
+ char *comment;
+ gsize i;
+
+ basename = g_strdup_printf ("%s.xml", mimetype);
+
+ dirs = g_content_type_get_mime_dirs ();
+ for (i = 0; dirs[i] != NULL; i++)
+ {
+ comment = load_comment_for_mime_helper (dirs[i], basename);
+ if (comment)
+ {
+ g_free (basename);
+ return comment;
+ }
+ }
+ g_free (basename);
+
+ return g_strdup_printf (_("%s type"), mimetype);
+}
+
+gchar *
+g_content_type_get_description_impl (const gchar *type)
+{
+ static GHashTable *type_comment_cache = NULL;
+ gchar *type_copy = NULL;
+ gchar *comment;
+
+ g_return_val_if_fail (type != NULL, NULL);
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ type = xdg_mime_unalias_mime_type (type);
+ g_end_ignore_leaks ();
+
+ if (type_comment_cache == NULL)
+ type_comment_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ comment = g_hash_table_lookup (type_comment_cache, type);
+ comment = g_strdup (comment);
+
+ if (comment != NULL)
+ {
+ G_UNLOCK (gio_xdgmime);
+ return g_steal_pointer (&comment);
+ }
+
+ type_copy = g_strdup (type);
+
+ G_UNLOCK (gio_xdgmime);
+ comment = load_comment_for_mime (type_copy);
+ G_LOCK (gio_xdgmime);
+
+ g_hash_table_insert (type_comment_cache,
+ g_steal_pointer (&type_copy),
+ g_strdup (comment));
+ G_UNLOCK (gio_xdgmime);
+
+ return g_steal_pointer (&comment);
+}
+
+char *
+g_content_type_get_mime_type_impl (const char *type)
+{
+ g_return_val_if_fail (type != NULL, NULL);
+
+ return g_strdup (type);
+}
+
+static GIcon *
+g_content_type_get_icon_internal (const gchar *type,
+ gboolean symbolic)
+{
+ char *mimetype_icon;
+ char *generic_mimetype_icon = NULL;
+ char *q;
+ char *icon_names[6];
+ int n = 0;
+ GIcon *themed_icon;
+ const char *xdg_icon;
+ int i;
+
+ g_return_val_if_fail (type != NULL, NULL);
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ xdg_icon = xdg_mime_get_icon (type);
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ if (xdg_icon)
+ icon_names[n++] = g_strdup (xdg_icon);
+
+ mimetype_icon = g_strdup (type);
+ while ((q = strchr (mimetype_icon, '/')) != NULL)
+ *q = '-';
+
+ icon_names[n++] = mimetype_icon;
+
+ generic_mimetype_icon = g_content_type_get_generic_icon_name (type);
+ if (generic_mimetype_icon)
+ icon_names[n++] = generic_mimetype_icon;
+
+ if (symbolic)
+ {
+ for (i = 0; i < n; i++)
+ {
+ icon_names[n + i] = icon_names[i];
+ icon_names[i] = g_strconcat (icon_names[i], "-symbolic", NULL);
+ }
+
+ n += n;
+ }
+
+ themed_icon = g_themed_icon_new_from_names (icon_names, n);
+
+ for (i = 0; i < n; i++)
+ g_free (icon_names[i]);
+
+ return themed_icon;
+}
+
+GIcon *
+g_content_type_get_icon_impl (const gchar *type)
+{
+ return g_content_type_get_icon_internal (type, FALSE);
+}
+
+GIcon *
+g_content_type_get_symbolic_icon_impl (const gchar *type)
+{
+ return g_content_type_get_icon_internal (type, TRUE);
+}
+
+gchar *
+g_content_type_get_generic_icon_name_impl (const gchar *type)
+{
+ const gchar *xdg_icon_name;
+ gchar *icon_name;
+
+ g_return_val_if_fail (type != NULL, NULL);
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ xdg_icon_name = xdg_mime_get_generic_icon (type);
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ if (!xdg_icon_name)
+ {
+ const char *p;
+ const char *suffix = "-x-generic";
+
+ p = strchr (type, '/');
+ if (p == NULL)
+ p = type + strlen (type);
+
+ icon_name = g_malloc (p - type + strlen (suffix) + 1);
+ memcpy (icon_name, type, p - type);
+ memcpy (icon_name + (p - type), suffix, strlen (suffix));
+ icon_name[(p - type) + strlen (suffix)] = 0;
+ }
+ else
+ {
+ icon_name = g_strdup (xdg_icon_name);
+ }
+
+ return icon_name;
+}
+
+gboolean
+g_content_type_can_be_executable_impl (const gchar *type)
+{
+ g_return_val_if_fail (type != NULL, FALSE);
+
+ if (g_content_type_is_a (type, "application/x-executable") ||
+ g_content_type_is_a (type, "text/plain"))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+looks_like_text (const guchar *data, gsize data_size)
+{
+ gsize i;
+ char c;
+
+ for (i = 0; i < data_size; i++)
+ {
+ c = data[i];
+
+ if (g_ascii_iscntrl (c) &&
+ !g_ascii_isspace (c) &&
+ c != '\b')
+ return FALSE;
+ }
+ return TRUE;
+}
+
+gchar *
+g_content_type_from_mime_type_impl (const gchar *mime_type)
+{
+ char *umime;
+
+ g_return_val_if_fail (mime_type != NULL, NULL);
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+ /* mime type and content type are same on unixes */
+ umime = g_strdup (xdg_mime_unalias_mime_type (mime_type));
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ return umime;
+}
+
+gchar *
+g_content_type_guess_impl (const gchar *filename,
+ const guchar *data,
+ gsize data_size,
+ gboolean *result_uncertain)
+{
+ char *basename;
+ const char *name_mimetypes[10], *sniffed_mimetype;
+ char *mimetype;
+ int i;
+ int n_name_mimetypes;
+ int sniffed_prio;
+
+ sniffed_prio = 0;
+ n_name_mimetypes = 0;
+ sniffed_mimetype = XDG_MIME_TYPE_UNKNOWN;
+
+ if (result_uncertain)
+ *result_uncertain = FALSE;
+
+ /* our test suite and potentially other code used -1 in the past, which is
+ * not documented and not allowed; guard against that */
+ g_return_val_if_fail (data_size != (gsize) -1, g_strdup (XDG_MIME_TYPE_UNKNOWN));
+
+ G_LOCK (gio_xdgmime);
+ g_begin_ignore_leaks ();
+
+ if (filename)
+ {
+ i = strlen (filename);
+ if (i > 0 && filename[i - 1] == '/')
+ {
+ name_mimetypes[0] = "inode/directory";
+ name_mimetypes[1] = NULL;
+ n_name_mimetypes = 1;
+ if (result_uncertain)
+ *result_uncertain = TRUE;
+ }
+ else
+ {
+ basename = g_path_get_basename (filename);
+ n_name_mimetypes = xdg_mime_get_mime_types_from_file_name (basename, name_mimetypes, 10);
+ g_free (basename);
+ }
+ }
+
+ /* Got an extension match, and no conflicts. This is it. */
+ if (n_name_mimetypes == 1)
+ {
+ gchar *s = g_strdup (name_mimetypes[0]);
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+ return s;
+ }
+
+ if (data)
+ {
+ sniffed_mimetype = xdg_mime_get_mime_type_for_data (data, data_size, &sniffed_prio);
+ if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
+ data &&
+ looks_like_text (data, data_size))
+ sniffed_mimetype = "text/plain";
+
+ /* For security reasons we don't ever want to sniff desktop files
+ * where we know the filename and it doesn't have a .desktop extension.
+ * This is because desktop files allow executing any application and
+ * we don't want to make it possible to hide them looking like something
+ * else.
+ */
+ if (filename != NULL &&
+ strcmp (sniffed_mimetype, "application/x-desktop") == 0)
+ sniffed_mimetype = "text/plain";
+ }
+
+ if (n_name_mimetypes == 0)
+ {
+ if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
+ result_uncertain)
+ *result_uncertain = TRUE;
+
+ mimetype = g_strdup (sniffed_mimetype);
+ }
+ else
+ {
+ mimetype = NULL;
+ if (sniffed_mimetype != XDG_MIME_TYPE_UNKNOWN)
+ {
+ if (sniffed_prio >= 80) /* High priority sniffing match, use that */
+ mimetype = g_strdup (sniffed_mimetype);
+ else
+ {
+ /* There are conflicts between the name matches and we
+ * have a sniffed type, use that as a tie breaker.
+ */
+ for (i = 0; i < n_name_mimetypes; i++)
+ {
+ if ( xdg_mime_mime_type_subclass (name_mimetypes[i], sniffed_mimetype))
+ {
+ /* This nametype match is derived from (or the same as)
+ * the sniffed type). This is probably it.
+ */
+ mimetype = g_strdup (name_mimetypes[i]);
+ break;
+ }
+ }
+ }
+ }
+
+ if (mimetype == NULL)
+ {
+ /* Conflicts, and sniffed type was no help or not there.
+ * Guess on the first one
+ */
+ mimetype = g_strdup (name_mimetypes[0]);
+ if (result_uncertain)
+ *result_uncertain = TRUE;
+ }
+ }
+
+ g_end_ignore_leaks ();
+ G_UNLOCK (gio_xdgmime);
+
+ return mimetype;
+}
+
+static void
+enumerate_mimetypes_subdir (const char *dir,
+ const char *prefix,
+ GHashTable *mimetypes)
+{
+ DIR *d;
+ struct dirent *ent;
+ char *mimetype;
+
+ d = opendir (dir);
+ if (d)
+ {
+ while ((ent = readdir (d)) != NULL)
+ {
+ if (g_str_has_suffix (ent->d_name, ".xml"))
+ {
+ mimetype = g_strdup_printf ("%s/%.*s", prefix, (int) strlen (ent->d_name) - 4, ent->d_name);
+ g_hash_table_replace (mimetypes, mimetype, NULL);
+ }
+ }
+ closedir (d);
+ }
+}
+
+static void
+enumerate_mimetypes_dir (const char *dir,
+ GHashTable *mimetypes)
+{
+ DIR *d;
+ struct dirent *ent;
+ const char *mimedir;
+ char *name;
+
+ mimedir = dir;
+
+ d = opendir (mimedir);
+ if (d)
+ {
+ while ((ent = readdir (d)) != NULL)
+ {
+ if (strcmp (ent->d_name, "packages") != 0)
+ {
+ name = g_build_filename (mimedir, ent->d_name, NULL);
+ if (g_file_test (name, G_FILE_TEST_IS_DIR))
+ enumerate_mimetypes_subdir (name, ent->d_name, mimetypes);
+ g_free (name);
+ }
+ }
+ closedir (d);
+ }
+}
+
+GList *
+g_content_types_get_registered_impl (void)
+{
+ const char * const *dirs;
+ GHashTable *mimetypes;
+ GHashTableIter iter;
+ gpointer key;
+ gsize i;
+ GList *l;
+
+ mimetypes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ dirs = g_content_type_get_mime_dirs ();
+ for (i = 0; dirs[i] != NULL; i++)
+ enumerate_mimetypes_dir (dirs[i], mimetypes);
+
+ l = NULL;
+ g_hash_table_iter_init (&iter, mimetypes);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ {
+ l = g_list_prepend (l, key);
+ g_hash_table_iter_steal (&iter);
+ }
+
+ g_hash_table_destroy (mimetypes);
+
+ return l;
+}
+
+
+/* tree magic data */
+static GList *tree_matches = NULL;
+static gboolean need_reload = FALSE;
+
+G_LOCK_DEFINE_STATIC (gio_treemagic);
+
+typedef struct
+{
+ gchar *path;
+ GFileType type;
+ guint match_case : 1;
+ guint executable : 1;
+ guint non_empty : 1;
+ guint on_disc : 1;
+ gchar *mimetype;
+ GList *matches;
+} TreeMatchlet;
+
+typedef struct
+{
+ gchar *contenttype;
+ gint priority;
+ GList *matches;
+} TreeMatch;
+
+
+static void
+tree_matchlet_free (TreeMatchlet *matchlet)
+{
+ g_list_free_full (matchlet->matches, (GDestroyNotify) tree_matchlet_free);
+ g_free (matchlet->path);
+ g_free (matchlet->mimetype);
+ g_slice_free (TreeMatchlet, matchlet);
+}
+
+static void
+tree_match_free (TreeMatch *match)
+{
+ g_list_free_full (match->matches, (GDestroyNotify) tree_matchlet_free);
+ g_free (match->contenttype);
+ g_slice_free (TreeMatch, match);
+}
+
+static TreeMatch *
+parse_header (gchar *line)
+{
+ gint len;
+ gchar *s;
+ TreeMatch *match;
+
+ len = strlen (line);
+
+ if (line[0] != '[' || line[len - 1] != ']')
+ return NULL;
+
+ line[len - 1] = 0;
+ s = strchr (line, ':');
+ if (s == NULL)
+ return NULL;
+
+ match = g_slice_new0 (TreeMatch);
+ match->priority = atoi (line + 1);
+ match->contenttype = g_strdup (s + 1);
+
+ return match;
+}
+
+static TreeMatchlet *
+parse_match_line (gchar *line,
+ gint *depth)
+{
+ gchar *s, *p;
+ TreeMatchlet *matchlet;
+ gchar **parts;
+ gint i;
+
+ matchlet = g_slice_new0 (TreeMatchlet);
+
+ if (line[0] == '>')
+ {
+ *depth = 0;
+ s = line;
+ }
+ else
+ {
+ *depth = atoi (line);
+ s = strchr (line, '>');
+ if (s == NULL)
+ goto handle_error;
+ }
+ s += 2;
+ p = strchr (s, '"');
+ if (p == NULL)
+ goto handle_error;
+ *p = 0;
+
+ matchlet->path = g_strdup (s);
+ s = p + 1;
+ parts = g_strsplit (s, ",", 0);
+ if (strcmp (parts[0], "=file") == 0)
+ matchlet->type = G_FILE_TYPE_REGULAR;
+ else if (strcmp (parts[0], "=directory") == 0)
+ matchlet->type = G_FILE_TYPE_DIRECTORY;
+ else if (strcmp (parts[0], "=link") == 0)
+ matchlet->type = G_FILE_TYPE_SYMBOLIC_LINK;
+ else
+ matchlet->type = G_FILE_TYPE_UNKNOWN;
+ for (i = 1; parts[i]; i++)
+ {
+ if (strcmp (parts[i], "executable") == 0)
+ matchlet->executable = 1;
+ else if (strcmp (parts[i], "match-case") == 0)
+ matchlet->match_case = 1;
+ else if (strcmp (parts[i], "non-empty") == 0)
+ matchlet->non_empty = 1;
+ else if (strcmp (parts[i], "on-disc") == 0)
+ matchlet->on_disc = 1;
+ else
+ matchlet->mimetype = g_strdup (parts[i]);
+ }
+
+ g_strfreev (parts);
+
+ return matchlet;
+
+handle_error:
+ g_slice_free (TreeMatchlet, matchlet);
+ return NULL;
+}
+
+static gint
+cmp_match (gconstpointer a, gconstpointer b)
+{
+ const TreeMatch *aa = (const TreeMatch *)a;
+ const TreeMatch *bb = (const TreeMatch *)b;
+
+ return bb->priority - aa->priority;
+}
+
+static void
+insert_match (TreeMatch *match)
+{
+ tree_matches = g_list_insert_sorted (tree_matches, match, cmp_match);
+}
+
+static void
+insert_matchlet (TreeMatch *match,
+ TreeMatchlet *matchlet,
+ gint depth)
+{
+ if (depth == 0)
+ match->matches = g_list_append (match->matches, matchlet);
+ else
+ {
+ GList *last;
+ TreeMatchlet *m;
+
+ last = g_list_last (match->matches);
+ if (!last)
+ {
+ tree_matchlet_free (matchlet);
+ g_warning ("can't insert tree matchlet at depth %d", depth);
+ return;
+ }
+
+ m = (TreeMatchlet *) last->data;
+ while (--depth > 0)
+ {
+ last = g_list_last (m->matches);
+ if (!last)
+ {
+ tree_matchlet_free (matchlet);
+ g_warning ("can't insert tree matchlet at depth %d", depth);
+ return;
+ }
+
+ m = (TreeMatchlet *) last->data;
+ }
+ m->matches = g_list_append (m->matches, matchlet);
+ }
+}
+
+static void
+read_tree_magic_from_directory (const gchar *prefix)
+{
+ gchar *filename;
+ gchar *text;
+ gsize len;
+ gchar **lines;
+ gsize i;
+ TreeMatch *match;
+ TreeMatchlet *matchlet;
+ gint depth;
+
+ filename = g_build_filename (prefix, "treemagic", NULL);
+
+ if (g_file_get_contents (filename, &text, &len, NULL))
+ {
+ if (strcmp (text, "MIME-TreeMagic") == 0)
+ {
+ lines = g_strsplit (text + strlen ("MIME-TreeMagic") + 2, "\n", 0);
+ match = NULL;
+ for (i = 0; lines[i] && lines[i][0]; i++)
+ {
+ if (lines[i][0] == '[' && (match = parse_header (lines[i])) != NULL)
+ {
+ insert_match (match);
+ }
+ else if (match != NULL)
+ {
+ matchlet = parse_match_line (lines[i], &depth);
+ if (matchlet == NULL)
+ {
+ g_warning ("%s: body corrupt; skipping", filename);
+ break;
+ }
+ insert_matchlet (match, matchlet, depth);
+ }
+ else
+ {
+ g_warning ("%s: header corrupt; skipping", filename);
+ break;
+ }
+ }
+
+ g_strfreev (lines);
+ }
+ else
+ g_warning ("%s: header not found, skipping", filename);
+
+ g_free (text);
+ }
+
+ g_free (filename);
+}
+
+static void
+tree_magic_schedule_reload (void)
+{
+ need_reload = TRUE;
+}
+
+static void
+xdg_mime_reload (void *user_data)
+{
+ tree_magic_schedule_reload ();
+}
+
+static void
+tree_magic_shutdown (void)
+{
+ g_list_free_full (tree_matches, (GDestroyNotify) tree_match_free);
+ tree_matches = NULL;
+}
+
+static void
+tree_magic_init (void)
+{
+ static gboolean initialized = FALSE;
+ gsize i;
+
+ if (!initialized)
+ {
+ initialized = TRUE;
+
+ xdg_mime_register_reload_callback (xdg_mime_reload, NULL, NULL);
+ need_reload = TRUE;
+ }
+
+ if (need_reload)
+ {
+ const char * const *dirs;
+
+ need_reload = FALSE;
+
+ tree_magic_shutdown ();
+
+ dirs = g_content_type_get_mime_dirs ();
+ for (i = 0; dirs[i] != NULL; i++)
+ read_tree_magic_from_directory (dirs[i]);
+ }
+}
+
+/* a filtering enumerator */
+
+typedef struct
+{
+ gchar *path;
+ gint depth;
+ gboolean ignore_case;
+ gchar **components;
+ gchar **case_components;
+ GFileEnumerator **enumerators;
+ GFile **children;
+} Enumerator;
+
+static gboolean
+component_match (Enumerator *e,
+ gint depth,
+ const gchar *name)
+{
+ gchar *case_folded, *key, *utf8_name;
+ gboolean found;
+
+ if (strcmp (name, e->components[depth]) == 0)
+ return TRUE;
+
+ if (!e->ignore_case)
+ return FALSE;
+
+ utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+ if (utf8_name == NULL)
+ utf8_name = g_utf8_make_valid (name, -1);
+
+ case_folded = g_utf8_casefold (utf8_name, -1);
+ key = g_utf8_collate_key (case_folded, -1);
+
+ found = strcmp (key, e->case_components[depth]) == 0;
+
+ g_free (utf8_name);
+ g_free (case_folded);
+ g_free (key);
+
+ return found;
+}
+
+static GFile *
+next_match_recurse (Enumerator *e,
+ gint depth)
+{
+ GFile *file;
+ GFileInfo *info;
+ const gchar *name;
+
+ while (TRUE)
+ {
+ if (e->enumerators[depth] == NULL)
+ {
+ if (depth > 0)
+ {
+ file = next_match_recurse (e, depth - 1);
+ if (file)
+ {
+ e->children[depth] = file;
+ e->enumerators[depth] = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+ }
+ }
+ if (e->enumerators[depth] == NULL)
+ return NULL;
+ }
+
+ while ((info = g_file_enumerator_next_file (e->enumerators[depth], NULL, NULL)))
+ {
+ name = g_file_info_get_name (info);
+ if (component_match (e, depth, name))
+ {
+ file = g_file_get_child (e->children[depth], name);
+ g_object_unref (info);
+ return file;
+ }
+ g_object_unref (info);
+ }
+
+ g_object_unref (e->enumerators[depth]);
+ e->enumerators[depth] = NULL;
+ g_object_unref (e->children[depth]);
+ e->children[depth] = NULL;
+ }
+}
+
+static GFile *
+enumerator_next (Enumerator *e)
+{
+ return next_match_recurse (e, e->depth - 1);
+}
+
+static Enumerator *
+enumerator_new (GFile *root,
+ const char *path,
+ gboolean ignore_case)
+{
+ Enumerator *e;
+ gint i;
+ gchar *case_folded;
+
+ e = g_new0 (Enumerator, 1);
+ e->path = g_strdup (path);
+ e->ignore_case = ignore_case;
+
+ e->components = g_strsplit (e->path, G_DIR_SEPARATOR_S, -1);
+ e->depth = g_strv_length (e->components);
+ if (e->ignore_case)
+ {
+ e->case_components = g_new0 (char *, e->depth + 1);
+ for (i = 0; e->components[i]; i++)
+ {
+ case_folded = g_utf8_casefold (e->components[i], -1);
+ e->case_components[i] = g_utf8_collate_key (case_folded, -1);
+ g_free (case_folded);
+ }
+ }
+
+ e->children = g_new0 (GFile *, e->depth);
+ e->children[0] = g_object_ref (root);
+ e->enumerators = g_new0 (GFileEnumerator *, e->depth);
+ e->enumerators[0] = g_file_enumerate_children (root,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ return e;
+}
+
+static void
+enumerator_free (Enumerator *e)
+{
+ gint i;
+
+ for (i = 0; i < e->depth; i++)
+ {
+ if (e->enumerators[i])
+ g_object_unref (e->enumerators[i]);
+ if (e->children[i])
+ g_object_unref (e->children[i]);
+ }
+
+ g_free (e->enumerators);
+ g_free (e->children);
+ g_strfreev (e->components);
+ if (e->case_components)
+ g_strfreev (e->case_components);
+ g_free (e->path);
+ g_free (e);
+}
+
+static gboolean
+matchlet_match (TreeMatchlet *matchlet,
+ GFile *root)
+{
+ GFile *file;
+ GFileInfo *info;
+ gboolean result;
+ const gchar *attrs;
+ Enumerator *e;
+ GList *l;
+
+ e = enumerator_new (root, matchlet->path, !matchlet->match_case);
+
+ do
+ {
+ file = enumerator_next (e);
+ if (!file)
+ {
+ enumerator_free (e);
+ return FALSE;
+ }
+
+ if (matchlet->mimetype)
+ attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+ else
+ attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE;
+ info = g_file_query_info (file,
+ attrs,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+ if (info)
+ {
+ result = TRUE;
+
+ if (matchlet->type != G_FILE_TYPE_UNKNOWN &&
+ g_file_info_get_file_type (info) != matchlet->type)
+ result = FALSE;
+
+ if (matchlet->executable &&
+ !g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
+ result = FALSE;
+ }
+ else
+ result = FALSE;
+
+ if (result && matchlet->non_empty)
+ {
+ GFileEnumerator *child_enum;
+ GFileInfo *child_info;
+
+ child_enum = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (child_enum)
+ {
+ child_info = g_file_enumerator_next_file (child_enum, NULL, NULL);
+ if (child_info)
+ g_object_unref (child_info);
+ else
+ result = FALSE;
+ g_object_unref (child_enum);
+ }
+ else
+ result = FALSE;
+ }
+
+ if (result && matchlet->mimetype)
+ {
+ if (strcmp (matchlet->mimetype, g_file_info_get_content_type (info)) != 0)
+ result = FALSE;
+ }
+
+ if (info)
+ g_object_unref (info);
+ g_object_unref (file);
+ }
+ while (!result);
+
+ enumerator_free (e);
+
+ if (!matchlet->matches)
+ return TRUE;
+
+ for (l = matchlet->matches; l; l = l->next)
+ {
+ TreeMatchlet *submatchlet;
+
+ submatchlet = l->data;
+ if (matchlet_match (submatchlet, root))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+match_match (TreeMatch *match,
+ GFile *root,
+ GPtrArray *types)
+{
+ GList *l;
+
+ for (l = match->matches; l; l = l->next)
+ {
+ TreeMatchlet *matchlet = l->data;
+ if (matchlet_match (matchlet, root))
+ {
+ g_ptr_array_add (types, g_strdup (match->contenttype));
+ break;
+ }
+ }
+}
+
+gchar **
+g_content_type_guess_for_tree_impl (GFile *root)
+{
+ GPtrArray *types;
+ GList *l;
+
+ types = g_ptr_array_new ();
+
+ G_LOCK (gio_treemagic);
+
+ tree_magic_init ();
+ for (l = tree_matches; l; l = l->next)
+ {
+ TreeMatch *match = l->data;
+ match_match (match, root, types);
+ }
+
+ G_UNLOCK (gio_treemagic);
+
+ g_ptr_array_add (types, NULL);
+
+ return (gchar **)g_ptr_array_free (types, FALSE);
+}
diff --git a/gio/gosxcontenttype.m b/gio/gcontenttype-osx.m
similarity index 92%
rename from gio/gosxcontenttype.m
rename to gio/gcontenttype-osx.m
index 4d7a650c7..b498380cd 100644
--- a/gio/gosxcontenttype.m
+++ b/gio/gcontenttype-osx.m
@@ -20,6 +20,7 @@
#include "config.h"
#include "gcontenttype.h"
+#include "gcontenttypeprivate.h"
#include "gicon.h"
#include "gthemedicon.h"
@@ -107,22 +108,22 @@ create_cstr_from_cfstring_with_fallback (CFStringRef str,
/*< private >*/
void
-g_content_type_set_mime_dirs (const gchar * const *dirs)
+g_content_type_set_mime_dirs_impl (const gchar * const *dirs)
{
/* noop on macOS */
}
/*< private >*/
const gchar * const *
-g_content_type_get_mime_dirs (void)
+g_content_type_get_mime_dirs_impl (void)
{
const gchar * const *mime_dirs = { NULL };
return mime_dirs;
}
gboolean
-g_content_type_equals (const gchar *type1,
- const gchar *type2)
+g_content_type_equals_impl (const gchar *type1,
+ const gchar *type2)
{
CFStringRef str1, str2;
gboolean ret;
@@ -145,8 +146,8 @@ g_content_type_equals (const gchar *type1,
}
gboolean
-g_content_type_is_a (const gchar *ctype,
- const gchar *csupertype)
+g_content_type_is_a_impl (const gchar *ctype,
+ const gchar *csupertype)
{
CFStringRef type, supertype;
gboolean ret;
@@ -166,8 +167,8 @@ g_content_type_is_a (const gchar *ctype,
}
gboolean
-g_content_type_is_mime_type (const gchar *type,
- const gchar *mime_type)
+g_content_type_is_mime_type_impl (const gchar *type,
+ const gchar *mime_type)
{
gchar *content_type;
gboolean ret;
@@ -183,7 +184,7 @@ g_content_type_is_mime_type (const gchar *type,
}
gboolean
-g_content_type_is_unknown (const gchar *type)
+g_content_type_is_unknown_impl (const gchar *type)
{
g_return_val_if_fail (type != NULL, FALSE);
@@ -198,7 +199,7 @@ g_content_type_is_unknown (const gchar *type)
}
gchar *
-g_content_type_get_description (const gchar *type)
+g_content_type_get_description_impl (const gchar *type)
{
CFStringRef str;
CFStringRef desc_str;
@@ -327,25 +328,25 @@ g_content_type_get_icon_internal (const gchar *uti,
}
GIcon *
-g_content_type_get_icon (const gchar *type)
+g_content_type_get_icon_impl (const gchar *type)
{
return g_content_type_get_icon_internal (type, FALSE);
}
GIcon *
-g_content_type_get_symbolic_icon (const gchar *type)
+g_content_type_get_symbolic_icon_impl (const gchar *type)
{
return g_content_type_get_icon_internal (type, TRUE);
}
gchar *
-g_content_type_get_generic_icon_name (const gchar *type)
+g_content_type_get_generic_icon_name_impl (const gchar *type)
{
return NULL;
}
gboolean
-g_content_type_can_be_executable (const gchar *type)
+g_content_type_can_be_executable_impl (const gchar *type)
{
CFStringRef uti;
gboolean ret = FALSE;
@@ -369,7 +370,7 @@ g_content_type_can_be_executable (const gchar *type)
}
gchar *
-g_content_type_from_mime_type (const gchar *mime_type)
+g_content_type_from_mime_type_impl (const gchar *mime_type)
{
CFStringRef mime_str;
CFStringRef uti_str;
@@ -437,7 +438,7 @@ g_content_type_from_mime_type (const gchar *mime_type)
}
gchar *
-g_content_type_get_mime_type (const gchar *type)
+g_content_type_get_mime_type_impl (const gchar *type)
{
CFStringRef uti_str;
CFStringRef mime_str;
@@ -489,10 +490,10 @@ looks_like_text (const guchar *data,
}
gchar *
-g_content_type_guess (const gchar *filename,
- const guchar *data,
- gsize data_size,
- gboolean *result_uncertain)
+g_content_type_guess_impl (const gchar *filename,
+ const guchar *data,
+ gsize data_size,
+ gboolean *result_uncertain)
{
CFStringRef uti = NULL;
gchar *cextension;
@@ -595,14 +596,14 @@ g_content_type_guess (const gchar *filename,
}
GList *
-g_content_types_get_registered (void)
+g_content_types_get_registered_impl (void)
{
/* TODO: UTTypeCreateAllIdentifiersForTag? */
return NULL;
}
gchar **
-g_content_type_guess_for_tree (GFile *root)
+g_content_type_guess_for_tree_impl (GFile *root)
{
return NULL;
}
diff --git a/gio/gcontenttype-win32.c b/gio/gcontenttype-win32.c
index d227d599e..a81a86976 100644
--- a/gio/gcontenttype-win32.c
+++ b/gio/gcontenttype-win32.c
@@ -28,6 +28,7 @@
#include
#include
#include "gcontenttype.h"
+#include "gcontenttypeprivate.h"
#include "gthemedicon.h"
#include "gicon.h"
#include "glibintl.h"
@@ -87,22 +88,22 @@ get_registry_classes_key (const char *subdir,
/*< private >*/
void
-g_content_type_set_mime_dirs (const gchar * const *dirs)
+g_content_type_set_mime_dirs_impl (const gchar * const *dirs)
{
/* noop on Windows */
}
/*< private >*/
const gchar * const *
-g_content_type_get_mime_dirs (void)
+g_content_type_get_mime_dirs_impl (void)
{
const gchar * const *mime_dirs = { NULL };
return mime_dirs;
}
gboolean
-g_content_type_equals (const gchar *type1,
- const gchar *type2)
+g_content_type_equals_impl (const gchar *type1,
+ const gchar *type2)
{
char *progid1, *progid2;
gboolean res;
@@ -126,8 +127,8 @@ g_content_type_equals (const gchar *type1,
}
gboolean
-g_content_type_is_a (const gchar *type,
- const gchar *supertype)
+g_content_type_is_a_impl (const gchar *type,
+ const gchar *supertype)
{
gboolean res;
char *perceived_type;
@@ -152,8 +153,8 @@ g_content_type_is_a (const gchar *type,
}
gboolean
-g_content_type_is_mime_type (const gchar *type,
- const gchar *mime_type)
+g_content_type_is_mime_type_impl (const gchar *type,
+ const gchar *mime_type)
{
gchar *content_type;
gboolean ret;
@@ -169,7 +170,7 @@ g_content_type_is_mime_type (const gchar *type,
}
gboolean
-g_content_type_is_unknown (const gchar *type)
+g_content_type_is_unknown_impl (const gchar *type)
{
g_return_val_if_fail (type != NULL, FALSE);
@@ -177,7 +178,7 @@ g_content_type_is_unknown (const gchar *type)
}
gchar *
-g_content_type_get_description (const gchar *type)
+g_content_type_get_description_impl (const gchar *type)
{
char *progid;
char *description;
@@ -201,7 +202,7 @@ g_content_type_get_description (const gchar *type)
}
gchar *
-g_content_type_get_mime_type (const gchar *type)
+g_content_type_get_mime_type_impl (const gchar *type)
{
char *mime;
@@ -224,17 +225,8 @@ g_content_type_get_mime_type (const gchar *type)
G_LOCK_DEFINE_STATIC (_type_icons);
static GHashTable *_type_icons = NULL;
-/**
- * g_content_type_get_icon:
- * @type: a content type string
- *
- * Gets the icon for a content type.
- *
- * Returns: (transfer full): #GIcon corresponding to the content type. Free the returned
- * object with g_object_unref()
- */
GIcon *
-g_content_type_get_icon (const gchar *type)
+g_content_type_get_icon_impl (const gchar *type)
{
GIcon *themed_icon;
char *name = NULL;
@@ -292,19 +284,19 @@ g_content_type_get_icon (const gchar *type)
}
GIcon *
-g_content_type_get_symbolic_icon (const gchar *type)
+g_content_type_get_symbolic_icon_impl (const gchar *type)
{
return g_content_type_get_icon (type);
}
gchar *
-g_content_type_get_generic_icon_name (const gchar *type)
+g_content_type_get_generic_icon_name_impl (const gchar *type)
{
return NULL;
}
gboolean
-g_content_type_can_be_executable (const gchar *type)
+g_content_type_can_be_executable_impl (const gchar *type)
{
g_return_val_if_fail (type != NULL, FALSE);
@@ -343,7 +335,7 @@ looks_like_text (const guchar *data,
}
gchar *
-g_content_type_from_mime_type (const gchar *mime_type)
+g_content_type_from_mime_type_impl (const gchar *mime_type)
{
char *key, *content_type;
@@ -362,10 +354,10 @@ g_content_type_from_mime_type (const gchar *mime_type)
}
gchar *
-g_content_type_guess (const gchar *filename,
- const guchar *data,
- gsize data_size,
- gboolean *result_uncertain)
+g_content_type_guess_impl (const gchar *filename,
+ const guchar *data,
+ gsize data_size,
+ gboolean *result_uncertain)
{
char *basename;
char *type;
@@ -410,7 +402,7 @@ g_content_type_guess (const gchar *filename,
}
GList *
-g_content_types_get_registered (void)
+g_content_types_get_registered_impl (void)
{
DWORD index;
wchar_t keyname[256];
@@ -446,7 +438,7 @@ g_content_types_get_registered (void)
}
gchar **
-g_content_type_guess_for_tree (GFile *root)
+g_content_type_guess_for_tree_impl (GFile *root)
{
/* FIXME: implement */
return NULL;
diff --git a/gio/gcontenttype.c b/gio/gcontenttype.c
index de9e5a739..aa8f4040a 100644
--- a/gio/gcontenttype.c
+++ b/gio/gcontenttype.c
@@ -23,18 +23,8 @@
*/
#include "config.h"
-#include
-#include
-#include
-#include
#include "gcontenttypeprivate.h"
-#include "gthemedicon.h"
-#include "gicon.h"
#include "gfile.h"
-#include "gfileenumerator.h"
-#include "gfileinfo.h"
-#include "glibintl.h"
-#include "glib-private.h"
/**
@@ -51,109 +41,6 @@
* such as `com.apple.application`.
**/
-#include
-
-#define XDG_PREFIX _gio_xdg
-#include "xdgmime/xdgmime.h"
-
-static void tree_magic_schedule_reload (void);
-
-/* We lock this mutex whenever we modify global state in this module.
- * Taking and releasing this lock should always be associated with a pair of
- * g_begin_ignore_leaks()/g_end_ignore_leaks() calls, as any call into xdgmime
- * could trigger xdg_mime_init(), which makes a number of one-time allocations
- * which GLib can never free as it doesn’t know when is suitable to call
- * xdg_mime_shutdown(). */
-G_LOCK_DEFINE_STATIC (gio_xdgmime);
-
-gsize
-_g_unix_content_type_get_sniff_len (void)
-{
- gsize size;
-
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- size = xdg_mime_get_max_buffer_extents ();
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- return size;
-}
-
-gchar *
-_g_unix_content_type_unalias (const gchar *type)
-{
- gchar *res;
-
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- res = g_strdup (xdg_mime_unalias_mime_type (type));
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- return res;
-}
-
-gchar **
-_g_unix_content_type_get_parents (const gchar *type)
-{
- const gchar *umime;
- gchar **parents;
- GPtrArray *array;
- int i;
-
- array = g_ptr_array_new ();
-
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
-
- umime = xdg_mime_unalias_mime_type (type);
-
- g_ptr_array_add (array, g_strdup (umime));
-
- parents = xdg_mime_list_mime_parents (umime);
- for (i = 0; parents && parents[i] != NULL; i++)
- g_ptr_array_add (array, g_strdup (parents[i]));
-
- free (parents);
-
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- g_ptr_array_add (array, NULL);
-
- return (gchar **)g_ptr_array_free (array, FALSE);
-}
-
-G_LOCK_DEFINE_STATIC (global_mime_dirs);
-static gchar **global_mime_dirs = NULL;
-
-static void
-_g_content_type_set_mime_dirs_locked (const char * const *dirs)
-{
- g_clear_pointer (&global_mime_dirs, g_strfreev);
-
- if (dirs != NULL)
- {
- global_mime_dirs = g_strdupv ((gchar **) dirs);
- }
- else
- {
- GPtrArray *mime_dirs = g_ptr_array_new_with_free_func (g_free);
- const gchar * const *system_dirs = g_get_system_data_dirs ();
-
- g_ptr_array_add (mime_dirs, g_build_filename (g_get_user_data_dir (), "mime", NULL));
- for (; *system_dirs != NULL; system_dirs++)
- g_ptr_array_add (mime_dirs, g_build_filename (*system_dirs, "mime", NULL));
- g_ptr_array_add (mime_dirs, NULL); /* NULL terminator */
-
- global_mime_dirs = (gchar **) g_ptr_array_free (mime_dirs, FALSE);
- }
-
- xdg_mime_set_dirs ((const gchar * const *) global_mime_dirs);
- tree_magic_schedule_reload ();
-}
-
/**
* g_content_type_set_mime_dirs:
* @dirs: (array zero-terminated=1) (nullable): %NULL-terminated list of
@@ -186,13 +73,10 @@ _g_content_type_set_mime_dirs_locked (const char * const *dirs)
*
* Since: 2.60
*/
-/*< private >*/
void
g_content_type_set_mime_dirs (const gchar * const *dirs)
{
- G_LOCK (global_mime_dirs);
- _g_content_type_set_mime_dirs_locked (dirs);
- G_UNLOCK (global_mime_dirs);
+ g_content_type_set_mime_dirs_impl (dirs);
}
/**
@@ -206,23 +90,10 @@ g_content_type_set_mime_dirs (const gchar * const *dirs)
* and with the first directory to try listed first
* Since: 2.60
*/
-/*< private >*/
const gchar * const *
g_content_type_get_mime_dirs (void)
{
- const gchar * const *mime_dirs;
-
- G_LOCK (global_mime_dirs);
-
- if (global_mime_dirs == NULL)
- _g_content_type_set_mime_dirs_locked (NULL);
-
- mime_dirs = (const gchar * const *) global_mime_dirs;
-
- G_UNLOCK (global_mime_dirs);
-
- g_assert (mime_dirs != NULL);
- return mime_dirs;
+ return g_content_type_get_mime_dirs_impl ();
}
/**
@@ -239,18 +110,10 @@ gboolean
g_content_type_equals (const gchar *type1,
const gchar *type2)
{
- gboolean res;
-
g_return_val_if_fail (type1 != NULL, FALSE);
g_return_val_if_fail (type2 != NULL, FALSE);
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- res = xdg_mime_mime_type_equal (type1, type2);
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- return res;
+ return g_content_type_equals_impl (type1, type2);
}
/**
@@ -267,18 +130,10 @@ gboolean
g_content_type_is_a (const gchar *type,
const gchar *supertype)
{
- gboolean res;
-
g_return_val_if_fail (type != NULL, FALSE);
g_return_val_if_fail (supertype != NULL, FALSE);
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- res = xdg_mime_mime_type_subclass (type, supertype);
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- return res;
+ return g_content_type_is_a_impl (type, supertype);
}
/**
@@ -298,7 +153,10 @@ gboolean
g_content_type_is_mime_type (const gchar *type,
const gchar *mime_type)
{
- return g_content_type_is_a (type, mime_type);
+ g_return_val_if_fail (type != NULL, FALSE);
+ g_return_val_if_fail (mime_type != NULL, FALSE);
+
+ return g_content_type_is_mime_type_impl (type, mime_type);
}
/**
@@ -317,157 +175,7 @@ g_content_type_is_unknown (const gchar *type)
{
g_return_val_if_fail (type != NULL, FALSE);
- return strcmp (XDG_MIME_TYPE_UNKNOWN, type) == 0;
-}
-
-
-typedef enum {
- MIME_TAG_TYPE_OTHER,
- MIME_TAG_TYPE_COMMENT
-} MimeTagType;
-
-typedef struct {
- int current_type;
- int current_lang_level;
- int comment_lang_level;
- char *comment;
-} MimeParser;
-
-
-static int
-language_level (const char *lang)
-{
- const char * const *lang_list;
- int i;
-
- /* The returned list is sorted from most desirable to least
- desirable and always contains the default locale "C". */
- lang_list = g_get_language_names ();
-
- for (i = 0; lang_list[i]; i++)
- if (strcmp (lang_list[i], lang) == 0)
- return 1000-i;
-
- return 0;
-}
-
-static void
-mime_info_start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data,
- GError **error)
-{
- int i;
- const char *lang;
- MimeParser *parser = user_data;
-
- if (strcmp (element_name, "comment") == 0)
- {
- lang = "C";
- for (i = 0; attribute_names[i]; i++)
- if (strcmp (attribute_names[i], "xml:lang") == 0)
- {
- lang = attribute_values[i];
- break;
- }
-
- parser->current_lang_level = language_level (lang);
- parser->current_type = MIME_TAG_TYPE_COMMENT;
- }
- else
- parser->current_type = MIME_TAG_TYPE_OTHER;
-}
-
-static void
-mime_info_end_element (GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data,
- GError **error)
-{
- MimeParser *parser = user_data;
-
- parser->current_type = MIME_TAG_TYPE_OTHER;
-}
-
-static void
-mime_info_text (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error)
-{
- MimeParser *parser = user_data;
-
- if (parser->current_type == MIME_TAG_TYPE_COMMENT &&
- parser->current_lang_level > parser->comment_lang_level)
- {
- g_free (parser->comment);
- parser->comment = g_strndup (text, text_len);
- parser->comment_lang_level = parser->current_lang_level;
- }
-}
-
-static char *
-load_comment_for_mime_helper (const char *dir,
- const char *basename)
-{
- GMarkupParseContext *context;
- char *filename, *data;
- gsize len;
- gboolean res;
- MimeParser parse_data = {0};
- GMarkupParser parser = {
- mime_info_start_element,
- mime_info_end_element,
- mime_info_text,
- NULL,
- NULL
- };
-
- filename = g_build_filename (dir, basename, NULL);
-
- res = g_file_get_contents (filename, &data, &len, NULL);
- g_free (filename);
- if (!res)
- return NULL;
-
- context = g_markup_parse_context_new (&parser, G_MARKUP_DEFAULT_FLAGS, &parse_data, NULL);
- res = g_markup_parse_context_parse (context, data, len, NULL);
- g_free (data);
- g_markup_parse_context_free (context);
-
- if (!res)
- return NULL;
-
- return parse_data.comment;
-}
-
-
-static char *
-load_comment_for_mime (const char *mimetype)
-{
- const char * const *dirs;
- char *basename;
- char *comment;
- gsize i;
-
- basename = g_strdup_printf ("%s.xml", mimetype);
-
- dirs = g_content_type_get_mime_dirs ();
- for (i = 0; dirs[i] != NULL; i++)
- {
- comment = load_comment_for_mime_helper (dirs[i], basename);
- if (comment)
- {
- g_free (basename);
- return comment;
- }
- }
- g_free (basename);
-
- return g_strdup_printf (_("%s type"), mimetype);
+ return g_content_type_is_unknown_impl (type);
}
/**
@@ -482,41 +190,9 @@ load_comment_for_mime (const char *mimetype)
gchar *
g_content_type_get_description (const gchar *type)
{
- static GHashTable *type_comment_cache = NULL;
- gchar *type_copy = NULL;
- gchar *comment;
-
g_return_val_if_fail (type != NULL, NULL);
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- type = xdg_mime_unalias_mime_type (type);
- g_end_ignore_leaks ();
-
- if (type_comment_cache == NULL)
- type_comment_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- comment = g_hash_table_lookup (type_comment_cache, type);
- comment = g_strdup (comment);
-
- if (comment != NULL)
- {
- G_UNLOCK (gio_xdgmime);
- return g_steal_pointer (&comment);
- }
-
- type_copy = g_strdup (type);
-
- G_UNLOCK (gio_xdgmime);
- comment = load_comment_for_mime (type_copy);
- G_LOCK (gio_xdgmime);
-
- g_hash_table_insert (type_comment_cache,
- g_steal_pointer (&type_copy),
- g_strdup (comment));
- G_UNLOCK (gio_xdgmime);
-
- return g_steal_pointer (&comment);
+ return g_content_type_get_description_impl (type);
}
/**
@@ -533,60 +209,7 @@ g_content_type_get_mime_type (const char *type)
{
g_return_val_if_fail (type != NULL, NULL);
- return g_strdup (type);
-}
-
-static GIcon *
-g_content_type_get_icon_internal (const gchar *type,
- gboolean symbolic)
-{
- char *mimetype_icon;
- char *generic_mimetype_icon = NULL;
- char *q;
- char *icon_names[6];
- int n = 0;
- GIcon *themed_icon;
- const char *xdg_icon;
- int i;
-
- g_return_val_if_fail (type != NULL, NULL);
-
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- xdg_icon = xdg_mime_get_icon (type);
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- if (xdg_icon)
- icon_names[n++] = g_strdup (xdg_icon);
-
- mimetype_icon = g_strdup (type);
- while ((q = strchr (mimetype_icon, '/')) != NULL)
- *q = '-';
-
- icon_names[n++] = mimetype_icon;
-
- generic_mimetype_icon = g_content_type_get_generic_icon_name (type);
- if (generic_mimetype_icon)
- icon_names[n++] = generic_mimetype_icon;
-
- if (symbolic)
- {
- for (i = 0; i < n; i++)
- {
- icon_names[n + i] = icon_names[i];
- icon_names[i] = g_strconcat (icon_names[i], "-symbolic", NULL);
- }
-
- n += n;
- }
-
- themed_icon = g_themed_icon_new_from_names (icon_names, n);
-
- for (i = 0; i < n; i++)
- g_free (icon_names[i]);
-
- return themed_icon;
+ return g_content_type_get_mime_type_impl (type);
}
/**
@@ -601,7 +224,9 @@ g_content_type_get_icon_internal (const gchar *type,
GIcon *
g_content_type_get_icon (const gchar *type)
{
- return g_content_type_get_icon_internal (type, FALSE);
+ g_return_val_if_fail (type != NULL, NULL);
+
+ return g_content_type_get_icon_impl (type);
}
/**
@@ -618,7 +243,9 @@ g_content_type_get_icon (const gchar *type)
GIcon *
g_content_type_get_symbolic_icon (const gchar *type)
{
- return g_content_type_get_icon_internal (type, TRUE);
+ g_return_val_if_fail (type != NULL, NULL);
+
+ return g_content_type_get_symbolic_icon_impl (type);
}
/**
@@ -639,37 +266,9 @@ g_content_type_get_symbolic_icon (const gchar *type)
gchar *
g_content_type_get_generic_icon_name (const gchar *type)
{
- const gchar *xdg_icon_name;
- gchar *icon_name;
-
g_return_val_if_fail (type != NULL, NULL);
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- xdg_icon_name = xdg_mime_get_generic_icon (type);
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- if (!xdg_icon_name)
- {
- const char *p;
- const char *suffix = "-x-generic";
-
- p = strchr (type, '/');
- if (p == NULL)
- p = type + strlen (type);
-
- icon_name = g_malloc (p - type + strlen (suffix) + 1);
- memcpy (icon_name, type, p - type);
- memcpy (icon_name + (p - type), suffix, strlen (suffix));
- icon_name[(p - type) + strlen (suffix)] = 0;
- }
- else
- {
- icon_name = g_strdup (xdg_icon_name);
- }
-
- return icon_name;
+ return g_content_type_get_generic_icon_name_impl (type);
}
/**
@@ -687,29 +286,7 @@ g_content_type_can_be_executable (const gchar *type)
{
g_return_val_if_fail (type != NULL, FALSE);
- if (g_content_type_is_a (type, "application/x-executable") ||
- g_content_type_is_a (type, "text/plain"))
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-looks_like_text (const guchar *data, gsize data_size)
-{
- gsize i;
- char c;
-
- for (i = 0; i < data_size; i++)
- {
- c = data[i];
-
- if (g_ascii_iscntrl (c) &&
- !g_ascii_isspace (c) &&
- c != '\b')
- return FALSE;
- }
- return TRUE;
+ return g_content_type_can_be_executable_impl (type);
}
/**
@@ -726,18 +303,9 @@ looks_like_text (const guchar *data, gsize data_size)
gchar *
g_content_type_from_mime_type (const gchar *mime_type)
{
- char *umime;
-
g_return_val_if_fail (mime_type != NULL, NULL);
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
- /* mime type and content type are same on unixes */
- umime = g_strdup (xdg_mime_unalias_mime_type (mime_type));
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- return umime;
+ return g_content_type_from_mime_type_impl (mime_type);
}
/**
@@ -762,175 +330,7 @@ g_content_type_guess (const gchar *filename,
gsize data_size,
gboolean *result_uncertain)
{
- char *basename;
- const char *name_mimetypes[10], *sniffed_mimetype;
- char *mimetype;
- int i;
- int n_name_mimetypes;
- int sniffed_prio;
-
- sniffed_prio = 0;
- n_name_mimetypes = 0;
- sniffed_mimetype = XDG_MIME_TYPE_UNKNOWN;
-
- if (result_uncertain)
- *result_uncertain = FALSE;
-
- /* our test suite and potentially other code used -1 in the past, which is
- * not documented and not allowed; guard against that */
- g_return_val_if_fail (data_size != (gsize) -1, g_strdup (XDG_MIME_TYPE_UNKNOWN));
-
- G_LOCK (gio_xdgmime);
- g_begin_ignore_leaks ();
-
- if (filename)
- {
- i = strlen (filename);
- if (i > 0 && filename[i - 1] == '/')
- {
- name_mimetypes[0] = "inode/directory";
- name_mimetypes[1] = NULL;
- n_name_mimetypes = 1;
- if (result_uncertain)
- *result_uncertain = TRUE;
- }
- else
- {
- basename = g_path_get_basename (filename);
- n_name_mimetypes = xdg_mime_get_mime_types_from_file_name (basename, name_mimetypes, 10);
- g_free (basename);
- }
- }
-
- /* Got an extension match, and no conflicts. This is it. */
- if (n_name_mimetypes == 1)
- {
- gchar *s = g_strdup (name_mimetypes[0]);
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
- return s;
- }
-
- if (data)
- {
- sniffed_mimetype = xdg_mime_get_mime_type_for_data (data, data_size, &sniffed_prio);
- if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
- data &&
- looks_like_text (data, data_size))
- sniffed_mimetype = "text/plain";
-
- /* For security reasons we don't ever want to sniff desktop files
- * where we know the filename and it doesn't have a .desktop extension.
- * This is because desktop files allow executing any application and
- * we don't want to make it possible to hide them looking like something
- * else.
- */
- if (filename != NULL &&
- strcmp (sniffed_mimetype, "application/x-desktop") == 0)
- sniffed_mimetype = "text/plain";
- }
-
- if (n_name_mimetypes == 0)
- {
- if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
- result_uncertain)
- *result_uncertain = TRUE;
-
- mimetype = g_strdup (sniffed_mimetype);
- }
- else
- {
- mimetype = NULL;
- if (sniffed_mimetype != XDG_MIME_TYPE_UNKNOWN)
- {
- if (sniffed_prio >= 80) /* High priority sniffing match, use that */
- mimetype = g_strdup (sniffed_mimetype);
- else
- {
- /* There are conflicts between the name matches and we
- * have a sniffed type, use that as a tie breaker.
- */
- for (i = 0; i < n_name_mimetypes; i++)
- {
- if ( xdg_mime_mime_type_subclass (name_mimetypes[i], sniffed_mimetype))
- {
- /* This nametype match is derived from (or the same as)
- * the sniffed type). This is probably it.
- */
- mimetype = g_strdup (name_mimetypes[i]);
- break;
- }
- }
- }
- }
-
- if (mimetype == NULL)
- {
- /* Conflicts, and sniffed type was no help or not there.
- * Guess on the first one
- */
- mimetype = g_strdup (name_mimetypes[0]);
- if (result_uncertain)
- *result_uncertain = TRUE;
- }
- }
-
- g_end_ignore_leaks ();
- G_UNLOCK (gio_xdgmime);
-
- return mimetype;
-}
-
-static void
-enumerate_mimetypes_subdir (const char *dir,
- const char *prefix,
- GHashTable *mimetypes)
-{
- DIR *d;
- struct dirent *ent;
- char *mimetype;
-
- d = opendir (dir);
- if (d)
- {
- while ((ent = readdir (d)) != NULL)
- {
- if (g_str_has_suffix (ent->d_name, ".xml"))
- {
- mimetype = g_strdup_printf ("%s/%.*s", prefix, (int) strlen (ent->d_name) - 4, ent->d_name);
- g_hash_table_replace (mimetypes, mimetype, NULL);
- }
- }
- closedir (d);
- }
-}
-
-static void
-enumerate_mimetypes_dir (const char *dir,
- GHashTable *mimetypes)
-{
- DIR *d;
- struct dirent *ent;
- const char *mimedir;
- char *name;
-
- mimedir = dir;
-
- d = opendir (mimedir);
- if (d)
- {
- while ((ent = readdir (d)) != NULL)
- {
- if (strcmp (ent->d_name, "packages") != 0)
- {
- name = g_build_filename (mimedir, ent->d_name, NULL);
- if (g_file_test (name, G_FILE_TEST_IS_DIR))
- enumerate_mimetypes_subdir (name, ent->d_name, mimetypes);
- g_free (name);
- }
- }
- closedir (d);
- }
+ return g_content_type_guess_impl (filename, data, data_size, result_uncertain);
}
/**
@@ -946,591 +346,7 @@ enumerate_mimetypes_dir (const char *dir,
GList *
g_content_types_get_registered (void)
{
- const char * const *dirs;
- GHashTable *mimetypes;
- GHashTableIter iter;
- gpointer key;
- gsize i;
- GList *l;
-
- mimetypes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
- dirs = g_content_type_get_mime_dirs ();
- for (i = 0; dirs[i] != NULL; i++)
- enumerate_mimetypes_dir (dirs[i], mimetypes);
-
- l = NULL;
- g_hash_table_iter_init (&iter, mimetypes);
- while (g_hash_table_iter_next (&iter, &key, NULL))
- {
- l = g_list_prepend (l, key);
- g_hash_table_iter_steal (&iter);
- }
-
- g_hash_table_destroy (mimetypes);
-
- return l;
-}
-
-
-/* tree magic data */
-static GList *tree_matches = NULL;
-static gboolean need_reload = FALSE;
-
-G_LOCK_DEFINE_STATIC (gio_treemagic);
-
-typedef struct
-{
- gchar *path;
- GFileType type;
- guint match_case : 1;
- guint executable : 1;
- guint non_empty : 1;
- guint on_disc : 1;
- gchar *mimetype;
- GList *matches;
-} TreeMatchlet;
-
-typedef struct
-{
- gchar *contenttype;
- gint priority;
- GList *matches;
-} TreeMatch;
-
-
-static void
-tree_matchlet_free (TreeMatchlet *matchlet)
-{
- g_list_free_full (matchlet->matches, (GDestroyNotify) tree_matchlet_free);
- g_free (matchlet->path);
- g_free (matchlet->mimetype);
- g_slice_free (TreeMatchlet, matchlet);
-}
-
-static void
-tree_match_free (TreeMatch *match)
-{
- g_list_free_full (match->matches, (GDestroyNotify) tree_matchlet_free);
- g_free (match->contenttype);
- g_slice_free (TreeMatch, match);
-}
-
-static TreeMatch *
-parse_header (gchar *line)
-{
- gint len;
- gchar *s;
- TreeMatch *match;
-
- len = strlen (line);
-
- if (line[0] != '[' || line[len - 1] != ']')
- return NULL;
-
- line[len - 1] = 0;
- s = strchr (line, ':');
- if (s == NULL)
- return NULL;
-
- match = g_slice_new0 (TreeMatch);
- match->priority = atoi (line + 1);
- match->contenttype = g_strdup (s + 1);
-
- return match;
-}
-
-static TreeMatchlet *
-parse_match_line (gchar *line,
- gint *depth)
-{
- gchar *s, *p;
- TreeMatchlet *matchlet;
- gchar **parts;
- gint i;
-
- matchlet = g_slice_new0 (TreeMatchlet);
-
- if (line[0] == '>')
- {
- *depth = 0;
- s = line;
- }
- else
- {
- *depth = atoi (line);
- s = strchr (line, '>');
- if (s == NULL)
- goto handle_error;
- }
- s += 2;
- p = strchr (s, '"');
- if (p == NULL)
- goto handle_error;
- *p = 0;
-
- matchlet->path = g_strdup (s);
- s = p + 1;
- parts = g_strsplit (s, ",", 0);
- if (strcmp (parts[0], "=file") == 0)
- matchlet->type = G_FILE_TYPE_REGULAR;
- else if (strcmp (parts[0], "=directory") == 0)
- matchlet->type = G_FILE_TYPE_DIRECTORY;
- else if (strcmp (parts[0], "=link") == 0)
- matchlet->type = G_FILE_TYPE_SYMBOLIC_LINK;
- else
- matchlet->type = G_FILE_TYPE_UNKNOWN;
- for (i = 1; parts[i]; i++)
- {
- if (strcmp (parts[i], "executable") == 0)
- matchlet->executable = 1;
- else if (strcmp (parts[i], "match-case") == 0)
- matchlet->match_case = 1;
- else if (strcmp (parts[i], "non-empty") == 0)
- matchlet->non_empty = 1;
- else if (strcmp (parts[i], "on-disc") == 0)
- matchlet->on_disc = 1;
- else
- matchlet->mimetype = g_strdup (parts[i]);
- }
-
- g_strfreev (parts);
-
- return matchlet;
-
-handle_error:
- g_slice_free (TreeMatchlet, matchlet);
- return NULL;
-}
-
-static gint
-cmp_match (gconstpointer a, gconstpointer b)
-{
- const TreeMatch *aa = (const TreeMatch *)a;
- const TreeMatch *bb = (const TreeMatch *)b;
-
- return bb->priority - aa->priority;
-}
-
-static void
-insert_match (TreeMatch *match)
-{
- tree_matches = g_list_insert_sorted (tree_matches, match, cmp_match);
-}
-
-static void
-insert_matchlet (TreeMatch *match,
- TreeMatchlet *matchlet,
- gint depth)
-{
- if (depth == 0)
- match->matches = g_list_append (match->matches, matchlet);
- else
- {
- GList *last;
- TreeMatchlet *m;
-
- last = g_list_last (match->matches);
- if (!last)
- {
- tree_matchlet_free (matchlet);
- g_warning ("can't insert tree matchlet at depth %d", depth);
- return;
- }
-
- m = (TreeMatchlet *) last->data;
- while (--depth > 0)
- {
- last = g_list_last (m->matches);
- if (!last)
- {
- tree_matchlet_free (matchlet);
- g_warning ("can't insert tree matchlet at depth %d", depth);
- return;
- }
-
- m = (TreeMatchlet *) last->data;
- }
- m->matches = g_list_append (m->matches, matchlet);
- }
-}
-
-static void
-read_tree_magic_from_directory (const gchar *prefix)
-{
- gchar *filename;
- gchar *text;
- gsize len;
- gchar **lines;
- gsize i;
- TreeMatch *match;
- TreeMatchlet *matchlet;
- gint depth;
-
- filename = g_build_filename (prefix, "treemagic", NULL);
-
- if (g_file_get_contents (filename, &text, &len, NULL))
- {
- if (strcmp (text, "MIME-TreeMagic") == 0)
- {
- lines = g_strsplit (text + strlen ("MIME-TreeMagic") + 2, "\n", 0);
- match = NULL;
- for (i = 0; lines[i] && lines[i][0]; i++)
- {
- if (lines[i][0] == '[' && (match = parse_header (lines[i])) != NULL)
- {
- insert_match (match);
- }
- else if (match != NULL)
- {
- matchlet = parse_match_line (lines[i], &depth);
- if (matchlet == NULL)
- {
- g_warning ("%s: body corrupt; skipping", filename);
- break;
- }
- insert_matchlet (match, matchlet, depth);
- }
- else
- {
- g_warning ("%s: header corrupt; skipping", filename);
- break;
- }
- }
-
- g_strfreev (lines);
- }
- else
- g_warning ("%s: header not found, skipping", filename);
-
- g_free (text);
- }
-
- g_free (filename);
-}
-
-static void
-tree_magic_schedule_reload (void)
-{
- need_reload = TRUE;
-}
-
-static void
-xdg_mime_reload (void *user_data)
-{
- tree_magic_schedule_reload ();
-}
-
-static void
-tree_magic_shutdown (void)
-{
- g_list_free_full (tree_matches, (GDestroyNotify) tree_match_free);
- tree_matches = NULL;
-}
-
-static void
-tree_magic_init (void)
-{
- static gboolean initialized = FALSE;
- gsize i;
-
- if (!initialized)
- {
- initialized = TRUE;
-
- xdg_mime_register_reload_callback (xdg_mime_reload, NULL, NULL);
- need_reload = TRUE;
- }
-
- if (need_reload)
- {
- const char * const *dirs;
-
- need_reload = FALSE;
-
- tree_magic_shutdown ();
-
- dirs = g_content_type_get_mime_dirs ();
- for (i = 0; dirs[i] != NULL; i++)
- read_tree_magic_from_directory (dirs[i]);
- }
-}
-
-/* a filtering enumerator */
-
-typedef struct
-{
- gchar *path;
- gint depth;
- gboolean ignore_case;
- gchar **components;
- gchar **case_components;
- GFileEnumerator **enumerators;
- GFile **children;
-} Enumerator;
-
-static gboolean
-component_match (Enumerator *e,
- gint depth,
- const gchar *name)
-{
- gchar *case_folded, *key, *utf8_name;
- gboolean found;
-
- if (strcmp (name, e->components[depth]) == 0)
- return TRUE;
-
- if (!e->ignore_case)
- return FALSE;
-
- utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
- if (utf8_name == NULL)
- utf8_name = g_utf8_make_valid (name, -1);
-
- case_folded = g_utf8_casefold (utf8_name, -1);
- key = g_utf8_collate_key (case_folded, -1);
-
- found = strcmp (key, e->case_components[depth]) == 0;
-
- g_free (utf8_name);
- g_free (case_folded);
- g_free (key);
-
- return found;
-}
-
-static GFile *
-next_match_recurse (Enumerator *e,
- gint depth)
-{
- GFile *file;
- GFileInfo *info;
- const gchar *name;
-
- while (TRUE)
- {
- if (e->enumerators[depth] == NULL)
- {
- if (depth > 0)
- {
- file = next_match_recurse (e, depth - 1);
- if (file)
- {
- e->children[depth] = file;
- e->enumerators[depth] = g_file_enumerate_children (file,
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NONE,
- NULL,
- NULL);
- }
- }
- if (e->enumerators[depth] == NULL)
- return NULL;
- }
-
- while ((info = g_file_enumerator_next_file (e->enumerators[depth], NULL, NULL)))
- {
- name = g_file_info_get_name (info);
- if (component_match (e, depth, name))
- {
- file = g_file_get_child (e->children[depth], name);
- g_object_unref (info);
- return file;
- }
- g_object_unref (info);
- }
-
- g_object_unref (e->enumerators[depth]);
- e->enumerators[depth] = NULL;
- g_object_unref (e->children[depth]);
- e->children[depth] = NULL;
- }
-}
-
-static GFile *
-enumerator_next (Enumerator *e)
-{
- return next_match_recurse (e, e->depth - 1);
-}
-
-static Enumerator *
-enumerator_new (GFile *root,
- const char *path,
- gboolean ignore_case)
-{
- Enumerator *e;
- gint i;
- gchar *case_folded;
-
- e = g_new0 (Enumerator, 1);
- e->path = g_strdup (path);
- e->ignore_case = ignore_case;
-
- e->components = g_strsplit (e->path, G_DIR_SEPARATOR_S, -1);
- e->depth = g_strv_length (e->components);
- if (e->ignore_case)
- {
- e->case_components = g_new0 (char *, e->depth + 1);
- for (i = 0; e->components[i]; i++)
- {
- case_folded = g_utf8_casefold (e->components[i], -1);
- e->case_components[i] = g_utf8_collate_key (case_folded, -1);
- g_free (case_folded);
- }
- }
-
- e->children = g_new0 (GFile *, e->depth);
- e->children[0] = g_object_ref (root);
- e->enumerators = g_new0 (GFileEnumerator *, e->depth);
- e->enumerators[0] = g_file_enumerate_children (root,
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NONE,
- NULL,
- NULL);
-
- return e;
-}
-
-static void
-enumerator_free (Enumerator *e)
-{
- gint i;
-
- for (i = 0; i < e->depth; i++)
- {
- if (e->enumerators[i])
- g_object_unref (e->enumerators[i]);
- if (e->children[i])
- g_object_unref (e->children[i]);
- }
-
- g_free (e->enumerators);
- g_free (e->children);
- g_strfreev (e->components);
- if (e->case_components)
- g_strfreev (e->case_components);
- g_free (e->path);
- g_free (e);
-}
-
-static gboolean
-matchlet_match (TreeMatchlet *matchlet,
- GFile *root)
-{
- GFile *file;
- GFileInfo *info;
- gboolean result;
- const gchar *attrs;
- Enumerator *e;
- GList *l;
-
- e = enumerator_new (root, matchlet->path, !matchlet->match_case);
-
- do
- {
- file = enumerator_next (e);
- if (!file)
- {
- enumerator_free (e);
- return FALSE;
- }
-
- if (matchlet->mimetype)
- attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
- G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE ","
- G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
- else
- attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
- G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE;
- info = g_file_query_info (file,
- attrs,
- G_FILE_QUERY_INFO_NONE,
- NULL,
- NULL);
- if (info)
- {
- result = TRUE;
-
- if (matchlet->type != G_FILE_TYPE_UNKNOWN &&
- g_file_info_get_file_type (info) != matchlet->type)
- result = FALSE;
-
- if (matchlet->executable &&
- !g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
- result = FALSE;
- }
- else
- result = FALSE;
-
- if (result && matchlet->non_empty)
- {
- GFileEnumerator *child_enum;
- GFileInfo *child_info;
-
- child_enum = g_file_enumerate_children (file,
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NONE,
- NULL,
- NULL);
-
- if (child_enum)
- {
- child_info = g_file_enumerator_next_file (child_enum, NULL, NULL);
- if (child_info)
- g_object_unref (child_info);
- else
- result = FALSE;
- g_object_unref (child_enum);
- }
- else
- result = FALSE;
- }
-
- if (result && matchlet->mimetype)
- {
- if (strcmp (matchlet->mimetype, g_file_info_get_content_type (info)) != 0)
- result = FALSE;
- }
-
- if (info)
- g_object_unref (info);
- g_object_unref (file);
- }
- while (!result);
-
- enumerator_free (e);
-
- if (!matchlet->matches)
- return TRUE;
-
- for (l = matchlet->matches; l; l = l->next)
- {
- TreeMatchlet *submatchlet;
-
- submatchlet = l->data;
- if (matchlet_match (submatchlet, root))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-match_match (TreeMatch *match,
- GFile *root,
- GPtrArray *types)
-{
- GList *l;
-
- for (l = match->matches; l; l = l->next)
- {
- TreeMatchlet *matchlet = l->data;
- if (matchlet_match (matchlet, root))
- {
- g_ptr_array_add (types, g_strdup (match->contenttype));
- break;
- }
- }
+ return g_content_types_get_registered_impl ();
}
/**
@@ -1558,23 +374,7 @@ match_match (TreeMatch *match,
gchar **
g_content_type_guess_for_tree (GFile *root)
{
- GPtrArray *types;
- GList *l;
+ g_return_val_if_fail (G_IS_FILE (root), NULL);
- types = g_ptr_array_new ();
-
- G_LOCK (gio_treemagic);
-
- tree_magic_init ();
- for (l = tree_matches; l; l = l->next)
- {
- TreeMatch *match = l->data;
- match_match (match, root, types);
- }
-
- G_UNLOCK (gio_treemagic);
-
- g_ptr_array_add (types, NULL);
-
- return (gchar **)g_ptr_array_free (types, FALSE);
+ return g_content_type_guess_for_tree_impl (root);
}
diff --git a/gio/gcontenttypeprivate.h b/gio/gcontenttypeprivate.h
index d3d671b91..a642b63b8 100644
--- a/gio/gcontenttypeprivate.h
+++ b/gio/gcontenttypeprivate.h
@@ -31,6 +31,29 @@ gsize _g_unix_content_type_get_sniff_len (void);
char * _g_unix_content_type_unalias (const char *type);
char **_g_unix_content_type_get_parents (const char *type);
+void g_content_type_set_mime_dirs_impl (const gchar * const *dirs);
+const gchar * const *g_content_type_get_mime_dirs_impl (void);
+gboolean g_content_type_equals_impl (const gchar *type1,
+ const gchar *type2);
+gboolean g_content_type_is_a_impl (const gchar *type,
+ const gchar *supertype);
+gboolean g_content_type_is_mime_type_impl (const gchar *type,
+ const gchar *mime_type);
+gboolean g_content_type_is_unknown_impl (const gchar *type);
+gchar *g_content_type_get_description_impl (const gchar *type);
+char *g_content_type_get_mime_type_impl (const char *type);
+GIcon *g_content_type_get_icon_impl (const gchar *type);
+GIcon *g_content_type_get_symbolic_icon_impl (const gchar *type);
+gchar *g_content_type_get_generic_icon_name_impl (const gchar *type);
+gboolean g_content_type_can_be_executable_impl (const gchar *type);
+gchar *g_content_type_from_mime_type_impl (const gchar *mime_type);
+gchar *g_content_type_guess_impl (const gchar *filename,
+ const guchar *data,
+ gsize data_size,
+ gboolean *result_uncertain);
+GList *g_content_types_get_registered_impl (void);
+gchar **g_content_type_guess_for_tree_impl (GFile *root);
+
G_END_DECLS
#endif /* __G_CONTENT_TYPE_PRIVATE_H__ */
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 640057a06..343f30949 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -1777,7 +1777,7 @@ g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
/**
* GDesktopAppInfo:filename:
*
- * The origin filename of this #GDesktopAppInfo
+ * The origin filename of this [class@Gio.DesktopAppInfo]
*/
g_object_class_install_property (gobject_class,
PROP_FILENAME,
@@ -2064,11 +2064,11 @@ g_desktop_app_info_load_file (GDesktopAppInfo *self)
/**
* g_desktop_app_info_new_from_keyfile:
- * @key_file: an opened #GKeyFile
+ * @key_file: an opened [type@GLib.KeyFile]
*
- * Creates a new #GDesktopAppInfo.
+ * Creates a new [class@Gio.DesktopAppInfo].
*
- * Returns: (nullable): a new #GDesktopAppInfo or %NULL on error.
+ * Returns: (nullable): a new [class@Gio.DesktopAppInfo] or `NULL` on error.
*
* Since: 2.18
**/
@@ -2095,9 +2095,9 @@ g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
* @filename: (type filename): the path of a desktop file, in the GLib
* filename encoding
*
- * Creates a new #GDesktopAppInfo.
+ * Creates a new [class@Gio.DesktopAppInfo].
*
- * Returns: (nullable): a new #GDesktopAppInfo or %NULL on error.
+ * Returns: (nullable): a new [class@Gio.DesktopAppInfo] or `NULL` on error.
**/
GDesktopAppInfo *
g_desktop_app_info_new_from_filename (const char *filename)
@@ -2115,22 +2115,22 @@ g_desktop_app_info_new_from_filename (const char *filename)
/**
* g_desktop_app_info_new:
- * @desktop_id: the desktop file id
+ * @desktop_id: the desktop file ID
*
- * Creates a new #GDesktopAppInfo based on a desktop file id.
+ * Creates a new [class@Gio.DesktopAppInfo] based on a desktop file ID.
*
- * A desktop file id is the basename of the desktop file, including the
- * .desktop extension. GIO is looking for a desktop file with this name
+ * A desktop file ID is the basename of the desktop file, including the
+ * `.desktop` extension. GIO is looking for a desktop file with this name
* in the `applications` subdirectories of the XDG
* data directories (i.e. the directories specified in the `XDG_DATA_HOME`
* and `XDG_DATA_DIRS` environment variables). GIO also supports the
* prefix-to-subdirectory mapping that is described in the
* [Menu Spec](http://standards.freedesktop.org/menu-spec/latest/)
- * (i.e. a desktop id of kde-foo.desktop will match
+ * (i.e. a desktop ID of `kde-foo.desktop` will match
* `/usr/share/applications/kde/foo.desktop`).
*
- * Returns: (nullable): a new #GDesktopAppInfo, or %NULL if no desktop
- * file with that id exists.
+ * Returns: (nullable): a new [class@Gio.DesktopAppInfo], or `NULL` if no
+ * desktop file with that ID exists.
*/
GDesktopAppInfo *
g_desktop_app_info_new (const char *desktop_id)
@@ -2248,12 +2248,13 @@ g_desktop_app_info_get_display_name (GAppInfo *appinfo)
/**
* g_desktop_app_info_get_is_hidden:
- * @info: a #GDesktopAppInfo.
+ * @info: a [class@Gio.DesktopAppInfo].
*
- * A desktop file is hidden if the Hidden key in it is
- * set to True.
+ * A desktop file is hidden if the
+ * [`Hidden` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-hidden)
+ * in it is set to `True`.
*
- * Returns: %TRUE if hidden, %FALSE otherwise.
+ * Returns: `TRUE` if hidden, `FALSE` otherwise.
**/
gboolean
g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
@@ -2263,14 +2264,14 @@ g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
/**
* g_desktop_app_info_get_filename:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
*
* When @info was created from a known filename, return it. In some
- * situations such as the #GDesktopAppInfo returned from
- * g_desktop_app_info_new_from_keyfile(), this function will return %NULL.
+ * situations such as a [class@Gio.DesktopAppInfo] returned from
+ * [ctor@Gio.DesktopAppInfo.new_from_keyfile], this function will return `NULL`.
*
* Returns: (nullable) (type filename): The full path to the file for @info,
- * or %NULL if not known.
+ * or `NULL` if not known.
* Since: 2.24
*/
const char *
@@ -2313,12 +2314,14 @@ g_desktop_app_info_get_icon (GAppInfo *appinfo)
/**
* g_desktop_app_info_get_categories:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
*
* Gets the categories from the desktop file.
*
- * Returns: (nullable): The unparsed Categories key from the desktop file;
- * i.e. no attempt is made to split it by ';' or validate it.
+ * Returns: (nullable): The unparsed
+ * [`Categories` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-categories)
+ * from the desktop file;
+ * i.e. no attempt is made to split it by `;` or validate it.
*/
const char *
g_desktop_app_info_get_categories (GDesktopAppInfo *info)
@@ -2328,11 +2331,12 @@ g_desktop_app_info_get_categories (GDesktopAppInfo *info)
/**
* g_desktop_app_info_get_keywords:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
*
* Gets the keywords from the desktop file.
*
- * Returns: (transfer none): The value of the Keywords key
+ * Returns: (transfer none): The value of the
+ * [`Keywords` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-keywords)
*
* Since: 2.32
*/
@@ -2344,11 +2348,12 @@ g_desktop_app_info_get_keywords (GDesktopAppInfo *info)
/**
* g_desktop_app_info_get_generic_name:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
*
* Gets the generic name from the desktop file.
*
- * Returns: (nullable): The value of the GenericName key
+ * Returns: (nullable): The value of the
+ * [`GenericName` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-genericname)
*/
const char *
g_desktop_app_info_get_generic_name (GDesktopAppInfo *info)
@@ -2358,13 +2363,14 @@ g_desktop_app_info_get_generic_name (GDesktopAppInfo *info)
/**
* g_desktop_app_info_get_nodisplay:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
*
- * Gets the value of the NoDisplay key, which helps determine if the
- * application info should be shown in menus. See
- * %G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY and g_app_info_should_show().
+ * Gets the value of the
+ * [`NoDisplay` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-nodisplay)
+ * which helps determine if the application info should be shown in menus. See
+ * `G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY` and [method@Gio.AppInfo.should_show].
*
- * Returns: The value of the NoDisplay key
+ * Returns: The value of the `NoDisplay` key
*
* Since: 2.30
*/
@@ -2376,24 +2382,25 @@ g_desktop_app_info_get_nodisplay (GDesktopAppInfo *info)
/**
* g_desktop_app_info_get_show_in:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @desktop_env: (nullable): a string specifying a desktop name
*
* Checks if the application info should be shown in menus that list available
* applications for a specific name of the desktop, based on the
- * `OnlyShowIn` and `NotShowIn` keys.
+ * [`OnlyShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-onlyshowin)
+ * and [`NotShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-notshowin)
+ * keys.
*
- * @desktop_env should typically be given as %NULL, in which case the
+ * @desktop_env should typically be given as `NULL`, in which case the
* `XDG_CURRENT_DESKTOP` environment variable is consulted. If you want
* to override the default mechanism then you may specify @desktop_env,
* but this is not recommended.
*
- * Note that g_app_info_should_show() for @info will include this check (with
- * %NULL for @desktop_env) as well as additional checks.
+ * Note that [method@Gio.AppInfo.should_show] for @info will include this check
+ * (with `NULL` for @desktop_env) as well as additional checks.
*
- * Returns: %TRUE if the @info should be shown in @desktop_env according to the
- * `OnlyShowIn` and `NotShowIn` keys, %FALSE
- * otherwise.
+ * Returns: `TRUE` if the @info should be shown in @desktop_env according to the
+ * `OnlyShowIn` and `NotShowIn` keys, `FALSE` otherwise.
*
* Since: 2.30
*/
@@ -3544,28 +3551,28 @@ g_desktop_app_info_launch (GAppInfo *appinfo,
/**
* g_desktop_app_info_launch_uris_as_manager_with_fds:
- * @appinfo: a #GDesktopAppInfo
+ * @appinfo: a [class@Gio.DesktopAppInfo]
* @uris: (element-type utf8): List of URIs
- * @launch_context: (nullable): a #GAppLaunchContext
- * @spawn_flags: #GSpawnFlags, used for each process
- * @user_setup: (scope async) (nullable) (closure user_setup_data): a #GSpawnChildSetupFunc, used once
- * for each process.
+ * @launch_context: (nullable): a [class@Gio.AppLaunchContext]
+ * @spawn_flags: [flags@GLib.SpawnFlags], used for each process
+ * @user_setup: (scope async) (nullable) (closure user_setup_data): a
+ * [callback@GLib.SpawnChildSetupFunc], used once for each process.
* @user_setup_data: User data for @user_setup
* @pid_callback: (scope call) (nullable) (closure pid_callback_data): Callback for child processes
* @pid_callback_data: User data for @callback
- * @stdin_fd: file descriptor to use for child's stdin, or -1
- * @stdout_fd: file descriptor to use for child's stdout, or -1
- * @stderr_fd: file descriptor to use for child's stderr, or -1
- * @error: return location for a #GError, or %NULL
+ * @stdin_fd: file descriptor to use for child’s stdin, or `-1`
+ * @stdout_fd: file descriptor to use for child’s stdout, or `-1`
+ * @stderr_fd: file descriptor to use for child’s stderr, or `-1`
+ * @error: return location for a #GError, or `NULL`
*
- * Equivalent to g_desktop_app_info_launch_uris_as_manager() but allows
+ * Equivalent to [method@Gio.DesktopAppInfo.launch_uris_as_manager] but allows
* you to pass in file descriptors for the stdin, stdout and stderr streams
* of the launched process.
*
* If application launching occurs via some non-spawn mechanism (e.g. D-Bus
* activation) then @stdin_fd, @stdout_fd and @stderr_fd are ignored.
*
- * Returns: %TRUE on successful launch, %FALSE otherwise.
+ * Returns: `TRUE` on successful launch, `FALSE` otherwise.
*
* Since: 2.58
*/
@@ -3599,34 +3606,35 @@ g_desktop_app_info_launch_uris_as_manager_with_fds (GDesktopAppInfo *
/**
* g_desktop_app_info_launch_uris_as_manager:
- * @appinfo: a #GDesktopAppInfo
+ * @appinfo: a [class@Gio.DesktopAppInfo]
* @uris: (element-type utf8): List of URIs
- * @launch_context: (nullable): a #GAppLaunchContext
- * @spawn_flags: #GSpawnFlags, used for each process
- * @user_setup: (scope async) (nullable): a #GSpawnChildSetupFunc, used once
- * for each process.
+ * @launch_context: (nullable): a [class@Gio.AppLaunchContext]
+ * @spawn_flags: [flags@GLib.SpawnFlags], used for each process
+ * @user_setup: (scope async) (nullable): a [callback@GLib.SpawnChildSetupFunc],
+ * used once for each process.
* @user_setup_data: (closure user_setup) (nullable): User data for @user_setup
* @pid_callback: (scope call) (nullable): Callback for child processes
* @pid_callback_data: (closure pid_callback) (nullable): User data for @callback
- * @error: return location for a #GError, or %NULL
+ * @error: return location for a #GError, or `NULL`
*
- * This function performs the equivalent of g_app_info_launch_uris(),
+ * This function performs the equivalent of [method@Gio.AppInfo.launch_uris],
* but is intended primarily for operating system components that
* launch applications. Ordinary applications should use
- * g_app_info_launch_uris().
+ * [method@Gio.AppInfo.launch_uris].
*
* If the application is launched via GSpawn, then @spawn_flags, @user_setup
- * and @user_setup_data are used for the call to g_spawn_async().
+ * and @user_setup_data are used for the call to [func@GLib.spawn_async].
* Additionally, @pid_callback (with @pid_callback_data) will be called to
- * inform about the PID of the created process. See g_spawn_async_with_pipes()
- * for information on certain parameter conditions that can enable an
- * optimized posix_spawn() codepath to be used.
+ * inform about the PID of the created process. See
+ * [func@GLib.spawn_async_with_pipes] for information on certain parameter
+ * conditions that can enable an optimized [`posix_spawn()`](man:posix_spawn(3))
+ * code path to be used.
*
- * If application launching occurs via some other mechanism (eg: D-Bus
+ * If application launching occurs via some other mechanism (for example, D-Bus
* activation) then @spawn_flags, @user_setup, @user_setup_data,
* @pid_callback and @pid_callback_data are ignored.
*
- * Returns: %TRUE on successful launch, %FALSE otherwise.
+ * Returns: `TRUE` on successful launch, `FALSE` otherwise.
*/
gboolean
g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo *appinfo,
@@ -3658,15 +3666,17 @@ g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo *appinfo,
* @desktop_env: a string specifying what desktop this is
*
* Sets the name of the desktop that the application is running in.
- * This is used by g_app_info_should_show() and
- * g_desktop_app_info_get_show_in() to evaluate the
- * `OnlyShowIn` and `NotShowIn`
- * desktop entry fields.
+ *
+ * This is used by [method@Gio.AppInfo.should_show] and
+ * [method@Gio.DesktopAppInfo.get_show_in] to evaluate the
+ * [`OnlyShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-onlyshowin)
+ * and [`NotShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-notshowin)
+ * keys.
*
* Should be called only once; subsequent calls are ignored.
*
* Deprecated:2.42:do not use this API. Since 2.42 the value of the
- * `XDG_CURRENT_DESKTOP` environment variable will be used.
+ * `XDG_CURRENT_DESKTOP` environment variable will be used.
*/
void
g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
@@ -4314,28 +4324,12 @@ g_desktop_app_info_delete (GAppInfo *appinfo)
}
/* Create for commandline {{{2 */
-/**
- * g_app_info_create_from_commandline:
- * @commandline: (type filename): the commandline to use
- * @application_name: (nullable): the application name, or %NULL to use @commandline
- * @flags: flags that can specify details of the created #GAppInfo
- * @error: a #GError location to store the error occurring, %NULL to ignore.
- *
- * Creates a new #GAppInfo from the given information.
- *
- * Note that for @commandline, the quoting rules of the Exec key of the
- * [freedesktop.org Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec)
- * are applied. For example, if the @commandline contains
- * percent-encoded URIs, the percent-character must be doubled in order to prevent it from
- * being swallowed by Exec key unquoting. See the specification for exact quoting rules.
- *
- * Returns: (transfer full): new #GAppInfo for given command.
- **/
+
GAppInfo *
-g_app_info_create_from_commandline (const char *commandline,
- const char *application_name,
- GAppInfoCreateFlags flags,
- GError **error)
+g_app_info_create_from_commandline_impl (const char *commandline,
+ const char *application_name,
+ GAppInfoCreateFlags flags,
+ GError **error)
{
char **split;
char *basename;
@@ -4484,25 +4478,8 @@ g_desktop_app_info_get_desktop_ids_for_content_type (const gchar *content_type,
return (gchar **) g_ptr_array_free (hits, FALSE);
}
-/**
- * g_app_info_get_recommended_for_type:
- * @content_type: the content type to find a [iface@Gio.AppInfo] for
- *
- * Gets a list of recommended [iface@Gio.AppInfo]s for a given content type,
- * i.e. those applications which claim to support the given content type
- * exactly, and not by MIME type subclassing.
- *
- * Note that the first application of the list is the last used one, i.e.
- * the last one for which [method@Gio.AppInfo.set_as_last_used_for_type] has
- * been called.
- *
- * Returns: (element-type GAppInfo) (transfer full): list of
- * [iface@Gio.AppInfo]s for given @content_type or `NULL` on error.
- *
- * Since: 2.28
- **/
GList *
-g_app_info_get_recommended_for_type (const gchar *content_type)
+g_app_info_get_recommended_for_type_impl (const gchar *content_type)
{
gchar **desktop_ids;
GList *infos;
@@ -4527,21 +4504,8 @@ g_app_info_get_recommended_for_type (const gchar *content_type)
return g_list_reverse (infos);
}
-/**
- * g_app_info_get_fallback_for_type:
- * @content_type: the content type to find a [iface@Gio.AppInfo] for
- *
- * Gets a list of fallback [iface@Gio.AppInfo]s for a given content type, i.e.
- * those applications which claim to support the given content type by MIME
- * type subclassing and not directly.
- *
- * Returns: (element-type GAppInfo) (transfer full): list of [iface@Gio.AppInfo]s
- * for given @content_type or `NULL` on error.
- *
- * Since: 2.28
- **/
GList *
-g_app_info_get_fallback_for_type (const gchar *content_type)
+g_app_info_get_fallback_for_type_impl (const gchar *content_type)
{
gchar **recommended_ids;
gchar **all_ids;
@@ -4579,20 +4543,8 @@ g_app_info_get_fallback_for_type (const gchar *content_type)
return g_list_reverse (infos);
}
-/**
- * g_app_info_get_all_for_type:
- * @content_type: the content type to find a [iface@Gio.AppInfo] for
- *
- * Gets a list of all [iface@Gio.AppInfo]s for a given content type,
- * including the recommended and fallback [iface@Gio.AppInfo]s. See
- * [func@Gio.AppInfo.get_recommended_for_type] and
- * [func@Gio.AppInfo.get_fallback_for_type].
- *
- * Returns: (element-type GAppInfo) (transfer full): list of
- * [iface@Gio.AppInfo]s for given @content_type.
- **/
GList *
-g_app_info_get_all_for_type (const char *content_type)
+g_app_info_get_all_for_type_impl (const char *content_type)
{
gchar **desktop_ids;
GList *infos;
@@ -4617,40 +4569,17 @@ g_app_info_get_all_for_type (const char *content_type)
return g_list_reverse (infos);
}
-/**
- * g_app_info_reset_type_associations:
- * @content_type: a content type
- *
- * Removes all changes to the type associations done by
- * [method@Gio.AppInfo.set_as_default_for_type],
- * [method@Gio.AppInfo.set_as_default_for_extension],
- * [method@Gio.AppInfo.add_supports_type] or
- * [method@Gio.AppInfo.remove_supports_type].
- *
- * Since: 2.20
- */
void
-g_app_info_reset_type_associations (const char *content_type)
+g_app_info_reset_type_associations_impl (const char *content_type)
{
update_mimeapps_list (NULL, content_type,
UPDATE_MIME_NONE,
NULL);
}
-/**
- * g_app_info_get_default_for_type:
- * @content_type: the content type to find a [iface@Gio.AppInfo] for
- * @must_support_uris: if `TRUE`, the [iface@Gio.AppInfo] is expected to
- * support URIs
- *
- * Gets the default [iface@Gio.AppInfo] for a given content type.
- *
- * Returns: (transfer full) (nullable): [iface@Gio.AppInfo] for given
- * @content_type or `NULL` on error.
- */
GAppInfo *
-g_app_info_get_default_for_type (const char *content_type,
- gboolean must_support_uris)
+g_app_info_get_default_for_type_impl (const char *content_type,
+ gboolean must_support_uris)
{
GPtrArray *blocklist;
GPtrArray *results;
@@ -4713,20 +4642,8 @@ out:
return info;
}
-/**
- * g_app_info_get_default_for_uri_scheme:
- * @uri_scheme: a string containing a URI scheme.
- *
- * Gets the default application for handling URIs with
- * the given URI scheme. A URI scheme is the initial part
- * of the URI, up to but not including the ':', e.g. "http",
- * "ftp" or "sip".
- *
- * Returns: (transfer full) (nullable): #GAppInfo for given @uri_scheme or
- * %NULL on error.
- */
GAppInfo *
-g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
+g_app_info_get_default_for_uri_scheme_impl (const char *uri_scheme)
{
GAppInfo *app_info;
char *content_type, *scheme_down;
@@ -4751,10 +4668,10 @@ g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
* Gets all applications that implement @interface.
*
* An application implements an interface if that interface is listed in
- * the Implements= line of the desktop file of the application.
+ * the `Implements` line of the desktop file of the application.
*
- * Returns: (element-type GDesktopAppInfo) (transfer full): a list of #GDesktopAppInfo
- * objects.
+ * Returns: (element-type GDesktopAppInfo) (transfer full): a list of
+ * [class@Gio.DesktopAppInfo] objects.
*
* Since: 2.42
**/
@@ -4807,15 +4724,15 @@ g_desktop_app_info_get_implementations (const gchar *interface)
* any time.
*
* None of the search results are subjected to the normal validation
- * checks performed by g_desktop_app_info_new() (for example, checking that
+ * checks performed by [ctor@Gio.DesktopAppInfo.new] (for example, checking that
* the executable referenced by a result exists), and so it is possible for
- * g_desktop_app_info_new() to return %NULL when passed an app ID returned by
- * this function. It is expected that calling code will do this when
- * subsequently creating a #GDesktopAppInfo for each result.
+ * [ctor@Gio.DesktopAppInfo.new] to return `NULL` when passed an app ID returned
+ * by this function. It is expected that calling code will do this when
+ * subsequently creating a [class@Gio.DesktopAppInfo] for each result.
*
* Returns: (array zero-terminated=1) (element-type GStrv) (transfer full): a
- * list of strvs. Free each item with g_strfreev() and free the outer
- * list with g_free().
+ * list of strvs. Free each item with [func@GLib.strfreev] and free the outer
+ * list with [func@GLib.free].
*/
gchar ***
g_desktop_app_info_search (const gchar *search_string)
@@ -4892,23 +4809,8 @@ g_desktop_app_info_search (const gchar *search_string)
return results;
}
-/**
- * g_app_info_get_all:
- *
- * Gets a list of all of the applications currently registered
- * on this system.
- *
- * For desktop files, this includes applications that have
- * `NoDisplay=true` set or are excluded from display by means
- * of `OnlyShowIn` or `NotShowIn`. See [method@Gio.AppInfo.should_show].
- * The returned list does not include applications which have
- * the `Hidden` key set.
- *
- * Returns: (element-type GAppInfo) (transfer full): a newly allocated
- * list of references to [iface@Gio.AppInfo]s.
- **/
GList *
-g_app_info_get_all (void)
+g_app_info_get_all_impl (void)
{
GHashTable *apps;
GHashTableIter iter;
@@ -4946,8 +4848,8 @@ g_app_info_get_all (void)
* #GDesktopAppInfoLookup is an opaque data structure and can only be accessed
* using the following functions.
*
- * Deprecated: 2.28: The #GDesktopAppInfoLookup interface is deprecated and
- * unused by GIO.
+ * Deprecated: 2.28: The [iface@Gio.DesktopAppInfoLookup] interface is
+ * deprecated and unused by GIO.
**/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -4964,23 +4866,24 @@ g_desktop_app_info_lookup_default_init (GDesktopAppInfoLookupInterface *iface)
/**
* g_desktop_app_info_lookup_get_default_for_uri_scheme:
- * @lookup: a #GDesktopAppInfoLookup
+ * @lookup: a [iface@Gio.DesktopAppInfoLookup]
* @uri_scheme: a string containing a URI scheme.
*
* Gets the default application for launching applications
- * using this URI scheme for a particular #GDesktopAppInfoLookup
+ * using this URI scheme for a particular [iface@Gio.DesktopAppInfoLookup]
* implementation.
*
- * The #GDesktopAppInfoLookup interface and this function is used
- * to implement g_app_info_get_default_for_uri_scheme() backends
+ * The [iface@Gio.DesktopAppInfoLookup] interface and this function is used
+ * to implement [func@Gio.AppInfo.get_default_for_uri_scheme] backends
* in a GIO module. There is no reason for applications to use it
- * directly. Applications should use g_app_info_get_default_for_uri_scheme().
+ * directly. Applications should use
+ * [func@Gio.AppInfo.get_default_for_uri_scheme].
*
- * Returns: (transfer full) (nullable): #GAppInfo for given @uri_scheme or
- * %NULL on error.
+ * Returns: (transfer full) (nullable): [iface@Gio.AppInfo] for given
+ * @uri_scheme or `NULL` on error.
*
- * Deprecated: 2.28: The #GDesktopAppInfoLookup interface is deprecated and
- * unused by GIO.
+ * Deprecated: 2.28: The [iface@Gio.DesktopAppInfoLookup] interface is
+ * deprecated and unused by GIO.
*/
GAppInfo *
g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
@@ -5001,14 +4904,14 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/**
* g_desktop_app_info_get_startup_wm_class:
- * @info: a #GDesktopAppInfo that supports startup notify
+ * @info: a [class@Gio.DesktopAppInfo] that supports startup notify
*
- * Retrieves the StartupWMClass field from @info. This represents the
- * WM_CLASS property of the main window of the application, if launched
+ * Retrieves the `StartupWMClass` field from @info. This represents the
+ * `WM_CLASS` property of the main window of the application, if launched
* through @info.
*
- * Returns: (nullable) (transfer none): the startup WM class, or %NULL if none is set
- * in the desktop file.
+ * Returns: (nullable) (transfer none): the startup WM class, or `NULL` if none
+ * is set in the desktop file.
*
* Since: 2.34
*/
@@ -5022,15 +4925,15 @@ g_desktop_app_info_get_startup_wm_class (GDesktopAppInfo *info)
/**
* g_desktop_app_info_get_string:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @key: the key to look up
*
* Looks up a string value in the keyfile backing @info.
*
- * The @key is looked up in the "Desktop Entry" group.
+ * The @key is looked up in the `Desktop Entry` group.
*
- * Returns: (nullable): a newly allocated string, or %NULL if the key
- * is not found
+ * Returns: (nullable): a newly allocated string, or `NULL` if the key is not
+ * found
*
* Since: 2.36
*/
@@ -5046,16 +4949,16 @@ g_desktop_app_info_get_string (GDesktopAppInfo *info,
/**
* g_desktop_app_info_get_locale_string:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @key: the key to look up
*
* Looks up a localized string value in the keyfile backing @info
* translated to the current locale.
*
- * The @key is looked up in the "Desktop Entry" group.
+ * The @key is looked up in the `Desktop Entry` group.
*
- * Returns: (nullable): a newly allocated string, or %NULL if the key
- * is not found
+ * Returns: (nullable): a newly allocated string, or `NULL` if the key is not
+ * found
*
* Since: 2.56
*/
@@ -5073,15 +4976,14 @@ g_desktop_app_info_get_locale_string (GDesktopAppInfo *info,
/**
* g_desktop_app_info_get_boolean:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @key: the key to look up
*
* Looks up a boolean value in the keyfile backing @info.
*
- * The @key is looked up in the "Desktop Entry" group.
+ * The @key is looked up in the `Desktop Entry` group.
*
- * Returns: the boolean value, or %FALSE if the key
- * is not found
+ * Returns: the boolean value, or `FALSE` if the key is not found
*
* Since: 2.36
*/
@@ -5097,17 +4999,18 @@ g_desktop_app_info_get_boolean (GDesktopAppInfo *info,
/**
* g_desktop_app_info_get_string_list:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @key: the key to look up
- * @length: (out) (optional): return location for the number of returned strings, or %NULL
+ * @length: (out) (optional): return location for the number of returned
+ * strings, or `NULL`
*
* Looks up a string list value in the keyfile backing @info.
*
- * The @key is looked up in the "Desktop Entry" group.
+ * The @key is looked up in the `Desktop Entry` group.
*
* Returns: (array zero-terminated=1 length=length) (element-type utf8) (transfer full):
- * a %NULL-terminated string array or %NULL if the specified
- * key cannot be found. The array should be freed with g_strfreev().
+ * a `NULL`-terminated string array or `NULL` if the specified
+ * key cannot be found. The array should be freed with [func@GLib.strfreev].
*
* Since: 2.60
*/
@@ -5124,13 +5027,13 @@ g_desktop_app_info_get_string_list (GDesktopAppInfo *info,
/**
* g_desktop_app_info_has_key:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @key: the key to look up
*
- * Returns whether @key exists in the "Desktop Entry" group
+ * Returns whether @key exists in the `Desktop Entry` group
* of the keyfile backing @info.
*
- * Returns: %TRUE if the @key exists
+ * Returns: `TRUE` if the @key exists
*
* Since: 2.36
*/
@@ -5148,15 +5051,17 @@ g_desktop_app_info_has_key (GDesktopAppInfo *info,
/**
* g_desktop_app_info_list_actions:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
*
- * Returns the list of "additional application actions" supported on the
- * desktop file, as per the desktop file specification.
+ * Returns the list of
+ * [‘additional application actions’](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s11.html)
+ * supported on the desktop file, as per the desktop file specification.
*
* As per the specification, this is the list of actions that are
- * explicitly listed in the "Actions" key of the [Desktop Entry] group.
+ * explicitly listed in the `Actions` key of the `Desktop Entry` group.
*
- * Returns: (array zero-terminated=1) (element-type utf8) (transfer none): a list of strings, always non-%NULL
+ * Returns: (array zero-terminated=1) (element-type utf8) (transfer none): a
+ * list of strings, always non-`NULL`
*
* Since: 2.38
**/
@@ -5183,14 +5088,15 @@ app_info_has_action (GDesktopAppInfo *info,
/**
* g_desktop_app_info_get_action_name:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @action_name: the name of the action as from
- * g_desktop_app_info_list_actions()
+ * [method@Gio.DesktopAppInfo.list_actions]
*
- * Gets the user-visible display name of the "additional application
- * action" specified by @action_name.
+ * Gets the user-visible display name of the
+ * [‘additional application actions’](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s11.html)
+ * specified by @action_name.
*
- * This corresponds to the "Name" key within the keyfile group for the
+ * This corresponds to the `Name` key within the keyfile group for the
* action.
*
* Returns: (transfer full): the locale-specific action name
@@ -5225,25 +5131,26 @@ g_desktop_app_info_get_action_name (GDesktopAppInfo *info,
/**
* g_desktop_app_info_launch_action:
- * @info: a #GDesktopAppInfo
+ * @info: a [class@Gio.DesktopAppInfo]
* @action_name: the name of the action as from
- * g_desktop_app_info_list_actions()
- * @launch_context: (nullable): a #GAppLaunchContext
+ * [method@Gio.DesktopAppInfo.list_actions]
+ * @launch_context: (nullable): a [class@Gio.AppLaunchContext]
*
* Activates the named application action.
*
* You may only call this function on action names that were
- * returned from g_desktop_app_info_list_actions().
+ * returned from [method@Gio.DesktopAppInfo.list_actions].
*
* Note that if the main entry of the desktop file indicates that the
* application supports startup notification, and @launch_context is
- * non-%NULL, then startup notification will be used when activating the
+ * non-`NULL`, then startup notification will be used when activating the
* action (and as such, invocation of the action on the receiving side
* must signal the end of startup notification when it is completed).
* This is the expected behaviour of applications declaring additional
- * actions, as per the desktop file specification.
+ * actions, as per the
+ * [desktop file specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s11.html).
*
- * As with g_app_info_launch() there is no way to detect failures that
+ * As with [method@Gio.AppInfo.launch] there is no way to detect failures that
* occur while using this function.
*
* Since: 2.38
diff --git a/gio/gosxappinfo.m b/gio/gosxappinfo.m
index 50b08e0be..6de647d6b 100644
--- a/gio/gosxappinfo.m
+++ b/gio/gosxappinfo.m
@@ -22,6 +22,7 @@
#include "config.h"
#include "gappinfo.h"
+#include "gappinfoprivate.h"
#include "gosxappinfo.h"
#include "gcontenttype.h"
#include "gfile.h"
@@ -577,10 +578,10 @@ g_osx_app_info_iface_init (GAppInfoIface *iface)
}
GAppInfo *
-g_app_info_create_from_commandline (const char *commandline,
- const char *application_name,
- GAppInfoCreateFlags flags,
- GError **error)
+g_app_info_create_from_commandline_impl (const char *commandline,
+ const char *application_name,
+ GAppInfoCreateFlags flags,
+ GError **error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"Creating an app info from a command line not currently supported");
@@ -622,7 +623,7 @@ g_osx_app_info_get_all_for_scheme (const char *cscheme)
}
GList *
-g_app_info_get_all_for_type (const char *content_type)
+g_app_info_get_all_for_type_impl (const char *content_type)
{
gchar *mime_type;
CFArrayRef bundle_list;
@@ -667,20 +668,20 @@ g_app_info_get_all_for_type (const char *content_type)
}
GList *
-g_app_info_get_recommended_for_type (const char *content_type)
+g_app_info_get_recommended_for_type_impl (const char *content_type)
{
return g_app_info_get_all_for_type (content_type);
}
GList *
-g_app_info_get_fallback_for_type (const char *content_type)
+g_app_info_get_fallback_for_type_impl (const char *content_type)
{
return g_app_info_get_all_for_type (content_type);
}
GAppInfo *
-g_app_info_get_default_for_type (const char *content_type,
- gboolean must_support_uris)
+g_app_info_get_default_for_type_impl (const char *content_type,
+ gboolean must_support_uris)
{
gchar *mime_type;
CFStringRef type;
@@ -731,7 +732,7 @@ g_app_info_get_default_for_type (const char *content_type,
}
GAppInfo *
-g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
+g_app_info_get_default_for_uri_scheme_impl (const char *uri_scheme)
{
CFStringRef scheme, bundle_id;
NSBundle *bundle;
@@ -756,7 +757,7 @@ g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
}
GList *
-g_app_info_get_all (void)
+g_app_info_get_all_impl (void)
{
/* There is no API for this afaict
* could manually do it...
@@ -765,6 +766,6 @@ g_app_info_get_all (void)
}
void
-g_app_info_reset_type_associations (const char *content_type)
+g_app_info_reset_type_associations_impl (const char *content_type)
{
}
diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c
index 0b179d877..f2b9cf346 100644
--- a/gio/gwin32appinfo.c
+++ b/gio/gwin32appinfo.c
@@ -29,6 +29,7 @@
#include
#include "gcontenttype.h"
+#include "gappinfoprivate.h"
#include "gwin32appinfo.h"
#include "gappinfo.h"
#include "gioerror.h"
@@ -5671,10 +5672,10 @@ g_win32_app_info_get_supported_types (GAppInfo *appinfo)
}
GAppInfo *
-g_app_info_create_from_commandline (const char *commandline,
- const char *application_name,
- GAppInfoCreateFlags flags,
- GError **error)
+g_app_info_create_from_commandline_impl (const char *commandline,
+ const char *application_name,
+ GAppInfoCreateFlags flags,
+ GError **error)
{
GWin32AppInfo *info;
GWin32AppInfoApplication *app;
@@ -5754,7 +5755,7 @@ g_win32_app_info_iface_init (GAppInfoIface *iface)
}
GAppInfo *
-g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
+g_app_info_get_default_for_uri_scheme_impl (const char *uri_scheme)
{
GWin32AppInfoURLSchema *scheme = NULL;
char *scheme_down;
@@ -5796,8 +5797,8 @@ g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
}
GAppInfo *
-g_app_info_get_default_for_type (const char *content_type,
- gboolean must_support_uris)
+g_app_info_get_default_for_type_impl (const char *content_type,
+ gboolean must_support_uris)
{
GWin32AppInfoFileExtension *ext = NULL;
char *ext_down;
@@ -5858,7 +5859,7 @@ g_app_info_get_default_for_type (const char *content_type,
}
GList *
-g_app_info_get_all (void)
+g_app_info_get_all_impl (void)
{
GHashTableIter iter;
gpointer value;
@@ -5887,7 +5888,7 @@ g_app_info_get_all (void)
}
GList *
-g_app_info_get_all_for_type (const char *content_type)
+g_app_info_get_all_for_type_impl (const char *content_type)
{
GWin32AppInfoFileExtension *ext = NULL;
char *ext_down;
@@ -5957,21 +5958,21 @@ g_app_info_get_all_for_type (const char *content_type)
}
GList *
-g_app_info_get_fallback_for_type (const gchar *content_type)
+g_app_info_get_fallback_for_type_impl (const gchar *content_type)
{
/* TODO: fix this once gcontenttype support is improved */
return g_app_info_get_all_for_type (content_type);
}
GList *
-g_app_info_get_recommended_for_type (const gchar *content_type)
+g_app_info_get_recommended_for_type_impl (const gchar *content_type)
{
/* TODO: fix this once gcontenttype support is improved */
return g_app_info_get_all_for_type (content_type);
}
void
-g_app_info_reset_type_associations (const char *content_type)
+g_app_info_reset_type_associations_impl (const char *content_type)
{
/* nothing to do */
}
diff --git a/gio/meson.build b/gio/meson.build
index a1c0ae36b..3da7a6e47 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -392,7 +392,7 @@ if host_system != 'windows'
if glib_have_cocoa
settings_sources += files('gnextstepsettingsbackend.m')
- contenttype_sources += files('gosxcontenttype.m')
+ contenttype_sources += files('gcontenttype-osx.m')
unix_sources += files('gosxappinfo.m')
framework_dep = dependency('appleframeworks', modules : ['Foundation', 'CoreFoundation', 'AppKit'])
platform_deps += [framework_dep]
@@ -405,7 +405,7 @@ if host_system != 'windows'
)
application_headers += files('gosxappinfo.h')
else
- contenttype_sources += files('gcontenttype.c')
+ contenttype_sources += files('gcontenttype-fdo.c')
unix_sources += files('gdesktopappinfo.c')
gio_unix_include_headers += files('gdesktopappinfo.h')
launch_desktop_sources = files('gio-launch-desktop.c')
@@ -489,6 +489,7 @@ gio_base_sources = files(
'gbytesicon.c',
'gcancellable.c',
'gcharsetconverter.c',
+ 'gcontenttype.c',
'gcontextspecificgroup.c',
'gconverter.c',
'gconverterinputstream.c',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8be46bf29..bfe244769 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,7 +12,7 @@ gio/gbufferedoutputstream.c
gio/gbytesicon.c
gio/gcancellable.c
gio/gcharsetconverter.c
-gio/gcontenttype.c
+gio/gcontenttype-fdo.c
gio/gcontenttype-win32.c
gio/gconverter.c
gio/gconverterinputstream.c
diff --git a/tools/glib.supp b/tools/glib.supp
index bddfe603e..5e4fbd23e 100644
--- a/tools/glib.supp
+++ b/tools/glib.supp
@@ -896,7 +896,7 @@
fun:g_get_home_dir
}
-# gcontenttype.c caches a one-time allocation global array of @global_mime_dirs.
+# gcontenttype-fdo.c caches a one-time allocation global array of @global_mime_dirs.
{
content_type_mime_dirs_realloc
Memcheck:Leak