The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
GError.xs 06
GMainLoop.xs 02
GObject.xs 017
GVariant.xs 0685
Glib.xs 03
MANIFEST 02
META.json 34
META.yml 910
Makefile.PL 524
NEWS 020
gperl-gtypes.c 039
gperl-gtypes.h 05
gperl.h 6678
lib/Glib/CodeGen.pm 11
lib/Glib/GenPod.pm 13
lib/Glib/MakeHelper.pm 77
lib/Glib/Object/Subclass.pm 11
lib/Glib/ParseXSDoc.pm 11
lib/Glib.pm 1150
t/9.t 711
t/variant.t 0338
typemap 3157
22 files changed (This is a version diff) 1331464
@@ -369,6 +369,12 @@ BOOT:
 	gperl_register_error_domain (G_THREAD_ERROR,
 	                             GPERL_TYPE_THREAD_ERROR,
 	                             "Glib::Thread::Error");
+#if GLIB_CHECK_VERSION (2, 24, 0)
+	/* gvariant.h */
+	gperl_register_error_domain (G_VARIANT_PARSE_ERROR,
+	                             GPERL_TYPE_VARIANT_PARSE_ERROR,
+	                             "Glib::Variant::ParseError");
+#endif
 
 	PERL_UNUSED_VAR (file);
 
@@ -128,6 +128,8 @@ async_watcher_install (void)
 		async_watcher_prepare,
 		async_watcher_check,
 		async_watcher_dispatch,
+		NULL,
+		NULL,
 		NULL
 	};
 	/* FIXME: we never unref the watcher. */
