dbus/glib dbus-gvalue.h, 1.4, 1.5 dbus-gvalue.c, 1.8, 1.9 dbus-gvalue-utils.h, NONE, 1.1 dbus-gvalue-utils.c, NONE, 1.1 dbus-gtype-specialized.h, NONE, 1.1 dbus-gtype-specialized.c, NONE, 1.1 dbus-gproxy.c, 1.24, 1.25 dbus-gobject.h, 1.2, 1.3 dbus-gobject.c, 1.22, 1.23 dbus-gmain.c, 1.41, 1.42 dbus-binding-tool-glib.h, 1.4, 1.5 dbus-binding-tool-glib.c, 1.8, 1.9 Makefile.am, 1.17, 1.18

Colin Walters walters at freedesktop.org
Sun Jun 12 20:01:26 PDT 2005


Update of /cvs/dbus/dbus/glib
In directory gabe:/tmp/cvs-serv11651/glib

Modified Files:
	dbus-gvalue.h dbus-gvalue.c dbus-gproxy.c dbus-gobject.h 
	dbus-gobject.c dbus-gmain.c dbus-binding-tool-glib.h 
	dbus-binding-tool-glib.c Makefile.am 
Added Files:
	dbus-gvalue-utils.h dbus-gvalue-utils.c 
	dbus-gtype-specialized.h dbus-gtype-specialized.c 
Log Message:
2005-06-12  Colin Walters  <walters at verbum.org>

	Async signals and various bugfixes and testing by
	Ross Burton <ross at burtonini.com>.

	* glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete.
	(dbus_gvalue_genmarshal_name_from_type)
	(dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c.
	(dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature.
	(dbus_g_value_types_init, dbus_gtype_from_signature)
	(dbus_gtype_from_signature_iter, dbus_gtype_to_signature)
	(dbus_gtypes_from_arg_signature): New function prototypes.
	(dbus_gvalue_demarshal): Take context and error arguments.
	(dbus_gvalue_demarshal_variant): New function.
	(dbus_gvalue_demarshal_message): New function.
	(dbus_gvalue_store): Delete.

	* glib/dbus-gvalue.c:

	File has been almost entirely rewritten; now we special-case
	more types such as DBUS_TYPE_SIGNATURE, handle arrays and
	hash tables correctly, etc.  Full support for recursive values
	is not yet complete.

	* glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last
	argument of signal to G_TYPE_POINTER since we now pass a
	structure.
	(lookup_g_marshaller): Delete in favor of
	_dbus_gobject_lookup_marshaller.
	(marshal_dbus_message_to_g_marshaller): Use
	_dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message
	to handle remote signal callbacks.
	(dbus_g_proxy_new_from_proxy): New function; creates a new
	DBusGProxy by copying an existing one.
	(dbus_g_proxy_get_interface, dbus_g_proxy_set_interface)
	(dbus_g_proxy_get_path): New functions.
	(dbus_g_proxy_marshal_args_to_message): New function;
	factored out of existing code.
	(DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments
	from a varargs array.
	(dbus_g_proxy_begin_call_internal): New function.
	(dbus_g_proxy_end_call_internal): New function.
	(dbus_g_proxy_begin_call): Take GTypes instead of DBus types
	as arguments; simply invoke dbus_g_proxy_begin_call_internal
	after collecting args into value array.
	(dbus_g_proxy_end_call): Take GTypes instead of DBus types;
	invoke dbus_g_proxy_end_call_internal.
	(dbus_g_proxy_invoke): Simply invoke begin_call_interanl and
	end_call_internal.
	(dbus_g_proxy_call_no_reply): Take GTypes instead of DBus
	types.
	(array_free_all): New function.
	(dbus_g_proxy_add_signal): Take GTypes.

	* glib/dbus-gobject.h:
	(_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete.
	(_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller):
	Prototype.

	* glib/dbus-gobject.c: Add a global marshal_table hash which
	stores mappings from type signatures to marshallers.  Change lots
	of invocations of dbus_gtype_to_dbus_type to
	dbus_gtype_to_signature.
	(_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete.
	(introspect_signals): Fix test for query.return_type.
	(set_object_property): Update invocation of dbus_gvalue_demarshal.
	(invoke_object_method): Many changes.  Handle asynchronous
	invocations.  Convert arguments with
	dbus_gvalue_demarshal_message.  Handle errors.  Use
	DBusSignatureIter instead of strlen on args. Handle all arguments
	generically.  Special-case variants.
	(dbus_g_method_return, dbus_g_method_return_error): New function.
	(DBusGSignalClosure): New structure, closes over signal
	information.
	(dbus_g_signal_closure_new): New function.
	(dbus_g_signal_closure_finalize): New function.
	(signal_emitter_marshaller): New function; is special marshaller
	which emits signals on bus.
	(export_signals): New function; introspects object signals and
	connects to them.
	(dbus_g_object_type_install_info): Take GType instead of
	GObjectClass.
	(dbus_g_connection_register_g_object): Invoke export_signals.
	(dbus_g_connection_lookup_g_object): New function.
	(DBusGFuncSignature) New structure; used for mapping type
	signatures to marshallers.
	(funcsig_hash): New function; hashes DBusGFuncSignature.
	(funcsig_equal): New function; compares DBusGFuncSignature.
	(_dbus_gobject_lookup_marshaller): New function.
	(dbus_g_object_register_marshaller): New function; used to
	register a marshaller at runtime for a particular signature.

	* glib/dbus-gmain.c (_dbus_gmain_test): Add various tests.

	* glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC
	which notes a server method implementation should be
	asynchronous.

	* glib/dbus-binding-tool-glib.c
	(dbus_binding_tool_output_glib_server): Call
	dbus_g_value_types_init.
	(write_formal_parameters): Use dbus_gtype_from_signature.  Handle
	variants specially.
	(dbus_g_type_get_lookup_function): Turn GType into an invocation
	of a lookup function.
	(write_args_for_direction): Use dbus_g_type_get_lookup_function.
	(write_untyped_out_args): New method; write output arguments.
	(write_formal_declarations_for_direction): Function for
	writing prototypes.
	(write_formal_parameters_for_direction): Function for
	writing implementations.
	(write_typed_args_for_direction): Function for writing
	arguments prefixed with GTypes.
	(write_async_method_client): Write out async version
	of method.

	* glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h.
	(dbus_g_type_get_marshal_name): Move mapping from GType
	to marshal name into here.
	(dbus_g_type_get_c_name): Move into here.
	(compute_marshaller): Convert signature to type with
	dbus_gtype_from_signature, use dbus_g_type_get_marshal_name.
	(compute_marshaller_name): Ditto.
	(compute_marshaller): Handle async signal annotations.
	(gather_marshallers): Return if we don't have a known
	prefix.
	(generate_glue): Collect introspection blob here, and
	write all of the blob at the end.  This allows an object
	with multiple interfaces to work.
	Mark async methods in introspection blob.

	* glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add
	dbus-gtype-specialized.c, dbus-gtype-specialized.h,
	dbus-gvalue-utils.h, dbus-gvalue-utils.c.

	* dbus/dbus-glib.h: Don't include dbus-protocol.h; this
	avoids people accidentally using DBUS_TYPE_* which should
	not be necessary anymore.
	Do include dbus-gtype-specialized.h, which are utilities
	for GLib container types.
	Add various #defines for types such as
	DBUS_TYPE_G_BOOLEAN_ARRAY.
	(DBusGValueIterator, DBusGValue): Define, not fully used
	yet.
	(dbus_g_value_get_g_type): Type for recursive value.
	(dbus_g_value_open, dbus_g_value_iterator_get_value)
	(dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse)
	(dbus_g_value_free): Prototypes.
	(dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype.
	(dbus_g_proxy_set_interface): Prototype.
	(dbus_g_proxy_begin_call, dbus_g_proxy_end_call)
	(dbus_g_proxy_call_no_reply): Take GLib types instead of DBus
	types.
	(dbus_g_proxy_get_path, dbus_g_proxy_get_interface):
	Accessors.
	(DBusGAsyncData, DBusGMethodInvocation): Structures for
	doing async invocations.
	(dbus_g_method_return, dbus_g_method_return_error):
	Prototypes.
	* doc/dbus-tutorial.xml: Update GLib section.
	
	* tools/dbus-viewer.c (load_child_nodes): Update
	for new invocation type of dbus_g_proxy_end_call.
	(load_from_service_thread_func): Ditto.

	* tools/print-introspect.c (main): Ditto.

	* tools/dbus-names-model.c (have_names_notify)
	(names_model_reload, names_model_set_connection)
	Use GTypes.

	* python/Makefile.am (INCLUDES): Define DBUS_COMPILATION,
	needed since Python bindings use GLib bindings.

	* test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION.
	Add --prefix argument.

	* tools/Makefile.am: Define DBUS_COMPILATION.  Remove
	unneeded --ignore-unsupported arg.
	
	* test/glib/test-service-glib.c: 
	* test/glib/test-service-glib.xml:
	* test/glib/test-dbus-glib.c: Add many more tests.


Index: dbus-gvalue.h
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gvalue.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbus-gvalue.h	9 Mar 2005 17:09:11 -0000	1.4
+++ dbus-gvalue.h	13 Jun 2005 03:01:24 -0000	1.5
@@ -2,40 +2,49 @@
 #define DBUS_GOBJECT_VALUE_H
 
 #include <dbus/dbus.h>
+#include <dbus/dbus-signature.h>
 #include <glib.h>
 #include <glib-object.h>
+#include "dbus/dbus-glib.h"
 
 G_BEGIN_DECLS
 
-/* Used for return value storage */
-typedef union
-{
-  gboolean gboolean_val;
-  guchar guchar_val;
-  gint int_val;
-  gint64 gint64_val;
-  guint64 guint64_val;
-  double double_val;
-  gpointer gpointer_val;
-  char * chararray_val;
-} DBusBasicGValue;
+typedef struct {
+  DBusGConnection    *gconnection;
+  DBusGProxy         *proxy;
+} DBusGValueMarshalCtx;
 
-const char *   dbus_gvalue_genmarshal_name_from_type (const char *type);
+void           dbus_g_value_types_init        (void);
 
-const char *   dbus_gvalue_ctype_from_type           (const char *type, gboolean in);
+GType          dbus_gtype_from_signature      (const char              *signature,
+					       gboolean                 is_client);
 
-const char *   dbus_gtype_to_dbus_type    (GType            type);
+GType          dbus_gtype_from_signature_iter (DBusSignatureIter       *sigiter,
+					       gboolean                 is_client);
 
-gboolean       dbus_gvalue_init           (int              type,
-					   GValue          *value);
+const char *   dbus_gtype_to_signature        (GType                    type);
 
-gboolean       dbus_gvalue_demarshal      (DBusMessageIter *iter,
-					   GValue          *value);
-gboolean       dbus_gvalue_marshal        (DBusMessageIter *iter,
-					   GValue          *value);
+GArray *       dbus_gtypes_from_arg_signature (const char              *signature,
+					       gboolean                 is_client);
 
-gboolean       dbus_gvalue_store          (GValue          *value,
-					   gpointer         storage);
+gboolean       dbus_gvalue_demarshal          (DBusGValueMarshalCtx    *context,
+					       DBusMessageIter         *iter,
+					       GValue                  *value,
+					       GError                 **error);
+
+gboolean       dbus_gvalue_demarshal_variant  (DBusGValueMarshalCtx    *context,
+					       DBusMessageIter         *iter,
+					       GValue                  *value,
+					       GError                 **error);
+
+GValueArray *  dbus_gvalue_demarshal_message  (DBusGValueMarshalCtx    *context,
+					       DBusMessage             *message,
+					       guint                    n_params,
+					       const GType             *types, 
+					       GError                 **error);
+
+gboolean       dbus_gvalue_marshal            (DBusMessageIter         *iter,
+					       GValue                  *value);
 
 G_END_DECLS
 

Index: dbus-gvalue.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gvalue.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- dbus-gvalue.c	9 Mar 2005 17:09:11 -0000	1.8
+++ dbus-gvalue.c	13 Jun 2005 03:01:24 -0000	1.9
@@ -22,202 +22,680 @@
  *
  */
 
-#include <dbus-gvalue.h>
+#include "dbus-gvalue.h"
+#include "dbus-gobject.h"
+#include "dbus-gvalue-utils.h"
+#include "dbus/dbus-glib.h"
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
 #include "dbus/dbus-signature.h"
 
-/* This is slightly evil, we don't use g_value_set_foo() functions */
+static gboolean demarshal_static_variant (DBusGValueMarshalCtx    *context,
+					  DBusMessageIter         *iter,
+					  GValue                  *value,
+					  GError                 **error);
+static gpointer dbus_g_value_copy (gpointer value);
+
+
+struct DBusGValue
+{
+  enum {
+    DBUS_G_VALUE_TYPE_TOPLEVEL,
+    DBUS_G_VALUE_TYPE_ITERATOR
+  } type;
+  union {
+    struct {
+      DBusGConnection        *connection;
+      DBusGProxy             *proxy;
+      DBusMessage            *message;
+      char                   *signature;
+    } toplevel;
+    struct {
+      DBusGValue             *toplevel;
+      DBusMessageIter         iterator;
+    } recurse;
+  } value;
+};
+
+static gboolean marshal_basic                   (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_basic                 (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_strv                    (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_strv                  (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_variant                 (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_variant               (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_garray_basic            (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_garray_basic          (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_proxy                   (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_proxy                 (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_object                  (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_object                (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_proxy_array             (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_proxy_array           (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+static gboolean marshal_map                     (DBusMessageIter           *iter,
+						 GValue                    *value);
+static gboolean demarshal_ghashtable            (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+
+typedef gboolean (*DBusGValueMarshalFunc)       (DBusMessageIter           *iter,
+						 GValue                    *value);
+typedef gboolean (*DBusGValueDemarshalFunc)     (DBusGValueMarshalCtx      *context,
+						 DBusMessageIter           *iter,
+						 GValue                    *value,
+						 GError                   **error);
+
+typedef struct {
+  DBusGValueMarshalFunc       marshaller;
+  DBusGValueDemarshalFunc     demarshaller;
+} DBusGTypeMarshalVtable;
+
+typedef struct {
+  const char                       *sig;
+  const DBusGTypeMarshalVtable     *vtable;
+} DBusGTypeMarshalData;
+
+static GQuark
+dbus_g_type_metadata_data_quark ()
+{
+  static GQuark quark;
+  if (!quark)
+    quark = g_quark_from_static_string ("DBusGTypeMetaData");
+  
+  return quark;
+}
+
+static void
+set_type_metadata (GType type, const DBusGTypeMarshalData *data)
+{
+  g_type_set_qdata (type, dbus_g_type_metadata_data_quark (), (gpointer) data);
+}
+
 #define MAP_BASIC(d_t, g_t)                     \
     case DBUS_TYPE_##d_t:                       \
       return G_TYPE_##g_t;
-
 static GType
-dbus_dbus_type_to_gtype (int type)
+typecode_to_gtype (int type)
 {
   switch (type)
     {
       MAP_BASIC (BOOLEAN, BOOLEAN);
       MAP_BASIC (BYTE,    UCHAR);
+      MAP_BASIC (INT16,   INT);
       MAP_BASIC (INT32,   INT);
+      MAP_BASIC (UINT16,  UINT);
       MAP_BASIC (UINT32,  UINT);
       MAP_BASIC (INT64,   INT64);
       MAP_BASIC (UINT64,  UINT64);
       MAP_BASIC (DOUBLE,  DOUBLE);
-    case DBUS_TYPE_INT16:
-      return G_TYPE_INT;
-    case DBUS_TYPE_UINT16:
-      return G_TYPE_UINT;
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
-      return G_TYPE_STRING;
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_VARIANT:
+      MAP_BASIC (STRING,  STRING);
     default:
       return G_TYPE_INVALID;
     }
 }
-
 #undef MAP_BASIC
 
-gboolean
-dbus_gvalue_init (int     type,
-		  GValue *value)
+static gboolean
+dbus_typecode_maps_to_basic (int typecode)
+{
+  return typecode_to_gtype (typecode) != G_TYPE_INVALID;
+}
+
+static gboolean
+basic_typecode_to_gtype (int typecode)
+{
+  g_assert (dbus_type_is_basic (typecode));
+  g_assert (dbus_typecode_maps_to_basic (typecode));
+  return typecode_to_gtype (typecode);
+}
+
+static void
+register_basic (int typecode, const DBusGTypeMarshalData *typedata)
+{
+  set_type_metadata (basic_typecode_to_gtype (typecode), typedata);
+}
+
+static void
+register_array (int typecode, const DBusGTypeMarshalData *typedata)
 {
+  GType elt_gtype;
   GType gtype;
 
-  gtype = dbus_dbus_type_to_gtype (type);
-  if (gtype == G_TYPE_INVALID)
-    return FALSE;
-  g_value_init (value, gtype);
-  return TRUE;
+  elt_gtype = basic_typecode_to_gtype (typecode); 
+  gtype = dbus_g_type_get_collection ("GArray", elt_gtype);
+  set_type_metadata (gtype, typedata); 
 }
 
-/* FIXME - broken for containers
+static void
+register_dict (int key_type, int value_type, const DBusGTypeMarshalData *typedata)
+{
+  GType key_gtype;
+  GType value_gtype;
+  GType gtype;
+
+  key_gtype = basic_typecode_to_gtype (key_type); 
+  value_gtype = basic_typecode_to_gtype (value_type); 
+  gtype = dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype);
+  set_type_metadata (gtype, typedata); 
+}
+
+void
+dbus_g_value_types_init (void)
+{
+  static gboolean types_initialized;
+
+
+  if (types_initialized)
+    return;
+
+  g_assert (sizeof (DBusGValueIterator) >= sizeof (DBusMessageIter));
+
+  dbus_g_type_specialized_init ();
+  dbus_g_type_specialized_builtins_init ();
+  
+  static const DBusGTypeMarshalVtable basic_vtable = {
+    marshal_basic,
+    demarshal_basic
+  };
+  static const DBusGTypeMarshalVtable garray_basic_vtable = {
+    marshal_garray_basic,
+    demarshal_garray_basic
+  };
+  static const DBusGTypeMarshalVtable ghashtable_vtable = {
+    marshal_map,
+    demarshal_ghashtable
+  };
+
+  /* Register basic types */
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_BOOLEAN_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_BOOLEAN, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_BYTE_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_BYTE, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_INT16_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_INT16, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_UINT16_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_UINT16, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_UINT32_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_UINT32, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_INT32_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_INT32, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_UINT64_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_UINT64, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_INT64_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_INT64, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_DOUBLE_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_DOUBLE, &typedata);
+  }
+  {
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_STRING_AS_STRING,
+      &basic_vtable,
+    };
+    register_basic (DBUS_TYPE_STRING, &typedata);
+  }
+  
+  /* Register complex types with builtin GType mappings */
+  {
+    static const DBusGTypeMarshalVtable vtable = {
+      marshal_variant,
+      demarshal_variant
+    };
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_VARIANT_AS_STRING,
+      &vtable
+    };
+    set_type_metadata (G_TYPE_VALUE, &typedata);
+  };
+  {
+    static const DBusGTypeMarshalVtable vtable = {
+      marshal_strv,
+      demarshal_strv
+    };
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
+      &vtable
+    };
+    set_type_metadata (G_TYPE_STRV, &typedata);
+  };
+
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING,
+      &garray_basic_vtable
+    };
+    register_array (DBUS_TYPE_BOOLEAN, &typedata);
+  }
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
+      &garray_basic_vtable
+    };
+    register_array (DBUS_TYPE_BYTE, &typedata);
+  }
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
+      &garray_basic_vtable
+    };
+    register_array (DBUS_TYPE_UINT32, &typedata);
+  }
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
+      &garray_basic_vtable
+    };
+    register_array (DBUS_TYPE_INT32, &typedata);
+  }
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING,
+      &garray_basic_vtable
+    };
+    register_array (DBUS_TYPE_UINT64, &typedata);
+  }
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING,
+      &garray_basic_vtable
+    };
+    register_array (DBUS_TYPE_INT64, &typedata);
+  }
+  { 
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+      &ghashtable_vtable,
+    };
+    register_dict (DBUS_TYPE_STRING, DBUS_TYPE_STRING, &typedata);
+  }
+
+  {
+    static const DBusGTypeMarshalVtable vtable = {
+      marshal_proxy,
+      demarshal_proxy
+    };
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_OBJECT_PATH_AS_STRING,
+      &vtable
+    };
+    set_type_metadata (DBUS_TYPE_G_PROXY, &typedata);
+  }
+
+  {
+    static const DBusGTypeMarshalVtable vtable = {
+      marshal_object,
+      demarshal_object
+    };
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_OBJECT_PATH_AS_STRING,
+      &vtable
+    };
+    set_type_metadata (G_TYPE_OBJECT, &typedata);
+  }
+
+  {
+    static const DBusGTypeMarshalVtable vtable = {
+      marshal_proxy_array,
+      demarshal_proxy_array
+    };
+    static const DBusGTypeMarshalData typedata = {
+      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+      &vtable
+    };
+    set_type_metadata (DBUS_TYPE_G_PROXY_ARRAY, &typedata);
+  }
+
+  types_initialized = TRUE;
+}
+
+/**
+ * Get the GLib type ID for a DBusGValue boxed type.
+ *
+ * @returns GLib type
  */
