]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
2006-02-13 Robert McQueen <robot101@debian.org>
authorRobert McQueen <robot101@debian.org>
Mon, 13 Feb 2006 22:30:11 +0000 (22:30 +0000)
committerRobert McQueen <robot101@debian.org>
Mon, 13 Feb 2006 22:30:11 +0000 (22:30 +0000)
* glib/dbus-binding-tool-glib.c, glib/dbus-gmain.c,
glib/dbus-gsignature.c, glib/dbus-gtype-specialized.c,
glib/dbus-gtype-specialized.h, glib/dbus-gvalue-utils.c,
glib/dbus-gvalue-utils.h, glib/dbus-gvalue.c:
Patch from Rob Taylor <rob.taylor@collabora.co.uk> to add a big
missing piece of the glib bindings jigsaw puzzle. This modifies
the existing specialised types to have N type parameters (rather
than the current 1 or 2 for arrays and dictionaries respectively).
You can then use this to get a glib type to represent any arbitrary
D-Bus struct type using dbus_g_type_get_struct. The only
implementation of these types is with GValueArrays as before,
but it's now possible to store these in arrays, emit them in
signals, etc.

ChangeLog
glib/dbus-binding-tool-glib.c
glib/dbus-gmain.c
glib/dbus-gsignature.c
glib/dbus-gtype-specialized.c
glib/dbus-gtype-specialized.h
glib/dbus-gvalue-utils.c
glib/dbus-gvalue-utils.h
glib/dbus-gvalue.c

index 262b8c02f5611c94311bb34e995d9d41a5349522..f60c515e370c1c532988a111d9b687b509fd74de 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2006-02-13  Robert McQueen  <robot101@debian.org>
+
+       * glib/dbus-binding-tool-glib.c, glib/dbus-gmain.c,
+       glib/dbus-gsignature.c, glib/dbus-gtype-specialized.c,
+       glib/dbus-gtype-specialized.h, glib/dbus-gvalue-utils.c,
+       glib/dbus-gvalue-utils.h, glib/dbus-gvalue.c:
+       Patch from Rob Taylor <rob.taylor@collabora.co.uk> to add a big
+       missing piece of the glib bindings jigsaw puzzle. This modifies
+       the existing specialised types to have N type parameters (rather
+       than the current 1 or 2 for arrays and dictionaries respectively).
+       You can then use this to get a glib type to represent any arbitrary
+       D-Bus struct type using dbus_g_type_get_struct. The only
+       implementation of these types is with GValueArrays as before,
+       but it's now possible to store these in arrays, emit them in
+       signals, etc.
+
 2006-02-10  John (J5) Palmieri  <johnp@redhat.com>
 
        * dbus/dbus-signature.c (dbus_signature_iter_recurse): Correctly
index 21e0274493e74ad4ee858772448aa3512b489c9d..1386e3f157484e687ed3b3533aee19f2701e1633 100644 (file)
@@ -98,6 +98,10 @@ static const char *
 dbus_g_type_get_c_name (GType gtype)
 {
   GType subtype;
+  if (dbus_g_type_is_struct (gtype))
+    {
+      return "GValueArray";
+    }
   if (dbus_g_type_is_collection (gtype))
     {
       subtype = dbus_g_type_get_collection_specialization(gtype);
@@ -1050,6 +1054,28 @@ dbus_g_type_get_lookup_function (GType gtype)
       g_free (value_lookup);
       return type_lookup;
     }
+  else if (dbus_g_type_is_struct (gtype))
+    {
+      GType value_gtype;
+      GString *string;
+      char *value_lookup = NULL;
+      guint size, i;
+
+      string = g_string_new ("dbus_g_type_get_struct (\"GValueArray\"");
+
+      size = dbus_g_type_get_struct_size (gtype);
+      for (i=0; i < size; i++)
+        {
+          value_gtype = dbus_g_type_get_struct_member_type(gtype, i);
+          value_lookup = dbus_g_type_get_lookup_function (value_gtype);
+          g_assert (value_lookup);
+          g_string_append_printf (string, ", %s", value_lookup);
+          g_free (value_lookup);
+        }
+      g_string_append (string, ", G_TYPE_INVALID)");
+      return g_string_free (string, FALSE);
+    }
+
   MAP_KNOWN(G_TYPE_VALUE);
   MAP_KNOWN(G_TYPE_STRV);
   MAP_KNOWN(G_TYPE_VALUE_ARRAY);
index 993bcf37fcb6e7138aa4017c9bd8c3514386d807..267f0bfa880c25ae078abdc7852f5e03be09acc1 100644 (file)
@@ -754,14 +754,14 @@ _dbus_gmain_test (const char *test_data_dir)
 
   rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
   g_assert (rectype != G_TYPE_INVALID);
-  g_assert (!strcmp (g_type_name (rectype), "GArray+guint"));
+  g_assert (!strcmp (g_type_name (rectype), "GArray_guint_"));
 
   type = _dbus_gtype_from_signature ("au", TRUE);
   g_assert (type == rectype);
 
   rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
   g_assert (rectype != G_TYPE_INVALID);
-  g_assert (!strcmp (g_type_name (rectype), "GHashTable+gchararray+gchararray"));
+  g_assert (!strcmp (g_type_name (rectype), "GHashTable_gchararray+gchararray_"));
 
   type = _dbus_gtype_from_signature ("a{ss}", TRUE);
   g_assert (type == rectype);
index a0370b0ef7a439c1f854bdc53f3a140c43c175fa..5df959dbe940b0dc3b60b233d2ce720add74f29b 100644 (file)
@@ -117,6 +117,25 @@ signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client)
   return G_TYPE_INVALID; 
 }
 
