From 4f0b18d2031c2c9882c2d5a84435b3613f372c4c Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 21 Oct 2008 11:51:48 +0000 Subject: [PATCH] Bug 555740 - gicon serialization Based on patch from David Zeuthen 2008-10-21 Alexander Larsson Bug 555740 - gicon serialization Based on patch from David Zeuthen * gicon.[ch]: * gio.symbols: Add g_icon_to_string() and g_icon_new_for_string(). * gemblem.c: * gemblemedicon.c: * gfileicon.c: * gthemedicon.c: Implement icon serialization for built-in icon types * tests/Makefile.am: * tests/g-icon.c: Added GIcon serialization test svn path=/trunk/; revision=7618 --- docs/reference/ChangeLog | 5 + docs/reference/gio/gio-sections.txt | 2 + gio/ChangeLog | 19 ++ gio/gemblem.c | 80 +++++++ gio/gemblemedicon.c | 107 +++++++++ gio/gfileicon.c | 55 +++++ gio/gicon.c | 354 +++++++++++++++++++++++++++- gio/gicon.h | 30 ++- gio/gio.symbols | 2 + gio/gthemedicon.c | 57 +++++ gio/tests/Makefile.am | 6 +- gio/tests/g-icon.c | 241 +++++++++++++++++++ 12 files changed, 947 insertions(+), 11 deletions(-) create mode 100644 gio/tests/g-icon.c diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index fd079482..8a5c1e36 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,8 @@ +2008-10-21 Alexander Larsson + + * gio/gio-sections.txt: + Update with new symbolse + 2008-10-16 Matthias Clasen * === Released 2.19.0 === diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 3bb0a794..beb3ec1f 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -353,6 +353,8 @@ GIcon GIconIface g_icon_hash g_icon_equal +g_icon_to_string +g_icon_new_for_string G_ICON G_IS_ICON diff --git a/gio/ChangeLog b/gio/ChangeLog index 4102f2be..e69405e0 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,3 +1,22 @@ +2008-10-21 Alexander Larsson + + Bug 555740 - gicon serialization + Based on patch from David Zeuthen + + * gicon.[ch]: + * gio.symbols: + Add g_icon_to_string() and g_icon_new_for_string(). + + * gemblem.c: + * gemblemedicon.c: + * gfileicon.c: + * gthemedicon.c: + Implement icon serialization for built-in icon types + + * tests/Makefile.am: + * tests/g-icon.c: + Added GIcon serialization test + 2008-10-16 Matthias Clasen * === Released 2.19.0 === diff --git a/gio/gemblem.c b/gio/gemblem.c index b9c4f66a..7ecc6f17 100644 --- a/gio/gemblem.c +++ b/gio/gemblem.c @@ -26,6 +26,9 @@ #include "glibintl.h" #include "gioenums.h" #include "gioenumtypes.h" +#include "gioerror.h" +#include +#include #include "gioalias.h" @@ -273,11 +276,88 @@ g_emblem_equal (GIcon *icon1, g_icon_equal (emblem1->icon, emblem2->icon); } +static gboolean +g_emblem_to_tokens (GIcon *icon, + GPtrArray *tokens, + gint *out_version) +{ + GEmblem *emblem = G_EMBLEM (icon); + char *s; + + /* GEmblem are encoded as + * + * + */ + + g_return_val_if_fail (out_version != NULL, FALSE); + + *out_version = 0; + + s = g_icon_to_string (emblem->icon); + if (s == NULL) + return FALSE; + + g_ptr_array_add (tokens, s); + + s = g_strdup_printf ("%d", emblem->origin); + g_ptr_array_add (tokens, s); + + return TRUE; +} + +static GIcon * +g_emblem_from_tokens (gchar **tokens, + gint num_tokens, + gint version, + GError **error) +{ + GEmblem *emblem; + GIcon *icon; + GEmblemOrigin origin; + char *s; + + emblem = NULL; + + if (version != 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Can't handle version %d of GEmblem encoding"), + version); + return NULL; + } + + if (num_tokens != 2) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed number of tokens (%d) in GEmblem encoding"), + num_tokens); + return NULL; + } + + icon = g_icon_new_for_string (tokens[0], error); + + if (icon == NULL) + return NULL; + + origin = atoi (tokens[1]); + + emblem = g_emblem_new_with_origin (icon, origin); + g_object_unref (icon); + + return G_ICON (emblem); +} + static void g_emblem_iface_init (GIconIface *iface) { iface->hash = g_emblem_hash; iface->equal = g_emblem_equal; + iface->to_tokens = g_emblem_to_tokens; + iface->from_tokens = g_emblem_from_tokens; } #define __G_EMBLEM_C__ diff --git a/gio/gemblemedicon.c b/gio/gemblemedicon.c index 2e672673..36363f80 100644 --- a/gio/gemblemedicon.c +++ b/gio/gemblemedicon.c @@ -29,6 +29,7 @@ #include "gemblemedicon.h" #include "glibintl.h" +#include "gioerror.h" #include "gioalias.h" @@ -237,11 +238,117 @@ g_emblemed_icon_equal (GIcon *icon1, return list1 == NULL && list2 == NULL; } +static gboolean +g_emblemed_icon_to_tokens (GIcon *icon, + GPtrArray *tokens, + gint *out_version) +{ + GEmblemedIcon *emblemed_icon = G_EMBLEMED_ICON (icon); + GList *l; + char *s; + + /* GEmblemedIcons are encoded as + * + * []* + */ + + g_return_val_if_fail (out_version != NULL, FALSE); + + *out_version = 0; + + s = g_icon_to_string (emblemed_icon->icon); + if (s == NULL) + return FALSE; + + g_ptr_array_add (tokens, s); + + for (l = emblemed_icon->emblems; l != NULL; l = l->next) + { + GIcon *emblem_icon = G_ICON (l->data); + + s = g_icon_to_string (emblem_icon); + if (s == NULL) + return FALSE; + + g_ptr_array_add (tokens, s); + } + + return TRUE; +} + +static GIcon * +g_emblemed_icon_from_tokens (gchar **tokens, + gint num_tokens, + gint version, + GError **error) +{ + GEmblemedIcon *emblemed_icon; + char *s; + int n; + + emblemed_icon = NULL; + + if (version != 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Can't handle version %d of GEmblemedIcon encoding"), + version); + goto fail; + } + + if (num_tokens < 1) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed number of tokens (%d) in GEmblemedIcon encoding"), + num_tokens); + goto fail; + } + + emblemed_icon = g_object_new (G_TYPE_EMBLEMED_ICON, NULL); + emblemed_icon->icon = g_icon_new_for_string (tokens[0], error); + if (emblemed_icon->icon == NULL) + goto fail; + + for (n = 1; n < num_tokens; n++) + { + GIcon *emblem; + + emblem = g_icon_new_for_string (tokens[n], error); + if (emblem == NULL) + goto fail; + + if (!G_IS_EMBLEM (emblem)) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Expected a GEmblem for GEmblemedIcon")); + g_object_unref (emblem); + goto fail; + } + + emblemed_icon->emblems = g_list_append (emblemed_icon->emblems, emblem); + } + + return G_ICON (emblemed_icon); + + fail: + if (emblemed_icon != NULL) + g_object_unref (emblemed_icon); + return NULL; +} + static void g_emblemed_icon_icon_iface_init (GIconIface *iface) { iface->hash = g_emblemed_icon_hash; iface->equal = g_emblemed_icon_equal; + iface->to_tokens = g_emblemed_icon_to_tokens; + iface->from_tokens = g_emblemed_icon_from_tokens; } #define __G_EMBLEMED_ICON_C__ diff --git a/gio/gfileicon.c b/gio/gfileicon.c index e11972a5..730d3bae 100644 --- a/gio/gfileicon.c +++ b/gio/gfileicon.c @@ -29,6 +29,7 @@ #include "gloadableicon.h" #include "ginputstream.h" #include "gsimpleasyncresult.h" +#include "gioerror.h" #include "gioalias.h" @@ -202,12 +203,66 @@ g_file_icon_equal (GIcon *icon1, return g_file_equal (file1->file, file2->file); } +static gboolean +g_file_icon_to_tokens (GIcon *icon, + GPtrArray *tokens, + gint *out_version) +{ + GFileIcon *file_icon = G_FILE_ICON (icon); + + g_return_val_if_fail (out_version != NULL, FALSE); + + *out_version = 0; + + g_ptr_array_add (tokens, g_file_get_uri (file_icon->file)); + return TRUE; +} + +static GIcon * +g_file_icon_from_tokens (gchar **tokens, + gint num_tokens, + gint version, + GError **error) +{ + GIcon *icon; + GFile *file; + + icon = NULL; + + if (version != 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Can't handle version %d of GFileIcon encoding"), + version); + goto out; + } + + if (num_tokens != 1) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed input data for GFileIcon")); + goto out; + } + + file = g_file_new_for_uri (tokens[0]); + icon = g_file_icon_new (file); + g_object_unref (file); + + out: + return icon; +} static void g_file_icon_icon_iface_init (GIconIface *iface) { iface->hash = g_file_icon_hash; iface->equal = g_file_icon_equal; + iface->to_tokens = g_file_icon_to_tokens; + iface->from_tokens = g_file_icon_from_tokens; } diff --git a/gio/gicon.c b/gio/gicon.c index aafa5034..d087c40e 100644 --- a/gio/gicon.c +++ b/gio/gicon.c @@ -21,20 +21,32 @@ */ #include "config.h" +#include +#include + #include "gicon.h" +#include "gthemedicon.h" +#include "gfileicon.h" +#include "gemblemedicon.h" +#include "gfile.h" +#include "gioerror.h" #include "glibintl.h" #include "gioalias.h" +/* There versioning of this is implicit, version 1 would be ".1 " */ +#define G_ICON_SERIALIZATION_MAGIC0 ". " + /** * SECTION:gicon * @short_description: Interface for icons * @include: gio/gio.h * - * #GIcon is a very minimal interface for icons. It provides functions - * for checking the equality of two icons and hashing of icons. - * + * #GIcon is a very minimal interface for icons. It provides functions + * for checking the equality of two icons, hashing of icons and + * serializing an icon to and from strings. + * * #GIcon does not provide the actual pixmap for the icon as this is out * of GIO's scope, however implementations of #GIcon may contain the name * of an icon (see #GThemedIcon), or the path to an icon (see #GLoadableIcon). @@ -42,6 +54,13 @@ * To obtain a hash of a #GIcon, see g_icon_hash(). * * To check if two #GIcons are equal, see g_icon_equal(). + * + * For serializing a #GIcon, use g_icon_to_string() and + * g_icon_new_for_string(). + * + * If your application or library provides one or more #GIcon + * implementations you need to ensure that each #GType is registered + * with the type system prior to calling g_icon_new_for_string(). **/ static void g_icon_base_init (gpointer g_class); @@ -140,5 +159,334 @@ g_icon_equal (GIcon *icon1, return (* iface->equal) (icon1, icon2); } +static gboolean +g_icon_to_string_tokenized (GIcon *icon, GString *s) +{ + char *ret; + GPtrArray *tokens; + gint version; + GIconIface *icon_iface; + int i; + + g_return_val_if_fail (icon != NULL, FALSE); + g_return_val_if_fail (G_IS_ICON (icon), FALSE); + + ret = NULL; + + icon_iface = G_ICON_GET_IFACE (icon); + if (icon_iface->to_tokens == NULL) + return FALSE; + + tokens = g_ptr_array_new (); + if (!icon_iface->to_tokens (icon, tokens, &version)) + { + g_ptr_array_free (tokens, TRUE); + return FALSE; + } + + /* format: TypeName[.Version] .. + version 0 is implicit and can be omitted + all the tokens are url escaped to ensure they have no spaces in them */ + + g_string_append (s, g_type_name_from_instance ((GTypeInstance *)icon)); + if (version != 0) + g_string_append_printf (s, ".%d", version); + + for (i = 0; i < tokens->len; i++) + { + char *token; + + token = g_ptr_array_index (tokens, i); + + g_string_append_c (s, ' '); + /* We really only need to escape spaces here, so allow lots of otherwise reserved chars */ + g_string_append_uri_escaped (s, token, + G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE); + } + + g_ptr_array_free (tokens, TRUE); + + return TRUE; +} + +/** + * g_icon_to_string: + * @icon: a #GIcon. + * + * Generates a textual representation of @icon that can be used for + * serialization such as when passing @icon to a different process or + * saving it to persistent storage. Use g_icon_new_for_string() to + * get @icon back from the returned string. + * + * The encoding of the returned string is proprietary to #GIcon except + * in the following two cases + * + * + * + * If @icon is a #GFileIcon, the returned string is a native path + * (such as /path/to/my icon.png) without escaping + * if the #GFile for @icon is a native file. If the file is not + * native, the returned string is the result of g_file_get_uri() + * (such as sftp://path/to/my%%20icon.png). + * + * + * If @icon is a #GThemedIcon with exactly one name, the encoding is + * simply the name (such as network-server). + * + * + * + * Returns: An allocated NUL-terminated UTF8 string or %NULL if @icon can't + * be serialized. Use g_free() to free. + * + * Since: 2.20 + */ +gchar * +g_icon_to_string (GIcon *icon) +{ + gchar *ret; + + g_return_val_if_fail (icon != NULL, NULL); + g_return_val_if_fail (G_IS_ICON (icon), NULL); + + ret = NULL; + + if (G_IS_FILE_ICON (icon)) + { + GFile *file; + + file = g_file_icon_get_file (G_FILE_ICON (icon)); + if (g_file_is_native (file)) + { + ret = g_file_get_path (file); + if (!g_utf8_validate (ret, -1, NULL)) + { + g_free (ret); + ret = NULL; + } + } + else + ret = g_file_get_uri (file); + } + else if (G_IS_THEMED_ICON (icon)) + { + const char * const *names; + + names = g_themed_icon_get_names (G_THEMED_ICON (icon)); + if (names != NULL && + names[0] != NULL && + names[0][0] != '.' && /* Allowing icons starting with dot would break G_ICON_SERIALIZATION_MAGIC0 */ + g_utf8_validate (names[0], -1, NULL) && /* Only return utf8 strings */ + names[1] == NULL) + ret = g_strdup (names[0]); + } + + if (ret == NULL) + { + GString *s; + + s = g_string_new (G_ICON_SERIALIZATION_MAGIC0); + + if (g_icon_to_string_tokenized (icon, s)) + ret = g_string_free (s, FALSE); + else + g_string_free (s, TRUE); + } + + return ret; +} + +static GIcon * +g_icon_new_from_tokens (char **tokens, + GError **error) +{ + GIcon *icon; + char *typename, *version_str; + GType type; + gpointer klass; + GIconIface *icon_iface; + gint version; + char *endp; + int num_tokens; + int i; + + icon = NULL; + klass = NULL; + + num_tokens = g_strv_length (tokens); + + if (num_tokens < 1) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Wrong number of tokens (%d)"), + num_tokens); + goto out; + } + + typename = tokens[0]; + version_str = strchr (typename, '.'); + if (version_str) + { + *version_str = 0; + version_str += 1; + } + + + type = g_type_from_name (tokens[0]); + if (type == 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("No type for class name %s"), + tokens[0]); + goto out; + } + + if (!g_type_is_a (type, G_TYPE_ICON)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Type %s does not implement the GIcon interface"), + tokens[0]); + goto out; + } + + klass = g_type_class_ref (type); + if (klass == NULL) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Type %s is not classed"), + tokens[0]); + goto out; + } + + version = 0; + if (version_str) + { + version = strtol (version_str, &endp, 10); + if (endp == NULL || *endp != '\0') + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed version number: %s"), + version_str); + goto out; + } + } + + icon_iface = g_type_interface_peek (klass, G_TYPE_ICON); + g_assert (icon_iface != NULL); + + if (icon_iface->from_tokens == NULL) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Type %s does not implement from_tokens() on the GIcon interface"), + tokens[0]); + goto out; + } + + for (i = 1; i < num_tokens; i++) + { + char *escaped; + + escaped = tokens[i]; + tokens[i] = g_uri_unescape_string (escaped, NULL); + g_free (escaped); + } + + icon = icon_iface->from_tokens (tokens + 1, num_tokens - 1, version, error); + + out: + if (klass != NULL) + g_type_class_unref (klass); + return icon; +} + +static void +ensure_builtin_icon_types (void) +{ + static volatile GType t; + t = g_themed_icon_get_type (); + t = g_file_icon_get_type (); + t = g_emblemed_icon_get_type (); + t = g_emblem_get_type (); +} + +/** + * g_icon_new_for_string: + * @str: A string obtained via g_icon_to_string(). + * @error: Return location for error. + * + * Generate a #GIcon instance from @str. This function can fail if + * @str is not valid - see g_icon_to_string() for discussion. + * + * If your application or library provides one or more #GIcon + * implementations you need to ensure that each #GType is registered + * with the type system prior to calling g_icon_new_for_string(). + * + * Returns: An object implementing the #GIcon interface or %NULL if + * @error is set. + * + * Since: 2.20 + **/ +GIcon * +g_icon_new_for_string (const gchar *str, + GError **error) +{ + GIcon *icon; + + g_return_val_if_fail (str != NULL, NULL); + + ensure_builtin_icon_types (); + + icon = NULL; + + if (*str == '.') + { + if (g_str_has_prefix (str, G_ICON_SERIALIZATION_MAGIC0)) + { + gchar **tokens; + + /* handle tokenized encoding */ + tokens = g_strsplit (str + sizeof (G_ICON_SERIALIZATION_MAGIC0) - 1, " ", 0); + icon = g_icon_new_from_tokens (tokens, error); + g_strfreev (tokens); + } + else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Can't handle the supplied version the icon encoding")); + } + else + { + gchar *scheme; + + /* handle special GFileIcon and GThemedIcon cases */ + scheme = g_uri_parse_scheme (str); + if (scheme != NULL || str[0] == '/') + { + GFile *location; + location = g_file_new_for_commandline_arg (str); + icon = g_file_icon_new (location); + g_object_unref (location); + } + else + icon = g_themed_icon_new (str); + g_free (scheme); + } + + return icon; +} + + #define __G_ICON_C__ #include "gioaliasdef.c" diff --git a/gio/gicon.h b/gio/gicon.h index f75dfbfc..8f339f69 100644 --- a/gio/gicon.h +++ b/gio/gicon.h @@ -48,6 +48,12 @@ typedef struct _GIconIface GIconIface; * @g_iface: The parent interface. * @hash: A hash for a given #GIcon. * @equal: Checks if two #GIcons are equal. + * @to_tokens: Serializes a #GIcon into tokens. The tokens must not + * contain any whitespace. Don't implement if the #GIcon can't be + * serialized (Since 2.20). + * @from_tokens: Constructs a #GIcon from tokens. Set the #GError if + * the tokens are malformed. Don't implement if the #GIcon can't be + * serialized (Since 2.20). * * GIconIface is used to implement GIcon types for various * different systems. See #GThemedIcon and #GLoadableIcon for @@ -59,16 +65,26 @@ struct _GIconIface /* Virtual Table */ - guint (* hash) (GIcon *icon); - gboolean (* equal) (GIcon *icon1, - GIcon *icon2); + guint (* hash) (GIcon *icon); + gboolean (* equal) (GIcon *icon1, + GIcon *icon2); + gboolean (* to_tokens) (GIcon *icon, + GPtrArray *tokens, + gint *out_version); + GIcon * (* from_tokens) (gchar **tokens, + gint num_tokens, + gint version, + GError **error); }; -GType g_icon_get_type (void) G_GNUC_CONST; +GType g_icon_get_type (void) G_GNUC_CONST; -guint g_icon_hash (gconstpointer icon); -gboolean g_icon_equal (GIcon *icon1, - GIcon *icon2); +guint g_icon_hash (gconstpointer icon); +gboolean g_icon_equal (GIcon *icon1, + GIcon *icon2); +gchar *g_icon_to_string (GIcon *icon); +GIcon *g_icon_new_for_string (const gchar *str, + GError **error); G_END_DECLS diff --git a/gio/gio.symbols b/gio/gio.symbols index 051b86bd..9074b39c 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -470,6 +470,8 @@ g_filter_output_stream_get_base_stream g_icon_get_type G_GNUC_CONST g_icon_hash g_icon_equal +g_icon_to_string +g_icon_new_for_string #endif #endif diff --git a/gio/gthemedicon.c b/gio/gthemedicon.c index 6982d46f..68f8226f 100644 --- a/gio/gthemedicon.c +++ b/gio/gthemedicon.c @@ -26,6 +26,7 @@ #include "gthemedicon.h" #include "gicon.h" +#include "gioerror.h" #include "glibintl.h" #include "gioalias.h" @@ -458,11 +459,67 @@ g_themed_icon_equal (GIcon *icon1, return themed1->names[i] == NULL && themed2->names[i] == NULL; } + +static gboolean +g_themed_icon_to_tokens (GIcon *icon, + GPtrArray *tokens, + gint *out_version) +{ + GThemedIcon *themed_icon = G_THEMED_ICON (icon); + int n; + + g_return_val_if_fail (out_version != NULL, FALSE); + + *out_version = 0; + + for (n = 0; themed_icon->names[n] != NULL; n++) + g_ptr_array_add (tokens, + g_strdup (themed_icon->names[n])); + + return TRUE; +} + +static GIcon * +g_themed_icon_from_tokens (gchar **tokens, + gint num_tokens, + gint version, + GError **error) +{ + GIcon *icon; + gchar **names; + int n; + + icon = NULL; + + if (version != 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Can't handle version %d of GThemedIcon encoding"), + version); + goto out; + } + + names = g_new0 (gchar *, num_tokens + 1); + for (n = 0; n < num_tokens; n++) + names[n] = tokens[n]; + names[n] = NULL; + + icon = g_themed_icon_new_from_names (names, num_tokens); + g_free (names); + + out: + return icon; +} + static void g_themed_icon_icon_iface_init (GIconIface *iface) { iface->hash = g_themed_icon_hash; iface->equal = g_themed_icon_equal; + iface->to_tokens = g_themed_icon_to_tokens; + iface->from_tokens = g_themed_icon_from_tokens; } #define __G_THEMED_ICON_C__ diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index f3a7eb30..ea765d29 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -22,7 +22,8 @@ TEST_PROGS += \ g-file \ g-file-info \ data-input-stream \ - data-output-stream + data-output-stream \ + g-icon if OS_UNIX TEST_PROGS += live-g-file unix-streams desktop-app-info @@ -46,6 +47,9 @@ data_input_stream_LDADD = $(progs_ldadd) data_output_stream_SOURCES = data-output-stream.c data_output_stream_LDADD = $(progs_ldadd) +g_icon_SOURCES = g-icon.c +g_icon_LDADD = $(progs_ldadd) + live_g_file_SOURCES = live-g-file.c live_g_file_LDADD = $(progs_ldadd) diff --git a/gio/tests/g-icon.c b/gio/tests/g-icon.c new file mode 100644 index 00000000..ffa87a82 --- /dev/null +++ b/gio/tests/g-icon.c @@ -0,0 +1,241 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2008 Red Hat, Inc. + * + * This work is provided "as is"; redistribution and modification + * in whole or in part, in any medium, physical or electronic is + * permitted without restriction. + * + * This work 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. + * + * In no event shall the authors or contributors be liable for any + * direct, indirect, incidental, special, exemplary, or consequential + * damages (including, but not limited to, procurement of substitute + * goods or services; loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, whether + * in contract, strict liability, or tort (including negligence or + * otherwise) arising in any way out of the use of this software, even + * if advised of the possibility of such damage. + * + * Authors: David Zeuthen + */ + +#include +#include +#include +#include + +static void +test_g_icon_serialize (void) +{ + GIcon *icon; + GIcon *icon2; + GIcon *icon3; + GIcon *icon4; + GIcon *icon5; + GEmblem *emblem1; + GEmblem *emblem2; + const char *uri; + GFile *location; + char *data; + GError *error; + + error = NULL; + + /* check that GFileIcon and GThemedIcon serialize to the encoding specified */ + + uri = "file:///some/native/path/to/an/icon.png"; + location = g_file_new_for_uri (uri); + icon = g_file_icon_new (location); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "/some/native/path/to/an/icon.png"); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (location); + + uri = "file:///some/native/path/to/an/icon with spaces.png"; + location = g_file_new_for_uri (uri); + icon = g_file_icon_new (location); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "/some/native/path/to/an/icon with spaces.png"); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (location); + + uri = "sftp:///some/non-native/path/to/an/icon.png"; + location = g_file_new_for_uri (uri); + icon = g_file_icon_new (location); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "sftp:///some/non-native/path/to/an/icon.png"); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (location); + + uri = "sftp:///some/non-native/path/to/an/icon with spaces.png"; + location = g_file_new_for_uri (uri); + icon = g_file_icon_new (location); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "sftp:///some/non-native/path/to/an/icon%20with%20spaces.png"); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (location); + + icon = g_themed_icon_new ("network-server"); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "network-server"); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + + /* Check that we can serialize from well-known specified formats */ + icon = g_icon_new_for_string ("network-server%", &error); + g_assert_no_error (error); + icon2 = g_themed_icon_new ("network-server%"); + g_assert (g_icon_equal (icon, icon2)); + g_object_unref (icon); + g_object_unref (icon2); + + icon = g_icon_new_for_string ("/path/to/somewhere.png", &error); + g_assert_no_error (error); + location = g_file_new_for_commandline_arg ("/path/to/somewhere.png"); + icon2 = g_file_icon_new (location); + g_assert (g_icon_equal (icon, icon2)); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (location); + + icon = g_icon_new_for_string ("/path/to/somewhere with whitespace.png", &error); + g_assert_no_error (error); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "/path/to/somewhere with whitespace.png"); + g_free (data); + location = g_file_new_for_commandline_arg ("/path/to/somewhere with whitespace.png"); + icon2 = g_file_icon_new (location); + g_assert (g_icon_equal (icon, icon2)); + g_object_unref (location); + g_object_unref (icon2); + location = g_file_new_for_commandline_arg ("/path/to/somewhere%20with%20whitespace.png"); + icon2 = g_file_icon_new (location); + g_assert (!g_icon_equal (icon, icon2)); + g_object_unref (location); + g_object_unref (icon2); + g_object_unref (icon); + + icon = g_icon_new_for_string ("sftp:///path/to/somewhere.png", &error); + g_assert_no_error (error); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "sftp:///path/to/somewhere.png"); + g_free (data); + location = g_file_new_for_commandline_arg ("sftp:///path/to/somewhere.png"); + icon2 = g_file_icon_new (location); + g_assert (g_icon_equal (icon, icon2)); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (location); + + icon = g_icon_new_for_string ("sftp:///path/to/somewhere with whitespace.png", &error); + g_assert_no_error (error); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, "sftp:///path/to/somewhere%20with%20whitespace.png"); + g_free (data); + location = g_file_new_for_commandline_arg ("sftp:///path/to/somewhere with whitespace.png"); + icon2 = g_file_icon_new (location); + g_assert (g_icon_equal (icon, icon2)); + g_object_unref (location); + g_object_unref (icon2); + location = g_file_new_for_commandline_arg ("sftp:///path/to/somewhere%20with%20whitespace.png"); + icon2 = g_file_icon_new (location); + g_assert (g_icon_equal (icon, icon2)); + g_object_unref (location); + g_object_unref (icon2); + g_object_unref (icon); + + /* Check that GThemedIcon serialization works */ + + icon = g_themed_icon_new ("network-server"); + g_themed_icon_append_name (G_THEMED_ICON (icon), "computer"); + data = g_icon_to_string (icon); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + + icon = g_themed_icon_new ("icon name with whitespace"); + g_themed_icon_append_name (G_THEMED_ICON (icon), "computer"); + data = g_icon_to_string (icon); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + + icon = g_themed_icon_new_with_default_fallbacks ("network-server-xyz"); + g_themed_icon_append_name (G_THEMED_ICON (icon), "computer"); + data = g_icon_to_string (icon); + icon2 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon, icon2)); + g_free (data); + g_object_unref (icon); + g_object_unref (icon2); + + /* Check that GEmblemedIcon serialization works */ + + icon = g_themed_icon_new ("face-smirk"); + icon2 = g_themed_icon_new ("emblem-important"); + g_themed_icon_append_name (G_THEMED_ICON (icon2), "emblem-shared"); + location = g_file_new_for_uri ("file:///some/path/somewhere.png"); + icon3 = g_file_icon_new (location); + g_object_unref (location); + emblem1 = g_emblem_new_with_origin (icon2, G_EMBLEM_ORIGIN_DEVICE); + emblem2 = g_emblem_new_with_origin (icon3, G_EMBLEM_ORIGIN_LIVEMETADATA); + icon4 = g_emblemed_icon_new (icon, emblem1); + g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon4), emblem2); + data = g_icon_to_string (icon4); + icon5 = g_icon_new_for_string (data, &error); + g_assert_no_error (error); + g_assert (g_icon_equal (icon4, icon5)); + g_object_unref (emblem1); + g_object_unref (emblem2); + g_object_unref (icon); + g_object_unref (icon2); + g_object_unref (icon3); + g_object_unref (icon4); + g_object_unref (icon5); +} + +int +main (int argc, + char *argv[]) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/g-icon/serialize", test_g_icon_serialize); + + return g_test_run(); +} -- 2.34.1