One of the problems we have with applying GObject-Introspection to
telepathy-glib is that we have no way to introspect the a{sv}
GHashTables exposed in tp-glib's API if the variant value is more
complex than a simple type, since the GValue used to store the variant
does not contain the full type.

i.e. introspection works for { 'one': <1> }, but not { 'one': <(1,
'One')> }

dbus-glib however stores complete type information for registered
container types, which we can look up to build a GVariant of the complex
type.

I've written a proof of concept of this: g_value_to_g_variant (attached)

I figure this sort of thing can be provided as a utility function that
we can then use in tp-glib to make binding-friendly API. It also may
well ease the transition from dbus-glib to gdbus for some people.
Possibly it should be provided by dbus-glib? Thoughts?

-- 
Danielle Madeley
Software Developer, Collabora Ltd.                  Melbourne, Australia

www.collabora.co.uk
/*
 * Proof of concept GValue-to-GVariant converter
 *
 * Compile with: gcc -ggdb -O0 -o gvalue-to-gvariant \
 *  `pkg-config --cflags --libs dbus-glib-1 gio-2.0 telepathy-glib` \
 *  gvalue-to-gvariant.c 
 *
 * Authors: Danielle Madeley <[email protected]>
 */

#include <gio/gio.h>
#include <dbus/dbus-glib.h>

static GVariant *g_value_to_g_variant (const GValue *value);

static void
_collection_iterator (const GValue *value,
    gpointer user_data)
{
  GPtrArray *children = user_data;

  g_ptr_array_add (children, g_value_to_g_variant (value));
}

static void
_map_iterator (const GValue *kvalue,
    const GValue *vvalue,
    gpointer user_data)
{
  GPtrArray *children = user_data;

  g_ptr_array_add (children,
      g_variant_new_dict_entry (
        g_value_to_g_variant (kvalue),
        g_value_to_g_variant (vvalue)));
}

static GVariant *
g_value_to_g_variant (const GValue *value)
{
  GType type;

  type = G_VALUE_TYPE (value);

  if (dbus_g_type_is_collection (type))
    {
      GVariant *variant;
      GPtrArray *children;

      children = g_ptr_array_new ();
      dbus_g_type_collection_value_iterate (value, _collection_iterator,
          children);

      variant = g_variant_new_array (NULL, (GVariant **) children->pdata,
          children->len);
      g_ptr_array_free (children, TRUE);

      return variant;
    }
  else if (dbus_g_type_is_map (type))
    {
      GVariant *variant;
      GPtrArray *children;

      children = g_ptr_array_new ();
      dbus_g_type_map_value_iterate (value, _map_iterator, children);

      variant = g_variant_new_array (NULL, (GVariant **) children->pdata,
          children->len);
      g_ptr_array_free (children, TRUE);

      return variant;
    }
  else if (dbus_g_type_is_struct (type))
    {
      GVariant *variant, **children;
      guint size, i;

      size = dbus_g_type_get_struct_size (type);
      children = g_new0 (GVariant *, size);

      for (i = 0; i < size; i++)
        {
          GValue cvalue = { 0, };

          g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, i));
          dbus_g_type_struct_get_member (value, i, &cvalue);

          children[i] = g_value_to_g_variant (&cvalue);
          g_value_unset (&cvalue);
        }

      variant = g_variant_new_tuple (children, size);
      g_free (children);

      return variant;
    }
  else if (type == G_TYPE_BOOLEAN)
    return g_variant_new_boolean (g_value_get_boolean (value));
  else if (type == G_TYPE_UCHAR)
    return g_variant_new_byte (g_value_get_uchar (value));
  else if (type == G_TYPE_INT)
    return g_variant_new_int32 (g_value_get_int (value));
  else if (type == G_TYPE_UINT)
    return g_variant_new_uint32 (g_value_get_uint (value));
  else if (type == G_TYPE_INT64)
    return g_variant_new_int64 (g_value_get_int64 (value));
  else if (type == G_TYPE_UINT64)
    return g_variant_new_uint64 (g_value_get_uint64 (value));
  else if (type == G_TYPE_DOUBLE)
    return g_variant_new_double (g_value_get_double (value));
  else if (type == G_TYPE_STRING)
    return g_variant_new_string (g_value_get_string (value));
  else if (type == G_TYPE_STRV)
    return g_variant_new_strv (g_value_get_boxed (value), -1);
  else if (type == DBUS_TYPE_G_OBJECT_PATH)
    return g_variant_new_object_path (g_value_get_boxed (value));
  else if (type == G_TYPE_VALUE)
    return g_variant_new_variant (
        g_value_to_g_variant (g_value_get_boxed (value)));
  else
    {
      g_error ("Unknown type: %s", g_type_name (type));
    }
}