+static GType
+signature_iter_to_g_type_struct (DBusSignatureIter *iter, gboolean is_client)
+{
+  GArray *types;
+  GType ret;
+  types = g_array_new (FALSE, FALSE, sizeof (GType));
+  do
+    {
+      GType curtype;
+      curtype = _dbus_gtype_from_signature_iter (iter, is_client);
+      g_array_append_val (types, curtype);
+    }
+  while (dbus_signature_iter_next (iter));
+
+  ret = dbus_g_type_get_structv ("GValueArray", types->len, (GType*) types->data);
+  g_array_free (types, TRUE);
+  return ret;
+}
+
 GType
 _dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client)
 {
@@ -136,8 +155,6 @@ _dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client)
 
       if (current_type == DBUS_TYPE_VARIANT)
        return G_TYPE_VALUE;
-      if (current_type == DBUS_TYPE_STRUCT)
-       return G_TYPE_VALUE_ARRAY;
       
       dbus_signature_iter_recurse (iter, &subiter);
 
@@ -149,6 +166,10 @@ _dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client)
          else 
            return signature_iter_to_g_type_array (&subiter, is_client);
        }
+      else if (current_type == DBUS_TYPE_STRUCT)
+        {
+          return signature_iter_to_g_type_struct (&subiter, is_client);
+        }
       else
        {
          g_assert_not_reached ();
index ad93a8c53c527322731479bfb923c517816c06ef..338e49d01e7181f68911061c4177179501cb8bbc 100644 (file)
@@ -28,7 +28,8 @@
 
 typedef enum {
   DBUS_G_SPECTYPE_COLLECTION,
-  DBUS_G_SPECTYPE_MAP
+  DBUS_G_SPECTYPE_MAP,
+  DBUS_G_SPECTYPE_STRUCT
 } DBusGTypeSpecializedType;
 
 typedef struct {
@@ -37,7 +38,8 @@ typedef struct {
 } DBusGTypeSpecializedContainer;
 
 typedef struct {
-  GType types[6];
+  guint num_types;
+  GType *types;
   const DBusGTypeSpecializedContainer     *klass;
 } DBusGTypeSpecializedData;
 
@@ -71,6 +73,7 @@ lookup_specialization_data (GType type)
   return g_type_get_qdata (type, specialized_type_data_quark ());
 }
 
+
 /* Copied from gboxed.c */
 static void
 proxy_value_init (GValue *value)
@@ -151,7 +154,9 @@ proxy_collect_value (GValue      *value,
          value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
        }
       else
-       value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
+        {
+         value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
+        }
     }
 
   return NULL;
@@ -188,18 +193,21 @@ proxy_lcopy_value (const GValue *value,
 }
 
 static char *
-build_specialization_name (const char *prefix, GType first_type, GType second_type)
+build_specialization_name (const char *prefix, guint num_types, GType *types)
 {
   GString *fullname;
+  guint i;
 
   fullname = g_string_new (prefix);
-  g_string_append_c (fullname, '+');
-  g_string_append (fullname, g_type_name (first_type));
-  if (second_type != G_TYPE_INVALID)
+
+  g_string_append_c (fullname, '_');
+  for (i=0; i < num_types; i++)
     {
-      g_string_append_c (fullname, '+');
-      g_string_append (fullname, g_type_name (second_type));
+      if (i!=0)
+        g_string_append_c (fullname, '+');
+      g_string_append (fullname, g_type_name (types[i]));
     }
+  g_string_append_c (fullname, '_');
   return g_string_free (fullname, FALSE);
 }
 
@@ -235,6 +243,16 @@ dbus_g_type_register_map (const char                            *name,
   register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
 }
 