-static int
-base_type_from_signature  (const char *signature)
+GType
+dbus_g_value_get_g_type (void)
 {
-  DBusSignatureIter iter;
+  static GType type_id = 0;
 
-  dbus_signature_iter_init (&iter, signature);
+  if (!type_id)
+    type_id = g_boxed_type_register_static ("DBusGValue",
+					    dbus_g_value_copy,
+					    (GBoxedFreeFunc) dbus_g_value_free);
+  return type_id;
+}
 
-  return dbus_signature_iter_get_current_type (&iter);
+void
+dbus_g_value_open (DBusGValue          *value,
+		   DBusGValueIterator  *iter)
+{
+  DBusGValue *real;
+
+  g_return_if_fail (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL);
+
+  real = (DBusGValue*) iter;
+  real->type = DBUS_G_VALUE_TYPE_ITERATOR;
+  real->value.recurse.toplevel = value;
+
+  dbus_message_iter_init (value->value.toplevel.message,
+			  &(real->value.recurse.iterator));
+  value->value.recurse.toplevel = value;
 }
 
-const char *
-dbus_gvalue_genmarshal_name_from_type (const char *signature)
+gboolean
+dbus_g_value_iterator_get_values (DBusGValueIterator *iter,
+				  GError            **error,
+				  GValue             *first_val,
+				  ...)
 {
-  int type;
+  GValue *value;
+  va_list args;
+  DBusGValue *iterval;
 
-  type = base_type_from_signature (signature);
-  switch (type)
+  va_start (args, first_val);
+
+  iterval = (DBusGValue *) iter;
+
+  value = first_val;
+  do
     {
-    case DBUS_TYPE_BOOLEAN:
-      return "BOOLEAN";
-    case DBUS_TYPE_BYTE:
-      return "UCHAR";
-    case DBUS_TYPE_INT32:
-      return "INT";
-    case DBUS_TYPE_UINT32:
-      return "UINT";
-    case DBUS_TYPE_INT64:
-      return "INT64";
-    case DBUS_TYPE_UINT64:
-      return "UINT64";
-    case DBUS_TYPE_DOUBLE:
-      return "DOUBLE";
-    case DBUS_TYPE_INT16:
-      return "INT";
-      break;
-    case DBUS_TYPE_UINT16:
-      return "UINT";
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
-      return "STRING";
-      
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_VARIANT:
-      return NULL;
-    }
+      DBusGValueMarshalCtx context;
+
+      context.gconnection = (iterval->value.recurse.toplevel)->value.toplevel.connection;
+      context.proxy = (iterval->value.recurse.toplevel)->value.toplevel.proxy;
+      if (!dbus_gvalue_demarshal (&context,
+				  &(iterval->value.recurse.iterator),
+				  value,
+				  error))
+	return FALSE;
+    } while ((value = va_arg (args, GValue *)) != NULL);
+  
+  return TRUE;
+}
+
+static char *
+dbus_g_value_get_signature (DBusGValue *value)
+{
+  return value->value.toplevel.signature;
+}
+
+static gpointer
+dbus_g_value_copy (gpointer value)
+{
+  /* FIXME */
   return NULL;
 }
 
-const char *
-dbus_gvalue_ctype_from_type (const char *signature, gboolean in)
+void
+dbus_g_value_free (DBusGValue *value)
 {
-  int type;
+  if (value->type == DBUS_G_VALUE_TYPE_TOPLEVEL)
+    {
+      dbus_message_unref (value->value.toplevel.message);
+      g_free (value->value.toplevel.signature);
+    }
+}
 
-  type = base_type_from_signature (signature);
+static GType
+signature_iter_to_g_type_dict (const DBusSignatureIter *subiter, gboolean is_client)
+{
+  DBusSignatureIter iter;
+  GType key_gtype;
+  GType value_gtype;
 
-  switch (type)
+  g_assert (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_DICT_ENTRY);
+
+  dbus_signature_iter_recurse (subiter, &iter);
+
+  key_gtype = dbus_gtype_from_signature_iter (&iter, is_client); 
+  if (key_gtype == G_TYPE_INVALID)
+    return G_TYPE_INVALID;
+
+  dbus_signature_iter_next (&iter);
+  value_gtype = dbus_gtype_from_signature_iter (&iter, is_client);
+  if (value_gtype == G_TYPE_INVALID)
+    return G_TYPE_INVALID;
+
+  if (!dbus_gtype_is_valid_hash_key (key_gtype)
+      || !dbus_gtype_is_valid_hash_value (value_gtype))
+    /* Later we need to return DBUS_TYPE_G_VALUE */
+    return G_TYPE_INVALID; 
+
+  return dbus_g_type_get_map ("GHashTable", key_gtype, value_gtype);
+}
+
+static GType
+signature_iter_to_g_type_array (DBusSignatureIter *iter, gboolean is_client)
+{
+  GType elt_gtype;
+  DBusGTypeMarshalData *typedata;
+
+  elt_gtype = dbus_gtype_from_signature_iter (iter, is_client);
+  if (elt_gtype == G_TYPE_INVALID)
+    return G_TYPE_INVALID;
+
+  typedata = g_type_get_qdata (elt_gtype, dbus_g_type_metadata_data_quark ());
+  if (typedata == NULL)
+    return G_TYPE_INVALID;
+  
+  if (elt_gtype == G_TYPE_OBJECT)
+    return DBUS_TYPE_G_OBJECT_ARRAY;
+  if (elt_gtype == G_TYPE_STRING)
+    return G_TYPE_STRV;
+  if (dbus_g_type_is_fixed (elt_gtype))
+    return dbus_g_type_get_collection ("GArray", elt_gtype);
+
+  /* Later we need to return DBUS_TYPE_G_VALUE */
+  return G_TYPE_INVALID; 
+}
+
+static gboolean
+signature_iter_to_g_type_struct (DBusSignatureIter *origiter, gboolean is_client)
+{
+  /* FIXME allow structures */
+  return G_TYPE_INVALID;
+#if 0
+  DBusSignatureIter iter;
+  int current_type;
+
+  iter = *origiter;
+
+  while ((current_type = dbus_signature_iter_get_current_type (&iter)) != DBUS_TYPE_INVALID) {
+    subtype = dbus_gtype_from_signature_iter (&iter, is_client);
+    if (subtype == G_TYPE_INVALID)
+      return G_TYPE_INVALID;
+  }
+  return DBUS_TYPE_G_VALUE ();
+#endif
+}
+
+GType
+dbus_gtype_from_signature_iter (DBusSignatureIter *iter, gboolean is_client)
+{
+  int current_type;
+
+  current_type = dbus_signature_iter_get_current_type (iter);
+  /* TODO: handle type 0? */
+  if (dbus_typecode_maps_to_basic (current_type))
+    return basic_typecode_to_gtype (current_type);
+  else if (current_type == DBUS_TYPE_OBJECT_PATH)
+    return is_client ? DBUS_TYPE_G_PROXY : G_TYPE_OBJECT;
+  else
     {
-    case DBUS_TYPE_BOOLEAN:
-      return "gboolean";
-    case DBUS_TYPE_BYTE:
-      return "guchar";
-    case DBUS_TYPE_INT32:
-      return "gint32";
-    case DBUS_TYPE_UINT32:
-      return "guint32";
-    case DBUS_TYPE_INT64:
-      return "gint64";
-    case DBUS_TYPE_UINT64:
-      return "guint64";
-    case DBUS_TYPE_DOUBLE:
-      return "gdouble";
-    case DBUS_TYPE_INT16:
-      return "gint";
-      break;
-    case DBUS_TYPE_UINT16:
-      return "guint";
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
-      /* FIXME - kind of a hack */
-      if (in)
-	return "const char *";
+      DBusSignatureIter subiter;
+
+      g_assert (dbus_type_is_container (current_type));
+      dbus_signature_iter_recurse (iter, &subiter);
+
+      if (current_type == DBUS_TYPE_ARRAY)
+	{
+	  int elt_type = dbus_signature_iter_get_current_type (&subiter);
+	  if (elt_type == DBUS_TYPE_DICT_ENTRY)
+	    return signature_iter_to_g_type_dict (&subiter, 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 if (current_type == DBUS_TYPE_VARIANT)
+	return g_value_get_type ();
+      else if (current_type == DBUS_TYPE_DICT_ENTRY)
+	return G_TYPE_INVALID;
       else
-	return "char *";
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_VARIANT:
-      return NULL;
+	{
+	  g_assert_not_reached ();
+	  return G_TYPE_INVALID;
+	}
     }
-  return NULL;
 }
 
-const char *
-dbus_gtype_to_dbus_type (GType type)
+GType
+dbus_gtype_from_signature (const char *signature, gboolean is_client)
 {
-  switch (type)
+  DBusSignatureIter iter;
+
+  dbus_signature_iter_init (&iter, signature);
+
+  return dbus_gtype_from_signature_iter (&iter, is_client);
+}
+
+static char *
+dbus_gvalue_to_signature (GValue *value)
+{
+  const char *ret;
+
+  ret = dbus_gtype_to_signature (G_VALUE_TYPE (value));
+  if (ret)
+    return g_strdup (ret);
+  else
     {
-    case G_TYPE_CHAR:
-    case G_TYPE_UCHAR:
-      return DBUS_TYPE_BYTE_AS_STRING;
+      DBusGValue *val;
       
-    case G_TYPE_BOOLEAN:
-      return DBUS_TYPE_BOOLEAN_AS_STRING;
+      g_assert (G_VALUE_TYPE (value) == DBUS_TYPE_G_VALUE);
 
-      /* long gets cut to 32 bits so the remote API is consistent
-       * on all architectures
-       */
+      val = g_value_get_boxed (value);
       
-    case G_TYPE_LONG:
-    case G_TYPE_INT:
-      return DBUS_TYPE_INT32_AS_STRING;
-    case G_TYPE_ULONG:
-    case G_TYPE_UINT:
-      return DBUS_TYPE_UINT32_AS_STRING;
+      return dbus_g_value_get_signature (val);
+    }
+}
 
-    case G_TYPE_INT64:
-      return DBUS_TYPE_INT64_AS_STRING;
+const char *
+dbus_gtype_to_signature (GType gtype)
+{
+  DBusGTypeMarshalData *typedata;
 
-    case G_TYPE_UINT64:
-      return DBUS_TYPE_UINT64_AS_STRING;
-      
-    case G_TYPE_FLOAT:
-    case G_TYPE_DOUBLE:
-      return DBUS_TYPE_DOUBLE_AS_STRING;
+  typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+  if (typedata == NULL)
+    return NULL;
+  return typedata->sig;
+}
 
-    case G_TYPE_STRING:
-      return DBUS_TYPE_STRING_AS_STRING;
+GArray *
+dbus_gtypes_from_arg_signature (const char *argsig, gboolean is_client)
+{
+  GArray *ret;
+  int current_type;
+  DBusSignatureIter sigiter;
 
-    default:
-      return NULL;
+  ret = g_array_new (FALSE, FALSE, sizeof (GType));
+
+  dbus_signature_iter_init (&sigiter, argsig);
+  while ((current_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+    {
+      GType curtype;
+
+      curtype = dbus_gtype_from_signature_iter (&sigiter, is_client);
+      g_array_append_val (ret, curtype);
+      dbus_signature_iter_next (&sigiter);
     }
+  return ret;
 }
 
-gboolean
-dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
-{
-  g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
 
-  dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value);
+static gboolean
+demarshal_basic (DBusGValueMarshalCtx      *context,
+		 DBusMessageIter           *iter,
+		 GValue                    *value,
+		 GError                   **error)
+{
+  int current_type;
   
-  switch (dbus_message_iter_get_arg_type (iter))
+  current_type = dbus_message_iter_get_arg_type (iter);
+  g_assert (dbus_type_is_basic (current_type));
+
+  switch (current_type)
     {
     case DBUS_TYPE_BOOLEAN:
       {
@@ -283,24 +761,407 @@
 	return TRUE;
       }
     case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
       {
         const char *s;
         dbus_message_iter_get_basic (iter, &s);
-        g_value_set_string (value, s);
+	g_value_set_string (value, s);
 	return TRUE;
       }
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_VARIANT:
     default:
+      g_assert_not_reached ();
       return FALSE;
     }
 }
-    
+
+static gboolean
+demarshal_static_variant (DBusGValueMarshalCtx    *context,
+			  DBusMessageIter         *iter,
+			  GValue                  *value,
+			  GError                 **error)
+{
+  char *sig;
+  int current_type;
+  DBusMessageIter subiter;
+  GType variant_type;
+
+  current_type = dbus_message_iter_get_arg_type (iter);
+  dbus_message_iter_recurse (iter, &subiter);
+  sig = dbus_message_iter_get_signature (&subiter);
+
+  variant_type = dbus_gtype_from_signature (sig, context->proxy != NULL);
+  if (variant_type != G_TYPE_INVALID)
+    {
+      g_value_init (value, variant_type);
+
+      if (!dbus_gvalue_demarshal (context, &subiter, value, error))
+	{
+	  dbus_free (sig);
+	  return FALSE;
+	}
+    }
+  dbus_free (sig);
+  return TRUE;
+}
+
+static gboolean
+demarshal_variant (DBusGValueMarshalCtx    *context,
+		   DBusMessageIter         *iter,
+		   GValue                  *value,
+		   GError                 **error)
+
+{
+  GValue *variant_val;
+  variant_val = g_new0 (GValue, 1);
+
+  if (!demarshal_static_variant (context, iter, variant_val, error))
+    return FALSE;
+  
+  g_value_set_boxed_take_ownership (value, variant_val);
+  return TRUE;
+}
+
+static gboolean
+demarshal_proxy (DBusGValueMarshalCtx    *context,
+		 DBusMessageIter         *iter,
+		 GValue                  *value,
+		 GError                 **error)
+{
+  const char *name;
+  DBusGProxy *new_proxy;
+  const char *objpath;
+  int current_type;
+
+  current_type = dbus_message_iter_get_arg_type (iter);
+  g_assert (current_type == DBUS_TYPE_OBJECT_PATH);
+
+  g_assert (context->proxy != NULL);
+  
+  name = dbus_g_proxy_get_bus_name (context->proxy);
+      
+  dbus_message_iter_get_basic (iter, &objpath);
+
+  new_proxy = dbus_g_proxy_new_from_proxy (context->proxy, NULL, objpath);
+  g_value_set_object_take_ownership (value, new_proxy);
+
+  return TRUE;
+}
+
+static gboolean
+demarshal_object (DBusGValueMarshalCtx    *context,
+		  DBusMessageIter         *iter,
+		  GValue                  *value,
+		  GError                 **error)
+{
+  const char *objpath;
+  int current_type;
+  GObject *obj;
+
+  current_type = dbus_message_iter_get_arg_type (iter);
+  g_assert (current_type == DBUS_TYPE_OBJECT_PATH);
+  g_assert (context->proxy == NULL);
+
+  dbus_message_iter_get_basic (iter, &objpath);
+
+  obj = dbus_g_connection_lookup_g_object (context->gconnection, objpath);
+  if (obj == NULL)
+    {
+      g_set_error (error,
+		   DBUS_GERROR,
+		   DBUS_GERROR_INVALID_ARGS,
+		   _("Unregistered object at path '%s'"),
+		   objpath);
+      return FALSE;
+    }
+  g_value_set_object (value, obj);
+
+  return TRUE;
+}
+
+static gboolean
+demarshal_strv (DBusGValueMarshalCtx    *context,
+		DBusMessageIter         *iter,
+		GValue                  *value,
+		GError                 **error)
+{
+  DBusMessageIter subiter;
+  int current_type;
+  char **ret;
+  int len;
+  int i;
+
+  dbus_message_iter_recurse (iter, &subiter);
+
+  len = dbus_message_iter_get_array_len (&subiter);
+  g_assert (len >= 0);
+  ret = g_malloc (sizeof (char *) * (len + 1));
+  
+  i = 0;
+  while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+    {
+      g_assert (i < len);
+      g_assert (current_type == DBUS_TYPE_STRING);
+      
+      dbus_message_iter_get_basic (&subiter, &(ret[i]));
+      ret[i] = g_strdup (ret[i]);
+
+      dbus_message_iter_next (&subiter);
+      i++;
+    }
+  ret[i] = NULL; 
+  g_value_set_boxed_take_ownership (value, ret);
+  
+  return TRUE;
+}
+
+static gboolean
+demarshal_garray_basic (DBusGValueMarshalCtx    *context,
+			DBusMessageIter         *iter,
+			GValue                  *value,
+			GError                 **error)
+{
+  DBusMessageIter subiter;
+  GArray *ret;
+  GType elt_gtype;
+  int elt_size;
+  void *msgarray;
+  int msgarray_len;
+
+  dbus_message_iter_recurse (iter, &subiter);
+
+  elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value));
+  g_assert (elt_gtype != G_TYPE_INVALID);
+  g_assert (dbus_g_type_is_fixed (elt_gtype));
+
+  elt_size = dbus_g_type_fixed_get_size (elt_gtype);
+  
+  ret = g_array_new (FALSE, TRUE, elt_size);
+
+  msgarray = NULL;
+  dbus_message_iter_get_fixed_array (&subiter,
+				     &msgarray,
+				     &msgarray_len);
+  g_assert (msgarray != NULL);
+  g_assert (msgarray_len >= 0);
+  g_array_append_vals (ret, msgarray, (guint) msgarray_len);
+
+  g_value_set_boxed_take_ownership (value, ret);
+  
+  return TRUE;
+}
+
+static gboolean
+demarshal_proxy_array (DBusGValueMarshalCtx    *context,
+		       DBusMessageIter         *iter,
+		       GValue                  *value,
+		       GError                 **error)
+{
+  DBusMessageIter subiter;
+  GPtrArray *ret;
+  guint len;
+  guint i;
+  int current_type;
+
+  g_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY);
+
+  dbus_message_iter_recurse (iter, &subiter);
+
+  len = dbus_message_iter_get_array_len (&subiter);
+  g_assert (len >= 0);
+  ret = g_ptr_array_sized_new (len);
+  
+  i = 0;
+  while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+    {
+      GValue subval = {0, };
+      g_assert (i < len);
+
+      if (!demarshal_proxy (context, &subiter, &subval, error))
+	{
+	  for (i = 0; i < ret->len; i++)
+	    g_object_unref (g_ptr_array_index (ret, i));
+	  g_ptr_array_free (ret, TRUE);
+	  return FALSE;
+	}
+
+      g_ptr_array_index (ret, i) = g_value_get_boxed (&subval);
+      /* Don't unset value, now owned by ret */
+
+      i++;
+    }
+  g_value_set_boxed_take_ownership (value, ret);
+  
+  return TRUE;
+}
+
+static gboolean
+demarshal_ghashtable (DBusGValueMarshalCtx    *context,
+		      DBusMessageIter         *iter,
+		      GValue                  *value,
+		      GError                 **error)
+{
+  GType gtype;
+  DBusMessageIter subiter;
+  int current_type;
+  GHashTable *ret;
+  GType key_gtype;
+  GType value_gtype;
+
+  current_type = dbus_message_iter_get_arg_type (iter);
+  g_assert (current_type == DBUS_TYPE_ARRAY);
+
+  gtype = G_VALUE_TYPE (value);
+
+  dbus_message_iter_recurse (iter, &subiter);
+
+  g_assert (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_DICT_ENTRY);
+
+  key_gtype = dbus_g_type_get_map_key_specialization (gtype);
+  g_assert (dbus_gtype_is_valid_hash_key (key_gtype));
+  value_gtype = dbus_g_type_get_map_value_specialization (gtype);
+  g_assert (dbus_gtype_is_valid_hash_value (value_gtype));
+
+  ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype),
+			       dbus_g_hash_equal_from_gtype (key_gtype),
+			       dbus_g_hash_free_from_gtype (key_gtype),
+			       dbus_g_hash_free_from_gtype (value_gtype));
+
+  while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID)
+    {
+      DBusMessageIter entry_iter;
+      GValue key_value = {0,};
+      GValue value_value = {0,};
+
+      current_type = dbus_message_iter_get_arg_type (&subiter);
+      g_assert (current_type == DBUS_TYPE_DICT_ENTRY);
+
+      dbus_message_iter_recurse (&subiter, &entry_iter);
+
+      g_value_init (&key_value, key_gtype);
+      if (!dbus_gvalue_demarshal (context,
+				  &entry_iter,
+				  &key_value,
+				  error))
+	return FALSE;
+
+      dbus_message_iter_next (&entry_iter);
+
+      g_value_init (&value_value, value_gtype);
+      if (!dbus_gvalue_demarshal (context,
+				  &entry_iter,
+				  &value_value,
+				  error))
+	return FALSE;
+
+      dbus_g_hash_table_insert_steal_values (ret,
+					     &key_value,
+					     &value_value);
+      /* Ownership of values passes to hash table, don't unset */
+
+      dbus_message_iter_next (&subiter);
+    }
+  g_value_set_boxed_take_ownership (value, ret);
+  
+  return TRUE;
+}
+
+static gboolean
+demarshal_recurse (DBusGValueMarshalCtx    *context,
+		   DBusMessageIter         *iter,
+		   GValue                  *value,
+		   GError                 **error)
+{
+  return FALSE;
+}
+
 gboolean
-dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
+dbus_gvalue_demarshal (DBusGValueMarshalCtx    *context,
+		       DBusMessageIter         *iter,
+		       GValue                  *value,
+		       GError                 **error)
+{
+  GType gtype;
+  DBusGTypeMarshalData *typedata;
+
+  gtype = G_VALUE_TYPE (value);
+
+  typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+  g_return_val_if_fail (typedata != NULL || g_type_is_a (gtype, DBUS_TYPE_G_VALUE), FALSE);
+
+  if (typedata == NULL)
+    {
+      if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE))
+	return demarshal_recurse (context, iter, value, error);
+      g_assert_not_reached ();
+    }
+  g_assert (typedata->vtable);
+  return typedata->vtable->demarshaller (context, iter, value, error);
+}
+
+gboolean
+dbus_gvalue_demarshal_variant (DBusGValueMarshalCtx    *context,
+			       DBusMessageIter         *iter,
+			       GValue                  *value,
+			       GError                 **error)
+{
+  return demarshal_static_variant (context, iter, value, error);
+}
+
+GValueArray *
+dbus_gvalue_demarshal_message  (DBusGValueMarshalCtx    *context,
+				DBusMessage             *message,
+				guint                    n_types,
+				const GType             *types,
+				GError                 **error)
+{
+  GValueArray *ret;
+  DBusMessageIter iter;
+  int current_type;
+  guint index;
+  
+  ret = g_value_array_new (6);  /* 6 is a typical maximum for arguments */
+
+  dbus_message_iter_init (message, &iter);
+  index = 0;
+  while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+    {
+      GValue *value;
+      GType gtype;
+
+      if (index >= n_types)
+	{
+	  g_set_error (error, DBUS_GERROR,
+		       DBUS_GERROR_INVALID_ARGS,
+		       _("Too many arguments in message"));
+	  goto lose;
+	}
+      
+      g_value_array_append (ret, NULL);
+      value = g_value_array_get_nth (ret, index);
+
+      gtype = types[index]; 
+      g_value_init (value, gtype);
+
+      if (!dbus_gvalue_demarshal (context, &iter, value, error))
+	goto lose;
+      dbus_message_iter_next (&iter);
+      index++;
+    }
+  if (index < n_types)
+    {
+      g_set_error (error, DBUS_GERROR,
+		   DBUS_GERROR_INVALID_ARGS,
+		   _("Too few arguments in message"));
+      goto lose;
+    }
+
+  return ret;
+ lose:
+  g_value_array_free (ret);
+  return NULL;
+}
+
+static gboolean
+marshal_basic (DBusMessageIter *iter, GValue *value)
 {
   GType value_type;
 
@@ -353,9 +1214,6 @@
           goto nomem;
       }
       return TRUE;
-      /* long gets cut to 32 bits so the remote API is consistent
-       * on all architectures
-       */
     case G_TYPE_LONG:
       {
         dbus_int32_t v = g_value_get_long (value);
@@ -424,9 +1282,10 @@
       return TRUE;
       
     default:
-      /* FIXME: we need to define custom boxed types for arrays
-	 etc. so we can map them transparently / pleasantly */
-      return FALSE;
+      {
+	g_assert_not_reached ();
+	return FALSE;
+      }
     }
 
  nomem:
@@ -434,49 +1293,320 @@
   return FALSE;
 }
 
-/* FIXME is there a better way to do this? */
+static gboolean
+marshal_strv (DBusMessageIter   *iter,
+	      GValue             *value)
+{
+  DBusMessageIter subiter;
+  char **array;
+  char **elt;
+  gboolean ret;
+
+  g_assert (G_VALUE_TYPE (value) == g_strv_get_type ());
+
+  array = g_value_get_boxed (value);
+
+  if (!dbus_message_iter_open_container (iter,
+					 DBUS_TYPE_ARRAY,
+					 "s",
+					 &subiter))
+    goto out;
+
+  for (elt = array; *elt; elt++)
+    {
+      if (!dbus_message_iter_append_basic (&subiter,
+					   DBUS_TYPE_STRING,
+					   elt))
+	goto out;
+    }
+
+  if (!dbus_message_iter_close_container (iter, &subiter))
+    goto out;
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+static gboolean
+marshal_garray_basic (DBusMessageIter   *iter,
+		      GValue            *value)
+{
+  GType elt_gtype;
+  DBusMessageIter subiter;
+  GArray *array;
+  guint elt_size;
+  const char *subsignature_str;
+  gboolean ret;
+
+  elt_gtype = dbus_g_type_get_collection_specialization (G_VALUE_TYPE (value));
+  /* FIXME - this means we can't send an array of DBusGValue right now... */
+  subsignature_str = dbus_gtype_to_signature (elt_gtype);
+  g_assert (subsignature_str != NULL);
+  
+  elt_size = dbus_g_type_fixed_get_size (elt_gtype);
+
+  array = g_value_get_boxed (value);
+
+  if (!dbus_message_iter_open_container (iter,
+					 DBUS_TYPE_ARRAY,
+					 subsignature_str,
+					 &subiter))
+    goto out;
+
+  /* TODO - This assumes that basic values are the same size
+   * is this always true?  If it is we can probably avoid
+   * a lot of the overhead in _marshal_basic_instance...
+   */
+  if (!dbus_message_iter_append_fixed_array (&subiter,
+					     subsignature_str[0],
+					     &(array->data),
+					     array->len))
+    goto out;
+
+  if (!dbus_message_iter_close_container (iter, &subiter))
+    goto out;
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+static gboolean
+marshal_proxy (DBusMessageIter         *iter,
+	       GValue                  *value)
+{
+  const char *path;
+  DBusGProxy *proxy;
+
+  g_assert (G_VALUE_TYPE (value) == dbus_g_proxy_get_type ());
+
+  proxy = g_value_get_object (value);
+  path = dbus_g_proxy_get_path (proxy);
+  
+  if (!dbus_message_iter_append_basic (iter,
+				       DBUS_TYPE_OBJECT_PATH,
+				       &path))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+marshal_object (DBusMessageIter         *iter,
+		GValue                  *value)
+{
+  const char *path;
+  GObject *obj;
+
+  obj = g_value_get_object (value);
+  path = _dbus_gobject_get_path (obj);
+
+  if (path == NULL)
+    /* FIXME should throw error */
+    return FALSE;
+  
+  if (!dbus_message_iter_append_basic (iter,
+				       DBUS_TYPE_OBJECT_PATH,
+				       &path))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+marshal_proxy_array (DBusMessageIter   *iter,
+		     GValue            *value)
+{
+  DBusMessageIter subiter;
+  GPtrArray *array;
+  const char *subsignature_str;
+  gboolean ret;
+  guint i;
+
+  subsignature_str = dbus_gtype_to_signature (DBUS_TYPE_G_PROXY);
+  g_assert (subsignature_str != NULL);
+
+  array = g_value_get_boxed (value);
+
+  if (!dbus_message_iter_open_container (iter,
+					 DBUS_TYPE_ARRAY,
+					 subsignature_str,
+					 &subiter))
+    goto out;
+
+  for (i = 0; i < array->len; i++)
+    {
+      GValue val = {0, };
+
+      g_value_init (&val, DBUS_TYPE_G_PROXY);
+      g_value_set_static_boxed (&val, g_ptr_array_index (array, i));
+
+      marshal_proxy (&subiter, &val);
+
+      g_value_unset (&val);
+    }
+
+  if (!dbus_message_iter_close_container (iter, &subiter))
+    goto out;
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+struct DBusGLibHashMarshalData
+{
+  const char *entry_sig;
+  DBusMessageIter *iter;
+  gboolean err;
+};
+
+static void
+marshal_map_entry (const GValue *key,
+		   const GValue *value,
+		   gpointer data)
+{
+  struct DBusGLibHashMarshalData *hashdata = data;
+  DBusMessageIter subiter;
+
+  if (hashdata->err)
+    return;
+
+  if (!dbus_message_iter_open_container (hashdata->iter,
+					 DBUS_TYPE_DICT_ENTRY,
+					 NULL,
+					 &subiter))
+    goto lose;
+
+  if (!dbus_gvalue_marshal (&subiter, (GValue*) key))
+    goto lose;
+
+  if (!dbus_gvalue_marshal (&subiter, (GValue*) value))
+    goto lose;
+
+  if (!dbus_message_iter_close_container (hashdata->iter, &subiter))
+    goto lose;
+  
+  return;
+ lose:
+  hashdata->err = TRUE;
+}
+
+static gboolean
+marshal_map (DBusMessageIter   *iter,
+	     GValue            *value)
+{
+  GType gtype;
+  DBusMessageIter arr_iter;
+  gboolean ret;
+  struct DBusGLibHashMarshalData hashdata;
+  GType key_type;
+  GType value_type;
+  const char *key_sig;
+  const char *value_sig;
+  char *entry_sig;
+  char *array_sig;
+
+  gtype = G_VALUE_TYPE (value);
+
+  ret = FALSE;
+
+  key_type = dbus_g_type_get_map_key_specialization (gtype);
+  g_assert (dbus_gtype_is_valid_hash_key (key_type));
+  value_type = dbus_g_type_get_map_value_specialization (gtype);
+  g_assert (dbus_gtype_is_valid_hash_value (value_type));
+
+  key_sig = dbus_gtype_to_signature (key_type);
+  value_sig = dbus_gtype_to_signature (value_type);
+  entry_sig = g_strdup_printf ("%s%s", key_sig, value_sig);
+  array_sig = g_strdup_printf ("%c%s%c",
+			       DBUS_DICT_ENTRY_BEGIN_CHAR,
+			       entry_sig,
+			       DBUS_DICT_ENTRY_END_CHAR);
+  if (!dbus_message_iter_open_container (iter,
+					 DBUS_TYPE_ARRAY,
+					 array_sig,
+					 &arr_iter))
+    goto lose;
+
+  hashdata.iter = &arr_iter;
+  hashdata.err = FALSE;
+  hashdata.entry_sig = entry_sig;
+
+  dbus_g_type_map_value_iterate (value,
+				 marshal_map_entry,
+				 &hashdata);
+
+  if (!dbus_message_iter_close_container (iter, &arr_iter))
+    goto lose;
+
+ out:
+  g_free (entry_sig);
+  g_free (array_sig);
+  return !hashdata.err;
+ lose:
+  hashdata.err = TRUE;
+  goto out;
+}
+
+static gboolean
+marshal_variant (DBusMessageIter          *iter,
+		 GValue                   *value)
+{
+  GType value_gtype;
+  DBusMessageIter subiter;
+  char *variant_sig;
+  GValue *real_value;
+  gboolean ret;
+
+  real_value = g_value_get_boxed (value);
+  value_gtype = G_VALUE_TYPE (real_value);
+
+  variant_sig = dbus_gvalue_to_signature (real_value);
+  if (variant_sig == NULL)
+    {
+      g_warning ("Unsupported value type \"%s\"",
+		 g_type_name (value_gtype));
+      return FALSE;
+    }
+
+  if (!dbus_message_iter_open_container (iter,
+					 DBUS_TYPE_VARIANT,
+					 variant_sig,
+					 &subiter))
+    goto out;
+
+  if (!marshal_basic (&subiter, real_value))
+    goto out;
+
+  if (!dbus_message_iter_close_container (iter, &subiter))
+    goto out;
+
+  ret = TRUE;
+ out:
+  g_free (variant_sig);
+  return ret;
+}
+
+static gboolean
+marshal_recurse (DBusMessageIter         *iter,
+		 GValue                  *value)
+{
+  return FALSE;
+}
+
 gboolean
-dbus_gvalue_store (GValue          *value,
-		   gpointer        storage)
+dbus_gvalue_marshal (DBusMessageIter         *iter,
+		     GValue                  *value)
 {
-  switch (G_VALUE_TYPE (value))
+  GType gtype;
+  DBusGTypeMarshalData *typedata;
+
+  gtype = G_VALUE_TYPE (value);
+
+  typedata = g_type_get_qdata (gtype, dbus_g_type_metadata_data_quark ());
+  if (typedata == NULL)
     {
-    case G_TYPE_CHAR:
-      *((gchar *) storage) = g_value_get_char (value);
-      return TRUE;
-    case G_TYPE_UCHAR:
-      *((guchar *) storage) = g_value_get_uchar (value);
-      return TRUE;
-    case G_TYPE_BOOLEAN:
-      *((gboolean *) storage) = g_value_get_boolean (value);
-      return TRUE;
-    case G_TYPE_LONG:
-      *((glong *) storage) = g_value_get_long (value);
-      return TRUE;
-    case G_TYPE_ULONG:
-      *((gulong *) storage) = g_value_get_ulong (value);
-      return TRUE;
-    case G_TYPE_INT:
-      *((gint *) storage) = g_value_get_int (value);
-      return TRUE;
-    case G_TYPE_UINT:
-      *((guint *) storage) = g_value_get_uint (value);
-      return TRUE;
-    case G_TYPE_INT64:
-      *((gint64 *) storage) = g_value_get_int64 (value);
-      return TRUE;
-    case G_TYPE_UINT64:
-      *((guint64 *) storage) = g_value_get_uint64 (value);
-      return TRUE;
-    case G_TYPE_FLOAT:
-    case G_TYPE_DOUBLE:
-      *((gdouble *) storage) = g_value_get_double (value);
-      return TRUE;
-    case G_TYPE_STRING:
-      /* FIXME - should optimize by not duping string twice */
-      *((gchar **) storage) = g_value_dup_string (value);
-      return TRUE;
-    default:
+      if (g_type_is_a (gtype, DBUS_TYPE_G_VALUE))
+	return marshal_recurse (iter, value);
       return FALSE;
     }
+  g_assert (typedata->vtable);
+  return typedata->vtable->marshaller (iter, value);
 }

--- NEW FILE: dbus-gvalue-utils.h ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gvalue-utils.h: Non-DBus-specific functions related to GType/GValue
 *
 * Copyright (C) 2005 Red Hat, Inc.
 *
 * Licensed under the Academic Free License version 2.1
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef DBUS_GOBJECT_VALUE_UTILS_H
#define DBUS_GOBJECT_VALUE_UTILS_H

#include <glib.h>
#include <glib-object.h>

G_BEGIN_DECLS

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); 

gboolean       dbus_gvalue_set_from_pointer          (GValue *value,
						      gconstpointer storage);

typedef void (*DBusGHashValueForeachFunc) (GValue * key, GValue *val, gpointer data);

void           dbus_g_hash_table_value_foreach       (GHashTable                *table,
						      GType                      hash_type,
						      DBusGHashValueForeachFunc  func,
						      gpointer                   data);

void           dbus_g_hash_table_insert_values       (GHashTable                *table,
						      GValue                    *key_val,
						      GValue                    *value_val);
void           dbus_g_hash_table_insert_steal_values (GHashTable *table,
						      GValue     *key_val,
						      GValue     *value_val);

gboolean       dbus_gtype_is_valid_hash_key          (GType type);
gboolean       dbus_gtype_is_valid_hash_value        (GType type);

GHashFunc      dbus_g_hash_func_from_gtype           (GType gtype);
GEqualFunc     dbus_g_hash_equal_from_gtype          (GType gtype);
GDestroyNotify dbus_g_hash_free_from_gtype           (GType gtype);

gboolean       dbus_gvalue_store                     (GValue          *value,
						      gpointer         storage);

gboolean       dbus_gvalue_take                      (GValue          *value,
						      GTypeCValue     *cvalue);


G_END_DECLS

#endif

--- NEW FILE: dbus-gvalue-utils.c ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue 
 *
 * Copyright (C) 2005 Red Hat, Inc.
 *
 * Licensed under the Academic Free License version 2.1
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "dbus/dbus-glib.h"
#include "dbus-gvalue-utils.h"
#include <glib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>


static guint
fixed_type_get_size (GType type)
{
  switch (type)
    {
    case G_TYPE_CHAR:
    case G_TYPE_UCHAR:
      return sizeof (gchar);
    case G_TYPE_BOOLEAN:
      return sizeof (gboolean);
    case G_TYPE_LONG:
    case G_TYPE_ULONG:
      return sizeof (glong);
    case G_TYPE_INT:
    case G_TYPE_UINT:
      return sizeof (gint);
    case G_TYPE_INT64:
    case G_TYPE_UINT64:
      return sizeof (gint64);
    case G_TYPE_FLOAT:
      return sizeof (gfloat);
    case G_TYPE_DOUBLE:
      return sizeof (gdouble);
    default:
      return 0;
    }
}

gboolean
dbus_g_type_is_fixed (GType type)
{
  return fixed_type_get_size (type) > 0;
}

guint
dbus_g_type_fixed_get_size (GType type)
{
  g_assert (dbus_g_type_is_fixed (type));
  return fixed_type_get_size (type);
}

gboolean
dbus_gvalue_store (GValue          *value,
		   gpointer        storage)
{
  /* FIXME - can we use the GValue lcopy_value method
   * to do this in a cleaner way?
   */
  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    {
    case G_TYPE_CHAR:
      *((gchar *) storage) = g_value_get_char (value);
      return TRUE;
    case G_TYPE_UCHAR:
      *((guchar *) storage) = g_value_get_uchar (value);
      return TRUE;
    case G_TYPE_BOOLEAN:
      *((gboolean *) storage) = g_value_get_boolean (value);
      return TRUE;
    case G_TYPE_LONG:
      *((glong *) storage) = g_value_get_long (value);
      return TRUE;
    case G_TYPE_ULONG:
      *((gulong *) storage) = g_value_get_ulong (value);
      return TRUE;
    case G_TYPE_INT:
      *((gint *) storage) = g_value_get_int (value);
      return TRUE;
    case G_TYPE_UINT:
      *((guint *) storage) = g_value_get_uint (value);
      return TRUE;
    case G_TYPE_INT64:
      *((gint64 *) storage) = g_value_get_int64 (value);
      return TRUE;
    case G_TYPE_UINT64:
      *((guint64 *) storage) = g_value_get_uint64 (value);
      return TRUE;
    case G_TYPE_DOUBLE:
      *((gdouble *) storage) = g_value_get_double (value);
      return TRUE;
    case G_TYPE_STRING:
      *((gchar **) storage) = (char*) g_value_get_string (value);
      return TRUE;
    case G_TYPE_POINTER:
      *((gpointer *) storage) = g_value_get_pointer (value);
      return TRUE;
    case G_TYPE_OBJECT:
      *((gpointer *) storage) = g_value_get_object (value);
      return TRUE;
    case G_TYPE_BOXED:
      *((gpointer *) storage) = g_value_get_boxed (value);
      return TRUE;
    default:
      return FALSE;
    }
}

gboolean
dbus_gvalue_set_from_pointer (GValue          *value,
			      gconstpointer    storage)
{
  /* FIXME - is there a better way to do this? */
  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    {
    case G_TYPE_CHAR:
      g_value_set_char (value, *((gchar *) storage));
      return TRUE;
    case G_TYPE_UCHAR:
      g_value_set_uchar (value, *((guchar *) storage));
      return TRUE;
    case G_TYPE_BOOLEAN:
      g_value_set_boolean (value, *((gboolean *) storage));
      return TRUE;
    case G_TYPE_LONG:
      g_value_set_long (value, *((glong *) storage));
      return TRUE;
    case G_TYPE_ULONG:
      g_value_set_ulong (value, *((gulong *) storage));
      return TRUE;
    case G_TYPE_INT:
      g_value_set_int (value, *((gint *) storage));
      return TRUE;
    case G_TYPE_UINT:
      g_value_set_uint (value, *((guint *) storage));
      return TRUE;
    case G_TYPE_INT64:
      g_value_set_int64 (value, *((gint64 *) storage));
      return TRUE;
    case G_TYPE_UINT64:
      g_value_set_uint64 (value, *((guint64 *) storage));
      return TRUE;
    case G_TYPE_DOUBLE:
      g_value_set_double (value, *((gdouble *) storage));
      return TRUE;
    case G_TYPE_STRING:
      g_value_set_string (value, *((gchar **) storage));
      return TRUE;
    case G_TYPE_POINTER:
      g_value_set_pointer (value, *((gpointer *) storage));
      return TRUE;
    case G_TYPE_OBJECT:
      g_value_set_object (value, *((gpointer *) storage));
      return TRUE;
    case G_TYPE_BOXED:
      g_value_set_boxed (value, *((gpointer *) storage));
      return TRUE;
    default:
      return FALSE;
    }
}

gboolean
dbus_gvalue_take (GValue          *value,
		  GTypeCValue     *cvalue)
{
  GType g_type;
  GTypeValueTable *value_table;
  char *error_msg;

  g_type = G_VALUE_TYPE (value);
  value_table = g_type_value_table_peek (g_type);

  error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS);
  if (error_msg)
    {
      g_warning ("%s: %s", G_STRLOC, error_msg);
      g_free (error_msg);
      return FALSE;
    }
  /* Clear the NOCOPY_CONTENTS flag; we want to take ownership
   * of the value.
   */
  value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS);
  return TRUE;
}

static gboolean
hash_func_from_gtype (GType gtype, GHashFunc *func)
{
  switch (gtype)
    {
    case G_TYPE_CHAR:
    case G_TYPE_UCHAR:
    case G_TYPE_BOOLEAN:
    case G_TYPE_INT:
    case G_TYPE_UINT:
      *func = NULL;
      return TRUE;
    case G_TYPE_STRING:
      *func = g_str_hash;
      return TRUE;
    default:
      return FALSE;
    }
}

static gboolean
hash_free_from_gtype (GType gtype, GDestroyNotify *func)
{
  switch (gtype)
    {
    case G_TYPE_CHAR:
    case G_TYPE_UCHAR:
    case G_TYPE_BOOLEAN:
    case G_TYPE_INT:
    case G_TYPE_UINT:
      *func = NULL;
      return TRUE;
    case G_TYPE_STRING:
      *func = g_free;
      return TRUE;
    default:
      if (gtype == G_TYPE_VALUE)
	{
	  *func = (GDestroyNotify) g_value_unset;
	  return TRUE;
	}
      return FALSE;
    }
}

gboolean
dbus_gtype_is_valid_hash_key (GType type)
{
  GHashFunc func;
  return hash_func_from_gtype (type, &func);
}

gboolean
dbus_gtype_is_valid_hash_value (GType type)
{
  GDestroyNotify func;
  return hash_free_from_gtype (type, &func);
}

GHashFunc
dbus_g_hash_func_from_gtype (GType gtype)
{
  GHashFunc func;
  gboolean ret;
  ret = hash_func_from_gtype (gtype, &func);
  g_assert (ret != FALSE);
  return func;
}

GEqualFunc
dbus_g_hash_equal_from_gtype (GType gtype)
{
  g_assert (dbus_gtype_is_valid_hash_key (gtype));

  switch (gtype)
    {
    case G_TYPE_CHAR:
    case G_TYPE_UCHAR:
    case G_TYPE_BOOLEAN:
    case G_TYPE_INT:
    case G_TYPE_UINT:
      return NULL;
    case G_TYPE_STRING:
      return g_str_equal;
    default:
      g_assert_not_reached ();
      return NULL;
    }
}

GDestroyNotify
dbus_g_hash_free_from_gtype (GType gtype)
{
  GDestroyNotify func;
  gboolean ret;
  ret = hash_free_from_gtype (gtype, &func);
  g_assert (ret != FALSE);
  return func;
}

static void
gvalue_from_hash_value (GValue *value, gpointer instance)
{
  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    {
    case G_TYPE_CHAR:
      g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance));
      break;
    case G_TYPE_UCHAR:
      g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance));
      break;
    case G_TYPE_BOOLEAN:
      g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance));
      break;
    case G_TYPE_INT:
      g_value_set_int (value, GPOINTER_TO_INT (instance));
      break;
    case G_TYPE_UINT:
      g_value_set_uint (value, GPOINTER_TO_UINT (instance));
      break;
    case G_TYPE_STRING:
      g_value_set_static_string (value, instance);
      break;
    case G_TYPE_POINTER:
      g_value_set_pointer (value, instance);
      break;
    case G_TYPE_BOXED:
      g_value_set_static_boxed (value, instance);
      break;
    case G_TYPE_OBJECT:
      g_value_set_object (value, instance);
      g_object_unref (g_value_get_object (value));
      break;
    default:
      g_assert_not_reached ();
      break;
    }
}