/* include tp-glib for its registered GTypes and utility functions, so we
 * can test this thing works */
#include <telepathy-glib/telepathy-glib.h>

int
main (int argc,
    char **argv)
{
  char *str;
  GValue value = { 0, };
  GVariant *variant;

  g_type_init ();

  g_value_init (&value, TP_STRUCT_TYPE_SIMPLE_PRESENCE);
  g_value_take_boxed (&value,
      tp_value_array_build (3,
        G_TYPE_UINT, 1,
        G_TYPE_STRING, "available",
        G_TYPE_STRING, "message",
        G_TYPE_INVALID));

  variant = g_value_to_g_variant (&value);
  g_value_unset (&value);

  str = g_variant_print (variant, FALSE);
  g_print ("variant = %s\n", str);

  g_free (str);
  g_variant_unref (variant);

  g_value_init (&value, TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP);
  g_value_take_boxed (&value,
      tp_asv_new (
        "key",
        G_TYPE_STRING,
        "value",

        "one",
        G_TYPE_INT,
        1,

        NULL));

  variant = g_value_to_g_variant (&value);
  g_value_unset (&value);

  str = g_variant_print (variant, FALSE);
  g_print ("variant = %s\n", str);

  g_free (str);
  g_variant_unref (variant);

    {
      GPtrArray *array = g_ptr_array_new ();

      g_ptr_array_add (array, tp_value_array_build (2,
            G_TYPE_UINT, 0,
            G_TYPE_STRING, "Alias 0",
            G_TYPE_INVALID));
      g_ptr_array_add (array, tp_value_array_build (2,
            G_TYPE_UINT, 1,
            G_TYPE_STRING, "Alias 1",
            G_TYPE_INVALID));
      g_ptr_array_add (array, tp_value_array_build (2,
            G_TYPE_UINT, 1337,
            G_TYPE_STRING, "Alias the Jester",
            G_TYPE_INVALID));

      g_value_init (&value, TP_ARRAY_TYPE_ALIAS_PAIR_LIST);
      g_value_take_boxed (&value, array);

      variant = g_value_to_g_variant (&value);
      g_value_unset (&value);

      str = g_variant_print (variant, FALSE);
      g_print ("variant = %s\n", str);

      g_free (str);
      g_variant_unref (variant);
    }

    {
      GPtrArray *array = g_ptr_array_new ();
      const char *as[] = { "as1", "as2", "as3", NULL };

      g_ptr_array_add (array, tp_asv_new (
            "one", G_TYPE_UINT, 1,
            "two", G_TYPE_UINT, 2,
            NULL));
      g_ptr_array_add (array, tp_asv_new (
            "three", G_TYPE_UINT, 3,
            "four", G_TYPE_UINT, 4,
            NULL));

      g_value_init (&value, TP_STRUCT_TYPE_HANDLER_CAPABILITIES);
      g_value_take_boxed (&value, tp_value_array_build (3,
            G_TYPE_STRING, "Well.Known.Name",
            TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, array,
            G_TYPE_STRV, as,
            G_TYPE_INVALID));

      g_ptr_array_free (array, TRUE);

      variant = g_value_to_g_variant (&value);
      g_value_unset (&value);

      str = g_variant_print (variant, FALSE);
      g_print ("variant = %s\n", str);

      g_free (str);
      g_variant_unref (variant);
    }
}
_______________________________________________
telepathy mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/telepathy

Reply via email to