+void
+dbus_g_type_register_struct (const char                             *name,
+                            const DBusGTypeSpecializedStructVtable *vtable,
+                            guint                                   flags)
+{
+  g_return_if_fail (specialized_types_is_initialized ());
+  register_container (name, DBUS_G_SPECTYPE_STRUCT, (const DBusGTypeSpecializedVtable*) vtable);
+}
+
+
 const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type)
 {
   DBusGTypeSpecializedData *data;
@@ -257,12 +275,22 @@ const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (
   return (DBusGTypeSpecializedCollectionVtable *)(data->klass->vtable);
 }
 
+const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type)
+{
+  DBusGTypeSpecializedData *data;
+  g_return_val_if_fail (dbus_g_type_is_struct (struct_type), NULL);
+
+  data = lookup_specialization_data (struct_type);
+  g_assert (data != NULL);
+
+  return (DBusGTypeSpecializedStructVtable *)(data->klass->vtable);
+}
 
 static GType
 register_specialized_instance (const DBusGTypeSpecializedContainer   *klass,
                               char                                  *name,
-                              GType                                  first_type,
-                              GType                                  second_type)
+                              guint                                  num_types,
+                              GType                                 *types)
 {
   GType ret;
   
@@ -297,8 +325,8 @@ register_specialized_instance (const DBusGTypeSpecializedContainer   *klass,
     {
       DBusGTypeSpecializedData *data;
       data = g_new0 (DBusGTypeSpecializedData, 1);
-      data->types[0] = first_type;
-      data->types[1] = second_type;
+      data->num_types = num_types;
+      data->types = g_memdup (types, sizeof (GType) * num_types);
       data->klass = klass;
       g_type_set_qdata (ret, specialized_type_data_quark (), data);
     }
@@ -308,8 +336,8 @@ register_specialized_instance (const DBusGTypeSpecializedContainer   *klass,
 
 static GType
 lookup_or_register_specialized (const char  *container,
-                               GType       first_type,
-                               GType       second_type)
+                               guint        num_types,
+                               GType       *types)
 {
   GType ret;
   char *name;
@@ -320,14 +348,14 @@ lookup_or_register_specialized (const char  *container,
   klass = g_hash_table_lookup (specialized_containers, container);
   g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
 
-  name = build_specialization_name (container, first_type, second_type);
+  name = build_specialization_name (container, num_types, types);
   ret = g_type_from_name (name);
   if (ret == G_TYPE_INVALID)
     {
       /* Take ownership of name */
       ret = register_specialized_instance (klass, name,
-                                          first_type,
-                                          second_type);
+                                          num_types,
+                                          types);
     }
   else
     g_free (name);
@@ -338,7 +366,7 @@ GType
 dbus_g_type_get_collection (const char *container,
                            GType       specialization)
 {
-  return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID);
+  return lookup_or_register_specialized (container, 1, &specialization);
 }
 
 GType
@@ -346,9 +374,42 @@ dbus_g_type_get_map (const char   *container,
                     GType         key_specialization,
                     GType         value_specialization)
 {
-  return lookup_or_register_specialized (container, key_specialization, value_specialization);
+  GType types[2] = {key_specialization, value_specialization};
+  return lookup_or_register_specialized (container, 2, types);
+}
+
+GType
+dbus_g_type_get_structv (const char   *container,
+                        guint         num_items,
+                        GType        *types)
+{
+  return lookup_or_register_specialized (container, num_items, types);
 }
 
+GType
+dbus_g_type_get_struct (const char *container,
+                        GType first_type,
+                        ...)
+{
+  GArray *types;
+  GType curtype;
+  va_list args;
+  va_start (args, first_type);
+
+  types = g_array_new (FALSE, FALSE, sizeof (GType));
+  curtype = first_type;
+  while (curtype != G_TYPE_INVALID)
+    {
+      g_array_append_val (types, curtype);
+      curtype = va_arg (args, GType);
+    }
+  va_end (args);
+  return lookup_or_register_specialized (container, types->len, (GType*)types->data);
+
+}
+
+
+
 gboolean
 dbus_g_type_is_collection (GType gtype)
 {
@@ -369,13 +430,27 @@ dbus_g_type_is_map (GType gtype)
   return data->klass->type == DBUS_G_SPECTYPE_MAP;
 }
 
+gboolean
+dbus_g_type_is_struct (GType gtype)
+{
+  DBusGTypeSpecializedData *data;
+  data = lookup_specialization_data (gtype);
+  if (data == NULL)
+    return FALSE;
+  return data->klass->type == DBUS_G_SPECTYPE_STRUCT;
+}
+
+
 static GType
 get_specialization_index (GType gtype, guint i)
 {
   DBusGTypeSpecializedData *data;
 
   data = lookup_specialization_data (gtype);
-  return data->types[i];
+  if (i < data->num_types)
+    return data->types[i];
+  else
+    return G_TYPE_INVALID;
 }
 
 GType
@@ -399,6 +474,25 @@ dbus_g_type_get_map_value_specialization (GType gtype)
   return get_specialization_index (gtype, 1);
 }
 
+GType
+dbus_g_type_get_struct_member_type (GType gtype, guint index)
+{
+  g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID);
+  return get_specialization_index (gtype, index);
+}
+
+guint
+dbus_g_type_get_struct_size (GType gtype)
+{
+  DBusGTypeSpecializedData *data;
+  g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID);
+
+  data = lookup_specialization_data (gtype);
+  return data->num_types;
+}
+
+
+
 gpointer
 dbus_g_type_specialized_construct (GType type)
 {
@@ -469,7 +563,8 @@ dbus_g_type_specialized_init_append (GValue *value, DBusGTypeSpecializedAppendCo
   gtype = G_VALUE_TYPE (value);
   specdata = lookup_specialization_data (gtype);
   g_return_if_fail (specdata != NULL);
-  
+  g_return_if_fail (specdata->num_types != 0);
+
   realctx->val = value;
   realctx->specialization_type = specdata->types[0];
   realctx->specdata = specdata;
@@ -519,3 +614,160 @@ dbus_g_type_map_value_iterate (const GValue                           *value,
                                                                     g_value_get_boxed (value),
                                                                     iterator, user_data);
 }
+
+gboolean
+dbus_g_type_struct_get_member (const GValue *value,
+                              guint         index,
+                              GValue       *dest)
+{
+  DBusGTypeSpecializedData *data;
+  GType gtype;
+
+  g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
+  g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
+
+  gtype = G_VALUE_TYPE (value);
+  data = lookup_specialization_data (gtype);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->get_member(gtype,
+                                                                                          g_value_get_boxed (value),
+                                                                                          index, dest);
+}
+
+gboolean
+dbus_g_type_struct_set_member (GValue       *value,
+                              guint         index,
+                              const GValue *src)
+{
+  DBusGTypeSpecializedData *data;
+  GType gtype;
+
+  g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
+  g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
+
+  gtype = G_VALUE_TYPE (value);
+  data = lookup_specialization_data (gtype);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->set_member(gtype,
+                                                                                          g_value_get_boxed (value),
+                                                                                          index, src);
+}
+
+/**
+ * dbus_g_type_struct_get:
+ * @value: a GValue containing a DBusGTypeStruct type
+ * @member: struct member to get
+ * @...: location in which to return the value of this member,
+ *       followed optionally by more member/return locations pairs, followed by
+ *       by G_MAXUINT
+ *
+ * Collects the selected values of this struct into the return locations
+ * provided.
+ *
+ * Returns: FALSE on failure
+ */
+
+gboolean
+dbus_g_type_struct_get                   (const GValue *value,
+                                          guint first_member,
+                                          ...)
+{
+  va_list var_args;
+  GType type;
+  guint size,i;
+  gchar *error;
+  GValue val = {0,};
+
+  g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE);
+
+  va_start (var_args, first_member);
+  size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
+  i = first_member;
+  while (i != G_MAXUINT)
+    {
+      if (i >= size)
+        goto error;
+
+      type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i);
+
+      g_value_init (&val, type);
+      dbus_g_type_struct_get_member (value, i, &val);
+
+      G_VALUE_LCOPY (&val, var_args, 0, &error);
+      if (error)
+        {
+          g_warning ("%s, %s", G_STRFUNC, error);
+          g_free (error);
+          g_value_unset (&val);
+          goto error;
+        }
+      g_value_unset (&val);
+      i = va_arg (var_args, guint);
+    }
+  va_end (var_args);
+  return TRUE;
+error:
+  va_end (var_args);
+  return FALSE;
+}
+
+/**
+ * dbus_g_type_struct_set:
+ * @value: a GValue containing a DBusGTypeStruct type
+ * @member: struct member to set
+ * @...: value for the first member, followed optionally by
+ *       more member/value pairs, followed by G_MAXUINT
+ *
+ * Sets the selected members of the struct in @value.
+ *
+ * Returns: FALSE on failure
+ */
+
+gboolean
+dbus_g_type_struct_set                   (GValue *value,
+                                          guint first_member,
+                                          ...)
+{
+  va_list var_args;
+  GType type;
+  guint size,i;
+  gchar *error;
+  GValue val = {0,};
+
+  g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE);
+
+  va_start (var_args, first_member);
+  size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
+  i = first_member;
+  while (i != G_MAXUINT)
+    {
+      if (i >= size)
+        goto error;
+
+      type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i);
+
+      g_value_init (&val, type);
+
+      G_VALUE_COLLECT (&val, var_args, 0, &error);
+      if (error)
+        {
+          g_warning ("%s, %s", G_STRFUNC, error);
+          g_free (error);
+          g_value_unset (&val);
+          goto error;
+        }
+
+      dbus_g_type_struct_set_member (value, i, &val);
+
+      g_value_unset (&val);
+      i = va_arg (var_args, guint);
+    }
+  va_end (var_args);
+  return TRUE;
+error:
+  va_end (var_args);
+  return FALSE;
+}
+
index 505c95bc724055822267aba027f670520e6d7d3f..1d26009244c63f508d6d37111226aca1b3fbb183 100644 (file)
@@ -34,11 +34,21 @@ GType          dbus_g_type_get_collection                   (const char *contain
 GType          dbus_g_type_get_map                          (const char *container,
                                                             GType       key_specialization,
                                                             GType       value_specialization);
+GType          dbus_g_type_get_structv                      (const char *container,
+                                                            guint       num_items,
+                                                            GType      *types);
+GType          dbus_g_type_get_struct                       (const char *container,
+                                                             GType       first_type,
+                                                             ...);
 gboolean       dbus_g_type_is_collection                    (GType       gtype);
 gboolean       dbus_g_type_is_map                           (GType       gtype);
+gboolean       dbus_g_type_is_struct                        (GType       gtype);
 GType          dbus_g_type_get_collection_specialization    (GType       gtype);
 GType          dbus_g_type_get_map_key_specialization       (GType       gtype);
 GType          dbus_g_type_get_map_value_specialization     (GType       gtype);
+GType          dbus_g_type_get_struct_member_type           (GType       gtype,
+                                                             guint       index);
+guint          dbus_g_type_get_struct_size                  (GType       gtype);
 
 typedef void   (*DBusGTypeSpecializedCollectionIterator)    (const GValue *val,
                                                             gpointer      user_data);
@@ -81,6 +91,21 @@ void           dbus_g_type_map_value_iterate                (const GValue
                                                             DBusGTypeSpecializedMapIterator         iterator,
                                                             gpointer                                user_data);
 
+gboolean       dbus_g_type_struct_get_member            (const GValue *value,
+                                                         guint index,
+                                                         GValue *dest);
+gboolean       dbus_g_type_struct_set_member            (GValue *value,
+                                                         guint index,
+                                                         const GValue *src);
+
+gboolean       dbus_g_type_struct_get                   (const GValue *value,
+                                                         guint member,
+                                                         ...);
+
+gboolean       dbus_g_type_struct_set                   (GValue *value,
+                                                         guint member,
+                                                         ...);
+
 typedef gpointer (*DBusGTypeSpecializedConstructor)     (GType type);
 typedef void     (*DBusGTypeSpecializedFreeFunc)        (GType type, gpointer val);
 typedef gpointer (*DBusGTypeSpecializedCopyFunc)        (GType type, gpointer src);
@@ -116,6 +141,15 @@ typedef struct {
   DBusGTypeSpecializedMapAppendFunc                 append_func;
 } DBusGTypeSpecializedMapVtable;
 
+typedef gboolean (*DBusGTypeSpecializedStructGetMember) (GType type, gpointer instance, guint member, GValue *ret_value);
+typedef gboolean (*DBusGTypeSpecializedStructSetMember) (GType type, gpointer instance, guint member, const GValue *new_value);
+
+typedef struct {
+  DBusGTypeSpecializedVtable                        base_vtable;
+  DBusGTypeSpecializedStructGetMember               get_member;
+  DBusGTypeSpecializedStructSetMember               set_member;
+} DBusGTypeSpecializedStructVtable;
+
 void           dbus_g_type_specialized_init           (void);
 
 void           dbus_g_type_register_collection        (const char                                   *name,
@@ -128,6 +162,15 @@ void           dbus_g_type_register_map               (const char
 const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type);
 const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type);
 
+void           dbus_g_type_register_struct             (const char                                   *name,
+                                                      const DBusGTypeSpecializedStructVtable        *vtable,
+                                                      guint                                          flags);
+
+const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type);
+const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type);
+
+const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type);
+
 G_END_DECLS
 
 #endif
