/*
* 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);
#elif GLIB_CHECK_VERSION (2, 26, 0)
if (g_variant_is_floating (variant)) {
g_variant_ref_sink (variant);
}
#else
/* In this case, we have no way of finding out whether the
* variant has a floating ref, so we just always ref_sink even
* if this might cause a leak in some cases. */
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);
char g_variant_classify (GVariant *value);
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