| /* GTK - The GIMP Toolkit |
| * Copyright (C) 2017 Benjamin Otte |
| * |
| * 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 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 <http://www.gnu.org/licenses/>. |
| */ |
| |
| /** |
| * GdkContentFormats: |
| * |
| * The `GdkContentFormats` structure is used to advertise and negotiate the |
| * format of content. |
| * |
| * You will encounter `GdkContentFormats` when interacting with objects |
| * controlling operations that pass data between different widgets, window |
| * or application, like [class@Gdk.Drag], [class@Gdk.Drop], |
| * [class@Gdk.Clipboard] or [class@Gdk.ContentProvider]. |
| * |
| * GDK supports content in 2 forms: `GType` and mime type. |
| * Using `GTypes` is meant only for in-process content transfers. Mime types |
| * are meant to be used for data passing both in-process and out-of-process. |
| * The details of how data is passed is described in the documentation of |
| * the actual implementations. To transform between the two forms, |
| * [class@Gdk.ContentSerializer] and [class@Gdk.ContentDeserializer] are used. |
| * |
| * A `GdkContentFormats` describes a set of possible formats content can be |
| * exchanged in. It is assumed that this set is ordered. `GTypes` are more |
| * important than mime types. Order between different `GTypes` or mime types |
| * is the order they were added in, most important first. Functions that |
| * care about order, such as [method@Gdk.ContentFormats.union], will describe |
| * in their documentation how they interpret that order, though in general the |
| * order of the first argument is considered the primary order of the result, |
| * followed by the order of further arguments. |
| * |
| * For debugging purposes, the function [method@Gdk.ContentFormats.to_string] |
| * exists. It will print a comma-separated list of formats from most important |
| * to least important. |
| * |
| * `GdkContentFormats` is an immutable struct. After creation, you cannot change |
| * the types it represents. Instead, new `GdkContentFormats` have to be created. |
| * The [struct@Gdk.ContentFormatsBuilder] structure is meant to help in this |
| * endeavor. |
| */ |
| |
| #include "config.h" |
| |
| #include "gdkcontentformats.h" |
| #include "gdkcontentformatsprivate.h" |
| |
| #include <string.h> |
| |
| struct _GdkContentFormats |
| { |
| /*< private >*/ |
| guint ref_count; |
| |
| const char **mime_types; /* interned */ |
| gsize n_mime_types; |
| GType *gtypes; |
| gsize n_gtypes; |
| }; |
| |
| G_DEFINE_BOXED_TYPE (GdkContentFormats, gdk_content_formats, |
| gdk_content_formats_ref, |
| gdk_content_formats_unref) |
| |
| |
| /** |
| * gdk_intern_mime_type: |
| * @string: (transfer none): string of a potential mime type |
| * |
| * Canonicalizes the given mime type and interns the result. |
| * |
| * If @string is not a valid mime type, %NULL is returned instead. |
| * See RFC 2048 for the syntax if mime types. |
| * |
| * Returns: (nullable): An interned string for the canonicalized |
| * mime type or %NULL if the string wasn't a valid mime type |
| */ |
| const char * |
| gdk_intern_mime_type (const char *string) |
| { |
| char *tmp; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| if (!strchr (string, '/')) |
| return NULL; |
| |
| tmp = g_ascii_strdown (string, -1); |
| |
| string = g_intern_string (tmp); |
| |
| g_free (tmp); |
| |
| return string; |
| } |
| |
| static GdkContentFormats * |
| gdk_content_formats_new_take (GType * gtypes, |
| gsize n_gtypes, |
| const char **mime_types, |
| gsize n_mime_types) |
| { |
| GdkContentFormats *result = g_slice_new0 (GdkContentFormats); |
| result->ref_count = 1; |
| |
| result->gtypes = gtypes; |
| result->n_gtypes = n_gtypes; |
| result->mime_types = mime_types; |
| result->n_mime_types = n_mime_types; |
| |
| return result; |
| } |
| |
| /** |
| * gdk_content_formats_new: |
| * @mime_types: (array length=n_mime_types) (nullable): Pointer to an |
| * array of mime types |
| * @n_mime_types: number of entries in @mime_types. |
| * |
| * Creates a new `GdkContentFormats` from an array of mime types. |
| * |
| * The mime types must be valid and different from each other or the |
| * behavior of the return value is undefined. If you cannot guarantee |
| * this, use [struct@Gdk.ContentFormatsBuilder] instead. |
| * |
| * Returns: (transfer full): the new `GdkContentFormats`. |
| */ |
| GdkContentFormats * |
| gdk_content_formats_new (const char **mime_types, |
| guint n_mime_types) |
| { |
| guint i; |
| const char **mime_types_copy; |
| |
| if (n_mime_types == 0) |
| return gdk_content_formats_new_take (NULL, 0, NULL, 0); |
| |
| mime_types_copy = g_new (const char *, n_mime_types + 1); |
| |
| for (i = 0; i < n_mime_types; i++) |
| mime_types_copy[i] = g_intern_string (mime_types[i]); |
| |
| mime_types_copy[n_mime_types] = NULL; |
| |
| return gdk_content_formats_new_take (NULL, 0, mime_types_copy, n_mime_types); |
| } |
| |
| /** |
| * gdk_content_formats_new_for_gtype: |
| * @type: a `GType` |
| * |
| * Creates a new `GdkContentFormats` for a given `GType`. |
| * |
| * Returns: a new `GdkContentFormats` |
| */ |
| GdkContentFormats * |
| gdk_content_formats_new_for_gtype (GType type) |
| { |
| GType *data; |
| |
| g_return_val_if_fail (type != G_TYPE_INVALID, NULL); |
| |
| data = g_new (GType, 2); |
| data[0] = type; |
| data[1] = G_TYPE_INVALID; |
| |
| return gdk_content_formats_new_take (data, 1, NULL, 0); |
| } |
| |
| /** |
| * gdk_content_formats_parse: |
| * @string: the string to parse |
| * |
| * Parses the given @string into `GdkContentFormats` and |
| * returns the formats. |
| * |
| * Strings printed via [method@Gdk.ContentFormats.to_string] |
| * can be read in again successfully using this function. |
| * |
| * If @string does not describe valid content formats, %NULL |
| * is returned. |
| * |
| * Returns: (nullable): the content formats if @string is valid |
| * |
| * Since: 4.4 |
| */ |
| GdkContentFormats * |
| gdk_content_formats_parse (const char *string) |
| { |
| GdkContentFormatsBuilder *builder; |
| char **split; |
| gsize i; |
| |
| g_return_val_if_fail (string != NULL, NULL); |
| |
| split = g_strsplit_set (string, "\t\n\f\r ", -1); /* same as g_ascii_isspace() */ |
| builder = gdk_content_formats_builder_new (); |
| |
| /* first the GTypes */ |
| for (i = 0; split[i] != NULL; i++) |
| { |
| GType type; |
| |
| if (split[i][0] == 0) |
| continue; |
| |
| type = g_type_from_name (split[i]); |
| if (type != 0) |
| gdk_content_formats_builder_add_gtype (builder, type); |
| else |
| break; |
| } |
| |
| /* then the mime types */ |
| for (; split[i] != NULL; i++) |
| { |
| const char *mime_type; |
| |
| if (split[i][0] == 0) |
| continue; |
| |
| mime_type = gdk_intern_mime_type (split[i]); |
| if (mime_type) |
| gdk_content_formats_builder_add_mime_type (builder, mime_type); |
| else |
| break; |
| } |
| |
| if (split[i] != NULL) |
| { |
| g_strfreev (split); |
| gdk_content_formats_builder_unref (builder); |
| return NULL; |
| } |
| |
| g_strfreev (split); |
| return gdk_content_formats_builder_free_to_formats (builder); |
| } |
| |
| /** |
| * gdk_content_formats_ref: |
| * @formats: a `GdkContentFormats` |
| * |
| * Increases the reference count of a `GdkContentFormats` by one. |
| * |
| * Returns: the passed in `GdkContentFormats`. |
| */ |
| GdkContentFormats * |
| gdk_content_formats_ref (GdkContentFormats *formats) |
| { |
| g_return_val_if_fail (formats != NULL, NULL); |
| |
| formats->ref_count++; |
| |
| return formats; |
| } |
| |
| /** |
| * gdk_content_formats_unref: |
| * @formats: a `GdkContentFormats` |
| * |
| * Decreases the reference count of a `GdkContentFormats` by one. |
| * |
| * If the resulting reference count is zero, frees the formats. |
| */ |
| void |
| gdk_content_formats_unref (GdkContentFormats *formats) |
| { |
| g_return_if_fail (formats != NULL); |
| g_return_if_fail (formats->ref_count > 0); |
| |
| formats->ref_count--; |
| if (formats->ref_count > 0) |
| return; |
| |
| g_free (formats->gtypes); |
| g_free (formats->mime_types); |
| g_slice_free (GdkContentFormats, formats); |
| } |
| |
| /** |
| * gdk_content_formats_print: |
| * @formats: a `GdkContentFormats` |
| * @string: a `GString` to print into |
| * |
| * Prints the given @formats into a string for human consumption. |
| * |
| * The result of this function can later be parsed with |
| * [func@Gdk.ContentFormats.parse]. |
| */ |
| void |
| gdk_content_formats_print (GdkContentFormats *formats, |
| GString *string) |
| { |
| gsize i; |
| |
| g_return_if_fail (formats != NULL); |
| g_return_if_fail (string != NULL); |
| |
| for (i = 0; i < formats->n_gtypes; i++) |
| { |
| if (i > 0) |
| g_string_append (string, " "); |
| g_string_append (string, g_type_name (formats->gtypes[i])); |
| } |
| for (i = 0; i < formats->n_mime_types; i++) |
| { |
| if (i > 0 || formats->n_gtypes > 0) |
| g_string_append (string, " "); |
| g_string_append (string, formats->mime_types[i]); |
| } |
| } |
| |
| /** |
| * gdk_content_formats_to_string: |
| * @formats: a `GdkContentFormats` |
| * |
| * Prints the given @formats into a human-readable string. |
| * |
| * The resulting string can be parsed with [func@Gdk.ContentFormats.parse]. |
| * |
| * This is a small wrapper around [method@Gdk.ContentFormats.print] |
| * to help when debugging. |
| * |
| * Returns: (transfer full): a new string |
| */ |
| char * |
| gdk_content_formats_to_string (GdkContentFormats *formats) |
| { |
| GString *string; |
| |
| g_return_val_if_fail (formats != NULL, NULL); |
| |
| string = g_string_new (NULL); |
| gdk_content_formats_print (formats, string); |
| |
| return g_string_free (string, FALSE); |
| } |
| |
| /** |
| * gdk_content_formats_union: |
| * @first: (transfer full): the `GdkContentFormats` to merge into |
| * @second: (transfer none): the `GdkContentFormats` to merge from |
| * |
| * Append all missing types from @second to @first, in the order |
| * they had in @second. |
| * |
| * Returns: a new `GdkContentFormats` |
| */ |
| GdkContentFormats * |
| gdk_content_formats_union (GdkContentFormats *first, |
| const GdkContentFormats *second) |
| { |
| GdkContentFormatsBuilder *builder; |
| |
| g_return_val_if_fail (first != NULL, NULL); |
| g_return_val_if_fail (second != NULL, NULL); |
| |
| builder = gdk_content_formats_builder_new (); |
| |
| gdk_content_formats_builder_add_formats (builder, first); |
| gdk_content_formats_unref (first); |
| gdk_content_formats_builder_add_formats (builder, second); |
| |
| return gdk_content_formats_builder_free_to_formats (builder); |
| } |
| |
| static gboolean |
| gdk_content_formats_contain_interned_mime_type (const GdkContentFormats *formats, |
| const char *mime_type) |
| { |
| gsize i; |
| |
| for (i = 0; i < formats->n_mime_types; i++) |
| { |
| if (mime_type == formats->mime_types[i]) |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| /** |
| * gdk_content_formats_match: |
| * @first: the primary `GdkContentFormats` to intersect |
| * @second: the `GdkContentFormats` to intersect with |
| * |
| * Checks if @first and @second have any matching formats. |
| * |
| * Returns: %TRUE if a matching format was found. |
| */ |
| gboolean |
| gdk_content_formats_match (const GdkContentFormats *first, |
| const GdkContentFormats *second) |
| { |
| g_return_val_if_fail (first != NULL, FALSE); |
| g_return_val_if_fail (second != NULL, FALSE); |
| |
| return gdk_content_formats_match_gtype (first, second) != G_TYPE_INVALID |
| || gdk_content_formats_match_mime_type (first, second) != NULL; |
| } |
| |
| /** |
| * gdk_content_formats_match_gtype: |
| * @first: the primary `GdkContentFormats` to intersect |
| * @second: the `GdkContentFormats` to intersect with |
| * |
| * Finds the first `GType` from @first that is also contained |
| * in @second. |
| * |
| * If no matching `GType` is found, %G_TYPE_INVALID is returned. |
| * |
| * Returns: The first common `GType` or %G_TYPE_INVALID if none. |
| */ |
| GType |
| gdk_content_formats_match_gtype (const GdkContentFormats *first, |
| const GdkContentFormats *second) |
| { |
| gsize i; |
| |
| g_return_val_if_fail (first != NULL, FALSE); |
| g_return_val_if_fail (second != NULL, FALSE); |
| |
| for (i = 0; i < first->n_gtypes; i++) |
| { |
| if (gdk_content_formats_contain_gtype (second, first->gtypes[i])) |
| return first->gtypes[i]; |
| } |
| |
| return G_TYPE_INVALID; |
| } |
| |
| /** |
| * gdk_content_formats_match_mime_type: |
| * @first: the primary `GdkContentFormats` to intersect |
| * @second: the `GdkContentFormats` to intersect with |
| * |
| * Finds the first mime type from @first that is also contained |
| * in @second. |
| * |
| * If no matching mime type is found, %NULL is returned. |
| * |
| * Returns: (nullable): The first common mime type or %NULL if none |
| */ |
| const char * |
| gdk_content_formats_match_mime_type (const GdkContentFormats *first, |
| const GdkContentFormats *second) |
| { |
| gsize i; |
| |
| g_return_val_if_fail (first != NULL, FALSE); |
| g_return_val_if_fail (second != NULL, FALSE); |
| |
| for (i = 0; i < first->n_mime_types; i++) |
| { |
| if (gdk_content_formats_contain_interned_mime_type (second, first->mime_types[i])) |
| return first->mime_types[i]; |
| } |
| |
| return NULL; |
| } |
| |
| /** |
| * gdk_content_formats_contain_gtype: |
| * @formats: a `GdkContentFormats` |
| * @type: the `GType` to search for |
| * |
| * Checks if a given `GType` is part of the given @formats. |
| * |
| * Returns: %TRUE if the `GType` was found |
| */ |
| gboolean |
| gdk_content_formats_contain_gtype (const GdkContentFormats *formats, |
| GType type) |
| { |
| g_return_val_if_fail (formats != NULL, FALSE); |
| |
| gsize i; |
| |
| for (i = 0; i < formats->n_gtypes; i++) |
| { |
| if (type == formats->gtypes[i]) |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| /** |
| * gdk_content_formats_contain_mime_type: |
| * @formats: a `GdkContentFormats` |
| * @mime_type: the mime type to search for |
| * |
| * Checks if a given mime type is part of the given @formats. |
| * |
| * Returns: %TRUE if the mime_type was found |
| */ |
| gboolean |
| gdk_content_formats_contain_mime_type (const GdkContentFormats *formats, |
| const char *mime_type) |
| { |
| g_return_val_if_fail (formats != NULL, FALSE); |
| g_return_val_if_fail (mime_type != NULL, FALSE); |
| |
| return gdk_content_formats_contain_interned_mime_type (formats, |
| g_intern_string (mime_type)); |
| } |
| |
| /** |
| * gdk_content_formats_get_gtypes: |
| * @formats: a `GdkContentFormats` |
| * @n_gtypes: (out) (optional): optional pointer to take the |
| * number of `GType`s contained in the return value |
| * |
| * Gets the `GType`s included in @formats. |
| * |
| * Note that @formats may not contain any `GType`s, in particular when |
| * they are empty. In that case %NULL will be returned. |
| * |
| * Returns: (transfer none) (nullable) (array length=n_gtypes zero-terminated=1): |
| * %G_TYPE_INVALID-terminated array of types included in @formats |
| */ |
| const GType * |
| gdk_content_formats_get_gtypes (const GdkContentFormats *formats, |
| gsize *n_gtypes) |
| { |
| g_return_val_if_fail (formats != NULL, NULL); |
| |
| if (n_gtypes) |
| *n_gtypes = formats->n_gtypes; |
| |
| return formats->gtypes; |
| } |
| |
| /** |
| * gdk_content_formats_get_mime_types: |
| * @formats: a `GdkContentFormats` |
| * @n_mime_types: (out) (optional): optional pointer to take the |
| * number of mime types contained in the return value |
| * |
| * Gets the mime types included in @formats. |
| * |
| * Note that @formats may not contain any mime types, in particular |
| * when they are empty. In that case %NULL will be returned. |
| * |
| * Returns: (transfer none) (nullable) (array length=n_mime_types zero-terminated=1): |
| * %NULL-terminated array of interned strings of mime types included |
| * in @formats |
| */ |
| const char * const * |
| gdk_content_formats_get_mime_types (const GdkContentFormats *formats, |
| gsize *n_mime_types) |
| { |
| g_return_val_if_fail (formats != NULL, NULL); |
| |
| if (n_mime_types) |
| *n_mime_types = formats->n_mime_types; |
| |
| return formats->mime_types; |
| } |
| |
| /** |
| * GdkContentFormatsBuilder: |
| * |
| * A `GdkContentFormatsBuilder` is an auxiliary struct used to create |
| * new `GdkContentFormats`, and should not be kept around. |
| */ |
| |
| struct _GdkContentFormatsBuilder |
| { |
| int ref_count; |
| |
| /* (element-type GType) */ |
| GSList *gtypes; |
| gsize n_gtypes; |
| |
| /* (element-type utf8) (interned) */ |
| GSList *mime_types; |
| gsize n_mime_types; |
| }; |
| |
| G_DEFINE_BOXED_TYPE (GdkContentFormatsBuilder, |
| gdk_content_formats_builder, |
| gdk_content_formats_builder_ref, |
| gdk_content_formats_builder_unref) |
| |
| /** |
| * gdk_content_formats_builder_new: |
| * |
| * Create a new `GdkContentFormatsBuilder` object. |
| * |
| * The resulting builder would create an empty `GdkContentFormats`. |
| * Use addition functions to add types to it. |
| * |
| * Returns: a new `GdkContentFormatsBuilder` |
| */ |
| GdkContentFormatsBuilder * |
| gdk_content_formats_builder_new (void) |
| { |
| GdkContentFormatsBuilder *builder; |
| |
| builder = g_slice_new0 (GdkContentFormatsBuilder); |
| builder->ref_count = 1; |
| |
| return builder; |
| } |
| |
| /** |
| * gdk_content_formats_builder_ref: |
| * @builder: a `GdkContentFormatsBuilder` |
| * |
| * Acquires a reference on the given @builder. |
| * |
| * This function is intended primarily for bindings. |
| * `GdkContentFormatsBuilder` objects should not be kept around. |
| * |
| * Returns: (transfer none): the given `GdkContentFormatsBuilder` |
| * with its reference count increased |
| */ |
| GdkContentFormatsBuilder * |
| gdk_content_formats_builder_ref (GdkContentFormatsBuilder *builder) |
| { |
| g_return_val_if_fail (builder != NULL, NULL); |
| g_return_val_if_fail (builder->ref_count > 0, NULL); |
| |
| builder->ref_count += 1; |
| |
| return builder; |
| } |
| |
| static void |
| gdk_content_formats_builder_clear (GdkContentFormatsBuilder *builder) |
| { |
| g_clear_pointer (&builder->gtypes, g_slist_free); |
| g_clear_pointer (&builder->mime_types, g_slist_free); |
| } |
| |
| /** |
| * gdk_content_formats_builder_unref: |
| * @builder: a `GdkContentFormatsBuilder` |
| * |
| * Releases a reference on the given @builder. |
| */ |
| void |
| gdk_content_formats_builder_unref (GdkContentFormatsBuilder *builder) |
| { |
| g_return_if_fail (builder != NULL); |
| g_return_if_fail (builder->ref_count > 0); |
| |
| builder->ref_count -= 1; |
| |
| if (builder->ref_count > 0) |
| return; |
| |
| gdk_content_formats_builder_clear (builder); |
| g_slice_free (GdkContentFormatsBuilder, builder); |
| } |
| |
| /** |
| * gdk_content_formats_builder_free_to_formats: (skip) |
| * @builder: a `GdkContentFormatsBuilder` |
| * |
| * Creates a new `GdkContentFormats` from the current state of the |
| * given @builder, and frees the @builder instance. |
| * |
| * Returns: (transfer full): the newly created `GdkContentFormats` |
| * with all the formats added to @builder |
| */ |
| GdkContentFormats * |
| gdk_content_formats_builder_free_to_formats (GdkContentFormatsBuilder *builder) |
| { |
| GdkContentFormats *res; |
| |
| g_return_val_if_fail (builder != NULL, NULL); |
| |
| res = gdk_content_formats_builder_to_formats (builder); |
| |
| gdk_content_formats_builder_unref (builder); |
| |
| return res; |
| } |
| |
| /** |
| * gdk_content_formats_builder_to_formats: |
| * @builder: a `GdkContentFormats`Builder |
| * |
| * Creates a new `GdkContentFormats` from the given @builder. |
| * |
| * The given `GdkContentFormatsBuilder` is reset once this function returns; |
| * you cannot call this function multiple times on the same @builder instance. |
| * |
| * This function is intended primarily for bindings. C code should use |
| * [method@Gdk.ContentFormatsBuilder.free_to_formats]. |
| * |
| * Returns: (transfer full): the newly created `GdkContentFormats` |
| * with all the formats added to @builder |
| */ |
| GdkContentFormats * |
| gdk_content_formats_builder_to_formats (GdkContentFormatsBuilder *builder) |
| { |
| GdkContentFormats *result; |
| GType *gtypes; |
| const char **mime_types; |
| GSList *l; |
| gsize i; |
| |
| g_return_val_if_fail (builder != NULL, NULL); |
| |
| if (builder->n_gtypes > 0) |
| { |
| gtypes = g_new (GType, builder->n_gtypes + 1); |
| i = builder->n_gtypes; |
| gtypes[i--] = G_TYPE_INVALID; |
| /* add backwards because most important type is last in the list */ |
| for (l = builder->gtypes; l; l = l->next) |
| gtypes[i--] = GPOINTER_TO_SIZE (l->data); |
| } |
| else |
| { |
| gtypes = NULL; |
| } |
| |
| if (builder->n_mime_types > 0) |
| { |
| mime_types = g_new (const char *, builder->n_mime_types + 1); |
| i = builder->n_mime_types; |
| mime_types[i--] = NULL; |
| /* add backwards because most important type is last in the list */ |
| for (l = builder->mime_types; l; l = l->next) |
| mime_types[i--] = l->data; |
| } |
| else |
| { |
| mime_types = NULL; |
| } |
| |
| result = gdk_content_formats_new_take (gtypes, builder->n_gtypes, |
| mime_types, builder->n_mime_types); |
| |
| gdk_content_formats_builder_clear (builder); |
| |
| return result; |
| } |
| |
| /** |
| * gdk_content_formats_builder_add_formats: |
| * @builder: a `GdkContentFormatsBuilder` |
| * @formats: the formats to add |
| * |
| * Appends all formats from @formats to @builder, skipping those that |
| * already exist. |
| */ |
| void |
| gdk_content_formats_builder_add_formats (GdkContentFormatsBuilder *builder, |
| const GdkContentFormats *formats) |
| { |
| gsize i; |
| |
| g_return_if_fail (builder != NULL); |
| g_return_if_fail (formats != NULL); |
| |
| for (i = 0; i < formats->n_gtypes; i++) |
| gdk_content_formats_builder_add_gtype (builder, formats->gtypes[i]); |
| |
| for (i = 0; i < formats->n_mime_types; i++) |
| gdk_content_formats_builder_add_mime_type (builder, formats->mime_types[i]); |
| } |
| |
| /** |
| * gdk_content_formats_builder_add_gtype: |
| * @builder: a `GdkContentFormats`Builder |
| * @type: a `GType` |
| * |
| * Appends @type to @builder if it has not already been added. |
| **/ |
| void |
| gdk_content_formats_builder_add_gtype (GdkContentFormatsBuilder *builder, |
| GType type) |
| { |
| g_return_if_fail (builder != NULL); |
| g_return_if_fail (type != G_TYPE_INVALID); |
| |
| if (g_slist_find (builder->gtypes, GSIZE_TO_POINTER (type))) |
| return; |
| |
| builder->gtypes = g_slist_prepend (builder->gtypes, GSIZE_TO_POINTER (type)); |
| builder->n_gtypes++; |
| } |
| |
| /** |
| * gdk_content_formats_builder_add_mime_type: |
| * @builder: a `GdkContentFormatsBuilder` |
| * @mime_type: a mime type |
| * |
| * Appends @mime_type to @builder if it has not already been added. |
| */ |
| void |
| gdk_content_formats_builder_add_mime_type (GdkContentFormatsBuilder *builder, |
| const char *mime_type) |
| { |
| g_return_if_fail (builder != NULL); |
| g_return_if_fail (mime_type != NULL); |
| |
| mime_type = g_intern_string (mime_type); |
| |
| if (g_slist_find (builder->mime_types, mime_type)) |
| return; |
| |
| builder->mime_types = g_slist_prepend (builder->mime_types, (gpointer) mime_type); |
| builder->n_mime_types++; |
| } |
| |
| /* {{{ GdkFileList */ |
| |
| /* We're using GdkFileList* and GSList* interchangeably, counting on the |
| * fact that we're just passing around gpointers; the only reason why we |
| * have a GdkFileList opaque type is for language bindings, because they |
| * can have no idea what a GSList of GFiles is. |
| */ |
| |
| static gpointer |
| gdk_file_list_copy (gpointer list) |
| { |
| return g_slist_copy_deep (list, (GCopyFunc) g_object_ref, NULL); |
| } |
| |
| static void |
| gdk_file_list_free (gpointer list) |
| { |
| g_slist_free_full (list, g_object_unref); |
| } |
| |
| G_DEFINE_BOXED_TYPE (GdkFileList, gdk_file_list, gdk_file_list_copy, gdk_file_list_free) |
| |
| /** |
| * gdk_file_list_get_files: |
| * @file_list: the file list |
| * |
| * Retrieves the list of files inside a `GdkFileList`. |
| * |
| * This function is meant for language bindings. |
| * |
| * Returns: (transfer container) (element-type GFile): the files inside the list |
| * |
| * Since: 4.6 |
| */ |
| GSList * |
| gdk_file_list_get_files (GdkFileList *file_list) |
| { |
| return g_slist_copy ((GSList *) file_list); |
| } |
| |
| /** |
| * gdk_file_list_new_from_list: |
| * @files: (element-type GFile): a list of files |
| * |
| * Creates a new files list container from a singly linked list of |
| * `GFile` instances. |
| * |
| * This function is meant to be used by language bindings |
| * |
| * Returns: (transfer full): the newly created files list |
| * |
| * Since: 4.8 |
| */ |
| GdkFileList * |
| gdk_file_list_new_from_list (GSList *files) |
| { |
| return gdk_file_list_copy (files); |
| } |
| |
| /** |
| * gdk_file_list_new_from_array: |
| * @files: (array length=n_files): the files to add to the list |
| * @n_files: the number of files in the array |
| * |
| * Creates a new `GdkFileList` for the given array of files. |
| * |
| * This function is meant to be used by language bindings. |
| * |
| * Returns: (transfer full): the newly create files list |
| * |
| * Since: 4.8 |
| */ |
| GdkFileList * |
| gdk_file_list_new_from_array (GFile **files, |
| gsize n_files) |
| { |
| if (files == NULL || n_files == 0) |
| return NULL; |
| |
| GSList *res = NULL; |
| for (gssize i = n_files - 1; i >= 0; i--) |
| res = g_slist_prepend (res, g_object_ref (files[i])); |
| |
| return (GdkFileList *) res; |
| } |
| |
| /* }}} */ |