index 04c0c3e8fc5a160931f3e256625bdec7a2f90ec6..f64a921ff08941ae34e68abf418d8938a8b75ebe 100644 (file)
@@ -334,6 +334,16 @@ hash_free_from_gtype (GType gtype, GDestroyNotify *func)
               return TRUE;
             }
         }
+      else if (dbus_g_type_is_struct (gtype))
+        {
+          const DBusGTypeSpecializedStructVtable *vtable;
+          vtable = dbus_g_type_struct_peek_vtable (gtype);
+          if (vtable->base_vtable.simple_free_func)
+            {
+              *func = vtable->base_vtable.simple_free_func;
+              return TRUE;
+            }
+        }
       return FALSE;
     }
 }
@@ -611,6 +621,67 @@ hashtable_simple_free (gpointer val)
   g_hash_table_destroy (val);
 }
 
+static gpointer
+valuearray_constructor (GType type)
+{
+  GValueArray *ret;
+  guint size = dbus_g_type_get_struct_size (type);
+  guint i;
+  ret = g_value_array_new (size);
+  for (i=0; i < size; i++)
+    {
+      GValue val = {0,};
+      g_value_init (&val, dbus_g_type_get_struct_member_type (type, i));
+      g_value_array_append(ret, &val);
+    }
+  return (gpointer)ret;
+}
+
+static gpointer
+valuearray_copy (GType type, gpointer src)
+{
+  return g_value_array_copy ((GValueArray*) src);
+}
+
+static void
+valuearray_simple_free (gpointer val)
+{
+  g_value_array_free (val);
+}
+
+static gboolean
+valuearray_get_member (GType type, gpointer instance,
+                       guint member, GValue *ret)
+{
+  GValueArray *va = (GValueArray*) instance;
+  const GValue *val;
+  if (member < dbus_g_type_get_struct_size (type))
+    {
+      val = g_value_array_get_nth (va, member);
+      g_value_copy (val, ret);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+valuearray_set_member (GType type, gpointer instance,
+                       guint member, const GValue *member_type)
+{
+  GValueArray *va = (GValueArray*) instance;
+  GValue *vp;
+  if (member < dbus_g_type_get_struct_size (type))
+    {
+      vp = g_value_array_get_nth (va, member);
+      g_value_copy (member_type, vp);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+
 static gpointer
 array_constructor (GType type)
 {
@@ -945,10 +1016,24 @@ _dbus_g_type_specialized_builtins_init (void)
     hashtable_append
   };
 
+  static const DBusGTypeSpecializedStructVtable valuearray_vtable = {
+    {
+      valuearray_constructor,
+      NULL,
+      valuearray_copy,
+      valuearray_simple_free,
+      NULL,
+      NULL
+    },
+    valuearray_get_member,
+    valuearray_set_member
+  };
+
   dbus_g_type_register_collection ("GSList", &slist_vtable, 0);
   dbus_g_type_register_collection ("GArray", &array_vtable, 0);
   dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);
   dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
+  dbus_g_type_register_struct ("GValueArray", &valuearray_vtable, 0);
 }
 
 #ifdef DBUS_BUILD_TESTS
@@ -1160,6 +1245,105 @@ _dbus_gvalue_utils_test (const char *datadir)
     g_value_unset (&val);
   }
 
+  type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+  g_assert (dbus_g_type_is_struct (type));
+  g_assert (dbus_g_type_get_struct_size (type) == 3);
+  g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
+  g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
+  g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
+  {
+    GValueArray *instance;
+    GValue val = {0, };
+    GValue memval = {0, };
+
+    instance = dbus_g_type_specialized_construct (type);
+
+    g_assert (instance->n_values == 3);
+
+    g_value_init (&val, type);
+    g_value_set_boxed_take_ownership (&val, instance);
+
+    g_value_init (&memval, G_TYPE_STRING);
+    g_value_set_static_string (&memval, "foo");
+    dbus_g_type_struct_set_member (&val, 0, &memval);
+    g_value_unset (&memval);
+
+    g_value_init (&memval, G_TYPE_UINT);
+    g_value_set_uint (&memval, 42);
+    dbus_g_type_struct_set_member (&val, 1, &memval);
+    g_value_unset (&memval);
+
+    g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
+    g_value_set_static_boxed (&memval, "/bar/moo/foo/baz");
+    dbus_g_type_struct_set_member (&val, 2, &memval);
+    g_value_unset (&memval);
+
+    g_assert (instance->n_values == 3);
+
+    g_value_init (&memval, G_TYPE_STRING);
+    dbus_g_type_struct_get_member (&val, 0, &memval);
+    g_assert (0 == strcmp (g_value_get_string (&memval), "foo"));
+    g_value_unset (&memval);
+
+    g_value_init (&memval, G_TYPE_UINT);
+    dbus_g_type_struct_get_member (&val, 1, &memval);
+    g_assert (g_value_get_uint (&memval) == 42);
+    g_value_unset (&memval);
+
+    g_value_init (&memval, DBUS_TYPE_G_OBJECT_PATH);
+    dbus_g_type_struct_get_member (&val, 2, &memval);
+    g_assert (0 == strcmp ((gchar*) g_value_get_boxed (&memval),
+                           "/bar/moo/foo/baz"));
+    g_value_unset (&memval);
+
+    g_value_unset (&val);
+  }
+
+  type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+  g_assert (dbus_g_type_is_struct (type));
+  g_assert (dbus_g_type_get_struct_size (type) == 3);
+  g_assert (dbus_g_type_get_struct_member_type (type, 0) == G_TYPE_STRING);
+  g_assert (dbus_g_type_get_struct_member_type (type, 1) == G_TYPE_UINT);
+  g_assert (dbus_g_type_get_struct_member_type (type, 2) == DBUS_TYPE_G_OBJECT_PATH);
+  {
+    GValueArray *instance;
+    GValue val = {0, };
+
+    instance = dbus_g_type_specialized_construct (type);
+
+    g_assert (instance->n_values == 3);
+
+    g_value_init (&val, type);
+    g_value_set_boxed_take_ownership (&val, instance);
+
+    dbus_g_type_struct_set (&val,
+                            0,"foo",
+                            1, 42,
+                            2, "/bar/moo/foo/baz",
+                            G_MAXUINT);
+
+    g_assert (instance->n_values == 3);
+
+    {
+      gchar *string;
+      guint intval;
+      gchar *path;
+
+      dbus_g_type_struct_get (&val,
+                              0, &string,
+                              1, &intval,
+                              2, &path,
+                              G_MAXUINT);
+
+      g_assert (0 == strcmp (string, "foo"));
+      g_assert (intval == 42);
+      g_assert (0 == strcmp (path, "/bar/moo/foo/baz"));
+    }
+
+    g_value_unset (&val);
+  }
+
+
   return TRUE;
 }
 