static gpointer
hash_value_from_gvalue (GValue *value)
{
  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    {
    case G_TYPE_CHAR:
      return GINT_TO_POINTER ((int) g_value_get_char (value));
      break;
    case G_TYPE_UCHAR:
      return GUINT_TO_POINTER ((guint) g_value_get_uchar (value));
      break;
    case G_TYPE_BOOLEAN:
      return GUINT_TO_POINTER ((guint) g_value_get_boolean (value));
      break;
    case G_TYPE_INT:
      return GINT_TO_POINTER (g_value_get_int (value));
      break;
    case G_TYPE_UINT:
      return GUINT_TO_POINTER (g_value_get_uint (value));
      break;
    case G_TYPE_STRING:
      return (gpointer) g_value_get_string (value);
      break;
    case G_TYPE_POINTER:
      return g_value_get_pointer (value);
      break;
    case G_TYPE_BOXED:
      return g_value_get_boxed (value);
      break;
    case G_TYPE_OBJECT:
      return g_value_get_object (value);
      break;
    default:
      g_assert_not_reached ();
      return NULL;
    }
}

struct DBusGHashTableValueForeachData
{
  DBusGTypeSpecializedMapIterator func;
  GType key_type;
  GType value_type;
  gpointer data;
};

static void
hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data)
{
  GValue key_val = {0, };
  GValue value_val = {0, };
  struct DBusGHashTableValueForeachData *data = user_data;
  
  g_value_init (&key_val, data->key_type);
  g_value_init (&value_val, data->value_type);
  gvalue_from_hash_value (&key_val, key);
  gvalue_from_hash_value (&value_val, value);

  data->func (&key_val, &value_val, data->data);
}


static void
hashtable_iterator (GType                           hash_type,
		    gpointer                        instance,
		    DBusGTypeSpecializedMapIterator iterator,
		    gpointer                        user_data)
{
  struct DBusGHashTableValueForeachData data;
  GType key_gtype;
  GType value_gtype;

  key_gtype = dbus_g_type_get_map_key_specialization (hash_type);
  value_gtype = dbus_g_type_get_map_value_specialization (hash_type);

  data.func = iterator;
  data.key_type = key_gtype;
  data.value_type = value_gtype;
  data.data = user_data;

  g_hash_table_foreach (instance, hashtable_foreach_with_values, &data);
}

void
dbus_g_hash_table_insert_steal_values (GHashTable *table,
				       GValue     *key_val,
				       GValue     *value_val)
{
  gpointer key, val;
  
  key = hash_value_from_gvalue (key_val);
  val = hash_value_from_gvalue (value_val);

  g_hash_table_insert (table, key, val);
}

static gpointer
hashtable_constructor (GType type)
{
  GHashTable *ret;
  GType key_gtype;
  GType value_gtype;

  key_gtype = dbus_g_type_get_map_key_specialization (type);
  value_gtype = dbus_g_type_get_map_value_specialization (type);

  ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype),
			       dbus_g_hash_equal_from_gtype (key_gtype),
			       dbus_g_hash_free_from_gtype (key_gtype),
			       dbus_g_hash_free_from_gtype (value_gtype));
  return ret;
}

static void
hashtable_insert_values (GHashTable       *table,
			 const GValue     *key_val,
			 const GValue     *value_val)
{
  GValue key_copy = {0, };
  GValue value_copy = {0, };

  g_value_init (&key_copy, G_VALUE_TYPE (key_val));
  g_value_copy (key_val, &key_copy);
  g_value_init (&value_copy, G_VALUE_TYPE (value_val));
  g_value_copy (value_val, &value_copy);
  
  dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy);
}

static void
hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data)
{
  hashtable_insert_values ((GHashTable *) data, key, val);
}

static gpointer
hashtable_copy (GType type, gpointer src)
{
  GHashTable *ghash;
  GHashTable *ret;
  GValue hashval = {0,};

  ghash = src;

  ret = hashtable_constructor (type);

  g_value_init (&hashval, type);
  g_value_set_static_boxed (&hashval, ghash); 
  dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret);
  return ret;
}

static void
hashtable_free (GType type, gpointer val)
{
  g_hash_table_destroy (val);
}

static gpointer
array_constructor (GType type)
{
  GArray *array;
  guint elt_size;
  GType elt_type;
  gboolean zero_terminated;
  gboolean clear;

  elt_type = dbus_g_type_get_collection_specialization (type);
  g_assert (elt_type != G_TYPE_INVALID);

  elt_size = dbus_g_type_fixed_get_size (elt_type);

  /* These are "safe" defaults */ 
  zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */
  clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */

  array = g_array_new (zero_terminated, clear, elt_size);
  return array;
}

static gpointer
array_copy (GType type, gpointer src)
{
  GArray *garray;
  GArray *new;

  garray = src;

  new = array_constructor (type);
  g_array_append_vals (new, garray->data, garray->len);

  return new;
}

static void
array_free (GType type, gpointer val)
{
  GArray *array;
  array = val;
  g_array_free (array, TRUE);
}

static gboolean
array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len)
{
  GType elt_type;
  GArray *array = instance;

  elt_type = dbus_g_type_get_collection_specialization (type);
  if (!dbus_g_type_is_fixed (elt_type))
    return FALSE;

  *values = array->data;
  *len = array->len;
  return TRUE;
}

static gpointer
ptrarray_constructor (GType type)
{
  /* Later we should determine a destructor, need g_ptr_array_destroy */
  return g_ptr_array_new ();
}

static void
gvalue_from_ptrarray_value (GValue *value, gpointer instance)
{
  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    {
    case G_TYPE_POINTER:
      g_value_set_pointer (value, instance);
      break;
    case G_TYPE_BOXED:
      g_value_set_static_boxed (value, instance);
      break;
    case G_TYPE_OBJECT:
      g_value_set_object (value, instance);
      g_object_unref (g_value_get_object (value));
      break;
    default:
      g_assert_not_reached ();
      break;
    }
}

static gpointer
ptrarray_value_from_gvalue (const GValue *value)
{
  switch (g_type_fundamental (G_VALUE_TYPE (value)))
    {
    case G_TYPE_POINTER:
      return g_value_get_pointer (value);
      break;
    case G_TYPE_BOXED:
      return g_value_get_boxed (value);
      break;
    case G_TYPE_OBJECT:
      return g_value_get_object (value);
      break;
    default:
      g_assert_not_reached ();
      return NULL;
    }
}

static void
ptrarray_iterator (GType                                   hash_type,
		   gpointer                                instance,
		   DBusGTypeSpecializedCollectionIterator  iterator,
		   gpointer                                user_data)
{
  GPtrArray *ptrarray;
  GType elt_gtype;
  guint i;

  ptrarray = instance;

  elt_gtype = dbus_g_type_get_collection_specialization (hash_type);

  for (i = 0; i < ptrarray->len; i++)
    {
      GValue val = {0, };
      g_value_init (&val, elt_gtype);
      gvalue_from_ptrarray_value (&val, g_ptr_array_index (ptrarray, i));
      iterator (&val, user_data);
    }
}

static void
ptrarray_copy_elt (const GValue *val, gpointer user_data)
{
  GPtrArray *dest = user_data;
  GValue val_copy = {0, }; 
  
  g_value_init (&val_copy, G_VALUE_TYPE (val));
  g_value_copy (val, &val_copy);

  g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy));
}

static gpointer
ptrarray_copy (GType type, gpointer src)
{
  GPtrArray *new;
  GValue array_val = {0, };

  g_value_init (&array_val, type);
  g_value_set_static_boxed (&array_val, src);

  new = ptrarray_constructor (type);
  dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new);

  return new;
}

static void
ptrarray_free (GType type, gpointer val)
{
  GArray *array;
  array = val;
  g_array_free (array, TRUE);
}

void
dbus_g_type_specialized_builtins_init (void)
{
  static const DBusGTypeSpecializedCollectionVtable array_vtable = {
    {
      array_constructor,
      array_free,
      array_copy,
      NULL,
      NULL,
      NULL
    },
    array_fixed_accessor,
    NULL
  };

  dbus_g_type_register_collection ("GArray", &array_vtable, 0);

  static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = {
    {
      ptrarray_constructor,
      ptrarray_free,
      ptrarray_copy,
      NULL,
      NULL,
      NULL
    },
    NULL,
    ptrarray_iterator
  };

  dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0);

  static const DBusGTypeSpecializedMapVtable hashtable_vtable = {
    {
      hashtable_constructor,
      hashtable_free,
      hashtable_copy,
      NULL,
      NULL,
      NULL
    },
    hashtable_iterator
  };

  dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0);
}

--- NEW FILE: dbus-gtype-specialized.h ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtype-specialized.h: Non-DBus-specific functions for specialized GTypes
 *
 * Copyright (C) 2005 Red Hat, Inc.
 *
 * Licensed under the Academic Free License version 2.1
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef DBUS_GOBJECT_TYPE_SPECIALIZED_H
#define DBUS_GOBJECT_TYPE_SPECIALIZED_H

#include <glib.h>
#include <glib-object.h>

G_BEGIN_DECLS

GType          dbus_g_type_get_collection                   (const char *container,
							     GType       specialization);
GType          dbus_g_type_get_map                          (const char *container,
							     GType       key_specialization,
							     GType       value_specialization);
gboolean       dbus_g_type_is_collection                    (GType       gtype);
gboolean       dbus_g_type_is_map                           (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);

typedef void   (*DBusGTypeSpecializedCollectionIterator)    (const GValue *val,
							     gpointer      user_data);
typedef void   (*DBusGTypeSpecializedMapIterator)           (const GValue *key_val,
							     const GValue *value_val,
							     gpointer      user_data);

gpointer       dbus_g_type_specialized_construct            (GType type);

gboolean       dbus_g_type_collection_get_fixed             (GValue                                 *value,
							     gpointer                               *data,
							     guint                                  *len);

void           dbus_g_type_collection_value_iterate         (GValue                                 *value,
							     DBusGTypeSpecializedCollectionIterator  iterator,
							     gpointer                                user_data);

void           dbus_g_type_map_value_iterate                (GValue                                 *value,
							     DBusGTypeSpecializedMapIterator         iterator,
							     gpointer                                user_data);

typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type);
typedef void     (*DBusGTypeSpecializedFreeFunc)    (GType type, gpointer val);
typedef gpointer (*DBusGTypeSpecializedCopyFunc)    (GType type, gpointer src);

typedef struct {
  DBusGTypeSpecializedConstructor    constructor;
  DBusGTypeSpecializedFreeFunc       free_func;
  DBusGTypeSpecializedCopyFunc       copy_func;
  gpointer                           padding1;
  gpointer                           padding2;
  gpointer                           padding3;
} DBusGTypeSpecializedVtable;

typedef gboolean (*DBusGTypeSpecializedCollectionFixedAccessorFunc) (GType type, gpointer instance, gpointer *values, guint *len);
typedef void (*DBusGTypeSpecializedCollectionIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data);

typedef struct {
  DBusGTypeSpecializedVtable                        base_vtable;
  DBusGTypeSpecializedCollectionFixedAccessorFunc   fixed_accessor;
  DBusGTypeSpecializedCollectionIteratorFunc        iterator;
} DBusGTypeSpecializedCollectionVtable;

typedef void (*DBusGTypeSpecializedMapIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedMapIterator iterator, gpointer user_data);

typedef struct {
  DBusGTypeSpecializedVtable                        base_vtable;
  DBusGTypeSpecializedMapIteratorFunc               iterator;
} DBusGTypeSpecializedMapVtable;

void           dbus_g_type_specialized_init           (void);

void           dbus_g_type_register_collection        (const char                                   *name,
						       const DBusGTypeSpecializedCollectionVtable   *vtable,
						       guint                                         flags);
  
void           dbus_g_type_register_map               (const char                                   *name,
						       const DBusGTypeSpecializedMapVtable          *vtable,
						       guint                                         flags);

G_END_DECLS

#endif

--- NEW FILE: dbus-gtype-specialized.c ---
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes
 *
 * Copyright (C) 2005 Red Hat, Inc.
 *
 * Licensed under the Academic Free License version 2.1
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "dbus-gtype-specialized.h"
#include <glib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>

typedef enum {
  DBUS_G_SPECTYPE_COLLECTION,
  DBUS_G_SPECTYPE_MAP
} DBusGTypeSpecializedType;

typedef struct {
  DBusGTypeSpecializedType type;
  const DBusGTypeSpecializedVtable     *vtable;
} DBusGTypeSpecializedContainer;

typedef struct {
  GType types[6];
  const DBusGTypeSpecializedContainer     *klass;
} DBusGTypeSpecializedData;

static GHashTable /* char * -> data* */ *specialized_containers;

static GQuark
specialized_type_data_quark ()
{
  static GQuark quark;
  if (!quark)
    quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
  
  return quark;
}

void
dbus_g_type_specialized_init (void)
{
  specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}

static gboolean
specialized_types_is_initialized (void)
{
  return specialized_containers != NULL;
}

static DBusGTypeSpecializedData *
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)
{
  value->data[0].v_pointer = NULL;
}

/* Adapted from gboxed.c */
static void
proxy_value_free (GValue *value)
{
  if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
    {
      DBusGTypeSpecializedData *data;
      GType type;

      type = G_VALUE_TYPE (value);
      data = lookup_specialization_data (type);
      g_assert (data != NULL);

      data->klass->vtable->free_func (type, value->data[0].v_pointer);
    }
}

/* Adapted from gboxed.c */
static void
proxy_value_copy (const GValue *src_value,
		  GValue       *dest_value)
{
  if (src_value->data[0].v_pointer)
    {
      DBusGTypeSpecializedData *data;
      GType type;
      type = G_VALUE_TYPE (src_value);
      data = lookup_specialization_data (type);
      g_assert (data != NULL);
      dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
    }
  else
    dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
}

/* Copied from gboxed.c */
static gpointer
proxy_value_peek_pointer (const GValue *value)
{
  return value->data[0].v_pointer;
}

/* Adapted from gboxed.c */
static gchar*
proxy_collect_value (GValue      *value,
		     guint        n_collect_values,
		     GTypeCValue *collect_values,
		     guint        collect_flags)
{
  DBusGTypeSpecializedData *data;
  GType type;

  type = G_VALUE_TYPE (value);
  data = lookup_specialization_data (type);

  if (!collect_values[0].v_pointer)
    value->data[0].v_pointer = NULL;
  else
    {
      if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
	{
	  value->data[0].v_pointer = collect_values[0].v_pointer;
	  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);
    }

  return NULL;
}

/* Adapted from gboxed.c */
static gchar*
proxy_lcopy_value (const GValue *value,
		   guint         n_collect_values,
		   GTypeCValue  *collect_values,
		   guint         collect_flags)
{
  gpointer *boxed_p = collect_values[0].v_pointer;

  if (!boxed_p)
    return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));

  if (!value->data[0].v_pointer)
    *boxed_p = NULL;
  else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
    *boxed_p = value->data[0].v_pointer;
  else
    {
      DBusGTypeSpecializedData *data;
      GType type;

      type = G_VALUE_TYPE (value);
      data = lookup_specialization_data (type);

      *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
    }

  return NULL;
}

static char *
build_specialization_name (const char *prefix, GType first_type, GType second_type)
{
  GString *fullname;

  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, '+');
      g_string_append (fullname, g_type_name (second_type));
    }
  return g_string_free (fullname, FALSE);
}

static void
register_container (const char                         *name,
		    DBusGTypeSpecializedType            type,
		    const DBusGTypeSpecializedVtable   *vtable)
{
  DBusGTypeSpecializedContainer *klass;
  
  klass = g_new0 (DBusGTypeSpecializedContainer, 1);
  klass->type = type;
  klass->vtable = vtable;

  g_hash_table_insert (specialized_containers, g_strdup (name), klass);
}

void
dbus_g_type_register_collection (const char                                   *name,
				 const DBusGTypeSpecializedCollectionVtable   *vtable,
				 guint                                         flags)
{
  g_return_if_fail (specialized_types_is_initialized ());
  register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
}

void
dbus_g_type_register_map (const char                            *name,
			  const DBusGTypeSpecializedMapVtable   *vtable,
			  guint                                  flags)
{
  g_return_if_fail (specialized_types_is_initialized ());
  register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
}

static GType
register_specialized_instance (const DBusGTypeSpecializedContainer   *klass,
			       char                                  *name,
			       GType                                  first_type,
			       GType                                  second_type)
{
  GType ret;
  
  static const GTypeValueTable vtable =
    {
      proxy_value_init,
      proxy_value_free,
      proxy_value_copy,
      proxy_value_peek_pointer,
      "p",
      proxy_collect_value,
      "p",
      proxy_lcopy_value,
    };
  static const GTypeInfo derived_info =
    {
      0,		/* class_size */
      NULL,		/* base_init */
      NULL,		/* base_finalize */
      NULL,		/* class_init */
      NULL,		/* class_finalize */
      NULL,		/* class_data */
      0,		/* instance_size */
      0,		/* n_preallocs */
      NULL,		/* instance_init */
      &vtable,		/* value_table */
    };

  ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
  /* install proxy functions upon successfull registration */
  if (ret != G_TYPE_INVALID)
    {
      DBusGTypeSpecializedData *data;
      data = g_new0 (DBusGTypeSpecializedData, 1);
      data->types[0] = first_type;
      data->types[1] = second_type;
      data->klass = klass;
      g_type_set_qdata (ret, specialized_type_data_quark (), data);
    }

  return ret;
}

static GType
lookup_or_register_specialized (const char  *container,
				GType       first_type,
				GType       second_type)
{
  GType ret;
  char *name;
  const DBusGTypeSpecializedContainer *klass;

  g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID);

  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);
  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);
    }
  else
    g_free (name);
  return ret;
}

GType
dbus_g_type_get_collection (const char *container,
			    GType       specialization)
{
  return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID);
}

GType
dbus_g_type_get_map (const char   *container,
		     GType         key_specialization,
		     GType         value_specialization)
{
  return lookup_or_register_specialized (container, key_specialization, value_specialization);
}

gboolean
dbus_g_type_is_collection (GType gtype)
{
  DBusGTypeSpecializedData *data;
  data = lookup_specialization_data (gtype);
  if (data == NULL)
    return FALSE;
  return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
}