@@ -574,6 +574,23 @@ gperl_object_take_ownership (GObject * object)
 static void
 sink_initially_unowned (GObject *object)
 {
+	/* FIXME: This is not correct when the object is not floating.  The
+	 * sink function is supposed to effectively remove a reference, but
+	 * when the object is not floating, ref_sink+unref == ref+unref == nop.
+	 * Luckily, there do not seem to be functions of GInitiallyUnowned
+	 * descendants out there that transfer ownership of a non-floating
+	 * reference to the caller.  If we ever encounter one, this needs to be
+	 * revisited.
+	 *
+	 * One peculiar corner case is Glib::Object::Introspection's handling
+	 * of GtkWindow and its descendants.  G:O:I marks all constructors of
+	 * GInitiallyUnowned descendants as transferring ownership (to override
+	 * special-casing done by gobject-introspection).  This is thus
+	 * inadvertedly also applied to GtkWindow and its descendants even
+	 * though their constructors do not transfer ownership (because gtk+
+	 * keeps an internal reference to each window).  But due to this
+	 * incorrect code below, the ownership transfer is effectively ignored,
+	 * resulting in correct behavior. */
 	g_object_ref_sink (object);
 	g_object_unref (object);
 }
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2014 by the gtk2-perl team (see the file AUTHORS for the full
+ * list)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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 Library General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "gperl.h"
+
+/* --- GVariant --------------------------------------------------------------*/
+
+/* --- basic wrappers --- */
+
+static SV *
+variant_to_sv (GVariant * variant, gboolean own)
+{
+	SV * sv;
+	SV * rv;
+	HV * stash;
+
+	if (!variant)
+		return &PL_sv_undef;
+
+	sv = newSV (0);
+	_gperl_attach_mg (sv, variant);
+
+	if (own) {
+#if GLIB_CHECK_VERSION (2, 30, 0)
+		g_variant_take_ref (variant);
+#else
+		if (g_variant_is_floating (variant)) {
+			g_variant_ref_sink (variant);
+		}
+#endif
+	} else {
+		g_variant_ref (variant);
+	}
+
+	rv = newRV_noinc (sv);
+	stash = gv_stashpv ("Glib::Variant", TRUE);
+	sv_bless (rv, stash);
+
+	return rv;
+}
+
+static GVariant *
+sv_to_variant (SV * sv)
+{
+	MAGIC * mg;
+	if (!gperl_sv_is_ref (sv) || !(mg = _gperl_find_mg (SvRV (sv))))
+		return NULL;
+	return (GVariant *) mg->mg_ptr;
+}
+
+/* --- GValue wrappers --- */
+
+static SV *
+wrap_variant (const GValue * value)
+{
+	return variant_to_sv (g_value_get_variant (value), FALSE);
+}
+
+static void
+unwrap_variant (GValue * value, SV * sv)
+{
+	g_value_set_variant (value, sv_to_variant (sv));
+}
+
+static GPerlValueWrapperClass variant_wrapper_class = { wrap_variant, unwrap_variant };
+
+/* --- typemap glue --- */
+
+SV *
+newSVGVariant (GVariant * variant)
+{
+	return variant_to_sv (variant, FALSE);
+}
+
+SV *
+newSVGVariant_noinc (GVariant * variant)
+{
+	return variant_to_sv (variant, TRUE);
+}
+
+GVariant *
+SvGVariant (SV * sv)
+{
+	return sv_to_variant (sv);
+}
+
+/* --- GVariantType --------------------------------------------------------- */
+
+/* --- boxed wrappers ---*/
+
+static GPerlBoxedWrapperClass default_boxed_wrapper_class;
+static GPerlBoxedWrapperClass variant_type_wrapper_class;
+
+static gpointer
+unwrap_variant_type (GType gtype, const char * package, SV * sv)
+{
+	if (!gperl_sv_is_ref (sv)) {
+		GVariantType * vtype;
+		vtype = g_variant_type_new (SvPV_nolen (sv));
+		sv = default_boxed_wrapper_class.wrap (gtype, package, vtype, TRUE);
+		/* fall through */
+	}
+	return default_boxed_wrapper_class.unwrap (gtype, package, sv);
+}
+
+/* --- typemap glue --- */
+
+SV *
+newSVGVariantType (const GVariantType * type)
+{
+	if (!type)
+		return &PL_sv_undef;
+	return gperl_new_boxed ((gpointer) type, G_TYPE_VARIANT_TYPE, FALSE);
+}
+
+SV *
+newSVGVariantType_own (const GVariantType * type)
+{
+	return gperl_new_boxed ((gpointer) type, G_TYPE_VARIANT_TYPE, TRUE);
+}
+
+const GVariantType *
+SvGVariantType (SV * sv)
+{
+	if (!gperl_sv_is_defined (sv))
+		return NULL;
+	return gperl_get_boxed_check (sv, G_TYPE_VARIANT_TYPE);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* --- helpers ---*/
+
+static void
+sv_to_variant_array (SV * sv, GVariant *** array_p, gsize * n_p)
+{
+	AV * av;
+	gsize i;
+	if (!gperl_sv_is_array_ref (sv))
+		croak ("Expected an array reference for 'children'");
+	av = (AV *) SvRV (sv);
+	*n_p = av_len (av) + 1;
+	*array_p = g_new0 (GVariant *, *n_p);
+	for (i = 0; i < *n_p; i++) {
+		SV ** svp = av_fetch (av, i, 0);
+		if (svp)
+			(*array_p)[i] = SvGVariant (*svp);
+	}
+}
+
+static void
+sv_to_variant_type_array (SV * sv, const GVariantType *** array_p, gint * n_p)
+{
+	AV * av;
+	gint i;
+	if (!gperl_sv_is_array_ref (sv))
+		croak ("Expected an array reference for 'items'");
+	av = (AV *) SvRV (sv);
+	*n_p = av_len (av) + 1;
+	*array_p = g_new0 (const GVariantType *, *n_p);
+	for (i = 0; i < *n_p; i++) {
+		SV ** svp = av_fetch (av, i, 0);
+		if (svp)
+			(*array_p)[i] = SvGVariantType (*svp);
+	}
+}
+
+/* -------------------------------------------------------------------------- */
+
+MODULE = Glib::Variant	PACKAGE = Glib::Variant	PREFIX = g_variant_
+
+=for object Glib::Variant strongly typed value datatype
+=cut
+
+=for position SYNOPSIS
+
+=head1 SYNOPSIS
+
+  my $v = Glib::Variant->new ('as', ['GTK+', 'Perl']);
+  my $aref = $v->get ('as');
+
+=for position DESCRIPTION
+
+=head1 DESCRIPTION
+
+There are two sets of APIs for creating and dealing with C<Glib::Variant>s: the
+low-level API described below under L</METHODS>, and the convenience API
+described in this section.
+
+=head2 CONVENIENCE API
+
+=over
+
+=item variant = Glib::Variant->new ($format_string, $value)
+
+=item (variant1, ...) = Glib::Variant->new ($format_string, $value1, ...)
+
+Constructs a variant from C<$format_string> and C<$value>.  Also supports
+constructing multiple variants when the format string is a concatenation of
+multiple types.
+
+=item value = $variant->get ($format_string)
+
+Deconstructs C<$variant> according to C<$format_string>.
+
+=back
+
+The following symbols are currently supported in format strings:
+
+  +------------------------------+---------------------------------+
+  |            Symbol            |             Meaning             |
+  +------------------------------+---------------------------------+
+  | b, y, n, q, i, u, x, t, h, d | Boolean, byte and numeric types |
+  | s, o, g                      | String types                    |
+  | v                            | Variant types                   |
+  | a                            | Arrays                          |
+  | m                            | Maybe types                     |
+  | ()                           | Tuples                          |
+  | {}                           | Dictionary entries              |
+  +------------------------------+---------------------------------+
+
+Note that if a format string specifies an array, a tuple or a dictionary entry
+("a", "()" or "{}"), then array references are expected by C<new> and produced
+by C<get>.  For arrays of dictionary entries ("a{}"), hash references are also
+supported by C<new> and handled as you would expect.
+
+For a complete specification, see the documentation at
+
+=over
+
+=item L<https://developer.gnome.org/glib/stable/glib-GVariantType.html>
+
+=item L<https://developer.gnome.org/glib/stable/glib-GVariant.html>
+
+=item L<https://developer.gnome.org/glib/stable/gvariant-format-strings.html>
+
+=item L<https://developer.gnome.org/glib/stable/gvariant-text.html>
+
+=back
+
+=cut
+
+=for see_also Glib::VariantType
+=cut
+
+BOOT:
+	gperl_register_fundamental_full (G_TYPE_VARIANT, "Glib::Variant",
+	                                 &variant_wrapper_class);
+	default_boxed_wrapper_class = variant_type_wrapper_class =
+		* gperl_default_boxed_wrapper_class ();
+	variant_type_wrapper_class.unwrap = unwrap_variant_type;
+	gperl_register_boxed (G_TYPE_VARIANT_TYPE, "Glib::VariantType",
+	                      &variant_type_wrapper_class);
+
+const GVariantType * g_variant_get_type (GVariant *value);
+
+const gchar * g_variant_get_type_string (GVariant *value);
+
+gboolean g_variant_is_of_type (GVariant *value, const GVariantType *type);
+
+gboolean g_variant_is_container (GVariant *value);
+
+const char * g_variant_classify (GVariant *value);
+    PREINIT:
+	GVariantClass vclass;
+    CODE:
+	vclass = g_variant_classify (value);
+	RETVAL = (const char *) &vclass;
+    OUTPUT:
+	RETVAL
+
+GVariant_noinc * g_variant_new_boolean (class, gboolean value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_byte (class, guchar value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_int16 (class, gint16 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_uint16 (class, guint16 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_int32 (class, gint32 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_uint32 (class, guint32 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_int64 (class, gint64 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_uint64 (class, guint64 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_handle (class, gint32 value);
+    C_ARGS:
+	value
+
+GVariant_noinc * g_variant_new_double (class, gdouble value);
+    C_ARGS:
+	value
+
+# GVariant * g_variant_new_take_string (gchar *string);
+GVariant_noinc * g_variant_new_string (class, const gchar *string);
+    C_ARGS:
+	string
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_38
+# GVariant * g_variant_new_printf (const gchar *format_string, ...) G_GNUC_PRINTF (1, 2);
+
+GVariant_noinc * g_variant_new_object_path (class, const gchar *object_path);
+    C_ARGS:
+	object_path
+
+gboolean g_variant_is_object_path (const gchar *string);
+
+GVariant_noinc * g_variant_new_signature (class, const gchar *signature);
+    C_ARGS:
+	signature
+
+gboolean g_variant_is_signature (const gchar *string);
+
+GVariant_noinc * g_variant_new_variant (class, GVariant *value);
+    C_ARGS:
+	value
+
+# FIXME:
+# GVariant * g_variant_new_strv (const gchar * const *strv, gssize length);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_30
+# GVariant * g_variant_new_objv (const gchar * const *strv, gssize length);
+
+#if GLIB_CHECK_VERSION (2, 26, 0)
+
+GVariant_noinc * g_variant_new_bytestring (class, const char_byte * string);
+    C_ARGS:
+	string
+
+# FIXME:
+# GVariant * g_variant_new_bytestring_array (const gchar * const *strv, gssize length);
+
+#endif
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_32
+# GVariant * g_variant_new_fixed_array (const GVariantType *element_type, gconstpointer elements, gsize n_elements, gsize element_size);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_36
+# GVariant * g_variant_new_from_bytes (const GVariantType *type, GBytes *bytes, gboolean trusted);
+
+# FIXME:
+# GVariant * g_variant_new_from_data (const GVariantType *type, gconstpointer data, gsize size, gboolean trusted, GDestroyNotify notify, gpointer user_data);
+
+gboolean g_variant_get_boolean (GVariant *value);
+
+guchar g_variant_get_byte (GVariant *value);
+
+gint16 g_variant_get_int16 (GVariant *value);
+
+guint16 g_variant_get_uint16 (GVariant *value);
+
+gint32 g_variant_get_int32 (GVariant *value);
+
+guint32 g_variant_get_uint32 (GVariant *value);
+
+gint64 g_variant_get_int64 (GVariant *value);
+
+guint64 g_variant_get_uint64 (GVariant *value);
+
+gint32 g_variant_get_handle (GVariant *value);
+
+gdouble g_variant_get_double (GVariant *value);
+
+GVariant_noinc * g_variant_get_variant (GVariant *value);
+
+# gchar * g_variant_dup_string (GVariant *value, gsize *length);
+const gchar * g_variant_get_string (GVariant *value);
+    C_ARGS:
+	value, NULL
+
+# FIXME:
+# gchar ** g_variant_dup_strv (GVariant *value, gsize *length);
+# const gchar ** g_variant_get_strv (GVariant *value, gsize *length);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_30
+# gchar ** g_variant_dup_objv (GVariant *value, gsize *length);
+# const gchar ** g_variant_get_objv (GVariant *value, gsize *length);
+
+#if GLIB_CHECK_VERSION (2, 26, 0)
+
+# gchar * g_variant_dup_bytestring (GVariant *value, gsize *length);
+const char * g_variant_get_bytestring (GVariant *value);
+
+# FIXME:
+# gchar ** g_variant_dup_bytestring_array (GVariant *value, gsize *length);
+# const gchar ** g_variant_get_bytestring_array (GVariant *value, gsize *length);
+
+#endif
+
+GVariant_noinc * g_variant_new_maybe (class, const GVariantType *child_type, GVariant *child);
+    C_ARGS:
+	child_type, child
+
+GVariant * g_variant_new_array (class, const GVariantType *child_type, SV *children);
+    PREINIT:
+	GVariant ** children_c;
+	gsize n_children;
+    CODE:
+	sv_to_variant_array (children, &children_c, &n_children);
+	RETVAL = g_variant_new_array (child_type, children_c, n_children);
+	g_free (children_c);
+    OUTPUT:
+	RETVAL
+
+GVariant * g_variant_new_tuple (class, SV *children);
+    PREINIT:
+	GVariant ** children_c;
+	gsize n_children;
+    CODE:
+	sv_to_variant_array (children, &children_c, &n_children);
+	RETVAL = g_variant_new_tuple (children_c, n_children);
+	g_free (children_c);
+    OUTPUT:
+	RETVAL
+
+GVariant_noinc * g_variant_new_dict_entry (class, GVariant *key, GVariant *value);
+    C_ARGS:
+	key, value
+
+GVariant_noinc * g_variant_get_maybe (GVariant *value);
+
+gsize g_variant_n_children (GVariant *value);
+
+# void g_variant_get_child (GVariant *value, gsize index_, const gchar *format_string, ...);
+
+GVariant_noinc * g_variant_get_child_value (GVariant *value, gsize index_);
+
+# gboolean g_variant_lookup (GVariant *dictionary, const gchar *key, const gchar *format_string, ...);
+GVariant_noinc * g_variant_lookup_value (GVariant *dictionary, const gchar *key, const GVariantType *expected_type);
+
+# FIXME:
+# gconstpointer g_variant_get_fixed_array (GVariant *value, gsize *n_elements, gsize element_size);
+
+gsize g_variant_get_size (GVariant *value);
+
+# FIXME:
+# gconstpointer g_variant_get_data (GVariant *value);
+# GLIB_AVAILABLE_IN_2_36
+# GBytes * g_variant_get_data_as_bytes (GVariant *value);
+# void g_variant_store (GVariant *value, gpointer data);
+
+# GString * g_variant_print_string (GVariant *value, GString *string, gboolean type_annotate);
+gchar_own * g_variant_print (GVariant *value, gboolean type_annotate);
+
+guint g_variant_hash (const GVariant * value);
+
+gboolean g_variant_equal (const GVariant * one, const GVariant * two);
+
+#if GLIB_CHECK_VERSION (2, 26, 0)
+
+gint g_variant_compare (const GVariant * one, const GVariant * two);
+
+#endif
+
+GVariant_noinc * g_variant_get_normal_form (GVariant *value);
+
+gboolean g_variant_is_normal_form (GVariant *value);
+
+GVariant_noinc * g_variant_byteswap (GVariant *value);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_36
+# GVariant * g_variant_new_from_bytes (const GVariantType *type, GBytes *bytes, gboolean trusted);
+
+# FIXME:
+# GVariant * g_variant_new_from_data (const GVariantType *type, gconstpointer data, gsize size, gboolean trusted, GDestroyNotify notify, gpointer user_data);
+
+void
+DESTROY (GVariant * variant)
+    CODE:
+	g_variant_unref (variant);
+
+# --------------------------------------------------------------------------- #
+
+# GVariantIter * g_variant_iter_new (GVariant *value);
+# gsize g_variant_iter_init (GVariantIter *iter, GVariant *value);
+# GVariantIter * g_variant_iter_copy (GVariantIter *iter);
+# gsize g_variant_iter_n_children (GVariantIter *iter);
+# void g_variant_iter_free (GVariantIter *iter);
+# GVariant * g_variant_iter_next_value (GVariantIter *iter);
+# gboolean g_variant_iter_next (GVariantIter *iter, const gchar *format_string, ...);
+# gboolean g_variant_iter_loop (GVariantIter *iter, const gchar *format_string, ...);
+
+# --------------------------------------------------------------------------- #
+
+# GLIB_AVAILABLE_IN_2_40 {
+#   GVariantDict * g_variant_dict_new (GVariant *from_asv);
+#   void g_variant_dict_init (GVariantDict *dict, GVariant *from_asv);
+#   gboolean g_variant_dict_lookup (GVariantDict *dict, const gchar *key, const gchar *format_string, ...);
+#   GVariant * g_variant_dict_lookup_value (GVariantDict *dict, const gchar *key, const GVariantType *expected_type);
+#   gboolean g_variant_dict_contains (GVariantDict *dict, const gchar *key);
+#   void g_variant_dict_insert (GVariantDict *dict, const gchar *key, const gchar *format_string, ...);
+#   void g_variant_dict_insert_value (GVariantDict *dict, const gchar *key, GVariant *value);
+#   gboolean g_variant_dict_remove (GVariantDict *dict, const gchar *key);
+#   void g_variant_dict_clear (GVariantDict *dict);
+#   GVariant * g_variant_dict_end (GVariantDict *dict);
+#   GVariantDict * g_variant_dict_ref (GVariantDict *dict);
+#   void g_variant_dict_unref (GVariantDict *dict);
+# }
+
+# --------------------------------------------------------------------------- #
+
+# GVariantBuilder * g_variant_builder_new (const GVariantType *type);
+# void g_variant_builder_unref (GVariantBuilder *builder);
+# GVariantBuilder * g_variant_builder_ref (GVariantBuilder *builder);
+# void g_variant_builder_init (GVariantBuilder *builder, const GVariantType *type);
+# GVariant * g_variant_builder_end (GVariantBuilder *builder);
+# void g_variant_builder_clear (GVariantBuilder *builder);
+# void g_variant_builder_open (GVariantBuilder *builder, const GVariantType *type);
+# void g_variant_builder_close (GVariantBuilder *builder);
+# void g_variant_builder_add_value (GVariantBuilder *builder, GVariant *value);
+# void g_variant_builder_add (GVariantBuilder *builder, const gchar *format_string, ...);
+# void g_variant_builder_add_parsed (GVariantBuilder *builder, const gchar *format, ...);
+
+# --------------------------------------------------------------------------- #
+
+# These are re-created in lib/Glib.pm.
+# GVariant * g_variant_new (const gchar *format_string, ...);
+# GVariant * g_variant_new_va (const gchar *format_string, const gchar **endptr, va_list *app);
+# void g_variant_get (GVariant *value, const gchar *format_string, ...);
+# void g_variant_get_va (GVariant *value, const gchar *format_string, const gchar **endptr, va_list *app);
+# GLIB_AVAILABLE_IN_2_34
+# gboolean g_variant_check_format_string (GVariant *value, const gchar *format_string, gboolean copy_only);
+
+# --------------------------------------------------------------------------- #
+
+=for apidoc __function__ __gerror__
+=cut
+GVariant_noinc *
+g_variant_parse (const GVariantType *type, const gchar *text)
+    PREINIT:
+	GError *error = NULL;
+    CODE:
+	RETVAL = g_variant_parse (type, text, NULL, NULL, &error);
+	if (error)
+		gperl_croak_gerror (NULL, error);
+    OUTPUT:
+	RETVAL
+
+# GVariant * g_variant_new_parsed (const gchar *format, ...);
+# GVariant * g_variant_new_parsed_va (const gchar *format, va_list *app);
+# GLIB_AVAILABLE_IN_2_40
+# gchar * g_variant_parse_error_print_context (GError *error, const gchar *source_str);
+
+# --------------------------------------------------------------------------- #
+
+MODULE = Glib::Variant	PACKAGE = Glib::VariantType	PREFIX = g_variant_type_
+
+=for see_also Glib::Variant
+=cut
+
+=for apidoc __function__
+=cut
+gboolean g_variant_type_string_is_valid (const gchar *type_string);
+
+=for apidoc
+=for signature (type_string, rest) = Glib::VariantType::string_scan ($string)
+Scans the start of C<$string> for a complete type string and extracts it.  If
+no type string can be found, an exception is thrown.
+=cut
+# gboolean g_variant_type_string_scan (const gchar *string, const gchar *limit, const gchar **endptr);
+void
+g_variant_type_string_scan (const char *string)
+    PREINIT:
+	const char *limit = NULL;
+	const char *endptr = NULL;
+    PPCODE:
+	if (!g_variant_type_string_scan (string, limit, &endptr))
+		croak ("Could not find type string at the start of '%s'",
+		       string);
+	PUSHs (sv_2mortal (newSVpvn (string, endptr-string)));
+        if (endptr && *endptr)
+        	XPUSHs (sv_2mortal (newSVpv (endptr, 0)));
+
+GVariantType_own * g_variant_type_new (class, const gchar *type_string);
+    C_ARGS:
+	type_string
+
+# const gchar * g_variant_type_peek_string (const GVariantType *type);
+# gchar * g_variant_type_dup_string (const GVariantType  *type);
+SV * g_variant_type_get_string (const GVariantType *type)
+    PREINIT:
+	const char * string;
+    CODE:
+	string = g_variant_type_peek_string (type);
+	RETVAL = newSVpv (string, g_variant_type_get_string_length (type));
+    OUTPUT:
+	RETVAL
+
+gboolean g_variant_type_is_definite (const GVariantType *type);
+
+gboolean g_variant_type_is_container (const GVariantType *type);
+
+gboolean g_variant_type_is_basic (const GVariantType *type);
+
+gboolean g_variant_type_is_maybe (const GVariantType *type);
+
+gboolean g_variant_type_is_array (const GVariantType *type);
+
+gboolean g_variant_type_is_tuple (const GVariantType *type);
+
+gboolean g_variant_type_is_dict_entry (const GVariantType *type);
+
+gboolean g_variant_type_is_variant (const GVariantType *type);
+
+guint g_variant_type_hash (const GVariantType *type);
+
+gboolean g_variant_type_equal (const GVariantType *type1, const GVariantType *type2);
+
+gboolean g_variant_type_is_subtype_of (const GVariantType *type, const GVariantType *supertype);
+
+const GVariantType * g_variant_type_element (const GVariantType *type);
+
+const GVariantType * g_variant_type_first (const GVariantType *type);
+
+const GVariantType * g_variant_type_next (const GVariantType *type);
+
+gsize g_variant_type_n_items (const GVariantType *type);
+
+const GVariantType * g_variant_type_key (const GVariantType *type);
+
+const GVariantType * g_variant_type_value (const GVariantType *type);
+
+GVariantType_own * g_variant_type_new_array (class, const GVariantType *element);
+    C_ARGS:
+	element
+
+GVariantType_own * g_variant_type_new_maybe (class, const GVariantType *element);
+    C_ARGS:
+	element
+
+GVariantType_own * g_variant_type_new_tuple (class, SV *items);
+    PREINIT:
+	const GVariantType ** items_c;
+	gint n_items;
+    CODE:
+	sv_to_variant_type_array (items, &items_c, &n_items);
+	RETVAL = g_variant_type_new_tuple (items_c, n_items);
+	g_free (items_c);
+    OUTPUT:
+	RETVAL
+
+GVariantType_own * g_variant_type_new_dict_entry (class, const GVariantType *key, const GVariantType *value);
+    C_ARGS:
+	key, value
@@ -470,6 +470,9 @@ BOOT:
 #if GLIB_CHECK_VERSION (2, 12, 0)
 	GPERL_CALL_BOOT (boot_Glib__BookmarkFile);
 #endif /* GLIB_CHECK_VERSION (2, 12, 0) */
+#if GLIB_CHECK_VERSION (2, 24, 0)
+	GPERL_CALL_BOOT (boot_Glib__Variant);
+#endif /* GLIB_CHECK_VERSION (2, 24, 0) */
 	/* make sure that we're running/linked against a version at least as 
 	 * new as we built against, otherwise bad things will happen. */
 	if ((((int)glib_major_version) < GLIB_MAJOR_VERSION)
@@ -26,6 +26,7 @@ GSignal.xs
 GType.xs
 GUtils.xs
 GValue.xs
+GVariant.xs
 lib/Glib.pm
 lib/Glib/CodeGen.pm
 lib/Glib/GenPod.pm
@@ -71,6 +72,7 @@ t/signal_query.t
 t/tied_definedness.t
 t/tied_flags.t
 t/tied_set_property.t
+t/variant.t
 TODO
 typemap
 xsapi.pod.foot
@@ -4,7 +4,7 @@
       "gtk2-perl Team <gtk-perl-list at gnome dot org>"
    ],
    "dynamic_config" : 1,
-   "generated_by" : "ExtUtils::MakeMaker version 6.86, CPAN::Meta::Converter version 2.133380",
+   "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.143240",
    "license" : [
       "lgpl_2_1"
    ],
@@ -35,6 +35,7 @@
          "GKeyFile.xs",
          "GOption.xs",
          "GBookmarkFile.xs",
+         "GVariant.xs",
          "Makefile.PL",
          "xsapi.pod.head",
          "xsapi.pod.foot"
@@ -63,7 +64,7 @@
          }
       }
    },
-   "release_status" : "stable",
+   "release_status" : "unstable",
    "resources" : {
       "bugtracker" : {
          "mailto" : "bug-Glib [at] rt.cpan.org",
@@ -80,5 +81,5 @@
       },
       "x_MailingList" : "https://mail.gnome.org/mailman/listinfo/gtk-perl-list"
    },
-   "version" : "1.305"
+   "version" : "1.310"
 }
@@ -3,17 +3,17 @@ abstract: 'Perl wrappers for the GLib utility and Object libraries'
 author:
   - 'gtk2-perl Team <gtk-perl-list at gnome dot org>'
 build_requires:
-  ExtUtils::MakeMaker: 0
+  ExtUtils::MakeMaker: '0'
 configure_requires:
-  ExtUtils::Depends: 0.300
-  ExtUtils::MakeMaker: 0
-  ExtUtils::PkgConfig: 1.000
+  ExtUtils::Depends: '0.300'
+  ExtUtils::MakeMaker: '0'
+  ExtUtils::PkgConfig: '1.000'
 dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.86, CPAN::Meta::Converter version 2.133380'
+generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.143240'
 license: lgpl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
-  version: 1.4
+  version: '1.4'
 name: Glib
 no_index:
   directory:
@@ -36,18 +36,19 @@ no_index:
     - GKeyFile.xs
     - GOption.xs
     - GBookmarkFile.xs
+    - GVariant.xs
     - Makefile.PL
     - xsapi.pod.head
     - xsapi.pod.foot
   package:
     - MY
 requires:
-  ExtUtils::Depends: 0.300
-  ExtUtils::PkgConfig: 1.000
+  ExtUtils::Depends: '0.300'
+  ExtUtils::PkgConfig: '1.000'
 resources:
   MailingList: https://mail.gnome.org/mailman/listinfo/gtk-perl-list
   bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Glib
   homepage: http://gtk2-perl.sourceforge.net
   license: http://www.gnu.org/licenses/lgpl-2.1.html
   repository: git://git.gnome.org/perl-Glib
-version: 1.305
+version: '1.310'
@@ -89,6 +89,10 @@ if (ExtUtils::PkgConfig->atleast_version ('glib-2.0', '2.12.0')) {
 	push @xs_files, 'GBookmarkFile.xs';
 }
 
+if (ExtUtils::PkgConfig->atleast_version ('glib-2.0', '2.24.0')) {
+	push @xs_files, 'GVariant.xs';
+}
+
 my %meta_merge = (
         q(meta-spec)          => {
             version => '2',
@@ -96,8 +100,8 @@ my %meta_merge = (
         },
         author              =>
             ['gtk2-perl Team <gtk-perl-list at gnome dot org>'],
-        #release_status      => 'unstable',
-        release_status      => 'stable',
+        release_status      => 'unstable',
+        #release_status      => 'stable',
         # valid values: https://metacpan.org/module/CPAN::Meta::Spec#license
         license             => 'lgpl_2_1',
         resources => {
@@ -192,6 +196,20 @@ $glib->save_config ('build/IFiles.pm');
 our @exports;
 require 'Glib.exports';
 
+# On OpenBSD, any program that directly or indirectly wants to load
+# libpthread.so must do so from the start.  But when perl is built without
+# ithreads, it will also most likely not be compiled with "-pthread".  When
+# libglib/libgobject then go and try to load libpthread.so, the loader will
+# error out.
+my @openbsd_compat_flags = ();
+if ($^O eq 'openbsd' && $Config::Config{ldflags} !~ m/-pthread\b/) {
+  warn " ***\n *** on OpenBSD, we either need perl linked with '-pthread',\n",
+       " ***   or we need to set LD_PRELOAD=libpthread.so; doing the latter now...\n ***\n";
+  @openbsd_compat_flags = (
+    macro => {FULLPERLRUN => 'LD_PRELOAD=libpthread.so $(FULLPERL)'},
+  );
+}
+
 WriteMakefile(
     NAME		=> 'Glib',
     VERSION_FROM	=> 'lib/Glib.pm', # finds $VERSION
@@ -203,9 +221,10 @@ WriteMakefile(
     DL_FUNCS		=> { Glib => [] },
     META_MERGE		=> \%meta_merge,
     $glib ? $glib->get_makefile_vars : (),
+    @openbsd_compat_flags,
 );
 
-=unstable
+#=unstable
 
 print <<__EOW__;
 WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
@@ -218,7 +237,7 @@ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 __EOW__
 
-=cut
+#=cut
 
 =frozen
 
@@ -250,7 +269,7 @@ build/podindex :: \$(INST_LIB)/Glib/GenPod.pm
 
 \$(INST_LIB)/\$(FULLEXT)/xsapi.pod :: build/doc.pl apidoc.pl xsapi.pod.head xsapi.pod.foot
 	\$(NOECHO) \$(ECHO) Creating XS API documentation...
-	\$(NOECHO) $^X apidoc.pl xsapi.pod.head xsapi.pod.foot build/doc.pl > \$@
+	\$(NOECHO) \$(FULLPERLRUN) apidoc.pl xsapi.pod.head xsapi.pod.foot build/doc.pl > \$@
 
 "
 	     . Glib::MakeHelper->postamble_precompiled_headers (qw/gperl.h/)
@@ -1,3 +1,23 @@
+Overview of changes in Glib 1.310 (unstable)
+============================================
+
+* Add Glib::Variant and Glib::VariantType
+* Add char_byte and char_byte_ornull typemaps
+* Reorder and reformat our header and typemap a little
+* Hush a compiler warning in GMainLoop.xs
+
+Overview of changes in Glib 1.307 (stable)
+==========================================
+
+* Fix hang of t/9.t on FreeBSD/NetBSD perls not built with "-pthread"; 
+  closes RT#82349
+* Add code comments about the peculiar Glib::InitiallyUnowned sink handling
+
+Overview of changes in Glib 1.306 (stable)
+==========================================
+
+* Fix libpthread-related building issues on OpenBSD
+
 Overview of changes in Glib 1.305 (stable)
 ==========================================
 
@@ -510,3 +510,42 @@ gperl_thread_error_get_type (void)
 
 #define GPERL_TYPE_THREAD_ERROR gperl_thread_error_get_type()
 GType gperl_thread_error_get_type (void);
+
+/* -------------------------------------------------------------------------- */
+
+#if GLIB_CHECK_VERSION (2, 24, 0)
+
+GType
+gperl_variant_parse_error_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GEnumValue values[] = {
+      { G_VARIANT_PARSE_ERROR_FAILED, "G_VARIANT_PARSE_ERROR_FAILED", "failed" },
+      { G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED, "G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED", "basic-type-expected" },
+      { G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE, "G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE", "cannot-infer-type" },
+      { G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED, "G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED", "definite-type-expected" },
+      { G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END, "G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END", "input-not-at-end" },
+      { G_VARIANT_PARSE_ERROR_INVALID_CHARACTER, "G_VARIANT_PARSE_ERROR_INVALID_CHARACTER", "invalid-character" },
+      { G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING, "G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING", "invalid-format-string" },
+      { G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH, "G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH", "invalid-object-path" },
+      { G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE, "G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE", "invalid-signature" },
+      { G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING, "G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING", "invalid-type-string" },
+      { G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE, "G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE", "no-common-type" },
+      { G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE, "G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE", "number-out-of-range" },
+      { G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG, "G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG", "number-too-big" },
+      { G_VARIANT_PARSE_ERROR_TYPE_ERROR, "G_VARIANT_PARSE_ERROR_TYPE_ERROR", "type-error" },
+      { G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN, "G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN", "unexpected-token" },
+      { G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD, "G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD", "unknown-keyword" },
+      { G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT, "G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT", "unterminated-string-constant" },
+      { G_VARIANT_PARSE_ERROR_VALUE_EXPECTED, "G_VARIANT_PARSE_ERROR_VALUE_EXPECTED", "value-expected" },
+      { 0, NULL, NULL }
+    };
+    type = g_enum_register_static ("GVariantParseError", values);
+  }
+
+  return type;
+}
+
+#endif
@@ -79,6 +79,11 @@ GType gperl_spawn_error_get_type (void) G_GNUC_CONST;
 #define GPERL_TYPE_THREAD_ERROR gperl_thread_error_get_type ()
 GType gperl_thread_error_get_type (void) G_GNUC_CONST;
 
+#if GLIB_CHECK_VERSION (2, 24, 0)
+#define GPERL_TYPE_VARIANT_PARSE_ERROR gperl_variant_parse_error_get_type ()
+GType gperl_variant_parse_error_get_type (void);
+#endif
+
 G_END_DECLS
 
 #endif /* __GPERL_GTYPES_H__ */
@@ -37,13 +37,18 @@
 #include <glib-object.h>
 
 /*
- * filenames
+ * --- filenames --------------------------------------------------------------
  */
+typedef gchar* GPerlFilename;
+typedef const gchar* GPerlFilename_const;
+typedef gchar* GPerlFilename_own;
+typedef GPerlFilename GPerlFilename_ornull;
+
 gchar *gperl_filename_from_sv (SV *sv);
 SV *gperl_sv_from_filename (const gchar *filename);
 
 /*
- * enums and flags
+ * --- enums and flags --------------------------------------------------------
  */
 gboolean gperl_try_convert_enum (GType type, SV * sv, gint * val);
 gint gperl_convert_enum (GType type, SV * val);
@@ -55,8 +60,9 @@ gint gperl_convert_flag_one (GType type, const char * val_p);
 gint gperl_convert_flags (GType type, SV * val);
 SV * gperl_convert_back_flags (GType type, gint val);
 
-/* register a fundamental type (enums, flags...) */
-
+/*
+ * --- fundamental types ------------------------------------------------------
+ */
 typedef struct _GPerlValueWrapperClass GPerlValueWrapperClass;
 
 typedef SV*  (*GPerlValueWrapFunc)   (const GValue * value);
@@ -77,7 +83,7 @@ const char * gperl_fundamental_package_from_type (GType gtype);
 GPerlValueWrapperClass * gperl_fundamental_wrapper_class_from_type (GType gtype);
 
 /*
- * GErrors as exception objects
+ * --- GErrors as exception objects -------------------------------------------
  */
 /* it is rare that you should ever want or need these two functions. */
 SV * gperl_sv_from_gerror (GError * error);
@@ -90,7 +96,7 @@ void gperl_register_error_domain (GQuark domain,
 void gperl_croak_gerror (const char * ignored, GError * err);
 
 /*
- * inheritance management
+ * --- inheritance management -------------------------------------------------
  */
 /* push @{$parent_package}::ISA, $child_package */
 void gperl_set_isa (const char * child_package, const char * parent_package);
@@ -103,45 +109,38 @@ void gperl_prepend_isa (const char * child_package, const char * parent_package)
 GType gperl_type_from_package (const char * package);
 const char * gperl_package_from_type (GType type);
 
-
 /*
- * we need a GBoxed wrapper for a generic SV, so we can store SVs
- * in GObjects reliably.
+ * --- gchar converters -------------------------------------------------------
  */
-#define GPERL_TYPE_SV	(gperl_sv_get_type ())
-GType gperl_sv_get_type (void) G_GNUC_CONST;
-SV * gperl_sv_copy (SV * sv);
-void gperl_sv_free (SV * sv);
-
+typedef gchar gchar_length; /* length in bytes */
+typedef gchar gchar_utf8_length; /* length in characters */
+typedef gchar gchar_own;
+typedef gchar gchar_ornull;
+typedef gchar gchar_own_ornull;
 
-/*
- * clean function wrappers for treating gchar* as UTF8 strings, in the
+/* clean function wrappers for treating gchar* as UTF8 strings, in the
  * same idiom as the rest of the cast macros.  these are wrapped up
- * as functions because comma expressions in macros get kinda tricky.
- */
+ * as functions because comma expressions in macros get kinda tricky. */
 /*const*/ gchar * SvGChar (SV * sv);
 SV * newSVGChar (const gchar * str);
 
-
 /*
- * 64 bit integer converters
+ * --- 64 bit integer converters ----------------------------------------------
  */
 gint64 SvGInt64 (SV *sv);
 SV * newSVGInt64 (gint64 value);
 guint64 SvGUInt64 (SV *sv);
 SV * newSVGUInt64 (guint64 value);
 
-
 /*
- * GValues
+ * --- GValue -----------------------------------------------------------------
  */
 gboolean gperl_value_from_sv (GValue * value, SV * sv);
 SV * gperl_sv_from_value (const GValue * value);
 
 /*
- * GBoxed
+ * --- GBoxed -----------------------------------------------------------------
  */
-
 typedef struct _GPerlBoxedWrapperClass GPerlBoxedWrapperClass;
 
 typedef SV*      (*GPerlBoxedWrapFunc)    (GType        gtype,
@@ -171,14 +170,28 @@ SV * gperl_new_boxed (gpointer boxed, GType gtype, gboolean own);
 SV * gperl_new_boxed_copy (gpointer boxed, GType gtype);
 gpointer gperl_get_boxed_check (SV * sv, GType gtype);
 
-
 GType gperl_boxed_type_from_package (const char * package);
 const char * gperl_boxed_package_from_type (GType type);
 
+/*
+ * we need a GBoxed wrapper for a generic SV, so we can store SVs
+ * in GObjects reliably.
+ */
+#define GPERL_TYPE_SV	(gperl_sv_get_type ())
+GType gperl_sv_get_type (void) G_GNUC_CONST;
+SV * gperl_sv_copy (SV * sv);
+void gperl_sv_free (SV * sv);
 
 /*
- * GObject
+ * --- GObject ----------------------------------------------------------------
  */
+typedef GObject GObject_ornull;
+typedef GObject GObject_noinc;
+#define newSVGObject(obj)	(gperl_new_object ((obj), FALSE))
+#define newSVGObject_noinc(obj)	(gperl_new_object ((obj), TRUE))
+#define SvGObject(sv)		(gperl_get_object_check (sv, G_TYPE_OBJECT))
+#define SvGObject_ornull(sv)	(gperl_sv_is_defined (sv) ? SvGObject (sv) : NULL)
+
 void gperl_register_object (GType gtype, const char * package);
 void gperl_register_object_alias (GType gtype, const char * package);
 
@@ -203,32 +216,8 @@ void _gperl_attach_mg (SV * sv, void * ptr);
 MAGIC * _gperl_find_mg (SV * sv);
 void _gperl_remove_mg (SV * sv);
 
-/* typedefs and macros for use with the typemap */
-typedef gchar gchar_length; /* length in bytes */
-typedef gchar gchar_utf8_length; /* length in characters */
-typedef gchar gchar_own;
-typedef gchar gchar_ornull;
-typedef gchar gchar_own_ornull;
-typedef char char_ornull;
-typedef char char_own;
-typedef char char_own_ornull;
-typedef GObject GObject_ornull;
-typedef GObject GObject_noinc;
-typedef gchar *GPerlFilename;
-typedef const gchar *GPerlFilename_const;
-typedef gchar *GPerlFilename_own;
-typedef GPerlFilename GPerlFilename_ornull;
-typedef GParamSpec GParamSpec_ornull;
-
-#define newSVGObject(obj)	(gperl_new_object ((obj), FALSE))
-#define newSVGObject_noinc(obj)	(gperl_new_object ((obj), TRUE))
-#define SvGObject(sv)		(gperl_get_object_check (sv, G_TYPE_OBJECT))
-#define SvGObject_ornull(sv)	(gperl_sv_is_defined (sv) ? SvGObject (sv) : NULL)
-#define newSVGParamSpec_ornull(sv)	newSVGParamSpec(sv)
-
-
 /*
- * GSignal.xs
+ * --- GSignal ----------------------------------------------------------------
  */
 SV * newSVGSignalFlags (GSignalFlags flags);
 GSignalFlags SvGSignalFlags (SV * sv);
@@ -244,9 +233,8 @@ gulong gperl_signal_connect          (SV              * instance,
                                       SV              * data,
                                       GConnectFlags     flags);
 
-
 /*
- * GClosure
+ * --- GClosure ---------------------------------------------------------------
  */
 typedef struct _GPerlClosure GPerlClosure;
 struct _GPerlClosure {
@@ -271,9 +259,8 @@ GClosure * gperl_closure_new_with_marshaller (SV              * callback,
                                               GClosureMarshal   marshaller);
 
 /*
- * GPerlCallback
+ * --- GPerlCallback ----------------------------------------------------------
  */
-
 typedef struct _GPerlCallback GPerlCallback;
 struct _GPerlCallback {
 	gint    n_params;
@@ -297,23 +284,25 @@ void            gperl_callback_invoke  (GPerlCallback * callback,
                                         ...);
 
 /*
- * exception handling
+ * --- exception handling -----------------------------------------------------
  */
-
 int  gperl_install_exception_handler (GClosure * closure);
 void gperl_remove_exception_handler  (guint tag);
 void gperl_run_exception_handlers    (void);
 
 /*
- * to be used by extensions...
+ * --- log handling for extensions --------------------------------------------
  */
 gint gperl_handle_logs_for (const gchar * log_domain);
 
 /*
- * gparamspec.h / GParamSpec.xs
+ * --- GParamSpec -------------------------------------------------------------
  */
+typedef GParamSpec GParamSpec_ornull;
 SV * newSVGParamSpec (GParamSpec * pspec);
 GParamSpec * SvGParamSpec (SV * sv);
+#define newSVGParamSpec_ornull(sv)	newSVGParamSpec(sv)
+
 SV * newSVGParamFlags (GParamFlags flags);
 GParamFlags SvGParamFlags (SV * sv);
 
@@ -322,7 +311,7 @@ const char * gperl_param_spec_package_from_type (GType gtype);
 GType gperl_param_spec_type_from_package (const char * package);
 
 /*
- * gkeyfile.h / GKeyFile.xs
+ * --- GKeyFile ---------------------------------------------------------------
  */
 #if GLIB_CHECK_VERSION (2, 6, 0)
 SV * newSVGKeyFile (GKeyFile * key_file);
@@ -332,18 +321,17 @@ GKeyFileFlags SvGKeyFileFlags (SV * sv);
 #endif /* GLIB_CHECK_VERSION (2, 6, 0) */
 
 /*
- * gbookmarkfile.h / GBookmarkFile.xs
+ * --- GBookmarkFile ----------------------------------------------------------
  */
 #if GLIB_CHECK_VERSION (2, 12, 0)
 SV * newSVGBookmarkFile (GBookmarkFile * bookmark_file);
 GBookmarkFile * SvGBookmarkFile (SV * sv);
 #endif /* GLIB_CHECK_VERSION (2, 12, 0) */
 
-#if GLIB_CHECK_VERSION (2, 6, 0)
-
 /*
- * GOption.xs
+ * --- GOption ----------------------------------------------------------------
  */
+#if GLIB_CHECK_VERSION (2, 6, 0)
 
 typedef GOptionContext GOptionContext_own;
 
@@ -366,7 +354,7 @@ GType gperl_option_group_get_type (void);
 #endif /* 2.6.0 */
 
 /*
- * gutils.h / GUtils.xs
+ * --- gutils.h / GUtils.xs ---------------------------------------------------
  */
 #if GLIB_CHECK_VERSION (2, 14, 0)
 GUserDirectory SvGUserDirectory (SV *sv);
@@ -374,8 +362,32 @@ SV * newSVGUserDirectory (GUserDirectory dir);
 #endif
 
 /*
- * miscellaneous
+ * -- GVariant ----------------------------------------------------------------
  */
+#if GLIB_CHECK_VERSION (2, 24, 0)
+
+typedef GVariant GVariant_noinc;
+SV * newSVGVariant (GVariant * variant);
+SV * newSVGVariant_noinc (GVariant * variant);
+GVariant * SvGVariant (SV * sv);
+
+typedef GVariantType GVariantType_own;
+SV * newSVGVariantType (const GVariantType * type);
+SV * newSVGVariantType_own (const GVariantType * type);
+const GVariantType * SvGVariantType (SV * sv);
+
+#endif /* 2.24.0 */
+
+/*
+ * --- miscellaneous ----------------------------------------------------------
+ */
+
+/* for use with the typemap */
+typedef char char_ornull;
+typedef char char_own;
+typedef char char_own_ornull;
+typedef char char_byte;
+typedef char char_byte_ornull;
 
 /* never use this function directly.  use GPERL_CALL_BOOT. */
 void _gperl_call_XS (pTHX_ void (*subaddr) (pTHX_ CV *), CV * cv, SV ** mark);
@@ -5,7 +5,7 @@ use warnings;
 use Carp;
 use IO::File;
 
-our $VERSION = '1.305';
+our $VERSION = '1.310';
 
 # type handlers should look like this:
 #    sub gen_foo_stuff {
@@ -9,7 +9,7 @@
 
 package Glib::GenPod;
 
-our $VERSION = '1.305';
+our $VERSION = '1.310';
 
 use strict;
 use warnings;
@@ -448,6 +448,8 @@ our %basic_types = (
 	gchar_length => 'string',
 	gchar_utf8_length => 'string',
 
+	char_byte => 'byte string',
+
 	FILE => 'file handle',
 	time_t => 'unix timestamp',
 
@@ -4,7 +4,7 @@
 
 package Glib::MakeHelper;
 
-our $VERSION = '1.305';
+our $VERSION = '1.310';
 
 =head1 NAME
 
@@ -422,7 +422,7 @@ build/blib_done_ :: build/blib_done_dynamic
 
 build/doc.pl :: Makefile @xs_files
 	\$(NOECHO) \$(ECHO) Parsing XS files...
-	\$(NOECHO) $^X -I \$(INST_LIB) -I \$(INST_ARCHLIB) -MGlib::ParseXSDoc \\
+	\$(NOECHO) \$(FULLPERLRUN) -I \$(INST_LIB) -I \$(INST_ARCHLIB) -MGlib::ParseXSDoc \\
 		-e "xsdocparse (qw(@xs_files))" > \$@
 
 # passing all of these files through the single podindex file, which is 
@@ -432,18 +432,18 @@ build/doc.pl :: Makefile @xs_files
 
 build/podindex :: \$(BLIB_DONE) Makefile build/doc.pl \$(POD_DEPENDS)
 	\$(NOECHO) \$(ECHO) Generating POD...
-	\$(NOECHO) $^X -I \$(INST_LIB) -I \$(INST_ARCHLIB) -MGlib::GenPod -M\$(NAME) \\
+	\$(NOECHO) \$(FULLPERLRUN) -I \$(INST_LIB) -I \$(INST_ARCHLIB) -MGlib::GenPod -M\$(NAME) \\
 		-e "$docgen_code"
 
 \$(INST_LIB)/\$(FULLEXT)/:
-	$^X -MExtUtils::Command -e mkpath \$@
+	\$(FULLPERLRUN) -MExtUtils::Command -e mkpath \$@
 
 \$(INST_LIB)/\$(FULLEXT)/index.pod :: \$(INST_LIB)/\$(FULLEXT)/ build/podindex
 	\$(NOECHO) \$(ECHO) Creating POD index...
-	\$(NOECHO) $^X -e "print qq(\\n=head1 NAME\\n\\n\$(NAME) - API Reference Pod Index\\n\\n=head1 PAGES\\n\\n=over\\n\\n)" \\
+	\$(NOECHO) \$(FULLPERLRUN) -e "print qq(\\n=head1 NAME\\n\\n\$(NAME) - API Reference Pod Index\\n\\n=head1 PAGES\\n\\n=over\\n\\n)" \\
 		> \$(INST_LIB)/\$(FULLEXT)/index.pod
-	\$(NOECHO) $^X -ne "print q(=item L<) . (split q( ))[1] . qq(>\\n\\n);" < build/podindex >> \$(INST_LIB)/\$(FULLEXT)/index.pod
-	\$(NOECHO) $^X -e "print qq(=back\\n\\n);" >> \$(INST_LIB)/\$(FULLEXT)/index.pod
+	\$(NOECHO) \$(FULLPERLRUN) -ne "print q(=item L<) . (split q( ))[1] . qq(>\\n\\n);" < build/podindex >> \$(INST_LIB)/\$(FULLEXT)/index.pod
+	\$(NOECHO) \$(FULLPERLRUN) -e "print qq(=back\\n\\n);" >> \$(INST_LIB)/\$(FULLEXT)/index.pod
 __EOM__
 }
 
@@ -20,7 +20,7 @@
 
 package Glib::Object::Subclass;
 
-our $VERSION = '1.305';
+our $VERSION = '1.310';
 
 use Glib;
 
@@ -13,7 +13,7 @@ our @EXPORT = qw(
 	xsdocparse
 );
 
-our $VERSION = '1.305';
+our $VERSION = '1.310';
 
 our $NOISY = $ENV{NOISYDOC};
 
@@ -27,7 +27,7 @@ use Exporter;
 require DynaLoader;
 our @ISA = qw(DynaLoader Exporter);
 
-our $VERSION = '1.305';
+our $VERSION = '1.310';
 
 use constant {
 	TRUE  => 1,
@@ -216,6 +216,155 @@ sub AUTOLOAD {
 	return $object_or_type->$method (@_);
 }
 
+package Glib::Variant;
+
+my %LEAF_HANDLERS = (
+  b => ['new_boolean', 'get_boolean'],
+  y => ['new_byte', 'get_byte'],
+  n => ['new_int16', 'get_int16'],
+  q => ['new_uint16', 'get_uint16'],
+  i => ['new_int32', 'get_int32'],
+  u => ['new_uint32', 'get_uint32'],
+  x => ['new_int64', 'get_int64'],
+  t => ['new_uint64', 'get_uint64'],
+  h => ['new_handle', 'get_handle'],
+  d => ['new_double', 'get_double'],
+  s => ['new_string', 'get_string'],
+  o => ['new_object_path', 'get_string'],
+  g => ['new_signature', 'get_string'],
+);
+
+# Documented in GVariant.xs.
+sub new {
+  my ($class, $format, @values) = @_;
+  if (!defined $format || $format eq '') {
+    return;
+  }
+
+  my ($ts, $format_rest) = Glib::VariantType::string_scan ($format);
+  my ($value, @values_rest) = @values;
+  my $t = Glib::VariantType->new ($ts);
+  my $v;
+
+  if ($t->is_basic) {
+    my $ctor = $LEAF_HANDLERS{$t->get_string}->[0];
+    $v = Glib::Variant->$ctor ($value);
+  }
+
+  elsif ($t->is_variant) {
+    $v = Glib::Variant->new_variant ($value);
+  }
+
+  elsif ($t->is_array) {
+    my $et = $t->element;
+    my @children;
+    if (eval { defined $#$value }) {
+      @children = map { Glib::Variant->new ($et->get_string, $_) } @$value;
+    } elsif ($et->is_dict_entry && eval { defined scalar %$value }) {
+      while (my ($ek, $ev) = each %$value) {
+        push @children, Glib::Variant->new ($et->get_string, [$ek, $ev]);
+      }
+    } else {
+      Carp::croak ('Expected an array ref');
+    }
+    $v = Glib::Variant->new_array ($et, \@children);
+  }
+
+  elsif ($t->is_maybe) {
+    my $et = $t->element;
+    my $child = defined $value ? Glib::Variant->new ($et->get_string, $value) : undef;
+    $v = Glib::Variant->new_maybe ($et, $child);
+  }
+
+  elsif ($t->is_tuple) {
+    my $n = $t->n_items;
+    if ($n && !eval { $#$value+1 == $n }) {
+      Carp::croak ("Expected an array ref with $n elements");
+    }
+    my @children;
+    for (my ($i, $et) = (0, $t->first); $et; $i++, $et = $et->next) {
+      push @children, Glib::Variant->new ($et->get_string, $value->[$i]);
+    }
+    $v = Glib::Variant->new_tuple (\@children);
+  }
+
+  elsif ($t->is_dict_entry) {
+    my $kt = $t->first;
+    my $vt = $kt->next;
+    my $kv = Glib::Variant->new ($kt->get_string, $value->[0]);
+    my $vv = Glib::Variant->new ($vt->get_string, $value->[1]);
+    $v = Glib::Variant->new_dict_entry ($kv, $vv);
+  }
+
+  else {
+    Carp::croak ("Cannot handle the part '$ts' in the format string '$format'");
+  }
+
+  return wantarray ? ($v, Glib::Variant->new ($format_rest, @values_rest)) : $v;
+}
+
+# Documented in GVariant.xs.
+sub get {
+  my ($v, $format) = @_;
+  if (!defined $format || $format eq '') {
+    return;
+  }
+
+  my ($ts, $format_rest) = Glib::VariantType::string_scan ($format);
+  if (defined $format_rest) {
+    Carp::carp ("Unhandled rest of format string detected: '$format_rest'");
+  }
+  my $t = Glib::VariantType->new ($ts);
+  my $value;
+
+  if ($t->is_basic) {
+    my $getter = $LEAF_HANDLERS{$t->get_string}->[1];
+    $value = $v->$getter;
+  }
+
+  elsif ($t->is_variant) {
+    $value = $v->get_variant;
+  }
+
+  elsif ($t->is_array) {
+    my $et = $t->element;
+    my @children;
+    foreach my $i (1 .. $v->n_children) {
+      push @children, $v->get_child_value ($i-1)->get ($et->get_string);
+    }
+    $value = \@children;
+  }
+
+  elsif ($t->is_maybe) {
+    my $et = $t->element;
+    my $wrapper = $v->get_maybe;
+    $value = defined $wrapper ? $wrapper->get ($et->get_string) : undef;
+  }
+
+  elsif ($t->is_tuple) {
+    my $n = $t->n_items;
+    my @children;
+    for (my ($i, $et) = (0, $t->first); $et; $i++, $et = $et->next) {
+      push @children, $v->get_child_value ($i)->get ($et->get_string);
+    }
+    $value = \@children;
+  }
+
+  elsif ($t->is_dict_entry) {
+    my $kt = $t->first;
+    my $vt = $kt->next;
+    my $kv = $v->get_child_value (0)->get ($kt->get_string);
+    my $vv = $v->get_child_value (1)->get ($vt->get_string);
+    $value = [$kv, $vv];
+  }
+
+  else {
+    Carp::croak ("Cannot handle the part '$ts' in the format string '$format'");
+  }
+
+  return $value;
+}
+
 package Glib;
 
 1;
@@ -210,16 +210,20 @@ if (Glib->CHECK_VERSION (2, 14, 0)) {
 
 
 {
+  my $skip_reason = undef;
   if (! $have_fork) {
-    print "ok 26 # skip, no fork: $fork_excuse\n";
-    print "ok 27 # skip\n";
-    print "ok 28 # skip\n";
-    print "ok 29 # skip\n";
-    print "ok 30 # skip\n";
-    goto SKIP_CHILD_TESTS;
+    $skip_reason = "no fork: $fork_excuse";
   }
   if (! Glib->CHECK_VERSION (2, 4, 0)) {
-    print "ok 26 # skip: need glib >= 2.4\n";
+    $skip_reason = 'need glib >= 2.4';
+  }
+  if ($^O eq 'freebsd' || $^O eq 'netbsd') {
+    if ($Config{ldflags} !~ m/-pthread\b/) {
+      $skip_reason = 'need a perl built with "-pthread" on freebsd/netbsd';
+    }
+  }
+  if (defined $skip_reason) {
+    print "ok 26 # skip: $skip_reason\n";
     print "ok 27 # skip\n";
     print "ok 28 # skip\n";
     print "ok 29 # skip\n";
@@ -0,0 +1,338 @@
+#!perl
+use strict;
+use warnings;
+use utf8;
+use Glib qw/TRUE FALSE/;
+use Test::More;
+
+use constant {
+  MIN_INT64 => "-9223372036854775807",
+  MAX_INT64 => "9223372036854775807",
+
+  MIN_UINT64 => "0",
+  MAX_UINT64 => "18446744073709551615"
+};
+
+if (Glib->CHECK_VERSION (2, 24, 0)) {
+  plan tests => 211;
+} else {
+  plan skip_all => 'Need libglib >= 2.24';
+}
+
+my @leafs = (
+  [ 'new_boolean', 'get_boolean', 'b', TRUE ],
+  [ 'new_byte', 'get_byte', 'y', 2**8-1 ],
+  [ 'new_int16', 'get_int16', 'n', 2**15-1 ],
+  [ 'new_uint16', 'get_uint16', 'q', 2**16-1 ],
+  [ 'new_int32', 'get_int32', 'i', 2**31-1 ],
+  [ 'new_uint32', 'get_uint32', 'u', 2**32-1 ],
+  [ 'new_int64', 'get_int64', 'x', MAX_INT64 ],
+  [ 'new_uint64', 'get_uint64', 't', MAX_UINT64 ],
+  [ 'new_handle', 'get_handle', 'h', 2**31-1 ],
+  [ 'new_double', 'get_double', 'd', 0.25 ],
+  [ 'new_string', 'get_string', 's', 'äöü⁂üöä' ],
+  [ 'new_object_path', 'get_string', 'o', '/a/b/c' ],
+  [ 'new_signature', 'get_string', 'g', 'ii' ],
+);
+
+{
+  foreach my $l (@leafs) {
+    my ($ctor, $getter, $type_string, $value) = @$l;
+    note ($ctor);
+    my $v = Glib::Variant->$ctor ($value);
+    isa_ok ($v, 'Glib::Variant');
+    isa_ok ($v->get_type, 'Glib::VariantType');
+    ok ($v->is_of_type ($v->get_type));
+    is ($v->get_type_string, $type_string);
+    ok (!$v->is_container);
+    is ($v->classify, $type_string);
+    is ($v->$getter, $value);
+  }
+
+  ok (Glib::Variant::is_object_path ('/a/b/c'));
+  ok (Glib::Variant::is_signature ('ii'));
+}
+
+note ('new_variant');
+{
+  {
+    my $child = Glib::Variant->new_byte (23);
+    my $wrapper = Glib::Variant->new_variant ($child);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'v');
+    is ($wrapper->classify, 'v');
+    {
+      my $wrapped_child = $wrapper->get_variant;
+      is ($wrapped_child->get_byte, 23);
+    }
+    undef $child;
+    {
+      my $wrapped_child = $wrapper->get_variant;
+      is ($wrapped_child->get_byte, 23);
+    }
+  }
+  {
+    my $child = Glib::Variant->new_byte (23);
+    my $wrapper = Glib::Variant->new_variant ($child);
+    undef $wrapper;
+    is ($child->get_byte, 23);
+  }
+}
+
+note ('new_bytestring');
+SKIP: {
+  skip 'new_bytestring', 6
+    unless Glib->CHECK_VERSION (2, 26, 0);
+
+  {
+    my $bs = "\x{a3}\x{ff}";
+    my $v = Glib::Variant->new_bytestring ($bs);
+    isa_ok ($v, 'Glib::Variant');
+    is ($v->get_type_string, 'ay');
+    is ($v->classify, 'a');
+    is ($v->get_bytestring, $bs);
+  }
+
+  {
+    my $bs = "\x{a3}\x{ff}";
+    utf8::upgrade ($bs);
+    my $v = Glib::Variant->new_bytestring ($bs);
+    is ($v->get_bytestring, $bs);
+  }
+
+  {
+    my $bs = "\x{a3}\x{ff}";
+    utf8::encode ($bs);
+    my $v = Glib::Variant->new_bytestring ($bs);
+    is ($v->get_bytestring, $bs);
+  }
+}
+
+note ('new_maybe');
+{
+  my $child_type = 'y';
+  my $child = Glib::Variant->new_byte (42);
+  {
+    my $wrapper = Glib::Variant->new_maybe ($child_type, undef);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'my');
+    is ($wrapper->classify, 'm');
+    ok (! defined $wrapper->get_maybe);
+    is ($wrapper->n_children, 0);
+  }
+  {
+    my $wrapper = Glib::Variant->new_maybe (undef, $child);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'my');
+    is ($wrapper->classify, 'm');
+    is ($wrapper->get_maybe->get_byte, $child->get_byte);
+    is ($wrapper->n_children, 1);
+    is ($wrapper->get_child_value (0)->get_byte, 42);
+  }
+  {
+    my $wrapper = Glib::Variant->new_maybe ($child_type, $child);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'my');
+    is ($wrapper->classify, 'm');
+    is ($wrapper->get_maybe->get_byte, $child->get_byte);
+    is ($wrapper->n_children, 1);
+    is ($wrapper->get_child_value (0)->get_byte, $child->get_byte);
+  }
+}
+
+note ('new_array');
+{
+  my $child_type = 'y';
+  my $children = [map { Glib::Variant->new_byte ($_) } (23, 42, 65)];
+  {
+    my $array = Glib::Variant->new_array ($child_type, []);
+    isa_ok ($array, 'Glib::Variant');
+    is ($array->get_type_string, 'ay');
+    is ($array->classify, 'a');
+    is ($array->n_children, 0);
+  }
+  {
+    my $array = Glib::Variant->new_array (undef, $children);
+    isa_ok ($array, 'Glib::Variant');
+    is ($array->get_type_string, 'ay');
+    is ($array->classify, 'a');
+    is ($array->n_children, 3);
+    is ($array->get_child_value (2)->get_byte, $children->[2]->get_byte);
+  }
+  {
+    my $array = Glib::Variant->new_array ($child_type, $children);
+    isa_ok ($array, 'Glib::Variant');
+    is ($array->get_type_string, 'ay');
+    is ($array->classify, 'a');
+    is ($array->n_children, 3);
+    is ($array->get_child_value (2)->get_byte, $children->[2]->get_byte);
+  }
+}
+
+note ('new_tuple');
+{
+  my $children = [Glib::Variant->new_byte (23),
+                  Glib::Variant->new_string ('forty-two'),
+                  Glib::Variant->new_double (0.25)];
+  {
+    my $tuple = Glib::Variant->new_tuple ([]);
+    isa_ok ($tuple, 'Glib::Variant');
+    is ($tuple->get_type_string, '()');
+    is ($tuple->classify, '(');
+    is ($tuple->n_children, 0);
+  }
+  {
+    my $tuple = Glib::Variant->new_tuple ($children);
+    isa_ok ($tuple, 'Glib::Variant');
+    is ($tuple->get_type_string, '(ysd)');
+    is ($tuple->classify, '(');
+    is ($tuple->n_children, 3);
+    is ($tuple->get_child_value (2)->get_double, $children->[2]->get_double);
+  }
+}
+
+note ('new_dict_entry');
+{
+  my $key = Glib::Variant->new_string ('forty-two');
+  my $value = Glib::Variant->new_byte (23);
+  {
+    my $entry = Glib::Variant->new_dict_entry ($key, $value);
+    isa_ok ($entry, 'Glib::Variant');
+    is ($entry->get_type_string, '{sy}');
+    is ($entry->classify, '{');
+    is ($entry->get_child_value (1)->get_byte, $value->get_byte);
+  }
+}
+
+note ('lookup_value');
+{
+  my $entries = [map { Glib::Variant->new_dict_entry (Glib::Variant->new_string ($_->[0]),
+                                                      Glib::Variant->new_byte ($_->[1])) }
+                     (['one' => 1], ['two' => 2], ['four' => 4], ['eight' => 8])];
+  my $array = Glib::Variant->new_array ('{sy}', $entries);
+  is ($array->lookup_value ('one', 'y')->get_byte, 1);
+  is ($array->lookup_value ('two', undef)->get_byte, 2);
+  ok (! defined $array->lookup_value ('fourr', undef));
+}
+
+note ('printing and parsing');
+{
+  {
+    my $a = Glib::Variant->new_byte (23);
+    my $text = $a->print (TRUE);
+    is ($text, 'byte 0x17');
+    is (Glib::Variant::parse (undef, $text)->get_byte, 23);
+    is (Glib::Variant::parse ('y', $text)->get_byte, 23);
+  }
+
+  {
+    my $text = 'byte 0x17';
+    eval { Glib::Variant::parse ('b', $text)->get_byte };
+    ok (Glib::Error::matches ($@, 'Glib::Variant::ParseError', 'type-error'));
+  }
+}
+
+note ('misc.');
+{
+  my $a = Glib::Variant->new_byte (23);
+  my $b = Glib::Variant->new_byte (42);
+
+  ok (defined $a->get_size);
+  ok (defined $a->hash);
+  ok ($a->equal ($a));
+  ok (! $a->equal ($b));
+  is ($a->get_normal_form->get_byte, $a->get_byte);
+  ok ($a->is_normal_form);
+  is ($a->byteswap->get_byte, $a->get_byte);
+
+  SKIP: {
+    skip 'compare', 2
+      unless Glib->CHECK_VERSION (2, 26, 0);
+    cmp_ok ($a->compare ($b), '<', 0);
+    cmp_ok ($b->compare ($a), '>', 1);
+  }
+}
+
+note ('convenience constructor and accessor');
+{
+  note (' leafs');
+  foreach my $l (@leafs) {
+    my ($ctor, $getter, $type_string, $value) = @$l;
+    my $v = Glib::Variant->new ($type_string, $value);
+    is ($v->get_type_string, $type_string);
+    is ($v->get ($type_string), $value);
+  }
+
+  note (' list context');
+  {
+    my ($v) = Glib::Variant->new ('i', 23);
+    is ($v->get ('i'), 23);
+
+    my ($v1, $v2, $v3) = Glib::Variant->new ('ids', 23, 0.25, 'äöü');
+    is ($v1->get ('i'), 23);
+    is ($v2->get ('d'), 0.25);
+    is ($v3->get ('s'), 'äöü');
+  }
+
+  note (' variant');
+  {
+    my $child = Glib::Variant->new_byte (23);
+    my $wrapper = Glib::Variant->new ('v', $child);
+    is ($wrapper->get_type_string, 'v');
+    {
+      my $wrapped_child = $wrapper->get ('v');
+      is ($wrapped_child->get_byte, 23);
+    }
+  }
+
+  note (' array');
+  {
+    my $v1 = Glib::Variant->new ('as', ['äöü', 'Perl', '💑']);
+    is_deeply ($v1->get ('as'), ['äöü', 'Perl', '💑']);
+
+    my $v2 = Glib::Variant->new ('aai', [[23, 42], [2, 3], [4, 2]]);
+    is_deeply ($v2->get ('aai'), [[23, 42], [2, 3], [4, 2]]);
+
+    is (Glib::Variant->new ('ai', [])->n_children, 0);
+    is (Glib::Variant->new ('ai', undef)->n_children, 0);
+  }
+
+  note (' maybe');
+  {
+    my $v1 = Glib::Variant->new ('mi', undef);
+    ok (! defined $v1->get ('mi'));
+
+    my $v2 = Glib::Variant->new ('mi', 23);
+    is ($v2->get ('mi'), 23);
+
+    my $v3 = Glib::Variant->new ('mai', undef);
+    ok (! defined $v3->get ('mai'));
+
+    my $v4 = Glib::Variant->new ('mai', [23, 42]);
+    is_deeply ($v4->get ('mai'), [23, 42]);
+  }
+
+  note (' tuple');
+  {
+    my $v1 = Glib::Variant->new ('()');
+    is ($v1->n_children, 0);
+
+    my $v2 = Glib::Variant->new ('(si)', ['äöü', 23]);
+    is_deeply ($v2->get ('(si)'), ['äöü', 23]);
+
+    my $v3 = Glib::Variant->new ('a(si)', [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+    is_deeply ($v3->get ('a(si)'), [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+  }
+
+  note (' dict entry');
+  {
+    my $v1 = Glib::Variant->new ('{si}', ['äöü', 23]);
+    is_deeply ($v1->get ('{si}'), ['äöü', 23]);
+
+    my $v2 = Glib::Variant->new ('a{si}', [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+    is_deeply ($v2->get ('a{si}'), [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+
+    my $v3 = Glib::Variant->new ('a{si}', {'äöü' => 23, 'Perl' => 42, '💑' => 2342});
+    is_deeply ($v2->get ('a{si}'), [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+  }
+}
@@ -37,48 +37,56 @@ glong		T_IV
 gulong		T_UV
 gunichar	T_GUNICHAR
 gchar		T_IV
-gchar *		T_GCHAR
-const gchar *	T_GCHAR
-gchar_own *	T_GCHAR_OWN
-gchar_length *	T_GCHAR_LEN
-const gchar_length *	T_GCHAR_LEN
-gchar_utf8_length *	T_GCHAR_UTF8_LEN
-const gchar_utf8_length *	T_GCHAR_UTF8_LEN
-gchar_ornull *	T_GCHAR_ORNULL
-gchar_own_ornull *	T_GCHAR_OWN_ORNULL
-const gchar_ornull *	T_GCHAR_ORNULL
-char_ornull *	T_CHAR_ORNULL
-char_own *	T_CHAR_OWN
-char_own_ornull *	T_CHAR_OWN_ORNULL
-const char_ornull *	T_CHAR_ORNULL
 guchar		T_UV
-guchar *	T_GUCHAR
-const guchar *	T_GUCHAR
 gfloat		T_FLOAT
 gdouble		T_DOUBLE
 gsize		T_UV
 gssize		T_IV
 gpointer	T_PTR
 
-GObject*	T_GPERL_GENERIC_WRAPPER
-GObject_ornull*	T_GPERL_GENERIC_WRAPPER
-GObject_noinc*	T_GPERL_GENERIC_WRAPPER
+gchar *				T_GCHAR
+const gchar *			T_GCHAR
+gchar_own *			T_GCHAR_OWN
+gchar_length *			T_GCHAR_LEN
+const gchar_length *		T_GCHAR_LEN
+gchar_utf8_length *		T_GCHAR_UTF8_LEN
+const gchar_utf8_length *	T_GCHAR_UTF8_LEN
+gchar_ornull *			T_GCHAR_ORNULL
+gchar_own_ornull *		T_GCHAR_OWN_ORNULL
+const gchar_ornull *		T_GCHAR_ORNULL
+
+char_ornull *			T_CHAR_ORNULL
+char_own *			T_CHAR_OWN
+char_own_ornull *		T_CHAR_OWN_ORNULL
+const char_ornull *		T_CHAR_ORNULL
+
+char_byte *			T_CHAR_BYTE
+const char_byte *		T_CHAR_BYTE
+char_byte_ornull *		T_CHAR_BYTE_ORNULL
+const char_byte_ornull *	T_CHAR_BYTE_ORNULL
 
-GParamSpec*	T_GPERL_GENERIC_WRAPPER
+guchar *			T_GUCHAR
+const guchar *			T_GUCHAR
+
+GObject*		T_GPERL_GENERIC_WRAPPER
+GObject_ornull*		T_GPERL_GENERIC_WRAPPER
+GObject_noinc*		T_GPERL_GENERIC_WRAPPER
+
+GParamSpec*		T_GPERL_GENERIC_WRAPPER
 GParamSpec_ornull*	T_GPERL_GENERIC_WRAPPER
-GParamFlags	T_GPERL_GENERIC_WRAPPER
+GParamFlags		T_GPERL_GENERIC_WRAPPER
 
-GSignalFlags	T_GPERL_GENERIC_WRAPPER
+GSignalFlags		T_GPERL_GENERIC_WRAPPER
 
-GKeyFile*	T_GPERL_GENERIC_WRAPPER
-GKeyFileFlags	T_GPERL_GENERIC_WRAPPER
+GKeyFile*		T_GPERL_GENERIC_WRAPPER
+GKeyFileFlags		T_GPERL_GENERIC_WRAPPER
 
-GBookmarkFile*	T_GPERL_GENERIC_WRAPPER
+GBookmarkFile*		T_GPERL_GENERIC_WRAPPER
 
-GIOCondition	T_G_TYPE_IO_CONDITION
+GIOCondition		T_G_TYPE_IO_CONDITION
 
-GMainContext*	T_G_MAIN_CONTEXT
-GMainLoop*	T_G_MAIN_LOOP
+GMainContext*		T_G_MAIN_CONTEXT
+GMainLoop*		T_G_MAIN_LOOP
 
 GPerlFilename		T_GPERL_FILENAME
 GPerlFilename_const	T_GPERL_FILENAME
@@ -90,9 +98,17 @@ GOptionContext_own *	T_GPERL_GENERIC_WRAPPER
 GOptionGroup *		T_GPERL_GENERIC_WRAPPER
 GOptionGroup_own *	T_GPERL_GENERIC_WRAPPER
 
-GUserDirectory	T_GPERL_GENERIC_WRAPPER
+GUserDirectory		T_GPERL_GENERIC_WRAPPER
+
+GVariant *		T_GPERL_GENERIC_WRAPPER
+const GVariant *	T_GPERL_GENERIC_WRAPPER
+GVariant_noinc *	T_GPERL_GENERIC_WRAPPER
 
-#####
+GVariantType *		T_GPERL_GENERIC_WRAPPER
+const GVariantType *	T_GPERL_GENERIC_WRAPPER
+GVariantType_own *	T_GPERL_GENERIC_WRAPPER
+
+###############################################################################
 INPUT
 
 # a general-purpose typemap... strips any trailing star and/or leading "const",
@@ -146,6 +162,16 @@ T_CHAR_ORNULL
 		$var = NULL;
 	}
 
+T_CHAR_BYTE
+	$var = ($type)SvPVbyte_nolen ($arg);
+
+T_CHAR_BYTE_ORNULL
+	if (gperl_sv_is_defined ($arg)) {
+		$var = ($type)SvPVbyte_nolen ($arg);
+	} else {
+		$var = NULL;
+	}
+
 T_G_TYPE_IO_CONDITION
 	$var = gperl_convert_flags (G_TYPE_IO_CONDITION, $arg);
 
@@ -167,7 +193,7 @@ T_GPERL_FILENAME_ORNULL
 		 ? gperl_filename_from_sv ($arg)
 		 : NULL)
 
-######
+###############################################################################
 OUTPUT
 
 T_GPERL_GENERIC_WRAPPER