index 139f4a312f5eb4139742b76b4119540847df24cb..cba3b61a20608de9aa5e22d41647d4d05ae3378c 100644 (file)
@@ -29,7 +29,7 @@
 
 G_BEGIN_DECLS
 
-void          _dbus_g_type_specialized_builtins_init (void);
+void           _dbus_g_type_specialized_builtins_init (void);
 
 gboolean       _dbus_g_type_is_fixed                  (GType gtype); 
 guint          _dbus_g_type_fixed_get_size            (GType gtype); 
index e332e71a50ccec4e048d953c5b2e30c37bf69c02..3e8cf1e78a8b13cbba459c2e70b260d459303115 100644 (file)
@@ -107,6 +107,13 @@ static gboolean demarshal_collection_array      (DBusGValueMarshalCtx      *cont
                                                 DBusMessageIter           *iter,
                                                 GValue                    *value,
                                                 GError                   **error);
+static gboolean marshal_struct                  (DBusMessageIter           *iter,
+                                                const GValue              *value);
+static gboolean demarshal_struct                (DBusGValueMarshalCtx      *context,
+                                                DBusMessageIter           *iter,
+                                                GValue                    *value,
+                                                GError                   **error);
+
 
 typedef gboolean (*DBusGValueMarshalFunc)       (DBusMessageIter           *iter,
                                                 const GValue              *value);