gboolean
dbus_g_type_is_map (GType gtype)
{
  DBusGTypeSpecializedData *data;
  data = lookup_specialization_data (gtype);
  if (data == NULL)
    return FALSE;
  return data->klass->type == DBUS_G_SPECTYPE_MAP;
}

static GType
get_specialization_index (GType gtype, guint i)
{
  DBusGTypeSpecializedData *data;

  data = lookup_specialization_data (gtype);
  return data->types[i];
}

GType
dbus_g_type_get_collection_specialization (GType gtype)
{
  g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
  return get_specialization_index (gtype, 0);
}

GType
dbus_g_type_get_map_key_specialization (GType gtype)
{
  g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
  return get_specialization_index (gtype, 0);
}

GType
dbus_g_type_get_map_value_specialization (GType gtype)
{
  g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
  return get_specialization_index (gtype, 1);
}

gpointer
dbus_g_type_specialized_construct (GType type)
{
  DBusGTypeSpecializedData *data;
  g_return_val_if_fail (specialized_types_is_initialized (), FALSE);

  data = lookup_specialization_data (type);
  g_return_val_if_fail (data != NULL, FALSE);

  return data->klass->vtable->constructor (type);
}

gboolean
dbus_g_type_collection_get_fixed (GValue   *value,
				  gpointer *data_ret,
				  guint    *len_ret)
{
  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 ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype,
											   g_value_get_boxed (value),
											   data_ret, len_ret);
}

void
dbus_g_type_collection_value_iterate (GValue                                 *value,
				      DBusGTypeSpecializedCollectionIterator  iterator,
				      gpointer                                user_data)
{
  DBusGTypeSpecializedData *data;
  GType gtype;

  g_return_if_fail (specialized_types_is_initialized ());
  g_return_if_fail (G_VALUE_HOLDS_BOXED (value));

  gtype = G_VALUE_TYPE (value);
  data = lookup_specialization_data (gtype);
  g_return_if_fail (data != NULL);

  ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
									    g_value_get_boxed (value),
									    iterator, user_data);
}

void
dbus_g_type_map_value_iterate (GValue                                 *value,
			       DBusGTypeSpecializedMapIterator         iterator,
			       gpointer                                user_data)
{
  DBusGTypeSpecializedData *data;
  GType gtype;

  g_return_if_fail (specialized_types_is_initialized ());
  g_return_if_fail (G_VALUE_HOLDS_BOXED (value));

  gtype = G_VALUE_TYPE (value);
  data = lookup_specialization_data (gtype);
  g_return_if_fail (data != NULL);

  ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
								     g_value_get_boxed (value),
								     iterator, user_data);
}

Index: dbus-gproxy.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gproxy.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- dbus-gproxy.c	9 Mar 2005 17:09:11 -0000	1.24
+++ dbus-gproxy.c	13 Jun 2005 03:01:24 -0000	1.25
@@ -24,8 +24,8 @@
 #include <dbus/dbus-glib-lowlevel.h>
 #include <dbus/dbus-signature.h>
 #include "dbus-gutils.h"
-#include "dbus-gmarshal.h"
 #include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
 #include "dbus-gobject.h"
 #include <string.h>
 #include <glib/gi18n.h>
@@ -737,7 +737,7 @@
                   0,
                   NULL, NULL,
                   marshal_dbus_message_to_g_marshaller,
-                  G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_STRING);
+                  G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
 }
 
 static void
@@ -816,80 +816,6 @@
   return g_string_free (str, FALSE);
 }
 
-static GSignalCMarshaller
-lookup_g_marshaller (DBusGProxy *proxy,
-                     const char *signature)
-{
-  /* The "proxy" arg would eventually be used if you could provide
-   * a marshaller when adding a signal to the proxy
-   */
-
-#define MATCH1(sig, t0)         ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == '\0')
-#define MATCH2(sig, t0, t1)     ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == '\0')
-#define MATCH3(sig, t0, t1, t2) ((sig)[0] == (DBUS_TYPE_##t0) && (sig)[1] == (DBUS_TYPE_##t1) && (sig)[2] == (DBUS_TYPE_##t2) && (sig)[3] == '\0')
-  
-  switch (*signature)
-    {
-    case '\0':
-      return g_cclosure_marshal_VOID__VOID;
-
-    case DBUS_TYPE_BOOLEAN:
-      if (MATCH1 (signature, BOOLEAN))
-        return g_cclosure_marshal_VOID__BOOLEAN;
-      break;
-      
-    case DBUS_TYPE_BYTE:
-      if (MATCH1 (signature, BYTE))
-        return g_cclosure_marshal_VOID__UCHAR;
-      break;
-
-    case DBUS_TYPE_INT16:
-      if (MATCH1 (signature, INT16))
-        return g_cclosure_marshal_VOID__INT;
-      break;
-
-    case DBUS_TYPE_UINT16:
-      if (MATCH1 (signature, UINT16))
-        return g_cclosure_marshal_VOID__UINT;
-      break;
-      
-    case DBUS_TYPE_INT32:
-      if (MATCH1 (signature, INT32))
-        return g_cclosure_marshal_VOID__INT;
-      break;
-
-    case DBUS_TYPE_UINT32:
-      if (MATCH1 (signature, UINT32))
-        return g_cclosure_marshal_VOID__UINT;
-      break;
-
-    case DBUS_TYPE_DOUBLE:
-      if (MATCH1 (signature, DOUBLE))
-        return g_cclosure_marshal_VOID__DOUBLE;
-      break;
-
-    case DBUS_TYPE_OBJECT_PATH:
-      if (MATCH1 (signature, OBJECT_PATH))
-        return g_cclosure_marshal_VOID__STRING;
-      break;
-
-    case DBUS_TYPE_SIGNATURE:
-      if (MATCH1 (signature, SIGNATURE))
-        return g_cclosure_marshal_VOID__STRING;
-      break;
-      
-    case DBUS_TYPE_STRING:
-      if (MATCH1 (signature, STRING))
-        return g_cclosure_marshal_VOID__STRING;
-      /* This is for NameOwnerChanged */
-      else if (MATCH3 (signature, STRING, STRING, STRING))
-        return _dbus_g_marshal_NONE__STRING_STRING_STRING;
-      break;
-    }
-
-  return NULL;
-}
-
 static void
 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
                                       GValue       *return_value,
@@ -909,25 +835,36 @@
   GSignalCMarshaller c_marshaller;
   DBusGProxy *proxy;
   DBusMessage *message;
-  const char *signature;
+  GArray *gsignature;
+  const GType *types;
 
   g_assert (n_param_values == 3);
 
   proxy = g_value_get_object (&param_values[0]);
   message = g_value_get_boxed (&param_values[1]);
-  signature = g_value_get_string (&param_values[2]);
+  gsignature = g_value_get_pointer (&param_values[2]);
 
   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
   g_return_if_fail (message != NULL);
-  g_return_if_fail (signature != NULL);
-  
-  c_marshaller = lookup_g_marshaller (proxy, signature);
+  g_return_if_fail (gsignature != NULL);
+
+  c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
+						  (GType*) gsignature->data);
 
   g_return_if_fail (c_marshaller != NULL);
   
-  value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+  {
+    DBusGValueMarshalCtx context;
+    context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
+    context.proxy = proxy;
 
-  g_return_if_fail (value_array != NULL);
+    types = (const GType*) gsignature->data;
+    value_array = dbus_gvalue_demarshal_message (&context, message,
+						 gsignature->len, types, NULL);
+  }
+
+  if (value_array == NULL)
+    return;
   
   g_value_init (&value, G_TYPE_FROM_INSTANCE (proxy));
   g_value_set_instance (&value, proxy);
@@ -966,37 +903,40 @@
 
   if (q != 0)
     {
-      const char *signature;
-
-      signature = g_datalist_id_get_data (&proxy->signal_signatures, q);
-      if (signature == NULL)
-        {
-#if 0
-          /* this should not trigger a warning, as you shouldn't have to
-           * add signals you don't care about
-           */
-          g_warning ("Signal '%s' has not been added to this proxy object\n",
-                     name);
-#endif
-        }
-      else if (!dbus_message_has_signature (message, signature))
-        {
-          g_warning ("Signature '%s' expected for signal '%s', actual signature '%s'\n",
-                     signature,
-                     name,
-                     dbus_message_get_signature (message));
-        }
-      else
-        {
-          g_signal_emit (proxy,
-                         signals[RECEIVED],
-                         q,
-                         message,
-                         signature);
-        }
+      GArray *gsignature;
+      GArray *msg_gsignature;
+      guint i;
+      
+      gsignature = g_datalist_id_get_data (&proxy->signal_signatures, q);
+      if (gsignature == NULL)
+	goto out;
+      
+      msg_gsignature = dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
+						       TRUE);
+      for (i = 0; i < gsignature->len; i++)
+	{
+	  if (msg_gsignature->len == i
+	      || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
+	    goto mismatch;
+	}
+      if (msg_gsignature->len != i)
+	goto mismatch;
+      
+      g_signal_emit (proxy,
+		     signals[RECEIVED],
+		     q,
+		     message,
+		     msg_gsignature);
     }
 
+ out:
   g_free (name);
+  return;
+ mismatch:
+  g_warning ("Unexpected message signature '%s' for signal '%s'\n",
+	     dbus_message_get_signature (message),
+	     name);
+  goto out;
 }
 
 /** @} End of DBusGLibInternals */
@@ -1204,6 +1144,33 @@
 }
 
 /**
+ * Creates a proxy using an existing proxy as a template, substituting
+ * the specified interface and path.  Either or both may be NULL.
+ *
+ * @param proxy the proxy to use as a template
+ * @param path of the object inside the peer to call methods on
+ * @param interface name of the interface to call methods on
+ * @returns new proxy object
+ * 
+ */
+DBusGProxy*
+dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
+			     const char        *interface,
+			     const char        *path)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  if (interface == NULL)
+    interface = proxy->interface;
+  if (path == NULL)
+    path = proxy->path;
+
+  return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
+			   proxy->name,
+			   path, interface);
+}
+
+/**
  * Creates a proxy for an object in peer application (one
  * we're directly connected to). That is, this function is
  * intended for use when there's no message bus involved,
@@ -1255,199 +1222,63 @@
 }
 
 /**
- * Invokes a method on a remote interface. This function does not
- * block; instead it returns an opaque #DBusPendingCall object that
- * tracks the pending call.  The method call will not be sent over the
- * wire until the application returns to the main loop, or blocks in
- * dbus_connection_flush() to write out pending data.  The call will
- * be completed after a timeout, or when a reply is received.
- * To collect the results of the call (which may be an error,
- * or a reply), use dbus_g_proxy_end_call().
- *
- * @todo this particular function shouldn't die on out of memory,
- * since you should be able to do a call with large arguments.
- * 
- * @param proxy a proxy for a remote interface
- * @param method the name of the method to invoke
- * @param first_arg_type type of the first argument
+ * Gets the object interface proxy is bound to (may be #NULL in some cases).
  *
- * @returns opaque pending call object
- *  */
-DBusGPendingCall*
-dbus_g_proxy_begin_call (DBusGProxy *proxy,
-                        const char *method,
-                        int         first_arg_type,
-                        ...)
+ * @param proxy the proxy
+ * @returns an object interface 
+ */
+const char*
+dbus_g_proxy_get_interface (DBusGProxy        *proxy)
 {
-  DBusPendingCall *pending;
-  DBusMessage *message;
-  va_list args;
-  
   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
 
-  message = dbus_message_new_method_call (proxy->name,
-                                          proxy->path,
-                                          proxy->interface,
-                                          method);
-  if (message == NULL)
-    goto oom;
-
-  va_start (args, first_arg_type);
-  if (!dbus_message_append_args_valist (message, first_arg_type,
-                                        args))
-    goto oom;
-  va_end (args);
-
-  if (!dbus_connection_send_with_reply (proxy->manager->connection,
-                                        message,
-                                        &pending,
-                                        -1))
-    goto oom;
-
-  return DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
-
- oom:
-  /* FIXME we should create a pending call that's
-   * immediately completed with an error status without
-   * ever going on the wire.
-   */
-  
-  g_error ("Out of memory");
-  return NULL;
+  return proxy->interface;
 }
 
 /**
- * Collects the results of a method call. The method call was normally
- * initiated with dbus_g_proxy_end_call(). This function will block if
- * the results haven't yet been received; use
- * dbus_g_pending_call_set_notify() to be notified asynchronously that a
- * pending call has been completed. If it's completed, it will not block.
- *
- * If the call results in an error, the error is set as normal for
- * GError and the function returns #FALSE.
- *
- * Otherwise, the "out" parameters and return value of the
- * method are stored in the provided varargs list.
- * The list should be terminated with #DBUS_TYPE_INVALID.
- *
- * This function doesn't affect the reference count of the
- * #DBusGPendingCall, the caller of dbus_g_proxy_begin_call() still owns
- * a reference.
- *
- * @todo this should be changed to make a g_malloc() copy of the
- * data returned probably; right now the data vanishes
- * when you free the PendingCall which is sort of strange.
+ * Sets the object interface proxy is bound to
  *
- * @param proxy a proxy for a remote interface
- * @param pending the pending call from dbus_g_proxy_begin_call()
- * @param error return location for an error
- * @param first_arg_type type of first "out" argument
- * @returns #FALSE if an error is set
+ * @param proxy the proxy
+ * @param interface_name an object interface 
  */
-gboolean
-dbus_g_proxy_end_call (DBusGProxy          *proxy,
-                       DBusGPendingCall    *pending,
-                       GError             **error,
-                       int                  first_arg_type,
-                       ...)
+void
+dbus_g_proxy_set_interface (DBusGProxy        *proxy,
+			    const char        *interface_name)
 {
-  DBusMessage *message;
-  va_list args;
-  DBusError derror;
-  
-  g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
-  g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
-  g_return_val_if_fail (pending != NULL, FALSE);
-
-  dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
-  message = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
-
-  g_assert (message != NULL);
-
-  dbus_error_init (&derror);
-
-  switch (dbus_message_get_type (message))
-    {
-    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
-      va_start (args, first_arg_type);
-      if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
-        {
-          va_end (args);
-          goto error;
-        }
-      va_end (args);
-
-      dbus_message_unref (message);
-      return TRUE;
-      
-    case DBUS_MESSAGE_TYPE_ERROR:
-      dbus_set_error_from_message (&derror, message);
-      goto error;
-
-    default:
-      dbus_set_error (&derror, DBUS_ERROR_FAILED,
-                      "Reply was neither a method return nor an exception");
-      goto error;
-    }
-
- error:
-  dbus_message_unref (message);
-  
-  dbus_set_g_error (error, &derror);
-  dbus_error_free (&derror);
-  return FALSE;
+  /* FIXME - need to unregister when we switch interface for now
+   * later should support idea of unset interface
+   */
+  dbus_g_proxy_manager_unregister (proxy->manager, proxy);
+  g_free (proxy->interface);
+  proxy->interface = g_strdup (interface_name);
+  dbus_g_proxy_manager_register (proxy->manager, proxy);
 }
 
 /**
- * Function for invoking a method and receiving reply values.
- * Normally this is not used directly - calls to it are generated
- * from client-side wrappers (see dbus-binding-tool).
- *
- * This function takes two type signatures, one for method arguments,
- * and one for return values.  The remaining arguments after the
- * error parameter should be values of the input arguments,
- * followed by pointer values to storage for return values.
+ * Gets the path this proxy is bound to
  *
- * @param proxy a proxy for a remote interface
- * @param method method to invoke
- * @param insig signature of input values
- * @param outsig signature of output values
- * @param error return location for an error
- * @returns #FALSE if an error is set, TRUE otherwise
+ * @param proxy the proxy
+ * @returns an object path
  */
-gboolean
-dbus_g_proxy_invoke (DBusGProxy        *proxy,
-		     const char        *method,
-		     const char        *insig,
-		     const char        *outsig,
-		     GError           **error,
-		     ...)
+const char*
+dbus_g_proxy_get_path (DBusGProxy        *proxy)
+{
+  g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
+  g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
+
+  return proxy->path;
+}
+
+static DBusMessage *
+dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
+				      const char  *method,
+				      GValueArray *args)
 {
-  DBusPendingCall *pending;
   DBusMessage *message;
-  DBusMessage *reply;
-  va_list args;
-  va_list args_unwind;
-  int n_retvals_processed;
   DBusMessageIter msgiter;
-  DBusSignatureIter sigiter;
-  int expected_type;
-  gboolean ret;
-  DBusError derror;
-  
-  g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
-  g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
-
-  va_start (args, error);
-  /* Keep around a copy of output arguments so we
-   * can free on error. */
-  G_VA_COPY (args_unwind, args);
+  guint i;
 
-  ret = FALSE;
-  pending = NULL;
-  reply = NULL;
-  n_retvals_processed = 0;
   message = dbus_message_new_method_call (proxy->name,
                                           proxy->path,
                                           proxy->interface,
@@ -1455,47 +1286,91 @@
   if (message == NULL)
     goto oom;
 
-  dbus_signature_iter_init (&sigiter, insig);
   dbus_message_iter_init_append (message, &msgiter);
-  while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+  for (i = 0; i < args->n_values; i++)
     {
-      GValue gvalue = {0, };
-      char *collect_err;
-
-      if (!dbus_gvalue_init (expected_type, &gvalue))
-	{
-	  g_set_error (error, DBUS_GERROR,
-		       DBUS_GERROR_INVALID_ARGS,
-		       _("Unsupported type '%c'"), expected_type);
-	  goto out;
-	} 
-      
-      G_VALUE_COLLECT (&gvalue, args, G_VALUE_NOCOPY_CONTENTS, &collect_err);
+      GValue *gvalue;
 
-      if (collect_err)
-	{
-	  g_set_error (error, DBUS_GERROR,
-		       DBUS_GERROR_INVALID_ARGS,
-		       collect_err);
-	  goto out;
-	}
+      gvalue = g_value_array_get_nth (args, i);
 
-      /* Anything we can init must be marshallable */
-      if (!dbus_gvalue_marshal (&msgiter, &gvalue))
+      if (!dbus_gvalue_marshal (&msgiter, gvalue))
 	g_assert_not_reached ();
-      g_value_unset (&gvalue);
-
-      dbus_signature_iter_next (&sigiter);
     }
+  return message;
+ oom:
+  return NULL;
+}
 
+#define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
+do { \
+  GType valtype; \
+  int i = 0; \
+  VALARRAY = g_value_array_new (6); \
+  valtype = FIRST_ARG_TYPE; \
+  while (valtype != G_TYPE_INVALID) \
+    { \
+      const char *collect_err; \
+      GValue *val; \
+      g_value_array_append (VALARRAY, NULL); \
+      val = g_value_array_get_nth (VALARRAY, i); \
+      g_value_init (val, valtype); \
+      collect_err = NULL; \
+      G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
+      valtype = va_arg (ARGS, GType); \
+      i++; \
+    } \
+} while (0)
+
+static DBusGPendingCall *
+dbus_g_proxy_begin_call_internal (DBusGProxy    *proxy,
+				  const char    *method,
+				  GValueArray   *args)
+{
+  DBusMessage *message;
+  DBusPendingCall *pending;
+
+  g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
+  g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
+
+  pending = NULL;
+
+  message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
+  if (!message)
+    goto oom;
+  
   if (!dbus_connection_send_with_reply (proxy->manager->connection,
                                         message,
                                         &pending,
                                         -1))
     goto oom;
+  g_assert (pending != NULL);
 
-  dbus_pending_call_block (pending);
-  reply = dbus_pending_call_steal_reply (pending);
+  return DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending);
+ oom:
+  g_error ("Out of memory");
+  return NULL;
+}
+
+static gboolean
+dbus_g_proxy_end_call_internal (DBusGProxy       *proxy,
+				DBusGPendingCall *pending,
+				GError          **error,
+				GType             first_arg_type,
+				va_list           args)
+{
+  DBusMessage *reply;
+  DBusMessageIter msgiter;
+  DBusError derror;
+  va_list args_unwind;
+  int n_retvals_processed;
+  gboolean ret;
+  GType valtype;
+
+  reply = NULL;
+  ret = FALSE;
+  n_retvals_processed = 0;
+  dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
+  reply = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending));
 
   g_assert (reply != NULL);
 
@@ -1505,53 +1380,86 @@
     {
     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
 
-      dbus_signature_iter_init (&sigiter, outsig);
       dbus_message_iter_init (reply, &msgiter);
-      while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+      valtype = first_arg_type;
+      while (valtype != G_TYPE_INVALID)
 	{
 	  int arg_type;
-	  gpointer *value_ret;
+	  gpointer return_storage;
 	  GValue gvalue = { 0, };
+	  DBusGValueMarshalCtx context;
+
+	  context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
+	  context.proxy = proxy;
 
-	  value_ret = va_arg (args, gpointer *);
 
 	  arg_type = dbus_message_iter_get_arg_type (&msgiter);
-	  if (expected_type != arg_type)
+	  if (arg_type == DBUS_TYPE_INVALID)
+	    g_set_error (error, DBUS_GERROR,
+			 DBUS_GERROR_INVALID_ARGS,
+			 _("Too few arguments in reply"));
+
+	  return_storage = va_arg (args, gpointer);
+	  if (return_storage == NULL)
+	    goto next;
+
+	  /* We handle variants specially; the caller is expected
+	   * to have already allocated storage for them.
+	   */
+	  if (arg_type == DBUS_TYPE_VARIANT
+	      && g_type_is_a (valtype, G_TYPE_VALUE))
 	    {
-	      if (arg_type == DBUS_TYPE_INVALID)
-		  g_set_error (error, DBUS_GERROR,
-			       DBUS_GERROR_INVALID_ARGS,
-			       _("Too few arguments in reply"));
-	      else
-		  g_set_error (error, DBUS_GERROR,
+	      if (!dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
+		{
+		  g_set_error (error,
+			       DBUS_GERROR,
 			       DBUS_GERROR_INVALID_ARGS,
-			       _("Reply argument was \"%c\", expected \"%c\""),
-			       arg_type, expected_type);  
-	      goto out;
+			       _("Couldn't convert argument, expected \"%s\""),
+			       g_type_name (valtype));
+		  goto out;
+		}
 	    }
-	  
-	  if (!dbus_gvalue_demarshal (&msgiter, &gvalue))
+	  else
 	    {
-	      g_set_error (error,
-			   DBUS_GERROR,
-			   DBUS_GERROR_INVALID_ARGS,
-			   _("Couldn't convert argument type \"%c\""), expected_type);
-	      goto out;
+	      g_value_init (&gvalue, valtype);
+
+	      /* FIXME, should use error here instead of NULL */ 
+	      if (!dbus_gvalue_demarshal (&context, &msgiter, &gvalue, NULL))
+		{
+		  g_set_error (error,
+			       DBUS_GERROR,
+			       DBUS_GERROR_INVALID_ARGS,
+			       _("Couldn't convert argument, expected \"%s\""),
+			       g_type_name (valtype));
+		  goto out;
+		}
+
+	      if (G_VALUE_TYPE (&gvalue) != valtype)
+		{
+		  g_set_error (error, DBUS_GERROR,
+			       DBUS_GERROR_INVALID_ARGS,
+			       _("Reply argument was \"%s\", expected \"%s\""),
+			       g_type_name (G_VALUE_TYPE (&gvalue)),
+			       g_type_name (valtype));  
+		  goto out;
+		}
+
+	      /* Anything that can be demarshaled must be storable */
+	      if (!dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
+		g_assert_not_reached ();
+	      /* Ownership of the value passes to the client, don't unset */
 	    }
-	  /* Anything that can be demarshaled must be storable */
-	  if (!dbus_gvalue_store (&gvalue, value_ret))
-	    g_assert_not_reached ();
-	  g_value_unset (&gvalue);
 	  
+	next:
 	  n_retvals_processed++;
-	  dbus_signature_iter_next (&sigiter);
 	  dbus_message_iter_next (&msgiter);
+	  valtype = va_arg (args, GType);
 	}
       if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
 	{
 	  g_set_error (error, DBUS_GERROR,
 		       DBUS_GERROR_INVALID_ARGS,
-		       _("Too many arguments"));
+		       _("Too many arguments in reply"));
 	  goto out;
 	}
       break;
@@ -1589,16 +1497,132 @@
   va_end (args_unwind);
 
   if (pending)
-    dbus_pending_call_unref (pending);
-  if (message)
-    dbus_message_unref (message);
+    dbus_g_pending_call_unref (pending);
   if (reply)
     dbus_message_unref (reply);
   return ret;
- oom:
-  g_error ("Out of memory");
-  ret = FALSE;
-  goto out;
+}
+
+
+/**
+ * Invokes a method on a remote interface. This function does not
+ * block; instead it returns an opaque #DBusPendingCall object that
+ * tracks the pending call.  The method call will not be sent over the
+ * wire until the application returns to the main loop, or blocks in
+ * dbus_connection_flush() to write out pending data.  The call will
+ * be completed after a timeout, or when a reply is received.
+ * To collect the results of the call (which may be an error,
+ * or a reply), use dbus_g_proxy_end_call().
+ *
+ * @todo this particular function shouldn't die on out of memory,
+ * since you should be able to do a call with large arguments.
+ * 
+ * @param proxy a proxy for a remote interface
+ * @param method the name of the method to invoke
+ * @param first_arg_type type of the first argument
+ *
+ * @returns opaque pending call object
+ *  */
+DBusGPendingCall*
+dbus_g_proxy_begin_call (DBusGProxy *proxy,
+			 const char  *method,
+			 GType       first_arg_type,
+                        ...)
+{
+  DBusGPendingCall *pending;
+  va_list args;
+  GValueArray *arg_values;
+  
+  va_start (args, first_arg_type);
+
+  DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
+  
+  pending = dbus_g_proxy_begin_call_internal (proxy, method, arg_values);
+
+  g_value_array_free (arg_values);
+
+  va_end (args);
+
+  return pending;
+}
+
+/**
+ * Collects the results of a method call. The method call was normally
+ * initiated with dbus_g_proxy_end_call(). This function will block if
+ * the results haven't yet been received; use
+ * dbus_g_pending_call_set_notify() to be notified asynchronously that a
+ * pending call has been completed. If it's completed, it will not block.
+ *
+ * If the call results in an error, the error is set as normal for
+ * GError and the function returns #FALSE.
+ *
+ * Otherwise, the "out" parameters and return value of the
+ * method are stored in the provided varargs list.
+ * The list should be terminated with G_TYPE_INVALID.
+ *
+ * This function unrefs the pending call.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param pending the pending call from dbus_g_proxy_begin_call()
+ * @param error return location for an error
+ * @param first_arg_type type of first "out" argument
+ * @returns #FALSE if an error is set
+ */
+gboolean
+dbus_g_proxy_end_call (DBusGProxy          *proxy,
+                       DBusGPendingCall    *pending,
+                       GError             **error,
+                       GType                first_arg_type,
+                       ...)
+{
+  gboolean ret;
+  va_list args;
+
+  va_start (args, first_arg_type);
+
+  ret = dbus_g_proxy_end_call_internal (proxy, pending, error, first_arg_type, args);
+
+  va_end (args);
+  
+  return ret;
+}
+
+/**
+ * Function for invoking a method and receiving reply values.
+ * Normally this is not used directly - calls to it are generated
+ * from client-side wrappers (see dbus-binding-tool).
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method method to invoke
+ * @param error return location for an error
+ * @returns #FALSE if an error is set, TRUE otherwise
+ */
+gboolean
+dbus_g_proxy_invoke (DBusGProxy        *proxy,
+		     const char        *method,
+		     GError           **error,
+		     GType              first_arg_type,
+		     ...)
+{
+  gboolean ret;
+  DBusGPendingCall *pending;
+  va_list args;
+  GValueArray *in_args;
+
+  va_start (args, first_arg_type);
+
+  DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
+
+  pending = dbus_g_proxy_begin_call_internal (proxy, method, in_args);
+
+  g_value_array_free (in_args);
+
+  first_arg_type = va_arg (args, GType);
+  ret = dbus_g_proxy_end_call_internal (proxy, pending, error, first_arg_type, args);
+
+  va_end (args);
+
+  return ret;
 }
 
 /**
@@ -1614,30 +1638,29 @@
  */
 void
 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
-                           const char               *method,
-                           int                       first_arg_type,
-                           ...)
+			    const char               *method,
+			    GType                     first_arg_type,
+			    ...)
 {
   DBusMessage *message;
   va_list args;
+  GValueArray *in_args;
   
   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
 
-  message = dbus_message_new_method_call (proxy->name,
-                                          proxy->path,
-                                          proxy->interface,
-                                          method);
-  if (message == NULL)
+  va_start (args, first_arg_type);
+  DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
+
+  message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
+
+  g_value_array_free (in_args);
+  va_end (args);
+
+  if (!message)
     goto oom;
 
   dbus_message_set_no_reply (message, TRUE);
-  
-  va_start (args, first_arg_type);
-  if (!dbus_message_append_args_valist (message, first_arg_type,
-                                        args))
-    goto oom;
-  va_end (args);
 
   if (!dbus_connection_send (proxy->manager->connection,
                              message,
@@ -1696,41 +1719,63 @@
     g_error ("Out of memory\n");
 }
 
+static void
+array_free_all (gpointer array)
+{
+  g_array_free (array, TRUE);
+}
+
 /**
- * Specifies the signature of a signal, such that it's possible to
- * connect to the signal on this proxy.
+ * Specifies the argument signature of a signal;.only necessary
+ * if the remote object does not support introspection.  The arguments
+ * specified are the GLib types expected.
  *
  * @param proxy the proxy for a remote interface
  * @param signal_name the name of the signal
- * @param signature D-BUS signature of the signal
+ * @param first_type the first argument type, or G_TYPE_INVALID if none
  */
 void
 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
                           const char        *signal_name,
-                          const char        *signature)
+			  GType              first_type,
+                          ...)
 {
   GQuark q;
   char *name;
+  GArray *gtypesig;
+  GType gtype;
+  va_list args;
 
   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
   g_return_if_fail (signal_name != NULL);
-  g_return_if_fail (signature != NULL);
-#ifndef G_DISABLE_CHECKS
-  if (lookup_g_marshaller (proxy, signature) == NULL)
-    g_warning ("No marshaller for signature '%s', we need to add API for providing your own",
-               signature);
-#endif
   
   name = create_signal_name (proxy->interface, signal_name);
   
   q = g_quark_from_string (name);
   
   g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
+
+  gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
+
+  va_start (args, first_type);
+  gtype = first_type;
+  while (gtype != G_TYPE_INVALID)
+    {
+      g_array_append_val (gtypesig, gtype);
+      gtype = va_arg (args, GType);
+    }
+  va_end (args);
+
+#ifndef G_DISABLE_CHECKS
+  if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
+    g_warning ("No marshaller for signature of signal '%s'", signal_name);
+#endif
+
   
   g_datalist_id_set_data_full (&proxy->signal_signatures,
-                               q, g_strdup (signature),
-                               g_free);
+                               q, gtypesig,
+                               array_free_all);
 
   g_free (name);
 }

Index: dbus-gobject.h
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gobject.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- dbus-gobject.h	18 Feb 2005 03:14:33 -0000	1.2
+++ dbus-gobject.h	13 Jun 2005 03:01:24 -0000	1.3
@@ -24,11 +24,19 @@
 #define DBUS_GLIB_OBJECT_H
 
 #include <dbus/dbus.h>
+#include <dbus/dbus-signature.h>
 #include <glib.h>
+#include "dbus/dbus-glib.h"
 
 G_BEGIN_DECLS
 
-GValueArray*       _dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage         *message);
+const char *       _dbus_gobject_get_path (GObject *obj);
+
+GClosureMarshal    _dbus_gobject_lookup_marshaller (GType        rettype,
+						    guint        n_params,
+						    const GType *param_types);
+  
+						    
 
 G_END_DECLS
 

Index: dbus-gobject.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gobject.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- dbus-gobject.c	3 May 2005 17:45:29 -0000	1.22
+++ dbus-gobject.c	13 Jun 2005 03:01:24 -0000	1.23
@@ -22,12 +22,15 @@
  */
 
 #include <config.h>
+#include <gobject/gvaluecollector.h>
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 #include "dbus-gtest.h"
 #include "dbus-gutils.h"
 #include "dbus-gobject.h"
 #include "dbus-gvalue.h"
+#include "dbus-gmarshal.h"
+#include "dbus-gvalue-utils.h"
 #include <string.h>
 
 /**
@@ -35,8 +38,9 @@
  * @{
  */
 
-static GStaticRWLock info_hash_lock = G_STATIC_RW_LOCK_INIT;
+static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
 static GHashTable *info_hash = NULL;
+static GHashTable *marshal_table = NULL;
 
 static char*
 uscore_to_wincaps (const char *uscore)
@@ -129,7 +133,7 @@
 method_arg_info_from_object_info (const DBusGObjectInfo *object,
 				  const DBusGMethodInfo *method)
 {
-  return string_table_lookup (get_method_data (object, method), 2);
+  return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
 }
 
 static const char *
@@ -199,42 +203,6 @@
   return method_dir_signature_from_object_info (object, method, FALSE);
 }
 
-/**
- * Converts the args of a message into an array of GValue.
- *
- * @param message the message
- * @returns #NULL if conversion fails, otherwise the values.
- */
-GValueArray *
-_dbus_glib_marshal_dbus_message_to_gvalue_array (DBusMessage *message)
-{
-  GValueArray *ret;
-  DBusMessageIter iter;
-  int dtype;
-
-  ret = g_value_array_new (6);  /* 6 is a typical maximum for arguments */
-  dbus_message_iter_init (message, &iter);
-  
-  while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
-    {
-      GValue value = { 0, };
-
-      if (!dbus_gvalue_demarshal (&iter, &value))
-        {
-          g_warning ("Unable to convert arg type %d to GValue", dtype);
-          g_value_array_free (ret);
-          ret = NULL;
-          goto out;
-        }
-      g_value_array_append (ret, &value);
-      
-      dbus_message_iter_next (&iter);
-    }
-
- out:
-  return ret;
-}
-
 static void
 gobject_unregister_function (DBusConnection  *connection,
                              void            *user_data)
@@ -267,7 +235,7 @@
       gboolean can_get;
       GParamSpec *spec = specs[i];
       
-      dbus_type = dbus_gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
+      dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
       if (dbus_type == NULL)
 	continue;
       
@@ -347,7 +315,7 @@
       
       g_signal_query (ids[i], &query);
 
-      if (query.return_type)
+      if (query.return_type != G_TYPE_NONE)
 	continue; /* FIXME: these could be listed as methods ? */
 
       g_string_append (xml, "    <signal name=\"");
@@ -356,8 +324,11 @@
 
       for (arg = 0; arg < query.n_params; arg++)
 	{
-	  const char *dbus_type = dbus_gtype_to_dbus_type (query.param_types[arg]);
+	  const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
 
+	  if (!dbus_type)
+	    continue;
+	  
           g_string_append (xml, "      <arg type=\"");
           g_string_append (xml, dbus_type);
           g_string_append (xml, "\"/>\n");
@@ -428,7 +399,7 @@
 {
   GType classtype;
 
-  g_static_rw_lock_reader_lock (&info_hash_lock);
+  g_static_rw_lock_reader_lock (&globals_lock);
 
   for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
     {
@@ -475,7 +446,7 @@
 	}
     }
 
-  g_static_rw_lock_reader_lock (&info_hash_lock);
+  g_static_rw_lock_reader_unlock (&globals_lock);
 }
 
 static DBusHandlerResult
@@ -560,15 +531,15 @@
   GValue value = { 0, };
   DBusMessage *ret;
   DBusMessageIter sub;
+  DBusGValueMarshalCtx context;
 
   dbus_message_iter_recurse (iter, &sub);
-  
-  /* The g_object_set_property() will transform some types, e.g. it
-   * will let you use a uchar to set an int property etc. Note that
-   * any error in value range or value conversion will just
-   * g_warning(). These GObject skels are not for secure applications.
-   */
-  if (dbus_gvalue_demarshal (&sub, &value))
+
+  context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+  context.proxy = NULL;
+
+  g_value_init (&value, pspec->value_type);
+  if (dbus_gvalue_demarshal (&context, &sub, &value, NULL))
     {
       g_object_set_property (object,
                              pspec->name,
@@ -644,7 +615,7 @@
   signature = dbus_message_get_signature (message);
   ret = FALSE;
 
-  g_static_rw_lock_reader_lock (&info_hash_lock);
+  g_static_rw_lock_reader_lock (&globals_lock);
 
   if (!info_hash)
     goto out;
@@ -674,6 +645,7 @@
 	      expected_interface = method_interface_from_object_info (*object_ret, method);
 	      expected_member = method_name_from_object_info (*object_ret, method);
 	      expected_signature = method_input_signature_from_object_info (*object_ret, method);
+
 	      if ((interface == NULL
 		   || strcmp (expected_interface, interface) == 0)
 		  && strcmp (expected_member, member) == 0
@@ -689,7 +661,7 @@
 	}
     }
  out:
-  g_static_rw_lock_reader_lock (&info_hash_lock);
+  g_static_rw_lock_reader_unlock (&globals_lock);
   return ret;
 }
 
@@ -759,74 +731,147 @@
 		      DBusConnection  *connection,
 		      DBusMessage     *message)
 {
-  gboolean had_error;
+  gboolean had_error, call_only;
   GError *gerror;
   GValueArray *value_array;
   GValue object_value = {0,};
   GValue error_value = {0,};
   GValue return_value = {0,};
   GClosure closure;
-  char *out_signature;
-  int out_signature_len;
-  GArray *out_param_values;
-  int i;
+  char *in_signature;
+  char *out_signature = NULL;
+  int current_type;
+  DBusSignatureIter out_signature_iter;
+  GArray *out_param_values = NULL;
+  GValueArray *out_param_gvalues = NULL;
+  int out_param_count;
+  int out_param_pos, out_param_gvalue_pos;
   DBusHandlerResult result;
   DBusMessage *reply;
 
   gerror = NULL;
 
+  if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0) {
+    call_only = TRUE;
+  } else {
+    call_only = FALSE;
+  }
+
   /* This is evil.  We do this to work around the fact that
    * the generated glib marshallers check a flag in the closure object
    * which we don't care about.  We don't need/want to create
    * a new closure for each invocation.
    */
   memset (&closure, 0, sizeof (closure));
+
+  in_signature = method_input_signature_from_object_info (object_info, method); 
   
   /* Convert method IN parameters to GValueArray */
-  value_array = _dbus_glib_marshal_dbus_message_to_gvalue_array (message);
+  {
+    GArray *types_array;
+    guint n_params;
+    const GType *types;
+    DBusGValueMarshalCtx context;
 
-  g_return_val_if_fail (value_array != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+    context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+    context.proxy = NULL;
+
+    types_array = dbus_gtypes_from_arg_signature (in_signature, FALSE);
+    n_params = types_array->len;
+    types = (const GType*) types_array->data;
+
+    value_array = dbus_gvalue_demarshal_message (&context, message, n_params, types, NULL);
+    if (value_array == NULL)
+      {
+	g_free (in_signature); 
+	g_array_free (types_array, TRUE);
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      }
+    g_array_free (types_array, TRUE);
+  }
 
   /* Prepend object as first argument */ 
   g_value_init (&object_value, G_TYPE_OBJECT);
   g_value_set_object (&object_value, object);
   g_value_array_prepend (value_array, &object_value);
 
+  if (call_only) {
+    GValue context_value = {0,};
+    DBusGMethodInvocation *context;
+    context = g_new (DBusGMethodInvocation, 1);
+    context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
+    context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
+    context->object = object_info;
+    context->method = method;
+    g_value_init (&context_value, G_TYPE_POINTER);
+    g_value_set_pointer (&context_value, context);
+    g_value_array_append (value_array, &context_value);
+  } else {
   out_signature = method_output_signature_from_object_info (object_info, method); 
-  out_signature_len = strlen (out_signature);
+
+  /* Count number of output parameters */
+  dbus_signature_iter_init (&out_signature_iter, out_signature);
+  out_param_count = 0;
+  while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
+    {
+      out_param_count++;
+      dbus_signature_iter_next (&out_signature_iter);
+    }
 
   /* Create an array to store the actual values of OUT
    * parameters.  Then, create a GValue boxed POINTER
    * to each of those values, and append to the invocation,
    * so the method can return the OUT parameters.
    */
-  out_param_values = g_array_new (FALSE, TRUE, sizeof (DBusBasicGValue));
-  for (i = 0; i < out_signature_len; i++)
+  out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
+
+  /* We have a special array of GValues for toplevel GValue return
+   * types.
+   */
+  out_param_gvalues = g_value_array_new (out_param_count);
+  out_param_pos = 0;
+  out_param_gvalue_pos = 0;
+  dbus_signature_iter_init (&out_signature_iter, out_signature);
+  while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
     {
       GValue value = {0, };
-      DBusBasicGValue basic;
-
-      memset (&basic, 0, sizeof (basic));
-
-      /* FIXME - broken for container types */
+      GTypeCValue storage;
 
-      g_array_append_val (out_param_values, basic);
       g_value_init (&value, G_TYPE_POINTER);
-      g_value_set_pointer (&value, &(g_array_index (out_param_values, DBusBasicGValue, i)));
+
+      /* We special case variants to make method invocation a bit nicer */
+      if (current_type != DBUS_TYPE_VARIANT)
+	{
+	  memset (&storage, 0, sizeof (storage));
+	  g_array_append_val (out_param_values, storage);
+	  g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
+	  out_param_pos++;
+	}
+      else
+	{
+	  g_value_array_append (out_param_gvalues, NULL);
+	  g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
+	  out_param_gvalue_pos++;
+	}
       g_value_array_append (value_array, &value);
+      dbus_signature_iter_next (&out_signature_iter);
     }
 
   /* Append GError as final argument */
   g_value_init (&error_value, G_TYPE_POINTER);
   g_value_set_pointer (&error_value, &gerror);
   g_value_array_append (value_array, &error_value);
-
+  }
   /* Actually invoke method */
   g_value_init (&return_value, G_TYPE_BOOLEAN);
   method->marshaller (&closure, &return_value,
 		      value_array->n_values,
 		      value_array->values,
 		      NULL, method->function);
+  if (call_only) {
+    result = DBUS_HANDLER_RESULT_HANDLED;
+    goto done;
+  }
   had_error = !g_value_get_boolean (&return_value);
 
   if (!had_error)
@@ -839,16 +884,34 @@
 
       /* Append OUT arguments to reply */
       dbus_message_iter_init_append (reply, &iter);
-      for (i = 0; i < out_signature_len; i++)
+      dbus_signature_iter_init (&out_signature_iter, out_signature);
+      out_param_pos = 0;
+      out_param_gvalue_pos = 0;
+      while ((current_type = dbus_signature_iter_get_current_type (&out_signature_iter)) != DBUS_TYPE_INVALID)
 	{
-	  DBusBasicGValue *value;
-
-	  /* FIXME - broken for container types */
-
-	  value = &(g_array_index (out_param_values, DBusBasicGValue, i));
-	  if (!dbus_message_iter_append_basic (&iter, out_signature[i], value))
-	    goto nomem;
+	  GValue gvalue = {0, };
 	  
+	  g_value_init (&gvalue, dbus_gtype_from_signature_iter (&out_signature_iter, FALSE));
+	  if (current_type != DBUS_TYPE_VARIANT)
+	    {
+	      if (!dbus_gvalue_take (&gvalue,
+				     &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
+		g_assert_not_reached ();
+	      out_param_pos++;
+	    }
+	  else
+	    {
+	      g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
+	      out_param_gvalue_pos++;
+	    }
+	      
+	  if (!dbus_gvalue_marshal (&iter, &gvalue))
+	    goto nomem;
+	  /* Here we actually free the allocated value; we
+	   * took ownership of it with dbus_gvalue_take.
+	   */
+	  g_value_unset (&gvalue);
+	  dbus_signature_iter_next (&out_signature_iter);
 	}
     }
   else
@@ -860,30 +923,17 @@
       dbus_message_unref (reply);
     }
 
-  /* Assume that if there was an error, no return values are
-   * set */
-  if (!had_error)
-    {
-      /* Be sure to free all returned STRING arguments for now;
-       * later this should be specified via method info parameter
-       * annotation; probably we want to support custom free funcs too */
-      for (i = 0; i < out_signature_len; i++)
-	{
-	  DBusBasicGValue *value;
-
-	  value = &(g_array_index (out_param_values, DBusBasicGValue, i));
-	  if (out_signature[i] == DBUS_TYPE_STRING)
-	    g_free (value->gpointer_val);
-	}
-    } 
-
   result = DBUS_HANDLER_RESULT_HANDLED;
  done:
+  g_free (in_signature);
   g_free (out_signature);
-  g_array_free (out_param_values, TRUE);
+  if (!call_only) {
+    g_array_free (out_param_values, TRUE);
+    g_value_array_free (out_param_gvalues);
+    g_value_unset (&object_value);
+    g_value_unset (&error_value);
+  }
   g_value_array_free (value_array);
-  g_value_unset (&object_value);
-  g_value_unset (&error_value);
   g_value_unset (&return_value);
   return result;
  nomem:
@@ -891,6 +941,55 @@
   goto done;
 }
 