@@ -346,6 +353,7 @@ dbus_g_object_path_get_g_type (void)
   return type_id;
 }
 
+
 char *
 _dbus_gtype_to_signature (GType gtype)
 {
@@ -377,6 +385,21 @@ _dbus_gtype_to_signature (GType gtype)
       g_free (key_subsig);
       g_free (val_subsig);
     }
+  else if (dbus_g_type_is_struct (gtype))
+    {
+      guint i, size;
+      GString *sig;
+      size = dbus_g_type_get_struct_size (gtype);
+      sig = g_string_sized_new (size+2); /*some sensible starting size*/
+      g_string_assign (sig, DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
+      for (i=0; i < size; i++)
+        {
+          g_string_append (sig, _dbus_gtype_to_signature (
+              dbus_g_type_get_struct_member_type (gtype, i)));
+        }
+      g_string_append (sig, DBUS_STRUCT_END_CHAR_AS_STRING);
+      ret = g_string_free (sig, FALSE);
+    }
   else
     {
       typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
@@ -384,7 +407,6 @@ _dbus_gtype_to_signature (GType gtype)
        return NULL;
       ret = g_strdup (typedata->sig);
     }
-  
   return ret;
 }
 
@@ -851,6 +873,76 @@ demarshal_map (DBusGValueMarshalCtx    *context,
   return TRUE;
 }
 