+void
+dbus_g_method_return (DBusGMethodInvocation *context, ...)
+{
+  DBusMessage *reply;
+  DBusMessageIter iter;
+  va_list args;
+  char *out_sig;
+  GArray *argsig;
+  guint i;
+
+  reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
+  out_sig = method_output_signature_from_object_info (context->object, context->method);
+  argsig = dbus_gtypes_from_arg_signature (out_sig, FALSE);
+
+  dbus_message_iter_init_append (reply, &iter);
+
+  va_start (args, context);
+  for (i = 0; i < argsig->len; i++) {
+    GValue value = {0,};
+    char *error;
+    g_value_init (&value, g_array_index (argsig, GType, i));
+    error = NULL;
+    G_VALUE_COLLECT (&value, args, 0, &error);
+    if (error) {
+      g_warning(error);
+      g_free (error);
+    }
+    dbus_gvalue_marshal (&iter, &value);
+  }
+  va_end (args);
+
+  dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
+  dbus_message_unref (reply);
+
+  dbus_g_connection_unref (context->connection);
+  dbus_g_message_unref (context->message);
+  g_free (context);
+}
+
+void
+dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
+{
+  DBusMessage *reply;
+  reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
+  dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
+  dbus_message_unref (reply);
+}
+
+
 static DBusHandlerResult
 gobject_message_function (DBusConnection  *connection,
                           DBusMessage     *message,
@@ -1009,6 +1108,125 @@
   NULL
 };
 
+typedef struct {
+  GClosure         closure;
+  DBusGConnection *connection;
+  GObject         *object;
+  char            *signame;
+} DBusGSignalClosure;
+
+static GClosure *
+dbus_g_signal_closure_new (DBusGConnection *connection,
+			   GObject         *object,
+			   const char      *signame)
+{
+  DBusGSignalClosure *closure;
+  
+  closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
+
+  closure->connection = dbus_g_connection_ref (connection);
+  closure->object = object;
+  closure->signame = g_strdup (signame);
+  return (GClosure*) closure;
+}
+
+static void
+dbus_g_signal_closure_finalize (gpointer data,
+				GClosure *closure)
+{
+  DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
+
+  dbus_g_connection_unref (sigclosure->connection);
+  g_free (sigclosure->signame);
+}
+
+static void
+signal_emitter_marshaller (GClosure        *closure,
+			   GValue          *retval,
+			   guint            n_param_values,
+			   const GValue    *param_values,
+			   gpointer         invocation_hint,
+			   gpointer         marshal_data)
+{
+  DBusGSignalClosure *sigclosure;
+  DBusMessage *signal;
+  DBusMessageIter iter;
+  guint i;
+  const char *path;
+
+  sigclosure = (DBusGSignalClosure *) closure;
+  
+  g_assert (retval == NULL);
+
+  path = _dbus_gobject_get_path (sigclosure->object);
+
+  g_assert (path != NULL);
+
+  signal = dbus_message_new_signal (path,
+				    "org.gtk.objects",
+				    sigclosure->signame);
+  if (!signal)
+    {
+      g_error ("out of memory");
+      return;
+    }
+
+  dbus_message_iter_init_append (signal, &iter);
+
+  /* First argument is the object itself, and we can't marshall that */
+  for (i = 1; i < n_param_values; i++)
+    {
+      if (!dbus_gvalue_marshal (&iter,
+				(GValue *) (&(param_values[i]))))
+	{
+	  g_warning ("failed to marshal parameter %d for signal %s",
+		     i, sigclosure->signame);
+	  goto out;
+	}
+    }
+  dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
+			signal, NULL);
+ out:
+  dbus_message_unref (signal);
+}
+
+static void
+export_signals (DBusGConnection *connection, GObject *object)
+{
+  guint i;
+  guint *ids, n_ids;
+
+  ids = g_signal_list_ids (G_TYPE_FROM_INSTANCE (object), &n_ids);
+  if (!n_ids)
+    return;
+
+  /* FIXME: recurse to parent types ? */
+  for (i = 0; i < n_ids; i++)
+    {
+      GSignalQuery query;
+      GClosure *closure;
+      
+      g_signal_query (ids[i], &query);
+
+      if (query.return_type != G_TYPE_NONE) {
+	g_warning("Not exporting signal '%s' as it has a return type %s", query.signal_name, g_type_name (query.return_type));
+	continue; /* FIXME: these could be listed as methods ? */
+      }
+
+      closure = dbus_g_signal_closure_new (connection, object, query.signal_name);
+      g_closure_set_marshal (closure, signal_emitter_marshaller);
+
+      g_signal_connect_closure_by_id (object,
+				      ids[i],
+				      0,
+				      closure,
+				      FALSE);
+
+      g_closure_add_finalize_notifier (closure, NULL,
+				       dbus_g_signal_closure_finalize);
+    }
+}
+
 /** @} */ /* end of internals */
 
 /**
@@ -1017,7 +1235,7 @@
  */
 
 /**
- * Install introspection information about the given object class
+ * Install introspection information about the given object GType
  * sufficient to allow methods on the object to be invoked by name.
  * The introspection information is normally generated by
  * dbus-glib-tool, then this function is called in the
@@ -1027,16 +1245,24 @@
  * object registered with dbus_g_connection_register_g_object() can have
  * their methods invoked remotely.
  *
- * @param object_class class struct of the object
+ * @param object_type GType for the object
  * @param info introspection data generated by dbus-glib-tool
  */
 void
-dbus_g_object_class_install_info (GObjectClass          *object_class,
-                                  const DBusGObjectInfo *info)
+dbus_g_object_type_install_info (GType                  object_type,
+				 const DBusGObjectInfo *info)
 {
+  GObjectClass *object_class;
+
+  g_return_if_fail (G_TYPE_IS_OBJECT (object_type));
+
+  dbus_g_value_types_init ();
+
+  object_class = g_type_class_peek (object_type);
+
   g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
 
-  g_static_rw_lock_writer_lock (&info_hash_lock);
+  g_static_rw_lock_writer_lock (&globals_lock);
 
   if (info_hash == NULL)
     {
@@ -1045,7 +1271,7 @@
 
   g_hash_table_replace (info_hash, object_class, (void*) info);
 
-  g_static_rw_lock_writer_unlock (&info_hash_lock);
+  g_static_rw_lock_writer_unlock (&globals_lock);
 }
 
 static void
@@ -1087,12 +1313,175 @@
     return;
   }
 
+  export_signals (connection, object);
+
   g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
   g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
 }
 
+GObject *
+dbus_g_connection_lookup_g_object (DBusGConnection       *connection,
+				   const char            *at_path)
+{
+  gpointer ret;
+  if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
+    return NULL;
+  return ret;
+}
+
+typedef struct {
+  GType    rettype;
+  guint    n_params;
+  GType   *params;
+} DBusGFuncSignature;
+
+static guint
+funcsig_hash (gconstpointer key)
+{
+  const DBusGFuncSignature *sig = key;
+  GType *types;
+  guint ret;
+
+  ret = sig->rettype;
+  types = sig->params;
+
+  while (*types != G_TYPE_INVALID)
+    {
+      ret += (int) (*types);
+      types++;
+    }
+      
+  return ret;
+}
+
+static gboolean
+funcsig_equal (gconstpointer aval,
+	       gconstpointer bval)
+{
+  const DBusGFuncSignature *a = aval;
+  const DBusGFuncSignature *b = bval;
+  const GType *atypes;
+  const GType *btypes;
+
+  if (a->rettype != b->rettype)
+    return FALSE;
+
+  atypes = a->params;
+  btypes = b->params;
+
+  while (*atypes != G_TYPE_INVALID)
+    {
+      if (*btypes != *atypes)
+	return FALSE;
+      atypes++;
+      btypes++;
+    }
+  if (*btypes != G_TYPE_INVALID)
+    return FALSE;
+      
+  return TRUE;
+}
+
+GClosureMarshal
+_dbus_gobject_lookup_marshaller (GType        rettype,
+				 guint        n_params,
+				 const GType *param_types)
+{
+  GClosureMarshal ret;
+  DBusGFuncSignature sig;
+
+  sig.rettype = rettype;
+  sig.n_params = n_params;
+  sig.params = (GType*) param_types;
+  
+  g_static_rw_lock_reader_lock (&globals_lock);
+
+  if (marshal_table)
+    ret = g_hash_table_lookup (marshal_table, &sig);
+  else
+    ret = NULL;
+
+  g_static_rw_lock_reader_unlock (&globals_lock);
+
+  if (ret == NULL)
+    {
+      if (rettype == G_TYPE_NONE)
+	{
+	  if (n_params == 0)
+	    ret = g_cclosure_marshal_VOID__VOID;
+	  else if (n_params == 1)
+	    {
+	      switch (param_types[0])
+		{
+		case G_TYPE_BOOLEAN:
+		  ret = g_cclosure_marshal_VOID__BOOLEAN;
+		case G_TYPE_UCHAR:
+		  ret = g_cclosure_marshal_VOID__UCHAR;
+		case G_TYPE_INT:
+		  ret = g_cclosure_marshal_VOID__INT;
+		case G_TYPE_UINT:
+		  ret = g_cclosure_marshal_VOID__UINT;
+		case G_TYPE_DOUBLE:
+		  ret = g_cclosure_marshal_VOID__DOUBLE;
+		case G_TYPE_STRING:
+		  ret = g_cclosure_marshal_VOID__STRING;
+		}
+	    }
+	}
+      else if (n_params == 3
+	       && param_types[0] == G_TYPE_STRING
+	       && param_types[1] == G_TYPE_STRING
+	       && param_types[2] == G_TYPE_STRING)
+	{
+	  ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+	}
+    }
+
+  return ret;
+}
+
+/**
+ * Register a GClosureMarshal to be used for signal invocations.
+ * This function will not be needed once GLib includes libffi.
+ *
+ * @param rettype a GType for the return type of the function
+ * @param n_types number of function parameters
+ * @param param_types a C array of GTypes values
+ * @param marshaller a GClosureMarshal to be used for invocation
+ */
+void
+dbus_g_object_register_marshaller (GType            rettype,
+				   guint            n_types,
+				   const GType      *param_types,
+				   GClosureMarshal   marshaller)
+{
+  DBusGFuncSignature *sig;
+  
+  g_static_rw_lock_writer_lock (&globals_lock);
+
+  if (marshal_table == NULL)
+    marshal_table = g_hash_table_new_full (funcsig_hash,
+					   funcsig_equal,
+					   g_free,
+					   NULL);
+  sig = g_new0 (DBusGFuncSignature, 1);
+  sig->rettype = rettype;
+  sig->n_params = n_types;
+  sig->params = g_new (GType, n_types);
+  memcpy (sig->params, param_types, n_types * sizeof (GType));
+
+  g_hash_table_insert (marshal_table, sig, marshaller);
+
+  g_static_rw_lock_writer_unlock (&globals_lock);
+}
+
 /** @} */ /* end of public API */
 
+const char * _dbus_gobject_get_path (GObject *obj)
+{
+  return g_object_get_data (obj, "dbus_glib_object_path");
+}
+
 #ifdef DBUS_BUILD_TESTS
 #include <stdlib.h>
 

Index: dbus-gmain.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gmain.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- dbus-gmain.c	16 May 2005 21:27:03 -0000	1.41
+++ dbus-gmain.c	13 Jun 2005 03:01:24 -0000	1.42
@@ -27,6 +27,9 @@
 #include <dbus/dbus-glib-lowlevel.h>
 #include "dbus-gtest.h"
 #include "dbus-gutils.h"
+#include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
+#include <string.h>
 
 #include <libintl.h>
 #define _(x) dgettext (GETTEXT_PACKAGE, x)
@@ -709,6 +712,8 @@
   DBusError derror;
 
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  dbus_g_value_types_init ();
   
   dbus_error_init (&derror);
 
@@ -738,6 +743,30 @@
 gboolean
 _dbus_gmain_test (const char *test_data_dir)
 {
+  GType rectype;
+  GType gtype;
+
+  g_type_init ();
+  dbus_g_value_types_init ();
+
+  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"));
+
+  gtype = dbus_gtype_from_signature ("au", TRUE);
+  g_assert (gtype == 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"));
+
+  gtype = dbus_gtype_from_signature ("a{ss}", TRUE);
+  g_assert (gtype == rectype);
+
+  gtype = dbus_gtype_from_signature ("o", FALSE);
+  g_assert (gtype == G_TYPE_OBJECT);
+  gtype = dbus_gtype_from_signature ("o", TRUE);
+  g_assert (gtype == DBUS_TYPE_G_PROXY);
   
   return TRUE;
 }

Index: dbus-binding-tool-glib.h
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-binding-tool-glib.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbus-binding-tool-glib.h	11 May 2005 19:02:31 -0000	1.4
+++ dbus-binding-tool-glib.h	13 Jun 2005 03:01:24 -0000	1.5
@@ -26,6 +26,7 @@
 G_BEGIN_DECLS
 
 #define DBUS_GLIB_ANNOTATION_C_SYMBOL "org.freedesktop.DBus.GLib.CSymbol"
+#define DBUS_GLIB_ANNOTATION_ASYNC "org.freedesktop.DBus.GLib.Async"
 
 gboolean dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error);
 gboolean dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const char *prefix, GError **error);

Index: dbus-binding-tool-glib.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-binding-tool-glib.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- dbus-binding-tool-glib.c	11 May 2005 19:02:31 -0000	1.8
+++ dbus-binding-tool-glib.c	13 Jun 2005 03:01:24 -0000	1.9
@@ -26,6 +26,7 @@
 #include "dbus-gparser.h"
 #include "dbus-gutils.h"
 #include "dbus-gvalue.h"
+#include "dbus-gvalue-utils.h"
 #include "dbus-glib-tool.h"
 #include "dbus-binding-tool-glib.h"
 #include <glib/gi18n.h>
@@ -45,12 +46,67 @@
   GError **error;
   
   GHashTable *generated;
+  GString *blob;
+  guint count;
 } DBusBindingToolCData;
 
 static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
 static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
 static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
 
+static const char *
+dbus_g_type_get_marshal_name (GType gtype)
+{
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_BOOLEAN:
+      return "BOOLEAN";
+    case G_TYPE_UCHAR:
+      return "UCHAR";
+    case G_TYPE_INT:
+      return "INT";
+    case G_TYPE_UINT:
+      return "UINT";
+    case G_TYPE_INT64:
+      return "INT64";
+    case G_TYPE_UINT64:
+      return "UINT64";
+    case G_TYPE_DOUBLE:
+      return "DOUBLE";
+    case G_TYPE_STRING:
+      return "STRING";
+    case G_TYPE_POINTER:
+      return "POINTER";
+    case G_TYPE_BOXED:
+      return "BOXED";
+    case G_TYPE_OBJECT:
+      return "OBJECT";
+    default:
+      return NULL;
+    }
+}
+
+/* This entire function is kind of...ugh. */
+static const char *
+dbus_g_type_get_c_name (GType gtype)
+{
+  if (dbus_g_type_is_collection (gtype))
+    return "GArray";
+  if (dbus_g_type_is_map (gtype))
+    return "GHashTable";
+  
+  if (g_type_is_a (gtype, G_TYPE_STRING))
+    return "char *";
+
+  /* This one is even more hacky...we get an extra *
+   * because G_TYPE_STRV is a G_TYPE_BOXED
+   */
+  if (g_type_is_a (gtype, G_TYPE_STRV))
+    return "char *";
+  
+  return g_type_name (gtype);
+}
+
 static char *
 compute_marshaller (MethodInfo *method, GError **error)
 {
@@ -71,9 +127,10 @@
       if (arg_info_get_direction (arg) == ARG_IN)
 	{
 	  const char *marshal_name;
+	  GType gtype;
 
-	  marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
-	  if (!marshal_name)
+	  gtype = dbus_gtype_from_signature (arg_info_get_type (arg), FALSE);
+	  if (gtype == G_TYPE_INVALID)
 	    {
 	      g_set_error (error,
 			   DBUS_BINDING_TOOL_ERROR,
@@ -83,6 +140,10 @@
 	      g_string_free (ret, TRUE);
 	      return NULL;
 	    }
+
+	  marshal_name = dbus_g_type_get_marshal_name (gtype);
+	  g_assert (marshal_name);
+
 	  if (!first)
 	    g_string_append (ret, ",");
 	  else
@@ -91,6 +152,12 @@
 	}
     }
 
+  if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) {
+    if (!first)
+      g_string_append (ret, ",");
+    g_string_append (ret, "POINTER");
+    first = FALSE;
+  } else {
   /* Append pointer for each out arg storage */
   for (elt = method_info_get_args (method); elt; elt = elt->next)
     {
@@ -105,12 +172,13 @@
 	  g_string_append (ret, "POINTER");
 	}
     }
-
   /* Final GError parameter */
   if (!first)
     g_string_append (ret, ",");
   g_string_append (ret, "POINTER");
 
+  }
+
   return g_string_free (ret, FALSE);
 
 }
@@ -136,25 +204,31 @@
 	{
 	  const char *marshal_name;
 	  const char *type;
+	  GType gtype;
 
 	  type = arg_info_get_type (arg);
-	  marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
-	  if (!marshal_name)
+	  gtype = dbus_gtype_from_signature (type, FALSE);
+	  if (gtype == G_TYPE_INVALID)
 	    {
 	      g_set_error (error,
 			   DBUS_BINDING_TOOL_ERROR,
 			   DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
-			   _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
+			   _("Unsupported conversion from D-BUS type %s to glib type"),
 			   type);
 	      g_string_free (ret, TRUE);
 	      return NULL;
 	    }
+	  marshal_name = dbus_g_type_get_marshal_name (gtype);
+	  g_assert (marshal_name != NULL);
 
 	  g_string_append (ret, "_");
-	  g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (type));
+	  g_string_append (ret, marshal_name);
 	}
     }
 
+  if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) {
+    g_string_append (ret, "_POINTER");
+  } else {
   /* Append pointer for each out arg storage */
   for (elt = method_info_get_args (method); elt; elt = elt->next)
     {
@@ -165,9 +239,9 @@
 	  g_string_append (ret, "_POINTER");
 	}
     }
-
   /* Final GError parameter */
   g_string_append (ret, "_POINTER");