+static gboolean
+demarshal_struct (DBusGValueMarshalCtx    *context,
+                  DBusMessageIter         *iter,
+                  GValue                  *value,
+                  GError                 **error)
+{
+  int current_type;
+  DBusMessageIter subiter;
+  guint i, size;
+  GValue val = {0,};
+  GType elt_type;
+
+  current_type = dbus_message_iter_get_arg_type (iter);
+  if (current_type != DBUS_TYPE_STRUCT)
+    {
+      g_set_error (error,
+                   DBUS_GERROR,
+                   DBUS_GERROR_INVALID_ARGS,
+                   _("Expected D-BUS struct, got type code \'%c\'"), (guchar) current_type);
+      return FALSE;
+    }
+
+  dbus_message_iter_recurse (iter, &subiter);
+
+  g_value_set_boxed_take_ownership (value,
+    dbus_g_type_specialized_construct (G_VALUE_TYPE (value)));
+
+  size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
+
+  for (i=0; i < size; i++)
+    {
+
+      elt_type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE(value), i);
+      if (elt_type == G_TYPE_INVALID)
+        {
+          g_value_unset (value);
+          g_set_error (error,
+                       DBUS_GERROR,
+                       DBUS_GERROR_INVALID_ARGS,
+                       _("Couldn't demarshal argument, "
+                         "struct type %s has no member %d"),
+                       g_type_name (G_VALUE_TYPE(value)), i);
+          return FALSE;
+        }
+
+      g_value_init (&val, elt_type);
+
+      if (!_dbus_gvalue_demarshal (context, &subiter, &val, error))
+        {
+          g_value_unset (&val);
+          g_value_unset (value);
+          return FALSE;
+        }
+      if (!dbus_g_type_struct_set_member (value, i, &val))
+        {
+          g_value_unset (&val);
+          g_value_unset (value);
+          return FALSE;
+        }
+
+      dbus_message_iter_next (&subiter);
+      g_value_unset (&val);
+    }
+
+  g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_INVALID);
+
+  return TRUE;
+}
+
+
 static DBusGValueDemarshalFunc
 get_type_demarshaller (GType type)
 {
@@ -865,6 +957,8 @@ get_type_demarshaller (GType type)
        return demarshal_collection;
       if (dbus_g_type_is_map (type))
        return demarshal_map;
+      if (dbus_g_type_is_struct (type))
+        return demarshal_struct;
 
       g_warning ("No demarshaller registered for type \"%s\"", g_type_name (type));
       return NULL;
@@ -1452,6 +1546,48 @@ marshal_map (DBusMessageIter   *iter,
   goto out;
 }
 
+static gboolean
+marshal_struct (DBusMessageIter   *iter,
+                const GValue      *value)
+{
+  GType gtype;
+  DBusMessageIter subiter;
+  gboolean ret;
+  guint size, i;
+  GValue val = {0,};
+
+  gtype = G_VALUE_TYPE (value);
+
+  ret = FALSE;
+
+  size = dbus_g_type_get_struct_size (gtype);
+
+  if (!dbus_message_iter_open_container (iter,
+                                         DBUS_TYPE_STRUCT,
+                                         NULL,
+                                         &subiter))
+    goto oom;
+
+  for (i = 0; i < size; i++)
+    {
+      g_value_init (&val, dbus_g_type_get_struct_member_type
+          (G_VALUE_TYPE(value), i));
+      if (!dbus_g_type_struct_get_member (value, i, &val))
+        return FALSE;
+      if (!_dbus_gvalue_marshal (&subiter, &val))
+        return FALSE;
+      g_value_unset(&val);
+    }
+
+  if (!dbus_message_iter_close_container (iter, &subiter))
+    goto oom;
+
+  return TRUE;
+ oom:
+  g_error ("out of memory");
+  return FALSE;
+}
+
 static gboolean
 marshal_variant (DBusMessageIter          *iter,
                 const GValue             *value)
@@ -1504,6 +1640,8 @@ get_type_marshaller (GType type)
        return marshal_collection;
       if (dbus_g_type_is_map (type))
        return marshal_map;
+      if (dbus_g_type_is_struct (type))
+       return marshal_struct;
 
       g_warning ("No marshaller registered for type \"%s\"", g_type_name (type));
       return NULL;
@@ -1697,17 +1835,15 @@ _dbus_gvalue_test (const char *test_data_dir)
   assert_bidirectional_mapping (G_TYPE_UCHAR, DBUS_TYPE_BYTE_AS_STRING);
   assert_bidirectional_mapping (G_TYPE_UINT, DBUS_TYPE_UINT32_AS_STRING);
 
-  assert_signature_maps_to (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, G_TYPE_VALUE_ARRAY);
-  assert_signature_maps_to (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, G_TYPE_VALUE_ARRAY);
-  assert_signature_maps_to (DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, G_TYPE_VALUE_ARRAY);
-
   assert_bidirectional_mapping (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
-                               DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
+                             DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
   assert_bidirectional_mapping (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
                                DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING);
   assert_bidirectional_mapping (dbus_g_type_get_collection ("GArray", G_TYPE_INT),
                                DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING);
 
+  assert_bidirectional_mapping (dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID),
+                               DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING );
   return TRUE;
 }