+  }
 
   return g_string_free (ret, FALSE);
 }
@@ -210,7 +284,8 @@
       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
       if (interface_c_name == NULL)
         {
-          return TRUE;
+	  if (!data->prefix)
+	    return TRUE;
         }
 
       methods = interface_info_get_methods (interface);
@@ -223,10 +298,6 @@
           char *marshaller_name;
 
           method = (MethodInfo *) tmp->data;
-          if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL) == NULL)
-            {
-              continue;
-            }
 
           marshaller_name = compute_marshaller (method, error);
 	  if (!marshaller_name)
@@ -291,12 +362,56 @@
 {
   if (base_info_get_type (base) == INFO_TYPE_NODE)
     {
+      GString *object_introspection_data_blob;
+      GIOChannel *channel;
+      guint i;
+
+      channel = data->channel;
+      
+      object_introspection_data_blob = g_string_new_len ("", 0);
+      
+      data->blob = object_introspection_data_blob;
+      data->count = 0;
+
+      if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))
+	goto io_lose;
+
       if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
 			       data, error))
 	return FALSE;
       if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
 			       data, error))
 	return FALSE;
+
+      WRITE_OR_LOSE ("};\n\n");
+
+      /* Information about the object. */
+
+      if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
+				      channel, error, data->prefix))
+	goto io_lose;
+      WRITE_OR_LOSE ("  0,\n");
+      if (!write_printf_to_iochannel ("  dbus_glib_%s_methods,\n", channel, error, data->prefix))
+	goto io_lose;
+      if (!write_printf_to_iochannel ("  %d,\n", channel, error, data->count))
+	goto io_lose;
+      WRITE_OR_LOSE("  \"");
+      for (i = 0; i < object_introspection_data_blob->len; i++)
+	{
+	  if (object_introspection_data_blob->str[i] != '\0')
+	    {
+	      if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
+		return FALSE;
+	    }
+	  else
+	    {
+	      if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
+		return FALSE;
+	    }
+	}
+      WRITE_OR_LOSE ("\"\n};\n\n");
+
+      g_string_free (object_introspection_data_blob, TRUE);
     }
   else
     {
@@ -304,41 +419,43 @@
       InterfaceInfo *interface;
       GSList *methods;
       GSList *tmp;
-      gsize i;
-      int count;
       const char *interface_c_name;
       GString *object_introspection_data_blob;
 
       channel = data->channel;
+      object_introspection_data_blob = data->blob;
 
       interface = (InterfaceInfo *) base;
       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
       if (interface_c_name == NULL)
         {
-          return TRUE;
+	  if (data->prefix == NULL)
+	    return TRUE;
+	  interface_c_name = data->prefix;
         }
 
-      object_introspection_data_blob = g_string_new_len ("", 0);
-
       methods = interface_info_get_methods (interface);
-      count = 0;
 
       /* Table of marshalled methods. */
 
-      if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL)))
-	goto io_lose;
       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
         {
           MethodInfo *method;
           char *marshaller_name;
-	  const char *method_c_name;
+	  char *method_c_name;
+          gboolean async = FALSE;
 	  GSList *args;
 
           method = (MethodInfo *) tmp->data;
-	  method_c_name = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL);
+	  method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL));
           if (method_c_name == NULL)
-            {
-              continue;
+	    {
+	      char *method_name_uscored;
+	      method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
+              method_c_name = g_strdup_printf ("%s_%s",
+					       interface_c_name,
+					       method_name_uscored);
+	      g_free (method_name_uscored);
             }
 
           if (!write_printf_to_iochannel ("  { (GCallback) %s, ", channel, error,
@@ -357,6 +474,9 @@
 	      goto io_lose;
 	    }
 
+          if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
+            async = TRUE;
+
 	  /* Object method data blob format:
 	   * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
 	   */
@@ -367,6 +487,9 @@
 	  g_string_append (object_introspection_data_blob, method_info_get_name (method));
 	  g_string_append_c (object_introspection_data_blob, '\0');
 
+	  g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S');
+	  g_string_append_c (object_introspection_data_blob, '\0');
+
 	  for (args = method_info_get_args (method); args; args = args->next)
 	    {
 	      ArgInfo *arg;
@@ -400,37 +523,8 @@
 
 	  g_string_append_c (object_introspection_data_blob, '\0');
 
-          count++;
+          data->count++;
         }
-      WRITE_OR_LOSE ("};\n\n");
-
-      /* Information about the object. */
-
-      if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
-				      channel, error, interface_c_name))
-	goto io_lose;
-      WRITE_OR_LOSE ("  0,\n");
-      if (!write_printf_to_iochannel ("  dbus_glib_%s_methods,\n", channel, error, interface_c_name))
-	goto io_lose;
-      if (!write_printf_to_iochannel ("  %d,\n", channel, error, count))
-	goto io_lose;
-      WRITE_OR_LOSE("  \"");
-      for (i = 0; i < object_introspection_data_blob->len; i++)
-	{
-	  if (object_introspection_data_blob->str[i] != '\0')
-	    {
-	      if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
-		return FALSE;
-	    }
-	  else
-	    {
-	      if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
-		return FALSE;
-	    }
-	}
-      WRITE_OR_LOSE ("\"\n};\n\n");
-
-      g_string_free (object_introspection_data_blob, TRUE);
     }
   return TRUE;
  io_lose:
@@ -471,6 +565,8 @@
 
   memset (&data, 0, sizeof (data));
 
+  dbus_g_value_types_init ();
+
   data.prefix = prefix;
   data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
   data.error = error;
@@ -607,6 +703,8 @@
     {
       ArgInfo *arg;
       const char *type_str;
+      const char *type_suffix;
+      GType gtype;
       int direction;
 
       arg = args->data;
@@ -615,9 +713,8 @@
 
       direction = arg_info_get_direction (arg);
 
-      type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
-
-      if (!type_str)
+      gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+      if (gtype == G_TYPE_INVALID)
 	{
 	  g_set_error (error,
 		       DBUS_BINDING_TOOL_ERROR,
@@ -628,18 +725,37 @@
 		       interface_info_get_name (iface));
 	  return FALSE;
 	}
+      type_str = dbus_g_type_get_c_name (gtype);
+      g_assert (type_str);
+      /* Variants are special...*/
+      if (gtype == G_TYPE_VALUE)
+	{
+	  if (direction == ARG_IN)
+	    type_suffix = "*";
+	  else
+	    type_suffix = "";
+	}
+      else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+	      || g_type_is_a (gtype, G_TYPE_OBJECT)
+	   || g_type_is_a (gtype, G_TYPE_POINTER)))
+	type_suffix = "*";
+      else
+	type_suffix = "";
+
 
       switch (direction)
 	{
 	case ARG_IN:
-	  if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
+	  if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
 					  type_str,
+					  type_suffix,
 					  arg_info_get_name (arg)))
 	    goto io_lose;
 	  break;
 	case ARG_OUT:
-	  if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
+	  if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
 					  type_str,
+					  type_suffix,
 					  arg_info_get_name (arg)))
 	    goto io_lose;
 	  break;
@@ -653,32 +769,71 @@
   return FALSE;
 }
 
-static gboolean
-write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+#define MAP_FUNDAMENTAL(NAME) \
+   case G_TYPE_ ## NAME: \
+     return g_strdup ("G_TYPE_" #NAME);
+#define MAP_KNOWN(NAME) \
+    if (gtype == NAME) \
+      return g_strdup (#NAME)
+static char *
+dbus_g_type_get_lookup_function (GType gtype)
 {
-  GSList *args;
-
-  WRITE_OR_LOSE ("\"");
-
-  for (args = method_info_get_args (method); args; args = args->next)
+  char *type_lookup;
+  switch (gtype)
     {
-      ArgInfo *arg;
-
-      arg = args->data;
-
-      if (direction != arg_info_get_direction (arg))
-	continue;
-
-      if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg)))
-	goto io_lose;
+      MAP_FUNDAMENTAL(CHAR);
+      MAP_FUNDAMENTAL(UCHAR);
+      MAP_FUNDAMENTAL(BOOLEAN);
+      MAP_FUNDAMENTAL(LONG);
+      MAP_FUNDAMENTAL(ULONG);
+      MAP_FUNDAMENTAL(INT);
+      MAP_FUNDAMENTAL(UINT);
+      MAP_FUNDAMENTAL(INT64);
+      MAP_FUNDAMENTAL(UINT64);
+      MAP_FUNDAMENTAL(FLOAT);
+      MAP_FUNDAMENTAL(DOUBLE);
+      MAP_FUNDAMENTAL(STRING);
     }
-
-  WRITE_OR_LOSE ("\", ");
-
-  return TRUE;
- io_lose:
-  return FALSE;
+  if (dbus_g_type_is_collection (gtype))
+    {
+      GType elt_gtype;
+      char *sublookup;
+      
+      elt_gtype = dbus_g_type_get_collection_specialization (gtype);
+      sublookup = dbus_g_type_get_lookup_function (elt_gtype);
+      g_assert (sublookup);
+      type_lookup = g_strdup_printf ("dbus_g_type_get_collection (\"GArray\", %s)",
+				     sublookup);
+      g_free (sublookup);
+      return type_lookup;
+    }
+  else if (dbus_g_type_is_map (gtype))
+    {
+      GType key_gtype;
+      char *key_lookup;
+      GType value_gtype;
+      char *value_lookup;
+      
+      key_gtype = dbus_g_type_get_map_key_specialization (gtype);
+      value_gtype = dbus_g_type_get_map_value_specialization (gtype);
+      key_lookup = dbus_g_type_get_lookup_function (key_gtype);
+      g_assert (key_lookup);
+      value_lookup = dbus_g_type_get_lookup_function (value_gtype);
+      g_assert (value_lookup);
+      type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)",
+				     key_lookup, value_lookup);
+      g_free (key_lookup);
+      g_free (value_lookup);
+      return type_lookup;
+    }
+  MAP_KNOWN(G_TYPE_VALUE);
+  MAP_KNOWN(G_TYPE_STRV);
+  MAP_KNOWN(DBUS_TYPE_G_PROXY);
+  MAP_KNOWN(DBUS_TYPE_G_PROXY_ARRAY);
+  return NULL;
 }
+#undef MAP_FUNDAMENTAL
+#undef MAP_KNOWN
 
 static gboolean
 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
@@ -688,25 +843,38 @@
   for (args = method_info_get_args (method); args; args = args->next)
     {
       ArgInfo *arg;
+      GType gtype;
+      char *type_lookup;
 
       arg = args->data;
 
       if (direction != arg_info_get_direction (arg))
 	continue;
 
+      gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+      g_assert (gtype != G_TYPE_INVALID);
+      type_lookup = dbus_g_type_get_lookup_function (gtype);
+      g_assert (type_lookup != NULL);
+
       switch (direction)
 	{
+
 	case ARG_IN:
-	  if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg)))
+	  if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error,
+					  type_lookup,
+					  arg_info_get_name (arg)))
 	    goto io_lose;
 	  break;
 	case ARG_OUT:
-	  if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg)))
+	  if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error,
+					  type_lookup,
+					  arg_info_get_name (arg)))
 	    goto io_lose;
 	  break;
 	case ARG_INVALID:
 	  break;
 	}
+      g_free (type_lookup);
     }
 
   return TRUE;
@@ -722,15 +890,303 @@
   for (args = method_info_get_args (method); args; args = args->next)
     {
       ArgInfo *arg;
+      GType gtype;
+
       arg = args->data;
-      if (!dbus_gvalue_ctype_from_type (arg_info_get_type (arg),
-					arg_info_get_direction (arg)))
+      gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+      if (gtype == G_TYPE_INVALID)
 	return FALSE;
     }
   return TRUE;
 }
 
 static gboolean
+write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
+{
+  GSList *args;
+
+  for (args = method_info_get_args (method); args; args = args->next)
+    {
+      ArgInfo *arg;
+
+      arg = args->data;
+      if (arg_info_get_direction (arg) != ARG_OUT)
+        continue;
+            
+      if (!write_printf_to_iochannel ("OUT_%s, ", channel, error,
+                                      arg_info_get_name (arg)))
+        goto io_lose;
+     }
+
+   return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+static gboolean
+write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
+ {
+   GSList *args;
+ 
+   for (args = method_info_get_args (method); args; args = args->next)
+     {
+       ArgInfo *arg;
+      GType gtype;
+      const char *type_str, *type_suffix;
+      int dir;
+
+       arg = args->data;
+
+      dir = arg_info_get_direction (arg);
+
+      gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+      type_str = dbus_g_type_get_c_name (gtype);
+
+      if (!type_str)
+       {
+         g_set_error (error,
+                      DBUS_BINDING_TOOL_ERROR,
+                      DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+                      _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
+                      arg_info_get_type (arg),
+                      method_info_get_name (method),
+                      interface_info_get_name (iface));
+         return FALSE;
+       }
+
+      /* Variants are special...*/
+      if (gtype == G_TYPE_VALUE)
+	{
+	  if (direction == ARG_IN)
+	    type_suffix = "*";
+	  else
+	    type_suffix = "";
+	}
+      else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+	      || g_type_is_a (gtype, G_TYPE_OBJECT)
+	   || g_type_is_a (gtype, G_TYPE_POINTER)))
+	type_suffix = "*";
+      else
+	type_suffix = "";
+
+      if (direction != dir)
+        continue;
+
+          switch (dir)
+       {
+       case ARG_IN:
+         if (!write_printf_to_iochannel ("  %s%s IN_%s;\n", channel, error,
+                                         type_str, type_suffix,
+                                         arg_info_get_name (arg)))
+           goto io_lose;
+         break;
+       case ARG_OUT:
+         if (!write_printf_to_iochannel ("  %s%s OUT_%s;\n", channel, error,
+                                         type_str, type_suffix,
+                                         arg_info_get_name (arg)))
+           goto io_lose;
+         break;
+       case ARG_INVALID:
+         break;
+       }
+     }
+   return TRUE;
+ io_lose:
+  return FALSE;
+ }
+
+static gboolean
+write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error)
+{
+  GSList *args;
+
+  for (args = method_info_get_args (method); args; args = args->next)
+    {
+      ArgInfo *arg;
+      const char *type_str;
+      const char *type_suffix;
+      GType gtype;
+      int direction;
+
+      arg = args->data;
+
+      direction = arg_info_get_direction (arg);
+      if (dir != direction) continue;
+      
+      WRITE_OR_LOSE (", ");
+
+      gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+      type_str = dbus_g_type_get_c_name (gtype);
+      /* Variants are special...*/
+      if (gtype == G_TYPE_VALUE)
+	{
+	  if (direction == ARG_IN)
+	    type_suffix = "*";
+	  else
+	    type_suffix = "";
+	}
+      else if ((g_type_is_a (gtype, G_TYPE_BOXED)
+	      || g_type_is_a (gtype, G_TYPE_OBJECT)
+	   || g_type_is_a (gtype, G_TYPE_POINTER)))
+	type_suffix = "*";
+      else
+	type_suffix = "";
+
+      if (!type_str)
+	{
+	  g_set_error (error,
+		       DBUS_BINDING_TOOL_ERROR,
+		       DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
+		       _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
+		       arg_info_get_type (arg),
+		       method_info_get_name (method),
+		       interface_info_get_name (iface));
+	  return FALSE;
+	}
+ 
+       switch (direction)
+ 	{
+ 	case ARG_IN:
+	  if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
+					  type_str,
+					  type_suffix,
+					  arg_info_get_name (arg)))
+ 	    goto io_lose;
+ 	  break;
+ 	case ARG_OUT:
+	  if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
+					  type_str,
+					  type_suffix,
+					  arg_info_get_name (arg)))
+ 	    goto io_lose;
+ 	  break;
+ 	case ARG_INVALID:
+	  break;
+	}
+    }
+  return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+static gboolean
+write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
+ {
+  GSList *args;
+  
+  for (args = method_info_get_args (method); args; args = args->next)
+    {
+      ArgInfo *arg;
+      int dir;
+      GType gtype;
+      const char *type_lookup;
+      
+      arg = args->data;
+
+      dir = arg_info_get_direction (arg);
+
+      if (dir != direction)
+        continue;
+
+      gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+      type_lookup = dbus_g_type_get_lookup_function (gtype);
+
+      if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg)))
+          goto io_lose;
+    }
+  return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+static gboolean
+write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error)
+{
+  char *method_name, *iface_prefix;
+  iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
+  method_name = compute_client_method_name (iface_prefix, method);
+  
+  /* Write the typedef for the client callback */
+  if (!write_printf_to_iochannel ("typedef void (*%s_reply) (", channel, error, method_name))
+    goto io_lose;
+  {
+    GSList *args;
+    for (args = method_info_get_args (method); args; args = args->next)
+      {
+	ArgInfo *arg;
+	const char *type_suffix, *type_str;
+	GType gtype;
+	
+	arg = args->data;
+	
+	if (arg_info_get_direction (arg) != ARG_OUT)
+	  continue;
+	gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
+	if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED)
+	     || g_type_is_a (gtype, G_TYPE_OBJECT)
+	     || g_type_is_a (gtype, G_TYPE_POINTER)))
+	  type_suffix = "*";
+	else
+	  type_suffix = "";
+	type_str = dbus_g_type_get_c_name (dbus_gtype_from_signature (arg_info_get_type (arg), TRUE));
+	if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg)))
+	  goto io_lose;
+      }
+  }
+  WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n");
+  
+  
+  /* Write the callback when the call returns */
+  WRITE_OR_LOSE ("static void\n");
+  if (!write_printf_to_iochannel ("%s_async_callback (DBusGPendingCall *pending, DBusGAsyncData *data)\n", channel, error, method_name))
+    goto io_lose;
+  WRITE_OR_LOSE ("{\n");
+  WRITE_OR_LOSE ("  GError *error = NULL;\n");
+  if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error))
+    goto io_lose;
+  WRITE_OR_LOSE ("  dbus_g_proxy_end_call (data->proxy, pending, &error, ");
+  if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error))
+    goto io_lose;
+  WRITE_OR_LOSE("G_TYPE_INVALID);\n");
+  if (!write_printf_to_iochannel ("  (*(%s_reply)data->cb) (", channel, error, method_name))
+    goto io_lose;
+  if (!write_untyped_out_args (interface, method, channel, error))
+    goto io_lose;
+  WRITE_OR_LOSE ("error, data->userdata);\n");
+  WRITE_OR_LOSE ("  return;\n}\n\n");
+  
+
+  /* Write the main wrapper function */
+  WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
+  if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error,
+                                  method_name))
+    goto io_lose;
+  if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error))
+    goto io_lose;
+  
+  if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name))
+    goto io_lose;
+  
+  WRITE_OR_LOSE ("{\n");
+  WRITE_OR_LOSE ("  DBusGPendingCall *pending;\n  DBusGAsyncData *stuff;\n  stuff = g_new (DBusGAsyncData, 1);\n  stuff->proxy = proxy;\n  stuff->cb = callback;\n  stuff->userdata = userdata;\n");
+  if (!write_printf_to_iochannel ("  pending = dbus_g_proxy_begin_call (proxy, \"%s\", ", channel, error, method_info_get_name (method)))
+    goto io_lose;
+  if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
+    goto io_lose;
+  WRITE_OR_LOSE ("G_TYPE_INVALID);\n");
+
+  if (!write_printf_to_iochannel ("  dbus_g_pending_call_set_notify(pending, (DBusGPendingCallNotify)%s_async_callback, stuff, g_free);\n", channel, error, method_name))
+    goto io_lose;
+
+  WRITE_OR_LOSE ("  return TRUE;\n}\n\n");
+
+  g_free (method_name);
+  return TRUE;
+ io_lose:
+  return FALSE;
+ }
+
+static gboolean
 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
 {
   GSList *tmp;
@@ -818,21 +1274,19 @@
 					  method_info_get_name (method)))
 	    goto io_lose;
 
-	  if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error))
-	    goto io_lose;
-
-	  if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error))
-	    goto io_lose;
-
 	  WRITE_OR_LOSE ("error, ");
 
 	  if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
 	    goto io_lose;
 
+	  WRITE_OR_LOSE ("G_TYPE_INVALID, ");
+
 	  if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
 	    goto io_lose;
 
-	  WRITE_OR_LOSE ("NULL);\n}\n\n");
+	  WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n");
+
+	  write_async_method_client (channel, interface, method, error);
 	}
 
       if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix))
@@ -853,6 +1307,8 @@
   DBusBindingToolCData data;
   gboolean ret;
 
+  dbus_g_value_types_init ();
+
   memset (&data, 0, sizeof (data));
   
   data.channel = channel;

Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/glib/Makefile.am,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- Makefile.am	17 Mar 2005 17:48:29 -0000	1.17
+++ Makefile.am	13 Jun 2005 03:01:24 -0000	1.18
@@ -15,8 +15,12 @@
 	dbus-gthread.c				\
 	dbus-gutils.c				\
 	dbus-gutils.h				\
+	dbus-gtype-specialized.c		\
+	dbus-gtype-specialized.h		\
 	dbus-gvalue.c				\
-	dbus-gvalue.h
+	dbus-gvalue.h				\
+	dbus-gvalue-utils.c			\
+	dbus-gvalue-utils.h
 
 libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la
 ## don't export symbols that start with "_" (we use this 



More information about the dbus-commit mailing list